Browse Source

Fix detached style properties with functionName

pull/79/merge
Artur Arseniev 9 years ago
parent
commit
4724b50384
  1. 2
      bower.json
  2. 10
      dist/grapes.min.js
  3. 2
      index.html
  4. 2
      package.json
  5. 2
      src/commands/main.js
  6. 43
      src/style_manager/model/Layer.js
  7. 3
      src/style_manager/model/PropertyFactory.js
  8. 351
      src/style_manager/view/LayerView.js
  9. 283
      src/style_manager/view/PropertyCompositeView.js
  10. 263
      src/style_manager/view/PropertyFileView.js
  11. 63
      src/style_manager/view/PropertyIntegerView.js
  12. 94
      src/style_manager/view/PropertyStackView.js
  13. 61
      src/style_manager/view/PropertyView.js
  14. 2
      src/utils/Sorter.js
  15. 2
      test/specs/dom_components/view/ComponentTextView.js
  16. 10
      test/specs/dom_components/view/ComponentV.js

2
bower.json

@ -1,7 +1,7 @@
{ {
"name": "grapesjs", "name": "grapesjs",
"description": "Open source Web Template Editor", "description": "Open source Web Template Editor",
"version": "0.5.27", "version": "0.5.28",
"author": "Artur Arseniev", "author": "Artur Arseniev",
"homepage": "http://grapesjs.com", "homepage": "http://grapesjs.com",
"main": [ "main": [

10
dist/grapes.min.js

File diff suppressed because one or more lines are too long

2
index.html

@ -270,7 +270,7 @@
font-family: Helvetica, serif; font-family: Helvetica, serif;
font-weight: 100; font-weight: 100;
background-image:url("http://grapesjs.com/img/bg-gr-v.png"), url("http://grapesjs.com/img/work-desk.jpg"); background-image:url("http://grapesjs.com/img/bg-gr-v.png"), url("http://grapesjs.com/img/work-desk.jpg");
background-attachment:scroll, scroll; background-attachment: fixed, scroll;
background-position:left top, center center; background-position:left top, center center;
background-repeat:repeat-y, no-repeat; background-repeat:repeat-y, no-repeat;
background-size: contain, cover; background-size: contain, cover;

2
package.json

@ -1,7 +1,7 @@
{ {
"name": "grapesjs", "name": "grapesjs",
"description": "Open source Web Template Editor", "description": "Open source Web Template Editor",
"version": "0.5.27", "version": "0.5.28",
"author": "Artur Arseniev", "author": "Artur Arseniev",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"homepage": "http://grapesjs.com", "homepage": "http://grapesjs.com",

2
src/commands/main.js

@ -146,9 +146,7 @@ define(function(require) {
return; return;
} }
var toolbarEl = ed.Canvas.getToolbarEl(); var toolbarEl = ed.Canvas.getToolbarEl();
var toolbarDisplay = toolbarEl.style.display;
var cmdMove = ed.Commands.get('move-comp'); var cmdMove = ed.Commands.get('move-comp');
cmdMove.onEndMoveFromModel = function() { cmdMove.onEndMoveFromModel = function() {

43
src/style_manager/model/Layer.js

@ -1,31 +1,32 @@
define(['backbone'], define(['backbone'],
function(Backbone) { function(Backbone) {
return Backbone.Model.extend({ return Backbone.Model.extend({
defaults: { defaults: {
index: '', index: '',
active: true, value: '',
value: '', values: {},
values: {}, active: true,
preview: false, preview: false,
}, },
initialize: function(){ initialize: function(){
var value = this.get('value'); var value = this.get('value');
// If there is no value I'll try to get it from values // If there is no value I'll try to get it from values
// I need value setted to make preview working // I need value setted to make preview working
if(!value){ if(!value){
var val = ''; var val = '';
var values = this.get('values'); var values = this.get('values');
for(var prop in values) for (var prop in values) {
val += ' ' + values[prop]; val += ' ' + values[prop];
}
this.set('value', val.trim()); this.set('value', val.trim());
} }
}, },
}); });
}); });

3
src/style_manager/model/PropertyFactory.js

@ -254,6 +254,9 @@ define(['backbone'],
case 'transform-scale-z': case 'transform-scale-z':
obj.functionName = 'scaleZ'; obj.functionName = 'scaleZ';
break; break;
case 'background-image':
obj.functionName = 'url';
break;
} }
// Options // Options

351
src/style_manager/view/LayerView.js

@ -1,175 +1,180 @@
define(['backbone', 'text!./../templates/layer.html'], define(['backbone', 'text!./../templates/layer.html'],
function (Backbone, layerTemplate) { function (Backbone, layerTemplate) {
/** /**
* @class LayerView * @class LayerView
* */ * */
return Backbone.View.extend({ return Backbone.View.extend({
events:{ events:{
'click': 'updateIndex', 'click': 'updateIndex',
}, },
template: _.template(layerTemplate), template: _.template(layerTemplate),
initialize: function(o) { initialize: function(o) {
this.stackModel = o.stackModel || {}; this.stackModel = o.stackModel || {};
this.config = o.config || {}; this.config = o.config || {};
this.pfx = this.config.stylePrefix || ''; this.pfx = this.config.stylePrefix || '';
this.className = this.pfx + 'layer'; this.className = this.pfx + 'layer';
this.sorter = o.sorter || null; this.sorter = o.sorter || null;
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, 'change:props', this.showProps); this.listenTo(this.model, 'change:props', this.showProps);
this.events['click #' + this.pfx + 'close-layer'] = 'remove'; this.events['click #' + this.pfx + 'close-layer'] = 'remove';
this.events['mousedown > #' + this.pfx + 'move'] = 'initSorter'; this.events['mousedown > #' + this.pfx + 'move'] = 'initSorter';
if( !this.model.get('preview') ){ if( !this.model.get('preview') ){
this.$el.addClass(this.pfx + 'no-preview'); this.$el.addClass(this.pfx + 'no-preview');
} }
this.$el.data('model', this.model); this.$el.data('model', this.model);
this.delegateEvents(); this.delegateEvents();
}, },
/** /**
* Delegate sorting * Delegate sorting
* @param {Event} e * @param {Event} e
* */ * */
initSorter: function(e){ initSorter: function(e){
if(this.sorter) if(this.sorter)
this.sorter.startSort(this.el); this.sorter.startSort(this.el);
}, },
/** /**
* Returns properties * Returns properties
* @return {Collection|null} * @return {Collection|null}
*/ */
getProps: function(){ getProps: function(){
if(this.stackModel.get) if(this.stackModel.get)
return this.stackModel.get('properties'); return this.stackModel.get('properties');
else else
return null; return null;
}, },
/** /**
* Emitted when the value is changed * Emitted when the value is changed
*/ */
valueChanged: function(){ valueChanged: function() {
var preview = this.model.get('preview'); var preview = this.model.get('preview');
if(!preview) if(!preview)
return; return;
if(!this.$preview) if(!this.$preview)
this.$preview = this.$el.find('#' + this.pfx + 'preview'); this.$preview = this.$el.find('#' + this.pfx + 'preview');
var prw = ''; var prw = '';
if(typeof preview === "function") var props = this.getProps();
preview(this.getProps(), this.$preview); var previewEl = this.$preview;
else if (typeof preview === 'function') {
this.onPreview(this.getProps(), this.$preview); preview(props, previewEl);
}, } else {
this.onPreview(props, previewEl);
/** }
* Default method for changing preview box },
* @param {Collection} props
* @param {Element} $el /**
*/ * Default method for changing preview box
onPreview: function(props, $el){ * @param {Collection} props
var aV = this.model.get('value').split(' '); * @param {Element} $el
var lim = 3; */
var nV = ''; onPreview: function(props, $el) {
props.each(function(p, index){ var aV = this.model.get('value').split(' ');
var v = aV[index] || ''; var lim = 3;
if(v){ var nV = '';
if(p.get('type') == 'integer'){ props.each(function(p, index){
var vI = parseInt(v, 10), var v = aV[index] || '';
u = v.replace(vI,''); if(v){
vI = !isNaN(vI) ? vI : 0; if(p.get('type') == 'integer'){
if(vI > lim) var vI = parseInt(v, 10),
vI = lim; u = v.replace(vI,'');
if(vI < -lim) vI = !isNaN(vI) ? vI : 0;
vI = -lim; if(vI > lim)
v = vI + u; vI = lim;
} if(vI < -lim)
} vI = -lim;
nV += v + ' '; v = vI + u;
}); }
}
if(this.stackModel.get){ nV += v + ' ';
var property = this.stackModel.get('property'); });
if(property)
this.$preview.get(0).style[property] = nV; if(this.stackModel.get){
} var property = this.stackModel.get('property');
}, if(property)
this.$preview.get(0).style[property] = nV;
/** }
* Show inputs on this layer },
* */
showProps:function(){ /**
this.$props = this.model.get('props'); * Show inputs on this layer
this.$el.find('#' + this.pfx + 'inputs').html(this.$props.show()); * */
this.model.set({props: null }, {silent: true }); showProps:function(){
}, this.$props = this.model.get('props');
this.$el.find('#' + this.pfx + 'inputs').html(this.$props.show());
/** @inheritdoc */ this.model.set({props: null }, {silent: true });
remove: function(e){ },
// Prevent from revoming all events on props
if(this.$props) /** @inheritdoc */
this.$props.detach(); remove: function(e){
// Prevent from revoming all events on props
if(e && e.stopPropagation) if(this.$props)
e.stopPropagation(); this.$props.detach();
Backbone.View.prototype.remove.apply(this, arguments); if(e && e.stopPropagation)
e.stopPropagation();
//---
if(this.model.collection.contains(this.model)) Backbone.View.prototype.remove.apply(this, arguments);
this.model.collection.remove(this.model);
//---
if(this.stackModel && this.stackModel.set){ if(this.model.collection.contains(this.model))
this.stackModel.set({stackIndex: null}, {silent: true}); this.model.collection.remove(this.model);
this.stackModel.trigger('updateValue');
} if(this.stackModel && this.stackModel.set){
}, this.stackModel.set({stackIndex: null}, {silent: true});
this.stackModel.trigger('updateValue');
/** }
* Update index },
* @param Event
* /**
* @return void * Update index
* */ * @param Event
updateIndex: function(e){ *
var i = this.getIndex(); * @return void
this.stackModel.set('stackIndex', i); * */
updateIndex: function(e) {
if(this.model.collection) var i = this.getIndex();
this.model.collection.trigger('deselectAll'); this.stackModel.set('stackIndex', i);
this.$el.addClass(this.pfx + 'active'); if(this.model.collection)
}, this.model.collection.trigger('deselectAll');
/** this.$el.addClass(this.pfx + 'active');
* Fetch model index },
* @return {number} Index
*/ /**
getIndex: function(){ * Fetch model index
var index = 0; * @return {number} Index
*/
if(this.model.collection) getIndex: function() {
index = this.model.collection.indexOf(this.model); var index = 0;
var model = this.model;
return index;
}, if (model.collection) {
index = model.collection.indexOf(model);
render : function(){ }
this.$el.html( this.template({
label: 'Layer ' + this.model.get('index'), return index;
pfx: this.pfx, },
}));
this.$el.attr('class', this.className); render : function(){
this.valueChanged(); this.$el.html( this.template({
return this; label: 'Layer ' + this.model.get('index'),
}, pfx: this.pfx,
}));
}); this.$el.attr('class', this.className);
this.valueChanged();
return this;
},
});
}); });

283
src/style_manager/view/PropertyCompositeView.js

@ -1,142 +1,145 @@
define(['backbone','./PropertyView', 'text!./../templates/propertyComposite.html','require'], define(['backbone','./PropertyView', 'text!./../templates/propertyComposite.html','require'],
function (Backbone, PropertyView, propertyTemplate, require) { function (Backbone, PropertyView, propertyTemplate, require) {
/** /**
* @class PropertyCompositeView * @class PropertyCompositeView
* */ * */
return PropertyView.extend({ return PropertyView.extend({
template: _.template(propertyTemplate), template: _.template(propertyTemplate),
initialize: function(o) { initialize: function(o) {
PropertyView.prototype.initialize.apply(this, arguments); PropertyView.prototype.initialize.apply(this, arguments);
_.bindAll(this, 'build'); _.bindAll(this, 'build');
this.config = o.config || {}; this.config = o.config || {};
this.className = this.className + ' '+ this.pfx +'composite'; this.className = this.className + ' '+ this.pfx +'composite';
}, },
/** /**
* 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'))
PropertyView.prototype.valueUpdated.apply(this, arguments); PropertyView.prototype.valueUpdated.apply(this, arguments);
}, },
/** /**
* Renders input * Renders input
* */ * */
renderInput: function() { renderInput: function() {
var props = this.model.get('properties'); var model = this.model;
var detached = this.model.get('detached'); var props = model.get('properties') || [];
if(props && props.length){ var self = this;
if(!this.$input)
this.$input = $('<input>', {value: 0, type: 'hidden' }); if (props.length) {
if(!this.$input)
if(!this.props){ this.$input = $('<input>', {value: 0, type: 'hidden' });
this.props = this.model.get('properties');
} if (!this.props) {
this.props = model.get('properties');
if(!this.$props){ }
//Not yet supported nested composite
this.props.each(function(prop, index){ if (!this.$props) {
if(prop && prop.get('type') == 'composite'){ //Not yet supported nested composite
this.props.remove(prop); this.props.each(function(prop, index) {
console.warn('Nested composite types not yet allowed.'); if(prop && prop.get('type') == 'composite') {
} this.props.remove(prop);
}, this); console.warn('Nested composite types not yet allowed.');
}
var PropertiesView = require('./PropertiesView'); prop.parent = model;
var propsView = new PropertiesView(this.getPropsConfig()); }, this);
this.$props = propsView.render().$el;
this.$el.find('#'+ this.pfx +'input-holder').html(this.$props); var PropertiesView = require('./PropertiesView');
} 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} /**
*/ * Returns configurations that should be past to properties
getPropsConfig: function(opts){ * @param {Object} opts
var that = this; * @return {Object}
*/
result = { getPropsConfig: function(opts){
config: this.config, var that = this;
collection: this.props,
target: this.target, result = {
propTarget: this.propTarget, config: this.config,
// On any change made to children I need to update composite value collection: this.props,
onChange: function(el, view, opts){ target: this.target,
var result = that.build(); propTarget: this.propTarget,
that.model.set('value', result, opts); // On any change made to children I need to update composite value
}, onChange: function(el, view, opts){
// Each child property will receive a full composite string, eg. '0px 0px 10px 0px' var result = that.build();
// I need to extract from that string the corresponding one to that property. that.model.set('value', result, opts);
customValue: function(property, mIndex){ },
return that.valueOnIndex(mIndex, property); // 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);
// If detached let follow its standard flow },
if(this.model.get('detached')) };
delete result.onChange;
// If detached let follow its standard flow
return result; if(this.model.get('detached'))
}, delete result.onChange;
/** return result;
* Get default value of the property },
* @return {string}
* */ /**
getDefaultValue: function(){ * Get default value of the property
var str = ''; * @return {string}
this.props.each(function(prop, index){ * */
str += prop.get('defaults') + prop.get('unit') + ' '; getDefaultValue: function(){
}); var str = '';
return str.replace(/ +$/,''); this.props.each(function(prop, index){
}, str += prop.get('defaults') + prop.get('unit') + ' ';
});
/** return str.replace(/ +$/,'');
* Extract string from composite value },
* @param {number} index Index
* @param {Object} view Property view /**
* @return {string} * Extract string from composite value
* */ * @param {number} index Index
valueOnIndex: function(index, view){ * @param {Object} view Property view
var result = null; * @return {string}
var a = this.getComponentValue().split(' '); * */
if(a.length && a[index]){ valueOnIndex: function(index, view){
result = a[index]; var result = null;
if(view && view.model && view.model.get('functionName')){ var a = this.getComponentValue().split(' ');
var v = this.fetchFromFunction(result); if(a.length && a[index]){
if(v) result = a[index];
result = v; if(view && view.model && view.model.get('functionName')){
} var v = this.fetchFromFunction(result);
} if(v)
return result; result = v;
}, }
}
/** return result;
* Build composite value },
* @param {Object} selectedEl Selected element
* @param {Object} propertyView Property view /**
* @param {Object} opts Options * Build composite value
* @return {string} * @param {Object} selectedEl Selected element
* */ * @param {Object} propertyView Property view
build: function(selectedEl, propertyView, opts){ * @param {Object} opts Options
var result = ''; * @return {string}
this.model.get('properties').each(function(prop){ * */
var v = prop.getValue(); build: function(selectedEl, propertyView, opts){
func = prop.get('functionName'); var result = '';
this.model.get('properties').each(function(prop){
if(func) var v = prop.getValue();
v = func + '(' + v + ')'; func = prop.get('functionName');
result += v + ' '; if(func)
}); v = func + '(' + v + ')';
return result.replace(/ +$/,'');
}, result += v + ' ';
});
}); return result.replace(/ +$/,'');
},
});
}); });

263
src/style_manager/view/PropertyFileView.js

@ -1,134 +1,133 @@
define(['backbone','./PropertyView', 'text!./../templates/propertyFile.html'], define(['backbone','./PropertyView', 'text!./../templates/propertyFile.html'],
function (Backbone, PropertyView, propertyTemplate) { function (Backbone, PropertyView, propertyTemplate) {
/** /**
* @class PropertyColorView * @class PropertyColorView
* */ * */
return PropertyView.extend({ return PropertyView.extend({
template: _.template(propertyTemplate), template: _.template(propertyTemplate),
initialize: function(options) { initialize: function(options) {
PropertyView.prototype.initialize.apply(this, arguments); PropertyView.prototype.initialize.apply(this, arguments);
this.assets = this.target.get('assets'); this.assets = this.target.get('assets');
this.modal = this.target.get('Modal'); this.modal = this.target.get('Modal');
this.am = this.target.get('AssetManager'); this.am = this.target.get('AssetManager');
this.className = this.className + ' '+ this.pfx +'file'; this.className = this.className + ' '+ this.pfx +'file';
this.events['click #'+this.pfx+'close'] = 'removeFile'; this.events['click #'+this.pfx+'close'] = 'removeFile';
this.events['click #'+this.pfx+'images'] = 'openAssetManager'; this.events['click #'+this.pfx+'images'] = 'openAssetManager';
this.delegateEvents(); this.delegateEvents();
}, },
/** @inheritdoc */ /** @inheritdoc */
renderInput: function() { renderInput: function() {
if (!this.$input) {
if(!this.$input){ this.$input = $('<input>', {placeholder: this.defaultValue, type: 'text' });
this.$input = $('<input>', {placeholder: this.defaultValue, type: 'text' }); }
}
if (!this.$preview) {
if(!this.$preview){ this.$preview = this.$el.find('#' + this.pfx + 'preview-file');
this.$preview = this.$el.find('#' + this.pfx + 'preview-file'); }
}
if (!this.$previewBox) {
if(!this.$previewBox){ this.$previewBox = this.$el.find('#' + this.pfx + 'preview-box');
this.$previewBox = this.$el.find('#' + this.pfx + 'preview-box'); }
}
if(!this.componentValue || this.componentValue == this.defaultValue)
if(!this.componentValue || this.componentValue == this.defaultValue) this.setPreviewView(0);
this.setPreviewView(0); else
else this.setPreviewView(1);
this.setPreviewView(1);
this.setValue(this.componentValue, 0);
this.setValue(this.componentValue,0); },
},
/**
/** * Change visibility of the preview box
* Change visibility of the preview box * @param bool Visibility
* @param bool Visibility *
* * @return void
* @return void * */
* */ setPreviewView: function(v){
setPreviewView: function(v){ if(!this.$previewBox)
if(!this.$previewBox) return;
return; if(v)
if(v) this.$previewBox.addClass(this.pfx + 'show');
this.$previewBox.addClass(this.pfx + 'show'); else
else this.$previewBox.removeClass(this.pfx + 'show');
this.$previewBox.removeClass(this.pfx + 'show'); },
},
/**
/** * Spread url
* Spread url * @param string Url
* @param string Url *
* * @return void
* @return void * */
* */ spreadUrl: function(url) {
spreadUrl: function(url){ this.setValue(url);
this.setValue('url("'+url+'")'); this.setPreviewView(1);
this.setPreviewView(1); },
},
/**
/** * Shows file preview
* Shows file preview * @param string Value
* @param string Value * */
* */ setPreview: function(url) {
setPreview: function(v){ if(this.$preview)
if(this.$preview) this.$preview.css('background-image', "url(" + url + ")");
this.$preview.css('background-image',v); },
},
/** @inheritdoc */
/** @inheritdoc */ setValue: function(value, f){
setValue: function(value, f){ PropertyView.prototype.setValue.apply(this, arguments);
PropertyView.prototype.setValue.apply(this, arguments); this.setPreview(value);
this.setPreview(value); },
},
/** @inheritdoc */
/** @inheritdoc */ renderTemplate: function(){
renderTemplate: function(){ this.$el.append( this.template({
this.$el.append( this.template({ upload : 'Upload',
upload : 'Upload', assets : 'Images',
assets : 'Images', pfx : this.pfx
pfx : this.pfx }));
})); },
},
/** @inheritdoc */
/** @inheritdoc */ cleanValue: function(){
cleanValue: function(){ this.setPreviewView(0);
this.setPreviewView(0); this.model.set({value: ''},{silent: true});
this.model.set({value: ''},{silent: true}); },
},
/**
/** * Remove file from input
* Remove file from input *
* * @return void
* @return void * */
* */ removeFile:function(){
removeFile:function(){ this.model.set('value',this.defaultValue);
this.model.set('value',this.defaultValue); PropertyView.prototype.cleanValue.apply(this, arguments);
PropertyView.prototype.cleanValue.apply(this, arguments); this.setPreviewView(0);
this.setPreviewView(0); },
},
/**
/** * Open dialog for image selecting
* Open dialog for image selecting * @param {Object} e Event
* @param {Object} e Event *
* * @return void
* @return void * */
* */ openAssetManager: function(e){
openAssetManager: function(e){ var that = this;
var that = this; if(this.modal && this.am){
if(this.modal && this.am){ this.modal.setTitle('Select image');
this.modal.setTitle('Select image'); this.modal.setContent(this.am.render());
this.modal.setContent(this.am.render()); this.am.setTarget(null);
this.am.setTarget(null); this.modal.open();
this.modal.open(); this.am.onSelect(function(model){
this.am.onSelect(function(model){ that.modal.close();
that.modal.close(); that.spreadUrl(model.get('src'));
that.spreadUrl(model.get('src')); that.valueChanged(e);
that.valueChanged(e); });
}); }
} },
},
});
});
}); });

63
src/style_manager/view/PropertyIntegerView.js

@ -1,40 +1,41 @@
define(['backbone','./PropertyView', 'Abstract/ui/InputNumber'], define(['backbone','./PropertyView', 'Abstract/ui/InputNumber'],
function (Backbone, PropertyView, InputNumber) { function (Backbone, PropertyView, InputNumber) {
return PropertyView.extend({ return PropertyView.extend({
initialize: function(options) { initialize: function(options) {
PropertyView.prototype.initialize.apply(this, arguments); PropertyView.prototype.initialize.apply(this, arguments);
this.listenTo( this.model ,'change:unit', this.valueChanged); this.listenTo( this.model ,'change:unit', this.valueChanged);
}, },
/** /**
* Returns value from inputs * Returns value from inputs
* @return {string} * @return {string}
*/ */
getValueForTarget: function(){ getValueForTarget: function() {
return this.model.get('value') + this.model.get('unit'); var model = this.model;
}, return model.get('value') + model.get('unit');
},
renderInput: function() { renderInput: function() {
if (!this.input) { if (!this.input) {
var inputNumber = new InputNumber({ var inputNumber = new InputNumber({
model: this.model, model: this.model,
ppfx: this.ppfx ppfx: this.ppfx
}); });
this.input = inputNumber.render(); this.input = inputNumber.render();
this.$el.append(this.input.$el); this.$el.append(this.input.$el);
this.$input = this.input.inputEl; this.$input = this.input.inputEl;
this.$unit = this.input.unitEl; this.$unit = this.input.unitEl;
} }
this.setValue(this.componentValue); this.setValue(this.componentValue);
}, },
renderTemplate: function(){}, renderTemplate: function(){},
setValue: function(value) { setValue: function(value) {
this.input.setValue(value, {silent: 1}); this.input.setValue(value, {silent: 1});
}, },
}); });
}); });

94
src/style_manager/view/PropertyStackView.js

@ -28,6 +28,12 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
else { else {
this.checkVisibility(); this.checkVisibility();
this.refreshLayers(); this.refreshLayers();
/*
this.model.get('properties').each(function(prop) {
console.log(prop.get('property'), ' - ', prop.get('value'));
});
*/
} }
}, },
@ -47,10 +53,11 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
* *
* @return {Object} * @return {Object}
* */ * */
indexChanged: function(e){ indexChanged: function(e) {
var layer = this.getLayers().at(this.model.get('stackIndex')); var model = this.model;
var layer = this.getLayers().at(model.get('stackIndex'));
layer.set('props', this.$props); layer.set('props', this.$props);
this.model.get('properties').each(function(prop){ model.get('properties').each(function (prop) {
prop.trigger('targetUpdated'); prop.trigger('targetUpdated');
}); });
}, },
@ -68,7 +75,7 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
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();
@ -91,21 +98,25 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
}, },
/** /**
* Extract string from composite value * Extract string from the composite value of the target
* @param integer Index * @param {integer} index Property index
* @param View propView Property view * @param {View} propView Property view
* @return string * @return string
* @private
* */ * */
valueOnIndex: function(index, propView){ valueOnIndex: function(index, propView) {
var result = null; var result = null;
var layerIndex = this.model.get('stackIndex');
// 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.getTargetValue().split(',');
result = valist[this.model.get('stackIndex')]; result = valist[layerIndex];
result = result ? result.trim() : result; result = result ? result.trim() : propView.getDefaultValue();
}else{ result = propView.tryFetchFromFunction(result);
var aStack = this.getStackValues(); } else {
var strVar = aStack[this.model.get('stackIndex')]; var aStack = this.getStackValues();
var strVar = aStack[layerIndex];
if(!strVar) if(!strVar)
return; return;
var a = strVar.split(' '); var a = strVar.split(' ');
@ -113,11 +124,15 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
result = a[index]; result = a[index];
} }
} }
return result; return result;
}, },
/** @inheritdoc */ /**
build: function(){ * Build composite value
* @private
* */
build: function() {
var stackIndex = this.model.get('stackIndex'); var stackIndex = this.model.get('stackIndex');
if(stackIndex === null) if(stackIndex === null)
return; return;
@ -148,15 +163,17 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
* *
* @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;
@ -166,11 +183,13 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
/** /**
* Fired when the input value is updated * Fired when the input value is updated
*/ */
valueUpdated: function(){ valueUpdated: function() {
if(!this.model.get('detached')) var model = this.model;
this.model.set('value', this.createValue());
else{ if (!model.get('detached')) {
this.model.get('properties').each(function(prop){ model.set('value', this.createValue());
} else {
model.get('properties').each(function(prop){
prop.trigger('change:value'); prop.trigger('change:value');
}); });
} }
@ -216,15 +235,17 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
* 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();
@ -239,22 +260,25 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
} }
} }
}); });
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')){ var detached = this.model.get('detached');
if (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)
@ -266,17 +290,23 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
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'))
// Avoid updating with detached as it will cause issues on next change
if (!detached) {
this.valueUpdated(); this.valueUpdated();
}
this.model.set({stackIndex: null}, {silent: true}); this.model.set({stackIndex: null}, {silent: true});
}, },

61
src/style_manager/view/PropertyView.js

@ -91,8 +91,8 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
* *
* @return {Boolean} * @return {Boolean}
* */ * */
sameValue: function(){ sameValue: function() {
return this.getComponentValue() == (this.model.get('value') + this.model.get('unit')); return this.getComponentValue() == this.getValueForTarget();
}, },
@ -102,6 +102,7 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
* @return {String} * @return {String}
* */ * */
getComponentValue: function() { getComponentValue: function() {
var propModel = this.model;
var target = this.getTarget(); var target = this.getTarget();
if(!target) if(!target)
@ -114,7 +115,7 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
this.componentValue = this.defaultValue + (this.unit || ''); // todo model this.componentValue = this.defaultValue + (this.unit || ''); // todo model
// Check if wrap inside function is required // Check if wrap inside function is required
if(this.model.get('functionName')){ if (propModel.get('functionName')) {
var v = this.fetchFromFunction(this.componentValue); var v = this.fetchFromFunction(this.componentValue);
if(v) if(v)
this.componentValue = v; this.componentValue = v;
@ -123,7 +124,7 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
// This allow to ovveride the normal flow of selecting component value, // This allow to ovveride the normal flow of selecting component value,
// useful in composite properties // useful in composite properties
if(this.customValue && typeof this.customValue === "function"){ if(this.customValue && typeof this.customValue === "function"){
var index = this.model.collection.indexOf(this.model); var index = propModel.collection.indexOf(propModel);
var t = this.customValue(this, index); var t = this.customValue(this, index);
if(t) if(t)
this.componentValue = t; this.componentValue = t;
@ -132,22 +133,68 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
return this.componentValue; return this.componentValue;
}, },
/**
* Refactor of getComponentValue
* @param {Object} [opts] Options
* @param {Boolean} [options.fetchFromFunction]
* @param {Boolean} [options.ignoreDefault]
* @return string
* @private
*/
getTargetValue: function (opts) {
var result;
var opt = opts || {};
var model = this.model;
var target = this.getTarget();
if (!target) {
return result;
}
result = target.get('style')[model.get('property')];
if (!result && !opt.ignoreDefault) {
result = this.getDefaultValue();
}
return result;
},
/**
* Returns default value
* @return {String}
* @private
*/
getDefaultValue: function () {
return this.model.get('defaults');
},
/** /**
* Fetch the string from function type value * Fetch the string from function type value
* @param {String} v Function type value * @param {String} v Function type value
* *
* @return {String} * @return {String}
* */ * */
fetchFromFunction: function(v){ fetchFromFunction: function(v) {
return v.substring(v.indexOf("(") + 1, v.lastIndexOf(")")); return v.substring(v.indexOf("(") + 1, v.lastIndexOf(")"));
}, },
tryFetchFromFunction: function(value) {
if (!this.model.get('functionName')) {
return value;
}
var start = value.indexOf("(") + 1;
var end = value.lastIndexOf(")");
return value.substring(start, end);
},
/** /**
* Returns value from inputs * Returns value from inputs
* @return {string} * @return {string}
*/ */
getValueForTarget: function(){ getValueForTarget: function() {
return this.model.getValue(); return this.model.get('value');
}, },
/** /**

2
src/utils/Sorter.js

@ -431,7 +431,7 @@ define(function(require) {
// Get children based on getChildrenContainer // Get children based on getChildrenContainer
var $elem = $(elem); var $elem = $(elem);
var elemData = $elem.data('model'); var elemData = $elem.data('model');
if (elemData) { if (elemData && elemData.view) {
elem = elemData.view.getChildrenContainer(); elem = elemData.view.getChildrenContainer();
} }

2
test/specs/dom_components/view/ComponentTextView.js

@ -35,7 +35,7 @@ define([path + 'ComponentTextView', 'DomComponents/model/Component'],
}); });
it('Component empty', function() { it('Component empty', function() {
$fixture.html().should.equal('<div></div>'); $fixture.html().should.equal('<div data-highlightable="1"></div>');
}); });
it('Input content is stored in model', function() { it('Input content is stored in model', function() {

10
test/specs/dom_components/view/ComponentV.js

@ -42,23 +42,23 @@ define([path + 'ComponentView', 'DomComponents/model/Component', 'DomComponents'
}); });
it('Component empty', function() { it('Component empty', function() {
$fixture.html().should.equal('<div></div>'); $fixture.html().should.equal('<div data-highlightable="1"></div>');
}); });
it('Add helper class on update of state', function() { it('Add helper class on update of state', function() {
model.set('state', 'test'); model.set('state', 'test');
$fixture.html().should.equal('<div class="' + hClass + '"></div>'); $fixture.html().should.equal('<div data-highlightable="1" class="' + hClass + '"></div>');
}); });
it('Clean form helper state', function() { it('Clean form helper state', function() {
model.set('state', 'test'); model.set('state', 'test');
model.set('state', ''); model.set('state', '');
$fixture.html().should.equal('<div class=""></div>'); $fixture.html().should.equal('<div data-highlightable="1" class=""></div>');
}); });
it('Add helper class on status update', function() { it('Add helper class on status update', function() {
model.set('status', 'selected'); model.set('status', 'selected');
$fixture.html().should.equal('<div class="selected"></div>'); $fixture.html().should.equal('<div data-highlightable="1" class="selected"></div>');
}); });
it('Get string of classes', function() { it('Get string of classes', function() {
@ -131,7 +131,7 @@ define([path + 'ComponentView', 'DomComponents/model/Component', 'DomComponents'
model: model, model: model,
defaultTypes: dcomp.componentTypes, defaultTypes: dcomp.componentTypes,
}); });
view.render().$el.html().should.equal('<span></span><div title="test"></div>'); view.render().$el.html().should.equal('<span data-highlightable="1"></span><div title="test" data-highlightable="1"></div>');
}); });
}); });

Loading…
Cancel
Save