diff --git a/app/src/protyle/toolbar/index.ts b/app/src/protyle/toolbar/index.ts index d0fbd62f6..5519a7da2 100644 --- a/app/src/protyle/toolbar/index.ts +++ b/app/src/protyle/toolbar/index.ts @@ -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) {