mirror of https://github.com/artf/grapesjs.git
5 changed files with 336 additions and 348 deletions
@ -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; |
||||
} |
} |
||||
}); |
}); |
||||
}); |
}); |
||||
|
|||||
@ -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; |
||||
}, |
}, |
||||
|
|
||||
}); |
}); |
||||
}); |
}); |
||||
|
|||||
Loading…
Reference in new issue