diff --git a/src/css_composer/main.js b/src/css_composer/main.js index b79c15826..9282ae7f6 100644 --- a/src/css_composer/main.js +++ b/src/css_composer/main.js @@ -1,15 +1,16 @@ define(function(require) { /** - * @class CssManager + * @class CssComposer * @param {Object} config Configurations * * */ - var CssManager = function(config) + var CssComposer = function(config) { var c = config || {}, def = require('./config/config'), CssRule = require('./model/CssRule'), - CssRules = require('./model/CssRules'); + CssRules = require('./model/CssRules'), + CssRulesView = require('./view/CssRulesView'); for (var name in def) { if (!(name in c)) @@ -17,7 +18,11 @@ define(function(require) { } //this.qset = { '' : CssRules, '340px': CssRules }; - var rules = new CssRules([]); + var rules = new CssRules([]), + rulesView = new CssRulesView({ + collection: rules, + config: c, + }); return { @@ -27,7 +32,8 @@ define(function(require) { * * @return {Object} Model class * */ - addRule: function(name){ + addRule: function(Rule){ + return rules.add(Rule); /* var label = name; var c = this.getRule(name); @@ -78,6 +84,7 @@ define(function(require) { * Compare 2 arrays to check if are the same * @param {Array} arr1 * @param {Array} arr2 + * * @return {Boolean} */ same: function(a1, a2){ @@ -107,9 +114,18 @@ define(function(require) { return rules; }, + /** + * Render block of CSS rules + * + * @return {Object} + */ + render: function(){ + return rulesView.render().el; + } + }; }; - return CssManager; + return CssComposer; }); \ No newline at end of file diff --git a/src/css_composer/view/CssRuleView.js b/src/css_composer/view/CssRuleView.js new file mode 100644 index 000000000..32c7169ba --- /dev/null +++ b/src/css_composer/view/CssRuleView.js @@ -0,0 +1,53 @@ +define(['backbone'], + function (Backbone) { + /** + * @class CssRuleView + * */ + return Backbone.View.extend({ + + tagName: 'style', + + initialize: function(o) { + this.config = o.config || {}; + this.listenTo(this.model, 'change:style', this.render); + + }, + + /** + * Returns string of selectors + * @return {String} + */ + renderSelectors: function(){ + var sel = []; + this.model.get('selectors').each(function(m){ + sel.push('.' + m.get('name')); + }); + return sel.join(''); + }, + + /** + * Returns string of properties + * @return {String} + */ + renderProperties: function(){ + var sel = [], + props = this.model.get('style'); + for (var prop in props){ + sel.push(prop + ':' + props[prop] + ';'); + } + return sel.join(''); + }, + + /* + http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript + */ + render : function(){ + if(!this.selStr) + this.selStr = this.renderSelectors(); + var prpStr = this.renderProperties(); + this.$el.html(this.selStr + '{' + prpStr + '}'); + return this; + }, + + }); +}); diff --git a/src/css_composer/view/CssRulesView.js b/src/css_composer/view/CssRulesView.js new file mode 100644 index 000000000..c1c6f9768 --- /dev/null +++ b/src/css_composer/view/CssRulesView.js @@ -0,0 +1,62 @@ +define(['backbone','./CssRuleView'], + function (Backbone, CssRuleView) { + /** + * @class CssRulesView + * */ + return Backbone.View.extend({ + + initialize: function(o) { + this.config = o.config; + this.preview = o.preview; + this.pfx = this.config.stylePrefix; + this.listenTo( this.collection, 'add', this.addTo ); + this.listenTo( this.collection, 'reset', this.render ); + }, + + /** + * Add to collection + * @param {Object} model + * */ + addTo: function(model){ + console.log('Added'); + this.addToCollection(model); + }, + + /** + * Add new object to collection + * @param {Object} model + * @param {Object} fragmentEl + * + * @return {Object} + * */ + addToCollection: function(model, fragmentEl){ + var fragment = fragmentEl || null; + var viewObject = CssRuleView; + + var view = new viewObject({ + model: model, + config: this.config, + }); + var rendered = view.render().el; + + if(fragment) + fragment.appendChild( rendered ); + else + this.$el.append(rendered); + + return rendered; + }, + + render: function() { + var fragment = document.createDocumentFragment(); + this.$el.empty(); + + this.collection.each(function(model){ + this.addToCollection(model, fragment); + }, this); + + this.$el.append(fragment); + return this; + } + }); +}); diff --git a/src/editor/view/EditorView.js b/src/editor/view/EditorView.js index b2d9b153a..a09db6319 100644 --- a/src/editor/view/EditorView.js +++ b/src/editor/view/EditorView.js @@ -4,30 +4,34 @@ function(Backbone){ * @class EditorView * */ return Backbone.View.extend({ - + initialize: function() { - this.cv = this.model.get('Canvas'); - this.pn = this.model.get('Panels'); - this.className = this.model.config.stylePrefix + 'editor'; + this.cv = this.model.get('Canvas'); + this.pn = this.model.get('Panels'); + this.css = this.model.get('CssComposer'); + this.className = this.model.config.stylePrefix + 'editor'; }, render: function(){ this.$el.empty(); - + this.$cont = $('body ' + this.model.config.container); - + this.model.set('$editor', this.$el); - + if(this.cv) this.$el.append(this.cv.render()); - + if(this.pn) this.$el.append(this.pn.render()); - + + if(this.css) + this.$el.append(this.css.render()); + this.$el.attr('class', this.className); - + this.$cont.html(this.$el); - + if(this.pn) this.pn.active(); diff --git a/src/style_manager/view/PropertyCompositeView.js b/src/style_manager/view/PropertyCompositeView.js index af953d2ee..310015858 100644 --- a/src/style_manager/view/PropertyCompositeView.js +++ b/src/style_manager/view/PropertyCompositeView.js @@ -1,36 +1,36 @@ -define(['backbone','./PropertyView', 'text!./../templates/propertyComposite.html','require'], +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'; }, - + /** * Renders input - * + * * @return void * */ renderInput: function() { var props = this.model.get('properties'); if(props && props.length){ - if(!this.$input) + if(!this.$input) this.$input = $('', {value: 0, type: 'hidden' }); - + if(!this.props){ var Properties = require('./../model/Properties'); this.props = new Properties(props); this.model.set('properties', this.props); } - + if(!this.$props){ //Avoid style for children this.props.each(function(prop, index){ @@ -43,15 +43,16 @@ define(['backbone','./PropertyView', 'text!./../templates/propertyComposite.html console.warn(prop.get('property')+' of type composite not yet allowed.'); } },this); - + var PropertiesView = require('./PropertiesView'); var that = this; var propsView = new PropertiesView({ config : this.config, - collection : this.props, + collection : this.props, target : this.target, + propTarget : this.propTarget, onChange : function(el, model){ - var result = that.build(el, model); + var result = that.build(el, model); that.model.set('value', result); }, onInputRender : function(property, mIndex){ @@ -67,10 +68,10 @@ define(['backbone','./PropertyView', 'text!./../templates/propertyComposite.html } } }, - + /** * Get default value of the property - * + * * @return string * */ getDefaultValue: function(){ @@ -80,12 +81,12 @@ define(['backbone','./PropertyView', 'text!./../templates/propertyComposite.html }); return str.replace(/ +$/,''); }, - + /** * Extract string from composite value * @param integer Index * @param object Property model - * + * * @return string * */ valueOnIndex: function(index, model){ @@ -102,12 +103,12 @@ define(['backbone','./PropertyView', 'text!./../templates/propertyComposite.html } return result; }, - + /** * Build composite value * @param Object Selected element * @param Object Property model - * + * * @return string * */ build: function(selectedEl, propertyModel){ diff --git a/src/style_manager/view/PropertyView.js b/src/style_manager/view/PropertyView.js index 2768aaa75..b6ea12a46 100644 --- a/src/style_manager/view/PropertyView.js +++ b/src/style_manager/view/PropertyView.js @@ -5,8 +5,8 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], * */ return Backbone.View.extend({ - template: _.template(propertyTemplate), - templateLabel: _.template(propertyTemplate), + template: _.template(propertyTemplate), + templateLabel: _.template(propertyTemplate), events: { 'change' : 'valueChanged', @@ -30,46 +30,26 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], this.list = this.model.get('list'); this.input = this.$input = null; this.className = this.pfx + 'property'; - this.selectedComponent = this.target.get('selectedComponent'); - - if(this.selectedComponent){ - this.componentValue = this.selectedComponent.get('style')[this.property]; - } - this.listenTo( this.propTarget, 'update', this.targetUpdated); - this.listenTo( this.target ,'change:selectedComponent',this.componentSelected); this.listenTo( this.model ,'change:value', this.valueChanged); - - }, - - /** - * Fired when target is updated - */ - targetUpdated: function() { - console.log('Property: target updated'); }, /** - * Rerender property for the new selected component, if necessary - * @param {Array[Model, value, options]} e - * + * Fired when the target is updated * */ - componentSelected: function(e){ - this.selectedComponent = this.target.get('selectedComponent'); + targetUpdated: function(){ + this.selectedComponent = this.propTarget.model; if(this.selectedComponent){ - //I will rerender it only if the assigned one is different from the actuale value - //console.log('property '+this.property+" view: "+this.componentValue+" model: "+ this.model.get('value')); - if( !this.sameValue() ){ + if(!this.sameValue()) this.renderInputRequest(); - } } }, /** - * Checks if the value from selected component is the same with - * the value of the model + * Checks if the value from selected component is the + * same of the value of the model * - * @return boolean + * @return {Boolean} * */ sameValue: function(){ return this.getComponentValue() == (this.model.get('value') + this.model.get('unit')); @@ -88,7 +68,7 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], if(this.selectedComponent.get('style')[this.property]) this.componentValue = this.selectedComponent.get('style')[this.property]; else - this.componentValue = this.defaultValue + (this.unit ? this.unit : ''); + this.componentValue = this.defaultValue + (this.unit || ''); // Check if wrap inside function is required if(this.func){ @@ -97,11 +77,11 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], this.componentValue = v; } - //This allow to ovveride the normal flow of selecting component value, - //useful in composite properties + // 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 t = this.customValue(this, index); + var index = this.model.collection.indexOf(this.model); + var t = this.customValue(this, index); if(t) this.componentValue = t; } @@ -110,7 +90,7 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], }, /** - * Fetch string from function type value + * Fetch the string from function type value * @param {String} v Function type value * * @return {String} @@ -124,8 +104,6 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], * @param {Object} e Events * @param {Mixed} val Value * @param {Object} opt Options - * - * @return void * */ valueChanged: function(e, val, opt){ if(!this.selectedComponent) @@ -156,7 +134,7 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], componentCss[this.property] = value; this.selectedComponent.set('style', componentCss, { avoidStore : avSt}); } - this.selectedValue = value;//TODO ? + this.selectedValue = value; if(this.onChange && typeof this.onChange === "function"){ this.onChange(this.selectedComponent, this.model); @@ -165,9 +143,8 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], /** * Set value to the input - * @param String value - * - * @return void + * @param {String} value + * @param {Boolean} force * */ setValue: function(value, force){ var f = force===0 ? 0 : 1; @@ -177,13 +154,11 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], } if(this.$input) this.$input.val(v); - this.model.set({value: v},{silent: true}); + this.model.set({value: v}, {silent: true}); }, /** * Render label - * - * @return void * */ renderLabel: function(){ this.$el.html( this.templateLabel({ @@ -196,8 +171,6 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], /** * Render field property - * - * @return void * */ renderField : function() { this.renderTemplate(); @@ -207,8 +180,6 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], /** * Render loaded template - * - * @return void * */ renderTemplate: function(){ this.$el.append( this.template({ @@ -221,8 +192,6 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], /** * Renders input, to override - * - * @return void * */ renderInput: function(){ console.warn("No render input implemented for '"+this.model.get('type')+"'"); @@ -230,8 +199,6 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], /** * Request to render input of the property - * - * @return void * */ renderInputRequest: function(){ this.renderInput(); @@ -243,8 +210,6 @@ define(['backbone', 'text!./../templates/propertyLabel.html'], /** * Clean input - * - * @return void * */ cleanValue: function(){ this.setValue(''); diff --git a/src/style_manager/view/SectorsView.js b/src/style_manager/view/SectorsView.js index 93d3fbb71..b9219a0a0 100644 --- a/src/style_manager/view/SectorsView.js +++ b/src/style_manager/view/SectorsView.js @@ -9,10 +9,11 @@ define(['backbone','./SectorView'], this.config = o.config; this.pfx = this.config.stylePrefix; this.target = o.target || {}; + + // The taget that will emit events for properties this.propTarget = {}; _.extend(this.propTarget, Backbone.Events); - - this.listenTo( this.target ,'change:selectedComponent', this.targetUpdated); + this.listenTo( this.target, 'change:selectedComponent', this.targetUpdated); }, @@ -21,21 +22,31 @@ define(['backbone','./SectorView'], */ targetUpdated: function() { var el = this.target.get('selectedComponent'); + + if(!el) + return; + var classes = el.get('classes'); + var pt = this.propTarget; if(classes.length){ var cssC = this.target.get('CssComposer'); var valid = _.filter(classes.models, function(item){ return item.get('active'); }); var iContainer = cssC.getRule(valid, 'status', 'mediaq'); if(!iContainer){ - //console.log(valid); iContainer = cssC.newRule(valid, 'status', 'mediaq'); - //console.log(iContainer.get('selectors').models); - this.propTarget.target = iContainer; - this.propTarget.trigger('update'); + // Hydrate styles from component element + iContainer.set('style', el.get('style')); + cssC.addRule(iContainer); + el.set('style', {}); + pt.model = iContainer; + pt.trigger('update'); + return; } } + pt.model = el; + pt.trigger('update'); }, render: function() {