-
Notifications
You must be signed in to change notification settings - Fork 0
/
Highlight popup.js
198 lines (180 loc) · 6.97 KB
/
Highlight popup.js
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
let currentSelection;
let selection;
let active = false;
let highlightColor = 'yellow';
let highlightSections = [];
const navBar = document.getElementById('navBar');
const btnToggle = document.getElementById('btnToggle');
const btnSelect = document.getElementById('btnSelect');
const btnYellow = document.getElementById('btnYellow');
const btnGreen = document.getElementById('btnGreen');
const btnPink = document.getElementById('btnPink');
const btnBlue = document.getElementById('btnBlue');
const highlightList = document.getElementById('highlightList');
const markInstance = new Mark(document.querySelector('.text-container'));
const colorPopup = document.getElementById('colorPopup');
const textSelect = () => {
selection = document.getSelection();
const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
const text = selection.toString();
if (range && text.length > 3) {
// check the range startContainer. nodeType 3 is the actual Text inside an Element, so select the parentNode in that situation
const startElmement = (range.startContainer.nodeType === 3 ? range.startContainer.parentNode : range.startContainer);
// Check up the DOM tree for the text-container, where all the highlightable text is contained.
const startComponent = startElmement.closest('.text-container');
if (startComponent) {
currentSelection = text;
}
else {
// selection is outside the text-container
currentSelection = null;
}
}
else {
// selection is too short
currentSelection = null;
}
// if we have a valid selection, enable the select button, otherwise disable it
btnSelect.disabled = currentSelection ? false : true;
btnSelect.innerText = currentSelection ? 'Highlight Selected Text' : 'Select Text to Highlight';
};
document.addEventListener('mouseup', () => {
const selection = document.getSelection();
const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
const text = selection.toString();
const colorPopup = document.getElementById('colorPopup');
if (range && text.length > 3) {
// check the range startContainer. nodeType 3 is the actual Text inside an Element, so select the parentNode in that situation
const startElement = (range.startContainer.nodeType === 3 ? range.startContainer.parentNode : range.startContainer);
// Check up the DOM tree for the text-container, where all the highlightable text is contained.
const startComponent = startElement.closest('.text-container');
if (startComponent) {
currentSelection = text;
// Show the color popup and position it at the end of the selection
const rect = range.getBoundingClientRect();
colorPopup.style.left = rect.right + 'px';
colorPopup.style.top = rect.bottom + 'px';
colorPopup.style.display = 'block';
}
else {
// selection is outside the text-container
currentSelection = null;
colorPopup.style.display = 'none';
}
}
else {
// selection is too short
currentSelection = null;
colorPopup.style.display = 'none';
}
});
const applyHighlighting = () => {
highlightSections.forEach(section => {
markInstance.mark(section.text, {
caseSensitive: true,
acrossElements: true,
separateWordSearch: false,
each: (elm) => {
elm.classList.add(section.color);
elm.classList.add('animated');
setTimeout(() => {
elm.classList.add('animate');
}, 250);
}
});
});
};
const removeHighlight = (index) => {
// update the array
highlightSections.splice(index, 1);
// update the list
const listItem = highlightList.children[index]; // +1 so we ignore the heading
if (listItem) {
listItem.classList.remove('in');
// wait for the animation to finish
setTimeout(() => {
// check if any highlights remain
if (highlightSections.length) {
// remove all highlighting, then reapply highlights that remain (but without the animation)
markInstance.unmark({
done: () => {
highlightSections.forEach(section => {
markInstance.mark(section.text, {
caseSensitive: true,
acrossElements: true,
separateWordSearch: false,
each: (elm) => {
elm.classList.add(section.color);
}
});
});
}
});
}
else {
// nothing left, clear all highlights. ad hide the list
markInstance.unmark();
}
buildHighlightList(true);
}, 250);
}
};
const changeColor = (color) => {
return new Promise((resolve, reject) => {
// animate the toolbar
navBar.classList.remove('animate');
setTimeout(() => {
navBar.classList.remove(highlightColor);
navBar.classList.add(color);
// update the color choice
highlightColor = color;
resolve();
}, 0);
})
.then(() => {
// Execute the btnSelect.onclick function immediately after changing the color
btnSelect.onclick();
})
.then(() => {
setTimeout(() => {
navBar.classList.add('animate');
}, 250);
// Hide the color popup
const colorPopup = document.getElementById('colorPopup');
colorPopup.style.display = 'none';
});
};
const buildHighlightList = (rebuild) => {
highlightList.innerHTML = highlightSections.length ? '' : '<span class="text-muted font-italic">None...</span>';
highlightSections.forEach((section, s) => {
const item = document.createElement('div');
item.classList.add('highlight-list-item');
item.innerHTML = `
<a role="button" onClick="removeHighlight(${s})">
<i class="fa fa-times"></i>
</a>
<mark class="${section.color}">${section.text}</mark>
</div>
`;
highlightList.appendChild(item);
if (!rebuild && s === highlightSections.length - 1) {
setTimeout(() => {
item.classList.add('in');
}, 250);
}
else {
item.classList.add('in');
}
})
};
document.addEventListener('selectionchange', textSelect);
btnSelect.onclick = () => {
highlightSections.push({
text: currentSelection,
color: highlightColor
});
console.log('Selected Text Snippets:', highlightSections);
selection.removeAllRanges();
applyHighlighting();
buildHighlightList();
};