Browse Source

Merge branch 'class-manager' into dev

pull/14/head
Artur Arseniev 10 years ago
parent
commit
773b4e9fe8
  1. 1
      .gitignore
  2. 2
      bower.json
  3. 3
      package.json
  4. 2
      src/class_manager/config/config.js
  5. 2
      src/class_manager/template/classTag.html
  6. 38
      src/class_manager/view/ClassTagsView.js
  7. 2
      src/commands/view/OpenStyleManager.js
  8. 1
      src/config/require-config.js
  9. 11
      src/css_composer/config/config.js
  10. 134
      src/css_composer/main.js
  11. 28
      src/css_composer/model/CssRule.js
  12. 0
      src/css_composer/model/CssRules.js
  13. 29
      src/css_composer/model/Selectors.js
  14. 53
      src/css_composer/view/CssRuleView.js
  15. 62
      src/css_composer/view/CssRulesView.js
  16. 8
      src/css_manager/config/config.js
  17. 64
      src/css_manager/main.js
  18. 16
      src/css_manager/model/CssRule.js
  19. 3
      src/editor/config/config.js
  20. 14
      src/editor/model/Editor.js
  21. 26
      src/editor/view/EditorView.js
  22. 46
      src/style_manager/view/PropertiesView.js
  23. 37
      src/style_manager/view/PropertyCompositeView.js
  24. 75
      src/style_manager/view/PropertyView.js
  25. 2
      src/style_manager/view/SectorView.js
  26. 41
      src/style_manager/view/SectorsView.js
  27. 1
      test/runner/main.js
  28. 3
      test/specs/class_manager/main.js
  29. 143
      test/specs/class_manager/view/ClassTagsView.js
  30. 84
      test/specs/css_composer/main.js
  31. 60
      test/specs/css_composer/model/CssModels.js

1
.gitignore

@ -10,5 +10,6 @@ grapes.sublime-workspace
img/
private/
vendor/
coverage/
node_modules/
bower_components/

2
bower.json

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

3
package.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Open source Web Template Editor",
"version": "0.1.2",
"version": "0.1.5",
"author": "Artur Arseniev",
"license": "BSD-3-Clause",
"homepage": "http://grapesjs.com",
@ -28,6 +28,7 @@
"grunt-contrib-watch": "^0.6.1",
"grunt-mocha": "^0.4.15",
"grunt-sass": "^1.1.0",
"istanbul": "^0.4.2",
"node-sass": "^3.4.2"
},
"keywords": [

2
src/class_manager/config/config.js

@ -11,7 +11,7 @@ define(function () {
label: 'Classes',
// Label for states
statesLabel: 'States',
statesLabel: 'State',
};
});

2
src/class_manager/template/classTag.html

@ -1,3 +1,3 @@
<span id="<%= pfx %>checkbox" class="fa"></span>
<span id="<%= pfx %>tag-label"> <%= label %> </span>
<span id="<%= pfx %>tag-label"><%= label %></span>
<span id="<%= pfx %>close">&Cross;</span>

38
src/class_manager/view/ClassTagsView.js

@ -7,13 +7,11 @@ define(['backbone', 'text!./../template/classTags.html', './ClassTagView'],
template: _.template(tagsTemplate),
events:{
'click .add': 'startNewClass',
},
events: {},
initialize: function(o) {
this.config = o.config || {};
this.pfx = this.config.stylePrefix;
this.pfx = this.config.stylePrefix || '';
this.className = this.pfx + 'tags';
this.addBtnId = this.pfx + 'add-tag';
this.newInputId = this.pfx + 'new';
@ -40,7 +38,7 @@ define(['backbone', 'text!./../template/classTags.html', './ClassTagView'],
},
/**
* Start new tag event
* Start tag creation
* @param {Object} e
*
*/
@ -50,7 +48,7 @@ define(['backbone', 'text!./../template/classTags.html', './ClassTagView'],
},
/**
* Start new tag event
* End tag creation
* @param {Object} e
*
*/
@ -59,14 +57,15 @@ define(['backbone', 'text!./../template/classTags.html', './ClassTagView'],
this.$input.hide().val('');
},
/**
* Add new class tag
* @param {Object} model
*
* Checks what to do on keyup event
* @param {Object} e
*/
addTag: function(model){
onInputKeyUp: function(e) {
if (e.keyCode === 13)
this.addNewTag(this.$input.val());
else if(e.keyCode === 27)
this.endNewTag();
},
/**
@ -79,21 +78,6 @@ define(['backbone', 'text!./../template/classTags.html', './ClassTagView'],
this.collection.reset(models);
},
/**
* Checks what to do on keyup event
* @param {Object} e
*/
onInputKeyUp: function(e) {
if (e.keyCode === 13)
this.addNewTag(this.$input.val());
else if(e.keyCode === 27)
this.endNewTag();
else{
//this.searchItem();
//console.log('search');
}
},
/**
* Add new tag to collection, if possible, and to the component
* @param {Object} e

2
src/commands/view/OpenStyleManager.js

@ -24,13 +24,11 @@ define(['StyleManager'], function(StyleManager) {
// Class Manager container
this.clm = em.get('ClassManager');
if(this.clm){
/*
this.$clm = new this.clm.ClassTagsView({
collection: new this.clm.ClassTags([]),
config: this.clm.config,
}).render().el;
this.$cn2.append(this.$clm);
*/
}
// Style Manager manager container

1
src/config/require-config.js

@ -42,6 +42,7 @@ require.config({
{ name: 'RichTextEditor', location: 'rich_text_editor', },
{ name: 'ModalDialog', location: 'modal_dialog', },
{ name: 'CodeManager', location: 'code_manager', },
{ name: 'CssComposer', location: 'css_composer', },
{ name: 'Commands', location: 'commands', },
{ name: 'Canvas', location: 'canvas', },
{ name: 'Panels', location: 'panels', }

11
src/css_composer/config/config.js

@ -0,0 +1,11 @@
define(function () {
return {
// Style prefix
stylePrefix: 'css-',
// Default CSS style
'default': '',
};
});

134
src/css_composer/main.js

@ -0,0 +1,134 @@
define(function(require) {
/**
* @class CssComposer
* @param {Object} config Configurations
*
* */
var CssComposer = function(config)
{
var c = config || {},
def = require('./config/config'),
CssRule = require('./model/CssRule'),
CssRules = require('./model/CssRules'),
Selectors = require('./model/Selectors'),
CssRulesView = require('./view/CssRulesView');
for (var name in def) {
if (!(name in c))
c[name] = def[name];
}
//this.qset = { '' : CssRules, '340px': CssRules };
var rules = new CssRules([]),
rulesView = new CssRulesView({
collection: rules,
config: c,
});
return {
Selectors: Selectors,
/**
* Create new rule and return it. Don't add it to the collection
* @param {Array} selectors Array of selectors
* @param {String} state Css rule state
* @param {String} width For which device this style is oriented
*
* @return {Object}
* */
newRule: function(selectors, state, width) {
var s = state || '';
var w = width || '';
var rule = new CssRule({
state: s,
maxWidth: w,
});
rule.get('selectors').add(selectors);
return rule;
},
/**
* Add new rule to the collection if not yet exists
* @param {Object} rule
*
* @return {Object}
* */
addRule: function(rule){
var models = rule.get('selectors').models;
var r = this.getRule(models, rule.get('state'), rule.get('maxWidth'));
if(!r)
r = rules.add(rule);
return r;
},
/**
* Get class by its name
* @param {Array} selectors Array of selectors
* @param {String} state Rule status
* @param {String} set Query set
*
* @return {Object|null}
* */
getRule : function(selectors, state, set) {
var req = _.pluck(selectors, 'cid');
fRule = null;
rules.each(function(rule){
if(fRule)
return;
var sel = _.pluck(rule.get('selectors').models, 'cid');
if(this.same(req, sel))
fRule = rule;
}, this);
return fRule;
},
/**
* Compare 2 arrays to check if are the same
* @param {Array} arr1
* @param {Array} arr2
*
* @return {Boolean}
*/
same: function(a1, a2){
if(a1.length !== a2.length)
return;
for (var i = 0; i < a1.length; i++) {
var f = 0;
for (var j = 0; j < a2.length; j++) {
if (a1[i] === a2[j])
f = 1;
}
if(f === 0)
return;
}
return true;
},
/**
* Get collection of css rules
*
* @return {Object}
* */
getRules : function() {
return rules;
},
/**
* Render block of CSS rules
*
* @return {Object}
*/
render: function(){
return rulesView.render().el;
}
};
};
return CssComposer;
});

28
src/css_composer/model/CssRule.js

@ -0,0 +1,28 @@
define(['backbone', './Selectors'],
function (Backbone, Selectors) {
/**
* @class CssRule
* */
return Backbone.Model.extend({
defaults: {
// Css selectors
selectors: {},
// Css properties style
style: {},
// On which device width this rule should be rendered, eg. @media (max-width: 1000px)
maxWidth: '',
// State of the rule, eg: hover | pressed | focused
state: '',
// Indicates if the rule is stylable
stylable: true,
},
initialize: function(c, opt) {
this.config = c || {};
this.slct = this.config.selectors || [];
this.set('selectors', new Selectors(this.slct));
},
});
});

0
src/css_manager/model/CssRules.js → src/css_composer/model/CssRules.js

29
src/css_composer/model/Selectors.js

@ -0,0 +1,29 @@
define([ 'backbone', 'require'],
function (Backbone, require) {
/**
* @class Selectors
* */
return Backbone.Collection.extend({
initialize: function(models, opt){
this.model = function(attrs, opts) {
var model;
switch(1){
default:
if(!this.ClassTag)
this.ClassTag = require("ClassManager/model/ClassTag");
model = new this.ClassTag(attrs, opts);
}
return model;
};
},
});
});

53
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;
},
});
});

62
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;
}
});
});

8
src/css_manager/config/config.js

@ -1,8 +0,0 @@
define(function () {
return {
// Style prefix
stylePrefix : 'css-',
};
});

64
src/css_manager/main.js

@ -1,64 +0,0 @@
define(function(require) {
/**
* @class CssManager
* @param {Object} config Configurations
*
* */
var CssManager = function(config)
{
var c = config || {},
def = require('./config/config');
this.CssRules = require('./model/CssRules');
for (var name in def) {
if (!(name in c))
c[name] = def[name];
}
this.rules = new this.CssRules([]);
this.config = c;
};
CssManager.prototype = {
/**
* Add new class to collection only if it's not already exists
* @param {String} name Class name
*
* @return {Object} Model class
* */
addRule: function(name){
var label = name;
var c = this.getClass(name);
if(!c)
return this.classes.add({name: name, label: label});
return c;
},
/**
* Get class by its name
* @param {Array[String]} ids Array of ids
* @param {String} status Rule status
* @param {String} set Query set
*
* @return {Object|null}
* */
getRule : function(ids, status, set) {
var res = this.classes.where({name: id});
return res.length ? res[0] : null;
},
/**
* Get collection of css rules
*
* @return {Object}
* */
getRules : function() {
return this.rules;
},
};
return ClassManager;
});

16
src/css_manager/model/CssRule.js

@ -1,16 +0,0 @@
define(['backbone'],
function (Backbone) {
/**
* @class CssRule
* */
return Backbone.Model.extend({
defaults: {
classes: {},
style: {},
stylable: true,
state: '',
},
});
});

3
src/editor/config/config.js

@ -64,6 +64,9 @@ define(function () {
//Configurations for Class Manager
classManager : {},
//Configurations for Css Composer
cssComposer : {},
};
return config;
});

14
src/editor/model/Editor.js

@ -6,6 +6,7 @@ define([
'StorageManager',
'ModalDialog',
'CodeManager',
'CssComposer',
'Commands',
'Canvas',
'RichTextEditor',
@ -20,6 +21,7 @@ define([
StorageManager,
ModalDialog,
CodeManager,
CssComposer,
Commands,
Canvas,
RichTextEditor,
@ -53,10 +55,22 @@ define([
this.initComponents();
this.initCanvas();
this.initUndoManager();
this.initCssComposer();
this.on('change:selectedComponent', this.componentSelected, this);
},
/**
* Initialize Css Composer
* */
initCssComposer: function()
{
var cfg = this.config.cssComposer,
pfx = cfg.stylePrefix || 'css-';
cfg.stylePrefix = this.config.stylePrefix + pfx;
this.set('CssComposer', new CssComposer(cfg));
},
/**
* Initialize Class manager
* */

26
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();

46
src/style_manager/view/PropertiesView.js

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

37
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 = $('<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){

75
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',
@ -16,6 +16,7 @@ define(['backbone', 'text!./../templates/propertyLabel.html'],
this.config = o.config;
this.pfx = this.config.stylePrefix || '';
this.target = o.target || {};
this.propTarget = o.propTarget || {};
this.onChange = o.onChange || {};
this.onInputRender = o.onInputRender || {};
this.customValue = o.customValue || {};
@ -29,45 +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.target ,'change:selectedComponent',this.componentSelected);
this.listenTo( this.propTarget, 'update', this.targetUpdated);
this.listenTo( this.model ,'change:value', this.valueChanged);
},
/**
* 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){
/*
var classes = this.selectedComponent.get('classes');
if(classes.length){
var valid = _.filter(classes.models, function(item){ return item.get('active'); });
var ids = _.pluck(valid, 'cid');
var cssBlock = '';//this.sm.get('CssManager').getRule(ids, 'status', 'mediaq');
}
*/
//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'));
@ -86,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){
@ -95,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;
}
@ -108,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}
@ -122,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)
@ -154,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);
@ -163,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;
@ -175,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({
@ -194,8 +171,6 @@ define(['backbone', 'text!./../templates/propertyLabel.html'],
/**
* Render field property
*
* @return void
* */
renderField : function() {
this.renderTemplate();
@ -205,8 +180,6 @@ define(['backbone', 'text!./../templates/propertyLabel.html'],
/**
* Render loaded template
*
* @return void
* */
renderTemplate: function(){
this.$el.append( this.template({
@ -219,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')+"'");
@ -228,8 +199,6 @@ define(['backbone', 'text!./../templates/propertyLabel.html'],
/**
* Request to render input of the property
*
* @return void
* */
renderInputRequest: function(){
this.renderInput();
@ -241,8 +210,6 @@ define(['backbone', 'text!./../templates/propertyLabel.html'],
/**
* Clean input
*
* @return void
* */
cleanValue: function(){
this.setValue('');

2
src/style_manager/view/SectorView.js

@ -13,6 +13,7 @@ define(['backbone', './PropertiesView', 'text!./../templates/sector.html'],
this.config = o.config;
this.pfx = this.config.stylePrefix;
this.target = o.target || {};
this.propTarget = o.propTarget || {};
this.open = this.model.get('open');
this.caretR = 'fa-caret-right';
this.caretD = 'fa-caret-down';
@ -82,6 +83,7 @@ define(['backbone', './PropertiesView', 'text!./../templates/sector.html'],
var view = new PropertiesView({
collection : objs,
target : this.target,
propTarget : this.propTarget,
config : this.config,
});
this.$el.append(view.render().el);

41
src/style_manager/view/SectorsView.js

@ -9,6 +9,46 @@ 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);
},
/**
* Fired when target is updated
*/
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){
iContainer = cssC.newRule(valid, 'status', 'mediaq');
// 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() {
@ -21,6 +61,7 @@ define(['backbone','./SectorView'],
name : obj.get('name'),
properties : obj.get('properties'),
target : this.target,
propTarget : this.propTarget,
config : this.config,
});
fragment.appendChild(view.render().el);

1
test/runner/main.js

@ -13,6 +13,7 @@ require(['../src/config/require-config.js', 'config/config.js'], function() {
'specs/asset_manager/view/FileUploader.js',
'specs/dom_components/main.js',
'specs/class_manager/main.js',
'specs/css_composer/main.js',
], function(chai)
{
var should = chai.should(),

3
test/specs/class_manager/main.js

@ -4,12 +4,14 @@ define([
'ClassManager',
modulePath + '/model/ClassModels',
modulePath + '/view/ClassTagView',
modulePath + '/view/ClassTagsView',
modulePath + '/e2e/ClassManager'
],
function(
ClassManager,
Models,
ClassTagView,
ClassTagsView,
e2e
) {
@ -84,6 +86,7 @@ define([
Models.run();
ClassTagView.run();
ClassTagsView.run();
e2e.run();
});

143
test/specs/class_manager/view/ClassTagsView.js

@ -0,0 +1,143 @@
var path = 'ClassManager/view/';
define([path + 'ClassTagsView', 'ClassManager/model/ClassTags'],
function(ClassTagsView, ClassTags) {
return {
run : function(){
describe('ClassTagsView', function() {
before(function () {
this.$fixtures = $("#fixtures");
this.$fixture = $('<div class="classtag-fixture"></div>');
});
beforeEach(function () {
this.target = { get: function(){} };
this.coll = new ClassTags();
_.extend(this.target, Backbone.Events);
this.view = new ClassTagsView({
config : { target: this.target },
collection: this.coll
});
this.$fixture.empty().appendTo(this.$fixtures);
this.$fixture.html(this.view.render().el);
this.btnAdd = this.view.$el.find('#' + this.view.addBtnId);
this.input = this.view.$el.find('input#' + this.view.newInputId);
this.$tags = this.$fixture.find('#tags-c');
});
afterEach(function () {
delete this.view.collection;
});
after(function () {
this.$fixture.remove();
});
it('Object exists', function() {
ClassTagsView.should.be.exist;
});
it('Not tags inside', function() {
this.$tags.html().should.equal('');
});
it('Add new tag triggers correct method', function() {
sinon.stub(this.view, "addToClasses");
this.coll.add({ name: 'test' });
this.view.addToClasses.calledOnce.should.equal(true);
});
it('Start new tag creation', function() {
this.btnAdd.click();
(this.btnAdd.css('display') == 'none').should.equal(true);
(this.input.css('display') !== 'none').should.equal(true);
});
it('Stop tag creation', function() {
this.btnAdd.click();
this.input.val('test')
this.input.blur();
(this.btnAdd.css('display') !== 'none').should.equal(true);
(this.input.css('display') == 'none').should.equal(true);
this.input.val().should.equal('');
});
it('Check keyup of ESC on input', function() {
this.btnAdd.click();
sinon.stub(this.view, "addNewTag");
this.input.trigger({
type: 'keyup',
keyCode: 13
});
this.view.addNewTag.calledOnce.should.equal(true);
});
it('Check keyup on ENTER on input', function() {
this.btnAdd.click();
sinon.stub(this.view, "endNewTag");
this.input.trigger({
type: 'keyup',
keyCode: 27
});
this.view.endNewTag.calledOnce.should.equal(true);
});
it('Collection changes on update of target', function() {
this.coll.add({ name: 'test' });
this.target.trigger('change:selectedComponent');
this.coll.length.should.equal(0);
});
it('Collection reacts on reset', function() {
this.coll.add([{ name: 'test1' }, { name: 'test2' }]);
sinon.stub(this.view, "addToClasses");
this.coll.trigger('reset');
this.view.addToClasses.calledTwice.should.equal(true);
});
it("Don't accept empty tags", function() {
this.view.addNewTag('');
this.$tags.html().should.equal('');
});
it("Accept new tags", function() {
sinon.stub(this.target, "get").returns({
addClass: function(v){
return {name: v};
}
});
this.view.compTarget = {
get: function(){
return { add: function(){} };
}
};
this.view.addNewTag('test');
this.view.addNewTag('test2');
this.$tags.children().length.should.equal(2);
});
it("New tag correctly added", function() {
this.coll.add({ label: 'test' });
this.$tags.children().first().find('#tag-label').html().should.equal('test');
});
describe('Should be rendered correctly', function() {
it('Has label', function() {
this.view.$el.find('#label').should.have.property(0);
});
it('Has tags container', function() {
this.view.$el.find('#tags-c').should.have.property(0);
});
it('Has add button', function() {
this.view.$el.find('#add-tag').should.have.property(0);
});
});
});
}
};
});

84
test/specs/css_composer/main.js

@ -0,0 +1,84 @@
var modulePath = './../../../test/specs/css_composer';
define([
'CssComposer',
modulePath + '/model/CssModels'
],
function(
CssComposer,
Models,
Selectors
) {
describe('Css Composer', function() {
describe('Main', function() {
beforeEach(function () {
this.obj = new CssComposer();
});
afterEach(function () {
delete this.obj;
});
it('Object exists', function() {
CssComposer.should.be.exist;
});
it("Rules are empty", function() {
this.obj.getRules().length.should.equal(0);
});
it('Create new rule with correct selectors', function() {
var sel = new this.obj.Selectors();
var s1 = sel.add({name: 'test1'});
var rule = this.obj.newRule(sel.models);
rule.get('selectors').at(0).should.deep.equal(s1);
});
it('Create new rule correctly', function() {
var sel = new this.obj.Selectors();
var s1 = sel.add({name: 'test1'});
var rule = this.obj.newRule(sel.models, 'state1', 'width1');
rule.get('state').should.equal('state1');
rule.get('maxWidth').should.equal('width1');
});
it("Add rule to collection", function() {
var sel = new this.obj.Selectors([{name: 'test1'}]);
var rule = this.obj.newRule(sel.models, 'state1', 'width1');
this.obj.addRule(rule);
this.obj.getRules().length.should.equal(1);
this.obj.getRules().at(0).get('selectors').at(0).get('name').should.equal('test1');
});
/*
it("Don't duplicate rules", function() {
var sel1 = new this.obj.Selectors([{name: 'test1'}]);
var rule1 = this.obj.newRule(sel1.models, 'state1', 'width1');
var aRule1 = this.obj.addRule(rule1);
var sel2 = new this.obj.Selectors([{name: 'test1'}]);
var rule2 = this.obj.newRule(sel2.models, 'state1', 'width1');
var aRule2 = this.obj.addRule(rule2);
console.log(sel1);
console.log(rule1);
console.log(aRule1);
console.log(sel2);
console.log(rule2);
console.log(aRule2);
console.log(this.obj.getRules().length);
aRule1.should.deep.equal(aRule2);
});
*/
});
Models.run();
});
});

60
test/specs/css_composer/model/CssModels.js

@ -0,0 +1,60 @@
var path = 'CssComposer/model/';
define([path + 'CssRule',
path + 'CssRules',
path + 'Selectors',
'ClassManager/model/ClassTag'],
function(CssRule, CssRules, Selectors, ClassTag) {
return {
run : function(){
describe('CssRule', function() {
beforeEach(function () {
this.obj = new CssRule();
});
afterEach(function () {
delete this.obj;
});
it('Has selectors property', function() {
this.obj.has('selectors').should.equal(true);
});
it('Has style property', function() {
this.obj.has('style').should.equal(true);
});
it('Has state property', function() {
this.obj.has('state').should.equal(true);
});
it('No default selectors', function() {
this.obj.get('selectors').length.should.equal(0);
});
});
describe('CssRules', function() {
it('Creates collection item correctly', function() {
var c = new CssRules();
var m = c.add({});
m.should.be.an.instanceOf(CssRule);
});
});
describe('Selectors', function() {
it('Creates collection item correctly', function() {
var c = new Selectors();
var m = c.add({});
m.should.be.an.instanceOf(ClassTag);
});
});
}
};
});
Loading…
Cancel
Save