A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
1export const hasTopClosestByClassName = (element: Node, className: string, top = false) => {
2 let closest = hasClosestByClassName(element, className, top);
3 let parentClosest: boolean | HTMLElement = false;
4 let findTop = false;
5 while (closest && (top ? closest.tagName !== "BODY" : !closest.classList.contains("protyle-wysiwyg")) && !findTop) {
6 parentClosest = hasClosestByClassName(closest.parentElement, className, top);
7 if (parentClosest) {
8 closest = parentClosest;
9 } else {
10 findTop = true;
11 }
12 }
13 return closest || false;
14};
15
16export const hasTopClosestByTag = (element: Node, nodeName: string) => {
17 let closest = hasClosestByTag(element, nodeName);
18 let parentClosest: boolean | HTMLElement = false;
19 let findTop = false;
20 while (closest && !closest.classList.contains("protyle-wysiwyg") && !findTop) {
21 parentClosest = hasClosestByTag(closest.parentElement, nodeName);
22 if (parentClosest) {
23 closest = parentClosest;
24 } else {
25 findTop = true;
26 }
27 }
28 return closest || false;
29};
30
31export const hasTopClosestByAttribute = (element: Node, attr: string, value: string | null, top = false) => {
32 let closest = hasClosestByAttribute(element, attr, value, top);
33 let parentClosest: boolean | HTMLElement = false;
34 let findTop = false;
35 while (closest && !closest.classList.contains("protyle-wysiwyg") && !findTop) {
36 parentClosest = hasClosestByAttribute(closest.parentElement, attr, value, top);
37 if (parentClosest) {
38 closest = parentClosest;
39 } else {
40 findTop = true;
41 }
42 }
43 return closest || false;
44};
45
46export const hasClosestByAttribute = (element: Node, attr: string, value: string | null, top = false) => {
47 if (!element || element.nodeType === 9) {
48 return false;
49 }
50 if (element.nodeType === 3) {
51 element = element.parentElement;
52 }
53 let e = element as HTMLElement;
54 let isClosest = false;
55 while (e && !isClosest && (top ? e.tagName !== "BODY" : !e.classList.contains("protyle-wysiwyg"))) {
56 if (typeof value === "string" && e.getAttribute(attr)?.split(" ").includes(value)) {
57 isClosest = true;
58 } else if (typeof value !== "string" && e.hasAttribute(attr)) {
59 isClosest = true;
60 } else {
61 e = e.parentElement;
62 }
63 }
64 return isClosest && e;
65};
66
67export const hasClosestByTag = (element: Node, nodeName: string) => {
68 if (!element || element.nodeType === 9) {
69 return false;
70 }
71 if (element.nodeType === 3) {
72 element = element.parentElement;
73 }
74 let e = element as HTMLElement;
75 let isClosest = false;
76 while (e && !isClosest && !e.classList.contains("protyle-wysiwyg")) {
77 if (e.nodeName === nodeName) {
78 isClosest = true;
79 } else {
80 e = e.parentElement;
81 }
82 }
83 return isClosest && e;
84};
85
86export const hasClosestByClassName = (element: Node, className: string, top = false) => {
87 if (!element || element.nodeType === 9) {
88 return false;
89 }
90 if (element.nodeType === 3) {
91 element = element.parentElement;
92 }
93 let e = element as HTMLElement;
94 let isClosest = false;
95 while (e && !isClosest && (top ? e.tagName !== "BODY" : !e.classList.contains("protyle-wysiwyg"))) {
96 if (e.classList?.contains(className)) {
97 isClosest = true;
98 } else {
99 e = e.parentElement;
100 }
101 }
102 return isClosest && e;
103};
104
105export const hasClosestBlock = (element: Node) => {
106 const nodeElement = hasClosestByAttribute(element, "data-node-id", null);
107 if (nodeElement && nodeElement.tagName !== "BUTTON" && nodeElement.getAttribute("data-type")?.startsWith("Node")) {
108 return nodeElement;
109 }
110 return false;
111};
112
113export const isInEmbedBlock = (element: Element) => {
114 const embedElement = hasTopClosestByAttribute(element, "data-type", "NodeBlockQueryEmbed");
115 if (embedElement) {
116 if (embedElement === element) {
117 return false;
118 } else {
119 return embedElement;
120 }
121 } else {
122 return false;
123 }
124};
125
126export const isInAVBlock = (element: Element) => {
127 if (hasClosestByClassName(element, "av__gallery-cover")) {
128 return hasClosestByClassName(element, "av");
129 }
130 return false;
131};