Vanessa 2025-04-26 23:57:55 +08:00
parent 4aa0724224
commit ef947c0259

View File

@ -286,6 +286,19 @@ export class Toolbar {
this.range.collapse(true); this.range.collapse(true);
} }
} }
let isEndSpan = false;
// https://github.com/siyuan-note/siyuan/issues/7200
if (this.range.endOffset === this.range.startContainer.textContent.length &&
!["DIV", "TD", "TH", "TR"].includes(this.range.endContainer.parentElement.tagName) &&
!hasNextSibling(this.range.endContainer)) {
this.range.setEndAfter(this.range.endContainer.parentElement);
isEndSpan = true;
}
if (this.range.startOffset === 0 &&
!["DIV", "TD", "TH", "TR"].includes(this.range.startContainer.parentElement.tagName) &&
!hasPreviousSibling(this.range.startContainer)) {
this.range.setStartBefore(this.range.startContainer.parentElement);
}
if (!html) { if (!html) {
this.range.insertNode(document.createElement("wbr")); this.range.insertNode(document.createElement("wbr"));
html = nodeElement.outerHTML; html = nodeElement.outerHTML;
@ -299,7 +312,7 @@ export class Toolbar {
}); });
if (this.range.startContainer.nodeType !== 3) { if (this.range.startContainer.nodeType !== 3) {
let emptyNode: Element = this.range.startContainer.childNodes[this.range.startOffset] as HTMLElement; let emptyNode: Element = this.range.startContainer.childNodes[this.range.startOffset] as HTMLElement;
if (emptyNode.nodeType === 3) { if (emptyNode && emptyNode.nodeType === 3) {
if ((this.range.startContainer as HTMLElement).tagName === "DIV") { if ((this.range.startContainer as HTMLElement).tagName === "DIV") {
emptyNode = emptyNode.previousSibling as HTMLElement; emptyNode = emptyNode.previousSibling as HTMLElement;
} else { } else {
@ -327,7 +340,11 @@ export class Toolbar {
const toolbarElement = isMobile() ? document.querySelector("#keyboardToolbar .keyboard__dynamic").nextElementSibling : this.element; const toolbarElement = isMobile() ? document.querySelector("#keyboardToolbar .keyboard__dynamic").nextElementSibling : this.element;
const actionBtn = action === "toolbar" ? toolbarElement.querySelector(`[data-type="${type}"]`) : undefined; const actionBtn = action === "toolbar" ? toolbarElement.querySelector(`[data-type="${type}"]`) : undefined;
const newNodes: Node[] = []; const newNodes: Node[] = [];
let keepZWPS = false;
let startContainer: Node;
let endContainer: Node;
let startOffset: number;
let endOffset: number;
if (type === "clear" || actionBtn?.classList.contains("protyle-toolbar__item--current") || ( if (type === "clear" || actionBtn?.classList.contains("protyle-toolbar__item--current") || (
action === "range" && rangeTypes.length > 0 && rangeTypes.includes(type) && !textObj action === "range" && rangeTypes.length > 0 && rangeTypes.includes(type) && !textObj
)) { )) {
@ -346,11 +363,10 @@ export class Toolbar {
return true; return true;
} }
}); });
// TODO
if (rangeTypes.length === 0 || type === "clear") { if (rangeTypes.length === 0 || type === "clear") {
newNodes.push(document.createTextNode(Constants.ZWSP)); newNodes.push(document.createTextNode(Constants.ZWSP));
startContainer = newNodes[0];
} else { } else {
// 遇到以下类型结尾不应继承 https://github.com/siyuan-note/siyuan/issues/7200
let removeIndex = 0; let removeIndex = 0;
while (removeIndex < rangeTypes.length) { while (removeIndex < rangeTypes.length) {
if (["inline-memo", "text", "block-ref", "virtual-block-ref", "file-annotation-ref", "a"].includes(rangeTypes[removeIndex])) { if (["inline-memo", "text", "block-ref", "virtual-block-ref", "file-annotation-ref", "a"].includes(rangeTypes[removeIndex])) {
@ -363,14 +379,13 @@ export class Toolbar {
inlineElement.setAttribute("data-type", rangeTypes.join(" ")); inlineElement.setAttribute("data-type", rangeTypes.join(" "));
inlineElement.textContent = Constants.ZWSP; inlineElement.textContent = Constants.ZWSP;
newNodes.push(inlineElement); newNodes.push(inlineElement);
startContainer = newNodes[0].firstChild;
} }
keepZWPS = true;
startOffset = 1;
} }
contents.childNodes.forEach((item: HTMLElement) => { contents.childNodes.forEach((item: HTMLElement) => {
if (item.nodeType !== 3 && item.tagName !== "BR" && item.tagName !== "IMG" && !item.classList.contains("img")) { if (item.nodeType !== 3 && item.tagName !== "BR" && item.tagName !== "IMG" && !item.classList.contains("img")) {
// TODO 图片后有粗体仅选中图片后rang 中会包含一个空的粗体,需移除
if (item.textContent === "") {
return;
}
const types = (item.getAttribute("data-type") || "").split(" "); const types = (item.getAttribute("data-type") || "").split(" ");
if (type === "clear") { if (type === "clear") {
for (let i = 0; i < types.length; i++) { for (let i = 0; i < types.length; i++) {
@ -395,19 +410,8 @@ export class Toolbar {
}); });
} }
if (types.length === 0) { if (types.length === 0) {
if (item.textContent === "") {
item.textContent = Constants.ZWSP;
}
newNodes.push(document.createTextNode(item.textContent)); newNodes.push(document.createTextNode(item.textContent));
} else { } else {
if (selectText && type === "clear" && textObj && textObj.type === "text") {
// 选中内容中没有样式需要清除时直接返回,否则清除粗体中部分内容会报错
if (item.style.color === "" && item.style.webkitTextFillColor === "" && item.style.webkitTextStroke === "" && item.style.textShadow === "" && item.style.backgroundColor === "" && item.style.fontSize === "") {
item.setAttribute("data-type", types.join(" "));
newNodes.push(item);
return true;
}
}
if (type === "clear") { if (type === "clear") {
item.style.color = ""; item.style.color = "";
item.style.webkitTextFillColor = ""; item.style.webkitTextFillColor = "";
@ -433,24 +437,25 @@ export class Toolbar {
rangeTypes.push(type); rangeTypes.push(type);
// 遇到以下类型结尾不应继承 https://github.com/siyuan-note/siyuan/issues/7200 // 遇到以下类型结尾不应继承 https://github.com/siyuan-note/siyuan/issues/7200
// if (isEndSpan) { if (isEndSpan) {
// let removeIndex = 0; let removeIndex = 0;
// while (removeIndex < rangeTypes.length) { while (removeIndex < rangeTypes.length) {
// if (["inline-memo", "text", "block-ref", "virtual-block-ref", "file-annotation-ref", "a"].includes(rangeTypes[removeIndex])) { if (["inline-memo", "text", "block-ref", "virtual-block-ref", "file-annotation-ref", "a"].includes(rangeTypes[removeIndex])) {
// rangeTypes.splice(removeIndex, 1); rangeTypes.splice(removeIndex, 1);
// } else { } else {
// ++removeIndex; ++removeIndex;
// } }
// } }
// // https://github.com/siyuan-note/siyuan/issues/14421 // https://github.com/siyuan-note/siyuan/issues/14421
// if (rangeTypes.length === 0) { if (rangeTypes.length === 0) {
// rangeTypes.push(type); rangeTypes.push(type);
// } }
// } }
inlineElement.setAttribute("data-type", [...new Set(rangeTypes)].join(" ")); inlineElement.setAttribute("data-type", [...new Set(rangeTypes)].join(" "));
inlineElement.textContent = Constants.ZWSP; inlineElement.textContent = Constants.ZWSP;
setFontStyle(inlineElement, textObj); setFontStyle(inlineElement, textObj);
newNodes.push(inlineElement); newNodes.push(inlineElement);
keepZWPS = true;
} else { } else {
// https://github.com/siyuan-note/siyuan/issues/7477 // https://github.com/siyuan-note/siyuan/issues/7477
// https://github.com/siyuan-note/siyuan/issues/8825 // https://github.com/siyuan-note/siyuan/issues/8825
@ -459,7 +464,7 @@ export class Toolbar {
contents.childNodes[0].remove(); contents.childNodes[0].remove();
} }
} }
contents.childNodes.forEach((item: HTMLElement, index) => { contents.childNodes.forEach((item: HTMLElement) => {
let removeText = ""; let removeText = "";
if (item.nodeType === 3) { if (item.nodeType === 3) {
if ( if (
@ -598,137 +603,145 @@ export class Toolbar {
for (let i = newNodes.length - 1; i > -1; i--) { for (let i = newNodes.length - 1; i > -1; i--) {
this.range.insertNode(newNodes[i]); this.range.insertNode(newNodes[i]);
} }
let startContainer;
let startOffset; if (!keepZWPS) {
let endOffset; // 合并元素
// 合并元素 for (let i = 0; i <= newNodes.length; i++) {
for (let i = 0; i <= newNodes.length; i++) { let previousElement = i === newNodes.length ? newNodes[i - 1] as HTMLElement : hasPreviousSibling(newNodes[i]) as HTMLElement;
let previousElement = i === newNodes.length ? newNodes[i - 1] as HTMLElement : hasPreviousSibling(newNodes[i]) as HTMLElement; if (previousElement.nodeType === 3 && previousElement.textContent === Constants.ZWSP) {
if (previousElement.nodeType === 3 && previousElement.textContent === Constants.ZWSP) { previousElement = hasPreviousSibling(previousElement) as HTMLElement;
previousElement = hasPreviousSibling(previousElement) as HTMLElement; previousElement.nextSibling.remove();
previousElement.nextSibling.remove(); }
} let currentNode = newNodes[i] as HTMLElement;
let currentNode = newNodes[i] as HTMLElement; if (!currentNode) {
if (!currentNode) { currentNode = hasNextSibling(newNodes[i - 1]) as HTMLElement;
currentNode = hasNextSibling(newNodes[i - 1]) as HTMLElement; if (currentNode.nodeType === 3 && currentNode.textContent === Constants.ZWSP) {
if (currentNode.nodeType === 3 && currentNode.textContent === Constants.ZWSP) { currentNode = hasNextSibling(currentNode) as HTMLElement;
currentNode = hasNextSibling(currentNode) as HTMLElement; currentNode.previousSibling.remove();
currentNode.previousSibling.remove(); }
}
if (currentNode && currentNode.nodeType !== 3) {
const currentType = (currentNode.getAttribute("data-type") || "").split(" ");
if (currentNode.tagName !== "BR" &&
previousElement && previousElement.nodeType !== 3 &&
currentNode.nodeType !== 3 &&
isArrayEqual(currentType, (previousElement.getAttribute("data-type") || "").split(" ")) &&
hasSameTextStyle(currentNode, previousElement, textObj)) {
if (currentType.includes("code") || currentType.includes("tag") || currentType.includes("kbd")) {
if (currentNode.textContent.startsWith(Constants.ZWSP)) {
currentNode.textContent = currentNode.textContent.substring(1);
}
}
if (currentType.includes("inline-math")) {
// 数学公式合并 data-content https://github.com/siyuan-note/siyuan/issues/6028
currentNode.setAttribute("data-content", previousElement.getAttribute("data-content") + currentNode.getAttribute("data-content"));
} else if (currentType.includes("block-ref") && previousElement.getAttribute("data-id") === currentNode.getAttribute("data-id")) {
if (previousElement.dataset.subtype !== "d" || previousElement.dataset.subtype !== "d") {
currentNode.setAttribute("data-subtype", "s");
currentNode.textContent = previousElement.textContent + currentNode.textContent;
}
} else {
// 测试不存在 https://ld246.com/article/1664454663564 情况,故移除引用合并限制
// 搜索结果引用被高亮隔断需进行合并 https://github.com/siyuan-note/siyuan/issues/7588
currentNode.textContent = previousElement.textContent + currentNode.textContent;
// 如果为备注时,合并备注内容
if (currentType.includes("inline-memo")) {
currentNode.setAttribute("data-inline-memo-content", (previousElement.getAttribute("data-inline-memo-content") || "") +
(currentNode.getAttribute("data-inline-memo-content") || ""));
}
}
if (!currentType.includes("inline-math")) {
if (i === 0) {
startContainer = currentNode;
startOffset = previousElement.textContent.length;
} else if (i === newNodes.length) {
endContainer = currentNode;
endOffset = previousElement.textContent.length;
if (startContainer.isSameNode(previousElement)) {
startContainer = currentNode;
}
}
}
previousElement.remove();
if (i > 0) {
newNodes.splice(i - 1, 1);
i--;
}
if (newNodes.length === 0) {
newNodes.push(currentNode);
break;
}
}
} }
} }
if (currentNode && currentNode.nodeType !== 3) { // 整理 zwsp
const currentType = (currentNode.getAttribute("data-type") || "").split(" "); for (let i = 0; i <= newNodes.length; i++) {
if (currentNode.tagName !== "BR" && const previousElement = i === newNodes.length ? newNodes[i - 1] as HTMLElement : hasPreviousSibling(newNodes[i]) as HTMLElement;
previousElement && previousElement.nodeType !== 3 && let currentNode = newNodes[i] as HTMLElement;
currentNode.nodeType !== 3 && if (!currentNode) {
isArrayEqual(currentType, (previousElement.getAttribute("data-type") || "").split(" ")) && currentNode = hasNextSibling(newNodes[i - 1]) as HTMLElement;
hasSameTextStyle(currentNode, previousElement, textObj)) { }
if (currentType.includes("code") || currentType.includes("tag") || currentType.includes("kbd")) { if (!currentNode) {
break;
}
if (currentNode.nodeType === 3) {
if (previousElement && previousElement.nodeType === 3) {
if (currentNode.textContent.startsWith(Constants.ZWSP)) { if (currentNode.textContent.startsWith(Constants.ZWSP)) {
currentNode.textContent = currentNode.textContent.substring(1); currentNode.textContent = currentNode.textContent.substring(1);
} }
} if (previousElement.textContent.endsWith(Constants.ZWSP)) {
if (currentType.includes("inline-math")) { previousElement.textContent = previousElement.textContent.substring(0, previousElement.textContent.length - 2);
// 数学公式合并 data-content https://github.com/siyuan-note/siyuan/issues/6028
currentNode.setAttribute("data-content", previousElement.getAttribute("data-content") + currentNode.getAttribute("data-content"));
} else if (currentType.includes("block-ref") && previousElement.getAttribute("data-id") === currentNode.getAttribute("data-id")) {
if (previousElement.dataset.subtype !== "d" || previousElement.dataset.subtype !== "d") {
currentNode.setAttribute("data-subtype", "s");
currentNode.textContent = previousElement.textContent + currentNode.textContent;
} }
} else { } else {
// 测试不存在 https://ld246.com/article/1664454663564 情况,故移除引用合并限制 const previousType = previousElement ? (previousElement.getAttribute("data-type") || "").split(" ") : [];
// 搜索结果引用被高亮隔断需进行合并 https://github.com/siyuan-note/siyuan/issues/7588 if (previousType.includes("code") || previousType.includes("tag") || previousType.includes("kbd")) {
currentNode.textContent = previousElement.textContent + currentNode.textContent; if (!currentNode.textContent.startsWith(Constants.ZWSP)) {
// 如果为备注时,合并备注内容 currentNode.textContent = Constants.ZWSP + currentNode.textContent;
if (currentType.includes("inline-memo")) { }
currentNode.setAttribute("data-inline-memo-content", (previousElement.getAttribute("data-inline-memo-content") || "") + } else if (currentNode.textContent.startsWith(Constants.ZWSP)) {
(currentNode.getAttribute("data-inline-memo-content") || "")); currentNode.textContent = currentNode.textContent.substring(1);
} }
} }
startContainer = currentNode;
if (currentType.includes("inline-math")) {
startOffset = null;
} else {
if (i === newNodes.length) {
endOffset = previousElement.textContent.length;
} else {
startOffset = previousElement.textContent.length;
}
}
previousElement.remove();
if (i > 0) {
newNodes.splice(i - 1, 1);
i--;
}
if (newNodes.length === 0) {
newNodes.push(currentNode);
break;
}
}
}
}
// 整理 zwsp
for (let i = 0; i <= newNodes.length; i++) {
const previousElement = i === newNodes.length ? newNodes[i - 1] as HTMLElement : hasPreviousSibling(newNodes[i]) as HTMLElement;
let currentNode = newNodes[i] as HTMLElement;
if (!currentNode) {
currentNode = hasNextSibling(newNodes[i - 1]) as HTMLElement;
}
if (currentNode.nodeType === 3) {
if (previousElement && previousElement.nodeType === 3) {
if (currentNode.textContent.startsWith(Constants.ZWSP)) {
currentNode.textContent = currentNode.textContent.substring(1);
}
if (previousElement.textContent.endsWith(Constants.ZWSP)) {
previousElement.textContent = previousElement.textContent.substring(0, previousElement.textContent.length - 2);
}
} else { } else {
const previousType = previousElement ? (previousElement.getAttribute("data-type") || "").split(" ") : []; const currentType = currentNode.nodeType === 3 ? [] : (currentNode.getAttribute("data-type") || "").split(" ");
if (previousType.includes("code") || previousType.includes("tag") || previousType.includes("kbd")) { if (currentType.includes("code") || currentType.includes("tag") || currentType.includes("kbd")) {
if (!currentNode.textContent.startsWith(Constants.ZWSP)) { if (!currentNode.textContent.startsWith(Constants.ZWSP)) {
currentNode.textContent = Constants.ZWSP + currentNode.textContent; currentNode.insertAdjacentText("afterbegin", Constants.ZWSP);
}
if (!previousElement || (previousElement.nodeType === 3 && previousElement.textContent.endsWith("\n"))) {
currentNode.insertAdjacentText("beforebegin", Constants.ZWSP);
} }
} else if (currentNode.textContent.startsWith(Constants.ZWSP)) { } else if (currentNode.textContent.startsWith(Constants.ZWSP)) {
currentNode.textContent = currentNode.textContent.substring(1); currentNode.textContent = currentNode.textContent.substring(1);
} }
} if (previousElement && previousElement.nodeType !== 3) {
} else { const previousType = (previousElement.getAttribute("data-type") || "").split(" ");
const currentType = (currentNode.getAttribute("data-type") || "").split(" "); if (previousType.includes("code") || previousType.includes("tag") || previousType.includes("kbd")) {
if (currentType.includes("code") || currentType.includes("tag") || currentType.includes("kbd")) { currentNode.insertAdjacentText("beforebegin", Constants.ZWSP);
if (!currentNode.textContent.startsWith(Constants.ZWSP)) { }
currentNode.insertAdjacentText("afterbegin", Constants.ZWSP);
}
if (!previousElement || (previousElement.nodeType === 3 && previousElement.textContent.endsWith("\n"))) {
currentNode.insertAdjacentText("beforebegin", Constants.ZWSP);
}
} else if (currentNode.textContent.startsWith(Constants.ZWSP)) {
currentNode.textContent = currentNode.textContent.substring(1);
}
if (previousElement && previousElement.nodeType !== 3) {
const previousType = (previousElement.getAttribute("data-type") || "").split(" ");
if (previousType.includes("code") || previousType.includes("tag") || previousType.includes("kbd")) {
currentNode.insertAdjacentText("beforebegin", Constants.ZWSP);
} }
} }
} }
} }
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss")); nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html); updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
nodeElement.querySelectorAll("wbr").forEach(item => { nodeElement.querySelectorAll("wbr").forEach(item => {
item.remove(); item.remove();
}); });
if (startContainer) { if (startContainer && typeof startOffset === "number") {
if (typeof startOffset === "number") { if (startContainer.nodeType === 3) {
this.range.setStart(startContainer.firstChild, startOffset); this.range.setStart(startContainer, startOffset);
} else { } else {
this.range.selectNode(startContainer); this.range.setStart(startContainer.firstChild, startOffset);
} }
} }
if (typeof endOffset === "number") { if (endContainer && typeof endOffset === "number") {
this.range.setEnd(startContainer.firstChild, endOffset); if (endContainer.nodeType === 3) {
this.range.setEnd(endContainer, endOffset);
} else {
this.range.setEnd(endContainer.firstChild, endOffset);
}
} }
focusByRange(this.range); focusByRange(this.range);