constlang=this.lang;
constlistDiv=this.util.createElement('DIV');
- listDiv.className='se-list-layer';
+ listDiv.className='se-submenu se-list-layer';
listDiv.innerHTML=''+'<div class="se-list-inner se-list-align">'+' <ul class="se-list-basic">'+
diff --git a/sample/html/getting-started.html b/sample/html/getting-started.html
index 68580d56a..962ba0910 100644
--- a/sample/html/getting-started.html
+++ b/sample/html/getting-started.html
@@ -317,7 +317,7 @@
tag:'div', // Tag name
name:'Custom div'||null, // default: tag name
command:'replace'||'range', // default: "replace"
- class:'__se__format__xxx'||null, // Class names must always begin with "__se__format__"
+ class:'__se__format__replace__xxx'||'__se__format__range__xxx', // Class names must always begin with "__se__format__(replace or range)__"
}]
colorList :Changedefault color array of color picker. default: [..[..]..] {Array}
Default value: [
diff --git a/sample/html/out/document-util.html b/sample/html/out/document-util.html
index d6658bf29..70ecb77ab 100644
--- a/sample/html/out/document-util.html
+++ b/sample/html/out/document-util.html
@@ -354,7 +354,7 @@
Parameters:
isFormatElement(element) → {Boolean}
- It is judged whether it is the format element. (P, DIV, H1-6, LI, TH, TD)
+ It is judged whether it is the format element. (P, DIV, H1-6, PRE, LI, TH, TD)
Parameters:
@@ -381,7 +381,7 @@
Parameters:
isRangeFormatElement(element) → {Boolean}
- It is judged whether it is the range format element. (BLOCKQUOTE, OL, UL, PRE, FIGCAPTION, TABLE, THEAD, TBODY, TR, TH, TD)
+ It is judged whether it is the range format element. (BLOCKQUOTE, OL, UL, FIGCAPTION, TABLE, THEAD, TBODY, TR, TH, TD)
Range format element is wrap the format element (P, DIV, H1-6, LI)
diff --git a/src/lib/core.js b/src/lib/core.js
index f4269e92d..3c9f9d297 100755
--- a/src/lib/core.js
+++ b/src/lib/core.js
@@ -1040,7 +1040,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
while (children[0]) {
c = children[0];
- if (util.isIgnoreNodeChange(c) && !util.isBreak(c) && !util.isListCell(format)) {
+ if (util._isIgnoreNodeChange(c) && !util.isBreak(c) && !util.isListCell(format)) {
if (format.childNodes.length > 0) {
if (!first) first = format;
parent.insertBefore(format, sibling);
@@ -1423,19 +1423,19 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
// node Changes
newNode = appendNode.cloneNode(false);
- const isRemoveAnchor = isRemoveFormat || (isRemoveNode && (function (arr, isAnchor) {
+ const isRemoveAnchor = isRemoveFormat || (isRemoveNode && (function (arr, _isMaintainedNode) {
for (let n = 0, len = arr.length; n < len; n++) {
- if (isAnchor(arr[n])) return true;
+ if (_isMaintainedNode(arr[n])) return true;
}
return false;
- })(removeNodeArray, util.isAnchor));
+ })(removeNodeArray, util._isMaintainedNode));
- const _getAnchor = this._util_getAnchor.bind(util, isRemoveAnchor);
- const _isAnchor = this._util_isAnchor.bind(util, isRemoveAnchor);
+ const _getMaintainedNode = this._util_getMaintainedNode.bind(util, isRemoveAnchor);
+ const _isMaintainedNode = this._util_isMaintainedNode.bind(util, isRemoveAnchor);
// one line
if (oneLine) {
- const newRange = this._nodeChange_oneLine(lineNodes[0], newNode, validation, startCon, startOff, endCon, endOff, isRemoveFormat, isRemoveNode, range.collapsed, _removeCheck, _getAnchor, _isAnchor);
+ const newRange = this._nodeChange_oneLine(lineNodes[0], newNode, validation, startCon, startOff, endCon, endOff, isRemoveFormat, isRemoveNode, range.collapsed, _removeCheck, _getMaintainedNode, _isMaintainedNode);
start.container = newRange.startContainer;
start.offset = newRange.startOffset;
end.container = newRange.endContainer;
@@ -1444,7 +1444,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
// multi line
else {
// start
- start = this._nodeChange_startLine(lineNodes[0], newNode, validation, startCon, startOff, isRemoveFormat, isRemoveNode, _removeCheck, _getAnchor, _isAnchor);
+ start = this._nodeChange_startLine(lineNodes[0], newNode, validation, startCon, startOff, isRemoveFormat, isRemoveNode, _removeCheck, _getMaintainedNode, _isMaintainedNode);
// mid
for (let i = 1; i < endLength; i++) {
newNode = appendNode.cloneNode(false);
@@ -1453,7 +1453,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
// end
if (endLength > 0) {
newNode = appendNode.cloneNode(false);
- end = this._nodeChange_endLine(lineNodes[endLength], newNode, validation, endCon, endOff, isRemoveFormat, isRemoveNode, _removeCheck, _getAnchor, _isAnchor);
+ end = this._nodeChange_endLine(lineNodes[endLength], newNode, validation, endCon, endOff, isRemoveFormat, isRemoveNode, _removeCheck, _getMaintainedNode, _isMaintainedNode);
} else {
end = start;
}
@@ -1605,25 +1605,25 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
},
/**
- * @description Return the parent anchor tag. (bind and use a util object)
- * @param {Boolean} isRemove Delete anchor tag
+ * @description Return the parent maintained tag. (bind and use a util object)
+ * @param {Boolean} isRemove Delete maintained tag
* @param {Element} element Element
* @returns {Element}
* @private
*/
- _util_getAnchor: function (isRemove, element) {
- return element && !isRemove ? this.getParentElement(element, function (current) {return this.isAnchor(current);}.bind(this)) : null;
+ _util_getMaintainedNode: function (isRemove, element) {
+ return element && !isRemove ? this.getParentElement(element, function (current) {return this._isMaintainedNode(current);}.bind(this)) : null;
},
/**
- * @description Checks if the element is an anchor tag. (bind and use a util object)
- * @param {Boolean} isRemove Delete anchor tag
+ * @description Check if element is a tag that should be persisted. (bind and use a util object)
+ * @param {Boolean} isRemove Delete maintained tag
* @param {Element} element Element
* @returns {Element}
* @private
*/
- _util_isAnchor: function (isRemove, element) {
- return element && !isRemove && element.nodeType !== 3 && this.isAnchor(element);
+ _util_isMaintainedNode: function (isRemove, element) {
+ return element && !isRemove && element.nodeType !== 3 && this._isMaintainedNode(element);
},
/**
@@ -1641,7 +1641,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
* @returns {{startContainer: *, startOffset: *, endContainer: *, endOffset: *}}
* @private
*/
- _nodeChange_oneLine: function (element, newInnerNode, validation, startCon, startOff, endCon, endOff, isRemoveFormat, isRemoveNode, collapsed, _removeCheck, _getAnchor, _isAnchor) {
+ _nodeChange_oneLine: function (element, newInnerNode, validation, startCon, startOff, endCon, endOff, isRemoveFormat, isRemoveNode, collapsed, _removeCheck, _getMaintainedNode, _isMaintainedNode) {
// not add tag
let parentCon = startCon.parentNode;
while (!parentCon.nextSibling && !parentCon.previousSibling && !util.isFormatElement(parentCon.parentNode) && !util.isWysiwygDiv(parentCon.parentNode)) {
@@ -1721,7 +1721,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
// startContainer
if (!startPass && child === startContainer) {
let line = pNode;
- anchorNode = _getAnchor(child);
+ anchorNode = _getMaintainedNode(child);
const prevNode = util.createTextNode(startContainer.nodeType === 1 ? '' : startContainer.substringData(0, startOffset));
const textNode = util.createTextNode(startContainer.nodeType === 1 ? '' : startContainer.substringData(startOffset,
isSameNode ?
@@ -1730,7 +1730,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
);
if (anchorNode) {
- const a = _getAnchor(ancestor);
+ const a = _getMaintainedNode(ancestor);
if (a && a.parentNode !== line) {
let m = a;
let p = null;
@@ -1751,7 +1751,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
ancestor.appendChild(prevNode);
}
- const prevAnchorNode = _getAnchor(ancestor);
+ const prevAnchorNode = _getMaintainedNode(ancestor);
if (!!prevAnchorNode) anchorNode = prevAnchorNode;
if (anchorNode) line = anchorNode;
@@ -1759,7 +1759,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
pCurrent = [];
cssText = '';
while (newNode !== line && newNode !== el && newNode !== null) {
- vNode = _isAnchor(newNode) ? null : validation(newNode);
+ vNode = _isMaintainedNode(newNode) ? null : validation(newNode);
if (vNode && newNode.nodeType === 1 && checkCss(newNode)) {
pCurrent.push(vNode);
cssText += newNode.style.cssText.substr(0, newNode.style.cssText.indexOf(':')) + '|';
@@ -1778,7 +1778,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
newInnerNode.appendChild(childNode);
line.appendChild(newInnerNode);
- if (anchorNode && !_getAnchor(endContainer)) {
+ if (anchorNode && !_getMaintainedNode(endContainer)) {
newInnerNode = newInnerNode.cloneNode(false);
pNode.appendChild(newInnerNode);
nNodeArray.push(newInnerNode);
@@ -1794,13 +1794,13 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
// endContainer
if (!endPass && child === endContainer) {
- anchorNode = _getAnchor(child);
+ anchorNode = _getMaintainedNode(child);
const afterNode = util.createTextNode(endContainer.nodeType === 1 ? '' : endContainer.substringData(endOffset, (endContainer.length - endOffset)));
const textNode = util.createTextNode(isSameNode || endContainer.nodeType === 1 ? '' : endContainer.substringData(0, endOffset));
if (anchorNode) {
anchorNode = anchorNode.cloneNode(false);
- } else if (_isAnchor(newInnerNode.parentNode) && !anchorNode) {
+ } else if (_isMaintainedNode(newInnerNode.parentNode) && !anchorNode) {
newInnerNode = newInnerNode.cloneNode(false);
pNode.appendChild(newInnerNode);
nNodeArray.push(newInnerNode);
@@ -1813,7 +1813,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
const anchors = [];
while (newNode !== pNode && newNode !== el && newNode !== null) {
if (newNode.nodeType === 1 && checkCss(newNode)) {
- if (_isAnchor(newNode)) anchors.push(newNode.cloneNode(false));
+ if (_isMaintainedNode(newNode)) anchors.push(newNode.cloneNode(false));
else pCurrent.push(newNode.cloneNode(false));
cssText += newNode.style.cssText.substr(0, newNode.style.cssText.indexOf(':')) + '|';
}
@@ -1833,7 +1833,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
}
if (anchorNode && cloneNode) {
- const afterAnchorNode = _getAnchor(cloneNode);
+ const afterAnchorNode = _getMaintainedNode(cloneNode);
if (afterAnchorNode) {
anchorNode = afterAnchorNode;
}
@@ -1843,7 +1843,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
pCurrent = [];
cssText = '';
while (newNode !== pNode && newNode !== el && newNode !== null) {
- vNode = _isAnchor(newNode) ? null : validation(newNode);
+ vNode = _isMaintainedNode(newNode) ? null : validation(newNode);
if (vNode && newNode.nodeType === 1 && checkCss(newNode)) {
pCurrent.push(vNode);
cssText += newNode.style.cssText.substr(0, newNode.style.cssText.indexOf(':')) + '|';
@@ -1886,7 +1886,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
// other
if (startPass) {
if (child.nodeType === 1 && !util.isBreak(child)) {
- if (!collapsed && util.isIgnoreNodeChange(child)) {
+ if (!collapsed && util._isIgnoreNodeChange(child)) {
newInnerNode = newInnerNode.cloneNode(false);
pNode.appendChild(child);
pNode.appendChild(newInnerNode);
@@ -1906,7 +1906,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
vNode = endPass ? newNode.cloneNode(false) : validation(newNode);
if (newNode.nodeType === 1 && !util.isBreak(child) && vNode && checkCss(newNode)) {
if (vNode) {
- if (_isAnchor(vNode)) {
+ if (_isMaintainedNode(vNode)) {
if (!anchorNode) anchors.push(vNode);
} else {
pCurrent.push(vNode);
@@ -1926,13 +1926,13 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
appendNode = newNode;
}
- if (_isAnchor(newInnerNode.parentNode) && !_isAnchor(childNode)) {
+ if (_isMaintainedNode(newInnerNode.parentNode) && !_isMaintainedNode(childNode)) {
newInnerNode = newInnerNode.cloneNode(false);
pNode.appendChild(newInnerNode);
nNodeArray.push(newInnerNode);
}
- if (!endPass && !anchorNode && _isAnchor(childNode)) {
+ if (!endPass && !anchorNode && _isMaintainedNode(childNode)) {
newInnerNode = newInnerNode.cloneNode(false);
const aChildren = childNode.childNodes;
for (let a = 0, aLen = aChildren.length; a < aLen; a++) {
@@ -1955,8 +1955,8 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
}
if (anchorNode && child.nodeType === 3) {
- if (_getAnchor(child)) {
- const ancestorAnchorNode = util.getParentElement(ancestor, function (current) {return this.isAnchor(current.parentNode) || current.parentNode === pNode;}.bind(util));
+ if (_getMaintainedNode(child)) {
+ const ancestorAnchorNode = util.getParentElement(ancestor, function (current) {return this._isMaintainedNode(current.parentNode) || current.parentNode === pNode;}.bind(util));
anchorNode.appendChild(ancestorAnchorNode);
newInnerNode = ancestorAnchorNode.cloneNode(false);
nNodeArray.push(newInnerNode);
@@ -2064,7 +2064,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
* @returns {{container: *, offset: *}}
* @private
*/
- _nodeChange_startLine: function (element, newInnerNode, validation, startCon, startOff, isRemoveFormat, isRemoveNode, _removeCheck, _getAnchor, _isAnchor) {
+ _nodeChange_startLine: function (element, newInnerNode, validation, startCon, startOff, isRemoveFormat, isRemoveNode, _removeCheck, _getMaintainedNode, _isMaintainedNode) {
// not add tag
let parentCon = startCon.parentNode;
while (!parentCon.nextSibling && !parentCon.previousSibling && !util.isFormatElement(parentCon.parentNode) && !util.isWysiwygDiv(parentCon.parentNode)) {
@@ -2114,7 +2114,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
if (passNode && !util.isBreak(child)) {
if (child.nodeType === 1) {
- if (util.isIgnoreNodeChange(child)) {
+ if (util._isIgnoreNodeChange(child)) {
newInnerNode = newInnerNode.cloneNode(false);
pNode.appendChild(child);
pNode.appendChild(newInnerNode);
@@ -2132,7 +2132,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
while (newNode.parentNode !== null && newNode !== el && newNode !== newInnerNode) {
vNode = validation(newNode);
if (newNode.nodeType === 1 && vNode) {
- if (_isAnchor(vNode)) {
+ if (_isMaintainedNode(vNode)) {
if (!anchorNode) anchors.push(vNode);
} else {
pCurrent.push(vNode);
@@ -2151,13 +2151,13 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
appendNode = newNode;
}
- if (_isAnchor(newInnerNode.parentNode) && !_isAnchor(childNode)) {
+ if (_isMaintainedNode(newInnerNode.parentNode) && !_isMaintainedNode(childNode)) {
newInnerNode = newInnerNode.cloneNode(false);
pNode.appendChild(newInnerNode);
nNodeArray.push(newInnerNode);
}
- if (!anchorNode && _isAnchor(childNode)) {
+ if (!anchorNode && _isMaintainedNode(childNode)) {
newInnerNode = newInnerNode.cloneNode(false);
const aChildren = childNode.childNodes;
for (let a = 0, aLen = aChildren.length; a < aLen; a++) {
@@ -2165,7 +2165,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
}
childNode.appendChild(newInnerNode);
pNode.appendChild(childNode);
- ancestor = !_isAnchor(newNode) ? newNode : newInnerNode;
+ ancestor = !_isMaintainedNode(newNode) ? newNode : newInnerNode;
nNodeArray.push(newInnerNode);
} else if (isTopNode) {
newInnerNode.appendChild(childNode);
@@ -2175,8 +2175,8 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
}
if (anchorNode && child.nodeType === 3) {
- if (_getAnchor(child)) {
- const ancestorAnchorNode = util.getParentElement(ancestor, function (current) {return this.isAnchor(current.parentNode) || current.parentNode === pNode;}.bind(util));
+ if (_getMaintainedNode(child)) {
+ const ancestorAnchorNode = util.getParentElement(ancestor, function (current) {return this._isMaintainedNode(current.parentNode) || current.parentNode === pNode;}.bind(util));
anchorNode.appendChild(ancestorAnchorNode);
newInnerNode = ancestorAnchorNode.cloneNode(false);
nNodeArray.push(newInnerNode);
@@ -2190,12 +2190,12 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
// startContainer
if (!passNode && child === container) {
let line = pNode;
- anchorNode = _getAnchor(child);
+ anchorNode = _getMaintainedNode(child);
const prevNode = util.createTextNode(container.nodeType === 1 ? '' : container.substringData(0, offset));
const textNode = util.createTextNode(container.nodeType === 1 ? '' : container.substringData(offset, (container.length - offset)));
if (anchorNode) {
- const a = _getAnchor(ancestor);
+ const a = _getMaintainedNode(ancestor);
if (a && a.parentNode !== line) {
let m = a;
let p = null;
@@ -2216,7 +2216,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
ancestor.appendChild(prevNode);
}
- const prevAnchorNode = _getAnchor(ancestor);
+ const prevAnchorNode = _getMaintainedNode(ancestor);
if (!!prevAnchorNode) anchorNode = prevAnchorNode;
if (anchorNode) line = anchorNode;
@@ -2381,7 +2381,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
if (!child) continue;
let coverNode = ancestor;
- if (util.isIgnoreNodeChange(child)) {
+ if (util._isIgnoreNodeChange(child)) {
pNode.appendChild(newInnerNode);
newInnerNode = newInnerNode.cloneNode(false);
pNode.appendChild(child);
@@ -2440,7 +2440,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
* @returns {{container: *, offset: *}}
* @private
*/
- _nodeChange_endLine: function (element, newInnerNode, validation, endCon, endOff, isRemoveFormat, isRemoveNode, _removeCheck, _getAnchor, _isAnchor) {
+ _nodeChange_endLine: function (element, newInnerNode, validation, endCon, endOff, isRemoveFormat, isRemoveNode, _removeCheck, _getMaintainedNode, _isMaintainedNode) {
// not add tag
let parentCon = endCon.parentNode;
while (!parentCon.nextSibling && !parentCon.previousSibling && !util.isFormatElement(parentCon.parentNode) && !util.isWysiwygDiv(parentCon.parentNode)) {
@@ -2490,7 +2490,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
if (passNode && !util.isBreak(child)) {
if (child.nodeType === 1) {
- if (util.isIgnoreNodeChange(child)) {
+ if (util._isIgnoreNodeChange(child)) {
newInnerNode = newInnerNode.cloneNode(false);
pNode.insertBefore(child, ancestor);
pNode.insertBefore(newInnerNode, child);
@@ -2508,7 +2508,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
while (newNode.parentNode !== null && newNode !== el && newNode !== newInnerNode) {
vNode = validation(newNode);
if (vNode && newNode.nodeType === 1) {
- if (_isAnchor(vNode)) {
+ if (_isMaintainedNode(vNode)) {
if (!anchorNode) anchors.push(vNode);
} else {
pCurrent.push(vNode);
@@ -2527,13 +2527,13 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
appendNode = newNode;
}
- if (_isAnchor(newInnerNode.parentNode) && !_isAnchor(childNode)) {
+ if (_isMaintainedNode(newInnerNode.parentNode) && !_isMaintainedNode(childNode)) {
newInnerNode = newInnerNode.cloneNode(false);
pNode.insertBefore(newInnerNode, pNode.firstChild);
nNodeArray.push(newInnerNode);
}
- if (!anchorNode && _isAnchor(childNode)) {
+ if (!anchorNode && _isMaintainedNode(childNode)) {
newInnerNode = newInnerNode.cloneNode(false);
const aChildren = childNode.childNodes;
for (let a = 0, aLen = aChildren.length; a < aLen; a++) {
@@ -2552,8 +2552,8 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
}
if (anchorNode && child.nodeType === 3) {
- if (_getAnchor(child)) {
- const ancestorAnchorNode = util.getParentElement(ancestor, function (current) {return this.isAnchor(current.parentNode) || current.parentNode === pNode;}.bind(util));
+ if (_getMaintainedNode(child)) {
+ const ancestorAnchorNode = util.getParentElement(ancestor, function (current) {return this._isMaintainedNode(current.parentNode) || current.parentNode === pNode;}.bind(util));
anchorNode.appendChild(ancestorAnchorNode);
newInnerNode = ancestorAnchorNode.cloneNode(false);
nNodeArray.push(newInnerNode);
@@ -2566,13 +2566,13 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
// endContainer
if (!passNode && child === container) {
- anchorNode = _getAnchor(child);
+ anchorNode = _getMaintainedNode(child);
const afterNode = util.createTextNode(container.nodeType === 1 ? '' : container.substringData(offset, (container.length - offset)));
const textNode = util.createTextNode(container.nodeType === 1 ? '' : container.substringData(0, offset));
if (anchorNode) {
anchorNode = anchorNode.cloneNode(false);
- const a = _getAnchor(ancestor);
+ const a = _getMaintainedNode(ancestor);
if (a && a.parentNode !== pNode) {
let m = a;
let p = null;
@@ -2587,7 +2587,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
m.parentNode.insertBefore(a, m.parentNode.firstChild);
}
anchorNode = anchorNode.cloneNode(false);
- } else if (_isAnchor(newInnerNode.parentNode) && !anchorNode) {
+ } else if (_isMaintainedNode(newInnerNode.parentNode) && !anchorNode) {
newInnerNode = newInnerNode.cloneNode(false);
pNode.appendChild(newInnerNode);
nNodeArray.push(newInnerNode);
@@ -2600,7 +2600,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
newNode = ancestor;
pCurrent = [];
while (newNode !== pNode && newNode !== null) {
- vNode = _isAnchor(newNode) ? null : validation(newNode);
+ vNode = _isMaintainedNode(newNode) ? null : validation(newNode);
if (vNode && newNode.nodeType === 1) {
pCurrent.push(vNode);
}
diff --git a/src/lib/util.js b/src/lib/util.js
index 758276f2e..60f9247b7 100755
--- a/src/lib/util.js
+++ b/src/lib/util.js
@@ -1008,7 +1008,7 @@ const util = {
const inst = this;
(function recursionFunc(current) {
- if (current !== element && inst.onlyZeroWidthSpace(current.textContent) && !/^BR$/i.test(current.nodeName) &&
+ if (current !== element && inst.onlyZeroWidthSpace(current.textContent) && !inst._notTextNode(current) &&
(!current.firstChild || !/^BR$/i.test(current.firstChild.nodeName)) && !inst.isComponent(current)) {
if (current.parentNode) {
current.parentNode.removeChild(current);
@@ -1028,15 +1028,6 @@ const util = {
if (element.childNodes.length === 0) element.innerHTML = ' ';
},
- /**
- * @description Nodes that need to be added without modification when changing text nodes !(span|font|b|strong|var|i|em|u|ins|s|strike|del|sub|sup|a)
- * @param {Element} element Element to check
- * @returns {Boolean}
- */
- isIgnoreNodeChange: function (element) {
- return element.nodeType !== 3 && !/^(span|font|b|strong|var|i|em|u|ins|s|strike|del|sub|sup|mark|a)$/i.test(element.nodeName);
- },
-
/**
* @description Gets the clean HTML code for editor
* @param {String} html HTML string
@@ -1071,6 +1062,36 @@ const util = {
return this._tagConvertor(cleanHTML || html);
},
+ /**
+ * @description Nodes that need to be added without modification when changing text nodes
+ * @param {Element} element Element to check
+ * @returns {Boolean}
+ * @private
+ */
+ _isIgnoreNodeChange: function (element) {
+ return element.nodeType !== 3 && !(/^(span|font|b|strong|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label)$/i.test(element.nodeName));
+ },
+
+ /**
+ * @description Nodes that must remain undetached when changing text nodes
+ * @param {Element} element Element to check
+ * @returns {Boolean}
+ * @private
+ */
+ _isMaintainedNode: function (element) {
+ return element.nodeType !== 3 && /^(a|label)$/i.test(element.nodeName);
+ },
+
+ /**
+ * @description Nodes without text
+ * @param {Element} element Element to check
+ * @returns {Boolean}
+ * @private
+ */
+ _notTextNode: function (element) {
+ return element.nodeType !== 3 && /^(br|input|canvas|img|iframe|audio|video)$/i.test(element.nodeName);
+ },
+
/**
* @description Delete Exclusion tags regexp object
* @returns {Object}
diff --git a/src/plugins/submenu/list.js b/src/plugins/submenu/list.js
index 2cbbc017c..91252598d 100644
--- a/src/plugins/submenu/list.js
+++ b/src/plugins/submenu/list.js
@@ -163,7 +163,7 @@ export default {
for (let i = 0, len = selectedFormsts.length, newCell, fTag, isCell, next, originParent, nextParent, parentTag, siblingTag, rangeTag; i < len; i++) {
fTag = selectedFormsts[i];
- if (fTag.childNodes.length === 0 && !this.util.isIgnoreNodeChange(fTag)) {
+ if (fTag.childNodes.length === 0 && !this.util._isIgnoreNodeChange(fTag)) {
this.util.removeItem(fTag);
continue;
}
From 672fd5728127287ac6d480f1a807afb7f72293ba Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Tue, 11 Feb 2020 16:37:36 +0900
Subject: [PATCH 13/99] modify: PRE tag enter key, custom formats #190
---
README.md | 2 +-
sample/html/getting-started.html | 2 +-
src/lib/core.js | 8 +++++---
src/lib/util.js | 4 ++--
test/dev/suneditor_build_test.html | 5 ++++-
test/dev/suneditor_build_test.js | 28 ++++++++++++++--------------
6 files changed, 27 insertions(+), 22 deletions(-)
diff --git a/README.md b/README.md
index 6d488844c..1d4c23b0c 100644
--- a/README.md
+++ b/README.md
@@ -360,7 +360,7 @@ formats : Change default formatBlock array. default: [..
tag: 'div', // Tag name
name: 'Custom div' || null, // default: tag name
command: 'replace' || 'range', // default: "replace"
- class: '__se__format__replace__xxx' || '__se__format__range__xxx', // Class names must always begin with "__se__format__(replace or range)__"
+ class: '__se__format__replace_xxx' || '__se__format__range_xxx', // Class names must always begin with "__se__format__(replace or range)_"
}]
colorList : Change default color array of color picker. default: [..[..]..] {Array}
Default value: [
diff --git a/sample/html/getting-started.html b/sample/html/getting-started.html
index 962ba0910..4196a3710 100644
--- a/sample/html/getting-started.html
+++ b/sample/html/getting-started.html
@@ -317,7 +317,7 @@
tag:'div', // Tag name
name:'Custom div'||null, // default: tag name
command:'replace'||'range', // default: "replace"
- class:'__se__format__replace__xxx'||'__se__format__range__xxx', // Class names must always begin with "__se__format__(replace or range)__"
+ class:'__se__format__replace_xxx'||'__se__format__range_xxx', // Class names must always begin with "__se__format__(replace or range)_"
}]
colorList :Changedefault color array of color picker. default: [..[..]..] {Array}
Default value: [
diff --git a/src/lib/core.js b/src/lib/core.js
index 3c9f9d297..13ca76361 100755
--- a/src/lib/core.js
+++ b/src/lib/core.js
@@ -4055,8 +4055,10 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
e.preventDefault();
const selectionFormat = selectionNode === formatEl;
- if ((selectionFormat && range.collapsed && selectionNode.children.length === range.endOffset) || (!selectionFormat && util.onlyZeroWidthSpace(selectionNode.textContent) && util.isBreak(selectionNode.previousSibling) && !selectionNode.nextSibling)) {
- if (!selectionFormat) util.removeItem(selectionNode);
+ if ((selectionFormat && range.collapsed && selectionNode.childNodes.length - 2 === range.endOffset && util.isBreak(selectionNode.childNodes[range.endOffset]) && util.isBreak(selectionNode.childNodes[range.endOffset - 1]) && util.isBreak(selectionNode.childNodes[range.endOffset - 2])) ||
+ (!selectionFormat && util.onlyZeroWidthSpace(selectionNode.textContent) && util.isBreak(selectionNode.previousElementSibling) && util.isBreak(selectionNode.previousElementSibling.previousElementSibling) && (!selectionNode.nextSibling || (!util.isBreak(selectionNode.nextSibling) && util.onlyZeroWidthSpace(selectionNode.nextSibling.textContent))))) {
+ if (selectionFormat) util.removeItem(selectionNode.childNodes[range.endOffset - 1]);
+ else util.removeItem(selectionNode);
const newEl = core.appendFormatTag(formatEl, formatEl.nextElementSibling ? formatEl.nextElementSibling.nodeName : 'P');
util.copyFormatAttributes(newEl, formatEl);
core.setRange(newEl, 1, newEl, 1);
@@ -4070,7 +4072,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
let con = wSelection.focusNode;
let offset = 1;
if (/^PRE$/i.test(wSelection.focusNode.nodeName)) {
- con = con.childNodes[wSelection.focusOffset > 1 ? wSelection.focusOffset - 1 : wSelection.focusOffset];
+ con = con.childNodes[util.isBreak(con.childNodes[wSelection.focusOffset - 1]) ? wSelection.focusOffset - 1 : wSelection.focusOffset];
} else {
con = con.previousSibling;
}
diff --git a/src/lib/util.js b/src/lib/util.js
index 60f9247b7..5a84f264f 100755
--- a/src/lib/util.js
+++ b/src/lib/util.js
@@ -306,7 +306,7 @@ const util = {
* @returns {Boolean}
*/
isFormatElement: function (element) {
- if (element && element.nodeType === 1 && (/^(P|DIV|H[1-6]|PRE|LI|TH|TD)$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__replace__.+(\\s|$)')) && !this.isComponent(element) && !this.isWysiwygDiv(element)) return true;
+ if (element && element.nodeType === 1 && (/^(P|DIV|H[1-6]|PRE|LI|TH|TD)$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__replace_.+(\\s|$)')) && !this.isComponent(element) && !this.isWysiwygDiv(element)) return true;
return false;
},
@@ -317,7 +317,7 @@ const util = {
* @returns {Boolean}
*/
isRangeFormatElement: function (element) {
- if (element && element.nodeType === 1 && (/^(BLOCKQUOTE|OL|UL|FIGCAPTION|TABLE|THEAD|TBODY|TR|TH|TD)$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__range__.+(\\s|$)'))) return true;
+ if (element && element.nodeType === 1 && (/^(BLOCKQUOTE|OL|UL|FIGCAPTION|TABLE|THEAD|TBODY|TR|TH|TD)$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__range_.+(\\s|$)'))) return true;
return false;
},
diff --git a/test/dev/suneditor_build_test.html b/test/dev/suneditor_build_test.html
index 759d98f9f..353bf62d6 100644
--- a/test/dev/suneditor_build_test.html
+++ b/test/dev/suneditor_build_test.html
@@ -108,9 +108,12 @@
margin: 0;
padding: 0;
}
- .sun-editor .__se__format__aaa, .sun-editor-editable .__se__format__aaa {
+ .sun-editor .__se__format__replace_NORMAL, .sun-editor-editable .__se__format__replace_NORMAL {
background-color: aquamarine;
}
+ .sun-editor .__se__format__replace_CODE, .sun-editor-editable .__se__format__replace_CODE {
+ border: 1px solid #333;
+ }
diff --git a/test/dev/suneditor_build_test.js b/test/dev/suneditor_build_test.js
index b2d61b7c7..70db95c25 100644
--- a/test/dev/suneditor_build_test.js
+++ b/test/dev/suneditor_build_test.js
@@ -23,20 +23,20 @@ let s1 = suneditor.create('editor', {
// mode: 'balloon',
buttonList: [['table', 'align', 'link', 'bold', 'underline', 'italic', 'strike', 'fontColor', 'hiliteColor', 'removeFormat', 'formatBlock', 'codeView', 'preview']],
width: '100%',
-// formats: [
-// {
-// tag: 'p', // Tag name
-// name: 'NORMAL', // default: tag name
-// command: 'replace', // default: "replace"
-// class: '__se__format__replace__NORMAL', // Class names must always begin with "__se__format__"
-// },
-// {
-// tag: 'div', // Tag name
-// name: 'CODE', // default: tag name
-// command: 'replace', // default: "replace"
-// class: '__se__format__CODE', // Class names must always begin with "__se__format__"
-// }
-// ]
+ formats: [
+ {
+ tag: 'div', // Tag name
+ name: 'NORMAL', // default: tag name
+ command: 'replace', // default: "replace"
+ class: '__se__format__replace_NORMAL', // Class names must always begin with "__se__format__"
+ },
+ {
+ tag: 'div', // Tag name
+ name: 'CODE', // default: tag name
+ command: 'replace', // default: "replace"
+ class: '__se__format__replace_CODE', // Class names must always begin with "__se__format__"
+ }
+ ]
})
window.cm = CodeMirror
From a2ab114c998763fb90a61a84b681866eccc9bd74 Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Tue, 11 Feb 2020 19:59:34 +0900
Subject: [PATCH 14/99] modify: pre - enter #190
---
src/lib/core.js | 24 ++++++++++++++----------
src/lib/util.js | 2 +-
test/dev/suneditor_build_test.js | 3 ++-
3 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/src/lib/core.js b/src/lib/core.js
index 13ca76361..1b80973b5 100755
--- a/src/lib/core.js
+++ b/src/lib/core.js
@@ -4054,10 +4054,12 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
if (!shift && /^PRE$/i.test(formatEl.nodeName)) {
e.preventDefault();
const selectionFormat = selectionNode === formatEl;
+ const wSelection = core.getSelection();
+ const children = selectionNode.childNodes, offset = wSelection.focusOffset, prev = selectionNode.previousElementSibling, next = selectionNode.nextSibling;
- if ((selectionFormat && range.collapsed && selectionNode.childNodes.length - 2 === range.endOffset && util.isBreak(selectionNode.childNodes[range.endOffset]) && util.isBreak(selectionNode.childNodes[range.endOffset - 1]) && util.isBreak(selectionNode.childNodes[range.endOffset - 2])) ||
- (!selectionFormat && util.onlyZeroWidthSpace(selectionNode.textContent) && util.isBreak(selectionNode.previousElementSibling) && util.isBreak(selectionNode.previousElementSibling.previousElementSibling) && (!selectionNode.nextSibling || (!util.isBreak(selectionNode.nextSibling) && util.onlyZeroWidthSpace(selectionNode.nextSibling.textContent))))) {
- if (selectionFormat) util.removeItem(selectionNode.childNodes[range.endOffset - 1]);
+ if ((selectionFormat && range.collapsed && children.length - 1 <= offset + 1 && util.isBreak(children[offset]) && (!children[offset + 1] || (!children[offset + 2] && children[offset + 1].nodeType === 3 && util.onlyZeroWidthSpace(children[offset + 1].textContent))) && offset > 0 && util.isBreak(children[offset - 1])) ||
+ (!selectionFormat && util.onlyZeroWidthSpace(selectionNode.textContent) && util.isBreak(prev) && (!prev.previousElementSibling || util.isBreak(prev.previousElementSibling)) && (!next || (!util.isBreak(next) && util.onlyZeroWidthSpace(next.textContent))))) {
+ if (selectionFormat) util.removeItem(children[offset - 1]);
else util.removeItem(selectionNode);
const newEl = core.appendFormatTag(formatEl, formatEl.nextElementSibling ? formatEl.nextElementSibling.nodeName : 'P');
util.copyFormatAttributes(newEl, formatEl);
@@ -4068,23 +4070,25 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
if (selectionFormat) {
core.execCommand('insertHTML', false, '
');
- const wSelection = _w.getSelection();
let con = wSelection.focusNode;
- let offset = 1;
- if (/^PRE$/i.test(wSelection.focusNode.nodeName)) {
- con = con.childNodes[util.isBreak(con.childNodes[wSelection.focusOffset - 1]) ? wSelection.focusOffset - 1 : wSelection.focusOffset];
+ const wOffset = wSelection.focusOffset;
+ if (formatEl === con) {
+ con = con.childNodes[wOffset - offset > 1 ? wOffset - 1 : wOffset];
} else {
con = con.previousSibling;
}
- core.setRange(con, offset, con, offset);
+
+ core.setRange(con, 1, con, 1);
} else {
const br = util.createElement('BR');
core.insertNode(br);
- if (!util.isBreak(br.previousSibling) && (!br.nextSibling || util.onlyZeroWidthSpace(br.nextSibling))) {
+
+ const brPrev = br.previousSibling, brNext = br.nextSibling;
+ if (!util.isBreak(brPrev) && (!brNext || util.onlyZeroWidthSpace(brNext))) {
br.parentNode.insertBefore(br.cloneNode(false), br);
core.setRange(br, 1, br, 1);
} else {
- core.setRange(br.nextSibling, 0, br.nextSibling, 0);
+ core.setRange(brNext, 0, brNext, 0);
}
}
diff --git a/src/lib/util.js b/src/lib/util.js
index 5a84f264f..3afef8d5a 100755
--- a/src/lib/util.js
+++ b/src/lib/util.js
@@ -1069,7 +1069,7 @@ const util = {
* @private
*/
_isIgnoreNodeChange: function (element) {
- return element.nodeType !== 3 && !(/^(span|font|b|strong|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label)$/i.test(element.nodeName));
+ return element.nodeType !== 3 && !/^(span|font|b|strong|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label)$/i.test(element.nodeName);
},
/**
diff --git a/test/dev/suneditor_build_test.js b/test/dev/suneditor_build_test.js
index 70db95c25..644389b51 100644
--- a/test/dev/suneditor_build_test.js
+++ b/test/dev/suneditor_build_test.js
@@ -35,7 +35,8 @@ let s1 = suneditor.create('editor', {
name: 'CODE', // default: tag name
command: 'replace', // default: "replace"
class: '__se__format__replace_CODE', // Class names must always begin with "__se__format__"
- }
+ },
+ 'pre'
]
})
From 688f45d4370c7d4323dc0ed31e3018348c076d74 Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Wed, 12 Feb 2020 17:56:10 +0900
Subject: [PATCH 15/99] add: format - freeFormat(pre), add:
util-isFreeFormatElement, getFreeFormatElement #190
---
README.md | 6 ++-
sample/html/getting-started.html | 4 +-
sample/html/out/document-util.html | 68 +++++++++++++++++++++++++++++-
src/lib/core.js | 29 +++++++------
src/lib/util.js | 43 ++++++++++++++++---
test/dev/suneditor_build_test.html | 2 +-
test/dev/suneditor_build_test.js | 4 +-
7 files changed, 130 insertions(+), 26 deletions(-)
diff --git a/README.md b/README.md
index 1d4c23b0c..8d94a3e28 100644
--- a/README.md
+++ b/README.md
@@ -355,12 +355,14 @@ fontSizeUnit : The font size unit. default: 'px
formats : Change default formatBlock array. default: [...] {Array}
Default value: [
'p', 'div', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
+ // "blockquote": range format, "pre": free format, "Other tags": replace format
],
Custom: [{
tag: 'div', // Tag name
name: 'Custom div' || null, // default: tag name
- command: 'replace' || 'range', // default: "replace"
- class: '__se__format__replace_xxx' || '__se__format__range_xxx', // Class names must always begin with "__se__format__(replace or range)_"
+ command: 'replace' || 'range' || 'free', // default: "replace"
+ class: '__se__format__replace_xxx' || '__se__format__range_xxx' || '__se__format__free_xxx'
+ // Class names must always begin with "__se__format__(replace, range, free)_"
}]
colorList : Change default color array of color picker. default: [..[..]..] {Array}
Default value: [
diff --git a/sample/html/getting-started.html b/sample/html/getting-started.html
index 4196a3710..60c890343 100644
--- a/sample/html/getting-started.html
+++ b/sample/html/getting-started.html
@@ -312,12 +312,14 @@
formats :Changedefault formatBlock array. default: [...] {Array}
Default value: [
'p', 'div', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
+ // "blockquote": range format, "pre": free format, "Other tags": replace format
],
Custom: [{
tag:'div', // Tag name
name:'Custom div'||null, // default: tag name
command:'replace'||'range', // default: "replace"
- class:'__se__format__replace_xxx'||'__se__format__range_xxx', // Class names must always begin with "__se__format__(replace or range)_"
+ class:'__se__format__replace_xxx'||'__se__format__range_xxx'||'__se__format__free_xxx'
+ // Class names must always begin with "__se__format__(replace, range, free)_"
}]
colorList :Changedefault color array of color picker. default: [..[..]..] {Array}
Default value: [
diff --git a/sample/html/out/document-util.html b/sample/html/out/document-util.html
index f0ac27d08..1b424fc4b 100644
--- a/sample/html/out/document-util.html
+++ b/sample/html/out/document-util.html
@@ -354,7 +354,7 @@
Parameters:
isFormatElement(element) → {Boolean}
- It is judged whether it is the format element. (P, DIV, H1-6, PRE, LI, TH, TD)
+ It is judged whether it is the format element. (P, DIV, H1-6, PRE, LI)
Parameters:
@@ -382,7 +382,35 @@
i
class="type-signature"> → {Boolean}
It is judged whether it is the range format element. (BLOCKQUOTE, OL, UL, FIGCAPTION, TABLE, THEAD, TBODY, TR, TH, TD)
- Range format element is wrap the format element (P, DIV, H1-6, LI)
+ Range format element is wrap the format element (P, DIV, H1-6, PRE, LI)
+
+
Parameters:
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
element
+
+ Element
+
+
The element to check
+
+
+
+
+
+
+
isFreeFormatElement(element) → {Boolean}
+
+ It is judged whether it is the free format element. (PRE)
+ Free format elements's line break is "BR" tag.
');
- let con = wSelection.focusNode;
+ let focusNode = wSelection.focusNode;
const wOffset = wSelection.focusOffset;
- if (formatEl === con) {
- con = con.childNodes[wOffset - offset > 1 ? wOffset - 1 : wOffset];
+ if (freeFormatEl === focusNode) {
+ focusNode = focusNode.childNodes[wOffset - offset > 1 ? wOffset - 1 : wOffset];
} else {
- con = con.previousSibling;
+ focusNode = focusNode.previousSibling;
}
- core.setRange(con, 1, con, 1);
+ core.setRange(focusNode, 1, focusNode, 1);
} else {
+ const focusNext = wSelection.focusNode.nextSibling;
const br = util.createElement('BR');
core.insertNode(br);
const brPrev = br.previousSibling, brNext = br.nextSibling;
- if (!util.isBreak(brPrev) && (!brNext || util.onlyZeroWidthSpace(brNext))) {
+ if (!util.isBreak(focusNext) && !util.isBreak(brPrev) && (!brNext || util.onlyZeroWidthSpace(brNext))) {
br.parentNode.insertBefore(br.cloneNode(false), br);
core.setRange(br, 1, br, 1);
} else {
diff --git a/src/lib/util.js b/src/lib/util.js
index 3afef8d5a..663c23ede 100755
--- a/src/lib/util.js
+++ b/src/lib/util.js
@@ -301,18 +301,18 @@ const util = {
},
/**
- * @description It is judged whether it is the format element (P, DIV, H1-6, PRE, LI, TH, TD)
+ * @description It is judged whether it is the format element (P, DIV, H1-6, PRE, LI)
* @param {Element} element The element to check
* @returns {Boolean}
*/
isFormatElement: function (element) {
- if (element && element.nodeType === 1 && (/^(P|DIV|H[1-6]|PRE|LI|TH|TD)$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__replace_.+(\\s|$)')) && !this.isComponent(element) && !this.isWysiwygDiv(element)) return true;
+ if (element && element.nodeType === 1 && (/^(P|DIV|H[1-6]|PRE|LI)$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__replace_.+(\\s|$)')) && !this.isComponent(element) && !this.isWysiwygDiv(element)) return true;
return false;
},
/**
* @description It is judged whether it is the range format element. (BLOCKQUOTE, OL, UL, FIGCAPTION, TABLE, THEAD, TBODY, TR, TH, TD)
- * * Range format element is wrap the format element (P, DIV, H1-6, LI)
+ * * Range format element is wrap the format element (P, DIV, H1-6, PRE, LI)
* @param {Element} element The element to check
* @returns {Boolean}
*/
@@ -321,6 +321,17 @@ const util = {
return false;
},
+ /**
+ * @description It is judged whether it is the free format element. (PRE)
+ * Free format elements's line break is "BR" tag.
+ * @param {Element} element
+ * @returns {Boolean}
+ */
+ isFreeFormatElement: function (element) {
+ if (element && element.nodeType === 1 && (/^PRE$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__free_.+(\\s|$)')) && !this.isComponent(element) && !this.isWysiwygDiv(element)) return true;
+ return false;
+ },
+
/**
* @description It is judged whether it is the component(img, iframe cover, table, hr) element - ".se-component"
* @param {Element} element The element to check
@@ -331,7 +342,7 @@ const util = {
},
/**
- * @description If a parent node that contains an argument node finds a format node (P, DIV, H[1-6], LI), it returns that node.
+ * @description If a parent node that contains an argument node finds a format node (P, DIV, H[1-6], PRE, LI), it returns that node.
* @param {Element} element Reference element if null or no value, it is relative to the current focus node.
* @param {Function|null} validation Additional validation function.
* @returns {Element}
@@ -354,7 +365,7 @@ const util = {
},
/**
- * @description If a parent node that contains an argument node finds a format node (BLOCKQUOTE, TABLE, TH, TD, OL, UL, PRE), it returns that node.
+ * @description If a parent node that contains an argument node finds a format node (BLOCKQUOTE, TABLE, TH, TD, OL, UL, TH, TD), it returns that node.
* @param {Element} element Reference element if null or no value, it is relative to the current focus node.
* @param {Function|null} validation Additional validation function.
* @returns {Element|null}
@@ -374,6 +385,28 @@ const util = {
return null;
},
+ /**
+ * @description If a parent node that contains an argument node finds a free format node (PRE), it returns that node.
+ * @param {Element} element Reference element if null or no value, it is relative to the current focus node.
+ * @param {Function|null} validation Additional validation function.
+ * @returns {Element}
+ */
+ getFreeFormatElement: function (element, validation) {
+ if (!element) return null;
+ if (!validation) {
+ validation = function () { return true; };
+ }
+
+ while (element) {
+ if (this.isWysiwygDiv(element)) return null;
+ if (this.isFreeFormatElement(element) && validation(element)) return element;
+
+ element = element.parentNode;
+ }
+
+ return null;
+ },
+
/**
* @description Add style and className of copyEl to originEl
* @param {Element} originEl Origin element
diff --git a/test/dev/suneditor_build_test.html b/test/dev/suneditor_build_test.html
index 353bf62d6..9bb176fa4 100644
--- a/test/dev/suneditor_build_test.html
+++ b/test/dev/suneditor_build_test.html
@@ -108,7 +108,7 @@
margin: 0;
padding: 0;
}
- .sun-editor .__se__format__replace_NORMAL, .sun-editor-editable .__se__format__replace_NORMAL {
+ .sun-editor .__se__format__free_NORMAL, .sun-editor-editable .__se__format__free_NORMAL {
background-color: aquamarine;
}
.sun-editor .__se__format__replace_CODE, .sun-editor-editable .__se__format__replace_CODE {
diff --git a/test/dev/suneditor_build_test.js b/test/dev/suneditor_build_test.js
index 644389b51..7f12f7328 100644
--- a/test/dev/suneditor_build_test.js
+++ b/test/dev/suneditor_build_test.js
@@ -27,8 +27,8 @@ let s1 = suneditor.create('editor', {
{
tag: 'div', // Tag name
name: 'NORMAL', // default: tag name
- command: 'replace', // default: "replace"
- class: '__se__format__replace_NORMAL', // Class names must always begin with "__se__format__"
+ command: 'free', // default: "replace"
+ class: '__se__format__free_NORMAL', // Class names must always begin with "__se__format__"
},
{
tag: 'div', // Tag name
From 4dbcf35242c2e401f90c3e945125a098c73b9545 Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Wed, 12 Feb 2020 20:26:37 +0900
Subject: [PATCH 16/99] add: formatBlock-free command
---
src/plugins/submenu/formatBlock.js | 42 ++++++++++++++++++++++++++++--
1 file changed, 40 insertions(+), 2 deletions(-)
diff --git a/src/plugins/submenu/formatBlock.js b/src/plugins/submenu/formatBlock.js
index 7319f3785..cf9b9e8b5 100644
--- a/src/plugins/submenu/formatBlock.js
+++ b/src/plugins/submenu/formatBlock.js
@@ -46,7 +46,7 @@ export default {
if (typeof format === 'string' && defaultFormats.indexOf(format) > -1) {
tagName = format.toLowerCase();
- command = tagName === 'blockquote' ? 'range' : 'replace';
+ command = tagName === 'blockquote' ? 'range' : tagName === 'pre' ? 'free' : 'replace';
h = /^h/.test(tagName) ? tagName.match(/\d+/)[0] : '';
name = lang_toolbar['tag_' + (h ? 'h' : tagName)] + h;
className = '';
@@ -130,11 +130,49 @@ export default {
if (!command) return;
- // blockquote, pre
+ // blockquote
if (command === 'range') {
const rangeElement = tag.cloneNode(false);
this.applyRangeFormatElement(rangeElement);
}
+ // pre
+ else if (command === 'free') {
+ const selectedFormsts = this.getSelectedElementsAndComponents();
+ const getParentFunc = function (current) {
+ return !this.isFormatElement(current);
+ }.bind(this.util);
+ const getBeforeFunc = function (current) {
+ return !this.isFormatElement(current.parentNode);
+ }.bind(this.util);
+
+ let parentNode = this.util.getParentElement(selectedFormsts[0].parentNode, getParentFunc);
+ let freeElement = tag.cloneNode(false);
+ const focusElement = freeElement;
+
+ for (let i = 0, len = selectedFormsts.length, f, before, html, isComp; i < len; i++) {
+ f = selectedFormsts[i];
+ if (!this.util.getParentElement(f, '.se-wrapper-inner')) continue;
+
+ before = this.util.getParentElement(f, getBeforeFunc);
+ isComp = this.util.isComponent(f);
+ html = (isComp ? '' : f.innerHTML).replace(/\n/g, '') + ' ';
+
+ if (parentNode !== f.parentNode || isComp) {
+ parentNode = before.parentNode;
+ parentNode.insertBefore(freeElement, before);
+ freeElement = tag.cloneNode(false);
+ }
+
+ freeElement.innerHTML += html;
+ if (len - 1 === i) before.parentNode.insertBefore(freeElement, before);
+
+ if (!isComp) this.util.removeItem(before);
+ }
+
+ // history stack
+ this.history.push(false);
+ this.setRange(focusElement, 0, focusElement, 0);
+ }
// others
else {
const range = this.getRange();
From 549d8295cc781ab2dc194b5eadeda9f11e8bcbb5 Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Thu, 13 Feb 2020 19:32:30 +0900
Subject: [PATCH 17/99] modify: formatblock
---
sample/html/out/document-util.html | 6 +-
src/lib/context.js | 1 +
src/lib/core.js | 10 ++-
src/lib/util.js | 4 +-
src/plugins/submenu/formatBlock.js | 127 +++++++++++++++--------------
5 files changed, 80 insertions(+), 68 deletions(-)
diff --git a/sample/html/out/document-util.html b/sample/html/out/document-util.html
index 1b424fc4b..f8ec4ca3b 100644
--- a/sample/html/out/document-util.html
+++ b/sample/html/out/document-util.html
@@ -354,7 +354,8 @@
Parameters:
isFormatElement(element) → {Boolean}
- It is judged whether it is the format element. (P, DIV, H1-6, PRE, LI)
+ It is judged whether it is the format element. (P, DIV, H1-6, PRE, LI)
+ Format element also contain "free format Element"
Parameters:
@@ -410,7 +411,8 @@
is
class="type-signature"> → {Boolean}
It is judged whether it is the free format element. (PRE)
- Free format elements's line break is "BR" tag.
+ Free format elements's line break is "BR" tag.
+ Free format elements is included in the format element.
Parameters:
diff --git a/src/lib/context.js b/src/lib/context.js
index be5fbdfed..0a7f9670c 100755
--- a/src/lib/context.js
+++ b/src/lib/context.js
@@ -46,6 +46,7 @@ const _Context = function (element, cons, options) {
font: cons._toolBar.querySelector('._se_command_font_family .txt'),
fontTooltip: cons._toolBar.querySelector('._se_command_font_family .se-tooltip-text'),
format: cons._toolBar.querySelector('._se_command_format'),
+ formatTooltip: cons._toolBar.querySelector('._se_command_format .se-tooltip-text'),
fontSize: cons._toolBar.querySelector('._se_command_font_size'),
align: cons._toolBar.querySelector('._se_command_align'),
list: cons._toolBar.querySelector('._se_command_list'),
diff --git a/src/lib/core.js b/src/lib/core.js
index 97733ad9c..2b4537c04 100755
--- a/src/lib/core.js
+++ b/src/lib/core.js
@@ -3336,6 +3336,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
this.commandMap = {
FORMAT: context.tool.format,
+ FORMAT_TOOLTIP: context.tool.formatTooltip,
FONT: context.tool.font,
FONT_TOOLTIP: context.tool.fontTooltip,
SIZE: context.tool.fontSize,
@@ -3485,9 +3486,8 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
if (util.isFormatElement(selectionParent)) {
/* Format block */
if (findFormat && commandMap.FORMAT) {
- commandMapNodes.push('FORMAT');
core.callPlugin('formatBlock', function () {
- core.plugins.formatBlock.active.call(core, selectionParent);
+ if (core.plugins.formatBlock.active.call(core, selectionParent)) commandMapNodes.push('FORMAT');
});
findFormat = false;
}
@@ -3571,7 +3571,11 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
for (let key in commandMap) {
if (commandMapNodes.indexOf(key) > -1) continue;
- if (commandMap.FONT && /^FONT$/i.test(key)) {
+ if (commandMap.FORMAT && /^FORMAT$/i.test(key)) {
+ util.changeTxt(commandMap.FORMAT, lang.toolbar.formats);
+ util.changeTxt(commandMap.FORMAT_TOOLTIP, lang.toolbar.formats);
+ }
+ else if (commandMap.FONT && /^FONT$/i.test(key)) {
util.changeTxt(commandMap.FONT, lang.toolbar.font);
util.changeTxt(commandMap.FONT_TOOLTIP, lang.toolbar.font);
}
diff --git a/src/lib/util.js b/src/lib/util.js
index 663c23ede..484a45462 100755
--- a/src/lib/util.js
+++ b/src/lib/util.js
@@ -302,11 +302,12 @@ const util = {
/**
* @description It is judged whether it is the format element (P, DIV, H1-6, PRE, LI)
+ * Format element also contain "free format Element"
* @param {Element} element The element to check
* @returns {Boolean}
*/
isFormatElement: function (element) {
- if (element && element.nodeType === 1 && (/^(P|DIV|H[1-6]|PRE|LI)$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__replace_.+(\\s|$)')) && !this.isComponent(element) && !this.isWysiwygDiv(element)) return true;
+ if (element && element.nodeType === 1 && (/^(P|DIV|H[1-6]|PRE|LI)$/i.test(element.nodeName) || this.hasClass(element, '(\\s|^)__se__format__replace_.+(\\s|$)|(\\s|^)__se__format__free_.+(\\s|$)')) && !this.isComponent(element) && !this.isWysiwygDiv(element)) return true;
return false;
},
@@ -324,6 +325,7 @@ const util = {
/**
* @description It is judged whether it is the free format element. (PRE)
* Free format elements's line break is "BR" tag.
+ * Free format elements is included in the format element.
* @param {Element} element
* @returns {Boolean}
*/
diff --git a/src/plugins/submenu/formatBlock.js b/src/plugins/submenu/formatBlock.js
index cf9b9e8b5..45f63bc39 100644
--- a/src/plugins/submenu/formatBlock.js
+++ b/src/plugins/submenu/formatBlock.js
@@ -87,8 +87,11 @@ export default {
}
this.util.changeTxt(this.commandMap.FORMAT, formatTitle);
+ this.util.changeTxt(this.commandMap.FORMAT_TOOLTIP, formatTitle);
this.commandMap.FORMAT.setAttribute('data-value', nodeName);
this.commandMap.FORMAT.setAttribute('data-class', className);
+
+ return formatTitle !== this.lang.formats;
},
on: function () {
@@ -135,51 +138,13 @@ export default {
const rangeElement = tag.cloneNode(false);
this.applyRangeFormatElement(rangeElement);
}
- // pre
- else if (command === 'free') {
- const selectedFormsts = this.getSelectedElementsAndComponents();
- const getParentFunc = function (current) {
- return !this.isFormatElement(current);
- }.bind(this.util);
- const getBeforeFunc = function (current) {
- return !this.isFormatElement(current.parentNode);
- }.bind(this.util);
-
- let parentNode = this.util.getParentElement(selectedFormsts[0].parentNode, getParentFunc);
- let freeElement = tag.cloneNode(false);
- const focusElement = freeElement;
-
- for (let i = 0, len = selectedFormsts.length, f, before, html, isComp; i < len; i++) {
- f = selectedFormsts[i];
- if (!this.util.getParentElement(f, '.se-wrapper-inner')) continue;
-
- before = this.util.getParentElement(f, getBeforeFunc);
- isComp = this.util.isComponent(f);
- html = (isComp ? '' : f.innerHTML).replace(/\n/g, '') + ' ';
-
- if (parentNode !== f.parentNode || isComp) {
- parentNode = before.parentNode;
- parentNode.insertBefore(freeElement, before);
- freeElement = tag.cloneNode(false);
- }
-
- freeElement.innerHTML += html;
- if (len - 1 === i) before.parentNode.insertBefore(freeElement, before);
-
- if (!isComp) this.util.removeItem(before);
- }
-
- // history stack
- this.history.push(false);
- this.setRange(focusElement, 0, focusElement, 0);
- }
- // others
+ // free, others
else {
const range = this.getRange();
const startOffset = range.startOffset;
const endOffset = range.endOffset;
- let selectedFormsts = this.getSelectedElementsAndComponents();
+ const selectedFormsts = this.getSelectedElementsAndComponents();
if (selectedFormsts.length === 0) return;
let first = selectedFormsts[0];
@@ -187,7 +152,7 @@ export default {
const firstPath = this.util.getNodePath(range.startContainer, first, null);
const lastPath = this.util.getNodePath(range.endContainer, last, null);
- // remove list
+ // remove selected list
let rangeArr = {};
let listFirst = false;
let listLast = false;
@@ -225,35 +190,73 @@ export default {
if (lastIndex && this.util.isList(r)) {
const edge = this.detachRangeFormatElement(rangeArr.r, rangeArr.f, null, false, true);
- if (listLast || len === 1) {
- last = edge.ec;
- if (listFirst) first = edge.sc || last;
- }
+ if (listLast || len === 1) last = edge.ec;
+ if (listFirst) first = edge.sc || last;
}
}
// change format tag
this.setRange(this.util.getNodeFromPath(firstPath, first), startOffset, this.util.getNodeFromPath(lastPath, last), endOffset);
- selectedFormsts = this.getSelectedElementsAndComponents();
- for (let i = 0, len = selectedFormsts.length, node, newFormat; i < len; i++) {
- node = selectedFormsts[i];
-
- if ((node.nodeName.toLowerCase() !== value.toLowerCase() || (node.className.match(/(\s|^)__se__format__[^\s]+/) || [''])[0].trim() !== className) && !this.util.isComponent(node)) {
- newFormat = tag.cloneNode(false);
- this.util.copyFormatAttributes(newFormat, node);
- newFormat.innerHTML = node.innerHTML;
-
- node.parentNode.insertBefore(newFormat, node);
- this.util.removeItem(node);
- }
+ const modifiedFormsts = this.getSelectedElementsAndComponents();
+
+ // free format
+ if (command === 'free') {
+ const getParentFunc = function (current) {
+ return !this.isFormatElement(current);
+ }.bind(this.util);
+ const getBeforeFunc = function (current) {
+ return !this.isFormatElement(current.parentNode);
+ }.bind(this.util);
+
+ let parentNode = this.util.getParentElement(modifiedFormsts[0].parentNode, getParentFunc);
+ let freeElement = tag.cloneNode(false);
+ const focusElement = freeElement;
+
+ for (let i = 0, len = modifiedFormsts.length, f, before, html, isComp, first = true; i < len; i++) {
+ f = modifiedFormsts[i];
+ if (f === (!modifiedFormsts[i + 1] ? null : modifiedFormsts[i + 1].parentNode)) continue;
+
+ isComp = this.util.isComponent(f);
+ html = isComp ? '' : f.innerHTML.replace(/(?!>)\s+(?=<)|\n/g, ' ');
+ before = this.util.getParentElement(f, getBeforeFunc);
+
+ if (parentNode !== f.parentNode || isComp) {
+ parentNode.insertBefore(freeElement, before);
+ parentNode = before.parentNode;
+ freeElement = tag.cloneNode(false);
+ }
+
+ freeElement.innerHTML += (first || !html || / $/i.test(html)) ? html : ' ' + html;
+ first = false;
- if (i === 0) first = newFormat || node;
- if (i === len - 1) last = newFormat || node;
- newFormat = null;
+ if (len - 1 === i) before.parentNode.insertBefore(freeElement, before);
+ if (!isComp) this.util.removeItem(before);
+ }
+
+ this.setRange(focusElement, 0, focusElement, 0);
+ }
+ // others format
+ else {
+ for (let i = 0, len = modifiedFormsts.length, node, newFormat; i < len; i++) {
+ node = modifiedFormsts[i];
+
+ if ((node.nodeName.toLowerCase() !== value.toLowerCase() || (node.className.match(/(\s|^)__se__format__[^\s]+/) || [''])[0].trim() !== className) && !this.util.isComponent(node)) {
+ newFormat = tag.cloneNode(false);
+ this.util.copyFormatAttributes(newFormat, node);
+ newFormat.innerHTML = node.innerHTML;
+
+ node.parentNode.insertBefore(newFormat, node);
+ this.util.removeItem(node);
+ }
+
+ if (i === 0) first = newFormat || node;
+ if (i === len - 1) last = newFormat || node;
+ newFormat = null;
+ }
+
+ this.setRange(this.util.getNodeFromPath(firstPath, first), startOffset, this.util.getNodeFromPath(lastPath, last), endOffset);
}
- this.setRange(this.util.getNodeFromPath(firstPath, first), startOffset, this.util.getNodeFromPath(lastPath, last), endOffset);
-
// history stack
this.history.push(false);
}
From 444f251c0d26f778a93501a7df8e01b63962b5dc Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Fri, 14 Feb 2020 17:54:39 +0900
Subject: [PATCH 18/99] modify: free format
---
src/plugins/submenu/formatBlock.js | 49 ++++++++++++++++++++----------
1 file changed, 33 insertions(+), 16 deletions(-)
diff --git a/src/plugins/submenu/formatBlock.js b/src/plugins/submenu/formatBlock.js
index 45f63bc39..619fcfb8a 100644
--- a/src/plugins/submenu/formatBlock.js
+++ b/src/plugins/submenu/formatBlock.js
@@ -201,36 +201,53 @@ export default {
// free format
if (command === 'free') {
- const getParentFunc = function (current) {
- return !this.isFormatElement(current);
- }.bind(this.util);
- const getBeforeFunc = function (current) {
- return !this.isFormatElement(current.parentNode);
- }.bind(this.util);
-
- let parentNode = this.util.getParentElement(modifiedFormsts[0].parentNode, getParentFunc);
+ let parentNode = modifiedFormsts[0].parentNode;
let freeElement = tag.cloneNode(false);
const focusElement = freeElement;
- for (let i = 0, len = modifiedFormsts.length, f, before, html, isComp, first = true; i < len; i++) {
+ for (let i = modifiedFormsts.length - 1, f, html, before, next, inner, isComp, first = true; i >= 0; i--) {
f = modifiedFormsts[i];
if (f === (!modifiedFormsts[i + 1] ? null : modifiedFormsts[i + 1].parentNode)) continue;
isComp = this.util.isComponent(f);
html = isComp ? '' : f.innerHTML.replace(/(?!>)\s+(?=<)|\n/g, ' ');
- before = this.util.getParentElement(f, getBeforeFunc);
+ before = this.util.getParentElement(f, function (current) {
+ return current.parentNode === parentNode;
+ });
if (parentNode !== f.parentNode || isComp) {
- parentNode.insertBefore(freeElement, before);
- parentNode = before.parentNode;
+ if (this.util.isFormatElement(parentNode)) {
+ parentNode.parentNode.insertBefore(freeElement, parentNode.nextSibling);
+ parentNode = parentNode.parentNode;
+ } else {
+ parentNode.insertBefore(freeElement, before ? before.nextSibling : null);
+ parentNode = f.parentNode;
+ }
+
+ next = freeElement.nextSibling;
+ if (next && freeElement.nodeName === next.nodeName && this.util.isSameAttributes(freeElement, next)) {
+ freeElement.innerHTML += ' ' + next.innerHTML;
+ this.util.removeItem(next);
+ }
+
freeElement = tag.cloneNode(false);
+ first = true;
}
- freeElement.innerHTML += (first || !html || / $/i.test(html)) ? html : ' ' + html;
- first = false;
+ inner = freeElement.innerHTML;
+ freeElement.innerHTML = ((first || !html || !inner || / $/i.test(html)) ? html : html + ' ') + inner;
+
+ if (i === 0) {
+ parentNode.insertBefore(freeElement, f);
+ next = f.nextSibling;
+ if (next && freeElement.nodeName === next.nodeName && this.util.isSameAttributes(freeElement, next)) {
+ freeElement.innerHTML += ' ' + next.innerHTML;
+ this.util.removeItem(next);
+ }
+ }
- if (len - 1 === i) before.parentNode.insertBefore(freeElement, before);
- if (!isComp) this.util.removeItem(before);
+ if (!isComp) this.util.removeItem(f);
+ if (!!html) first = false;
}
this.setRange(focusElement, 0, focusElement, 0);
From e9556e24fedf75d519ba98a1a05ee493480da367 Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Fri, 14 Feb 2020 18:26:04 +0900
Subject: [PATCH 19/99] modify: free format
---
src/lib/core.js | 1 +
src/plugins/submenu/formatBlock.js | 11 +++++++++--
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/lib/core.js b/src/lib/core.js
index 2b4537c04..3458a8008 100755
--- a/src/lib/core.js
+++ b/src/lib/core.js
@@ -431,6 +431,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
const commandMap = this.commandMap;
util.changeTxt(commandMap.FORMAT, lang.toolbar.formats);
+ util.changeTxt(commandMap.FORMAT_TOOLTIP, lang.toolbar.formats);
util.changeTxt(commandMap.FONT, lang.toolbar.font);
util.changeTxt(commandMap.FONT_TOOLTIP, lang.toolbar.font);
util.changeTxt(commandMap.SIZE, lang.toolbar.fontSize);
diff --git a/src/plugins/submenu/formatBlock.js b/src/plugins/submenu/formatBlock.js
index 619fcfb8a..2451fc066 100644
--- a/src/plugins/submenu/formatBlock.js
+++ b/src/plugins/submenu/formatBlock.js
@@ -201,11 +201,12 @@ export default {
// free format
if (command === 'free') {
- let parentNode = modifiedFormsts[0].parentNode;
+ const len = modifiedFormsts.length - 1;
+ let parentNode = modifiedFormsts[len].parentNode;
let freeElement = tag.cloneNode(false);
const focusElement = freeElement;
- for (let i = modifiedFormsts.length - 1, f, html, before, next, inner, isComp, first = true; i >= 0; i--) {
+ for (let i = len, f, html, before, next, inner, isComp, first = true; i >= 0; i--) {
f = modifiedFormsts[i];
if (f === (!modifiedFormsts[i + 1] ? null : modifiedFormsts[i + 1].parentNode)) continue;
@@ -244,6 +245,12 @@ export default {
freeElement.innerHTML += ' ' + next.innerHTML;
this.util.removeItem(next);
}
+
+ const prev = freeElement.previousSibling;
+ if (prev && freeElement.nodeName === prev.nodeName && this.util.isSameAttributes(freeElement, prev)) {
+ prev.innerHTML += ' ' + freeElement.innerHTML;
+ this.util.removeItem(freeElement);
+ }
}
if (!isComp) this.util.removeItem(f);
From 3e18b3994e411f491de341c153941a0ae70c6637 Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Fri, 14 Feb 2020 19:09:37 +0900
Subject: [PATCH 20/99] add: #198 onBlur event, add: event argument - core
---
README.md | 24 +++++++++++-----------
sample/html/examples.html | 22 +++++++++++----------
sample/html/getting-started.html | 22 +++++++++++----------
src/lib/core.js | 34 +++++++++++++++++---------------
test/dev/suneditor_build_test.js | 3 +++
5 files changed, 58 insertions(+), 47 deletions(-)
diff --git a/README.md b/README.md
index 8d94a3e28..7905840b3 100644
--- a/README.md
+++ b/README.md
@@ -623,23 +623,25 @@ editor.toolbar.show();
// Event functions -------------------------------------------------------------------------------------
// It can be redefined by receiving event object as parameter.
// It is not called in exceptional cases and is called after the default event function has finished.
-editor.onScroll = function (e) { console.log('onScroll', e) }
+editor.onScroll = function (e, core) { console.log('onScroll', e) }
-editor.onClick = function (e) { console.log('onClick', e) }
+editor.onClick = function (e, core) { console.log('onClick', e) }
-editor.onKeyDown = function (e) { console.log('onKeyDown', e) }
+editor.onKeyDown = function (e, core) { console.log('onKeyDown', e) }
-editor.onKeyUp = function (e) { console.log('onKeyUp', e) }
+editor.onKeyUp = function (e, core) { console.log('onKeyUp', e) }
-editor.onDrop = function (e) { console.log('onDrop', e) }
+editor.onDrop = function (e, core) { console.log('onDrop', e) }
-editor.onChange = function (contents) { console.log('onChange', contents) }
+editor.onChange = function (contents, core) { console.log('onChange', contents) }
+
+editor.onBlur = function (e, core) { console.log('onBlur', e) }
// onload event
// When reloaded with the "setOptions" method, the value of the "reload" argument is true.
editor.onload = function (core, reload) {
console.log('onload-core', core)
- console.log('onload-reload', reload)
+ console.log('onload-reload', reload)
}
// Paste event.
@@ -649,7 +651,7 @@ editor.onload = function (core, reload) {
* cleanData : HTML string modified for editor format
* maxCharCount : maxChartCount option (true if max character is exceeded)
*/
-editor.onPaste = function (e, cleanData, maxCharCount) { console.log('onPaste', e, cleanData, maxCharCount) }
+editor.onPaste = function (e, cleanData, maxCharCount, core) { console.log('onPaste', e) }
// Called when the image is uploaded or the uploaded image is deleted.
/**
@@ -665,7 +667,7 @@ editor.onPaste = function (e, cleanData, maxCharCount) { console.log('onPaste',
* }
* remainingFilesCount: Count of remaining image files
*/
-editor.onImageUpload = function (targetImgElement, index, state, imageInfo, remainingFilesCount) {
+editor.onImageUpload = function (targetImgElement, index, state, imageInfo, remainingFilesCount, core) {
console.log(`targetImgElement:${targetImgElement}, index:${index}, state('create', 'update', 'delete'):${state}`)
console.log(`imageInfo:${imageInfo}, remainingFilesCount:${remainingFilesCount}`)
}
@@ -676,7 +678,7 @@ editor.onImageUpload = function (targetImgElement, index, state, imageInfo, rema
* errorMessage: Error message to show
* result: Result object
*/
-editor.onImageUploadError = function (errorMessage, result) {
+editor.onImageUploadError = function (errorMessage, result, core) {
alert(errorMessage)
}
@@ -684,7 +686,7 @@ editor.onImageUploadError = function (errorMessage, result) {
* toolbar: Toolbar Element
* context: The editor's context object (editor.getContext())
*/
-editor.showInline = function (toolbar, context) {
+editor.showInline = function (toolbar, context, core) {
console.log('toolbar', toolbar);
console.log('context', context);
}
diff --git a/sample/html/examples.html b/sample/html/examples.html
index 55143ec02..d0c7ff967 100644
--- a/sample/html/examples.html
+++ b/sample/html/examples.html
@@ -478,17 +478,19 @@
// Event functions -------------------------------------------------------------------------------------// It can be redefined by receiving event object as parameter.// It is not called in exceptional cases and is called after the default event function has finished.
-editor.onScroll=function (e) { console.log('onScroll', e) }
+editor.onScroll=function (e, core) { console.log('onScroll', e) }
-editor.onClick=function (e) { console.log('onClick', e) }
+editor.onClick=function (e, core) { console.log('onClick', e) }
-editor.onKeyDown=function (e) { console.log('onKeyDown', e) }
+editor.onKeyDown=function (e, core) { console.log('onKeyDown', e) }
-editor.onKeyUp=function (e) { console.log('onKeyUp', e) }
+editor.onKeyUp=function (e, core) { console.log('onKeyUp', e) }
-editor.onDrop=function (e) { console.log('onDrop', e) }
+editor.onDrop=function (e, core) { console.log('onDrop', e) }
-editor.onChange=function (contents) { console.log('onChange', contents) }
+editor.onChange=function (contents, core) { console.log('onChange', contents) }
+
+editor.onBlur=function (e, core) { console.log('onBlur', e) }
// onload event// When reloaded with the "setOptions" method, the value of the "reload" argument is true.
@@ -504,7 +506,7 @@
* cleanData : HTML string modified for editor format * maxCharCount : maxChartCount option (true if max character is exceeded)*/
-editor.onPaste=function (e, cleanData, maxCharCount) { console.log('onPaste', e, cleanData, maxCharCount) }
+editor.onPaste=function (e, cleanData, maxCharCount, core) { console.log('onPaste', e, cleanData, maxCharCount) }
// Called when the image is uploaded or the uploaded image is deleted./**
@@ -520,7 +522,7 @@
* } * remainingFilesCount: Count of remaining image files*/
-editor.onImageUpload=function (targetImgElement, index, state, imageInfo, remainingFilesCount) {
+editor.onImageUpload=function (targetImgElement, index, state, imageInfo, remainingFilesCount, core) {
console.log(`targetImgElement:${targetImgElement}, index:${index}, state('create', 'update', 'delete'):${state}`)
console.log(`imageInfo:${imageInfo}, remainingFilesCount:${remainingFilesCount}`)
}
@@ -531,7 +533,7 @@
* errorMessage: Error message to show * result: Result object */
-editor.onImageUploadError=function (errorMessage, result) {
+editor.onImageUploadError=function (errorMessage, result, core) {
alert(errorMessage)
}
@@ -539,7 +541,7 @@
* toolbar: Toolbar Element * context: The editor's context object (editor.getContext())*/
-editor.showInline=function (toolbar, context) {
+editor.showInline=function (toolbar, context, core) {
console.log('toolbar', toolbar);
console.log('context', context);
}
diff --git a/sample/html/getting-started.html b/sample/html/getting-started.html
index 60c890343..22ff65080 100644
--- a/sample/html/getting-started.html
+++ b/sample/html/getting-started.html
@@ -578,17 +578,19 @@
// Event functions -------------------------------------------------------------------------------------// It can be redefined by receiving event object as parameter.// It is not called in exceptional cases and is called after the default event function has finished.
-editor.onScroll=function (e) { console.log('onScroll', e) }
+editor.onScroll=function (e, core) { console.log('onScroll', e) }
-editor.onClick=function (e) { console.log('onClick', e) }
+editor.onClick=function (e, core) { console.log('onClick', e) }
-editor.onKeyDown=function (e) { console.log('onKeyDown', e) }
+editor.onKeyDown=function (e, core) { console.log('onKeyDown', e) }
-editor.onKeyUp=function (e) { console.log('onKeyUp', e) }
+editor.onKeyUp=function (e, core) { console.log('onKeyUp', e) }
-editor.onDrop=function (e) { console.log('onDrop', e) }
+editor.onDrop=function (e, core) { console.log('onDrop', e) }
-editor.onChange=function (contents) { console.log('onChange', contents) }
+editor.onChange=function (contents, core) { console.log('onChange', contents) }
+
+editor.onBlur=function (e, core) { console.log('onBlur', e) }
// onload event// When reloaded with the "setOptions" method, the value of the "reload" argument is true.
@@ -604,7 +606,7 @@
* cleanData : HTML string modified for editor format * maxCharCount : maxChartCount option (true if max character is exceeded)*/
-editor.onPaste=function (e, cleanData, maxCharCount) { console.log('onPaste', e, cleanData, maxCharCount) }
+editor.onPaste=function (e, cleanData, maxCharCount, core) { console.log('onPaste', e, cleanData, maxCharCount) }
// Called when the image is uploaded or the uploaded image is deleted./**
@@ -620,7 +622,7 @@
* } * remainingFilesCount: Count of remaining image files*/
-editor.onImageUpload=function (targetImgElement, index, state, imageInfo, remainingFilesCount) {
+editor.onImageUpload=function (targetImgElement, index, state, imageInfo, remainingFilesCount, core) {
console.log(`targetImgElement:${targetImgElement}, index:${index}, state('create', 'update', 'delete'):${state}`)
console.log(`imageInfo:${imageInfo}, remainingFilesCount:${remainingFilesCount}`)
}
@@ -631,7 +633,7 @@
* errorMessage: Error message to show * result: Result object */
-editor.onImageUploadError=function (errorMessage, result) {
+editor.onImageUploadError=function (errorMessage, result, core) {
alert(errorMessage)
}
@@ -639,7 +641,7 @@
* toolbar: Toolbar Element * context: The editor's context object (editor.getContext())*/
-editor.showInline=function (toolbar, context) {
+editor.showInline=function (toolbar, context, core) {
console.log('toolbar', toolbar);
console.log('context', context);
}
diff --git a/src/lib/core.js b/src/lib/core.js
index 3458a8008..2aa1e5ef5 100755
--- a/src/lib/core.js
+++ b/src/lib/core.js
@@ -157,7 +157,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
* @private
*/
_imageUpload: function (targetImgElement, index, state, imageInfo, remainingFilesCount) {
- if (typeof userFunction.onImageUpload === 'function') userFunction.onImageUpload(targetImgElement, index * 1, state, imageInfo, remainingFilesCount);
+ if (typeof userFunction.onImageUpload === 'function') userFunction.onImageUpload(targetImgElement, index * 1, state, imageInfo, remainingFilesCount, core);
},
/**
@@ -165,7 +165,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
* @private
*/
_imageUploadError: function (errorMessage, result) {
- if (typeof userFunction.onImageUploadError === 'function') return userFunction.onImageUploadError(errorMessage, result);
+ if (typeof userFunction.onImageUploadError === 'function') return userFunction.onImageUploadError(errorMessage, result, core);
return true;
},
@@ -3766,7 +3766,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
else event._showToolbarBalloon(range);
}
- if (userFunction.onClick) userFunction.onClick(e);
+ if (userFunction.onClick) userFunction.onClick(e, core);
},
_showToolbarBalloon: function (rangeObj) {
@@ -3860,7 +3860,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
core._inlineToolbarAttr.width = toolbar.style.width = context.option.toolbarWidth;
core._inlineToolbarAttr.top = toolbar.style.top = (-1 - toolbar.offsetHeight) + 'px';
- if (typeof userFunction.showInline === 'function') userFunction.showInline(toolbar, context);
+ if (typeof userFunction.showInline === 'function') userFunction.showInline(toolbar, context, core);
event.onScroll_window();
core._inlineToolbarAttr.isShow = true;
@@ -4173,7 +4173,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
}
}
- if (userFunction.onKeyDown) userFunction.onKeyDown(e);
+ if (userFunction.onKeyDown) userFunction.onKeyDown(e, core);
},
onKeyUp_wysiwyg: function (e) {
@@ -4247,13 +4247,18 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
core.history.push(true);
}
- if (userFunction.onKeyUp) userFunction.onKeyUp(e);
+ if (userFunction.onKeyUp) userFunction.onKeyUp(e, core);
},
onScroll_wysiwyg: function (e) {
core.controllersOff();
if (core._isBalloon) event._hideToolbar();
- if (userFunction.onScroll) userFunction.onScroll(e);
+ if (userFunction.onScroll) userFunction.onScroll(e, core);
+ },
+
+ onBlur_wysiwyg: function (e) {
+ if (core._isInline || core._isBalloon) event._hideToolbar();
+ if (userFunction.onBlur) userFunction.onBlur(e, core);
},
onMouseDown_resizingBar: function (e) {
@@ -4370,7 +4375,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
const maxCharCount = core._charCount(clipboardData.getData('text/plain').length, true);
const cleanData = util.cleanHTML(clipboardData.getData('text/html'));
- if (typeof userFunction.onPaste === 'function' && !userFunction.onPaste(e, cleanData, maxCharCount)) {
+ if (typeof userFunction.onPaste === 'function' && !userFunction.onPaste(e, cleanData, maxCharCount, core)) {
e.preventDefault();
e.stopPropagation();
return false;
@@ -4432,7 +4437,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
}
}
- if (userFunction.onDrop) userFunction.onDrop(e);
+ if (userFunction.onDrop) userFunction.onDrop(e, core);
},
_setDropLocationSelection: function (e) {
@@ -4445,7 +4450,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
_onChange_historyStack: function () {
if (context.tool.save) context.tool.save.removeAttribute('disabled');
- if (userFunction.onChange) userFunction.onChange(core.getContents(true));
+ if (userFunction.onChange) userFunction.onChange(core.getContents(true), core);
},
_addEvent: function () {
@@ -4463,6 +4468,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
eventWysiwyg.addEventListener('dragover', event.onDragOver_wysiwyg, false);
eventWysiwyg.addEventListener('drop', event.onDrop_wysiwyg, false);
eventWysiwyg.addEventListener('scroll', event.onScroll_wysiwyg, false);
+ eventWysiwyg.addEventListener('blur', event.onBlur_wysiwyg, false);
/** Events are registered only a balloon mode or when there is a table plugin. */
if (core._isBalloon || core.plugins.table) {
@@ -4494,11 +4500,6 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
if (core._isInline) {
eventWysiwyg.addEventListener('focus', event._showToolbarInline, false);
}
-
- /** inline, balloon editor */
- if (core._isInline || core._isBalloon) {
- eventWysiwyg.addEventListener('blur', event._hideToolbar, false);
- }
/** window event */
_w.removeEventListener('resize', event.onResize_window);
@@ -4529,7 +4530,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
eventWysiwyg.removeEventListener('touchstart', event.onMouseDown_wysiwyg, {passive: true, useCapture: false});
eventWysiwyg.removeEventListener('focus', event._showToolbarInline);
- eventWysiwyg.removeEventListener('blur', event._hideToolbar);
+ eventWysiwyg.removeEventListener('blur', event.onBlur_wysiwyg);
context.element.code.removeEventListener('keydown', event._codeViewAutoHeight);
context.element.code.removeEventListener('keyup', event._codeViewAutoHeight);
@@ -4564,6 +4565,7 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
onDrop: null,
onChange: null,
onPaste: null,
+ onBlur: null,
showInline: null,
/**
diff --git a/test/dev/suneditor_build_test.js b/test/dev/suneditor_build_test.js
index 7f12f7328..32e2aec2d 100644
--- a/test/dev/suneditor_build_test.js
+++ b/test/dev/suneditor_build_test.js
@@ -112,6 +112,9 @@ ss.onScroll = function (e) {
ss.onClick = function (e) {
console.log('onClick', e);
};
+ss.onBlur = function (e, core) {
+ console.log('onBlur', e);
+};
ss.onKeyDown = function (e) {
console.log('onKeyDown', e);
};
From 1d8f49c7bd352404a41bce144d8eb710762a8169 Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Fri, 14 Feb 2020 20:02:30 +0900
Subject: [PATCH 21/99] modify: #209, #213 hide cell controller, fix: #210
disabled status- it's can table edited fix: #214 disabled button cursor
pointer
---
src/assets/css/suneditor.css | 2 +-
src/lib/core.js | 2 ++
src/plugins/submenu/table.js | 6 ++++++
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/assets/css/suneditor.css b/src/assets/css/suneditor.css
index cdee4d69c..4feafb81f 100755
--- a/src/assets/css/suneditor.css
+++ b/src/assets/css/suneditor.css
@@ -154,7 +154,7 @@
.sun-editor .se-btn:enabled.on:hover, .sun-editor .se-btn:enabled.on:focus {background-color:#d1d1d1; border-color:#c1c1c1; outline:0 none;}
.sun-editor .se-btn:enabled.on:active {background-color:#c1c1c1; border-color:#b1b1b1; -webkit-box-shadow:inset 0 3px 5px #b1b1b1; box-shadow:inset 0 3px 5px #b1b1b1;}
/* disabled buttons, icon blur */
-.sun-editor .se-btn:disabled, .sun-editor .se-btn-list:disabled, .sun-editor :disabled [class*='se-icon-']::before {cursor:not-allowed; background-color:inherit; color:#bdbdbd;}
+.sun-editor .se-btn:disabled, .sun-editor .se-btn-list:disabled, .sun-editor button:disabled {cursor:not-allowed; background-color:inherit; color:#bdbdbd;}
/** --- loading box */
.sun-editor .se-loading-box {position:absolute; display:none; width:100%; height:100%; top:0; left:0; background-color:#fff; opacity:.7; filter:alpha(opacity=70); z-index:2147483647;}
diff --git a/src/lib/core.js b/src/lib/core.js
index 2aa1e5ef5..3af9abd71 100755
--- a/src/lib/core.js
+++ b/src/lib/core.js
@@ -3686,6 +3686,8 @@ export default function (context, pluginCallButtons, plugins, lang, _options) {
* @warning Events are registered only when there is a table plugin.
*/
onMouseDown_wysiwyg: function (e) {
+ if (context.element.wysiwyg.getAttribute('contenteditable') === 'false') return;
+
const tableCell = util.getParentElement(e.target, util.isCell);
if (tableCell) {
const tablePlugin = core.plugins.table;
diff --git a/src/plugins/submenu/table.js b/src/plugins/submenu/table.js
index 1bdf013dd..f1a13300d 100644
--- a/src/plugins/submenu/table.js
+++ b/src/plugins/submenu/table.js
@@ -290,6 +290,12 @@ export default {
/** table edit controller */
call_controller_tableEdit: function (tdElement) {
+ if (!this.getSelection().isCollapsed) {
+ this.controllersOff();
+ this.util.removeClass(tdElement, 'se-table-selected-cell');
+ return;
+ }
+
const contextTable = this.context.table;
const tablePlugin = this.plugins.table;
const tableController = contextTable.tableController;
From d9a168d10852e958877274e21be8ebbc50a1ebc7 Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Mon, 17 Feb 2020 01:49:01 +0900
Subject: [PATCH 22/99] #200, #203 add: options-addTagsWhitelist,
pasteTagsWhitelist, add: util-createTagsWhitelist, modify:
util-convertContentsForEditor, cleanHTML add whitelist argument
---
README.md | 8 +++++
sample/html/options.html | 10 ++++++
sample/html/out/document-editor.html | 20 +++++++++++
sample/html/out/document-util.html | 53 ++++++++++++++++++++++++++--
src/lib/constructor.js | 5 ++-
src/lib/context.js | 1 +
src/lib/core.js | 36 +++++++++++++++----
src/lib/util.js | 27 ++++++++------
src/suneditor.js | 2 +-
test/dev/suneditor_build_test.js | 7 ++--
10 files changed, 145 insertions(+), 24 deletions(-)
diff --git a/README.md b/README.md
index 7905840b3..ac2af38a0 100644
--- a/README.md
+++ b/README.md
@@ -284,6 +284,14 @@ plugins: [
video
] : Plugins array. default: null {Array}
+// Tags whitelist--------------------------------------å---------------------------------------------------------
+// _defaultTagsWhitelist : 'br|p|div|pre|blockquote|h[1-6]|ol|ul|dl|li|hr|figure|figcaption|img|iframe|audio|video|table|thead|tbody|tr|th|td|a|b|strong|var|i|em|u|ins|s|span|strike|del|sub|sup'
+addTagsWhitelist : Add tags to the default tags whitelist of editor. default: '' {String}
+ ex) 'mark|canvas|label|select|option|input'
+// _editorTagsWhitelist : _defaultTagsWhitelist + addTagsWhitelist
+pasteTagsWhitelist : Whitelist of tags when pasting. default: _editorTagsWhitelist {String}
+ ex) 'p|h[1-6]'
+
// Layout-------------------------------------------------------------------------------------------------------
lang : language object. default : en {Object}
mode : The mode of the editor ('classic', 'inline', 'balloon'). default: 'classic' {String}
diff --git a/sample/html/options.html b/sample/html/options.html
index 1baf3d104..d931e2a87 100644
--- a/sample/html/options.html
+++ b/sample/html/options.html
@@ -50,6 +50,14 @@
- Elements that need to change text or className for each selection change
+ Elements that need to change text or className for each selection change.
+ After creating the editor, commandPlugins are added.
- The width of the toolbar.
- Applies only when the editor mode is 'inline' or 'balloon' mode.
-
-
-
-
stickyToolbar
-
- Number
-
-
Reference height value that should be changed to sticky toolbar mode
-
-
-
iframe
-
- Boolean
-
-
Content will be placed in an iframe and isolated from the rest of the page
-
-
-
fullPage
-
- Boolean
-
-
Allows the usage of HTML, HEAD, BODY tags and DOCTYPE declaration
-
-
-
iframeCSSFileName
-
- String
-
-
Name of the CSS file to apply inside the iframe.
-
-
-
codeMirror
-
- Object
-
-
CodeMirror core object
-
-
-
codeMirrorEditor
-
- Object
-
-
Generated CodeMirror Object
-
-
-
position
-
- String
-
-
The position property of editor
-
-
-
display
-
- String
-
-
The display property of editor
-
-
-
popupDisplay
-
- String
-
-
Size of background area when activating dialog window ('full'||'local')
-
-
-
resizingBar
-
- Boolean
-
-
Show the bottom resizing bar
-
-
-
showPathLabel
-
- Boolean
-
-
Displays the current node structure to resizingBar
-
-
-
charCounter
-
- Boolean
-
-
Shows the number of characters in the editor
-
-
-
maxCharCount
-
- Number
-
-
The maximum number of characters allowed to be inserted into the editor
-
-
-
width
-
- String
-
-
The width size of the editor
-
-
-
minWidth
-
- String
-
-
The min-width size of the editor
-
-
-
maxWidth
-
- String
-
-
The max-width size of the editor
-
-
-
height
-
- String
-
-
The height size of the editor
-
-
-
minHeight
-
- String
-
-
The min-height size of the editor
-
-
-
maxHeight
-
- String
-
-
The max-height size of the editor
-
-
-
font
-
- Array
-
-
Change default font-family array
-
-
-
fontSize
-
- Array
-
-
Change default font-size array
-
-
-
formats
-
- Array
-
-
Change default formatBlock array
-
-
-
colorList
-
- Array
-
-
Change default color array of color picker
-
-
-
imageResizing
-
- Boolean
-
-
Can resize the image
-
-
-
imageWidth
-
- Number
-
-
The default width size of the image frame
-
-
-
imageFileInput
-
- Boolean
-
-
Choose whether to create a file input tag in the image upload window
-
-
-
imageUrlInput
-
- Boolean
-
-
Choose whether to create a image url input tag in the image upload window
-
-
-
imageUploadUrl
-
- String
-
-
The image upload to server mapping address
-
-
-
imageUploadSizeLimit
-
- Number
-
-
The size of the total uploadable images (in bytes)
-
-
-
videoResizing
-
- Boolean
-
-
Can resize the video iframe
-
-
-
videoWidth
-
- Number
-
-
The default width size of the video frame
-
-
-
videoHeight
-
- Number
-
-
The default heigth size of the video frame
-
-
-
youtubeQuery
-
- String
-
-
The query string of a YouTube embedded URL
-
-
-
callBackSave
-
- Function
-
-
Callback functions that is called when the Save button is clicked
-
-
-
templates
-
- Array
-
-
Templates array
-
-
-
placeholder
-
- String
-
-
The placeholder text
-
@@ -757,10 +439,11 @@
-
commandPluginsactivePlugins
- Plugins array with active method.
+ Plugins array with "active" method.
+ "activePlugins" runs the "add" method when creating the editor.
@@ -769,7 +452,7 @@
commandMap<
class="type-signature">
Elements that need to change text or className for each selection change.
- After creating the editor, commandPlugins are added.
+ After creating the editor, activePlugins are added.
- It is judged whether it is the format element. (P, DIV, H1-6, PRE, LI)
+ It is judged whether it is the format element. (P, DIV, H[1-6], PRE, LI)
Format element also contain "free format Element"
Parameters:
@@ -393,7 +393,7 @@
i
class="type-signature"> → {Boolean}
It is judged whether it is the range format element. (BLOCKQUOTE, OL, UL, FIGCAPTION, TABLE, THEAD, TBODY, TR, TH, TD)
- Range format element is wrap the format element (P, DIV, H1-6, PRE, LI)
+ Range format element is wrap the format element (util.isFormatElement)
Parameters:
@@ -476,7 +476,7 @@
Parameters:
getFormatElement(element, validation) → {Element}
- If a parent node that contains an argument node finds a format node (P, DIV, H[1-6], LI), it returns that node.
+ If a parent node that contains an argument node finds a format node (util.isFormatElement), it returns that node.
- If a parent node that contains an argument node finds a format node (BLOCKQUOTE, TABLE, TH, TD, OL, UL, PRE), it returns that node.
+ If a parent node that contains an argument node finds a format node (util.isRangeFormatElement), it returns that node.
- If a parent node that contains an argument node finds a free format node (PRE), it returns that node.
+ If a parent node that contains an argument node finds a free format node (util.isFreeFormatElement), it returns that node.
Parameters:
diff --git a/src/lib/constructor.js b/src/lib/constructor.js
index 42ccf73c9..b9d4b44a1 100755
--- a/src/lib/constructor.js
+++ b/src/lib/constructor.js
@@ -386,7 +386,7 @@ export default {
/** user options */
options.lang = options.lang || _defaultLang;
/** Tags whitelist */
- options._defaultTagsWhitelist = typeof options._defaultTagsWhitelist === 'string' ? options._defaultTagsWhitelist : 'br|p|div|pre|blockquote|h[1-6]|ol|ul|dl|li|hr|figure|figcaption|img|iframe|audio|video|table|thead|tbody|tr|th|td|a|b|strong|var|i|em|u|ins|s|span|strike|del|sub|sup';
+ options._defaultTagsWhitelist = typeof options._defaultTagsWhitelist === 'string' ? options._defaultTagsWhitelist : 'br|p|div|pre|blockquote|h[1-6]|ol|ul|li|hr|figure|figcaption|img|iframe|audio|video|table|thead|tbody|tr|th|td|a|b|strong|var|i|em|u|ins|s|span|strike|del|sub|sup';
options._editorTagsWhitelist = options._defaultTagsWhitelist + (typeof options.addTagsWhitelist === 'string' && options.addTagsWhitelist.length > 0 ? '|' + options.addTagsWhitelist : '');
options.pasteTagsWhitelist = typeof options.pasteTagsWhitelist === 'string' ? options.pasteTagsWhitelist : options._editorTagsWhitelist;
/** Layout */
diff --git a/src/lib/core.js b/src/lib/core.js
index a18309ae5..65f10ceaf 100755
--- a/src/lib/core.js
+++ b/src/lib/core.js
@@ -982,7 +982,7 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
/**
* @description Appended all selected format Element to the argument element and insert
- * @param {Element} rangeElement Element of wrap the arguments (PRE, BLOCKQUOTE...)
+ * @param {Element} rangeElement Element of wrap the arguments (BLOCKQUOTE...)
*/
applyRangeFormatElement: function (rangeElement) {
const rangeLines = this.getSelectedElementsAndComponents();
diff --git a/src/lib/util.js b/src/lib/util.js
index 913d87497..66225a1f6 100755
--- a/src/lib/util.js
+++ b/src/lib/util.js
@@ -303,7 +303,7 @@ const util = {
},
/**
- * @description It is judged whether it is the format element (P, DIV, H1-6, PRE, LI)
+ * @description It is judged whether it is the format element (P, DIV, H[1-6], PRE, LI)
* Format element also contain "free format Element"
* @param {Element} element The element to check
* @returns {Boolean}
@@ -315,7 +315,7 @@ const util = {
/**
* @description It is judged whether it is the range format element. (BLOCKQUOTE, OL, UL, FIGCAPTION, TABLE, THEAD, TBODY, TR, TH, TD)
- * * Range format element is wrap the format element (P, DIV, H1-6, PRE, LI)
+ * * Range format element is wrap the format element (util.isFormatElement)
* @param {Element} element The element to check
* @returns {Boolean}
*/
@@ -346,7 +346,7 @@ const util = {
},
/**
- * @description If a parent node that contains an argument node finds a format node (P, DIV, H[1-6], PRE, LI), it returns that node.
+ * @description If a parent node that contains an argument node finds a format node (util.isFormatElement), it returns that node.
* @param {Element} element Reference element if null or no value, it is relative to the current focus node.
* @param {Function|null} validation Additional validation function.
* @returns {Element}
@@ -369,7 +369,7 @@ const util = {
},
/**
- * @description If a parent node that contains an argument node finds a format node (BLOCKQUOTE, TABLE, TH, TD, OL, UL, TH, TD), it returns that node.
+ * @description If a parent node that contains an argument node finds a format node (util.isRangeFormatElement), it returns that node.
* @param {Element} element Reference element if null or no value, it is relative to the current focus node.
* @param {Function|null} validation Additional validation function.
* @returns {Element|null}
@@ -390,7 +390,7 @@ const util = {
},
/**
- * @description If a parent node that contains an argument node finds a free format node (PRE), it returns that node.
+ * @description If a parent node that contains an argument node finds a free format node (util.isFreeFormatElement), it returns that node.
* @param {Element} element Reference element if null or no value, it is relative to the current focus node.
* @param {Function|null} validation Additional validation function.
* @returns {Element}
@@ -609,7 +609,7 @@ const util = {
* @returns {Boolean}
*/
isList: function (node) {
- return node && /^(OL|UL|DL)$/i.test(typeof node === 'string' ? node : node.nodeName);
+ return node && /^(OL|UL)$/i.test(typeof node === 'string' ? node : node.nodeName);
},
/**
From fa7e683abc80e5e13a87a7a6c0c528954f6668ce Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Thu, 27 Feb 2020 03:35:12 +0900
Subject: [PATCH 55/99] update: #217 applyRangeFormatElement - nested tags
update: nested list css style add: core-splitNestedElement change:
util-removeNestedTags > mergeNestedTags
---
sample/html/out/document-editor.html | 41 ++++++++++++--
sample/html/out/document-util.html | 18 ++++--
src/assets/css/suneditor-contents.css | 13 +++++
src/assets/css/suneditor.css | 28 +++++-----
src/lib/core.js | 79 ++++++++++++++++++++++-----
src/lib/util.js | 14 +++--
src/plugins/command/blockquote.js | 2 +-
7 files changed, 151 insertions(+), 44 deletions(-)
diff --git a/sample/html/out/document-editor.html b/sample/html/out/document-editor.html
index aa310b133..c2a5134ce 100644
--- a/sample/html/out/document-editor.html
+++ b/sample/html/out/document-editor.html
@@ -904,7 +904,7 @@
getSe
getSelectedElements(validation) → {Array}
- Returns a "formatElement"(P, DIV, H[1-6], LI) array from the currently selected range.
+ Returns a "formatElement"(util.isFormatElement) array from the currently selected range.
Parameters:
@@ -921,7 +921,7 @@
Parameters:
Function|null
-
The validation function. (Replaces the default validation function-util.isFormatElement(current))
+
The validation function. (Replaces the default validation function-util.isFormatElement)
@@ -1054,7 +1054,7 @@
Parameters:
Boolean
-
When true, it does not update the history stack and the selection object and return EdgeNodes (util.getEdgeChildNodes)
+
When true, it does not update the history stack and the selection object and return EdgeNodes (util.getEdgeChildNodes)
@@ -1139,6 +1139,34 @@
removeNode<
+
splitNestedElement(beforeTag) → {Element}
+
+ Split all nested tags based on "beforeTag"
+ Returns the last element of the splited tag.
+
+
Parameters:
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
beforeTag
+
+ Element
+
+
Criteria element
+
+
+
+
+
+
applyRangeFormatElement(rangeElement)
@@ -1170,7 +1198,7 @@
The elements of the "selectedFormats" array are detached from the "rangeElement" element. ("LI" tags are converted to "P" tags)
- When "selectedFormats" is null, all elements are detached and return {cc: parentNode, sc: nextSibling, ec: previousSibling}.
+ When "selectedFormats" is null, all elements are detached and return {cc: parentNode, sc: previousSibling, ec: nextSibling}.
Parameters:
@@ -1195,7 +1223,7 @@
Parameters:
Array|null
Array of format elements (P, DIV, LI...) to remove.
- If null, Applies to all elements and return {cc: parentNode, sc: nextSibling, ec: previousSibling}
+ If null, Applies to all elements and return {cc: parentNode, sc: previousSibling, ec: nextSibling}
newRangeElement
@@ -1216,7 +1244,7 @@
Parameters:
Boolean
-
When true, it does not update the history stack and the selection object and return EdgeNodes (util.getEdgeChildNodes)
+
When true, it does not update the history stack and the selection object and return EdgeNodes (util.getEdgeChildNodes)
Returns the number of parents nodes.
- "0" when the parent node is the WYSIWYG area.
+ "0" when the parent node is the WYSIWYG area.
+ "-1" when the element argument is the WYSIWYG area.
- Delete the currently selected node
+ Delete the currently selected nodes and reset selection range
+ Returns {container: "the last element after deletion", offset: "offset"}
Get format elements and components from the selected area. (P, DIV, H[1-6], OL, UL, TABLE..)
If some of the component are included in the selection, get the entire that component.
+
Parameters:
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
removeDuplicate
+
+ Boolean
+
+
If true, if there is a parent and child tag among the selected elements, the child tag is excluded.
+
+
+
@@ -1140,41 +1159,6 @@
removeNode<
-
splitElement(beforeNode, offset) → {Element}
-
- Split all tags based on "beforeNode"
- Returns the last element of the splited tag.
-
-
Parameters:
-
-
-
-
Name
-
Type
-
Description
-
-
-
-
-
beforeNode
-
- Node
-
-
Element or text node on which to base
-
-
-
offset
-
- Number|null
-
-
Text offset of "beforeNode" (Only valid when "beforeNode" is a text node)
+ Use with "npdePath (util.getNodePath)" to merge the same attributes and tags if they are present and modify the nodepath.
+ If "offset" has been changed, it will return as much "offset" as it has been modified.
+ "a", "b" You can send a maximum of two nodepaths.
+
- It is judged whether it is the component(img, iframe cover, table, hr) element - ".sun-editor-id-comp"
+ It is judged whether it is the component [img, iframe] cover(element className - ".se-component") and table, hr
+
+
Parameters:
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
element
+
+ Element
+
+
The element to check
+
+
+
+
+
+
+
isMediaComponent(element) → {Boolean}
+
+ It is judged whether it is the component [img, iframe] cover(element className - ".se-component")
+ Get the item from the array that matches the condition.
+
+
Parameters:
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
array
+
+ Array
+
+
Array to get item
+
+
+
validation
+
+ Function|null
+
+
Conditional function
+
+
+
multi
+
+ Boolean
+
+
+ If true, returns all items that meet the criteria otherwise, returns an empty array.
+ If false, returns only one item that meet the criteria otherwise return null.
+
+ "selectedFormats" array are detached from the list element.
+ The return value is applied when the first and last lines of "selectedFormats" are "LI" respectively.
+
The elements of the "selectedFormats" array are detached from the "rangeElement" element. ("LI" tags are converted to "P" tags)
- When "selectedFormats" is null, all elements are detached and return {cc: parentNode, sc: previousSibling, ec: nextSibling}.
+ When "selectedFormats" is null, all elements are detached and return {cc: parentNode, sc: previousSibling, ec: nextSibling, removeArray: [Array of removed elements]}.
Parameters:
diff --git a/src/lib/core.js b/src/lib/core.js
index e7266df88..81bdd7fdc 100755
--- a/src/lib/core.js
+++ b/src/lib/core.js
@@ -1099,8 +1099,6 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
if (util.isList(originParent)) {
if (listParent === null) listParent = util.createElement(originParent.nodeName);
-
- listParent.innerHTML += line.outerHTML;
lineArr.push(line);
if (i === len - 1 || rangeLines[i + 1].parentNode !== originParent) {
@@ -1129,6 +1127,10 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
else beforeTag = edge.cc;
}
+ for (let c = 0, cLen = edge.removeArray.length; c < cLen; c++) {
+ listParent.innerHTML += edge.removeArray[c].outerHTML;
+ }
+
rangeElement.appendChild(listParent);
listParent = null;
}
@@ -1177,13 +1179,14 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
/**
* @description The elements of the "selectedFormats" array are detached from the "rangeElement" element. ("LI" tags are converted to "P" tags)
- * When "selectedFormats" is null, all elements are detached and return {cc: parentNode, sc: nextSibling, ec: previousSibling}.
+ * When "selectedFormats" is null, all elements are detached and return {cc: parentNode, sc: nextSibling, ec: previousSibling, removeArray: [Array of removed elements]}.
* @param {Element} rangeElement Range format element (PRE, BLOCKQUOTE, OL, UL...)
* @param {Array|null} selectedFormats Array of format elements (P, DIV, LI...) to remove.
* If null, Applies to all elements and return {cc: parentNode, sc: nextSibling, ec: previousSibling}
* @param {Element|null} newRangeElement The node(rangeElement) to replace the currently wrapped node.
* @param {Boolean} remove If true, deleted without detached.
* @param {Boolean} notHistoryPush When true, it does not update the history stack and the selection object and return EdgeNodes (util.getEdgeChildNodes)
+ * @returns {Object}
*/
detachRangeFormatElement: function (rangeElement, selectedFormats, newRangeElement, remove, notHistoryPush) {
const range = this.getRange();
@@ -1196,6 +1199,7 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
let lastNode = null;
let rangeEl = rangeElement.cloneNode(false);
+ const removeArray = [];
const newList = util.isList(newRangeElement);
let insertedNew = false;
let reset = false;
@@ -1255,6 +1259,7 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
return first;
}
+ // detach loop
for (let i = 0, len = children.length, insNode; i < len; i++) {
insNode = children[i];
if (remove && i === 0) {
@@ -1285,7 +1290,7 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
}
} else {
const inner = insNode;
- insNode = util.createElement((util.isList(rangeElement.parentNode) || util.isListCell(rangeElement.parentNode)) ? 'LI' : util.isCell(rangeElement.parentNode) ? 'DIV' : 'P');
+ insNode = util.createElement(remove ? inner.nodeName : (util.isList(rangeElement.parentNode) || util.isListCell(rangeElement.parentNode)) ? 'LI' : util.isCell(rangeElement.parentNode) ? 'DIV' : 'P');
const innerChildren = inner.childNodes;
while (innerChildren[0]) {
insNode.appendChild(innerChildren[0]);
@@ -1296,28 +1301,30 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
insNode = insNode.cloneNode(true);
}
- if (!remove && !reset) {
- if (newRangeElement) {
- if (!insertedNew) {
- parent.insertBefore(newRangeElement, rangeElement);
- insertedNew = true;
+ if (!reset) {
+ if (!remove) {
+ if (newRangeElement) {
+ if (!insertedNew) {
+ parent.insertBefore(newRangeElement, rangeElement);
+ insertedNew = true;
+ }
+ insNode = appendNode(newRangeElement, insNode, null, children[i]);
+ } else {
+ insNode = appendNode(parent, insNode, rangeElement, children[i]);
}
- insNode = appendNode(newRangeElement, insNode, null, children[i]);
- } else {
- insNode = appendNode(parent, insNode, rangeElement, children[i]);
- }
-
- if (selectedFormats) {
- lastNode = insNode;
- if (!firstNode) {
- firstNode = insNode;
+
+ if (selectedFormats) {
+ lastNode = insNode;
+ if (!firstNode) {
+ firstNode = insNode;
+ }
+ } else if (!firstNode) {
+ firstNode = lastNode = insNode;
}
- } else if (!firstNode) {
- firstNode = lastNode = insNode;
+ } else {
+ removeArray.push(insNode);
}
- }
-
- if (reset) {
+ } else {
reset = false;
children = util.getListChildNodes(rangeElement, function (current) { return current.parentNode === rangeElement; });
rangeEl = rangeElement.cloneNode(false);
@@ -1347,6 +1354,7 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
cc: rangeParent,
sc: firstNode,
ec: rangeRight,
+ removeArray: removeArray
};
} else {
edge = util.getEdgeChildNodes(firstNode, (!lastNode.parentNode ? firstNode : lastNode));
@@ -4111,28 +4119,7 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
if (ctrl || alt || util.isWysiwygDiv(selectionNode)) break;
core.controllersOff();
-
- // table
- let currentNode = selectionNode;
- while (!util.isCell(currentNode) && !util.isWysiwygDiv(currentNode)) {
- currentNode = currentNode.parentNode;
- }
-
- if (currentNode && util.isCell(currentNode)) {
- const table = util.getParentElement(currentNode, 'table');
- const cells = util.getListChildren(table, util.isCell);
- let idx = shift ? util.prevIdx(cells, currentNode) : util.nextIdx(cells, currentNode);
-
- if (idx === cells.length && !shift) idx = 0;
- if (idx === -1 && shift) idx = cells.length - 1;
-
- const moveCell = cells[idx];
- if (!moveCell) return false;
-
- core.setRange(moveCell, 0, moveCell, 0);
- break;
- }
-
+ const isEdge = (!range.collapsed || core.isEdgePoint(range.startContainer, range.startOffset));
const selectedFormats = core.getSelectedElements();
const cells = [];
let lines = [];
@@ -4152,7 +4139,7 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
}
// Nested list
- if (cells.length > 0 && (!range.collapsed || core.isEdgePoint(range.startContainer, range.startOffset)) && core.plugins.list) {
+ if (cells.length > 0 && isEdge && core.plugins.list) {
core.callPlugin('list', function () {
const listRange = core.plugins.list.editInsideList.call(core, shift, cells);
if (fc) {
@@ -4165,6 +4152,23 @@ export default function (context, pluginCallButtons, plugins, lang, options) {
}
});
} else {
+ // table
+ const tableCell = util.getParentElement(selectionNode, util.isCell);
+ if (tableCell && isEdge) {
+ const table = util.getParentElement(tableCell, 'table');
+ const cells = util.getListChildren(table, util.isCell);
+ let idx = shift ? util.prevIdx(cells, tableCell) : util.nextIdx(cells, tableCell);
+
+ if (idx === cells.length && !shift) idx = 0;
+ if (idx === -1 && shift) idx = cells.length - 1;
+
+ const moveCell = cells[idx];
+ if (!moveCell) return false;
+
+ core.setRange(moveCell, 0, moveCell, 0);
+ break;
+ }
+
lines = lines.concat(cells);
fc = lc = null;
}
diff --git a/src/plugins/submenu/template.js b/src/plugins/submenu/template.js
index 9d66b97ec..6fcc6aded 100644
--- a/src/plugins/submenu/template.js
+++ b/src/plugins/submenu/template.js
@@ -29,8 +29,11 @@ export default {
setSubmenu: function () {
const templateList = this.context.option.templates;
- const listDiv = this.util.createElement('DIV');
+ if (!templateList || templateList.length === 0) {
+ throw Error('[SUNEDITOR.plugins.template.fail] To use the "template" plugin, please define the "templates" option.');
+ }
+ const listDiv = this.util.createElement('DIV');
listDiv.className = 'se-list-layer';
let list = '
' : '';
if(this.context.custom.textElement.value.length > 0) {
- // const parser = new this._w.DOMParser();
- // parser.parseFromString(title, 'text/html')
// Get Input value
- const value = title.concat('
', this.context.custom.textElement.value, '
');
+ let value = title;
+ const lines = this.context.custom.textElement.value.split('\n');
+ for (let i = 0, len = lines.length; i < len; i++) {
+ value += '
' + lines[i] + '
';
+ }
+ // rendering
const template = this.util.createElement('DIV');
template.innerHTML = value;
@@ -81,8 +84,8 @@ export default {
after = child;
}
- // set range
- // this.setRange(value, value.length, value, value.length);
+ // set range (It is not necessary this code in the next version)
+ // this.setRange(after, 1, after, 1);
// clear content
this.context.custom.textElement.value = null;
From 6fcaf9bf9dc37af9b47a87b2e266be0afb5837b2 Mon Sep 17 00:00:00 2001
From: JiHong88 <0125ses@hanmail.net>
Date: Fri, 6 Mar 2020 04:47:52 +0900
Subject: [PATCH 70/99] add: util-sortByDepth, moodify: backspace key action
---
sample/html/out/document-util.html | 35 ++++++++++++++++
src/lib/core.js | 66 +++++++++++++++++++++++++-----
src/lib/util.js | 23 +++++++++--
src/plugins/submenu/list.js | 15 +++----
4 files changed, 115 insertions(+), 24 deletions(-)
diff --git a/sample/html/out/document-util.html b/sample/html/out/document-util.html
index 9f7bb8015..d32b32a6d 100644
--- a/sample/html/out/document-util.html
+++ b/sample/html/out/document-util.html
@@ -1969,6 +1969,40 @@
/**
-* ID : 'suneditor_sample'
-* ClassName : 'sun-eidtor'
-*/
-// ID or DOM object
-constsuneditor=SUNEDITOR.create((document.getElementById('sample') ||'sample'),{
- // All of the plugins are loaded in the "window.SUNEDITOR" object in dist/suneditor.min.js file
- // Insert options
- // Language global object (default: en)
- lang:SUNEDITOR_LANG['ko']
-});
When you display a document created by suneditor
-You need to include "src/assets/css/suneditor-contents.css" or "dist/css/suneditor.min.css" file.
-Then add "sun-editor-editable" to the classname of the Tag element that displays the content.
-In "suneditor-contents.css", you can define the style of all the tags created in suneditor.
The init function can be used by predefining options and calling the create function on the returned object.
-The value of the option argument put in the "create" function call takes precedence
-
-
import'suneditor/dist/css/suneditor.min.css'
-importsuneditorfrom'suneditor'
-importpluginsfrom'suneditor/src/plugins'
-
-// all plugins
-constinitEditor=suneditor.init({
- plugins: plugins,
- height:200,
- buttonList: [
- ['undo', 'redo',
- 'font', 'fontSize', 'formatBlock',
- 'paragraphStyle',
- 'bold', 'underline', 'italic', 'strike', 'subscript', 'superscript',
- 'fontColor', 'hiliteColor', 'textStyle',
- 'removeFormat',
- 'outdent', 'indent',
- 'align', 'horizontalRule', 'list', 'lineHeight',
- 'table', 'link', 'image', 'video',
- 'fullScreen', 'showBlocks', 'codeView',
- 'preview', 'print', 'save', 'template']
- ]
-});
-
-initEditor.create('sample_1', {
- // The value of the option argument put in the "create" function call takes precedence
-});
-
-initEditor.create('sample_2', {
- // The value of the option argument put in the "create" function call takes precedence
- height:'auto',
- buttonList: [
- ['bold', 'underline', 'italic'],
- ['removeFormat'],
- ['preview', 'print']
- ]
-});
plugins: [
- // Submenu
- align,
- font,
- fontColor,
- fontSize,
- formatBlock,
- hiliteColor,
- horizontalRule,
- lineHeight,
- list,
- paragraphStyle,
- table,
- template,
- textStyle,
- // Dialog
- image,
- link,
- video
-] :Plugins array. default:null {Array}
-
-// Layout-------------------------------------------------------------------------------------------------------
-lang : language object. default: en {Object}
-mode :The mode of the editor ('classic', 'inline', 'balloon').default:'classic' {String}
-toolbarWidth :The width of the toolbar. Applies only when the editor mode is
- 'inline' or 'balloon' mode. default:'auto' {Number|String}
-stickyToolbar :Reference height value that should be changed to sticky toolbar mode.
- It can also be used when there is another fixed toolbar at the top.
- Set to 0, '0px', '50px', etc.
- If set to -1 or false or null to turn off. default:0 {Number|String|Boolean}
-iframe :Content will be placed in an iframe and isolated from the rest of the page. default:false {Boolean}
-fullPage :Allows the usage of HTML, HEAD, BODY tags and DOCTYPE declaration. default:false {Boolean}
-iframeCSSFileName :Name or Array of the CSS file to apply inside the iframe.
- Applied by searching by filename in the link tag of document,
- or put the URL value. default:'suneditor' {Array|String}
- ex) 'main' or ['suneditor', 'http://suneditor.com/sample/css/sample.css']
-codeMirror :If you put the CodeMirror object as an option, you can doCodeview using CodeMirror. default:null {Object}
- Use version 5.0.0 or later.
- ex) codeMirror:CodeMirror// Default option
- codeMirror: { // Custom option
- src:CodeMirror,
- options: {
- /** default options **
- * mode: 'htmlmixed',
- * htmlMode: true,
- * lineNumbers: true
- * lineWrapping: true
-*/
- }
- }
-
-// Display-------------------------------------------------------------------------------------------------------
-position :The position property of suneditor. default:null {String}
-display :The display property of suneditor. default:'block' {String}
-popupDisplay :Size of background area when activating dialog window ('full'||'local') default:'full' {String}
-
-// Bottom resizing bar-------------------------------------------------------------------------------------------
-resizingBar :Show the bottom resizing bar.
- If'height' value is 'auto', it will not be resized. default:true {Boolean}
-showPathLabel :Displays the current node structure to resizingBar. default:true {Boolean}
-charCounter :Shows the number of characters in the editor.
- If the maxCharCount option has a value, it becomes true. default:false {Boolean}
-maxCharCount :The maximum number of characters allowed to be inserted into the editor. default:null {Number}
-
-// Width size----------------------------------------------------------------------------------------------------
-width :The width size of the editor. default: clientWidth||'100%' {Number|String}
-minWidth :The min-width size of the editor.
- Used when 'width' value is 'auto' or '~%'.default:null {Number|String}
-maxWidth :The max-width size of the editor.
- Used when 'width' value is 'auto' or '~%'.default:null {Number|String}
-
-// Height size---------------------------------------------------------------------------------------------------
-height :The height size of the editor. default: clientHeight||'auto' {Number|String}
-minHeight :The min-height size of the editor.
- Used when 'height' value is 'auto'.default:null {Number|String}
-maxHeight :The max-height size of the editor.
- Used when 'height' value is 'auto'.default:null {Number|String}
-
-// Defining menu items-------------------------------------------------------------------------------------------
-font :Changedefault font-family array. default: [...] {Array}
- Default value: [
- 'Arial', 'Comic Sans MS', 'Courier New', 'Impact',
- 'Georgia','tahoma', 'Trebuchet MS', 'Verdana'
- ]
-fontSize :Changedefault font-size array. default: [...] {Array}
- Default value: [
- 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72
- ]
-fontSizeUnit :The font size unit. default:'px' {String}
-formats :Changedefault formatBlock array. default: [...] {Array}
- Default value: [
- 'p', 'div', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
- // "blockquote": range format, "pre": free format, "Other tags": replace format
- ],
- Custom: [{
- tag:'div', // Tag name
- name:'Custom div'||null, // default: tag name
- command:'replace'||'range', // default: "replace"
- class:'__se__format__replace_xxx'||'__se__format__range_xxx'||'__se__format__free_xxx'
- // Class names must always begin with "__se__format__(replace, range, free)_"
- }]
-colorList :Changedefault color array of color picker. default: [..[..]..] {Array}
- Default value: [
- '#ff0000', '#ff5e00', '#ffe400', '#abf200', '#00d8ff', '#0055ff', '#6600ff', '#ff00dd', '#000000',
- '#ffd8d8', '#fae0d4', '#faf4c0', '#e4f7ba', '#d4f4fa', '#d9e5ff', '#e8d9ff', '#ffd9fa', '#f1f1f1',
- '#ffa7a7', '#ffc19e', '#faed7d', '#cef279', '#b2ebf4', '#b2ccff', '#d1b2ff', '#ffb2f5', '#bdbdbd',
- '#f15f5f', '#f29661', '#e5d85c', '#bce55c', '#5cd1e5', '#6699ff', '#a366ff', '#f261df', '#8c8c8c',
- '#980000', '#993800', '#998a00', '#6b9900', '#008299', '#003399', '#3d0099', '#990085', '#353535',
- '#670000', '#662500', '#665c00', '#476600', '#005766', '#002266', '#290066', '#660058', '#222222'
- ]
- ex) [
- ['#ccc', '#dedede', 'OrangeRed', 'Orange', 'RoyalBlue', 'SaddleBrown'], // Line break
- ['SlateGray', 'BurlyWood', 'DeepPink', 'FireBrick', 'Gold', 'SeaGreen']
- ]
-lineHeights :Changedefault line-height array. default: [{}..] {Array}
- Default value: [
- {text:'1', value:1},
- {text:'1.15', value:1.15},
- {text:'1.5', value:1.5},
- {text:'2', value:2}
- ]
- ex) [
- {text:'Single', value:1},
- {text:'Double', value:2}
- ]
-paragraphStyles : You can apply custom classto format.
- ex) '.sun-editor-editable .__se__customClass'
- '.sun-editor .__se__customClass' // If you want to apply styles to menu items as well
- Default value: [
- {
- name:'Spaced', // Format style name
- class:'__se__p-spaced', // Define style for used class (Class names must always begin with "__se__")
- _class:''// You can control the style of the tags displayed in the menu by putting a class on the button of the menu.
- },
- {
- name:'Bordered',
- class:'__se__p-bordered'
- },
- {
- name:'Neon',
- class:'__se__p-neon'
- }
- ]
- ex) [
- 'spaced', 'neon', // The default value is called by name only and the name is called in the language file.
- {
- name:'Custom',
- class:'__se__customClass'
- }
- ]
-textStyles : You can apply custom style or classto selected text.
- ex(using a class)) '.sun-editor-editable .__se__customClass'
- '.sun-editor .__se__customClass' // If you want to apply styles to menu items as well
- Default value: [
- {
- name:'Translucent', // Text style name
- style:'opacity: 0.5;', // Style query
- tag:'span', // Style tag name (default: span)
- _class:''// You can control the style of the tags displayed in the menu by putting a class on the button of the menu.
- },
- {
- name:'Shadow',
- class:'__se__t-shadow', // Class names (Class names must always begin with "__se__")
- tag:'span'
- }
- ]
- ex) [
- 'translucent', // The default value is called by name only and the name is called in the language file.
- {
- name:'Emphasis',
- style:'-webkit-text-emphasis: filled;',
- tag:'span'
- }
- ]
-
-// Image---------------------------------------------------------------------------------------------------------
-imageResizing :Can resize the image. default:true {Boolean}
-imageHeightShow :Choose whether the image height input is visible. default:true {Boolean}
-imageWidth :Thedefault width size of the image frame. default:'auto' {String}
-imageSizeOnlyPercentage :Iftrue, image size can only be scaled by percentage. default:false {Boolean}
-imageRotation :Choose whether to image rotation buttons display.
- When"imageSizeOnlyPercentage" is "true" or or "imageHeightShow" is "false" the default value is false.
- If you want the button to be visible, put it a true. default:true {Boolean}
-imageFileInput :Choose whether to create a file input tag in the image upload window. default:true {Boolean}
-imageUrlInput :Choose whether to create a image url input tag in the image upload window.
- If the value of imageFileInput is false, it will be unconditionally. default:true {Boolean}
-imageUploadHeader :HttpHeader when uploading images. default:null {Object}
-imageUploadUrl :The image upload to server mapping address. default:null {String}
- ex) "/editor/uploadImage.ajax"
- When not used, it enters base64 data
- return {
- "errorMessage":"insert error message",
- "result": [
- {
- "url":"/download/editorImg/test_image.jpg",
- "name":"test_image.jpg",
- "size":"561276"
- }
- ]
- }
-imageUploadSizeLimit:The size of the total uploadable images (in bytes).
- Invokes the "onImageUploadError" method. default:null {Number}
-
-// Video----------------------------------------------------------------------------------------------------------
-videoResizing :Can resize the video iframe. default:true {Boolean}
-videoHeightShow :Choose whether the video height input is visible. default:true {Boolean}
-videoRatioShow :Choose whether the video ratio options is visible. default:true {Boolean}
-videoWidth :Thedefault width size of the video frame. default:'100%' {String}
-videoSizeOnlyPercentage :Iftrue, video size can only be scaled by percentage. default:false {Boolean}
-videoRotation :Choose whether to video rotation buttons display.
- When"videoSizeOnlyPercentage" is "true" or "videoHeightShow" is "false" the default value is false.
- If you want the button to be visible, put it a true. default:true {Boolean}
-videoRatio :Thedefault aspect ratio of the video.
- Up to four decimal places are allowed. default:0.5625 (16:9) {Float}
-videoRatioList :Video ratio selection options.
- default: [
- {name:'16:9', value:0.5625},
- {name:'4:3', value:0.75},
- {name:'21:9', value:0.4285}
- ],
- ex) [
- {name:'Classic Film 3:2', value:0.6666},
- {name:'HD', value:0.5625}
- ]
-youtubeQuery :The query string of a YouTube embedded URL. default:'' {String}
- It takes precedence over the value user entered.
- ex) 'autoplay=1&mute=1&enablejsapi=1&controls=0&rel=0&modestbranding=1'
- // https://developers.google.com/youtube/player_parameters
-
-// Defining save button-------------------------------------------------------------------------------------------
-callBackSave :Callback functions that is called when the Save button is clicked.
- Arguments- (contents).default: userFunction.save {Function}
-
-// Templates Array------------------------------------------------------------------------------------------------
-templates :If you use a template plugin, add it.
- Defines a list of templates. default:null {Array}
- ex) [
- {
- name:'Template-1',
- html:'<p>HTML source1</p>'
- },
- {
- name:'Template-2',
- html:'<p>HTML source2</p>'
- }
- ]
-
-// ETC------------------------------------------------------------------------------------------------------------
-placeholder :The placeholder text. default:null {String}
-
-// Buttons--------------------------------------------------------------------------------------------------------
-buttonList :Defines button list to array {Array}
- default: [
- ['undo', 'redo'],
- // ['font', 'fontSize', 'formatBlock'],
- // ['paragraphStyle'],
- ['bold', 'underline', 'italic', 'strike', 'subscript', 'superscript'],
- // ['fontColor', 'hiliteColor', 'textStyle'],
- ['removeFormat'],
- ['outdent', 'indent'],
- // ['align', 'horizontalRule', 'list', 'lineHeight'],
- // ['table', 'link', 'image', 'video'],
- ['fullScreen', 'showBlocks', 'codeView'],
- ['preview', 'print'],
- // ['save', 'template'],
- // '/', Line break
- ]
importsuneditorfrom'suneditor'
-
-consteditor=suneditor.create('example');
-
-// Add or reset option property
-editor.setOptions({
- minHeight:'300px',
- buttonList: [
- ['fontColor', 'hiliteColor']
- ],
- colorList: [
- ['#ccc', '#dedede', 'OrangeRed', 'Orange', 'RoyalBlue', 'SaddleBrown']
- ]
-});
-
-// Open a notice area
-editor.noticeOpen('test notice');
-
-// Close a notice area
-editor.noticeClose();
-
-// Copies the contents of the suneditor into a [textarea]
-editor.save();
-
-// Gets the suneditor's context object. Contains settings, plugins, and cached element objects
-editor.getContext();
-
-// Gets the contents of the suneditor
-// onlyContents {Boolean}: Return only the contents of the body without headers when the "fullPage" option is true
-editor.getContents(onlyContents:Boolean);
-
-// Gets a list of images uploaded to the editor
-/**
- * {
- * element: image element
- * src: imgage src
- * index: data index
- * name: file name
- * size: file size
- * select: select function
- * delete: delete function
- * }
- **/
-editor.getImagesInfo();
-
-// Upload images using image plugin
-// document.getElementById('example_files_input').files
-editor.insertImage(FileList);
-
-// Inserts an HTML element or HTML string or plain string at the current cursor position
-editor.insertHTML('<img src="http://suneditor.com/sample/img/sunset.jpg">');
-
-// Change the contents of the suneditor
-editor.setContents('set contents');
-
-// Add content to the suneditor
-editor.appendContents('append contents');
-
-// Disable the suneditor
-editor.disabled();
-
-// Enabled the suneditor
-editor.enabled();
-
-// Hide the suneditor
-editor.hide();
-
-// Show the suneditor
-editor.show();
-
-// Destroy the suneditor
-editor.destroy();
-
-// Toolbar methods
-// Disable the suneditor
-editor.toolbar.disabled();
-
-// Enabled the suneditor
-editor.toolbar.enabled();
-
-// Hide the suneditor
-editor.toolbar.hide();
-
-// Show the suneditor
-editor.toolbar.show();
-
-// Event functions -------------------------------------------------------------------------------------
-// It can be redefined by receiving event object as parameter.
-// It is not called in exceptional cases and is called after the default event function has finished.
-editor.onScroll=function (e, core) { console.log('onScroll', e) }
-
-editor.onClick=function (e, core) { console.log('onClick', e) }
-
-editor.onKeyDown=function (e, core) { console.log('onKeyDown', e) }
-
-editor.onKeyUp=function (e, core) { console.log('onKeyUp', e) }
-
-editor.onDrop=function (e, core) { console.log('onDrop', e) }
-
-editor.onChange=function (contents, core) { console.log('onChange', contents) }
-
-editor.onBlur=function (e, core) { console.log('onBlur', e) }
-
-// onload event
-// When reloaded with the "setOptions" method, the value of the "reload" argument is true.
-editor.onload=function (core, reload) {
- console.log('onload-core', core)
- console.log('onload-reload', reload)
-}
-
-// Paste event.
-// Called before the editor's default event action.
-// If it returns false, it stops without executing the rest of the action.
-/**
- * cleanData : HTML string modified for editor format
- * maxCharCount : maxChartCount option (true if max character is exceeded)
-*/
-editor.onPaste=function (e, cleanData, maxCharCount, core) { console.log('onPaste', e, cleanData, maxCharCount) }
-
-// Called when the image is uploaded or the uploaded image is deleted.
-/**
- * targetImgElement: Current img element
- * index: Uploaded index (key value)
- * state: Upload status ('create', 'update', 'delete')
- * imageInfo: {
- * * index: data index
- * * name: file name
- * * size: file size
- * * select: select function
- * * delete: delete function
- * }
- * remainingFilesCount: Count of remaining image files
-*/
-editor.onImageUpload=function (targetImgElement, index, state, imageInfo, remainingFilesCount, core) {
- console.log(`targetImgElement:${targetImgElement}, index:${index}, state('create', 'update', 'delete'):${state}`)
- console.log(`imageInfo:${imageInfo}, remainingFilesCount:${remainingFilesCount}`)
-}
-
-// Called when the image is upload failed.
-// If you return false, the default notices are not called.
-/**
- * errorMessage: Error message to show
- * result: Result object
-*/
-editor.onImageUploadError=function (errorMessage, result, core) {
- alert(errorMessage)
-}
-
-/**
- * toolbar: Toolbar Element
- * context: The editor's context object (editor.getContext())
-*/
-editor.showInline=function (toolbar, context, core) {
- console.log('toolbar', toolbar);
- console.log('context', context);
-}
+ It replaces the default callback function of the image upload.
+
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
response
+
+ Response
+
+
Response object
+
+
+
info
+
+ Object
+
+
+ -- Input information --
+ linkValue: Link url value
+ linkNewWindow: Open in new window Check Value
+ inputWidth: Value of width input
+ inputHeight: Value of height input
+ align: Align Check Value
+ isUpdate: Update image if true, create image if false
+ currentImage: If isUpdate is true, the currently selected image.
+