Vanessa 2025-04-25 17:21:26 +08:00
parent a7c989f064
commit 21baed3ad4

View File

@ -240,8 +240,8 @@ export class Toolbar {
if (!nodeElement.isSameNode(endElement)) {
this.range = setLastNodeRange(getContenteditableElement(nodeElement), this.range, false);
}
const rangeTypes = this.getCurrentType(this.range);
const rangeTypes = this.getCurrentType(this.range);
if (rangeTypes.length === 1) {
// https://github.com/siyuan-note/siyuan/issues/6501
// https://github.com/siyuan-note/siyuan/issues/12877
@ -256,60 +256,72 @@ export class Toolbar {
return;
}
}
const selectText = this.range.toString();
fixTableRange(this.range);
let previousElement: HTMLElement;
let nextElement: HTMLElement;
let previousIndex: number;
let nextIndex: number;
const previousSibling = hasPreviousSibling(this.range.startContainer);
if (!["DIV", "TD", "TH", "TR"].includes(this.range.startContainer.parentElement.tagName)) {
if (this.range.startOffset === 0 && !previousSibling) {
previousElement = this.range.startContainer.parentElement.previousSibling as HTMLElement;
this.range.setStartBefore(this.range.startContainer.parentElement);
} else {
previousElement = this.range.startContainer.parentElement;
let contents;
let html;
let needWrapTarget;
if (this.range.startContainer.nodeType === 3 && this.range.startContainer.parentElement.tagName === "SPAN" &&
this.range.startContainer.isSameNode(this.range.endContainer)) {
if (this.range.startOffset > -1 && this.range.endOffset <= this.range.startContainer.textContent.length) {
needWrapTarget = this.range.startContainer.parentElement;
}
} else if (previousSibling && previousSibling.nodeType !== 3 && this.range.startOffset === 0) {
// **aaa**bbb 选中 bbb 加粗
previousElement = previousSibling as HTMLElement;
} else if (["code", "tag", "kbd"].includes(type) && previousSibling && previousSibling.nodeType === 1 &&
this.range.startOffset === 1 && this.range.startContainer.textContent.startsWith(Constants.ZWSP)) {
// 合并相同元素第二条第一个操作 https://github.com/siyuan-note/siyuan/issues/14290
previousElement = previousSibling as HTMLElement;
}
let isEndSpan = false;
const nextSibling = hasNextSibling(this.range.endContainer);
if (!["DIV", "TD", "TH", "TR"].includes(this.range.endContainer.parentElement.tagName)) {
if (this.range.endOffset === this.range.endContainer.textContent.length && !nextSibling) {
nextElement = this.range.endContainer.parentElement.nextSibling as HTMLElement;
this.range.setEndAfter(this.range.endContainer.parentElement);
if (selectText === "") {
isEndSpan = true;
this.range.collapse(false);
}
} else {
nextElement = this.range.endContainer.parentElement;
}
} else if (nextSibling && nextSibling.nodeType !== 3 && this.range.endOffset === this.range.endContainer.textContent.length) {
// aaa**bbb** 选中 aaa 加粗
nextElement = nextSibling as HTMLElement;
}
this.range.insertNode(document.createElement("wbr"));
const html = nodeElement.outerHTML;
const contents = this.range.extractContents();
this.mergeNode(contents.childNodes);
// 选择 span 中的一部分需进行包裹
if (previousElement && nextElement && previousElement.isSameNode(nextElement) && contents.firstChild?.nodeType === 3) {
const attributes = previousElement.attributes;
contents.childNodes.forEach(item => {
const spanElement = document.createElement("span");
if (this.range.startOffset !== 0 && this.range.endOffset !== this.range.startContainer.textContent.length &&
!(this.range.startOffset === 1 && this.range.startContainer.textContent.startsWith(Constants.ZWSP))) {
// 切割元素
const parentElement = this.range.startContainer.parentElement;
const afterElement = document.createElement("span");
const attributes = parentElement.attributes;
for (let i = 0; i < attributes.length; i++) {
spanElement.setAttribute(attributes[i].name, attributes[i].value);
afterElement.setAttribute(attributes[i].name, attributes[i].value);
}
this.range.insertNode(document.createElement("wbr"));
html = nodeElement.outerHTML;
contents = this.range.extractContents();
this.range.setEnd(parentElement.lastChild, parentElement.lastChild.textContent.length);
afterElement.append(this.range.extractContents());
parentElement.after(afterElement);
this.range.setStartBefore(afterElement);
this.range.collapse(true);
}
}
if (!html) {
this.range.insertNode(document.createElement("wbr"));
html = nodeElement.outerHTML;
contents = this.range.extractContents();
}
this.mergeNode(contents.childNodes);
contents.childNodes.forEach(item => {
if (item.nodeType === 3 && item.textContent === Constants.ZWSP) {
item.remove();
}
});
if (this.range.startContainer.nodeType !== 3) {
let emptyNode: Element = this.range.startContainer.childNodes[this.range.startOffset] as HTMLElement;
if (emptyNode.nodeType === 3) {
if ((this.range.startContainer as HTMLElement).tagName === "DIV") {
emptyNode = emptyNode.previousSibling as HTMLElement;
} else {
emptyNode = this.range.startContainer as HTMLElement;
}
}
if (emptyNode && emptyNode.nodeType !== 3 && emptyNode.textContent.replace(Constants.ZWSP, "") === "") {
emptyNode.remove();
}
}
// 选择 span 中的部分需进行包裹
if (needWrapTarget) {
const attributes = needWrapTarget.attributes;
contents.childNodes.forEach(item => {
if (item.nodeType === 3) {
const spanElement = document.createElement("span");
for (let i = 0; i < attributes.length; i++) {
spanElement.setAttribute(attributes[i].name, attributes[i].value);
}
spanElement.innerHTML = item.textContent;
item.replaceWith(spanElement);
}
spanElement.innerHTML = item.textContent;
item.replaceWith(spanElement);
});
}
const toolbarElement = isMobile() ? document.querySelector("#keyboardToolbar .keyboard__dynamic").nextElementSibling : this.element;
@ -334,6 +346,7 @@ export class Toolbar {
return true;
}
});
// TODO
if (rangeTypes.length === 0 || type === "clear") {
newNodes.push(document.createTextNode(Constants.ZWSP));
} else {
@ -352,9 +365,9 @@ export class Toolbar {
newNodes.push(inlineElement);
}
}
contents.childNodes.forEach((item: HTMLElement, index) => {
contents.childNodes.forEach((item: HTMLElement) => {
if (item.nodeType !== 3 && item.tagName !== "BR" && item.tagName !== "IMG" && !item.classList.contains("img")) {
// 图片后有粗体仅选中图片后rang 中会包含一个空的粗体,需移除
// TODO 图片后有粗体仅选中图片后rang 中会包含一个空的粗体,需移除
if (item.textContent === "") {
return;
}
@ -403,28 +416,8 @@ export class Toolbar {
item.style.backgroundColor = "";
item.style.fontSize = "";
}
const previousIsSame = index === 0 && previousElement && previousElement.nodeType !== 3 &&
isArrayEqual(types, (previousElement.getAttribute("data-type") || "").split(" ")) &&
hasSameTextStyle(item, previousElement, textObj);
const nextIsSame = index === contents.childNodes.length - 1 && nextElement && nextElement.nodeType !== 3 &&
isArrayEqual(types, (nextElement.getAttribute("data-type") || "").split(" ")) &&
hasSameTextStyle(item, nextElement, textObj);
if (previousIsSame) {
previousIndex = previousElement.textContent.length;
previousElement.innerHTML = previousElement.innerHTML + item.innerHTML;
if (nextIsSame) {
nextIndex = previousElement.textContent.length;
previousElement.innerHTML = previousElement.innerHTML + nextElement.innerHTML;
nextElement.remove();
nextElement = previousElement;
}
} else if (nextIsSame) {
nextIndex = item.textContent.length;
nextElement.innerHTML = item.innerHTML + nextElement.innerHTML;
} else {
item.setAttribute("data-type", types.join(" "));
newNodes.push(item);
}
item.setAttribute("data-type", types.join(" "));
newNodes.push(item);
}
} else {
newNodes.push(item);
@ -440,27 +433,22 @@ export class Toolbar {
rangeTypes.push(type);
// 遇到以下类型结尾不应继承 https://github.com/siyuan-note/siyuan/issues/7200
if (isEndSpan) {
let removeIndex = 0;
while (removeIndex < rangeTypes.length) {
if (["inline-memo", "text", "block-ref", "virtual-block-ref", "file-annotation-ref", "a"].includes(rangeTypes[removeIndex])) {
rangeTypes.splice(removeIndex, 1);
} else {
++removeIndex;
}
}
// https://github.com/siyuan-note/siyuan/issues/14421
if (rangeTypes.length === 0) {
rangeTypes.push(type);
}
}
// if (isEndSpan) {
// let removeIndex = 0;
// while (removeIndex < rangeTypes.length) {
// if (["inline-memo", "text", "block-ref", "virtual-block-ref", "file-annotation-ref", "a"].includes(rangeTypes[removeIndex])) {
// rangeTypes.splice(removeIndex, 1);
// } else {
// ++removeIndex;
// }
// }
// // https://github.com/siyuan-note/siyuan/issues/14421
// if (rangeTypes.length === 0) {
// rangeTypes.push(type);
// }
// }
inlineElement.setAttribute("data-type", [...new Set(rangeTypes)].join(" "));
inlineElement.textContent = Constants.ZWSP;
// 在 a 元素中 ctrl+m 需继承其链接,也许不需要?没有用户反馈之前先保持现状
// if (type !== "a" && rangeTypes.includes("a") && nextElement.dataset.type.split(" ").includes("a") &&
// nextElement.isSameNode(previousElement)) {
// inlineElement.setAttribute("data-href", nextElement.getAttribute("data-href"));
// }
setFontStyle(inlineElement, textObj);
newNodes.push(inlineElement);
} else {
@ -474,28 +462,18 @@ export class Toolbar {
contents.childNodes.forEach((item: HTMLElement, index) => {
let removeText = "";
if (item.nodeType === 3) {
if (index === 0 && previousElement && previousElement.nodeType !== 3 &&
type === previousElement.getAttribute("data-type") &&
hasSameTextStyle(item, previousElement, textObj)) {
previousIndex = previousElement.textContent.length;
previousElement.innerHTML = previousElement.innerHTML + item.textContent;
} else if (index === contents.childNodes.length - 1 && nextElement && nextElement.nodeType !== 3 &&
type === nextElement.getAttribute("data-type") &&
hasSameTextStyle(item, nextElement, textObj)) {
nextIndex = item.textContent.length;
nextElement.innerHTML = item.textContent + nextElement.innerHTML;
} else if (
if (
// 图片会有零宽空格,但图片不进行处理 https://github.com/siyuan-note/siyuan/issues/12840
item.textContent !== Constants.ZWSP ||
// tag 会有零宽空格 https://github.com/siyuan-note/siyuan/issues/12922
(item.textContent === Constants.ZWSP && !rangeTypes.includes("img"))) {
// ZWSP spin 后会在行内元素外 https://github.com/siyuan-note/siyuan/issues/13871
if (item.textContent.startsWith(Constants.ZWSP) &&
// https://github.com/siyuan-note/siyuan/issues/14639
item.textContent.length > 1) {
newNodes.push(document.createTextNode(Constants.ZWSP));
item.textContent = item.textContent.substring(1);
}
// TODO ZWSP spin 后会在行内元素外 https://github.com/siyuan-note/siyuan/issues/13871
// if (item.textContent.startsWith(Constants.ZWSP) &&
// // https://github.com/siyuan-note/siyuan/issues/14639
// item.textContent.length > 1) {
// newNodes.push(document.createTextNode(Constants.ZWSP));
// item.textContent = item.textContent.substring(1);
// }
if (item.textContent) {
// https://github.com/siyuan-note/siyuan/issues/14204
while (item.textContent.endsWith("\n")) {
@ -506,35 +484,11 @@ export class Toolbar {
inlineElement.setAttribute("data-type", type);
inlineElement.textContent = item.textContent;
setFontStyle(inlineElement, textObj);
// 合并相同元素 https://github.com/siyuan-note/siyuan/issues/14290
const previousIsSame = index === 0 && previousElement && previousElement.nodeType !== 3 &&
type === previousElement.getAttribute("data-type") &&
hasSameTextStyle(inlineElement, previousElement, textObj);
const nextIsSame = index === contents.childNodes.length - 1 && nextElement && nextElement.nodeType !== 3 &&
type === nextElement.getAttribute("data-type") &&
hasSameTextStyle(inlineElement, nextElement, textObj);
if (previousIsSame) {
previousIndex = previousElement.textContent.length;
previousElement.innerHTML = previousElement.innerHTML + inlineElement.innerHTML.replace(Constants.ZWSP, "");
if (nextIsSame) {
nextIndex = previousElement.textContent.length;
previousElement.innerHTML = previousElement.innerHTML + nextElement.innerHTML.replace(Constants.ZWSP, "");
const nextPrevSibling = hasPreviousSibling(nextElement);
if (nextPrevSibling && nextPrevSibling.textContent === Constants.ZWSP) {
nextPrevSibling.remove();
}
nextElement.remove();
nextElement = previousElement;
}
} else if (nextIsSame) {
nextIndex = inlineElement.textContent.length;
nextElement.innerHTML = inlineElement.innerHTML + nextElement.innerHTML.replace(Constants.ZWSP, "");
if (type === "text" && !inlineElement.getAttribute("style")) {
newNodes.push(item);
} else {
if (type === "text" && !inlineElement.getAttribute("style")) {
newNodes.push(item);
} else {
newNodes.push(inlineElement);
}
newNodes.push(inlineElement);
}
}
} else {
@ -552,11 +506,6 @@ export class Toolbar {
if (!types.includes("img")) {
types.push(type);
}
// 以下行内元素需用 ZWSP 开头 https://github.com/siyuan-note/siyuan/issues/13871
if ((types.includes("code") || types.includes("tag") || types.includes("kbd")) &&
!item.textContent.startsWith(Constants.ZWSP)) {
item.insertAdjacentText("afterbegin", Constants.ZWSP);
}
// 上标和下标不能同时存在 https://github.com/siyuan-note/insider/issues/1049
if (type === "sub" && types.includes("sup")) {
types.find((item, index) => {
@ -620,47 +569,7 @@ export class Toolbar {
});
}
types = [...new Set(types)];
if (types.includes("block-ref") && item.getAttribute("data-subtype") === "d") {
// https://github.com/siyuan-note/siyuan/issues/14299
if (previousElement && previousElement.nodeType !== 3 && previousElement.getAttribute("data-id") === item.getAttribute("data-id")) {
previousElement.setAttribute("data-subtype", "s");
item.setAttribute("data-subtype", "s");
}
if (nextElement && nextElement.nodeType !== 3 && nextElement.getAttribute("data-id") === item.getAttribute("data-id")) {
nextElement.setAttribute("data-subtype", "s");
item.setAttribute("data-subtype", "s");
}
}
let previousIsSame = false;
previousIsSame = index === 0 && previousElement && previousElement.nodeType !== 3 &&
isArrayEqual(types, (previousElement.getAttribute("data-type") || "").split(" ")) &&
hasSameTextStyle(item, previousElement, textObj);
if (index === 0 && !previousIsSame && previousElement && previousElement.nodeType === 3 && previousElement.textContent === Constants.ZWSP) {
const tempPreviousElement = previousElement.previousSibling as HTMLElement;
previousIsSame = tempPreviousElement && tempPreviousElement.nodeType !== 3 &&
isArrayEqual(types, (tempPreviousElement.getAttribute("data-type") || "").split(" ")) &&
hasSameTextStyle(item, tempPreviousElement, textObj);
if (previousIsSame) {
previousElement.remove();
previousElement = tempPreviousElement;
}
}
const nextIsSame = index === contents.childNodes.length - 1 && nextElement && nextElement.nodeType !== 3 &&
isArrayEqual(types, (nextElement.getAttribute("data-type") || "").split(" ")) &&
hasSameTextStyle(item, nextElement, textObj);
if (previousIsSame) {
previousIndex = previousElement.textContent.length;
previousElement.innerHTML = previousElement.innerHTML + item.innerHTML.replace(Constants.ZWSP, "");
if (nextIsSame) {
nextIndex = previousElement.textContent.length;
previousElement.innerHTML = previousElement.innerHTML + nextElement.innerHTML.replace(Constants.ZWSP, "");
nextElement.remove();
nextElement = previousElement;
}
} else if (nextIsSame) {
nextIndex = item.textContent.length;
nextElement.innerHTML = item.innerHTML + nextElement.innerHTML.replace(Constants.ZWSP, "");
} else if (item.tagName !== "BR" && item.tagName !== "IMG") {
if (item.tagName !== "BR" && item.tagName !== "IMG") {
item.setAttribute("data-type", types.join(" "));
setFontStyle(item, textObj);
if (types.includes("text") && !item.getAttribute("style")) {
@ -685,265 +594,161 @@ export class Toolbar {
});
}
}
// 插入元素
for (let i = newNodes.length - 1; i > -1; i--) {
this.range.insertNode(newNodes[i]);
}
let startContainer;
let startOffset;
let endOffset;
// 合并元素
for (let i = 0; i <= newNodes.length; i++) {
let previousElement = i === newNodes.length ? newNodes[i - 1] as HTMLElement : hasPreviousSibling(newNodes[i]) as HTMLElement;
if (previousElement.nodeType === 3 && previousElement.textContent === Constants.ZWSP) {
previousElement = hasPreviousSibling(previousElement) as HTMLElement;
previousElement.nextSibling.remove();
}
let currentNode = newNodes[i] as HTMLElement;
if (!currentNode) {
currentNode = hasNextSibling(newNodes[i - 1]) as HTMLElement;
if (currentNode.nodeType === 3 && currentNode.textContent === Constants.ZWSP) {
currentNode = hasNextSibling(currentNode) as HTMLElement;
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")) {
startContainer = currentNode;
startOffset = null;
} else {
if (i === newNodes.length) {
endOffset = previousElement.textContent.length;
startContainer = currentNode;
} 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 {
const previousType = previousElement ? (previousElement.getAttribute("data-type") || "").split(" ") : [];
if (previousType.includes("code") || previousType.includes("tag") || previousType.includes("kbd")) {
if (!currentNode.textContent.startsWith(Constants.ZWSP)) {
currentNode.textContent = Constants.ZWSP + currentNode.textContent;
}
} else if (currentNode.textContent.startsWith(Constants.ZWSP)) {
currentNode.textContent = currentNode.textContent.substring(1);
}
}
} else {
const currentType = (currentNode.getAttribute("data-type") || "").split(" ");
if (currentType.includes("code") || currentType.includes("tag") || currentType.includes("kbd")) {
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);
}
}
}
}
if (this.range.startContainer.nodeType !== 3 && (this.range.startContainer as HTMLElement).tagName === "SPAN" &&
this.range.startContainer.isSameNode(this.range.endContainer) && !isEndSpan) {
// 切割元素
const startContainer = this.range.startContainer as HTMLElement;
const afterElement = document.createElement("span");
const attributes = startContainer.attributes;
for (let i = 0; i < attributes.length; i++) {
afterElement.setAttribute(attributes[i].name, attributes[i].value);
}
this.range.setEnd(startContainer.lastChild, startContainer.lastChild.textContent.length);
afterElement.append(this.range.extractContents());
startContainer.after(afterElement);
// https://github.com/siyuan-note/siyuan/issues/13871#issuecomment-2662855319
const firstTypes = startContainer.getAttribute("data-type").split(" ");
if (firstTypes.includes("code") || firstTypes.includes("tag") || firstTypes.includes("kbd")) {
afterElement.insertAdjacentText("beforebegin", Constants.ZWSP + Constants.ZWSP);
afterElement.insertAdjacentText("afterbegin", Constants.ZWSP);
this.range.setStart(afterElement.previousSibling, 1);
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
nodeElement.querySelectorAll("wbr").forEach(item => {
item.remove();
});
if (startContainer) {
if (typeof startOffset === "number") {
this.range.setStart(startContainer.firstChild, startOffset);
} else {
this.range.setStartBefore(afterElement);
}
this.range.collapse(true);
}
for (let i = 0; i < newNodes.length; i++) {
const currentNewNode = newNodes[i] as HTMLElement;
const nextNewNode = newNodes[i + 1] as HTMLElement;
const currentType = currentNewNode.nodeType !== 3 ? (currentNewNode.getAttribute("data-type") || "") : "";
if (currentNewNode.nodeType !== 3 && nextNewNode && nextNewNode.nodeType !== 3 &&
nextNewNode.tagName === currentNewNode.tagName &&
// 表格内多个换行 https://github.com/siyuan-note/siyuan/issues/12300
currentNewNode.tagName !== "BR" &&
isArrayEqual((nextNewNode.getAttribute("data-type") || "").split(" "), currentType.split(" ")) &&
currentNewNode.getAttribute("data-id") === nextNewNode.getAttribute("data-id") &&
currentNewNode.getAttribute("data-subtype") === nextNewNode.getAttribute("data-subtype") &&
currentNewNode.style.color === nextNewNode.style.color &&
currentNewNode.style.webkitTextFillColor === nextNewNode.style.webkitTextFillColor &&
currentNewNode.style.webkitTextStroke === nextNewNode.style.webkitTextStroke &&
currentNewNode.style.textShadow === nextNewNode.style.textShadow &&
currentNewNode.style.fontSize === nextNewNode.style.fontSize &&
currentNewNode.style.backgroundColor === nextNewNode.style.backgroundColor) {
// 合并相同的 node
if (currentType.indexOf("inline-math") > -1) {
// 数学公式合并 data-content https://github.com/siyuan-note/siyuan/issues/6028
nextNewNode.setAttribute("data-content", currentNewNode.getAttribute("data-content") + nextNewNode.getAttribute("data-content"));
} else {
// 测试不存在 https://ld246.com/article/1664454663564 情况,故移除引用合并限制
// 搜索结果引用被高亮隔断需进行合并 https://github.com/siyuan-note/siyuan/issues/7588
nextNewNode.innerHTML = currentNewNode.innerHTML + nextNewNode.innerHTML;
// 如果为备注时,合并备注内容
if (currentType.indexOf("inline-memo") > -1) {
nextNewNode.setAttribute("data-inline-memo-content", (currentNewNode.getAttribute("data-inline-memo-content") || "") +
(nextNewNode.getAttribute("data-inline-memo-content") || ""));
}
}
newNodes.splice(i, 1);
i--;
} else {
this.range.insertNode(currentNewNode);
if (currentNewNode.nodeType === 1 && ["code", "tag", "kbd"].includes(type)) {
// 添加为 span https://github.com/siyuan-note/siyuan/issues/6155
const currentPreviousSibling = hasPreviousSibling(currentNewNode);
if (!currentPreviousSibling || currentPreviousSibling.textContent.endsWith("\n")) {
currentNewNode.before(document.createTextNode(Constants.ZWSP));
}
if (!currentNewNode.textContent.startsWith(Constants.ZWSP)) {
currentNewNode.textContent = Constants.ZWSP + currentNewNode.textContent;
}
const currentNextSibling = hasNextSibling(currentNewNode);
if (!currentNextSibling ||
(currentNextSibling && (
currentNextSibling.nodeType !== 3 ||
(currentNextSibling.nodeType === 3 && !currentNextSibling.textContent.startsWith(Constants.ZWSP)))
)
) {
currentNewNode.after(document.createTextNode(Constants.ZWSP));
}
} else if (currentNewNode.nodeType === 3 && ["code", "tag", "kbd", "clear"].includes(type)) {
let currentPreviousSibling = hasPreviousSibling(currentNewNode) as HTMLElement;
let previousIsCTK = false;
let currentPreviousSiblingTypes: string[];
if (currentPreviousSibling) {
if (currentPreviousSibling.nodeType === 1) {
currentPreviousSiblingTypes = currentPreviousSibling.dataset.type.split(" ");
if (currentPreviousSiblingTypes.includes("code") || currentPreviousSiblingTypes.includes("tag") || currentPreviousSiblingTypes.includes("kbd")) {
previousIsCTK = true;
}
} else if (currentPreviousSibling.textContent.endsWith(Constants.ZWSP)) {
currentPreviousSibling.textContent = currentPreviousSibling.textContent.substring(0, currentPreviousSibling.textContent.length - 1);
}
}
let currentNextSibling = hasNextSibling(currentNewNode) as HTMLElement;
let nextIsCTK = false;
let currentNextSiblingTypes: string[];
if (currentNextSibling) {
if (currentNextSibling.nodeType === 1) {
currentNextSiblingTypes = currentNextSibling.dataset.type.split(" ");
if (currentNextSiblingTypes.includes("code") || currentNextSiblingTypes.includes("tag") || currentNextSiblingTypes.includes("kbd")) {
nextIsCTK = true;
}
} else if (currentNextSibling.textContent.startsWith(Constants.ZWSP) &&
(!previousIsCTK || previousIsCTK && currentPreviousSibling.textContent === Constants.ZWSP)) {
currentNextSibling.textContent = currentNextSibling.textContent.substring(1);
}
}
if (currentNewNode) {
if (previousIsCTK) {
if (!currentNewNode.textContent.startsWith(Constants.ZWSP)) {
currentNewNode.textContent = Constants.ZWSP + currentNewNode.textContent;
} else if (nextIsCTK && isArrayEqual(currentNextSiblingTypes, currentPreviousSiblingTypes) &&
hasSameTextStyle(currentNextSibling, currentPreviousSibling, textObj)) {
// 行内元素设置第一条第二个操作 https://github.com/siyuan-note/siyuan/issues/14290
newNodes.splice(i, 1);
i--;
currentNewNode.remove();
previousIndex = currentPreviousSibling.innerHTML.length;
nextElement = previousElement;
nextIndex = currentPreviousSibling.innerHTML.length + nextIndex;
currentPreviousSibling.innerHTML = currentPreviousSibling.innerHTML + currentNextSibling.innerHTML.replace(Constants.ZWSP, "");
currentNextSibling.remove();
}
} else if (currentNewNode.textContent.startsWith(Constants.ZWSP)) {
currentPreviousSibling = hasPreviousSibling(currentNewNode) as HTMLElement;
if (currentPreviousSibling.nodeType === 1) {
const currentPreviousSiblingTypes = currentPreviousSibling.dataset.type.split(" ");
if (!currentPreviousSiblingTypes.includes("code") && !currentPreviousSiblingTypes.includes("tag") && !currentPreviousSiblingTypes.includes("kbd")) {
currentNewNode.textContent = currentNewNode.textContent.substring(1);
}
} else {
currentNewNode.textContent = currentNewNode.textContent.substring(1);
}
}
if (nextIsCTK) {
if (!currentNextSibling.textContent.startsWith(Constants.ZWSP)) {
currentNextSibling.textContent = Constants.ZWSP + currentNextSibling.textContent;
}
} else if (currentNewNode.textContent.endsWith(Constants.ZWSP)) {
currentNextSibling = hasNextSibling(currentNewNode) as HTMLElement;
if (currentNextSibling.nodeType === 1) {
const currentNextSiblingTypes = currentNextSibling.dataset.type.split(" ");
if (!currentNextSiblingTypes.includes("code") && !currentNextSiblingTypes.includes("tag") && !currentNextSiblingTypes.includes("kbd")) {
currentNewNode.textContent = currentNewNode.textContent.substring(0, currentNewNode.textContent.length - 1);
}
} else {
currentNewNode.textContent = currentNewNode.textContent.substring(0, currentNewNode.textContent.length - 1);
}
}
}
}
this.range.collapse(false);
this.range.selectNode(startContainer);
}
}
if (previousElement) {
if (previousElement.nodeType !== 3 && previousElement.textContent === Constants.ZWSP) {
// https://github.com/siyuan-note/siyuan/issues/7548
previousElement.remove();
} else {
this.mergeNode(previousElement.childNodes);
}
if (typeof endOffset === "number") {
this.range.setEnd(startContainer.firstChild, endOffset);
}
if (nextElement) {
this.mergeNode(nextElement.childNodes);
}
if (typeof previousIndex === "number") {
this.range.setStart(previousElement.firstChild, previousIndex);
} else if (newNodes.length > 0) {
if (newNodes[0].nodeType !== 3 && (newNodes[0] as HTMLElement).getAttribute("data-type") === "inline-math") {
// 数学公式后面处理
} else {
if (newNodes[0].firstChild) {
if (newNodes[0].firstChild.textContent === Constants.ZWSP) {
// 新建元素时光标消失 https://github.com/siyuan-note/siyuan/issues/6481
// 新建元素粘贴后元素消失 https://ld246.com/article/1665556907936
this.range.setStart(newNodes[0].firstChild, 1);
} else {
this.range.setStart(newNodes[0].firstChild, 0);
}
} else if (newNodes[0].nodeType === 3) {
this.range.setStart(newNodes[0], 0);
} else {
this.range.setStartBefore(newNodes[0]);
}
}
} else if (nextElement) {
// aaa**bbb** 选中 aaa 加粗
this.range.setStart(nextElement.firstChild, 0);
}
if (typeof nextIndex === "number") {
this.range.setEnd(nextElement.lastChild, nextIndex);
} else if (newNodes.length > 0) {
const lastNewNode = newNodes[newNodes.length - 1];
if (lastNewNode.nodeType !== 3 && (lastNewNode as HTMLElement).getAttribute("data-type").indexOf("inline-math") > -1) {
const mathPreviousSibling = hasPreviousSibling(lastNewNode);
if (mathPreviousSibling && mathPreviousSibling.nodeType === 3) {
this.range.setStart(mathPreviousSibling, mathPreviousSibling.textContent.length);
} else {
this.range.setStartBefore(lastNewNode);
}
const mathNextSibling = hasNextSibling(lastNewNode);
if (mathNextSibling && mathNextSibling.nodeType === 3) { // https://github.com/siyuan-note/siyuan/issues/6065
this.range.setEnd(mathNextSibling, 0);
} else {
this.range.setEndAfter(lastNewNode);
}
} else {
if (lastNewNode.lastChild) {
if (lastNewNode.lastChild.textContent === Constants.ZWSP) {
// 新建元素时光标消失 https://github.com/siyuan-note/siyuan/issues/6481
// 新建元素粘贴后元素消失 https://ld246.com/article/1665556907936
this.range.collapse(true);
} else {
this.range.setEnd(lastNewNode.lastChild, lastNewNode.lastChild.textContent.length);
}
} else if (lastNewNode.nodeType === 3) {
this.range.setEnd(lastNewNode, lastNewNode.textContent.length);
if (lastNewNode.textContent === Constants.ZWSP) {
// 粗体后取消粗体光标不存在 https://github.com/siyuan-note/insider/issues/1056
this.range.collapse(false);
}
} else {
// eg: 表格中有3行时选中第二行三级多次加粗会增加换行
this.range.setEndAfter(lastNewNode);
}
}
} else if (previousElement) {
// **aaa**bbb 选中 bbb 加粗
// 需进行 mergeNode ,否用 alt+x 为相同颜色 aaabbb 中的 bbb 再次赋值后无法选中
this.range.setEnd(previousElement.firstChild, previousElement.firstChild.textContent.length);
}
let needFocus = true;
focusByRange(this.range);
if (type === "inline-math") {
mathRender(nodeElement);
if (selectText === "") {
protyle.toolbar.showRender(protyle, newNodes[0] as HTMLElement, undefined, html);
return;
}
} else if (type === "inline-memo") {
protyle.toolbar.showRender(protyle, newNodes[0] as HTMLElement, newNodes as Element[], html);
return;
} else if (type === "block-ref") {
this.range.collapse(false);
const memoElement = newNodes[0] as HTMLElement;
if (!memoElement.getAttribute("data-inline-memo-content")) {
protyle.toolbar.showRender(protyle, memoElement, newNodes as Element[], html);
}
} else if (type === "a") {
const aElement = newNodes[0] as HTMLElement;
if (aElement.textContent.replace(Constants.ZWSP, "") === "" || !aElement.getAttribute("data-href")) {
needFocus = false;
linkMenu(protyle, aElement, aElement.getAttribute("data-href") ? true : false);
} else {
this.range.collapse(false);
}
}
nodeElement.setAttribute("updated", dayjs().format("YYYYMMDDHHmmss"));
updateTransaction(protyle, nodeElement.getAttribute("data-node-id"), nodeElement.outerHTML, html);
const wbrElement = nodeElement.querySelector("wbr");
if (wbrElement) {
wbrElement.remove();
}
if (needFocus) {
focusByRange(this.range);
}
}
public showRender(protyle: IProtyle, renderElement: Element, updateElements?: Element[], oldHTML?: string) {