diff --git a/src/style_manager/view/PropertyIntegerView.js b/src/style_manager/view/PropertyIntegerView.js index 5047d8d55..05dd09a3f 100644 --- a/src/style_manager/view/PropertyIntegerView.js +++ b/src/style_manager/view/PropertyIntegerView.js @@ -13,9 +13,21 @@ define(['backbone','./PropertyView', 'text!./../templates/propertyInteger.html'] this.events['click .'+this.pfx+'u-arrow'] = 'upArrowClick'; this.events['click .'+this.pfx+'d-arrow'] = 'downArrowClick'; this.events['mousedown .'+this.pfx+'int-arrows'] = 'downIncrement'; + this.listenTo( this.model ,'change:unit', this.valueChanged); this.delegateEvents(); }, + /** + * Fired when the input value is updated + */ + valueUpdated: function(){ + if(this.$input && this.$unit) + this.model.set({ + value: this.$input.val(), + unit: this.$unit.val() + }); + }, + /** * Invoked when the up arrow is clicked * @param Event diff --git a/src/style_manager/view/PropertyView.js b/src/style_manager/view/PropertyView.js index c4ed24971..97f85d161 100644 --- a/src/style_manager/view/PropertyView.js +++ b/src/style_manager/view/PropertyView.js @@ -9,7 +9,7 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat templateLabel: _.template(propertyLabel), events: { - 'change' : 'valueChanged', + 'change': 'valueUpdated', }, initialize: function(o) { @@ -31,10 +31,22 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat this.input = this.$input = null; this.className = this.pfx + 'property'; this.inputHolderId = '#' + this.pfx + 'input-holder'; + + if(!this.model.get('value')) + this.model.set('value', this.model.get('defaults')); + this.listenTo( this.propTarget, 'update', this.targetUpdated); this.listenTo( this.model ,'change:value', this.valueChanged); }, + /** + * Fired when the input value is updated + */ + valueUpdated: function(){ + if(this.$input) + this.model.set('value', this.$input.val()); + }, + /** * Fired when the target is updated * */ @@ -54,6 +66,9 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat * @return {Boolean} * */ sameValue: function(){ + if(this.property == 'test'){ + console.log('compoVal: ' + this.getComponentValue() + ' modelVal: ' + (this.model.get('value') + this.model.get('unit'))); + } return this.getComponentValue() == (this.model.get('value') + this.model.get('unit')); }, @@ -67,8 +82,9 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat if(!this.selectedComponent) return; - if(this.selectedComponent.get('style')[this.property]) - this.componentValue = this.selectedComponent.get('style')[this.property]; + var targetProp = this.selectedComponent.get('style')[this.property]; + if(targetProp) + this.componentValue = targetProp; else this.componentValue = this.defaultValue + (this.unit || ''); @@ -101,6 +117,14 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat return v.substring(v.indexOf("(") + 1, v.lastIndexOf(")")); }, + /** + * Returns value from necessary inputs + * @return {string} + */ + getValueForTarget: function(){ + return this.model.get('value'); + }, + /** * Property was changed, so I need to update the component too * @param {Object} e Events @@ -108,13 +132,19 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat * @param {Object} opt Options * */ valueChanged: function(e, val, opt){ + //var v = e && e.currentTarget ? this.$input.val() : this.model.get('value'); + var mVal = this.model.get('value'); + + if(this.$input) + this.$input.val(mVal); + if(!this.selectedComponent) return; // Check if component is allowed to be styled - var stylable = this.selectedComponent.get('stylable'); - if( (stylable instanceof Array && _.indexOf(stylable, this.property) < 0) || !stylable ) + if(!this.isTargetStylable()) return; + var v = e && e.currentTarget ? this.$input.val() : this.model.get('value'), u = this.$unit ? this.$unit.val() : '', value = v + u, @@ -124,16 +154,21 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat if(this.model.get('type') == 'radio') value = this.$el.find('input:checked').val(); - if(this.$input) - this.$input.val(v); - this.model.set({ value : v, unit: u },{ silent : true }); + //if(this.$input) + //this.$input.val(v); + this.model.set({ value : v, unit: u }, { silent : true }); if(this.func) value = this.func + '(' + value + ')'; if( !this.model.get('doNotStyle') ){ var componentCss = _.clone( this.selectedComponent.get('style') ); - componentCss[this.property] = value; + + if(value) + componentCss[this.property] = value; + else + delete componentCss[this.property]; + this.selectedComponent.set('style', componentCss, { avoidStore : avSt}); if(this.helperComponent) this.helperComponent.set('style', componentCss, { avoidStore : avSt}); @@ -145,14 +180,30 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat } }, + /** + * Check if target is stylable with this property + * @return {Boolean} + */ + isTargetStylable: function(){ + if(!this.selectedComponent) + return; + var stylable = this.selectedComponent.get('stylable'); + // Stylable could also be an array indicating with which property + // the target could be styled + if(stylable instanceof Array) + stylable = _.indexOf(stylable, this.property) >= 0; + return stylable; + }, + /** * Set value to the input * @param {String} value * @param {Boolean} force * */ setValue: function(value, force){ - var f = force===0 ? 0 : 1; - var v = this.model.get('value') || this.defaultValue; + var f = force === 0 ? 0 : 1; + var def = this.model.get('defaults'); + var v = this.model.get('value') || def; if(value || f){ v = value; } @@ -200,11 +251,12 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat renderInput: function(){ if(!this.$input){ this.$input = $('', { - placeholder: this.defaultValue, + placeholder: this.model.get('defaults'), type: 'text' }); this.$el.find(this.inputHolderId).html(this.$input); } + this.setValue(this.componentValue, 0); }, /** diff --git a/test/specs/style_manager/view/PropertyView.js b/test/specs/style_manager/view/PropertyView.js index 7ce713512..52357bccd 100644 --- a/test/specs/style_manager/view/PropertyView.js +++ b/test/specs/style_manager/view/PropertyView.js @@ -7,10 +7,15 @@ define([path + 'PropertyView', 'StyleManager/model/Property', 'DomComponents/mod describe('PropertyView', function() { + var component; var $fixtures; var $fixture; + var target; var model; var view; + var propName = 'testprop'; + var propValue = 'testvalue'; + var defValue = 'testDefault'; before(function () { $fixtures = $("#fixtures"); @@ -18,8 +23,9 @@ define([path + 'PropertyView', 'StyleManager/model/Property', 'DomComponents/mod }); beforeEach(function () { + target = new Component(); component = new Component(); - model = new Property(); + model = new Property({property: propName}); view = new PropertyView({ model: model }); @@ -33,21 +39,146 @@ define([path + 'PropertyView', 'StyleManager/model/Property', 'DomComponents/mod after(function () { $fixture.remove(); + delete component; }); it('Rendered correctly', function() { var prop = view.el; $fixture.get(0).querySelector('.property').should.be.ok; prop.querySelector('.label').should.be.ok; + prop.querySelector('.field').should.be.ok; }); - it.skip('Update target on value change', function() { + it('Input should exist', function() { + view.$input.should.be.ok; }); - it.skip('Update value on target swap', function() { + it('Input value is empty', function() { + view.model.get('value').should.be.empty; + view.$input.val().should.be.empty; + }); + + it('Model not change without update trigger', function() { + view.$input.val(propValue); + view.model.get('value').should.be.empty; + }); + + // Tests valueUpdated() + it('Update model on input change', function() { + view.$input.val(propValue).trigger('change'); + view.model.get('value').should.equal(propValue); + }); + + // Tests getValueForTarget() + it('Get value for target', function() { + view.model.set('value', propValue); + view.getValueForTarget().should.equal(propValue); + }); + + // Tests valueChanged() -> ... + it('Update input on value change', function() { + view.model.set('value', propValue); + view.$input.val().should.equal(propValue); + }); + + it('Update target on value change', function() { + view.selectedComponent = component; + view.model.set('value', propValue); + var compStyle = view.selectedComponent.get('style'); + var assertStyle = {}; + assertStyle[propName] = propValue; + compStyle.should.deep.equal(assertStyle); + }); + + it('Clean target from the property if its value is empty', function() { + view.selectedComponent = component; + view.model.set('value', propValue); + view.model.set('value', ''); + var compStyle = view.selectedComponent.get('style'); + compStyle.should.deep.equal({}); + }); + + it('Check stylable element', function() { + view.selectedComponent = component; + view.isTargetStylable().should.equal(true); + component.set('stylable', false); + view.isTargetStylable().should.equal(false); + component.set('stylable', [propName]); + view.isTargetStylable().should.equal(true); + component.set('stylable', ['test1', propName]); + view.isTargetStylable().should.equal(true); + component.set('stylable', ['test1', 'test2']); + view.isTargetStylable().should.equal(false); }); it.skip('Get target style', function() { + //getComponentValue + }); + + it.skip('Fetch value from function', function() { + //fetchFromFunction + }); + + describe('With target setted', function() { + + beforeEach(function () { + target.model = component; + view = new PropertyView({ + model: model, + propTarget: target + }); + $fixture.empty().appendTo($fixtures); + $fixture.html(view.render().el); + }); + + it('Update value on target swap', function() { + var style = {}; + style[propName] = propValue; + component.set('style', style); + view.propTarget.trigger('update'); + view.model.get('value').should.equal(propValue); + }); + + it('Update value after multiple swaps', function() { + var style = {}; + style[propName] = propValue; + component.set('style', style); + view.propTarget.trigger('update'); + style[propName] = propValue + '2'; + component.set('style', style); + view.propTarget.trigger('update'); + view.model.get('value').should.equal(propValue + '2'); + }); + + }) + + describe('Init property', function() { + + beforeEach(function () { + component = new Component(); + model = new Property({ + property: propName, + defaults: defValue + }); + view = new PropertyView({ + model: model + }); + $fixture.empty().appendTo($fixtures); + $fixture.html(view.render().el); + }); + + it('Value as default', function() { + view.model.get('value').should.equal(defValue); + }); + + it('Placeholder as default', function() { + view.$input.attr('placeholder').should.equal(defValue); + }); + + it('Input value is empty', function() { + view.$input.val().should.equal(defValue); + }); + }); });