grapesjs_codeapps
Version:
Free and Open Source Web Builder Framework/SC Modification
386 lines (347 loc) • 9.72 kB
JavaScript
import { isUndefined, isString } from 'underscore';
import { getModel } from 'utils/mixins';
import Backbone from 'backbone';
const ComponentView = require('dom_components/view/ComponentView');
const inputProp = 'contentEditable';
const $ = Backbone.$;
let ItemsView;
module.exports = Backbone.View.extend({
events: {
'mousedown [data-toggle-move]': 'startSort',
'touchstart [data-toggle-move]': 'startSort',
'click [data-toggle-visible]': 'toggleVisibility',
'click [data-toggle-select]': 'handleSelect',
'mouseover [data-toggle-select]': 'handleHover',
'click [data-toggle-open]': 'toggleOpening',
'dblclick [data-name]': 'handleEdit',
'focusout [data-name]': 'handleEditEnd'
},
template(model) {
const pfx = this.pfx;
const ppfx = this.ppfx;
const hidable = this.config.hidable;
const count = this.countChildren(model);
const addClass = !count ? this.clsNoChild : '';
const clsTitle = `${this.clsTitle} ${addClass}`;
const clsTitleC = `${this.clsTitleC} ${ppfx}one-bg`;
const clsCaret = `${this.clsCaret} fa fa-chevron-right`;
const clsInput = `${this.inputNameCls} ${ppfx}no-app`;
const level = this.level + 1;
const gut = `${30 + level * 10}px`;
const name = model.getName();
const key = name.toLowerCase().replace(' ', '-');
return `
${
hidable
? `<i class="${pfx}layer-vis fa fa-eye ${
this.isVisible() ? '' : 'fa-eye-slash'
}" data-toggle-visible></i>`
: ''
}
<div class="${clsTitleC}">
<div class="${clsTitle}" style="padding-left: ${gut}" data-toggle-select>
<div class="${pfx}layer-title-inn">
<i class="${clsCaret}" data-toggle-open></i>
${model.getIcon()}
<span class="${clsInput}" data-name>
${window.lang.lay[key] || name}
</span>
</div>
</div>
</div>
<div class="${this.clsCount}">${count || ''}</div>
<div class="${this.clsMove}" data-toggle-move>
<i class="fa fa-arrows"></i>
</div>
<div class="${this.clsChildren}"></div>`;
},
initialize(o = {}) {
this.opt = o;
this.level = o.level;
this.config = o.config;
this.em = o.config.em;
this.ppfx = this.em.get('Config').stylePrefix;
this.sorter = o.sorter || '';
this.pfx = this.config.stylePrefix;
const pfx = this.pfx;
const ppfx = this.ppfx;
const model = this.model;
const components = model.get('components');
model.set('open', false);
this.listenTo(components, 'remove add reset', this.checkChildren);
this.listenTo(model, 'change:status', this.updateStatus);
this.listenTo(model, 'change:open', this.updateOpening);
this.listenTo(model, 'change:style:display', this.updateVisibility);
this.className = `${pfx}layer no-select ${ppfx}two-color`;
this.inputNameCls = `${ppfx}layer-name`;
this.clsTitleC = `${pfx}layer-title-c`;
this.clsTitle = `${pfx}layer-title`;
this.clsCaret = `${pfx}layer-caret`;
this.clsCount = `${pfx}layer-count`;
this.clsMove = `${pfx}layer-move`;
this.clsChildren = `${pfx}layer-children`;
this.clsNoChild = `${pfx}layer-no-chld`;
this.$el.data('model', model);
this.$el.data('collection', components);
model.viewLayer = this;
},
getVisibilityEl() {
if (!this.eyeEl) {
this.eyeEl = this.$el.children(`.${this.pfx}layer-vis`);
}
return this.eyeEl;
},
updateVisibility() {
const pfx = this.pfx;
const model = this.model;
const hClass = `${pfx}layer-hidden`;
const hideIcon = 'fa-eye-slash';
const hidden = model.getStyle().display == 'none';
const method = hidden ? 'addClass' : 'removeClass';
this.$el[method](hClass);
this.getVisibilityEl()[method](hideIcon);
},
/**
* Toggle visibility
* @param Event
*
* @return void
* */
toggleVisibility(e) {
e && e.stopPropagation();
const model = this.model;
const style = model.getStyle();
const hidden = style.display == 'none';
if (hidden) {
delete style.display;
} else {
style.display = 'none';
}
model.setStyle(style);
},
/**
* Handle the edit of the component name
*/
handleEdit(e) {
e && e.stopPropagation();
const em = this.em;
const inputEl = this.getInputName();
console.log('handleEdit');
inputEl[inputProp] = true;
inputEl.focus();
em && em.setEditing(1);
},
/**
* Handle with the end of editing of the component name
*/
handleEditEnd(e) {
e && e.stopPropagation();
const em = this.em;
const inputEl = this.getInputName();
const name = inputEl.textContent;
inputEl[inputProp] = false;
this.model.set({ name });
em && em.setEditing(0);
},
/**
* Get the input containing the name of the component
* @return {HTMLElement}
*/
getInputName() {
if (!this.inputName) {
this.inputName = this.el.querySelector(`.${this.inputNameCls}`);
}
return this.inputName;
},
/**
* Update item opening
*
* @return void
* */
updateOpening() {
var opened = this.opt.opened || {};
var model = this.model;
const chvDown = 'fa-chevron-down';
if (model.get('open')) {
this.$el.addClass('open');
this.getCaret().addClass(chvDown);
opened[model.cid] = model;
} else {
this.$el.removeClass('open');
this.getCaret().removeClass(chvDown);
delete opened[model.cid];
}
},
/**
* Toggle item opening
* @param {Object} e
*
* @return void
* */
toggleOpening(e) {
e.stopPropagation();
if (!this.model.get('components').length) return;
this.model.set('open', !this.model.get('open'));
},
/**
* Handle component selection
*/
handleSelect(e) {
e.stopPropagation();
const { em, config } = this;
if (em) {
const model = this.model;
em.setSelected(model, { fromLayers: 1 });
const scroll = config.scrollCanvas;
scroll && em.get('Canvas').scrollTo(model, scroll);
}
},
/**
* Handle component selection
*/
handleHover(e) {
e.stopPropagation();
const { em, config, model } = this;
em && config.showHover && em.setHovered(model, { fromLayers: 1 });
},
/**
* Delegate to sorter
* @param Event
* */
startSort(e) {
e.stopPropagation();
const sorter = this.sorter;
// Right or middel click
if (e.button && e.button !== 0) return;
sorter && sorter.startSort(e.target);
},
/**
* Freeze item
* @return void
* */
freeze() {
this.$el.addClass(this.pfx + 'opac50');
this.model.set('open', 0);
},
/**
* Unfreeze item
* @return void
* */
unfreeze() {
this.$el.removeClass(this.pfx + 'opac50');
},
/**
* Update item on status change
* @param Event
* */
updateStatus(e) {
ComponentView.prototype.updateStatus.apply(this, [
{
avoidHover: !this.config.highlightHover
}
]);
},
/**
* Check if component is visible
*
* @return bool
* */
isVisible() {
var css = this.model.get('style'),
pr = css.display;
if (pr && pr == 'none') return;
return 1;
},
/**
* Update item aspect after children changes
*
* @return void
* */
checkChildren() {
const model = this.model;
const count = this.countChildren(model);
const pfx = this.pfx;
const noChildCls = this.clsNoChild;
const title = this.$el
.children(`.${this.clsTitleC}`)
.children(`.${this.clsTitle}`);
if (!this.cnt) {
this.cnt = this.$el.children(`.${this.clsCount}`);
}
if (count) {
title.removeClass(noChildCls);
this.cnt.html(count);
} else {
title.addClass(noChildCls);
this.cnt.empty();
model.set('open', 0);
}
},
/**
* Count children inside model
* @param {Object} model
* @return {number}
* @private
*/
countChildren(model) {
var count = 0;
model.get('components').each(function(m) {
var isCountable = this.opt.isCountable;
var hide = this.config.hideTextnode;
if (isCountable && !isCountable(m, hide)) return;
count++;
}, this);
return count;
},
getCaret() {
if (!this.caret || !this.caret.length) {
const pfx = this.pfx;
this.caret = this.$el
.children(`.${this.clsTitleC}`)
.find(`.${this.clsCaret}`);
}
return this.caret;
},
setRoot(el) {
el = isString(el) ? this.em.getWrapper().find(el)[0] : el;
const model = getModel(el, $);
if (!model) return;
this.stopListening();
this.model = model;
this.initialize(this.opt);
this.render();
},
render() {
const model = this.model;
var pfx = this.pfx;
var vis = this.isVisible();
const el = this.$el.empty();
const level = this.level + 1;
if (isUndefined(ItemsView)) {
ItemsView = require('./ItemsView');
}
const children = new ItemsView({
collection: model.get('components'),
config: this.config,
sorter: this.sorter,
opened: this.opt.opened,
parent: model,
level
}).render().$el;
if (!this.config.showWrapper && level === 1) {
el.append(children);
} else {
el.html(this.template(model));
el.find(`.${this.clsChildren}`).append(children);
}
if (!model.get('draggable') || !this.config.sortable) {
el.children(`.${this.clsMove}`).remove();
}
!vis && (this.className += ` ${pfx}hide`);
el.attr('class', this.className);
this.updateOpening();
this.updateStatus();
this.updateVisibility();
return this;
}
});