-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgenerateHighlightedComment.tsx
More file actions
170 lines (149 loc) · 6.58 KB
/
generateHighlightedComment.tsx
File metadata and controls
170 lines (149 loc) · 6.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import { h, VNode } from "preact"; // Explicitly import VNode from Preact
import { render } from "preact";
import HighlightedCommentIcon from "../components/HighlightedCommentIcon";
import { css } from "goober";
import React from "preact/compat";
import { IHighlightCommentData } from "../eventManager/useHighlightCommentIcon";
import { isValidCslp } from "../../cslp";
/**
* Inserts highlighted comment icons based on an array of paths.
*
* This function locates elements in the DOM based on the `fieldMetadata.cslpValue`,
* and appends a comment icon near each matching element.
*
* @param payload - Array of comment data with field metadata, schema, absolutePath and discussion ID.
*/
const highlighCommentOffset = 25;
export function highlightCommentIconOnCanvas(
payload: IHighlightCommentData[]
): void {
const uniquePaths: { [key: string]: boolean } = {}; // Using object for uniqueness
payload.forEach((data) => {
const cslpValue = data?.fieldMetadata?.cslpValue;
// Check if the cslpValue is already in the Object
if (!isValidCslp(cslpValue) || uniquePaths[cslpValue]) {
return; // Skip if the value is not unique
}
uniquePaths[cslpValue] = true; // Mark it as processed
const element = document.querySelector(`[data-cslp="${cslpValue}"]`);
if (element && element instanceof HTMLElement) {
const { top, left } = element.getBoundingClientRect();
const iconContainer = document.createElement("div");
iconContainer.setAttribute("field-path", cslpValue);
iconContainer.style.position = "fixed";
iconContainer.style.top = `${top - highlighCommentOffset}px`;
iconContainer.style.left = `${left - highlighCommentOffset}px`;
iconContainer.style.zIndex = "900";
iconContainer.style.cursor = "pointer";
iconContainer.className = "highlighted-comment collab-icon";
// Render the HighlightedCommentIcon using Preact's render method
render(
h(HighlightedCommentIcon, { data }), // Use h directly with Preact
iconContainer
);
const visualBuilderContainer = document.querySelector(
".visual-builder__container"
);
if (visualBuilderContainer) {
let highlightCommentWrapper =
visualBuilderContainer.querySelector(
".visual-builder__highlighted-comment-wrapper"
);
if (!highlightCommentWrapper) {
highlightCommentWrapper = document.createElement("div");
highlightCommentWrapper.className =
"visual-builder__highlighted-comment-wrapper";
visualBuilderContainer.appendChild(highlightCommentWrapper);
}
highlightCommentWrapper.appendChild(iconContainer);
}
}
});
}
/**
* Update Highlighted comment position , whenever scroll or resize happen.
*/
export function updateHighlightedCommentIconPosition() {
// Query all elements with the .highlighted-comment class
const icons = document.querySelectorAll(".highlighted-comment");
icons.forEach((icon) => {
if (icon && icon instanceof HTMLElement) {
// Get the field-path attribute from the icon container
const path = icon.getAttribute("field-path");
if (path) {
// Query the target element using the path
const targetElement = document.querySelector(
`[data-cslp="${path}"]`
);
if (targetElement && targetElement instanceof HTMLElement) {
// Get the target element's position relative to the viewport
const { top, left } = targetElement.getBoundingClientRect();
// Update the position of the icon container
icon.style.top = `${top - highlighCommentOffset}px`; // Adjust based on the target element's top
icon.style.left = `${left - highlighCommentOffset}px`; // Adjust based on the target element's left
} else {
// Target element is gone (e.g. data-cslp mutated after a
// variant switch). Remove the orphaned icon instead of
// silently leaving it drifted — the visual editor will
// re-mount a fresh set via REQUEST_DISCUSSION_HIGHLIGHTS.
icon.remove();
}
}
}
});
}
/**
* Removes the first highlighted comment icon based on an array of paths.
*
* @param pathsToRemove - Array of field-paths to remove.
*/
export function removeHighlightedCommentIcon(pathToRemove: string): void {
// Loop through each path in the array
const iconToRemove = document.querySelectorAll(
`.highlighted-comment[field-path="${pathToRemove}"]`
);
iconToRemove?.forEach((icon) => icon?.remove());
}
export function removeAllHighlightedCommentIcons(): void {
const icons = document.querySelectorAll(".highlighted-comment");
icons?.forEach((icon) => icon?.remove());
}
// Define a hidden class in goober
const hiddenClass = css`
display: none;
`;
/**
* Toggle display style of a specific highlighted comment icon.
*
* @param path - The data-cslp attribute of the element whose corresponding highlighted comment icon should be toggled.
* @param shouldShow - Boolean value to determine whether to show or hide the icon.
* If true, the icon will be displayed. If false, the icon will be hidden.
*/
export function toggleHighlightedCommentIconDisplay(
path: string,
shouldShow: boolean
): void {
const icons = document.querySelectorAll<HTMLElement>(
`.highlighted-comment[field-path="${path}"]`
);
icons.forEach((icon) => {
if (shouldShow) {
icon.classList.remove(hiddenClass); // Show the element
} else {
icon.classList.add(hiddenClass); // Hide the element using goober's hidden class
}
});
}
/**
* Show all .highlighted-comment icons that have the hiddenClass applied.
*/
export function showAllHiddenHighlightedCommentIcons(): void {
// Query all elements that have both .highlighted-comment and hiddenClass
const hiddenIcons = document.querySelectorAll<HTMLElement>(
`.highlighted-comment.${hiddenClass}`
);
// Loop through each hidden icon and remove the hiddenClass
hiddenIcons.forEach((icon) => {
icon.classList.remove(hiddenClass); // Remove the hiddenClass to show the icon
});
}