mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-05-02 03:29:24 +08:00
This commit is contained in:
parent
a7c989f064
commit
21baed3ad4
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user