Browse Source

Prepare new structure for components

pull/36/head
Artur Arseniev 10 years ago
parent
commit
fb8ac68d0e
  1. 53
      src/dom_components/main.js
  2. 48
      src/dom_components/model/Component.js
  3. 28
      src/dom_components/model/ComponentImage.js
  4. 3
      src/dom_components/model/ComponentText.js
  5. 2
      src/dom_components/model/ComponentVideo.js
  6. 44
      src/dom_components/model/Components.js
  7. 16
      src/dom_components/view/ComponentVideoView.js
  8. 3
      src/dom_components/view/ComponentView.js
  9. 40
      src/dom_components/view/ComponentsView.js
  10. 8
      src/editor/config/config.js
  11. 63
      test/specs/dom_components/model/Component.js

53
src/dom_components/main.js

@ -36,18 +36,37 @@ define(function(require) {
return function (){
var c = {},
defaults = require('./config/config'),
Component = require('./model/Component'),
ComponentText = require('./model/ComponentText'),
ComponentImage = require('./model/ComponentImage'),
ComponentLink = require('./model/ComponentLink'),
ComponentMap = require('./model/ComponentMap'),
ComponentView = require('./view/ComponentView'),
ComponentImageView = require('./view/ComponentImageView'),
ComponentTextView = require('./view/ComponentTextView'),
ComponentMapView = require('./view/ComponentMapView'),
ComponentLinkView = require('./view/ComponentLinkView');
componentTypes = {},
defaults = require('./config/config'),
Component = require('./model/Component'),
ComponentView = require('./view/ComponentView');
var component, componentView;
var defaultTypes = {
'default': {
model: Component,
view: ComponentView,
},
'text': {
model: require('./model/ComponentText'),
view: require('./view/ComponentTextView'),
},
'image': {
model: require('./model/ComponentImage'),
view: require('./view/ComponentImageView'),
},
'link': {
model: require('./model/ComponentLink'),
view: require('./view/ComponentLinkView'),
},
'map': {
model: require('./model/ComponentMap'),
view: require('./view/ComponentMapView'),
},
'video': {
model: require('./model/ComponentVideo'),
view: require('./view/ComponentVideoView'),
}
};
return {
@ -100,12 +119,19 @@ define(function(require) {
c.am = c.em.get('AssetManager') || '';
}
component = new Component(c.wrapper, { sm: c.em, config: c });
component = new Component(c.wrapper, {
sm: c.em,
config: c,
defaultTypes: defaultTypes,
componentTypes: componentTypes,
});
component.set({ attributes: {id: 'wrapper'}});
component.get('components').add(c.components);
componentView = new ComponentView({
model: component,
config: c,
defaultTypes: defaultTypes,
componentTypes: componentTypes,
});
return this;
},
@ -290,7 +316,8 @@ define(function(require) {
* @private
*/
addComponentType: function(type, methods) {
componentTypes[type] = methods;
return this;
}
};

48
src/dom_components/model/Component.js

@ -20,6 +20,7 @@ define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitMana
content: '',
style: {},
attributes: {},
classes: '',
traits: ['id', 'title'],
},
@ -31,7 +32,7 @@ define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitMana
this.sm = opt ? opt.sm || {} : {};
this.config = o || {};
this.defaultC = this.config.components || [];
this.defaultCl = this.normalizeClasses(this.config.classes || []);
this.defaultCl = this.normalizeClasses(this.get('classes') || this.config.classes || []);
this.components = new Components(this.defaultC, opt);
this.set('components', this.components);
this.set('classes', new Selectors(this.defaultCl));
@ -132,13 +133,7 @@ define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitMana
sTag = m.get('void'),
attrId = '';
// Build the string of attributes
var attr = '';
_.each(attrs, function(value, prop){
// TODO: to refactor
if(prop == 'onmousedown')
return;
attr += value && prop!='style' ? ' ' + prop + '="' + value + '"' : '';
});
var attr = this.toAttrHTML();
// Build the string of classes
var strCls = '';
m.get('classes').each(function(m){
@ -146,32 +141,37 @@ define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitMana
});
strCls = strCls !== '' ? ' class="' + strCls.trim() + '"' : '';
/*
// TODO: to refactor
if(m.get('type') == 'image'){
tag = 'img';
sTag = 1;
attr += ' src="' + m.get('src') + '"';
}
*/
// If style is not empty I need an ID attached to the component
// TODO: need to refactor in case of 'ID Trait'
if(!_.isEmpty(m.get('style')))
// If style is not empty I need an ID attached to the component
// TODO: need to refactor in case of 'ID Trait'
if(!_.isEmpty(m.get('style')))
attrId = ' id="' + m.cid + '" ';
code += '<' + tag + strCls + attrId + attr + (sTag ? '/' : '') + '>' + m.get('content');
var cln = m.get('components');
if(cln.length)
code += this.toHTML(cln);
m.get('components').each(function(m) {
code += m.toHTML();
});
if(!sTag)
code += '</'+tag+'>';
return code;
},
/**
* Returns attributes string in HTML
* @return {string}
* @private
*/
toAttrHTML: function() {
var attr = '';
_.each(this.get('attributes'), function(val, prop){
attr += (val && prop != 'style') ? ' ' + prop + '="' + val + '"' : '';
});
return attr;
}
}, {
},{
/**
* Detect if the passed element is a valid component.
@ -181,7 +181,7 @@ define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitMana
* @return {Object}
* @private
*/
isValidEl: function(el) {
isComponent: function(el) {
var result = '';
if(el.tagName == 'DIV')
result = {tagName: 'div'};

28
src/dom_components/model/ComponentImage.js

@ -4,10 +4,32 @@ define(['./Component'],
return Component.extend({
defaults: _.extend({}, Component.prototype.defaults, {
src: '',
droppable: false,
traits: ['alt'],
tagName: 'img',
src: '',
void: 1,
droppable: false,
traits: ['alt'],
}),
/**
* Returns attributes string in HTML
* @return {string}
* @private
*/
toAttrHTML: function() {
var attr = '';
_.each(this.get('attributes'), function(value, prop){
if(prop == 'onmousedown')
return;
attr += value && prop!='style' ? ' ' + prop + '="' + value + '"' : '';
});
var src = this.get('src');
if(src)
attr += ' src="' + src + '"';
return attr;
}
});
});

3
src/dom_components/model/ComponentText.js

@ -4,8 +4,7 @@ define(['./Component'],
return Component.extend({
defaults: _.extend({}, Component.prototype.defaults, {
content : '',
droppable : false,
droppable: false,
}),
});

2
src/dom_components/model/ComponentVideo.js

@ -7,7 +7,7 @@ define(['./ComponentImage'],
type: 'video',
tagName: 'video',
provider: '', // on change of provider, traits are switched
traits: this.getSourceTraits(),
sources: [],
}),
// Listen provider change and switch traits, in TraitView listen traits change

44
src/dom_components/model/Components.js

@ -22,40 +22,22 @@ define([ 'backbone', 'require'],
if(opt && opt.config)
options.config = opt.config;
switch(attrs.type){
case 'text':
if(!this.mComponentText)
this.mComponentText = require("./ComponentText");
model = new this.mComponentText(attrs, options);
break;
case 'link':
if(!this.mComponentLink)
this.mComponentLink = require("./ComponentLink");
model = new this.mComponentLink(attrs, options);
break;
case 'image':
if(!this.mComponentImage)
this.mComponentImage = require("./ComponentImage");
model = new this.mComponentImage(attrs, options);
break;
case 'map':
if(!this.mComponentMap)
this.mComponentMap = require("./ComponentMap");
model = new this.mComponentMap(attrs, options);
break;
default:
if(!this.mComponent)
this.mComponent = require("./Component");
model = new this.mComponent(attrs, options);
if(opt && opt.defaultTypes)
options.defaultTypes = opt.defaultTypes;
if(opt && opt.componentTypes)
options.componentTypes = opt.componentTypes;
var df = opt.defaultTypes;
var cf = opt.componentTypes;
if(df[attrs.type]){
model = df[attrs.type].model;
}else{
model = df.default.model;
}
return model;
return new model(attrs, options);
};
},

16
src/dom_components/view/ComponentVideoView.js

@ -0,0 +1,16 @@
define(['backbone', './ComponentView'],
function (Backbone, ComponentView) {
return ComponentView.extend({
tagName: 'video',
events: {},
initialize: function(o){
ComponentView.prototype.initialize.apply(this, arguments);
console.log('Video view loaded');
},
});
});

3
src/dom_components/view/ComponentView.js

@ -12,6 +12,7 @@ define(['backbone', './ComponentsView'],
},
initialize: function(opt){
this.opts = opt || {};
this.config = opt.config || {};
this.pfx = this.config.stylePrefix || '';
this.ppfx = this.config.pStylePrefix || '';
@ -180,6 +181,8 @@ define(['backbone', './ComponentsView'],
var view = new ComponentsView({
collection: this.components,
config: this.config,
defaultTypes: this.opts.defaultTypes,
componentTypes: this.opts.componentTypes,
});
// With childNodes lets avoid wrapping 'div'

40
src/dom_components/view/ComponentsView.js

@ -4,7 +4,8 @@ function(Backbone, require) {
return Backbone.View.extend({
initialize: function(o) {
this.config = o.config;
this.opts = o || {};
this.config = o.config;
this.listenTo( this.collection, 'add', this.addTo );
this.listenTo( this.collection, 'reset', this.render );
},
@ -34,34 +35,19 @@ function(Backbone, require) {
if(!this.compView)
this.compView = require('./ComponentView');
var fragment = fragmentEl || null,
viewObject = this.compView;
viewObject = this.compView;
switch(model.get('type')){
case 'text':
if(!this.compViewText)
this.compViewText = require('./ComponentTextView');
viewObject = this.compViewText;
break;
case 'image':
if(!this.compViewImage)
this.compViewImage = require('./ComponentImageView');
viewObject = this.compViewImage;
break;
case 'link':
if(!this.compViewLink)
this.compViewLink = require('./ComponentLinkView');
viewObject = this.compViewLink;
break;
case 'map':
if(!this.compViewMap)
this.compViewMap = require('./ComponentMapView');
viewObject = this.compViewMap;
break;
}
var dt = this.opts.defaultTypes;
var ct = this.opts.componentTypes;
var type = model.get('type');
viewObject = dt[type] ? dt[type].view : dt.default.view;
var view = new viewObject({
model : model,
config : this.config,
var view = new viewObject({
model: model,
config: this.config,
defaultTypes: dt,
componentTypes: ct,
});
var rendered = view.render().el;

8
src/editor/config/config.js

@ -193,6 +193,14 @@ define(function () {
type: 'map',
style: {height: '350px'}
},
},{
id: 'video',
label: 'Video',
attributes: {class:'fa fa-youtube-play'},
content: {
type: 'video',
style: {height: '350px'}
},
}],
},

63
test/specs/dom_components/model/Component.js

@ -53,6 +53,48 @@ define(['DomComponents/model/Component',
obj.getName().should.equal('TestType 999');
});
it('Component toHTML', function() {
obj.toHTML().should.equal('<div></div>');
});
it('Component toHTML with attributes', function() {
obj = new Component({
tagName: 'article',
attributes: {
'data-test1': 'value1',
'data-test2': 'value2'
}
});
obj.toHTML().should.equal('<article data-test1="value1" data-test2="value2"></article>');
});
it('Component toHTML with classes', function() {
obj = new Component({
tagName: 'article'
});
['class1', 'class2'].forEach(function(item){
obj.get('classes').add({name: item});
});
obj.toHTML().should.equal('<article class="class1 class2"></article>');
});
it('Component toHTML with children', function() {
obj = new Component({tagName: 'article'});
obj.get('components').add({tagName: 'span'});
obj.toHTML().should.equal('<article><span></span></article>');
});
it('Component toHTML with more children', function() {
obj = new Component({tagName: 'article'});
obj.get('components').add([{tagName: 'span'}, {tagName: 'div'}]);
obj.toHTML().should.equal('<article><span></span><div></div></article>');
});
it('Component toHTML with no closing tag', function() {
obj = new Component({void: 1});
obj.toHTML().should.equal('<div/>');
});
});
describe('Image Component', function() {
@ -73,6 +115,19 @@ define(['DomComponents/model/Component',
obj.get('droppable').should.equal(false);
});
it('ComponentImage toHTML', function() {
obj = new ComponentImage();
obj.toHTML().should.equal('<img/>');
});
it('Component toHTML with attributes', function() {
obj = new ComponentImage({
attributes: {'alt': 'AltTest'},
src: 'testPath'
});
obj.toHTML().should.equal('<img alt="AltTest" src="testPath"/>');
});
});
describe('Text Component', function() {
@ -93,6 +148,14 @@ define(['DomComponents/model/Component',
obj.get('droppable').should.equal(false);
});
it('Component toHTML with attributes', function() {
obj = new ComponentText({
attributes: {'data-test': 'value'},
content: 'test content'
});
obj.toHTML().should.equal('<div data-test="value">test content</div>');
});
});
describe('Components', function() {

Loading…
Cancel
Save