Browse Source

Add PropertyStackView tests

pull/36/head
Artur Arseniev 10 years ago
parent
commit
33a63734da
  1. 3
      src/demo.js
  2. 2
      src/style_manager/view/LayerView.js
  3. 60
      src/style_manager/view/PropertyCompositeView.js
  4. 6
      src/style_manager/view/PropertyIntegerView.js
  5. 68
      src/style_manager/view/PropertyStackView.js
  6. 38
      src/style_manager/view/PropertyView.js
  7. 5
      src/utils/Sorter.js
  8. 3
      test/specs/style_manager/main.js
  9. 282
      test/specs/style_manager/view/PropertyStackView.js
  10. 14
      test/specs/style_manager/view/PropertyView.js

3
src/demo.js

@ -500,7 +500,7 @@ require(['config/require-config'], function() {
min : 0,
},{
name : 'Left',
property : 'padding-Left',
property : 'padding-left',
type : 'integer',
units : ['px','%'],
defaults : 0,
@ -619,6 +619,7 @@ require(['config/require-config'], function() {
name : 'Text shadow',
property : 'text-shadow',
type : 'stack',
detached : true,
preview : true,
properties : [{
name: 'X position',

2
src/style_manager/view/LayerView.js

@ -127,7 +127,7 @@ define(['backbone', 'text!./../templates/layer.html'],
this.model.collection.remove(this.model);
if(this.stackModel && this.stackModel.set){
this.stackModel.trigger('refreshValue');
this.stackModel.trigger('updateValue');
this.stackModel.set({stackIndex: null},{silent: true});
}
},

60
src/style_manager/view/PropertyCompositeView.js

@ -48,34 +48,45 @@ define(['backbone','./PropertyView', 'text!./../templates/propertyComposite.html
}, this);
var PropertiesView = require('./PropertiesView');
var that = this;
var propsViewOpts = {
config: this.config,
collection: this.props,
target: this.target,
propTarget: this.propTarget,
// Each child property will receive a full composite string, eg. '0px 0px 10px 0px'
// I need to extract from that string the corresponding one to that property.
customValue: function(property, mIndex){
return that.valueOnIndex(mIndex, property.model);
},
};
// On any change made to children I need to update composite value
if(!detached)
propsViewOpts.onChange = function(el, model){
var result = that.build(el, model);
that.model.set('value', result);
};
var propsView = new PropertiesView(propsViewOpts);
var propsView = new PropertiesView(this.getPropsConfig());
this.$props = propsView.render().$el;
this.$el.find('#'+ this.pfx +'input-holder').html(this.$props);
}
}
},
/**
* Returns configurations that should be past to properties
* @param {Object} opts
* @return {Object}
*/
getPropsConfig: function(opts){
var that = this;
result = {
config: this.config,
collection: this.props,
target: this.target,
propTarget: this.propTarget,
// On any change made to children I need to update composite value
onChange: function(el, view, opts){
var result = that.build();
that.model.set('value', result);
},
// Each child property will receive a full composite string, eg. '0px 0px 10px 0px'
// I need to extract from that string the corresponding one to that property.
customValue: function(property, mIndex){
return that.valueOnIndex(mIndex, property.model);
},
};
// If detached let follow its standard flow
if(this.model.get('detached'))
delete result.onChange;
return result;
},
/**
* Get default value of the property
* @return {string}
@ -111,10 +122,11 @@ define(['backbone','./PropertyView', 'text!./../templates/propertyComposite.html
/**
* Build composite value
* @param {Object} selectedEl Selected element
* @param {Object} propertyModel Property model
* @param {Object} propertyView Property view
* @param {Object} opts Options
* @return {string}
* */
build: function(selectedEl, propertyModel){
build: function(selectedEl, propertyView, opts){
var result = '';
this.model.get('properties').each(function(prop){
var v = prop.getValue();

6
src/style_manager/view/PropertyIntegerView.js

@ -63,7 +63,8 @@ define(['backbone','./PropertyView', 'text!./../templates/propertyInteger.html']
upArrowClick: function(e){
var value = this.model.get('value');
value = isNaN(value) ? 1 : parseInt(value,10) + 1;
value = value > this.max ? this.max : value;
if(this.max !== null)
value = value > this.max ? this.max : value;
this.model.set('value',value);
},
@ -76,7 +77,8 @@ define(['backbone','./PropertyView', 'text!./../templates/propertyInteger.html']
downArrowClick: function(e){
var value = this.model.get('value');
value = isNaN(value) ? 0 : parseInt(value,10) - 1;
value = value < this.min ? this.min : value;
if(this.min !== null)
value = value < this.min ? this.min : value;
this.model.set('value',value);
},

68
src/style_manager/view/PropertyStackView.js

@ -11,7 +11,7 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
PropertyCompositeView.prototype.initialize.apply(this, arguments);
this.model.set('stackIndex', null);
this.listenTo( this.model ,'change:stackIndex', this.indexChanged);
this.listenTo( this.model ,'refreshValue', this.refreshValue);
this.listenTo( this.model ,'updateValue', this.valueUpdated);
this.className = this.pfx + 'property '+ this.pfx +'stack';
this.events['click #'+this.pfx+'add'] = 'addLayer';
@ -27,7 +27,9 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
},
/**
* Triggered when another layer has been selected
* Triggered when another layer has been selected.
* This allow to move all rendered properties to a new
* selected layer
* @param {Event}
*
* @return {Object}
@ -35,26 +37,43 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
indexChanged: function(e){
var layer = this.getLayers().at(this.model.get('stackIndex'));
layer.set('props', this.$props);
this.target.trigger('change:selectedComponent');//TODO replace with getTarget
},
/**
* Get array of values from layers
* TODO replace with pluck
* @return Array
* */
getStackValues: function(){
var a = [];
this.getLayers().each(function(layer){
a.push( layer.get('value') );
});
return a;
return this.getLayers().pluck('value');
},
/** @inheritDoc */
getPropsConfig: function(opts){
var that = this;
var result = PropertyCompositeView.prototype.getPropsConfig.apply(this, arguments);
result.onChange = function(el, view, opt){
var model = view.model;
// This will update the layer value
var result = that.build(el, model);
if(that.model.get('detached')){
var propVal = '';
var index = model.collection.indexOf(model);
that.getLayers().each(function(layer){
var vals = layer.get('value').split(' ');
if(vals.length && vals[index])
propVal += (propVal ? ',' : '') + vals[index];
});
view.updateTargetStyle(propVal, null, opt);
}else
that.model.set('value', result);
};
return result;
},
/**
* Extract string from composite value
* @param integer Index
* TODO missing valueOnIndex
* @return string
* */
valueOnIndex: function(index){
@ -72,11 +91,12 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
},
/** @inheritdoc */
build: function(selectedEl, propertyModel){
if(this.model.get('stackIndex') === null)
build: function(){
var stackIndex = this.model.get('stackIndex');
if(stackIndex === null)
return;
var result = PropertyCompositeView.prototype.build.apply(this, arguments);
var model = this.getLayers().at(this.model.get('stackIndex'));
var model = this.getLayers().at(stackIndex);
if(!model)
return;
model.set('value',result);
@ -90,24 +110,28 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
* @return Object
* */
addLayer: function(e){
if(this.selectedComponent){
if(this.getTarget()){
var layers = this.getLayers();
var layer = layers.add({ name : 'test' });
var index = layers.indexOf(layer);
layer.set('value', this.getDefaultValue());
this.refreshValue();
this.valueUpdated();
this.model.set('stackIndex', index);
return layer;
}
},
/**
* Refresh value
*
* @return void
* */
refreshValue: function(){
this.model.set('value', this.createValue());
* Fired when the input value is updated
*/
valueUpdated: function(){
if(!this.model.get('detached'))
this.model.set('value', this.createValue());
else{
this.model.get('properties').each(function(prop){
prop.trigger('change:value');
});
}
},
/**
@ -166,7 +190,7 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
var layers = this.getLayers();
layers.reset();
layers.add(n);
this.refreshValue();
this.valueUpdated();
this.model.set({stackIndex: null}, {silent: true});
},

38
src/style_manager/view/PropertyView.js

@ -141,8 +141,7 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
* @param {Object} opt Options
* */
valueChanged: function(e, val, opt){
var mVal = this.getValueForTarget(),
avSt = opt ? opt.avoidStore : 0;
var mVal = this.getValueForTarget();
if(this.$input)
this.setValue(mVal);
@ -164,20 +163,33 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
var onChange = this.onChange;
if(onChange && typeof onChange === "function"){
onChange(target, this.model);
}else{
var componentCss = _.clone( target.get('style') );
onChange(target, this, opt);
}else
this.updateTargetStyle(value, null, opt);
},
if(value)
componentCss[this.property] = value;
else
delete componentCss[this.property];
/**
* Update target style
* @param {string} propertyValue
* @param {string} propertyName
* @param {Object} opts
*/
updateTargetStyle: function(propertyValue, propertyName, opts){
var propName = propertyName || this.property;
var value = propertyValue || '';
var avSt = opts ? opts.avoidStore : 0;
var target = this.getTarget();
var targetStyle = _.clone(target.get('style'));
target.set('style', componentCss, { avoidStore : avSt});
if(value)
targetStyle[propName] = value;
else
delete targetStyle[propName];
if(this.helperComponent)
this.helperComponent.set('style', componentCss, { avoidStore : avSt});
}
target.set('style', targetStyle, { avoidStore : avSt});
if(this.helperComponent)
this.helperComponent.set('style', targetStyle, { avoidStore : avSt});
},
/**

5
src/utils/Sorter.js

@ -9,7 +9,7 @@ define(['backbone'],
this.elT = 0;
this.elL = 0;
this.borderOffset = o.borderOffset || 10;
this.freezeClass = o.freezeClass || 'freezed';
this.freezeClass = o.freezeClass || 'opac50';
var el = o.container;
this.el = typeof el === 'string' ? document.querySelector(o.container) : el;
@ -98,6 +98,7 @@ define(['backbone'],
this.el.appendChild(this.plh);
}
this.eV.className += ' ' + this.freezeClass;
this.$el.on('mousemove',this.onMove);
$(document).on('mouseup',this.endMove);
$(document).on('keypress',this.rollback);
@ -350,6 +351,8 @@ define(['backbone'],
$(document).off('mouseup', this.endMove);
$(document).off('keypress', this.rollback);
this.plh.style.display = 'none';
var clsReg = new RegExp('(?:^|\\s)'+this.freezeClass+'(?!\\S)', 'gi');
this.eV.className = this.eV.className.replace(clsReg, '');
if(this.moved)
this.move(this.target, this.eV, this.lastPos);
},

3
test/specs/style_manager/main.js

@ -11,6 +11,7 @@ define([
modulePath + '/view/PropertyIntegerView',
modulePath + '/view/PropertyColorView',
modulePath + '/view/PropertyCompositeView',
modulePath + '/view/PropertyStackView',
modulePath + '/view/LayerView',
],
function(
@ -24,6 +25,7 @@ define([
PropertyIntegerView,
PropertyColorView,
PropertyCompositeView,
PropertyStackView,
LayerView
) {
@ -199,6 +201,7 @@ define([
PropertyIntegerView.run();
PropertyColorView.run();
PropertyCompositeView.run();
PropertyStackView.run();
LayerView.run();
});

282
test/specs/style_manager/view/PropertyStackView.js

@ -0,0 +1,282 @@
var path = 'StyleManager/view/';
define([path + 'PropertyStackView', 'StyleManager/model/Property', 'DomComponents/model/Component'],
function(PropertyStackView, Property, Component) {
return {
run : function(){
describe('PropertyStackView', function() {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propName = 'testprop';
var propValue = 'test1value';
var defValue = 'test2value';
var layers = [
{value: 'lval1'},
{value: 'lval2 lval22'},
{value: 'lval3 lval32 lval33'}
];
var properties = [
{property: 'subprop1'},
{
type: 'integer',
property: 'subprop2',
defaults: 0,
units: ['%', 'px']
},
{
type: 'select',
property: 'subprop3',
defaults: 'val2',
list: [
{value:'val1'},
{value:'val2'},
{value:'val3'},
]
},
];
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
beforeEach(function () {
target = new Component();
component = new Component();
target.model = component;
model = new Property({
type: 'stack',
property: propName,
properties: properties
});
view = new PropertyStackView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(function () {
//view.remove(); // strange errors ???
});
after(function () {
$fixture.remove();
delete component;
delete view;
delete model;
});
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;
prop.querySelector('#add').should.be.ok;
});
it('Layers rendered', function() {
view.el.querySelector('.layers').should.be.ok;
});
it('Layers should exist', function() {
view.$props.should.be.ok;
});
it('Layers rendered correctly', function() {
var children = view.$props.get(0).children;
children.length.should.equal(properties.length + 1);
children[0].id.should.equal(properties[0].property);
children[1].id.should.equal(properties[1].property);
children[2].id.should.equal(properties[2].property);
});
it('Input value is empty', function() {
view.model.get('value').should.be.empty;
});
it('Layers container is empty', function() {
var layers = view.el.querySelector('.layers');
layers.innerHTML.should.be.empty;
});
describe('With layers', function() {
beforeEach(function () {
model = new Property({
type: 'stack',
property: propName,
properties: properties,
});
view = new PropertyStackView({
model: model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
model.get('layers').add(layers);
});
it('Layers inserted', function() {
view.getLayers().length.should.equal(layers.length);
});
it('Get value on index', function() {
view.model.set('stackIndex', 1);
view.valueOnIndex(1).should.equal('lval22');
});
it('createValue merges layers', function() {
view.createValue().should.equal('lval1, lval2 lval22, lval3 lval32 lval33');
});
it('Add layer', function() {
view.addLayer();
view.getLayers().length.should.equal(layers.length+1);
});
});
describe('With target setted', function() {
var prop2Val;
var prop3Val;
var prop2Unit;
var finalResult;
var $prop1;
var $prop2;
var $prop3;
beforeEach(function () {
model = new Property({
type: 'stack',
property: propName,
properties: properties
});
view = new PropertyStackView({
model: model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
prop3Val = properties[2].list[2].value;
prop2Val = properties[1].defaults;
prop2Unit = properties[1].units[0];
finalResult = propValue + ' ' + prop2Val + prop2Unit +' ' + prop3Val;
$prop1 = view.$props.find('#' + properties[0].property + ' input');
$prop2 = view.$props.find('#' + properties[1].property + ' input');
$prop3 = view.$props.find('#' + properties[2].property + ' select');
});
it('Update model on input change', function() {
$prop1.val(propValue).trigger('change');
$prop3.val(prop3Val).trigger('change');
view.model.get('value').should.equal(finalResult);
});
it('Update value on models change', function() {
view.model.get('properties').at(0).set('value', propValue);
view.model.get('properties').at(2).set('value', prop3Val);
view.model.get('value').should.equal(finalResult);
});
it('Update target on value change', function() {
$prop1.val(propValue).trigger('change');
var compStyle = view.getTarget().get('style');
var assertStyle = {};
assertStyle[propName] = propValue + ' 0% val2';
compStyle.should.deep.equal(assertStyle);
});
it('Update target on detached value change', function() {
model = new Property({
type: 'stack',
property: propName,
properties: properties,
detached: true,
});
view = new PropertyStackView({
model: model,
propTarget: target
});
$fixture.html(view.render().el);
$prop1 = view.$props.find('#' + properties[0].property + ' input');
$prop1.val(propValue).trigger('change');
var compStyle = view.getTarget().get('style');
var assertStyle = {};
assertStyle[properties[0].property] = $prop1.val();
compStyle.should.deep.equal(assertStyle);
});
it('Update value and input on target swap', function() {
var style = {};
style[propName] = finalResult;
component.set('style', style);
view.propTarget.trigger('update');
$prop1.val().should.equal(propValue);
$prop3.val().should.equal(prop3Val);
});
it('Update value after multiple swaps', function() {
var style = {};
style[propName] = finalResult;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = propValue + '2 ' + prop2Val + '2' + prop2Unit + ' ' + 'val1';
component.set('style', style);
view.propTarget.trigger('update');
$prop1.val().should.equal(propValue + '2');
$prop2.val().should.equal('2');
$prop3.val().should.equal('val1');
});
it('The value is correctly extracted from the composite string', function() {
var style = {};
style[propName] = 'value1 value2 value3 value4';
component.set('style', style);
view.valueOnIndex(2).should.equal('value3');
view.valueOnIndex(0).should.equal('value1');
(view.valueOnIndex(4) === null).should.equal(true);
});
it('Build value from properties', function() {
view.model.get('properties').at(0).set('value', propValue);
view.model.get('properties').at(2).set('value', prop3Val);
view.build().should.equal(finalResult);
});
})
describe('Init property', function() {
beforeEach(function () {
model = new Property({
type: 'stack',
property: propName,
properties: properties,
defaults: defValue,
});
view = new PropertyStackView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', function() {
view.model.get('value').should.equal(defValue);
});
});
});
}
};
});

14
test/specs/style_manager/view/PropertyView.js

@ -163,6 +163,20 @@ define([path + 'PropertyView', 'StyleManager/model/Property', 'DomComponents/mod
$fixture.html(view.render().el);
});
it('updateTargetStyle', function() {
view.updateTargetStyle(propValue);
var style = {};
style[propName] = propValue;
component.get('style').should.deep.equal(style);
});
it('updateTargetStyle with custom property', function() {
view.updateTargetStyle(propValue, propName + '2');
var style = {};
style[propName + '2'] = propValue;
component.get('style').should.deep.equal(style);
});
it('Update value and input on target swap', function() {
var style = {};
style[propName] = propValue;

Loading…
Cancel
Save