mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Squire: improved handling of BR elements
This commit is contained in:
parent
f43c2c92b5
commit
584728bc89
2 changed files with 191 additions and 255 deletions
|
|
@ -56,10 +56,11 @@
|
||||||
.squire-wysiwyg {
|
.squire-wysiwyg {
|
||||||
font-family: var(--fontSans);
|
font-family: var(--fontSans);
|
||||||
|
|
||||||
/* Prevent collapse of empty elements so that the caret can be placed in there */
|
/* Prevent collapse of empty elements so that the caret can be placed in there
|
||||||
*:empty::before {
|
*:empty::before {
|
||||||
content: "\200B";
|
content: "\200B";
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
padding-left: 40px;
|
padding-left: 40px;
|
||||||
|
|
|
||||||
443
vendors/squire2/dist/squire-raw.js
vendored
443
vendors/squire2/dist/squire-raw.js
vendored
|
|
@ -349,203 +349,6 @@
|
||||||
return range;
|
return range;
|
||||||
};
|
};
|
||||||
|
|
||||||
// source/node/MergeSplit.ts
|
|
||||||
var fixCursor = (node) => {
|
|
||||||
let fixer = null;
|
|
||||||
if (node instanceof Text) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
if (isInline(node)) {
|
|
||||||
let child = node.firstChild;
|
|
||||||
if (cantFocusEmptyTextNodes) {
|
|
||||||
while (child && child instanceof Text && !child.data) {
|
|
||||||
node.removeChild(child);
|
|
||||||
child = node.firstChild;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!child) {
|
|
||||||
if (cantFocusEmptyTextNodes) {
|
|
||||||
fixer = document.createTextNode(ZWS);
|
|
||||||
} else {
|
|
||||||
fixer = document.createTextNode("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ((node instanceof Element || node instanceof DocumentFragment) && !node.querySelector("BR")) {
|
|
||||||
fixer = createElement("BR");
|
|
||||||
let parent = node;
|
|
||||||
let child;
|
|
||||||
while ((child = parent.lastElementChild) && !isInline(child)) {
|
|
||||||
parent = child;
|
|
||||||
}
|
|
||||||
node = parent;
|
|
||||||
}
|
|
||||||
if (fixer) {
|
|
||||||
try {
|
|
||||||
node.appendChild(fixer);
|
|
||||||
} catch (error) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
};
|
|
||||||
var fixContainer = (container, root) => {
|
|
||||||
let wrapper = null;
|
|
||||||
[...container.childNodes].forEach((child) => {
|
|
||||||
const isBR = child.nodeName === "BR";
|
|
||||||
if (!isBR && child.parentNode == root && isInline(child)) {
|
|
||||||
wrapper || (wrapper = createElement("DIV"));
|
|
||||||
wrapper.append(child);
|
|
||||||
} else if (isBR || wrapper) {
|
|
||||||
wrapper || (wrapper = createElement("DIV"));
|
|
||||||
fixCursor(wrapper);
|
|
||||||
if (isBR) {
|
|
||||||
child.replaceWith(wrapper);
|
|
||||||
} else {
|
|
||||||
container.insertBefore(wrapper, child);
|
|
||||||
}
|
|
||||||
wrapper = null;
|
|
||||||
}
|
|
||||||
isContainer(child) && fixContainer(child, root);
|
|
||||||
});
|
|
||||||
wrapper && container.append(fixCursor(wrapper));
|
|
||||||
return container;
|
|
||||||
};
|
|
||||||
var split = (node, offset, stopNode, root) => {
|
|
||||||
if (node instanceof Text && node !== stopNode) {
|
|
||||||
if (typeof offset !== "number") {
|
|
||||||
throw new Error("Offset must be a number to split text node!");
|
|
||||||
}
|
|
||||||
if (!node.parentNode) {
|
|
||||||
throw new Error("Cannot split text node with no parent!");
|
|
||||||
}
|
|
||||||
return split(node.parentNode, node.splitText(offset), stopNode, root);
|
|
||||||
}
|
|
||||||
let nodeAfterSplit = typeof offset === "number" ? offset < node.childNodes.length ? node.childNodes[offset] : null : offset;
|
|
||||||
const parent = node.parentNode;
|
|
||||||
if (!parent || node === stopNode || !(node instanceof Element)) {
|
|
||||||
return nodeAfterSplit;
|
|
||||||
}
|
|
||||||
const clone = node.cloneNode(false);
|
|
||||||
while (nodeAfterSplit) {
|
|
||||||
const next = nodeAfterSplit.nextSibling;
|
|
||||||
clone.append(nodeAfterSplit);
|
|
||||||
nodeAfterSplit = next;
|
|
||||||
}
|
|
||||||
if (node instanceof HTMLOListElement && getClosest(node, root, "BLOCKQUOTE")) {
|
|
||||||
clone.start = (+node.start || 1) + node.childNodes.length - 1;
|
|
||||||
}
|
|
||||||
fixCursor(node);
|
|
||||||
fixCursor(clone);
|
|
||||||
node.after(clone);
|
|
||||||
return split(parent, clone, stopNode, root);
|
|
||||||
};
|
|
||||||
var _mergeInlines = (node, fakeRange) => {
|
|
||||||
const children = node.childNodes;
|
|
||||||
let l = children.length;
|
|
||||||
const frags = [];
|
|
||||||
while (l--) {
|
|
||||||
const child = children[l];
|
|
||||||
const prev = l ? children[l - 1] : null;
|
|
||||||
if (prev && isInline(child) && areAlike(child, prev)) {
|
|
||||||
if (fakeRange.startContainer === child) {
|
|
||||||
fakeRange.startContainer = prev;
|
|
||||||
fakeRange.startOffset += getLength(prev);
|
|
||||||
}
|
|
||||||
if (fakeRange.endContainer === child) {
|
|
||||||
fakeRange.endContainer = prev;
|
|
||||||
fakeRange.endOffset += getLength(prev);
|
|
||||||
}
|
|
||||||
if (fakeRange.startContainer === node) {
|
|
||||||
if (fakeRange.startOffset > l) {
|
|
||||||
--fakeRange.startOffset;
|
|
||||||
} else if (fakeRange.startOffset === l) {
|
|
||||||
fakeRange.startContainer = prev;
|
|
||||||
fakeRange.startOffset = getLength(prev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fakeRange.endContainer === node) {
|
|
||||||
if (fakeRange.endOffset > l) {
|
|
||||||
--fakeRange.endOffset;
|
|
||||||
} else if (fakeRange.endOffset === l) {
|
|
||||||
fakeRange.endContainer = prev;
|
|
||||||
fakeRange.endOffset = getLength(prev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
detach(child);
|
|
||||||
if (child instanceof Text) {
|
|
||||||
prev.appendData(child.data);
|
|
||||||
} else {
|
|
||||||
frags.push(empty(child));
|
|
||||||
}
|
|
||||||
} else if (child instanceof Element) {
|
|
||||||
let frag;
|
|
||||||
while (frag = frags.pop()) {
|
|
||||||
child.append(frag);
|
|
||||||
}
|
|
||||||
_mergeInlines(child, fakeRange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var mergeInlines = (node, range) => {
|
|
||||||
const element = node instanceof Text ? node.parentNode : node;
|
|
||||||
if (element instanceof Element) {
|
|
||||||
const fakeRange = {
|
|
||||||
startContainer: range.startContainer,
|
|
||||||
startOffset: range.startOffset,
|
|
||||||
endContainer: range.endContainer,
|
|
||||||
endOffset: range.endOffset
|
|
||||||
};
|
|
||||||
_mergeInlines(element, fakeRange);
|
|
||||||
range.setStart(fakeRange.startContainer, fakeRange.startOffset);
|
|
||||||
range.setEnd(fakeRange.endContainer, fakeRange.endOffset);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var mergeWithBlock = (block, next, range, root) => {
|
|
||||||
let container = next;
|
|
||||||
let parent;
|
|
||||||
let offset;
|
|
||||||
while ((parent = container.parentNode) && parent !== root && parent instanceof Element && parent.childNodes.length === 1) {
|
|
||||||
container = parent;
|
|
||||||
}
|
|
||||||
detach(container);
|
|
||||||
offset = block.childNodes.length;
|
|
||||||
const last = block.lastChild;
|
|
||||||
if (last && last.nodeName === "BR") {
|
|
||||||
last.remove();
|
|
||||||
--offset;
|
|
||||||
}
|
|
||||||
block.append(empty(next));
|
|
||||||
range.setStart(block, offset);
|
|
||||||
range.collapse(true);
|
|
||||||
mergeInlines(block, range);
|
|
||||||
};
|
|
||||||
var mergeContainers = (node, root) => {
|
|
||||||
const prev = node.previousSibling;
|
|
||||||
const first = node.firstChild;
|
|
||||||
const isListItem = node.nodeName === "LI";
|
|
||||||
if (isListItem && (!first || !/^[OU]L$/.test(first.nodeName))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (prev && areAlike(prev, node)) {
|
|
||||||
if (!isContainer(prev)) {
|
|
||||||
if (!isListItem) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const block = createElement("DIV");
|
|
||||||
block.append(empty(prev));
|
|
||||||
prev.append(block);
|
|
||||||
}
|
|
||||||
detach(node);
|
|
||||||
const needsFix = !isContainer(node);
|
|
||||||
prev.append(empty(node));
|
|
||||||
needsFix && fixContainer(prev, root);
|
|
||||||
first && mergeContainers(first, root);
|
|
||||||
} else if (isListItem) {
|
|
||||||
const block = createElement("DIV");
|
|
||||||
node.insertBefore(block, first);
|
|
||||||
fixCursor(block);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// source/Clean.ts
|
// source/Clean.ts
|
||||||
var styleToSemantic = {
|
var styleToSemantic = {
|
||||||
"font-weight": {
|
"font-weight": {
|
||||||
|
|
@ -731,23 +534,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var cleanupBRs = (node, root, keepForBlankLine) => {
|
var cleanupBRs = (node) => {
|
||||||
const brs = node.querySelectorAll("BR");
|
const brs = node.querySelectorAll("BR");
|
||||||
const brBreaksLine = [];
|
const brBreaksLine = [];
|
||||||
let l = brs.length;
|
let l = brs.length;
|
||||||
for (let i = 0; i < l; ++i) {
|
for (let i = 0; i < l; ++i) {
|
||||||
brBreaksLine[i] = isLineBreak(brs[i], keepForBlankLine);
|
brBreaksLine[i] = isLineBreak(brs[i], false);
|
||||||
}
|
}
|
||||||
while (l--) {
|
while (l--) {
|
||||||
const br = brs[l];
|
const br = brs[l];
|
||||||
const parent = br.parentNode;
|
const parent = br.parentNode;
|
||||||
if (!parent) {
|
if (parent) {
|
||||||
continue;
|
if (!brBreaksLine[l]) {
|
||||||
}
|
detach(br);
|
||||||
if (!brBreaksLine[l]) {
|
}
|
||||||
detach(br);
|
|
||||||
} else if (!isInline(parent)) {
|
|
||||||
fixContainer(parent, root);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -755,6 +555,164 @@
|
||||||
return text.split("&").join("&").split("<").join("<").split(">").join(">").split('"').join(""");
|
return text.split("&").join("&").split("<").join("<").split(">").join(">").split('"').join(""");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// source/node/MergeSplit.ts
|
||||||
|
var fixCursor = (node) => {
|
||||||
|
if ((node instanceof Element || node instanceof DocumentFragment) && !isInline(node) && !node.children.length && !node.textContent.length) {
|
||||||
|
node.appendChild(createElement("BR"));
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
};
|
||||||
|
var fixContainer = (container) => {
|
||||||
|
let wrapper = null;
|
||||||
|
[...container.childNodes].forEach((child) => {
|
||||||
|
if (isInline(child)) {
|
||||||
|
wrapper || (wrapper = createElement("DIV"));
|
||||||
|
wrapper.append(child);
|
||||||
|
} else if (wrapper) {
|
||||||
|
(wrapper.children.length || wrapper.textContent.trim().length) && container.insertBefore(wrapper, child);
|
||||||
|
wrapper = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
wrapper && container.append(wrapper);
|
||||||
|
return container;
|
||||||
|
};
|
||||||
|
var split = (node, offset, stopNode, root) => {
|
||||||
|
if (node instanceof Text && node !== stopNode) {
|
||||||
|
if (typeof offset !== "number") {
|
||||||
|
throw new Error("Offset must be a number to split text node!");
|
||||||
|
}
|
||||||
|
if (!node.parentNode) {
|
||||||
|
throw new Error("Cannot split text node with no parent!");
|
||||||
|
}
|
||||||
|
return split(node.parentNode, node.splitText(offset), stopNode, root);
|
||||||
|
}
|
||||||
|
let nodeAfterSplit = typeof offset === "number" ? offset < node.childNodes.length ? node.childNodes[offset] : null : offset;
|
||||||
|
const parent = node.parentNode;
|
||||||
|
if (!parent || node === stopNode || !(node instanceof Element)) {
|
||||||
|
return nodeAfterSplit;
|
||||||
|
}
|
||||||
|
const clone = node.cloneNode(false);
|
||||||
|
while (nodeAfterSplit) {
|
||||||
|
const next = nodeAfterSplit.nextSibling;
|
||||||
|
clone.append(nodeAfterSplit);
|
||||||
|
nodeAfterSplit = next;
|
||||||
|
}
|
||||||
|
if (node instanceof HTMLOListElement && getClosest(node, root, "BLOCKQUOTE")) {
|
||||||
|
clone.start = (+node.start || 1) + node.childNodes.length - 1;
|
||||||
|
}
|
||||||
|
fixCursor(node);
|
||||||
|
fixCursor(clone);
|
||||||
|
node.after(clone);
|
||||||
|
return split(parent, clone, stopNode, root);
|
||||||
|
};
|
||||||
|
var _mergeInlines = (node, fakeRange) => {
|
||||||
|
const children = node.childNodes;
|
||||||
|
let l = children.length;
|
||||||
|
const frags = [];
|
||||||
|
while (l--) {
|
||||||
|
const child = children[l];
|
||||||
|
const prev = l ? children[l - 1] : null;
|
||||||
|
if (prev && isInline(child) && areAlike(child, prev)) {
|
||||||
|
if (fakeRange.startContainer === child) {
|
||||||
|
fakeRange.startContainer = prev;
|
||||||
|
fakeRange.startOffset += getLength(prev);
|
||||||
|
}
|
||||||
|
if (fakeRange.endContainer === child) {
|
||||||
|
fakeRange.endContainer = prev;
|
||||||
|
fakeRange.endOffset += getLength(prev);
|
||||||
|
}
|
||||||
|
if (fakeRange.startContainer === node) {
|
||||||
|
if (fakeRange.startOffset > l) {
|
||||||
|
--fakeRange.startOffset;
|
||||||
|
} else if (fakeRange.startOffset === l) {
|
||||||
|
fakeRange.startContainer = prev;
|
||||||
|
fakeRange.startOffset = getLength(prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fakeRange.endContainer === node) {
|
||||||
|
if (fakeRange.endOffset > l) {
|
||||||
|
--fakeRange.endOffset;
|
||||||
|
} else if (fakeRange.endOffset === l) {
|
||||||
|
fakeRange.endContainer = prev;
|
||||||
|
fakeRange.endOffset = getLength(prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
detach(child);
|
||||||
|
if (child instanceof Text) {
|
||||||
|
prev.appendData(child.data);
|
||||||
|
} else {
|
||||||
|
frags.push(empty(child));
|
||||||
|
}
|
||||||
|
} else if (child instanceof Element) {
|
||||||
|
let frag;
|
||||||
|
while (frag = frags.pop()) {
|
||||||
|
child.append(frag);
|
||||||
|
}
|
||||||
|
_mergeInlines(child, fakeRange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var mergeInlines = (node, range) => {
|
||||||
|
const element = node instanceof Text ? node.parentNode : node;
|
||||||
|
if (element instanceof Element) {
|
||||||
|
const fakeRange = {
|
||||||
|
startContainer: range.startContainer,
|
||||||
|
startOffset: range.startOffset,
|
||||||
|
endContainer: range.endContainer,
|
||||||
|
endOffset: range.endOffset
|
||||||
|
};
|
||||||
|
_mergeInlines(element, fakeRange);
|
||||||
|
range.setStart(fakeRange.startContainer, fakeRange.startOffset);
|
||||||
|
range.setEnd(fakeRange.endContainer, fakeRange.endOffset);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var mergeWithBlock = (block, next, range, root) => {
|
||||||
|
let container = next;
|
||||||
|
let parent;
|
||||||
|
let offset;
|
||||||
|
while ((parent = container.parentNode) && parent !== root && parent instanceof Element && parent.childNodes.length === 1) {
|
||||||
|
container = parent;
|
||||||
|
}
|
||||||
|
detach(container);
|
||||||
|
offset = block.childNodes.length;
|
||||||
|
const last = block.lastChild;
|
||||||
|
if (last && last.nodeName === "BR") {
|
||||||
|
last.remove();
|
||||||
|
--offset;
|
||||||
|
}
|
||||||
|
block.append(empty(next));
|
||||||
|
range.setStart(block, offset);
|
||||||
|
range.collapse(true);
|
||||||
|
mergeInlines(block, range);
|
||||||
|
};
|
||||||
|
var mergeContainers = (node, root) => {
|
||||||
|
const prev = node.previousSibling;
|
||||||
|
const first = node.firstChild;
|
||||||
|
const isListItem = node.nodeName === "LI";
|
||||||
|
if (isListItem && (!first || !/^[OU]L$/.test(first.nodeName))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (prev && areAlike(prev, node)) {
|
||||||
|
if (!isContainer(prev)) {
|
||||||
|
if (!isListItem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const block = createElement("DIV");
|
||||||
|
block.append(empty(prev));
|
||||||
|
prev.append(block);
|
||||||
|
}
|
||||||
|
detach(node);
|
||||||
|
const needsFix = !isContainer(node);
|
||||||
|
prev.append(empty(node));
|
||||||
|
needsFix && fixContainer(prev);
|
||||||
|
first && mergeContainers(first, root);
|
||||||
|
} else if (isListItem) {
|
||||||
|
const block = createElement("DIV");
|
||||||
|
node.insertBefore(block, first);
|
||||||
|
fixCursor(block);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// source/node/Block.ts
|
// source/node/Block.ts
|
||||||
var getBlockWalker = (node, root) => {
|
var getBlockWalker = (node, root) => {
|
||||||
const walker = createTreeWalker(root, SHOW_ELEMENT, isBlock);
|
const walker = createTreeWalker(root, SHOW_ELEMENT, isBlock);
|
||||||
|
|
@ -1059,7 +1017,7 @@
|
||||||
var insertTreeFragmentIntoRange = (range, frag, root) => {
|
var insertTreeFragmentIntoRange = (range, frag, root) => {
|
||||||
const firstInFragIsInline = frag.firstChild && isInline(frag.firstChild);
|
const firstInFragIsInline = frag.firstChild && isInline(frag.firstChild);
|
||||||
let node;
|
let node;
|
||||||
fixContainer(frag, root);
|
fixContainer(frag);
|
||||||
node = frag;
|
node = frag;
|
||||||
while (node = getNextBlock(node, root)) {
|
while (node = getNextBlock(node, root)) {
|
||||||
fixCursor(node);
|
fixCursor(node);
|
||||||
|
|
@ -1080,7 +1038,7 @@
|
||||||
range.collapse(true);
|
range.collapse(true);
|
||||||
let container = range.endContainer;
|
let container = range.endContainer;
|
||||||
let offset = range.endOffset;
|
let offset = range.endOffset;
|
||||||
cleanupBRs(block, root, false);
|
cleanupBRs(block);
|
||||||
if (isInline(container)) {
|
if (isInline(container)) {
|
||||||
const nodeAfterSplit = split(
|
const nodeAfterSplit = split(
|
||||||
container,
|
container,
|
||||||
|
|
@ -1480,7 +1438,7 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let current = startBlock;
|
let current = startBlock;
|
||||||
fixContainer(current.parentNode, root);
|
fixContainer(current.parentNode);
|
||||||
const previous = getPreviousBlock(current, root);
|
const previous = getPreviousBlock(current, root);
|
||||||
if (previous) {
|
if (previous) {
|
||||||
if (!previous.isContentEditable) {
|
if (!previous.isContentEditable) {
|
||||||
|
|
@ -1547,7 +1505,7 @@
|
||||||
if (!current) {
|
if (!current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fixContainer(current.parentNode, root);
|
fixContainer(current.parentNode);
|
||||||
next = getNextBlock(current, root);
|
next = getNextBlock(current, root);
|
||||||
if (next) {
|
if (next) {
|
||||||
if (!next.isContentEditable) {
|
if (!next.isContentEditable) {
|
||||||
|
|
@ -1945,8 +1903,6 @@
|
||||||
_makeConfig(userConfig) {
|
_makeConfig(userConfig) {
|
||||||
const config = {
|
const config = {
|
||||||
blockTag: "DIV",
|
blockTag: "DIV",
|
||||||
blockAttributes: null,
|
|
||||||
tagAttributes: {},
|
|
||||||
classNames: {
|
classNames: {
|
||||||
color: "color",
|
color: "color",
|
||||||
fontFamily: "font",
|
fontFamily: "font",
|
||||||
|
|
@ -2549,8 +2505,8 @@
|
||||||
const frag = this._config.sanitizeToDOMFragment(html, this);
|
const frag = this._config.sanitizeToDOMFragment(html, this);
|
||||||
const root = this._root;
|
const root = this._root;
|
||||||
cleanTree(frag, this._config);
|
cleanTree(frag, this._config);
|
||||||
cleanupBRs(frag, root, false);
|
cleanupBRs(frag);
|
||||||
fixContainer(frag, root);
|
fixContainer(frag);
|
||||||
let node = frag;
|
let node = frag;
|
||||||
let child = node.firstChild;
|
let child = node.firstChild;
|
||||||
if (!child || child.nodeName === "BR") {
|
if (!child || child.nodeName === "BR") {
|
||||||
|
|
@ -2596,7 +2552,7 @@
|
||||||
this.addDetectedLinks(frag, frag);
|
this.addDetectedLinks(frag, frag);
|
||||||
}
|
}
|
||||||
cleanTree(frag, this._config);
|
cleanTree(frag, this._config);
|
||||||
cleanupBRs(frag, root, false);
|
cleanupBRs(frag);
|
||||||
removeEmptyInlines(frag);
|
removeEmptyInlines(frag);
|
||||||
frag.normalize();
|
frag.normalize();
|
||||||
let node = frag;
|
let node = frag;
|
||||||
|
|
@ -2728,13 +2684,8 @@
|
||||||
const lines = plainText.split("\n");
|
const lines = plainText.split("\n");
|
||||||
const config = this._config;
|
const config = this._config;
|
||||||
const tag = config.blockTag;
|
const tag = config.blockTag;
|
||||||
const attributes = config.blockAttributes;
|
|
||||||
const closeBlock = "</" + tag + ">";
|
const closeBlock = "</" + tag + ">";
|
||||||
let openBlock = "<" + tag;
|
const openBlock = "<" + tag + ">";
|
||||||
for (const attr in attributes) {
|
|
||||||
openBlock += " " + attr + '="' + escapeHTML(attributes[attr]) + '"';
|
|
||||||
}
|
|
||||||
openBlock += ">";
|
|
||||||
for (let i = 0, l = lines.length; i < l; ++i) {
|
for (let i = 0, l = lines.length; i < l; ++i) {
|
||||||
let line = lines[i];
|
let line = lines[i];
|
||||||
line = escapeHTML(line).replace(/ (?=(?: |$))/g, " ");
|
line = escapeHTML(line).replace(/ (?=(?: |$))/g, " ");
|
||||||
|
|
@ -3034,7 +2985,6 @@
|
||||||
{
|
{
|
||||||
href: url
|
href: url
|
||||||
},
|
},
|
||||||
this._config.tagAttributes.a,
|
|
||||||
attributes
|
attributes
|
||||||
);
|
);
|
||||||
return this.changeFormat(
|
return this.changeFormat(
|
||||||
|
|
@ -3065,7 +3015,6 @@
|
||||||
(node2) => !getClosest(node2, root || this._root, "A")
|
(node2) => !getClosest(node2, root || this._root, "A")
|
||||||
);
|
);
|
||||||
const linkRegExp = this.linkRegExp;
|
const linkRegExp = this.linkRegExp;
|
||||||
const defaultAttributes = this._config.tagAttributes.a;
|
|
||||||
let node;
|
let node;
|
||||||
while (node = walker.nextNode()) {
|
while (node = walker.nextNode()) {
|
||||||
const parent = node.parentNode;
|
const parent = node.parentNode;
|
||||||
|
|
@ -3082,12 +3031,9 @@
|
||||||
}
|
}
|
||||||
const child = createElement(
|
const child = createElement(
|
||||||
"A",
|
"A",
|
||||||
Object.assign(
|
{
|
||||||
{
|
href: match[1] ? /^(?:ht|f)tps?:/i.test(match[1]) ? match[1] : "http://" + match[1] : "mailto:" + match[0]
|
||||||
href: match[1] ? /^(?:ht|f)tps?:/i.test(match[1]) ? match[1] : "http://" + match[1] : "mailto:" + match[0]
|
}
|
||||||
},
|
|
||||||
defaultAttributes
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
child.textContent = data.slice(index, endIndex);
|
child.textContent = data.slice(index, endIndex);
|
||||||
parent.insertBefore(child, node);
|
parent.insertBefore(child, node);
|
||||||
|
|
@ -3107,7 +3053,7 @@
|
||||||
createDefaultBlock(children) {
|
createDefaultBlock(children) {
|
||||||
const config = this._config;
|
const config = this._config;
|
||||||
return fixCursor(
|
return fixCursor(
|
||||||
createElement(config.blockTag, config.blockAttributes, children)
|
createElement(config.blockTag, null, children)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
splitBlock(lineBreakOnly, range) {
|
splitBlock(lineBreakOnly, range) {
|
||||||
|
|
@ -3197,21 +3143,15 @@
|
||||||
}
|
}
|
||||||
node = range.startContainer;
|
node = range.startContainer;
|
||||||
const offset = range.startOffset;
|
const offset = range.startOffset;
|
||||||
let splitTag = this.tagAfterSplit[block.nodeName];
|
let splitTag = this.tagAfterSplit[block.nodeName] || this._config.blockTag;
|
||||||
nodeAfterSplit = split(
|
nodeAfterSplit = split(
|
||||||
node,
|
node,
|
||||||
offset,
|
offset,
|
||||||
block.parentNode,
|
block.parentNode,
|
||||||
this._root
|
this._root
|
||||||
);
|
);
|
||||||
const config = this._config;
|
if (!hasTagAttributes(nodeAfterSplit, splitTag)) {
|
||||||
let splitProperties = null;
|
block = createElement(splitTag);
|
||||||
if (!splitTag) {
|
|
||||||
splitTag = config.blockTag;
|
|
||||||
splitProperties = config.blockAttributes;
|
|
||||||
}
|
|
||||||
if (!hasTagAttributes(nodeAfterSplit, splitTag, splitProperties)) {
|
|
||||||
block = createElement(splitTag, splitProperties);
|
|
||||||
if (nodeAfterSplit.dir) {
|
if (nodeAfterSplit.dir) {
|
||||||
block.dir = nodeAfterSplit.dir;
|
block.dir = nodeAfterSplit.dir;
|
||||||
}
|
}
|
||||||
|
|
@ -3376,11 +3316,9 @@
|
||||||
this._recordUndoState(range, this._isInUndoState);
|
this._recordUndoState(range, this._isInUndoState);
|
||||||
const type = list.nodeName;
|
const type = list.nodeName;
|
||||||
let newParent = startLi.previousSibling;
|
let newParent = startLi.previousSibling;
|
||||||
let listAttrs;
|
|
||||||
let next;
|
let next;
|
||||||
if (newParent.nodeName !== type) {
|
if (newParent.nodeName !== type) {
|
||||||
listAttrs = this._config.tagAttributes[type.toLowerCase()];
|
newParent = createElement(type);
|
||||||
newParent = createElement(type, listAttrs);
|
|
||||||
list.insertBefore(newParent, startLi);
|
list.insertBefore(newParent, startLi);
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
|
@ -3450,9 +3388,6 @@
|
||||||
}
|
}
|
||||||
_makeList(frag, type) {
|
_makeList(frag, type) {
|
||||||
const walker = getBlockWalker(frag, this._root);
|
const walker = getBlockWalker(frag, this._root);
|
||||||
const tagAttributes = this._config.tagAttributes;
|
|
||||||
const listAttrs = tagAttributes[type.toLowerCase()];
|
|
||||||
const listItemAttrs = tagAttributes.li;
|
|
||||||
let node;
|
let node;
|
||||||
while (node = walker.nextNode()) {
|
while (node = walker.nextNode()) {
|
||||||
if (node.parentNode instanceof HTMLLIElement) {
|
if (node.parentNode instanceof HTMLLIElement) {
|
||||||
|
|
@ -3460,7 +3395,7 @@
|
||||||
walker.currentNode = node.lastChild;
|
walker.currentNode = node.lastChild;
|
||||||
}
|
}
|
||||||
if (!(node instanceof HTMLLIElement)) {
|
if (!(node instanceof HTMLLIElement)) {
|
||||||
const newLi = createElement("LI", listItemAttrs);
|
const newLi = createElement("LI");
|
||||||
if (node.dir) {
|
if (node.dir) {
|
||||||
newLi.dir = node.dir;
|
newLi.dir = node.dir;
|
||||||
}
|
}
|
||||||
|
|
@ -3469,7 +3404,7 @@
|
||||||
prev.append(newLi);
|
prev.append(newLi);
|
||||||
detach(node);
|
detach(node);
|
||||||
} else {
|
} else {
|
||||||
replaceWith(node, createElement(type, listAttrs, [newLi]));
|
replaceWith(node, createElement(type, null, [newLi]));
|
||||||
}
|
}
|
||||||
newLi.append(empty(node));
|
newLi.append(empty(node));
|
||||||
walker.currentNode = newLi;
|
walker.currentNode = newLi;
|
||||||
|
|
@ -3479,7 +3414,7 @@
|
||||||
if (tag !== type && /^[OU]L$/.test(tag)) {
|
if (tag !== type && /^[OU]L$/.test(tag)) {
|
||||||
replaceWith(
|
replaceWith(
|
||||||
node,
|
node,
|
||||||
createElement(type, listAttrs, [empty(node)])
|
createElement(type, null, [empty(node)])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3502,7 +3437,7 @@
|
||||||
for (let i = 0, l = lists.length; i < l; ++i) {
|
for (let i = 0, l = lists.length; i < l; ++i) {
|
||||||
const list = lists[i];
|
const list = lists[i];
|
||||||
const listFrag = empty(list);
|
const listFrag = empty(list);
|
||||||
fixContainer(listFrag, root);
|
fixContainer(listFrag);
|
||||||
replaceWith(list, listFrag);
|
replaceWith(list, listFrag);
|
||||||
}
|
}
|
||||||
for (let i = 0, l = items.length; i < l; ++i) {
|
for (let i = 0, l = items.length; i < l; ++i) {
|
||||||
|
|
@ -3510,7 +3445,7 @@
|
||||||
if (isBlock(item)) {
|
if (isBlock(item)) {
|
||||||
replaceWith(item, this.createDefaultBlock([empty(item)]));
|
replaceWith(item, this.createDefaultBlock([empty(item)]));
|
||||||
} else {
|
} else {
|
||||||
fixContainer(item, root);
|
fixContainer(item);
|
||||||
replaceWith(item, empty(item));
|
replaceWith(item, empty(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3523,7 +3458,7 @@
|
||||||
this.modifyBlocks(
|
this.modifyBlocks(
|
||||||
(frag) => createElement(
|
(frag) => createElement(
|
||||||
"BLOCKQUOTE",
|
"BLOCKQUOTE",
|
||||||
this._config.tagAttributes.blockquote,
|
null,
|
||||||
[frag]
|
[frag]
|
||||||
),
|
),
|
||||||
range
|
range
|
||||||
|
|
@ -3608,7 +3543,7 @@
|
||||||
}
|
}
|
||||||
output.normalize();
|
output.normalize();
|
||||||
return fixCursor(
|
return fixCursor(
|
||||||
createElement("PRE", this._config.tagAttributes.pre, [
|
createElement("PRE", null, [
|
||||||
output
|
output
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
@ -3618,7 +3553,7 @@
|
||||||
this.changeFormat(
|
this.changeFormat(
|
||||||
{
|
{
|
||||||
tag: "CODE",
|
tag: "CODE",
|
||||||
attributes: this._config.tagAttributes.code
|
attributes: null
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
range
|
range
|
||||||
|
|
@ -3654,7 +3589,7 @@
|
||||||
node.parentNode.insertBefore(contents, node);
|
node.parentNode.insertBefore(contents, node);
|
||||||
node.data = value;
|
node.data = value;
|
||||||
}
|
}
|
||||||
fixContainer(pre, root);
|
fixContainer(pre);
|
||||||
replaceWith(pre, empty(pre));
|
replaceWith(pre, empty(pre));
|
||||||
}
|
}
|
||||||
return frag;
|
return frag;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue