Browse Source

Fix checkVisibility for detached properties (eg. background)

pull/79/merge
Artur Arseniev 10 years ago
parent
commit
49264becd6
  1. 22
      src/demo.js
  2. 112
      src/style_manager/view/PropertiesView.js
  3. 522
      src/style_manager/view/PropertyStackView.js
  4. 25
      src/style_manager/view/PropertyView.js
  5. 3
      src/style_manager/view/SectorView.js

22
src/demo.js

@ -158,28 +158,6 @@ require(['config/require-config'], function() {
open: false, open: false,
buildProps: ['transition', 'perspective', 'transform'], buildProps: ['transition', 'perspective', 'transform'],
},{ },{
name: 'Dimension',
open: false,
buildProps: ['margin'],
properties:[{
name: 'Marginnnn',
property: 'margin',
type: 'composite',
properties:[{
name: 'Top',
property: 'margin-top',
},{
name: 'Right',
property: 'margin-right',
},{
name: 'Bottom',
property: 'margin-bottom',
},{
name: 'Left',
property: 'margin-left',
},],
}],
},{
name: 'Flex', name: 'Flex',
open: false, open: false,
properties: [{ properties: [{

112
src/style_manager/view/PropertiesView.js

@ -1,67 +1,67 @@
define(['backbone','./PropertyView', './PropertyIntegerView', './PropertyRadioView', './PropertySelectView', define(['backbone','./PropertyView', './PropertyIntegerView', './PropertyRadioView', './PropertySelectView',
'./PropertyColorView', './PropertyFileView', './PropertyCompositeView', './PropertyStackView'], './PropertyColorView', './PropertyFileView', './PropertyCompositeView', './PropertyStackView'],
function (Backbone, PropertyView, PropertyIntegerView, PropertyRadioView, PropertySelectView, function (Backbone, PropertyView, PropertyIntegerView, PropertyRadioView, PropertySelectView,
PropertyColorView, PropertyFileView, PropertyCompositeView, PropertyStackView) { PropertyColorView, PropertyFileView, PropertyCompositeView, PropertyStackView) {
/** /**
* @class PropertiesView * @class PropertiesView
* */ * */
return Backbone.View.extend({ return Backbone.View.extend({
initialize: function(o) { initialize: function(o) {
this.config = o.config || {}; this.config = o.config || {};
this.pfx = this.config.stylePrefix || ''; this.pfx = this.config.stylePrefix || '';
this.target = o.target || {}; this.target = o.target || {};
this.propTarget = o.propTarget || {}; this.propTarget = o.propTarget || {};
this.onChange = o.onChange || {}; this.onChange = o.onChange || {};
this.onInputRender = o.onInputRender || {}; this.onInputRender = o.onInputRender || {};
this.customValue = o.customValue || {}; this.customValue = o.customValue || {};
}, },
render: function() { render: function() {
var fragment = document.createDocumentFragment(); var fragment = document.createDocumentFragment();
this.collection.each(function(model){ this.collection.each(function(model){
var objView = PropertyView; var objView = PropertyView;
switch(model.get('type')){ switch(model.get('type')){
case 'integer': case 'integer':
objView = PropertyIntegerView; break; objView = PropertyIntegerView; break;
case 'radio': case 'radio':
objView = PropertyRadioView; break; objView = PropertyRadioView; break;
case 'select': case 'select':
objView = PropertySelectView; break; objView = PropertySelectView; break;
case 'color': case 'color':
objView = PropertyColorView; break; objView = PropertyColorView; break;
case 'file': case 'file':
objView = PropertyFileView; break; objView = PropertyFileView; break;
case 'composite': case 'composite':
objView = PropertyCompositeView;break; objView = PropertyCompositeView;break;
case 'stack': case 'stack':
objView = PropertyStackView; break; objView = PropertyStackView; break;
} }
var view = new objView({ var view = new objView({
model: model, model: model,
name: model.get('name'), name: model.get('name'),
id: this.pfx + model.get('property'), id: this.pfx + model.get('property'),
target: this.target, target: this.target,
propTarget: this.propTarget, propTarget: this.propTarget,
onChange: this.onChange, onChange: this.onChange,
onInputRender: this.onInputRender, onInputRender: this.onInputRender,
config: this.config, config: this.config,
}); });
if(model.get('type') != 'composite'){ if(model.get('type') != 'composite'){
view.customValue = this.customValue; view.customValue = this.customValue;
} }
fragment.appendChild(view.render().el); fragment.appendChild(view.render().el);
},this); },this);
this.$el.append(fragment); this.$el.append(fragment);
this.$el.append($('<div>', {class: "clear"})); this.$el.append($('<div>', {class: "clear"}));
this.$el.attr('class', this.pfx + 'properties'); this.$el.attr('class', this.pfx + 'properties');
return this; return this;
} }
}); });
}); });

522
src/style_manager/view/PropertyStackView.js

@ -1,290 +1,292 @@
define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack.html','./../model/Layers','./LayersView'], define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack.html','./../model/Layers','./LayersView'],
function (Backbone, PropertyCompositeView, propertyTemplate, Layers, LayersView) { function (Backbone, PropertyCompositeView, propertyTemplate, Layers, LayersView) {
/** /**
* @class PropertyStackView * @class PropertyStackView
* */ * */
return PropertyCompositeView.extend({ return PropertyCompositeView.extend({
template: _.template(propertyTemplate), template: _.template(propertyTemplate),
initialize: function(o) { initialize: function(o) {
PropertyCompositeView.prototype.initialize.apply(this, arguments); PropertyCompositeView.prototype.initialize.apply(this, arguments);
this.model.set('stackIndex', null); this.model.set('stackIndex', null);
this.className = this.pfx + 'property '+ this.pfx +'stack'; this.className = this.pfx + 'property '+ this.pfx +'stack';
this.events['click #'+this.pfx+'add'] = 'addLayer'; this.events['click #'+this.pfx+'add'] = 'addLayer';
this.listenTo( this.model ,'change:stackIndex', this.indexChanged); this.listenTo( this.model ,'change:stackIndex', this.indexChanged);
this.listenTo( this.model ,'updateValue', this.valueUpdated); this.listenTo( this.model ,'updateValue', this.valueUpdated);
this.delegateEvents(); this.delegateEvents();
}, },
/** /**
* Fired when the target is updated. * Fired when the target is updated.
* With detached mode the component will be always empty as its value * With detached mode the component will be always empty as its value
* so we gonna check all props and fine if there is some differences. * so we gonna check all props and fine if there is some differences.
* */ * */
targetUpdated: function(){ targetUpdated: function(){
if(!this.model.get('detached')) if(!this.model.get('detached'))
PropertyCompositeView.prototype.targetUpdated.apply(this, arguments); PropertyCompositeView.prototype.targetUpdated.apply(this, arguments);
else else {
this.refreshLayers(); this.checkVisibility();
}, this.refreshLayers();
}
},
/** /**
* Returns the collection of layers * Returns the collection of layers
* @return {Collection} * @return {Collection}
*/ */
getLayers: function(){ getLayers: function(){
return this.model.get('layers'); return this.model.get('layers');
}, },
/** /**
* Triggered when another layer has been selected. * Triggered when another layer has been selected.
* This allow to move all rendered properties to a new * This allow to move all rendered properties to a new
* selected layer * selected layer
* @param {Event} * @param {Event}
* *
* @return {Object} * @return {Object}
* */ * */
indexChanged: function(e){ indexChanged: function(e){
var layer = this.getLayers().at(this.model.get('stackIndex')); var layer = this.getLayers().at(this.model.get('stackIndex'));
layer.set('props', this.$props); layer.set('props', this.$props);
this.model.get('properties').each(function(prop){ this.model.get('properties').each(function(prop){
prop.trigger('targetUpdated'); prop.trigger('targetUpdated');
}); });
}, },
/** /**
* Get array of values from layers * Get array of values from layers
* @return Array * @return Array
* */ * */
getStackValues: function(){ getStackValues: function(){
return this.getLayers().pluck('value'); return this.getLayers().pluck('value');
}, },
/** @inheritDoc */ /** @inheritDoc */
getPropsConfig: function(opts){ getPropsConfig: function(opts){
var that = this; var that = this;
var result = PropertyCompositeView.prototype.getPropsConfig.apply(this, arguments); var result = PropertyCompositeView.prototype.getPropsConfig.apply(this, arguments);
result.onChange = function(el, view, opt){ result.onChange = function(el, view, opt){
var model = view.model; var model = view.model;
var result = that.build(); var result = that.build();
if(that.model.get('detached')){ if(that.model.get('detached')){
var propVal = ''; var propVal = '';
var index = model.collection.indexOf(model); var index = model.collection.indexOf(model);
that.getLayers().each(function(layer){ that.getLayers().each(function(layer){
var val = layer.get('values')[model.get('property')]; var val = layer.get('values')[model.get('property')];
if(val) if(val)
propVal += (propVal ? ',' : '') + val; propVal += (propVal ? ',' : '') + val;
}); });
view.updateTargetStyle(propVal, null, opt); view.updateTargetStyle(propVal, null, opt);
}else }else
that.model.set('value', result, opt); that.model.set('value', result, opt);
}; };
return result; return result;
}, },
/** /**
* Extract string from composite value * Extract string from composite value
* @param integer Index * @param integer Index
* @param View propView Property view * @param View propView Property view
* @return string * @return string
* */ * */
valueOnIndex: function(index, propView){ valueOnIndex: function(index, propView){
var result = null; var result = null;
// If detached the value in this case is stacked, eg. substack-prop: 1px, 2px, 3px... // If detached the value in this case is stacked, eg. substack-prop: 1px, 2px, 3px...
if(this.model.get('detached')){ if(this.model.get('detached')){
var valist = propView.componentValue.split(','); var valist = propView.componentValue.split(',');
result = valist[this.model.get('stackIndex')]; result = valist[this.model.get('stackIndex')];
result = result ? result.trim() : result; result = result ? result.trim() : result;
}else{ }else{
var aStack = this.getStackValues(); var aStack = this.getStackValues();
var strVar = aStack[this.model.get('stackIndex')]; var strVar = aStack[this.model.get('stackIndex')];
if(!strVar) if(!strVar)
return; return;
var a = strVar.split(' '); var a = strVar.split(' ');
if(a.length && a[index]){ if(a.length && a[index]){
result = a[index]; result = a[index];
} }
} }
return result; return result;
}, },
/** @inheritdoc */ /** @inheritdoc */
build: function(){ build: function(){
var stackIndex = this.model.get('stackIndex'); var stackIndex = this.model.get('stackIndex');
if(stackIndex === null) if(stackIndex === null)
return; return;
var result = PropertyCompositeView.prototype.build.apply(this, arguments); var result = PropertyCompositeView.prototype.build.apply(this, arguments);
var model = this.getLayers().at(stackIndex); var model = this.getLayers().at(stackIndex);
if(!model) if(!model)
return; return;
// Store properties values inside layer, in this way it's more reliable // Store properties values inside layer, in this way it's more reliable
// to fetch them later // to fetch them later
var valObj = {}; var valObj = {};
this.model.get('properties').each(function(prop){ this.model.get('properties').each(function(prop){
var v = prop.getValue(), var v = prop.getValue(),
func = prop.get('functionName'); func = prop.get('functionName');
if(func) if(func)
v = func + '(' + v + ')'; v = func + '(' + v + ')';
valObj[prop.get('property')] = v; valObj[prop.get('property')] = v;
}); });
model.set('values', valObj); model.set('values', valObj);
model.set('value', result); model.set('value', result);
return this.createValue(); return this.createValue();
}, },
/** /**
* Add layer * Add layer
* @param Event * @param Event
* *
* @return Object * @return Object
* */ * */
addLayer: function(e){ addLayer: function(e){
if(this.getTarget()){ if(this.getTarget()){
var layers = this.getLayers(); var layers = this.getLayers();
var layer = layers.add({ name : 'test' }); var layer = layers.add({ name : 'test' });
var index = layers.indexOf(layer); var index = layers.indexOf(layer);
layer.set('value', this.getDefaultValue()); layer.set('value', this.getDefaultValue());
// In detached mode valueUpdated will add new 'layer value' // In detached mode valueUpdated will add new 'layer value'
// to all subprops // to all subprops
this.valueUpdated(); this.valueUpdated();
// This will set subprops with a new default values // This will set subprops with a new default values
this.model.set('stackIndex', index); this.model.set('stackIndex', index);
return layer; return layer;
} }
}, },
/** /**
* Fired when the input value is updated * Fired when the input value is updated
*/ */
valueUpdated: function(){ valueUpdated: function(){
if(!this.model.get('detached')) if(!this.model.get('detached'))
this.model.set('value', this.createValue()); this.model.set('value', this.createValue());
else{ else{
this.model.get('properties').each(function(prop){ this.model.get('properties').each(function(prop){
prop.trigger('change:value'); prop.trigger('change:value');
}); });
} }
}, },
/** /**
* Create value by layers * Create value by layers
* @return string * @return string
* */ * */
createValue: function(){ createValue: function(){
return this.getStackValues().join(', '); return this.getStackValues().join(', ');
}, },
/** /**
* Render layers * Render layers
* @return self * @return self
* */ * */
renderLayers: function() { renderLayers: function() {
if(!this.$field) if(!this.$field)
this.$field = this.$el.find('> .' + this.pfx + 'field'); this.$field = this.$el.find('> .' + this.pfx + 'field');
if(!this.$layers) if(!this.$layers)
this.$layers = new LayersView({ this.$layers = new LayersView({
collection: this.getLayers(), collection: this.getLayers(),
stackModel: this.model, stackModel: this.model,
preview: this.model.get('preview'), preview: this.model.get('preview'),
config: this.config config: this.config
}); });
this.$field.append(this.$layers.render().el); this.$field.append(this.$layers.render().el);
this.$props.hide(); this.$props.hide();
return this; return this;
}, },
/** @inheritdoc */ /** @inheritdoc */
renderInput: function() { renderInput: function() {
PropertyCompositeView.prototype.renderInput.apply(this, arguments); PropertyCompositeView.prototype.renderInput.apply(this, arguments);
this.refreshLayers(); this.refreshLayers();
}, },
/** /**
* Returns array suitale for layers from target style * Returns array suitale for layers from target style
* Only for detached stacks * Only for detached stacks
* @return {Array<string>} * @return {Array<string>}
*/ */
getLayersFromTarget: function(){ getLayersFromTarget: function(){
var arr = []; var arr = [];
var target = this.getTarget(); var target = this.getTarget();
if(!target) if(!target)
return arr; return arr;
var trgStyle = target.get('style'); var trgStyle = target.get('style');
this.model.get('properties').each(function(prop){ this.model.get('properties').each(function(prop){
var style = trgStyle[prop.get('property')]; var style = trgStyle[prop.get('property')];
if(style){ if(style){
var list = style.split(','); var list = style.split(',');
for(var i = 0, len = list.length; i < len; i++){ for(var i = 0, len = list.length; i < len; i++){
var val = list[i].trim(); var val = list[i].trim();
if(arr[i]){ if(arr[i]){
arr[i][prop.get('property')] = val; arr[i][prop.get('property')] = val;
}else{ }else{
var vals = {}; var vals = {};
vals[prop.get('property')] = val; vals[prop.get('property')] = val;
arr[i] = vals; arr[i] = vals;
} }
} }
} }
}); });
return arr; return arr;
}, },
/** /**
* Refresh layers * Refresh layers
* */ * */
refreshLayers: function(){ refreshLayers: function(){
var n = []; var n = [];
var a = []; var a = [];
var fieldName = 'value'; var fieldName = 'value';
if(this.model.get('detached')){ if(this.model.get('detached')){
fieldName = 'values'; fieldName = 'values';
a = this.getLayersFromTarget(); a = this.getLayersFromTarget();
}else{ }else{
var v = this.getComponentValue(); var v = this.getComponentValue();
if(v){ if(v){
// Remove spaces inside functions: // Remove spaces inside functions:
// eg: // eg:
// From: 1px 1px rgba(2px, 2px, 2px), 2px 2px rgba(3px, 3px, 3px) // From: 1px 1px rgba(2px, 2px, 2px), 2px 2px rgba(3px, 3px, 3px)
// To: 1px 1px rgba(2px,2px,2px), 2px 2px rgba(3px,3px,3px) // To: 1px 1px rgba(2px,2px,2px), 2px 2px rgba(3px,3px,3px)
v.replace(/\(([\w\s,.]*)\)/g, function(match){ v.replace(/\(([\w\s,.]*)\)/g, function(match){
var cleaned = match.replace(/,\s*/g, ','); var cleaned = match.replace(/,\s*/g, ',');
v = v.replace(match, cleaned); v = v.replace(match, cleaned);
}); });
a = v.split(', '); a = v.split(', ');
} }
} }
_.each(a, function(e){ _.each(a, function(e){
var o = {}; var o = {};
o[fieldName] = e; o[fieldName] = e;
n.push(o); n.push(o);
},this); },this);
this.$props.detach(); this.$props.detach();
var layers = this.getLayers(); var layers = this.getLayers();
layers.reset(); layers.reset();
layers.add(n); layers.add(n);
if(!this.model.get('detached')) if(!this.model.get('detached'))
this.valueUpdated(); this.valueUpdated();
this.model.set({stackIndex: null}, {silent: true}); this.model.set({stackIndex: null}, {silent: true});
}, },
render : function(){ render : function(){
this.renderLabel(); this.renderLabel();
this.renderField(); this.renderField();
this.renderLayers(); this.renderLayers();
this.$el.attr('class', this.className); this.$el.attr('class', this.className);
return this; return this;
}, },
}); });
}); });

25
src/style_manager/view/PropertyView.js

@ -32,9 +32,13 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
this.listenTo(this.propTarget, 'update', this.targetUpdated); this.listenTo(this.propTarget, 'update', this.targetUpdated);
this.listenTo(this.model, 'destroy remove', this.remove); this.listenTo(this.model, 'destroy remove', this.remove);
this.listenTo(this.model,'change:value', this.valueChanged); this.listenTo(this.model, 'change:value', this.valueChanged);
this.listenTo(this.model,'targetUpdated', this.targetUpdated); this.listenTo(this.model, 'targetUpdated', this.targetUpdated);
this.listenTo(this.model,'change:visible', this.updateVisibility); this.listenTo(this.model, 'change:visible', this.updateVisibility);
if (this.sector && this.sector.get('name') == 'Decorations') {
console.log(this.sector.get('name')+':', this.property, this.model.get('type'));
}
}, },
/** /**
@ -61,7 +65,16 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
targetUpdated: function() { targetUpdated: function() {
this.selectedComponent = this.propTarget.model; this.selectedComponent = this.propTarget.model;
this.helperComponent = this.propTarget.helper; this.helperComponent = this.propTarget.helper;
this.checkVisibility();
if(this.getTarget()) {
if(!this.sameValue()){
this.renderInputRequest();
}
}
},
checkVisibility: function () {
// Check if need to hide the property // Check if need to hide the property
if (this.config.hideNotStylable) { if (this.config.hideNotStylable) {
if (!this.isTargetStylable() || !this.isComponentStylable()) { if (!this.isTargetStylable() || !this.isComponentStylable()) {
@ -74,12 +87,6 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
this.sector.trigger('updateVisibility'); this.sector.trigger('updateVisibility');
} }
} }
if(this.getTarget()){
if(!this.sameValue()){
this.renderInputRequest();
}
}
}, },
/** /**

3
src/style_manager/view/SectorView.js

@ -29,8 +29,9 @@ define(['backbone', './PropertiesView', 'text!./../templates/sector.html'],
updateVisibility: function () { updateVisibility: function () {
var show; var show;
this.model.get('properties').each(function(prop) { this.model.get('properties').each(function(prop) {
if (prop.get('visible')) if (prop.get('visible')) {
show = 1; show = 1;
}
}); });
this.el.style.display = show ? 'block' : 'none'; this.el.style.display = show ? 'block' : 'none';
}, },

Loading…
Cancel
Save