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,
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',
open: false,
properties: [{

112
src/style_manager/view/PropertiesView.js

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

522
src/style_manager/view/PropertyStackView.js

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

Loading…
Cancel
Save