mirror of https://github.com/artf/grapesjs.git
13 changed files with 342 additions and 358 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,283 +1,301 @@ |
|||||
define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitManager/model/Traits'], |
define(['backbone','./Components', 'SelectorManager/model/Selectors', 'TraitManager/model/Traits'], |
||||
function (Backbone, Components, Selectors, Traits) { |
function (Backbone, Components, Selectors, Traits) { |
||||
|
|
||||
return Backbone.Model.extend({ |
return Backbone.Model.extend({ |
||||
|
|
||||
defaults: { |
defaults: { |
||||
// HTML tag of the component
|
// HTML tag of the component
|
||||
tagName: 'div', |
tagName: 'div', |
||||
|
|
||||
// Component type, eg. 'text', 'image', 'video', etc.
|
// Component type, eg. 'text', 'image', 'video', etc.
|
||||
type: '', |
type: '', |
||||
|
|
||||
// True if the component is removable from the canvas
|
// True if the component is removable from the canvas
|
||||
removable: true, |
removable: true, |
||||
|
|
||||
// Indicates if it's possible to drag the component inside other
|
// Indicates if it's possible to drag the component inside other
|
||||
// Tip: Indicate an array of selectors where it could be dropped inside
|
// Tip: Indicate an array of selectors where it could be dropped inside
|
||||
draggable: true, |
draggable: true, |
||||
|
|
||||
// Indicates if it's possible to drop other components inside
|
// Indicates if it's possible to drop other components inside
|
||||
// Tip: Indicate an array of selectors which could be dropped inside
|
// Tip: Indicate an array of selectors which could be dropped inside
|
||||
droppable: true, |
droppable: true, |
||||
|
|
||||
// Set false if don't want to see the badge (with the name) over the component
|
// Set false if don't want to see the badge (with the name) over the component
|
||||
badgable: true, |
badgable: true, |
||||
|
|
||||
// True if it's possible to style it
|
// True if it's possible to style it
|
||||
// Tip: Indicate an array of CSS properties which is possible to style
|
// Tip: Indicate an array of CSS properties which is possible to style
|
||||
stylable: true, |
stylable: true, |
||||
|
|
||||
// True if it's possible to clone the component
|
// True if it's possible to clone the component
|
||||
copyable: true, |
copyable: true, |
||||
|
|
||||
// Indicates if it possible to resize the component (at the moment implemented only on Image Components)
|
// Indicates if it's possible to resize the component (at the moment implemented only on Image Components)
|
||||
resizable: false, |
resizable: false, |
||||
|
|
||||
// This property is used by the HTML exporter as void elements do not
|
// Allow to edit the content of the component (used on Text components)
|
||||
// have closing tag, eg. <br/>, <hr/>, etc.
|
editable: false, |
||||
void: false, |
|
||||
|
// This property is used by the HTML exporter as void elements do not
|
||||
// Indicates if the component is in some CSS state like ':hover', ':active', etc.
|
// have closing tag, eg. <br/>, <hr/>, etc.
|
||||
state: '', |
void: false, |
||||
|
|
||||
status: '', |
// Indicates if the component is in some CSS state like ':hover', ':active', etc.
|
||||
|
state: '', |
||||
previousModel: '', |
|
||||
content: '', |
// State, eg. 'selected'
|
||||
style: {}, |
status: '', |
||||
attributes: {}, |
|
||||
classes: '', |
// Content of the component (not escaped) which will be appended before children rendering
|
||||
traits: ['id', 'title'], |
content: '', |
||||
|
|
||||
/** |
// Component related style
|
||||
* Set an array of items to show up inside the toolbar (eg. move, clone, delete) |
style: {}, |
||||
* when the component is selected |
|
||||
* toolbar: [{ |
// Key-value object of the component's attributes
|
||||
* attributes: {class: 'fa fa-arrows'}, |
attributes: {}, |
||||
* command: 'tlb-move', |
|
||||
* },{ |
// Array of classes
|
||||
* attributes: {class: 'fa fa-clone'}, |
classes: '', |
||||
* command: 'tlb-clone', |
|
||||
* }] |
// Traits
|
||||
*/ |
traits: ['id', 'title'], |
||||
toolbar: null, |
|
||||
|
/** |
||||
// TODO
|
* Set an array of items to show up inside the toolbar (eg. move, clone, delete) |
||||
editable: false, |
* when the component is selected |
||||
mirror: '', |
* toolbar: [{ |
||||
}, |
* attributes: {class: 'fa fa-arrows'}, |
||||
|
* command: 'tlb-move', |
||||
initialize: function(o, opt) { |
* },{ |
||||
// Check void elements
|
* attributes: {class: 'fa fa-clone'}, |
||||
if(opt && opt.config && opt.config.voidElements.indexOf(this.get('tagName')) >= 0) |
* command: 'tlb-clone', |
||||
this.set('void', true); |
* }] |
||||
|
*/ |
||||
this.opt = opt; |
toolbar: null, |
||||
this.sm = opt ? opt.sm || {} : {}; |
|
||||
this.config = o || {}; |
// TODO
|
||||
this.defaultC = this.config.components || []; |
previousModel: '', |
||||
this.defaultCl = this.normalizeClasses(this.get('classes') || this.config.classes || []); |
mirror: '', |
||||
this.components = new Components(this.defaultC, opt); |
}, |
||||
this.components.parent = this; |
|
||||
this.set('components', this.components); |
initialize: function(o, opt) { |
||||
this.set('classes', new Selectors(this.defaultCl)); |
// Check void elements
|
||||
var traits = new Traits(); |
if(opt && opt.config && opt.config.voidElements.indexOf(this.get('tagName')) >= 0) |
||||
traits.setTarget(this); |
this.set('void', true); |
||||
traits.add(this.get('traits')); |
|
||||
this.set('traits', traits); |
this.opt = opt; |
||||
this.initToolbar(); |
this.sm = opt ? opt.sm || {} : {}; |
||||
}, |
this.config = o || {}; |
||||
|
this.defaultC = this.config.components || []; |
||||
/** |
this.defaultCl = this.normalizeClasses(this.get('classes') || this.config.classes || []); |
||||
* Init toolbar |
this.components = new Components(this.defaultC, opt); |
||||
*/ |
this.components.parent = this; |
||||
initToolbar: function () { |
this.set('components', this.components); |
||||
var model = this; |
this.set('classes', new Selectors(this.defaultCl)); |
||||
if(!model.get('toolbar')) { |
var traits = new Traits(); |
||||
var tb = []; |
traits.setTarget(this); |
||||
if(model.get('draggable')) { |
traits.add(this.get('traits')); |
||||
tb.push({ |
this.set('traits', traits); |
||||
attributes: {class: 'fa fa-arrows'}, |
this.initToolbar(); |
||||
command: 'tlb-move', |
this.init(); |
||||
}); |
}, |
||||
} |
|
||||
if(model.get('copyable')) { |
/** |
||||
tb.push({ |
* Initialize callback |
||||
attributes: {class: 'fa fa-clone'}, |
*/ |
||||
command: 'tlb-clone', |
init: function () {}, |
||||
}); |
|
||||
} |
/** |
||||
if(model.get('removable')) { |
* Init toolbar |
||||
tb.push({ |
*/ |
||||
attributes: {class: 'fa fa-trash-o'}, |
initToolbar: function () { |
||||
command: 'tlb-delete', |
var model = this; |
||||
}); |
if(!model.get('toolbar')) { |
||||
} |
var tb = []; |
||||
model.set('toolbar', tb); |
if(model.get('draggable')) { |
||||
} |
tb.push({ |
||||
}, |
attributes: {class: 'fa fa-arrows'}, |
||||
|
command: 'tlb-move', |
||||
/** |
}); |
||||
* Load traits |
} |
||||
* @param {Array} traits |
if(model.get('copyable')) { |
||||
* @private |
tb.push({ |
||||
*/ |
attributes: {class: 'fa fa-clone'}, |
||||
loadTraits: function(traits) { |
command: 'tlb-clone', |
||||
var trt = new Traits(); |
}); |
||||
trt.setTarget(this); |
} |
||||
trt.add(traits); |
if(model.get('removable')) { |
||||
this.set('traits', trt); |
tb.push({ |
||||
}, |
attributes: {class: 'fa fa-trash-o'}, |
||||
|
command: 'tlb-delete', |
||||
/** |
}); |
||||
* Normalize input classes from array to array of objects |
} |
||||
* @param {Array} arr |
model.set('toolbar', tb); |
||||
* @return {Array} |
} |
||||
* @private |
}, |
||||
*/ |
|
||||
normalizeClasses: function(arr) { |
/** |
||||
var res = []; |
* Load traits |
||||
|
* @param {Array} traits |
||||
if(!this.sm.get) |
* @private |
||||
return; |
*/ |
||||
|
loadTraits: function(traits) { |
||||
var clm = this.sm.get('SelectorManager'); |
var trt = new Traits(); |
||||
if(!clm) |
trt.setTarget(this); |
||||
return; |
trt.add(traits); |
||||
|
this.set('traits', trt); |
||||
arr.forEach(function(val){ |
}, |
||||
var name = ''; |
|
||||
|
/** |
||||
if(typeof val === 'string') |
* Normalize input classes from array to array of objects |
||||
name = val; |
* @param {Array} arr |
||||
else |
* @return {Array} |
||||
name = val.name; |
* @private |
||||
|
*/ |
||||
var model = clm.add(name); |
normalizeClasses: function(arr) { |
||||
res.push(model); |
var res = []; |
||||
}); |
|
||||
return res; |
if(!this.sm.get) |
||||
}, |
return; |
||||
|
|
||||
/** |
var clm = this.sm.get('SelectorManager'); |
||||
* Override original clone method |
if(!clm) |
||||
* @private |
return; |
||||
*/ |
|
||||
clone: function() { |
arr.forEach(function(val){ |
||||
var attr = _.clone(this.attributes), |
var name = ''; |
||||
comp = this.get('components'), |
|
||||
traits = this.get('traits'), |
if(typeof val === 'string') |
||||
cls = this.get('classes'); |
name = val; |
||||
attr.components = []; |
else |
||||
attr.classes = []; |
name = val.name; |
||||
attr.traits = []; |
|
||||
if(comp.length){ |
var model = clm.add(name); |
||||
comp.each(function(md,i) { |
res.push(model); |
||||
attr.components[i] = md.clone(); |
}); |
||||
}); |
return res; |
||||
} |
}, |
||||
if(traits.length){ |
|
||||
traits.each(function(md, i) { |
/** |
||||
attr.traits[i] = md.clone(); |
* Override original clone method |
||||
}); |
* @private |
||||
} |
*/ |
||||
if(cls.length){ |
clone: function() { |
||||
cls.each(function(md,i) { |
var attr = _.clone(this.attributes), |
||||
attr.classes[i] = md.get('name'); |
comp = this.get('components'), |
||||
}); |
traits = this.get('traits'), |
||||
} |
cls = this.get('classes'); |
||||
attr.status = ''; |
attr.components = []; |
||||
attr.view = ''; |
attr.classes = []; |
||||
|
attr.traits = []; |
||||
return new this.constructor(attr, this.opt); |
if(comp.length){ |
||||
}, |
comp.each(function(md,i) { |
||||
|
attr.components[i] = md.clone(); |
||||
/** |
}); |
||||
* Get name of the component |
} |
||||
* @return {string} |
if(traits.length){ |
||||
* @private |
traits.each(function(md, i) { |
||||
* */ |
attr.traits[i] = md.clone(); |
||||
getName: function() { |
}); |
||||
if(!this.name){ |
} |
||||
var id = this.cid.replace(/\D/g,''), |
if(cls.length){ |
||||
type = this.get('type'); |
cls.each(function(md,i) { |
||||
var tag = this.get('tagName'); |
attr.classes[i] = md.get('name'); |
||||
tag = tag == 'div' ? 'box' : tag; |
}); |
||||
tag = type ? type : tag; |
} |
||||
this.name = tag.charAt(0).toUpperCase() + tag.slice(1); |
attr.status = ''; |
||||
} |
attr.view = ''; |
||||
return this.name; |
|
||||
}, |
return new this.constructor(attr, this.opt); |
||||
|
}, |
||||
/** |
|
||||
* Return HTML string of the component |
/** |
||||
* @param {Object} opts Options |
* Get name of the component |
||||
* @return {string} HTML string |
* @return {string} |
||||
* @private |
* @private |
||||
*/ |
* */ |
||||
toHTML: function(opts) { |
getName: function() { |
||||
var code = ''; |
if(!this.name){ |
||||
var m = this; |
var id = this.cid.replace(/\D/g,''), |
||||
var tag = m.get('tagName'), |
type = this.get('type'); |
||||
sTag = m.get('void'), |
var tag = this.get('tagName'); |
||||
attrId = ''; |
tag = tag == 'div' ? 'box' : tag; |
||||
// Build the string of attributes
|
tag = type ? type : tag; |
||||
var strAttr = ''; |
this.name = tag.charAt(0).toUpperCase() + tag.slice(1); |
||||
var attr = this.getAttrToHTML(); |
} |
||||
for(var prop in attr){ |
return this.name; |
||||
var val = attr[prop]; |
}, |
||||
strAttr += typeof val !== undefined && val !== '' ? |
|
||||
' ' + prop + '="' + val + '"' : ''; |
/** |
||||
} |
* Return HTML string of the component |
||||
// Build the string of classes
|
* @param {Object} opts Options |
||||
var strCls = ''; |
* @return {string} HTML string |
||||
m.get('classes').each(function(m){ |
* @private |
||||
strCls += ' ' + m.get('name'); |
*/ |
||||
}); |
toHTML: function(opts) { |
||||
strCls = strCls !== '' ? ' class="' + strCls.trim() + '"' : ''; |
var code = ''; |
||||
|
var m = this; |
||||
// If style is not empty I need an ID attached to the component
|
var tag = m.get('tagName'), |
||||
// TODO: need to refactor in case of 'ID Trait'
|
sTag = m.get('void'), |
||||
if(!_.isEmpty(m.get('style'))) |
attrId = ''; |
||||
attrId = ' id="' + m.cid + '" '; |
// Build the string of attributes
|
||||
|
var strAttr = ''; |
||||
code += '<' + tag + strCls + attrId + strAttr + (sTag ? '/' : '') + '>' + m.get('content'); |
var attr = this.getAttrToHTML(); |
||||
|
for(var prop in attr){ |
||||
m.get('components').each(function(m) { |
var val = attr[prop]; |
||||
code += m.toHTML(); |
strAttr += typeof val !== undefined && val !== '' ? |
||||
}); |
' ' + prop + '="' + val + '"' : ''; |
||||
|
} |
||||
if(!sTag) |
// Build the string of classes
|
||||
code += '</'+tag+'>'; |
var strCls = ''; |
||||
|
m.get('classes').each(function(m){ |
||||
return code; |
strCls += ' ' + m.get('name'); |
||||
}, |
}); |
||||
|
strCls = strCls !== '' ? ' class="' + strCls.trim() + '"' : ''; |
||||
/** |
|
||||
* Returns object of attributes for HTML |
// If style is not empty I need an ID attached to the component
|
||||
* @return {Object} |
// TODO: need to refactor in case of 'ID Trait'
|
||||
* @private |
if(!_.isEmpty(m.get('style'))) |
||||
*/ |
attrId = ' id="' + m.cid + '" '; |
||||
getAttrToHTML: function() { |
|
||||
var attr = this.get('attributes') || {}; |
code += '<' + tag + strCls + attrId + strAttr + (sTag ? '/' : '') + '>' + m.get('content'); |
||||
delete attr.style; |
|
||||
return attr; |
m.get('components').each(function(m) { |
||||
}, |
code += m.toHTML(); |
||||
|
}); |
||||
},{ |
|
||||
|
if(!sTag) |
||||
/** |
code += '</'+tag+'>'; |
||||
* Detect if the passed element is a valid component. |
|
||||
* In case the element is valid an object abstracted |
return code; |
||||
* from the element will be returned |
}, |
||||
* @param {HTMLElement} |
|
||||
* @return {Object} |
/** |
||||
* @private |
* Returns object of attributes for HTML |
||||
*/ |
* @return {Object} |
||||
isComponent: function(el) { |
* @private |
||||
return {tagName: el.tagName ? el.tagName.toLowerCase() : ''}; |
*/ |
||||
}, |
getAttrToHTML: function() { |
||||
|
var attr = this.get('attributes') || {}; |
||||
}); |
delete attr.style; |
||||
|
return attr; |
||||
|
}, |
||||
|
|
||||
|
},{ |
||||
|
|
||||
|
/** |
||||
|
* Detect if the passed element is a valid component. |
||||
|
* In case the element is valid an object abstracted |
||||
|
* from the element will be returned |
||||
|
* @param {HTMLElement} |
||||
|
* @return {Object} |
||||
|
* @private |
||||
|
*/ |
||||
|
isComponent: function(el) { |
||||
|
return {tagName: el.tagName ? el.tagName.toLowerCase() : ''}; |
||||
|
}, |
||||
|
|
||||
|
}); |
||||
}); |
}); |
||||
|
|||||
Loading…
Reference in new issue