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",
"description": "Open source Web Template Editor",
"version": "0.5.27",
"version": "0.5.28",
"author": "Artur Arseniev",
"homepage": "http://grapesjs.com",
"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-weight: 100;
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-repeat:repeat-y, no-repeat;
background-size: contain, cover;

2
package.json

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

2
src/commands/main.js

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

43
src/style_manager/model/Layer.js

@ -1,31 +1,32 @@
define(['backbone'],
function(Backbone) {
function(Backbone) {
return Backbone.Model.extend({
return Backbone.Model.extend({
defaults: {
index: '',
active: true,
value: '',
values: {},
preview: false,
},
defaults: {
index: '',
value: '',
values: {},
active: true,
preview: false,
},
initialize: function(){
var value = this.get('value');
initialize: function(){
var value = this.get('value');
// If there is no value I'll try to get it from values
// I need value setted to make preview working
if(!value){
var val = '';
var values = this.get('values');
// If there is no value I'll try to get it from values
// I need value setted to make preview working
if(!value){
var val = '';
var values = this.get('values');
for(var prop in values)
val += ' ' + values[prop];
for (var prop in values) {
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':
obj.functionName = 'scaleZ';
break;
case 'background-image':
obj.functionName = 'url';
break;
}
// Options

351
src/style_manager/view/LayerView.js

@ -1,175 +1,180 @@
define(['backbone', 'text!./../templates/layer.html'],
function (Backbone, layerTemplate) {
/**
* @class LayerView
* */
return Backbone.View.extend({
events:{
'click': 'updateIndex',
},
template: _.template(layerTemplate),
initialize: function(o) {
this.stackModel = o.stackModel || {};
this.config = o.config || {};
this.pfx = this.config.stylePrefix || '';
this.className = this.pfx + 'layer';
this.sorter = o.sorter || null;
this.listenTo(this.model, 'destroy remove', this.remove);
this.listenTo(this.model, 'change:value', this.valueChanged);
this.listenTo(this.model, 'change:props', this.showProps);
this.events['click #' + this.pfx + 'close-layer'] = 'remove';
this.events['mousedown > #' + this.pfx + 'move'] = 'initSorter';
if( !this.model.get('preview') ){
this.$el.addClass(this.pfx + 'no-preview');
}
this.$el.data('model', this.model);
this.delegateEvents();
},
/**
* Delegate sorting
* @param {Event} e
* */
initSorter: function(e){
if(this.sorter)
this.sorter.startSort(this.el);
},
/**
* Returns properties
* @return {Collection|null}
*/
getProps: function(){
if(this.stackModel.get)
return this.stackModel.get('properties');
else
return null;
},
/**
* Emitted when the value is changed
*/
valueChanged: function(){
var preview = this.model.get('preview');
if(!preview)
return;
if(!this.$preview)
this.$preview = this.$el.find('#' + this.pfx + 'preview');
var prw = '';
if(typeof preview === "function")
preview(this.getProps(), this.$preview);
else
this.onPreview(this.getProps(), this.$preview);
},
/**
* Default method for changing preview box
* @param {Collection} props
* @param {Element} $el
*/
onPreview: function(props, $el){
var aV = this.model.get('value').split(' ');
var lim = 3;
var nV = '';
props.each(function(p, index){
var v = aV[index] || '';
if(v){
if(p.get('type') == 'integer'){
var vI = parseInt(v, 10),
u = v.replace(vI,'');
vI = !isNaN(vI) ? vI : 0;
if(vI > lim)
vI = lim;
if(vI < -lim)
vI = -lim;
v = vI + u;
}
}
nV += v + ' ';
});
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');
this.$el.find('#' + this.pfx + 'inputs').html(this.$props.show());
this.model.set({props: null }, {silent: true });
},
/** @inheritdoc */
remove: function(e){
// Prevent from revoming all events on props
if(this.$props)
this.$props.detach();
if(e && e.stopPropagation)
e.stopPropagation();
Backbone.View.prototype.remove.apply(this, arguments);
//---
if(this.model.collection.contains(this.model))
this.model.collection.remove(this.model);
if(this.stackModel && this.stackModel.set){
this.stackModel.set({stackIndex: null}, {silent: true});
this.stackModel.trigger('updateValue');
}
},
/**
* Update index
* @param Event
*
* @return void
* */
updateIndex: function(e){
var i = this.getIndex();
this.stackModel.set('stackIndex', i);
if(this.model.collection)
this.model.collection.trigger('deselectAll');
this.$el.addClass(this.pfx + 'active');
},
/**
* Fetch model index
* @return {number} Index
*/
getIndex: function(){
var index = 0;
if(this.model.collection)
index = this.model.collection.indexOf(this.model);
return index;
},
render : function(){
this.$el.html( this.template({
label: 'Layer ' + this.model.get('index'),
pfx: this.pfx,
}));
this.$el.attr('class', this.className);
this.valueChanged();
return this;
},
});
function (Backbone, layerTemplate) {
/**
* @class LayerView
* */
return Backbone.View.extend({
events:{
'click': 'updateIndex',
},
template: _.template(layerTemplate),
initialize: function(o) {
this.stackModel = o.stackModel || {};
this.config = o.config || {};
this.pfx = this.config.stylePrefix || '';
this.className = this.pfx + 'layer';
this.sorter = o.sorter || null;
this.listenTo(this.model, 'destroy remove', this.remove);
this.listenTo(this.model, 'change:value', this.valueChanged);
this.listenTo(this.model, 'change:props', this.showProps);
this.events['click #' + this.pfx + 'close-layer'] = 'remove';
this.events['mousedown > #' + this.pfx + 'move'] = 'initSorter';
if( !this.model.get('preview') ){
this.$el.addClass(this.pfx + 'no-preview');
}
this.$el.data('model', this.model);
this.delegateEvents();
},
/**
* Delegate sorting
* @param {Event} e
* */
initSorter: function(e){
if(this.sorter)
this.sorter.startSort(this.el);
},
/**
* Returns properties
* @return {Collection|null}
*/
getProps: function(){
if(this.stackModel.get)
return this.stackModel.get('properties');
else
return null;
},
/**
* Emitted when the value is changed
*/
valueChanged: function() {
var preview = this.model.get('preview');
if(!preview)
return;
if(!this.$preview)
this.$preview = this.$el.find('#' + this.pfx + 'preview');
var prw = '';
var props = this.getProps();
var previewEl = this.$preview;
if (typeof preview === 'function') {
preview(props, previewEl);
} else {
this.onPreview(props, previewEl);
}
},
/**
* Default method for changing preview box
* @param {Collection} props
* @param {Element} $el
*/
onPreview: function(props, $el) {
var aV = this.model.get('value').split(' ');
var lim = 3;
var nV = '';
props.each(function(p, index){
var v = aV[index] || '';
if(v){
if(p.get('type') == 'integer'){
var vI = parseInt(v, 10),
u = v.replace(vI,'');
vI = !isNaN(vI) ? vI : 0;
if(vI > lim)
vI = lim;
if(vI < -lim)
vI = -lim;
v = vI + u;
}
}
nV += v + ' ';
});
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');
this.$el.find('#' + this.pfx + 'inputs').html(this.$props.show());
this.model.set({props: null }, {silent: true });
},
/** @inheritdoc */
remove: function(e){
// Prevent from revoming all events on props
if(this.$props)
this.$props.detach();
if(e && e.stopPropagation)
e.stopPropagation();
Backbone.View.prototype.remove.apply(this, arguments);
//---
if(this.model.collection.contains(this.model))
this.model.collection.remove(this.model);
if(this.stackModel && this.stackModel.set){
this.stackModel.set({stackIndex: null}, {silent: true});
this.stackModel.trigger('updateValue');
}
},
/**
* Update index
* @param Event
*
* @return void
* */
updateIndex: function(e) {
var i = this.getIndex();
this.stackModel.set('stackIndex', i);
if(this.model.collection)
this.model.collection.trigger('deselectAll');
this.$el.addClass(this.pfx + 'active');
},
/**
* Fetch model index
* @return {number} Index
*/
getIndex: function() {
var index = 0;
var model = this.model;
if (model.collection) {
index = model.collection.indexOf(model);
}
return index;
},
render : function(){
this.$el.html( this.template({
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'],
function (Backbone, PropertyView, propertyTemplate, require) {
/**
* @class PropertyCompositeView
* */
return PropertyView.extend({
template: _.template(propertyTemplate),
initialize: function(o) {
PropertyView.prototype.initialize.apply(this, arguments);
_.bindAll(this, 'build');
this.config = o.config || {};
this.className = this.className + ' '+ this.pfx +'composite';
},
/**
* Fired when the input value is updated
*/
valueUpdated: function(){
if(!this.model.get('detached'))
PropertyView.prototype.valueUpdated.apply(this, arguments);
},
/**
* Renders input
* */
renderInput: function() {
var props = this.model.get('properties');
var detached = this.model.get('detached');
if(props && props.length){
if(!this.$input)
this.$input = $('<input>', {value: 0, type: 'hidden' });
if(!this.props){
this.props = this.model.get('properties');
}
if(!this.$props){
//Not yet supported nested composite
this.props.each(function(prop, index){
if(prop && prop.get('type') == 'composite'){
this.props.remove(prop);
console.warn('Nested composite types not yet allowed.');
}
}, this);
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}
*/
getPropsConfig: function(opts){
var that = this;
result = {
config: this.config,
collection: this.props,
target: this.target,
propTarget: this.propTarget,
// On any change made to children I need to update composite value
onChange: function(el, view, opts){
var result = that.build();
that.model.set('value', result, opts);
},
// 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;
return result;
},
/**
* Get default value of the property
* @return {string}
* */
getDefaultValue: function(){
var str = '';
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}
* */
valueOnIndex: function(index, view){
var result = null;
var a = this.getComponentValue().split(' ');
if(a.length && a[index]){
result = a[index];
if(view && view.model && view.model.get('functionName')){
var v = this.fetchFromFunction(result);
if(v)
result = v;
}
}
return result;
},
/**
* Build composite value
* @param {Object} selectedEl Selected element
* @param {Object} propertyView Property view
* @param {Object} opts Options
* @return {string}
* */
build: function(selectedEl, propertyView, opts){
var result = '';
this.model.get('properties').each(function(prop){
var v = prop.getValue();
func = prop.get('functionName');
if(func)
v = func + '(' + v + ')';
result += v + ' ';
});
return result.replace(/ +$/,'');
},
});
function (Backbone, PropertyView, propertyTemplate, require) {
/**
* @class PropertyCompositeView
* */
return PropertyView.extend({
template: _.template(propertyTemplate),
initialize: function(o) {
PropertyView.prototype.initialize.apply(this, arguments);
_.bindAll(this, 'build');
this.config = o.config || {};
this.className = this.className + ' '+ this.pfx +'composite';
},
/**
* Fired when the input value is updated
*/
valueUpdated: function(){
if(!this.model.get('detached'))
PropertyView.prototype.valueUpdated.apply(this, arguments);
},
/**
* Renders input
* */
renderInput: function() {
var model = this.model;
var props = model.get('properties') || [];
var self = this;
if (props.length) {
if(!this.$input)
this.$input = $('<input>', {value: 0, type: 'hidden' });
if (!this.props) {
this.props = model.get('properties');
}
if (!this.$props) {
//Not yet supported nested composite
this.props.each(function(prop, index) {
if(prop && prop.get('type') == 'composite') {
this.props.remove(prop);
console.warn('Nested composite types not yet allowed.');
}
prop.parent = model;
}, this);
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}
*/
getPropsConfig: function(opts){
var that = this;
result = {
config: this.config,
collection: this.props,
target: this.target,
propTarget: this.propTarget,
// On any change made to children I need to update composite value
onChange: function(el, view, opts){
var result = that.build();
that.model.set('value', result, opts);
},
// 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;
return result;
},
/**
* Get default value of the property
* @return {string}
* */
getDefaultValue: function(){
var str = '';
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}
* */
valueOnIndex: function(index, view){
var result = null;
var a = this.getComponentValue().split(' ');
if(a.length && a[index]){
result = a[index];
if(view && view.model && view.model.get('functionName')){
var v = this.fetchFromFunction(result);
if(v)
result = v;
}
}
return result;
},
/**
* Build composite value
* @param {Object} selectedEl Selected element
* @param {Object} propertyView Property view
* @param {Object} opts Options
* @return {string}
* */
build: function(selectedEl, propertyView, opts){
var result = '';
this.model.get('properties').each(function(prop){
var v = prop.getValue();
func = prop.get('functionName');
if(func)
v = func + '(' + v + ')';
result += v + ' ';
});
return result.replace(/ +$/,'');
},
});
});

263
src/style_manager/view/PropertyFileView.js

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

63
src/style_manager/view/PropertyIntegerView.js

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

94
src/style_manager/view/PropertyStackView.js

@ -28,6 +28,12 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
else {
this.checkVisibility();
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}
* */
indexChanged: function(e){
var layer = this.getLayers().at(this.model.get('stackIndex'));
indexChanged: function(e) {
var model = this.model;
var layer = this.getLayers().at(model.get('stackIndex'));
layer.set('props', this.$props);
this.model.get('properties').each(function(prop){
model.get('properties').each(function (prop) {
prop.trigger('targetUpdated');
});
},
@ -68,7 +75,7 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
var that = this;
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 result = that.build();
@ -91,21 +98,25 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
},
/**
* Extract string from composite value
* @param integer Index
* @param View propView Property view
* Extract string from the composite value of the target
* @param {integer} index Property index
* @param {View} propView Property view
* @return string
* @private
* */
valueOnIndex: function(index, propView){
var result = null;
valueOnIndex: function(index, propView) {
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(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 (this.model.get('detached')) {
var valist = propView.getTargetValue().split(',');
result = valist[layerIndex];
result = result ? result.trim() : propView.getDefaultValue();
result = propView.tryFetchFromFunction(result);
} else {
var aStack = this.getStackValues();
var strVar = aStack[layerIndex];
if(!strVar)
return;
var a = strVar.split(' ');
@ -113,11 +124,15 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
result = a[index];
}
}
return result;
},
/** @inheritdoc */
build: function(){
/**
* Build composite value
* @private
* */
build: function() {
var stackIndex = this.model.get('stackIndex');
if(stackIndex === null)
return;
@ -148,15 +163,17 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
*
* @return Object
* */
addLayer: function(e){
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;
@ -166,11 +183,13 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
/**
* 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){
valueUpdated: function() {
var model = this.model;
if (!model.get('detached')) {
model.set('value', this.createValue());
} else {
model.get('properties').each(function(prop){
prop.trigger('change:value');
});
}
@ -216,15 +235,17 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
* Only for detached stacks
* @return {Array<string>}
*/
getLayersFromTarget: function(){
getLayersFromTarget: function() {
var arr = [];
var target = this.getTarget();
if(!target)
return arr;
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')];
if(style){
if (style) {
var list = style.split(',');
for(var i = 0, len = list.length; i < len; i++){
var val = list[i].trim();
@ -239,22 +260,25 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
}
}
});
return arr;
},
/**
* Refresh layers
* */
refreshLayers: function(){
refreshLayers: function() {
var n = [];
var a = [];
var fieldName = 'value';
if(this.model.get('detached')){
var detached = this.model.get('detached');
if (detached) {
fieldName = 'values';
a = this.getLayersFromTarget();
}else{
} else {
var v = this.getComponentValue();
if(v){
if (v) {
// Remove spaces inside functions:
// eg:
// 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(', ');
}
}
_.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'))
// Avoid updating with detached as it will cause issues on next change
if (!detached) {
this.valueUpdated();
}
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}
* */
sameValue: function(){
return this.getComponentValue() == (this.model.get('value') + this.model.get('unit'));
sameValue: function() {
return this.getComponentValue() == this.getValueForTarget();
},
@ -102,6 +102,7 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
* @return {String}
* */
getComponentValue: function() {
var propModel = this.model;
var target = this.getTarget();
if(!target)
@ -114,7 +115,7 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
this.componentValue = this.defaultValue + (this.unit || ''); // todo model
// Check if wrap inside function is required
if(this.model.get('functionName')){
if (propModel.get('functionName')) {
var v = this.fetchFromFunction(this.componentValue);
if(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,
// useful in composite properties
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);
if(t)
this.componentValue = t;
@ -132,22 +133,68 @@ define(['backbone', 'text!./../templates/propertyLabel.html', 'text!./../templat
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
* @param {String} v Function type value
*
* @return {String}
* */
fetchFromFunction: function(v){
fetchFromFunction: function(v) {
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
* @return {string}
*/
getValueForTarget: function(){
return this.model.getValue();
getValueForTarget: function() {
return this.model.get('value');
},
/**

2
src/utils/Sorter.js

@ -431,7 +431,7 @@ define(function(require) {
// Get children based on getChildrenContainer
var $elem = $(elem);
var elemData = $elem.data('model');
if (elemData) {
if (elemData && elemData.view) {
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() {
$fixture.html().should.equal('<div></div>');
$fixture.html().should.equal('<div data-highlightable="1"></div>');
});
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() {
$fixture.html().should.equal('<div></div>');
$fixture.html().should.equal('<div data-highlightable="1"></div>');
});
it('Add helper class on update of state', function() {
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() {
model.set('state', 'test');
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() {
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() {
@ -131,7 +131,7 @@ define([path + 'ComponentView', 'DomComponents/model/Component', 'DomComponents'
model: model,
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