diff --git a/common.blocks/form-field/_has-validation/form-field_has-validation.browser.js b/common.blocks/form-field/_has-validation/form-field_has-validation.browser.js index a5df49c..9f9947b 100644 --- a/common.blocks/form-field/_has-validation/form-field_has-validation.browser.js +++ b/common.blocks/form-field/_has-validation/form-field_has-validation.browser.js @@ -15,10 +15,11 @@ FormField.decl({ block : this.name, modName : 'has-validation', modVal : true }, 'inited' : function() { this.__base.apply(this, arguments); - !this.hasMod('message') && console.warn('Message modifier required for form-field_has-validation', this); + !this.hasMod('message') && + console.warn('Message modifier required for form-field_has-validation', this); - this.on('blur', function(e, data) { - this._dirty = this._dirty || (this.getVal() != this._initVal); + this.on('blur', function() { + this._dirty = this._dirty || (this.getVal() !== this._initVal); this.toggleMod('dirty', true, this._dirty); this._dirty && this.validate(); }.bind(this)); @@ -70,6 +71,11 @@ FormField.decl({ block : this.name, modName : 'has-validation', modVal : true }, this.getControl().toggleMod('invalid', true, Boolean(this._status)); this.getMessage().toggleMod('invalid', true, Boolean(this._status)); + + if(this.hasMod('message')) { + this.setMessageVal(this._status); + this._status && this.hasMod('focused') && this.getMessage().show(); + } } }); diff --git a/common.blocks/form-field/_has-validation/form-field_has-validation.deps.js b/common.blocks/form-field/_has-validation/form-field_has-validation.deps.js index 7809fbc..9076c9d 100644 --- a/common.blocks/form-field/_has-validation/form-field_has-validation.deps.js +++ b/common.blocks/form-field/_has-validation/form-field_has-validation.deps.js @@ -2,4 +2,11 @@ shouldDeps : [ { block : 'validation' } ] -}) +}, +{ + tech : 'spec.js', + shouldDeps : [ + { tech : 'js', block : 'form-field', mods : { type : 'input', message : 'text' } }, + { tech : 'bemhtml', block : 'form-field', mods : { type : 'input', message : 'text' } } + ] +}); diff --git a/common.blocks/form-field/_has-validation/form-field_has-validation.spec.js b/common.blocks/form-field/_has-validation/form-field_has-validation.spec.js new file mode 100644 index 0000000..e50954a --- /dev/null +++ b/common.blocks/form-field/_has-validation/form-field_has-validation.spec.js @@ -0,0 +1,53 @@ +// FIXME: this spec don't work without https://github.com/narqo/bem-pr/pull/90 +modules.define('spec', ['spec__utils', 'sinon', 'input', 'message', 'form-field'], function(provide, utils, sinon) { + + describe('form-field_has-validation', function() { + + var block, bemjson; + + beforeEach(function() { + bemjson = { + block : 'form-field', + mods : { + 'has-validation' : true + } + }; + }); + + afterEach(function() { + block && utils.destruct(block); + }); + + it('should not throw without `type` mod', function() { + block = utils.buildBlock('form-field', bemjson); + block.getVal().should.equal(''); + }); + + it('should call show message when changes status focused', function() { + bemjson.mods.type = 'input'; + bemjson.mods.message = 'text'; + bemjson.content = { + elem : 'control', + content : { + block : 'input', + val : 'XXX' + } + }; + block = utils.buildBlock('form-field', bemjson); + + // should not show for valid block + block.getControl().elem('control').focus(); + var spy = sinon.spy(block.getMessage(), 'show'); + block._updateStatus(); + (!!spy.called).should.be.false; + + // should show for invalid block + block._status = 'error'; + block._updateStatus(); + (!!spy.called).should.be.true; + }); + + }); + + provide(); +}); diff --git a/common.blocks/form-field/_message/form-field_message.browser.js b/common.blocks/form-field/_message/form-field_message.browser.js index 7606fc6..2406ce2 100644 --- a/common.blocks/form-field/_message/form-field_message.browser.js +++ b/common.blocks/form-field/_message/form-field_message.browser.js @@ -12,7 +12,20 @@ function(provide, FormField) { * @bem */ FormField.decl({ block : this.name, modName : 'message' }, /** @lends form-field.prototype */{ + onSetMod : { + 'focused' : { + 'true' : function() { + this.__base.apply(this, arguments); + this.hasMod('invalid') && this.getMessage().show(); + }, + '' : function() { + this.__base.apply(this, arguments); + + this.getMessage().hide(); + } + } + }, /** * Return instance of message block * @public diff --git a/common.blocks/form-field/_message/form-field_message_popup.browser.js b/common.blocks/form-field/_message/form-field_message_popup.browser.js index 5e42604..e5e4e02 100644 --- a/common.blocks/form-field/_message/form-field_message_popup.browser.js +++ b/common.blocks/form-field/_message/form-field_message_popup.browser.js @@ -16,8 +16,10 @@ FormField.decl({ block : this.name, modName : 'message', modVal : 'popup' }, /** 'js' : { 'inited' : function() { this.__base.apply(this, arguments); - - this.getMessage().setAnchor(this); + /* istanbul ignore else: no way to check, form-field throws without `type` */ + if(this.hasMod('type')) { + this.getMessage().setAnchor(this.getControl()); + } } } } diff --git a/common.blocks/form-field/_message/form-field_message_popup.deps.js b/common.blocks/form-field/_message/form-field_message_popup.deps.js index f8588c3..8a9aae0 100644 --- a/common.blocks/form-field/_message/form-field_message_popup.deps.js +++ b/common.blocks/form-field/_message/form-field_message_popup.deps.js @@ -3,4 +3,12 @@ shouldDeps : [ { block : 'message', mods : { type : 'popup' } } ] -}) +}, +{ + tech : 'spec.js', + shouldDeps : [ + { tech : 'js', block : 'form-field', mods : { type : 'input', message : 'popup' } }, + { tech : 'bemhtml', block : 'message', mods : { type : 'popup' } }, + { tech : 'bemhtml', block : 'form-field', mods : { type : 'input', message : 'popup' } } + ] +}); diff --git a/common.blocks/form-field/_message/form-field_message_popup.spec.js b/common.blocks/form-field/_message/form-field_message_popup.spec.js new file mode 100644 index 0000000..3f10495 --- /dev/null +++ b/common.blocks/form-field/_message/form-field_message_popup.spec.js @@ -0,0 +1,53 @@ +// FIXME: this spec don't work without https://github.com/narqo/bem-pr/pull/90 +modules.define('spec', ['spec__utils', 'sinon', 'form-field', 'message', 'popup', 'input'], function(provide, utils, sinon) { + + describe('form-field_message_popup', function() { + + var block; + + beforeEach(function() { + block = utils.buildBlock('form-field', { + block : 'form-field', + mods : { + type : 'input', + message : 'popup' + }, + content : { + block : 'input' + } + }); + }); + + afterEach(function() { + block && utils.destruct(block); + }); + + it('should show message on focus', function() { + var spy = sinon.spy(block.getMessage(), 'show'); + + // without invalid + block.setMod('focused'); + block.delMod('focused'); + (!!spy.called).should.be.false; + + // with invalid + block.setMod('invalid'); + block.setMod('focused'); + block.delMod('focused'); + (!!spy.called).should.be.true; + }); + + it('should set popup`s anchor to input', function() { + var anchor = block.getMessage()._popup._anchor; + + block.hasMod('type').should.be.true; + + setTimeout(function() { + (!!anchor).should.be.true; + anchor.attr('class').should.equal(block.getControl().domElem.attr('class')); + }, 20); + }); + }); + + provide(); +}); diff --git a/common.blocks/form-field/_validate/form-field_validate_email.deps.js b/common.blocks/form-field/_validate/form-field_validate_email.deps.js new file mode 100644 index 0000000..f021f51 --- /dev/null +++ b/common.blocks/form-field/_validate/form-field_validate_email.deps.js @@ -0,0 +1,6 @@ +[{ + shouldDeps : [ + { mod : 'has-validation' }, + { block : 'validation', mods : { email : true } } + ] +}]; diff --git a/common.blocks/form-field/_validate/form-field_validate_email.js b/common.blocks/form-field/_validate/form-field_validate_email.js new file mode 100644 index 0000000..1e0f87e --- /dev/null +++ b/common.blocks/form-field/_validate/form-field_validate_email.js @@ -0,0 +1,31 @@ +/** + * @module form-field + */ +modules.define('form-field', + ['validation_email', 'objects'], + function(provide, validateEmail, objects, FormField) { + +/** + * E-mail form-field validation + + * @exports + * @class form-field + * @bem + */ +FormField.decl({ modName : 'validate', modVal : 'email' }, /** @lends form-field.prototype */{ + + onSetMod : { + 'js' : { + 'inited' : function() { + this.__base.apply(this, arguments); + + this.getValidator().push(validateEmail(this.params.email)); + } + } + } + +}); + +provide(FormField); + +}); diff --git a/common.blocks/form-field/_validate/form-field_validate_email.spec.js b/common.blocks/form-field/_validate/form-field_validate_email.spec.js new file mode 100644 index 0000000..40fdc13 --- /dev/null +++ b/common.blocks/form-field/_validate/form-field_validate_email.spec.js @@ -0,0 +1,13 @@ +modules.define('spec', ['form-field'], function(provide) { + + describe('form-field_validate_email', function() { + + it('should add validate_email', function() { + + }); + + }); + + provide(); + +});