From d21b7e754f5339772cd30b7c40b8e8870a3408cb Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Mon, 25 Dec 2023 16:07:42 +0100 Subject: [PATCH] Cleanup, fix and improve some Squire handling --- vendors/squire/build/squire-raw.js | 254 +++++++++++++++++------------ 1 file changed, 149 insertions(+), 105 deletions(-) diff --git a/vendors/squire/build/squire-raw.js b/vendors/squire/build/squire-raw.js index 4c292d658..ea61b690f 100644 --- a/vendors/squire/build/squire-raw.js +++ b/vendors/squire/build/squire-raw.js @@ -414,10 +414,10 @@ const if (isTextNode(child)) { prev.appendData(child.data); } else { - frags.push(empty(child)); + frags.unshift(empty(child)); } } else if (isElement(child)) { - child.append(...frags.reverse()); + child.append(...frags); frags = []; _mergeInlines(child, fakeRange); } @@ -458,9 +458,9 @@ const mergeInlines(block, range); }, mergeContainers = (node, root) => { - const prev = node.previousSibling, - first = node.firstChild, - isListItem = node.nodeName === "LI"; + const prev = node.previousSibling; + const first = node.firstChild; + const isListItem = node.nodeName === "LI"; // Do not merge LIs, unless it only contains a UL if (isListItem && (!first || !listNodeNames.has(first.nodeName))) { return; @@ -579,11 +579,11 @@ const STRIKE: replaceWithTag("S"), SPAN: replaceStyles, FONT: node => { - let face = node.face, - size = node.size, - color = node.color, - newTag = createElement("SPAN"), - css = newTag.style; + const face = node.face; + const size = node.size; + let color = node.color; + let newTag = createElement("SPAN"); + let css = newTag.style; newTag.style.cssText = node.style.cssText; if (face) { css.fontFamily = face; @@ -592,8 +592,8 @@ const css.fontSize = fontSizes[size]; } if (color && /^#?([\dA-F]{3}){1,2}$/i.test(color)) { - if (color.charAt(0) !== '#') { - color = '#' + color; + if (color.charAt(0) !== "#") { + color = "#" + color; } css.color = color; } @@ -624,15 +624,15 @@ const 2. Convert inline tags into our preferred format. */ cleanTree = (node, preserveWS) => { - let children = node.childNodes, - nonInlineParent, i = children.length, child, nodeName, childLength; + const children = node.childNodes; + let nonInlineParent, i = children.length, child, nodeName, childLength; // startsWithWS, endsWithWS, data, sibling; nonInlineParent = node; while (isInline(nonInlineParent)) { nonInlineParent = nonInlineParent.parentNode; } -// let walker = createTreeWalker(nonInlineParent, SHOW_ELEMENT_OR_TEXT); +// const walker = createTreeWalker(nonInlineParent, SHOW_ELEMENT_OR_TEXT); while (i--) { child = children[i]; @@ -836,8 +836,8 @@ const } }, rangeDoesEndAtBlockBoundary = (range, root) => { - const endContainer = range.endContainer, - endOffset = range.endOffset; + const endContainer = range.endContainer; + const endOffset = range.endOffset; let currentNode; // If in a text node with content, and not at the end, we're not at the boundary if (isTextNode(endContainer)) { @@ -860,9 +860,9 @@ const } }, expandRangeToBlockBoundaries = (range, root) => { - const start = getStartBlockOfRange(range, root), - end = getEndBlockOfRange(range, root); - + const start = getStartBlockOfRange(range, root); + const end = getEndBlockOfRange(range, root); +// let parent; if (start && end) { range.setStart(start, 0); range.setEnd(end, end.childNodes.length); @@ -1509,13 +1509,8 @@ const // If at very beginning of text area, allow backspace // to break lists/blockquote. else if (current) { - let parent = getClosest(current, root, 'UL,OL,BLOCKQUOTE'); - if (parent) { - return ("BLOCKQUOTE" === parent.nodeName) - // Break blockquote - ? self.decreaseQuoteLevel(range) - // Break list - : self.decreaseListLevel(range); + if (decreaseLevel(self, range, current)) { + return; } self.setRange(range); } @@ -1527,22 +1522,26 @@ const setTimeout(() => afterDelete(self), 0); } }, + // source/keyboard/Delete.ts Delete = (self, event, range) => { const root = self._root; - let current, next, originalRange, - cursorContainer, cursorOffset, nodeAfterCursor; + let current; + let next; + let originalRange; + let cursorContainer; + let cursorOffset; + let nodeAfterCursor; self._removeZWS(); // Record undo checkpoint. self.saveUndoState(range); - // If not collapsed, delete contents if (!range.collapsed) { + // If not collapsed, delete contents event.preventDefault(); deleteContentsOfRange(range, root); afterDelete(self, range); - } - // If at end of block, merge next into this block - else if (rangeDoesEndAtBlockBoundary(range, root)) { + } else if (rangeDoesEndAtBlockBoundary(range, root)) { + // If at end of block, merge next into this block event.preventDefault(); if (current = getStartBlockOfRange(range, root)) { // In case inline data has somehow got between blocks. @@ -1569,10 +1568,9 @@ const self.setRange(range); } } - } - // Otherwise, leave to browser but check afterwards whether it has - // left behind an empty inline tag. - else { + } else { + // Otherwise, leave to browser but check afterwards whether it has + // left behind an empty inline tag. // But first check if the cursor is just before an IMG tag. If so, // delete it ourselves, because the browser won't if it is not // inline. @@ -1594,6 +1592,107 @@ const setTimeout(() => afterDelete(self), 0); } }, + + // source/keyboard/Tab.ts + Tab = (self, event, range) => { + self._removeZWS(); + // If no selection and at start of block + if (range.collapsed && rangeDoesStartAtBlockBoundary(range, self._root)) { + getClosest(range.startContainer, self._root, "UL,OL,BLOCKQUOTE") + && self.changeIndentationLevel('increase') + && event.preventDefault(); + } + }, + ShiftTab = (self, event, range) => { + self._removeZWS(); + // If no selection and at start of block + if (range.collapsed && rangeDoesStartAtBlockBoundary(range, self._root)) { + // Break list + decreaseLevel(self, range, range.startContainer) + && event.preventDefault(); + } + }, + + // source/keyboard/Space.ts + Space = (self, event, range) => { +/* + var _a; + let node; + const root = self._root; + self._recordUndoState(range); + self._getRangeAndRemoveBookmark(range); + if (!range.collapsed) { + deleteContentsOfRange(range, root); + self._ensureBottomLine(); + self.setSelection(range); + self._updatePath(range, true); + } else if (rangeDoesEndAtBlockBoundary(range, root)) { + const block = getStartBlockOfRange(range, root); + if (block && block.nodeName !== "PRE") { + const text = (_a = block.textContent) == null ? void 0 : _a.trimEnd().replace(ZWS, ""); + if (text === "*" || text === "1.") { + event.preventDefault(); + const walker = new TreeIterator(block, SHOW_TEXT); + let textNode; + while (textNode = walker.nextNode()) { + textNode.data = cantFocusEmptyTextNodes ? ZWS : ""; + } + if (text === "*") { + self.makeUnorderedList(); + } else { + self.makeOrderedList(); + } + return; + } + } + } + node = range.endContainer; + if (range.endOffset === getLength(node)) { + do { + if (node.nodeName === "A") { + range.setStartAfter(node); + break; + } + } while (!node.nextSibling && (node = node.parentNode) && node !== root); + } + if (self._config.addLinks) { + const linkRange = range.cloneRange(); + moveRangeBoundariesDownTree(linkRange); + const textNode = linkRange.startContainer; + const offset = linkRange.startOffset; + setTimeout(() => { + linkifyText(self, textNode, offset); + }, 0); + } + self.setSelection(range); +*/ + const root = self._root; + self._recordUndoState(range); + self._config.addLinks && addLinks(range.startContainer, root); + self._getRangeAndRemoveBookmark(range); +/* + // If the cursor is at the end of a link (foo|) then move it + // outside of the link (foo|) so that the space is not part of + // the link text. + // SnappyMail: disabled as it fails in Firefox + let node = range.endContainer; + if (range.collapsed && range.endOffset === getLength(node)) { + do { + if (node.nodeName === "A") { + range.setStartAfter(node); + break; + } + } while (!node.nextSibling && (node = node.parentNode) && node !== root); + } +*/ + // Delete the selection if not collapsed + if (!range.collapsed) { + deleteContentsOfRange(range, root); + self._ensureBottomLine(); + } + self.setRange(range); + }, + // source/keyboard/KeyHandlers.ts onKey = function(event) { if (event.defaultPrevented) { @@ -1650,67 +1749,9 @@ const keyHandlers = { // "backspace": Backspace, // "delete": Delete, - tab: (self, event, range) => { - let root = self._root; - let node, parent; - self._removeZWS(); - // If no selection and at start of block - if (range.collapsed && rangeDoesStartAtBlockBoundary(range, root)) { - node = getStartBlockOfRange(range, root); - // Iterate through the block's parents - while (parent = node.parentNode) { - // If we find a UL or OL (so are in a list, node must be an LI) - if (parent.nodeName === "UL" || parent.nodeName === "OL") { - // Then increase the list level - event.preventDefault(); - self.increaseListLevel(range); - break; - } - node = parent; - } - } - }, - 'shift-tab': (self, event, range) => { - let root = self._root; - let node; - self._removeZWS(); - // If no selection and at start of block - if (range.collapsed && rangeDoesStartAtBlockBoundary(range, root)) { - // Break list - node = range.startContainer; - if (getClosest(node, root, 'UL,OL')) { - event.preventDefault(); - self.decreaseListLevel(range); - } - } - }, - space: (self, _, range) => { - let root = self._root; - self._recordUndoState(range); - self._config.addLinks && addLinks(range.startContainer, root); - self._getRangeAndRemoveBookmark(range); - /* - // If the cursor is at the end of a link (foo|) then move it - // outside of the link (foo|) so that the space is not part of - // the link text. - // SnappyMail: disabled as it fails in Firefox - let node = range.endContainer; - if (range.collapsed && range.endOffset === getLength(node)) { - do { - if (node.nodeName === "A") { - range.setStartAfter(node); - break; - } - } while (!node.nextSibling && (node = node.parentNode) && node !== root); - } - */ - // Delete the selection if not collapsed - if (!range.collapsed) { - deleteContentsOfRange(range, root); - self._ensureBottomLine(); - } - self.setRange(range); - }, + tab: Tab, + 'shift-tab': ShiftTab, + space: Space, arrowleft: self => self._removeZWS(), arrowright: self => self._removeZWS() }, @@ -1973,6 +2014,9 @@ const return frag; }, + decreaseLevel = (self, range, node) => + getClosest(node, self._root, 'UL,OL,BLOCKQUOTE') && self.changeIndentationLevel('decrease'), + linkRegExp = /\b(?:((https?:\/\/)?(?:www\d{0,3}\.|[a-z0-9][a-z0-9.-]*\.[a-z]{2,}\/)(?:[^\s()<>]+|\([^\s()<>]+\))+(?:[^\s?&`!()[\]{};:'".,<>«»“”‘’]|\([^\s()<>]+\)))|([\w\-.%+]+@(?:[\w-]+\.)+[a-z]{2,}\b(?:\?[^&?\s]+=[^\s?&`!()[\]{};:'".,<>«»“”‘’]+(?:&[^&?\s]+=[^\s?&`!()[\]{};:'".,<>«»“”‘’]+)*)?))/i, addLinks = (frag, root) => { @@ -2397,7 +2441,7 @@ class Squire } _saveRangeToBookmark(range) { - let [startNode, endNode] = createBookmarkNodes(this), + let [startNode, endNode] = createBookmarkNodes(), temp; insertNodeInRange(range, startNode); @@ -3213,7 +3257,7 @@ class Squire // TODO: why was _docWasChanged() not triggered? this.editStack.inUndoState && this._docWasChanged(); this._recordUndoState(range); -// self._config.addLinks && addLinks(range.startContainer, root); +// this._config.addLinks && addLinks(range.startContainer, root); this._removeZWS(); this._getRangeAndRemoveBookmark(range); @@ -3226,7 +3270,7 @@ class Squire // const offset2 = range.startOffset; setTimeout(() => { // linkifyText(this, textNode, offset2); - addLinks(range.startContainer, self._root); + addLinks(range.startContainer, this._root); }, 0); } block = getStartBlockOfRange(range, root); @@ -3285,12 +3329,12 @@ class Squire return; } block = getClosest(block, root, "LI") || block; - if (isEmptyBlock(block) && (parent = getClosest(block, root, 'UL,OL,BLOCKQUOTE'))) { + if (isEmptyBlock(block) && (parent = getClosest(block, root, "UL,OL,BLOCKQUOTE"))) { return "BLOCKQUOTE" === parent.nodeName // Break blockquote - ? self.modifyBlocks((/* frag */) => self.createDefaultBlock(createBookmarkNodes(self)), range) + ? this.modifyBlocks((/* frag */) => this.createDefaultBlock(createBookmarkNodes()), range) // Break list - : self.decreaseListLevel(range); + : this.decreaseListLevel(range); } node = range.startContainer; const offset = range.startOffset; @@ -3645,7 +3689,7 @@ class Squire let parent = this.getSelectionClosest('UL,OL,BLOCKQUOTE'); if (parent || "increase" === direction) { let method = (!parent || "BLOCKQUOTE" === parent.nodeName) ? "Quote" : "List"; - this[direction + method + "Level"](); + return this[direction + method + "Level"](); } }