mirror of https://github.com/artf/grapesjs.git
nocodeframeworkdrag-and-dropsite-buildersite-generatortemplate-builderui-builderweb-builderweb-builder-frameworkwebsite-builderno-codepage-builder
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
348 lines
7.6 KiB
348 lines
7.6 KiB
var Backbone = require('backbone');
|
|
var ComponentsView = require('./ComponentsView');
|
|
|
|
module.exports = Backbone.View.extend({
|
|
|
|
className() {
|
|
return this.getClasses();
|
|
},
|
|
|
|
tagName() {
|
|
return this.model.get('tagName');
|
|
},
|
|
|
|
initialize(opt) {
|
|
var model = this.model;
|
|
this.opts = opt || {};
|
|
this.config = this.opts.config || {};
|
|
this.em = this.config.em || '';
|
|
this.pfx = this.config.stylePrefix || '';
|
|
this.ppfx = this.config.pStylePrefix || '';
|
|
this.components = model.get('components');
|
|
this.attr = model.get("attributes");
|
|
this.classe = this.attr.class || [];
|
|
this.listenTo(model, 'destroy remove', this.remove);
|
|
this.listenTo(model, 'change:style', this.updateStyle);
|
|
this.listenTo(model, 'change:attributes', this.updateAttributes);
|
|
this.listenTo(model, 'change:status', this.updateStatus);
|
|
this.listenTo(model, 'change:state', this.updateState);
|
|
this.listenTo(model, 'change:script', this.render);
|
|
this.listenTo(model, 'change', this.handleChange);
|
|
this.listenTo(model.get('classes'), 'add remove change', this.updateClasses);
|
|
this.$el.data('model', model);
|
|
model.view = this;
|
|
this.$el.data("collection", this.components);
|
|
|
|
if(model.get('classes').length)
|
|
this.importClasses();
|
|
|
|
this.init();
|
|
},
|
|
|
|
/**
|
|
* Initialize callback
|
|
*/
|
|
init() {},
|
|
|
|
/**
|
|
* Handle any property change
|
|
* @private
|
|
*/
|
|
handleChange() {
|
|
var em = this.em;
|
|
if(em) {
|
|
var model = this.model;
|
|
em.trigger('component:update', model);
|
|
|
|
for(var prop in model.changed) {
|
|
em.trigger('component:update:' + prop, model);
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Import, if possible, classes inside main container
|
|
* @private
|
|
* */
|
|
importClasses() {
|
|
var clm = this.config.em.get('SelectorManager');
|
|
|
|
if(clm){
|
|
this.model.get('classes').each(m => {
|
|
clm.add(m.get('name'));
|
|
});
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Fires on state update. If the state is not empty will add a helper class
|
|
* @param {Event} e
|
|
* @private
|
|
* */
|
|
updateState(e) {
|
|
var cl = 'hc-state';
|
|
var state = this.model.get('state');
|
|
|
|
if(state){
|
|
this.$el.addClass(cl);
|
|
}else{
|
|
this.$el.removeClass(cl);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Update item on status change
|
|
* @param {Event} e
|
|
* @private
|
|
* */
|
|
updateStatus(e) {
|
|
var el = this.el;
|
|
var status = this.model.get('status');
|
|
var pfx = this.pfx;
|
|
var ppfx = this.ppfx;
|
|
var selectedCls = pfx + 'selected';
|
|
var selectedParentCls = selectedCls + '-parent';
|
|
var freezedCls = `${ppfx}freezed`;
|
|
var actualCls = el.getAttribute('class') || '';
|
|
var cls = '';
|
|
|
|
switch (status) {
|
|
case 'selected':
|
|
cls = `${actualCls} ${selectedCls}`;
|
|
break;
|
|
case 'selected-parent':
|
|
cls = `${actualCls} ${selectedParentCls}`;
|
|
break;
|
|
case 'freezed':
|
|
cls = `${actualCls} ${freezedCls}`;
|
|
break;
|
|
default:
|
|
this.$el.removeClass(`${selectedCls} ${selectedParentCls} ${freezedCls}`);
|
|
}
|
|
|
|
cls = cls.trim();
|
|
|
|
if (cls) {
|
|
el.setAttribute('class', cls);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Get classes from attributes.
|
|
* This method is called before initialize
|
|
*
|
|
* @return {Array}|null
|
|
* @private
|
|
* */
|
|
getClasses() {
|
|
var attr = this.model.get("attributes"),
|
|
classes = attr['class'] || [];
|
|
if(classes.length){
|
|
return classes.join(" ");
|
|
}else
|
|
return null;
|
|
},
|
|
|
|
/**
|
|
* Update attributes
|
|
* @private
|
|
* */
|
|
updateAttributes() {
|
|
var model = this.model;
|
|
var attributes = {},
|
|
attr = model.get("attributes");
|
|
for(var key in attr) {
|
|
if(attr.hasOwnProperty(key))
|
|
attributes[key] = attr[key];
|
|
}
|
|
|
|
// Update src
|
|
if(model.get('src'))
|
|
attributes.src = model.get('src');
|
|
|
|
if(model.get('highlightable'))
|
|
attributes['data-highlightable'] = 1;
|
|
|
|
var styleStr = this.getStyleString();
|
|
|
|
if(styleStr)
|
|
attributes.style = styleStr;
|
|
|
|
this.$el.attr(attributes);
|
|
},
|
|
|
|
/**
|
|
* Update style attribute
|
|
* @private
|
|
* */
|
|
updateStyle() {
|
|
this.$el.attr('style', this.getStyleString());
|
|
},
|
|
|
|
/**
|
|
* Update component content
|
|
* @private
|
|
* */
|
|
updateContent() {
|
|
this.getChildrenContainer().innerHTML = this.model.get('content');
|
|
},
|
|
|
|
/**
|
|
* Return style string
|
|
* @return {string}
|
|
* @private
|
|
* */
|
|
getStyleString() {
|
|
var style = '';
|
|
this.style = this.model.get('style');
|
|
for(var key in this.style) {
|
|
if(this.style.hasOwnProperty(key))
|
|
style += key + ':' + this.style[key] + ';';
|
|
}
|
|
|
|
return style;
|
|
},
|
|
|
|
/**
|
|
* Update classe attribute
|
|
* @private
|
|
* */
|
|
updateClasses() {
|
|
var str = '';
|
|
|
|
this.model.get('classes').each(model => {
|
|
str += model.get('name') + ' ';
|
|
});
|
|
str = str.trim();
|
|
|
|
if(str)
|
|
this.$el.attr('class', str);
|
|
else
|
|
this.$el.removeAttr('class');
|
|
|
|
// Regenerate status class
|
|
this.updateStatus();
|
|
},
|
|
|
|
/**
|
|
* Reply to event call
|
|
* @param object Event that generated the request
|
|
* @private
|
|
* */
|
|
eventCall(event) {
|
|
event.viewResponse = this;
|
|
},
|
|
|
|
/**
|
|
* Prevent default helper
|
|
* @param {Event} e
|
|
* @private
|
|
*/
|
|
prevDef(e) {
|
|
e.preventDefault();
|
|
},
|
|
|
|
/**
|
|
* Render component's script
|
|
* @private
|
|
*/
|
|
updateScript() {
|
|
if (!this.model.get('script')) {
|
|
return;
|
|
}
|
|
|
|
var em = this.em;
|
|
if(em) {
|
|
var canvas = em.get('Canvas');
|
|
canvas.getCanvasView().updateScript(this);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Return children container
|
|
* Differently from a simple component where children container is the
|
|
* component itself
|
|
* <my-comp>
|
|
* <!--
|
|
* <child></child> ...
|
|
* -->
|
|
* </my-comp>
|
|
* You could have the children container more deeper
|
|
* <my-comp>
|
|
* <div></div>
|
|
* <div></div>
|
|
* <div>
|
|
* <div>
|
|
* <!--
|
|
* <child></child> ...
|
|
* -->
|
|
* </div>
|
|
* </div>
|
|
* </my-comp>
|
|
* @return HTMLElement
|
|
* @private
|
|
*/
|
|
getChildrenContainer() {
|
|
var container = this.el;
|
|
|
|
if (typeof this.getChildrenSelector == 'function') {
|
|
container = this.el.querySelector(this.getChildrenSelector());
|
|
} else if (typeof this.getTemplate == 'function') {
|
|
// Need to find deepest first child
|
|
}
|
|
|
|
return container;
|
|
},
|
|
|
|
/**
|
|
* Render children components
|
|
* @private
|
|
*/
|
|
renderChildren() {
|
|
var view = new ComponentsView({
|
|
collection: this.model.get('components'),
|
|
config: this.config,
|
|
componentTypes: this.opts.componentTypes,
|
|
});
|
|
|
|
var container = this.getChildrenContainer();
|
|
var childNodes = view.render($(container)).el.childNodes;
|
|
childNodes = Array.prototype.slice.call(childNodes);
|
|
|
|
for (var i = 0, len = childNodes.length ; i < len; i++) {
|
|
container.appendChild(childNodes.shift());
|
|
}
|
|
|
|
// If the children container is not the same as the component
|
|
// (so likely fetched with getChildrenSelector()) is necessary
|
|
// to disable pointer-events for all nested components as they
|
|
// might prevent the component to be selected
|
|
if (container !== this.el) {
|
|
var disableNode = el => {
|
|
var children = Array.prototype.slice.call(el.children);
|
|
children.forEach(el => {
|
|
el.style['pointer-events'] = 'none';
|
|
if (container !== el) {
|
|
disableNode(el);
|
|
}
|
|
});
|
|
};
|
|
disableNode(this.el);
|
|
}
|
|
},
|
|
|
|
renderAttributes() {
|
|
this.updateAttributes();
|
|
this.updateClasses();
|
|
},
|
|
|
|
render() {
|
|
this.renderAttributes();
|
|
var model = this.model;
|
|
this.updateContent();
|
|
this.renderChildren();
|
|
this.updateScript();
|
|
return this;
|
|
},
|
|
|
|
});
|
|
|