mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-02-07 16:04:19 +01:00
220 lines
9.3 KiB
TypeScript
220 lines
9.3 KiB
TypeScript
import {hasClosestBlock, hasClosestByAttribute} from "../util/hasClosest";
|
|
import {Constants} from "../../constants";
|
|
|
|
export const getPreviousBlock = (element: Element) => {
|
|
let parentElement = element;
|
|
while (parentElement) {
|
|
if (parentElement.previousElementSibling && parentElement.previousElementSibling.getAttribute("data-node-id")) {
|
|
return parentElement.previousElementSibling;
|
|
}
|
|
const pElement = hasClosestBlock(parentElement.parentElement);
|
|
if (pElement) {
|
|
parentElement = pElement;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
};
|
|
|
|
export const getLastBlock = (element: Element) => {
|
|
let lastElement;
|
|
Array.from(element.querySelectorAll("[data-node-id]")).reverse().find(item => {
|
|
if (!hasClosestByAttribute(item.parentElement, "data-type", "NodeBlockQueryEmbed")) {
|
|
lastElement = item;
|
|
return true;
|
|
}
|
|
});
|
|
return lastElement || element;
|
|
};
|
|
|
|
export const getFirstBlock = (element: Element) => {
|
|
let firstElement;
|
|
Array.from(element.querySelectorAll("[data-node-id]")).find(item => {
|
|
if (!hasClosestByAttribute(item.parentElement, "data-type", "NodeBlockQueryEmbed") &&
|
|
!item.classList.contains("li") && !item.classList.contains("sb")) {
|
|
firstElement = item;
|
|
return true;
|
|
}
|
|
});
|
|
return firstElement || element;
|
|
};
|
|
|
|
export const getNextBlock = (element: Element) => {
|
|
let parentElement = element;
|
|
while (parentElement) {
|
|
if (parentElement.nextElementSibling && !parentElement.nextElementSibling.classList.contains("protyle-attr")) {
|
|
return parentElement.nextElementSibling as HTMLElement;
|
|
}
|
|
const pElement = hasClosestBlock(parentElement.parentElement);
|
|
if (pElement) {
|
|
parentElement = pElement;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
export const getNoContainerElement = (element: Element) => {
|
|
let childElement = element;
|
|
while (childElement) {
|
|
if (childElement.classList.contains("list") || childElement.classList.contains("li") || childElement.classList.contains("bq") || childElement.classList.contains("sb")) {
|
|
childElement = childElement.querySelector("[data-node-id]");
|
|
} else {
|
|
return childElement;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
export const getContenteditableElement = (element: Element) => {
|
|
if (!element || (element.getAttribute("contenteditable") === "true") && !element.classList.contains("protyle-wysiwyg")) {
|
|
return element;
|
|
}
|
|
return element.querySelector('[contenteditable="true"]');
|
|
};
|
|
|
|
export const isNotEditBlock = (element: Element) => {
|
|
return ["NodeBlockQueryEmbed", "NodeThematicBreak", "NodeMathBlock", "NodeHTMLBlock", "NodeIFrame", "NodeWidget", "NodeVideo", "NodeAudio"].includes(element.getAttribute("data-type")) ||
|
|
(element.getAttribute("data-type") === "NodeCodeBlock" && element.classList.contains("render-node"));
|
|
};
|
|
|
|
export const getTopEmptyElement = (element: Element) => {
|
|
let topElement = element;
|
|
while (topElement.parentElement && !topElement.parentElement.classList.contains("protyle-wysiwyg")) {
|
|
if (!topElement.parentElement.getAttribute("data-node-id")) {
|
|
topElement = topElement.parentElement;
|
|
} else {
|
|
let hasText = false;
|
|
Array.from(topElement.parentElement.querySelectorAll('[contenteditable="true"]')).find(item => {
|
|
if (item.textContent.replace(Constants.ZWSP, "").replace("\n", "") !== "") {
|
|
hasText = true;
|
|
return true;
|
|
}
|
|
});
|
|
if (hasText || topElement.previousElementSibling?.getAttribute("data-node-id") ||
|
|
topElement.nextElementSibling?.getAttribute("data-node-id")) {
|
|
break;
|
|
} else {
|
|
topElement = topElement.parentElement;
|
|
}
|
|
}
|
|
}
|
|
return topElement;
|
|
};
|
|
|
|
export const getTopAloneElement = (topSourceElement: Element) => {
|
|
if ("NodeBlockquote" === topSourceElement.parentElement.getAttribute("data-type") && topSourceElement.parentElement.childElementCount === 2) {
|
|
while (!topSourceElement.parentElement.classList.contains("protyle-wysiwyg")) {
|
|
if (topSourceElement.parentElement.getAttribute("data-type") === "NodeBlockquote" && topSourceElement.parentElement.childElementCount === 2) {
|
|
topSourceElement = topSourceElement.parentElement;
|
|
} else {
|
|
topSourceElement = getTopAloneElement(topSourceElement);
|
|
break;
|
|
}
|
|
}
|
|
} else if ("NodeSuperBlock" === topSourceElement.parentElement.getAttribute("data-type") && topSourceElement.parentElement.childElementCount === 2) {
|
|
while (!topSourceElement.parentElement.classList.contains("protyle-wysiwyg")) {
|
|
if (topSourceElement.parentElement.getAttribute("data-type") === "NodeSuperBlock" && topSourceElement.parentElement.childElementCount === 2) {
|
|
topSourceElement = topSourceElement.parentElement;
|
|
} else {
|
|
topSourceElement = getTopAloneElement(topSourceElement);
|
|
break;
|
|
}
|
|
}
|
|
} else if ("NodeListItem" === topSourceElement.parentElement.getAttribute("data-type") && topSourceElement.parentElement.childElementCount === 3) {
|
|
while (!topSourceElement.parentElement.classList.contains("protyle-wysiwyg")) {
|
|
if (topSourceElement.parentElement.getAttribute("data-type") === "NodeListItem" && topSourceElement.parentElement.childElementCount === 3) {
|
|
topSourceElement = topSourceElement.parentElement;
|
|
} else if (topSourceElement.parentElement.getAttribute("data-type") === "NodeList" && topSourceElement.parentElement.childElementCount === 2) {
|
|
topSourceElement = topSourceElement.parentElement;
|
|
} else {
|
|
topSourceElement = getTopAloneElement(topSourceElement);
|
|
break;
|
|
}
|
|
}
|
|
} else if ("NodeList" === topSourceElement.parentElement.getAttribute("data-type") && topSourceElement.parentElement.childElementCount === 2) {
|
|
while (!topSourceElement.parentElement.classList.contains("protyle-wysiwyg")) {
|
|
if ("NodeList" === topSourceElement.parentElement.getAttribute("data-type") && topSourceElement.parentElement.childElementCount === 2) {
|
|
topSourceElement = topSourceElement.parentElement;
|
|
} else if (topSourceElement.parentElement.getAttribute("data-type") === "NodeListItem" && topSourceElement.parentElement.childElementCount === 3) {
|
|
topSourceElement = topSourceElement.parentElement;
|
|
} else {
|
|
topSourceElement = getTopAloneElement(topSourceElement);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return topSourceElement;
|
|
};
|
|
|
|
export const hasNextSibling = (element: Node) => {
|
|
let nextSibling = element.nextSibling;
|
|
while (nextSibling) {
|
|
if (nextSibling.textContent === "" && nextSibling.nodeType === 3) {
|
|
nextSibling = nextSibling.nextSibling;
|
|
} else {
|
|
return nextSibling;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
export const hasPreviousSibling = (element: Node) => {
|
|
let previousSibling = element.previousSibling;
|
|
while (previousSibling) {
|
|
if (previousSibling.textContent === "" && previousSibling.nodeType === 3) {
|
|
previousSibling = previousSibling.previousSibling;
|
|
} else {
|
|
return previousSibling;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
export const getNextFileLi = (current: Element) => {
|
|
let nextElement = current.nextElementSibling;
|
|
if (nextElement) {
|
|
if (nextElement.tagName === "LI") {
|
|
return nextElement;
|
|
} else if (nextElement.tagName === "UL") {
|
|
return nextElement.firstElementChild;
|
|
}
|
|
return false;
|
|
}
|
|
nextElement = current.parentElement;
|
|
while (nextElement.tagName === "UL") {
|
|
if (!nextElement.nextElementSibling) {
|
|
nextElement = nextElement.parentElement;
|
|
} else if (nextElement.nextElementSibling.tagName === "LI") {
|
|
return nextElement.nextElementSibling;
|
|
} else if (nextElement.nextElementSibling.tagName === "UL") {
|
|
return nextElement.nextElementSibling.firstElementChild;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
export const getPreviousFileLi = (current: Element) => {
|
|
let previousElement = current.previousElementSibling;
|
|
if (previousElement) {
|
|
if (previousElement.tagName === "LI") {
|
|
return previousElement;
|
|
} else if (previousElement.tagName === "UL") {
|
|
return previousElement.lastElementChild;
|
|
}
|
|
return false;
|
|
}
|
|
previousElement = current.parentElement;
|
|
while (previousElement.tagName === "UL") {
|
|
if (!previousElement.previousElementSibling) {
|
|
previousElement = previousElement.parentElement;
|
|
} else if (previousElement.previousElementSibling.tagName === "LI") {
|
|
return previousElement.previousElementSibling;
|
|
} else if (previousElement.previousElementSibling.tagName === "UL") {
|
|
const liElements = previousElement.previousElementSibling.querySelectorAll(".b3-list-item");
|
|
return liElements[liElements.length - 1];
|
|
}
|
|
}
|
|
return false;
|
|
};
|