suneditor
Version:
Vanilla JavaScript based WYSIWYG web editor
137 lines (116 loc) • 5.13 kB
JavaScript
import { dom, unicode } from '../../../helper';
/**
* @description Service responsible for `line` breaking and default `line` creation logic.
* - Handles the `Enter` key behavior (`P` vs `BR` vs `DIV`).
* - Manages the initial `line` creation when the editor is empty.
*/
export default class DefaultLineManager {
#$;
/**
* @constructor
* @param {import('../eventOrchestrator').default} inst
*/
constructor({ $ }) {
this.#$ = $;
}
/**
* @description Executes the default `line` creation logic.
* - If no `formatName` is provided, it uses the `defaultLine` option (usually `P`).
* - Handles creating a new `block` element when the user presses `Enter` or when initializing.
* @param {string} [formatName] The tag name to be used for the new `line` (e.g., `P`, `DIV`, `BR`).
* @returns {?void}
*/
execute(formatName) {
if (!this.#$.options.get('__lineFormatFilter')) return null;
if (this.#$.pluginManager.fileInfo.pluginRegExp.test(this.#$.ui.currentControllerName)) return;
const range = this.#$.selection.getRange();
const commonCon = /** @type {HTMLElement} */ (range.commonAncestorContainer);
const startCon = range.startContainer;
const endOffset = range.endOffset;
const rangeEl = this.#$.format.getBlock(commonCon, null);
/** @type {Node} */
let focusNode;
let offset, format;
if (rangeEl) {
format = dom.utils.createElement(formatName || this.#$.options.get('defaultLine'));
format.innerHTML = rangeEl.innerHTML;
if (format.childNodes.length === 0) format.innerHTML = unicode.zeroWidthSpace;
rangeEl.innerHTML = format.outerHTML;
format = rangeEl.firstChild;
focusNode = format.childNodes[endOffset] || dom.query.getEdgeChildNodes(format, null).sc;
if (!focusNode) {
focusNode = dom.utils.createTextNode(unicode.zeroWidthSpace);
format.insertBefore(focusNode, format.firstChild);
}
offset = focusNode.textContent.length;
this.#$.selection.setRange(focusNode, offset, focusNode, offset);
return;
}
if (commonCon.nodeType === 3 && this.#$.component.is(commonCon.parentElement)) {
const compInfo = this.#$.component.get(commonCon.parentElement);
if (!compInfo) return;
const container = compInfo.container;
if (commonCon.parentElement === container) {
const siblingEl = commonCon.nextElementSibling ? container : container.nextElementSibling;
const el = dom.utils.createElement(this.#$.options.get('defaultLine'), null, commonCon);
container.parentElement.insertBefore(el, siblingEl);
this.#$.focusManager.focusEdge(el);
return;
}
this.#$.component.select(compInfo.target, compInfo.pluginName);
return null;
} else if (commonCon.nodeType === 1 && commonCon.getAttribute('data-se-embed') === 'true') {
let el = commonCon.nextElementSibling;
if (!this.#$.format.isLine(el)) el = this.#$.format.addLine(commonCon, this.#$.options.get('defaultLine'));
this.#$.selection.setRange(el.firstChild, 0, el.firstChild, 0);
return;
}
if ((this.#$.format.isBlock(startCon) || dom.check.isWysiwygFrame(startCon)) && (this.#$.component.is(startCon.children[range.startOffset]) || this.#$.component.is(startCon.children[range.startOffset - 1]))) return;
if (dom.query.getParentElement(commonCon, dom.check.isExcludeFormat)) return null;
if (this.#$.format.isBlock(commonCon) && commonCon.childNodes.length <= 1) {
let br = null;
if (commonCon.childNodes.length === 1 && dom.check.isBreak(commonCon.firstChild)) {
br = commonCon.firstChild;
} else {
br = dom.utils.createTextNode(unicode.zeroWidthSpace);
commonCon.appendChild(br);
}
this.#$.selection.setRange(br, 1, br, 1);
return;
}
try {
if (commonCon.nodeType === 3) {
format = dom.utils.createElement(formatName || this.#$.options.get('defaultLine'));
commonCon.parentNode.insertBefore(format, commonCon);
format.appendChild(commonCon);
}
if (dom.check.isBreak(format.nextSibling)) dom.utils.removeItem(format.nextSibling);
if (dom.check.isBreak(format.previousSibling)) dom.utils.removeItem(format.previousSibling);
if (dom.check.isBreak(focusNode)) {
const zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
focusNode.parentNode.insertBefore(zeroWidth, focusNode);
focusNode = zeroWidth;
}
} catch {
this.#$.frameContext.get('_wd').execCommand('formatBlock', false, `<${formatName || this.#$.options.get('defaultLine')}>`);
this.#$.store.set('_lastSelectionNode', null);
this.#$.selection.init();
return;
}
if (format) {
if (dom.check.isBreak(format.nextSibling)) dom.utils.removeItem(format.nextSibling);
if (dom.check.isBreak(format.previousSibling)) dom.utils.removeItem(format.previousSibling);
if (dom.check.isBreak(focusNode)) {
const zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
focusNode.parentNode.insertBefore(zeroWidth, focusNode);
focusNode = zeroWidth;
}
}
this.#$.store.set('_lastSelectionNode', null);
if (startCon) {
this.#$.selection.setRange(startCon, 1, startCon, 1);
} else {
this.#$.focusManager.nativeFocus();
}
}
}