suneditor
Version:
Pure JavaScript based WYSIWYG web editor
163 lines (131 loc) • 5.18 kB
JavaScript
/*
* wysiwyg web editor
*
* suneditor.js
* Copyright 2017 JiHong Lee.
* MIT license.
*/
;
export default {
name: 'textStyle',
display: 'submenu',
add: function (core, targetElement) {
const context = core.context;
context.textStyle = {
_styleList: null
};
/** set submenu */
let listDiv = this.setSubmenu.call(core);
let listUl = listDiv.querySelector('ul');
/** add event listeners */
listUl.addEventListener('click', this.pickup.bind(core));
context.textStyle._styleList = listDiv.querySelectorAll('li button');
/** append target button menu */
core.initMenuTarget(this.name, targetElement, listDiv);
/** empty memory */
listDiv = null, listUl = null;
},
setSubmenu: function () {
const option = this.context.option;
const listDiv = this.util.createElement('DIV');
listDiv.className = 'se-submenu se-list-layer';
const defaultList = {
translucent: {
name: this.lang.menu.translucent,
style: 'opacity: 0.5;',
tag: 'span',
},
shadow: {
name: this.lang.menu.shadow,
class: '__se__t-shadow',
tag: 'span',
}
};
const styleList = !option.textStyles ? ['translucent', 'shadow'] : option.textStyles;
let list = '<div class="se-list-inner"><ul class="se-list-basic se-list-format">';
for (let i = 0, len = styleList.length, t, tag, name, attrs, command, value, _class; i < len; i++) {
t = styleList[i];
attrs = '', value = '', command = [];
if (typeof t === 'string') {
const defaultStyle = defaultList[t.toLowerCase()];
if (!defaultStyle) continue;
t = defaultStyle;
}
name = t.name;
tag = t.tag || 'span';
_class = t._class;
if (t.style) {
attrs += ' style="' + t.style + '"';
value += t.style.replace(/:[^;]+(;|$)\s*/g, ',');
command.push('style');
}
if (t.class) {
attrs += ' class="' + t.class + '"';
value += '.' + t.class.trim().replace(/\s+/g, ',.');
command.push('class');
}
value = value.replace(/,$/, '');
list += '<li>' +
'<button type="button" class="se-btn-list' + (_class ? ' ' + _class: '') + '" data-command="' + tag + '" data-value="' + value + '" title="' + name + '">' +
'<' + tag + attrs + '>' + name + '</' + tag + '>' +
'</button></li>';
}
list += '</ul></div>';
listDiv.innerHTML = list;
return listDiv;
},
/**
* @overriding submenu
*/
on: function () {
const util = this.util;
const textStyleContext = this.context.textStyle;
const styleButtonList = textStyleContext._styleList;
const selectionNode = this.getSelectionNode();
for (let i = 0, len = styleButtonList.length, btn, data, active; i < len; i++) {
btn = styleButtonList[i];
data = btn.getAttribute('data-value').split(',');
for (let v = 0, node, value; v < data.length; v++) {
node = selectionNode;
active = false;
while (!util.isFormatElement(node)) {
if (node.nodeName.toLowerCase() === btn.getAttribute('data-command').toLowerCase()) {
value = data[v];
if (/^\./.test(value) ? util.hasClass(node, value.replace(/^\./, '')) : !!node.style[value]) {
active = true;
break;
}
}
node = node.parentNode;
}
if (!active) break;
}
active ? util.addClass(btn, 'active') : util.removeClass(btn, 'active');
}
},
pickup: function (e) {
e.preventDefault();
e.stopPropagation();
let target = e.target;
let command = null, tag = null;
while (!command && !/UL/i.test(target.tagName)) {
command = target.getAttribute('data-command');
if (command) {
tag = target.firstChild;
break;
}
target = target.parentNode;
}
if (!command) return;
const checkStyles = tag.style.cssText.replace(/:.+(;|$)/g, ',').split(',');
checkStyles.pop();
const classes = tag.classList;
for (let i = 0, len = classes.length; i < len; i++) {
checkStyles.push('.' + classes[i]);
}
const newNode = this.util.hasClass(target, 'active') ? null : tag.cloneNode(false);
const removeNodes = newNode ? null : [tag.nodeName];
this.nodeChange(newNode, checkStyles, removeNodes, true);
this.submenuOff();
}
};