single-file-core 1.0.64 → 1.0.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/common/content-infobar-web.js +15 -258
- package/common/infobar.js +277 -0
- package/package.json +1 -1
- package/single-file-core.js +24 -14
- package/single-file-helper.js +10 -1
- package/single-file-mini-helper.js +50 -0
- package/single-file-util.js +3 -0
|
@@ -21,111 +21,11 @@
|
|
|
21
21
|
* Source.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
/* global globalThis, window, document
|
|
24
|
+
/* global globalThis, window, document */
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
import { appendInfobar, refreshInfobarInfo, extractInfobarData } from "./infobar.js";
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
const LINK_ICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAgMAAADXB5lNAAABhmlDQ1BJQ0MgcHJvZmlsZQAAKJF9kj1Iw0AYht+mSkUrDnYQcchQnSyIijqWKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjx4LiH9+59+e67A4RGhalm1wSgapaRisfEbG5VDLyiDwEAvZiVmKkn0osZeI6ve/j4ehfhWd7n/hz9St5kgE8kjjLdsIg3iGc2LZ3zPnGIlSSF+Jx43KACiR+5Lrv8xrnosMAzQ0YmNU8cIhaLHSx3MCsZKvE0cVhRNcoXsi4rnLc4q5Uaa9XJbxjMaytprtMcQRxLSCAJETJqKKMCCxFaNVJMpGg/5uEfdvxJcsnkKoORYwFVqJAcP/gb/O6tWZiadJOCMaD7xbY/RoHALtCs2/b3sW03TwD/M3Cltf3VBjD3SXq9rYWPgIFt4OK6rcl7wOUOMPSkS4bkSH6aQqEAvJ/RM+WAwVv6EGtu31r7OH0AMtSr5Rvg4BAYK1L2use9ezr79u+ZVv9+AFlNcp0UUpiqAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5AsHAB8H+DhhoQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAJUExURQAAAICHi4qKioTuJAkAAAABdFJOUwBA5thmAAAAAWJLR0QCZgt8ZAAAAJJJREFUOI3t070NRCEMA2CnYAOyDyPwpHj/Va7hJ3FzV7zy3ET5JIwoAF6Jk4wzAJAkzxAYG9YRTgB+24wBgKmfrGAKTcEfAY4KRlRoIeBTgKOCERVaCPgU4Khge2GqKOBTgKOCERVaAEC/4PNcnyoSWHpjqkhwKxbcig0Q6AorXYF/+A6eIYD1lVbwG/jdA6/kA2THRAURVubcAAAAAElFTkSuQmCC";
|
|
30
|
-
const CLOSE_ICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAgMAAADXB5lNAAABhmlDQ1BJQ0MgcHJvZmlsZQAAKJF9kj1Iw0AYht+mSkUrDnYQcchQnSyIijqWKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjx4LiH9+59+e67A4RGhalm1wSgapaRisfEbG5VDLyiDwEAvZiVmKkn0osZeI6ve/j4ehfhWd7n/hz9St5kgE8kjjLdsIg3iGc2LZ3zPnGIlSSF+Jx43KACiR+5Lrv8xrnosMAzQ0YmNU8cIhaLHSx3MCsZKvE0cVhRNcoXsi4rnLc4q5Uaa9XJbxjMaytprtMcQRxLSCAJETJqKKMCCxFaNVJMpGg/5uEfdvxJcsnkKoORYwFVqJAcP/gb/O6tWZiadJOCMaD7xbY/RoHALtCs2/b3sW03TwD/M3Cltf3VBjD3SXq9rYWPgIFt4OK6rcl7wOUOMPSkS4bkSH6aQqEAvJ/RM+WAwVv6EGtu31r7OH0AMtSr5Rvg4BAYK1L2use9ezr79u+ZVv9+AFlNcp0UUpiqAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5AsHAB8VC4EQ6QAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAJUExURQAAAICHi4qKioTuJAkAAAABdFJOUwBA5thmAAAAAWJLR0QCZgt8ZAAAAJtJREFUOI3NkrsBgCAMRLFwBPdxBArcfxXFkO8rbKWAAJfHJ9faf9vuYX/749T5NmShm3bEwbe2SxeuM4+2oxDL1cDoKtVUjRy+tH78Cv2CS+wIiQNC1AEhk4AQeUTMWUJMfUJMSEJMSEY8kIx4IONroaYAimNxsXp1PA7PxwfVL8QnowwoVC0lig07wDDVUjAdbAnjwtow/z/bDW7eI4M2KruJAAAAAElFTkSuQmCC";
|
|
31
|
-
const IMAGE_ICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABABAMAAABYR2ztAAABhmlDQ1BJQ0MgcHJvZmlsZQAAKJF9kj1Iw0AYht+mSkUrDnYQcchQnSyIijqWKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjx4LiH9+59+e67A4RGhalm1wSgapaRisfEbG5VDLyiDwEAvZiVmKkn0osZeI6ve/j4ehfhWd7n/hz9St5kgE8kjjLdsIg3iGc2LZ3zPnGIlSSF+Jx43KACiR+5Lrv8xrnosMAzQ0YmNU8cIhaLHSx3MCsZKvE0cVhRNcoXsi4rnLc4q5Uaa9XJbxjMaytprtMcQRxLSCAJETJqKKMCCxFaNVJMpGg/5uEfdvxJcsnkKoORYwFVqJAcP/gb/O6tWZiadJOCMaD7xbY/RoHALtCs2/b3sW03TwD/M3Cltf3VBjD3SXq9rYWPgIFt4OK6rcl7wOUOMPSkS4bkSH6aQqEAvJ/RM+WAwVv6EGtu31r7OH0AMtSr5Rvg4BAYK1L2use9ezr79u+ZVv9+AFlNcp0UUpiqAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5AsHADIRLMaOHwAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAPUExURQAAAIqKioyNjY2OjvDw8L2y1DEAAAABdFJOUwBA5thmAAAAAWJLR0QB/wIt3gAAAGNJREFUSMdjYCAJsLi4OBCQx6/CBQwIGIDPCBcXAkYQUsACU+AwlBVQHg6Eg5pgZBGOboIJZugDFwRwoJECJCUOhJI1wZwzqmBUwagCuipgIqTABG9h7YIKaKGAURAFEF/6AQAO4HqSoDP8bgAAAABJRU5ErkJggg==";
|
|
32
|
-
const SINGLEFILE_COMMENT = "SingleFile";
|
|
33
|
-
const SINGLE_FILE_UI_ELEMENT_CLASS = "single-file-ui-element";
|
|
34
|
-
const INFOBAR_STYLES = `
|
|
35
|
-
.infobar {
|
|
36
|
-
background-color: #737373;
|
|
37
|
-
color: white;
|
|
38
|
-
display: flex;
|
|
39
|
-
position: fixed;
|
|
40
|
-
top: 16px;
|
|
41
|
-
right: 16px;
|
|
42
|
-
height: auto;
|
|
43
|
-
width: auto;
|
|
44
|
-
min-height: 24px;
|
|
45
|
-
min-width: 24px;
|
|
46
|
-
background-position: center;
|
|
47
|
-
background-repeat: no-repeat;
|
|
48
|
-
z-index: 2147483647;
|
|
49
|
-
margin: 0 0 0 16px;
|
|
50
|
-
background-image: url(${IMAGE_ICON});
|
|
51
|
-
border-radius: 16px;
|
|
52
|
-
user-select: none;
|
|
53
|
-
-moz-user-select: none;
|
|
54
|
-
opacity: .7;
|
|
55
|
-
cursor: pointer;
|
|
56
|
-
padding-left: 0;
|
|
57
|
-
padding-right: 0;
|
|
58
|
-
padding-top: 0;
|
|
59
|
-
padding-bottom: 0;
|
|
60
|
-
border: 2px solid #eee;
|
|
61
|
-
background-size: 70% 70%;
|
|
62
|
-
transition: all 250ms;
|
|
63
|
-
font-size: 13px;
|
|
64
|
-
}
|
|
65
|
-
.infobar:hover {
|
|
66
|
-
opacity: 1;
|
|
67
|
-
}
|
|
68
|
-
.infobar-open {
|
|
69
|
-
opacity: 1;
|
|
70
|
-
background-color: #f9f9f9;
|
|
71
|
-
cursor: auto;
|
|
72
|
-
color: #2d2d2d;
|
|
73
|
-
padding-top: 2px;
|
|
74
|
-
padding-bottom: 2px;
|
|
75
|
-
border: 2px solid #878787;
|
|
76
|
-
background-image: none;
|
|
77
|
-
border-radius: 8px;
|
|
78
|
-
user-select: initial;
|
|
79
|
-
-moz-user-select: initial;
|
|
80
|
-
}
|
|
81
|
-
.infobar-close-button {
|
|
82
|
-
display: none;
|
|
83
|
-
opacity: .7;
|
|
84
|
-
padding-top: 4px;
|
|
85
|
-
padding-left: 8px;
|
|
86
|
-
padding-right: 8px;
|
|
87
|
-
cursor: pointer;
|
|
88
|
-
transition: opacity 250ms;
|
|
89
|
-
height: 16px;
|
|
90
|
-
}
|
|
91
|
-
.infobar-close-button:hover {
|
|
92
|
-
opacity: 1;
|
|
93
|
-
}
|
|
94
|
-
.infobar-content {
|
|
95
|
-
display: none;
|
|
96
|
-
font-family: Arial;
|
|
97
|
-
font-size: 14px;
|
|
98
|
-
line-height: 22px;
|
|
99
|
-
word-break: break-word;
|
|
100
|
-
white-space: pre-wrap;
|
|
101
|
-
position: relative;
|
|
102
|
-
top: 1px;
|
|
103
|
-
text-align: left;
|
|
104
|
-
}
|
|
105
|
-
.infobar-link {
|
|
106
|
-
display: none;
|
|
107
|
-
padding-left: 8px;
|
|
108
|
-
padding-right: 8px;
|
|
109
|
-
line-height: 11px;
|
|
110
|
-
cursor: pointer;
|
|
111
|
-
user-select: none;
|
|
112
|
-
outline: 0;
|
|
113
|
-
}
|
|
114
|
-
.infobar-link-icon {
|
|
115
|
-
padding-top: 4px;
|
|
116
|
-
padding-left: 2px;
|
|
117
|
-
cursor: pointer;
|
|
118
|
-
opacity: .7;
|
|
119
|
-
transition: opacity 250ms;
|
|
120
|
-
height: 16px;
|
|
121
|
-
}
|
|
122
|
-
.infobar-link-icon:hover {
|
|
123
|
-
opacity: 1;
|
|
124
|
-
}
|
|
125
|
-
.infobar-open .infobar-close-button, .infobar-open .infobar-content, .infobar-open .infobar-link {
|
|
126
|
-
display: inline-block;
|
|
127
|
-
}`;
|
|
128
|
-
let SHADOW_DOM_SUPPORTED = true;
|
|
28
|
+
(globalThis => {
|
|
129
29
|
|
|
130
30
|
const browser = globalThis.browser;
|
|
131
31
|
|
|
@@ -137,169 +37,26 @@
|
|
|
137
37
|
}
|
|
138
38
|
}
|
|
139
39
|
if (globalThis.singlefile) {
|
|
140
|
-
globalThis.singlefile.infobar = {
|
|
40
|
+
globalThis.singlefile.infobar = {
|
|
141
41
|
displayIcon
|
|
142
42
|
};
|
|
143
43
|
}
|
|
144
44
|
|
|
145
45
|
async function displayIcon() {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
let options;
|
|
155
|
-
if (browser && browser.runtime && browser.runtime.sendMessage) {
|
|
156
|
-
try {
|
|
157
|
-
options = await browser.runtime.sendMessage({ method: "tabs.getOptions", url });
|
|
158
|
-
} catch (error) {
|
|
159
|
-
options = { displayInfobar: true };
|
|
160
|
-
}
|
|
161
|
-
} else {
|
|
162
|
-
options = { displayInfobar: true };
|
|
163
|
-
}
|
|
164
|
-
if (options.displayInfobar) {
|
|
165
|
-
await initInfobar(url, optionalData);
|
|
46
|
+
let options = { displayInfobar: true };
|
|
47
|
+
const infoData = extractInfobarData(document);
|
|
48
|
+
if (infoData && infoData.saveUrl) {
|
|
49
|
+
if (browser && browser.runtime && browser.runtime.sendMessage) {
|
|
50
|
+
try {
|
|
51
|
+
options = await browser.runtime.sendMessage({ method: "tabs.getOptions", url: infoData.saveUrl });
|
|
52
|
+
} catch (error) {
|
|
53
|
+
// ignored
|
|
166
54
|
}
|
|
167
55
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
function isSingleFileComment(node) {
|
|
172
|
-
return node.nodeType == Node.COMMENT_NODE && node.textContent.includes(SINGLEFILE_COMMENT);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
async function initInfobar(url, optionalData /* saveDate, infoData */) {
|
|
176
|
-
let infobarElement = document.querySelector(INFOBAR_TAGNAME);
|
|
177
|
-
if (!infobarElement) {
|
|
178
|
-
let infoData = "";
|
|
179
|
-
if (optionalData.length) {
|
|
180
|
-
const saveDate = optionalData[0].split("saved date: ")[1];
|
|
181
|
-
if (saveDate) {
|
|
182
|
-
optionalData.shift();
|
|
183
|
-
}
|
|
184
|
-
if (optionalData.length > 1) {
|
|
185
|
-
let content = optionalData[0].split("info: ")[1].trim();
|
|
186
|
-
for (let indexLine = 1; indexLine < optionalData.length - 1; indexLine++) {
|
|
187
|
-
content += "\n" + optionalData[indexLine].trim();
|
|
188
|
-
}
|
|
189
|
-
infoData = content.trim();
|
|
190
|
-
} else {
|
|
191
|
-
infoData = saveDate;
|
|
192
|
-
}
|
|
56
|
+
if (options.displayInfobar) {
|
|
57
|
+
appendInfobar(document, options, true);
|
|
58
|
+
refreshInfobarInfo(document, infoData);
|
|
193
59
|
}
|
|
194
|
-
infoData = infoData || "No info";
|
|
195
|
-
infobarElement = createElement(INFOBAR_TAGNAME, document.body);
|
|
196
|
-
infobarElement.className = SINGLE_FILE_UI_ELEMENT_CLASS;
|
|
197
|
-
const shadowRoot = await getShadowRoot(infobarElement);
|
|
198
|
-
const styleElement = document.createElement("style");
|
|
199
|
-
styleElement.textContent = INFOBAR_STYLES;
|
|
200
|
-
shadowRoot.appendChild(styleElement);
|
|
201
|
-
const infobarContent = document.createElement("div");
|
|
202
|
-
infobarContent.classList.add("infobar");
|
|
203
|
-
shadowRoot.appendChild(infobarContent);
|
|
204
|
-
const closeElement = document.createElement("img");
|
|
205
|
-
closeElement.classList.add("infobar-close-button");
|
|
206
|
-
infobarContent.appendChild(closeElement);
|
|
207
|
-
closeElement.src = CLOSE_ICON;
|
|
208
|
-
closeElement.onclick = event => {
|
|
209
|
-
if (event.button === 0) {
|
|
210
|
-
infobarElement.remove();
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
const infoElement = document.createElement("span");
|
|
214
|
-
infobarContent.appendChild(infoElement);
|
|
215
|
-
infoElement.classList.add("infobar-content");
|
|
216
|
-
infoElement.textContent = infoData;
|
|
217
|
-
const linkElement = document.createElement("a");
|
|
218
|
-
linkElement.classList.add("infobar-link");
|
|
219
|
-
infobarContent.appendChild(linkElement);
|
|
220
|
-
linkElement.target = "_blank";
|
|
221
|
-
linkElement.rel = "noopener noreferrer";
|
|
222
|
-
linkElement.title = "Open source URL: " + url;
|
|
223
|
-
linkElement.href = url;
|
|
224
|
-
const imgElement = document.createElement("img");
|
|
225
|
-
imgElement.classList.add("infobar-link-icon");
|
|
226
|
-
linkElement.appendChild(imgElement);
|
|
227
|
-
imgElement.src = LINK_ICON;
|
|
228
|
-
hideInfobar(infobarContent);
|
|
229
|
-
|
|
230
|
-
document.addEventListener("click", event => {
|
|
231
|
-
if (event.button === 0) {
|
|
232
|
-
let element = event.target;
|
|
233
|
-
while (element && element != infobarElement) {
|
|
234
|
-
element = element.parentElement;
|
|
235
|
-
}
|
|
236
|
-
if (element != infobarElement) {
|
|
237
|
-
hideInfobar(infobarContent);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function displayInfobar(infobarContent) {
|
|
245
|
-
if (!SHADOW_DOM_SUPPORTED) {
|
|
246
|
-
const infobarElement = document.querySelector(INFOBAR_TAGNAME);
|
|
247
|
-
const frameElement = infobarElement.childNodes[0];
|
|
248
|
-
frameElement.contentWindow.getSelection().removeAllRanges();
|
|
249
|
-
}
|
|
250
|
-
infobarContent.classList.add("infobar-open");
|
|
251
|
-
infobarContent.onclick = null;
|
|
252
|
-
infobarContent.onmouseout = null;
|
|
253
|
-
if (!SHADOW_DOM_SUPPORTED) {
|
|
254
|
-
const infobarElement = document.querySelector(INFOBAR_TAGNAME);
|
|
255
|
-
const frameElement = infobarElement.childNodes[0];
|
|
256
|
-
frameElement.style.setProperty("width", "100vw", "important");
|
|
257
|
-
frameElement.style.setProperty("height", "100vh", "important");
|
|
258
|
-
frameElement.style.setProperty("width", (infobarContent.getBoundingClientRect().width + 33) + "px", "important");
|
|
259
|
-
frameElement.style.setProperty("height", (infobarContent.getBoundingClientRect().height + 21) + "px", "important");
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function hideInfobar(infobarContent) {
|
|
264
|
-
infobarContent.classList.remove("infobar-open");
|
|
265
|
-
infobarContent.onclick = event => {
|
|
266
|
-
if (event.button === 0) {
|
|
267
|
-
displayInfobar(infobarContent);
|
|
268
|
-
return false;
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
if (!SHADOW_DOM_SUPPORTED) {
|
|
272
|
-
const infobarElement = document.querySelector(INFOBAR_TAGNAME);
|
|
273
|
-
const frameElement = infobarElement.childNodes[0];
|
|
274
|
-
frameElement.style.setProperty("width", "44px", "important");
|
|
275
|
-
frameElement.style.setProperty("height", "48px", "important");
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
function createElement(tagName, parentElement) {
|
|
280
|
-
const element = document.createElement(tagName);
|
|
281
|
-
parentElement.appendChild(element);
|
|
282
|
-
Array.from(getComputedStyle(element)).forEach(property => element.style.setProperty(property, "initial", "important"));
|
|
283
|
-
return element;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
async function getShadowRoot(element) {
|
|
287
|
-
if (element.attachShadow) {
|
|
288
|
-
return element.attachShadow({ mode: "open" });
|
|
289
|
-
} else {
|
|
290
|
-
SHADOW_DOM_SUPPORTED = false;
|
|
291
|
-
const iframe = createElement("iframe", element);
|
|
292
|
-
iframe.style.setProperty("background-color", "transparent", "important");
|
|
293
|
-
iframe.style.setProperty("position", "fixed", "important");
|
|
294
|
-
iframe.style.setProperty("top", 0, "important");
|
|
295
|
-
iframe.style.setProperty("right", 0, "important");
|
|
296
|
-
iframe.style.setProperty("width", "44px", "important");
|
|
297
|
-
iframe.style.setProperty("height", "48px", "important");
|
|
298
|
-
iframe.style.setProperty("z-index", 2147483647, "important");
|
|
299
|
-
return new Promise(resolve => {
|
|
300
|
-
iframe.contentDocument.body.style.setProperty("margin", 0);
|
|
301
|
-
iframe.onload = () => resolve(iframe.contentDocument.body);
|
|
302
|
-
});
|
|
303
60
|
}
|
|
304
61
|
}
|
|
305
62
|
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2010-2022 Gildas Lormeau
|
|
3
|
+
* contact : gildas.lormeau <at> gmail.com
|
|
4
|
+
*
|
|
5
|
+
* This file is part of SingleFile.
|
|
6
|
+
*
|
|
7
|
+
* The code in this file is free software: you can redistribute it and/or
|
|
8
|
+
* modify it under the terms of the GNU Affero General Public License
|
|
9
|
+
* (GNU AGPL) as published by the Free Software Foundation, either version 3
|
|
10
|
+
* of the License, or (at your option) any later version.
|
|
11
|
+
*
|
|
12
|
+
* The code in this file is distributed in the hope that it will be useful,
|
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
|
|
15
|
+
* General Public License for more details.
|
|
16
|
+
*
|
|
17
|
+
* As additional permission under GNU AGPL version 3 section 7, you may
|
|
18
|
+
* distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
|
|
19
|
+
* AGPL normally required by section 4, provided you include this license
|
|
20
|
+
* notice and a URL through which recipients can access the Corresponding
|
|
21
|
+
* Source.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/* global getComputedStyle, XPathResult, Node */
|
|
25
|
+
|
|
26
|
+
const INFOBAR_TAGNAME = "single-file-infobar";
|
|
27
|
+
const INFOBAR_STYLES = `
|
|
28
|
+
.infobar,
|
|
29
|
+
.infobar .infobar-icon,
|
|
30
|
+
.infobar .infobar-link-icon {
|
|
31
|
+
min-inline-size: 28px;
|
|
32
|
+
min-block-size: 28px;
|
|
33
|
+
box-sizing: border-box;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.infobar,
|
|
37
|
+
.infobar .infobar-close-icon,
|
|
38
|
+
.infobar .infobar-link-icon {
|
|
39
|
+
opacity: 0.7;
|
|
40
|
+
transition: opacity 250ms;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.infobar:hover,
|
|
44
|
+
.infobar .infobar-close-icon:hover,
|
|
45
|
+
.infobar .infobar-link-icon:hover {
|
|
46
|
+
opacity: 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.infobar,
|
|
50
|
+
.infobar-content {
|
|
51
|
+
display: flex;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.infobar {
|
|
55
|
+
position: fixed;
|
|
56
|
+
top: 16px;
|
|
57
|
+
right: 16px;
|
|
58
|
+
margin-inline-start: 16px;
|
|
59
|
+
margin-block-end: 16px;
|
|
60
|
+
color: #2d2d2d;
|
|
61
|
+
background-color: #737373;
|
|
62
|
+
border: 2px solid;
|
|
63
|
+
border-color: #eee;
|
|
64
|
+
border-radius: 16px;
|
|
65
|
+
z-index: 2147483647;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.infobar:valid, .infobar:not(:focus-within) .infobar-content {
|
|
69
|
+
display: none;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.infobar:focus-within {
|
|
73
|
+
background-color: #f9f9f9;
|
|
74
|
+
border-color: #878787;
|
|
75
|
+
border-radius: 8px;
|
|
76
|
+
opacity: 1;
|
|
77
|
+
transition-property: opacity, background-color, border-color, border-radius,
|
|
78
|
+
color;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.infobar-content {
|
|
82
|
+
align-items: center;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.infobar-content span {
|
|
86
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
87
|
+
font-size: 14px;
|
|
88
|
+
line-height: 18px;
|
|
89
|
+
word-break: break-word;
|
|
90
|
+
white-space: pre-wrap;
|
|
91
|
+
margin-inline: 4px;
|
|
92
|
+
margin-block: 4px;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.infobar .infobar-icon,
|
|
96
|
+
.infobar .infobar-close-icon,
|
|
97
|
+
.infobar .infobar-link-icon {
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
background-position: center;
|
|
100
|
+
background-repeat: no-repeat;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.infobar .infobar-close-icon,
|
|
104
|
+
.infobar .infobar-link-icon {
|
|
105
|
+
align-self: flex-start;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.infobar .infobar-icon {
|
|
109
|
+
position: absolute;
|
|
110
|
+
min-inline-size: 24px;
|
|
111
|
+
min-block-size: 24px;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.infobar:focus-within .infobar-icon {
|
|
115
|
+
z-index: -1;
|
|
116
|
+
background-image: none;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.infobar .infobar-close-icon {
|
|
120
|
+
min-inline-size: 22px;
|
|
121
|
+
min-block-size: 22px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.infobar .infobar-icon {
|
|
125
|
+
background-color: transparent;
|
|
126
|
+
background-size: 70%;
|
|
127
|
+
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABABAMAAABYR2ztAAABhmlDQ1BJQ0MgcHJvZmlsZQAAKJF9kj1Iw0AYht+mSkUrDnYQcchQnSyIijqWKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjx4LiH9+59+e67A4RGhalm1wSgapaRisfEbG5VDLyiDwEAvZiVmKkn0osZeI6ve/j4ehfhWd7n/hz9St5kgE8kjjLdsIg3iGc2LZ3zPnGIlSSF+Jx43KACiR+5Lrv8xrnosMAzQ0YmNU8cIhaLHSx3MCsZKvE0cVhRNcoXsi4rnLc4q5Uaa9XJbxjMaytprtMcQRxLSCAJETJqKKMCCxFaNVJMpGg/5uEfdvxJcsnkKoORYwFVqJAcP/gb/O6tWZiadJOCMaD7xbY/RoHALtCs2/b3sW03TwD/M3Cltf3VBjD3SXq9rYWPgIFt4OK6rcl7wOUOMPSkS4bkSH6aQqEAvJ/RM+WAwVv6EGtu31r7OH0AMtSr5Rvg4BAYK1L2use9ezr79u+ZVv9+AFlNcp0UUpiqAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5AsHADIRLMaOHwAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAPUExURQAAAIqKioyNjY2OjvDw8L2y1DEAAAABdFJOUwBA5thmAAAAAWJLR0QB/wIt3gAAAGNJREFUSMdjYCAJsLi4OBCQx6/CBQwIGIDPCBcXAkYQUsACU+AwlBVQHg6Eg5pgZBGOboIJZugDFwRwoJECJCUOhJI1wZwzqmBUwagCuipgIqTABG9h7YIKaKGAURAFEF/6AQAO4HqSoDP8bgAAAABJRU5ErkJggg==);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.infobar .infobar-link-icon {
|
|
131
|
+
background-size: 60%;
|
|
132
|
+
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAgMAAADXB5lNAAABhmlDQ1BJQ0MgcHJvZmlsZQAAKJF9kj1Iw0AYht+mSkUrDnYQcchQnSyIijqWKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjx4LiH9+59+e67A4RGhalm1wSgapaRisfEbG5VDLyiDwEAvZiVmKkn0osZeI6ve/j4ehfhWd7n/hz9St5kgE8kjjLdsIg3iGc2LZ3zPnGIlSSF+Jx43KACiR+5Lrv8xrnosMAzQ0YmNU8cIhaLHSx3MCsZKvE0cVhRNcoXsi4rnLc4q5Uaa9XJbxjMaytprtMcQRxLSCAJETJqKKMCCxFaNVJMpGg/5uEfdvxJcsnkKoORYwFVqJAcP/gb/O6tWZiadJOCMaD7xbY/RoHALtCs2/b3sW03TwD/M3Cltf3VBjD3SXq9rYWPgIFt4OK6rcl7wOUOMPSkS4bkSH6aQqEAvJ/RM+WAwVv6EGtu31r7OH0AMtSr5Rvg4BAYK1L2use9ezr79u+ZVv9+AFlNcp0UUpiqAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5AsHAB8H+DhhoQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAJUExURQAAAICHi4qKioTuJAkAAAABdFJOUwBA5thmAAAAAWJLR0QCZgt8ZAAAAJJJREFUOI3t070NRCEMA2CnYAOyDyPwpHj/Va7hJ3FzV7zy3ET5JIwoAF6Jk4wzAJAkzxAYG9YRTgB+24wBgKmfrGAKTcEfAY4KRlRoIeBTgKOCERVaCPgU4Khge2GqKOBTgKOCERVaAEC/4PNcnyoSWHpjqkhwKxbcig0Q6AorXYF/+A6eIYD1lVbwG/jdA6/kA2THRAURVubcAAAAAElFTkSuQmCC);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.infobar .infobar-close-icon {
|
|
136
|
+
appearance: none;
|
|
137
|
+
background-size: 80%;
|
|
138
|
+
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAgMAAADXB5lNAAABhmlDQ1BJQ0MgcHJvZmlsZQAAKJF9kj1Iw0AYht+mSkUrDnYQcchQnSyIijqWKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjx4LiH9+59+e67A4RGhalm1wSgapaRisfEbG5VDLyiDwEAvZiVmKkn0osZeI6ve/j4ehfhWd7n/hz9St5kgE8kjjLdsIg3iGc2LZ3zPnGIlSSF+Jx43KACiR+5Lrv8xrnosMAzQ0YmNU8cIhaLHSx3MCsZKvE0cVhRNcoXsi4rnLc4q5Uaa9XJbxjMaytprtMcQRxLSCAJETJqKKMCCxFaNVJMpGg/5uEfdvxJcsnkKoORYwFVqJAcP/gb/O6tWZiadJOCMaD7xbY/RoHALtCs2/b3sW03TwD/M3Cltf3VBjD3SXq9rYWPgIFt4OK6rcl7wOUOMPSkS4bkSH6aQqEAvJ/RM+WAwVv6EGtu31r7OH0AMtSr5Rvg4BAYK1L2use9ezr79u+ZVv9+AFlNcp0UUpiqAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH5AsHAB8VC4EQ6QAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAAJUExURQAAAICHi4qKioTuJAkAAAABdFJOUwBA5thmAAAAAWJLR0QCZgt8ZAAAAJtJREFUOI3NkrsBgCAMRLFwBPdxBArcfxXFkO8rbKWAAJfHJ9faf9vuYX/749T5NmShm3bEwbe2SxeuM4+2oxDL1cDoKtVUjRy+tH78Cv2CS+wIiQNC1AEhk4AQeUTMWUJMfUJMSEJMSEY8kIx4IONroaYAimNxsXp1PA7PxwfVL8QnowwoVC0lig07wDDVUjAdbAnjwtow/z/bDW7eI4M2KruJAAAAAElFTkSuQmCC);
|
|
139
|
+
}
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
export { displayIcon, appendInfobar, refreshInfobarInfo, extractInfobarData, INFOBAR_TAGNAME };
|
|
143
|
+
|
|
144
|
+
function appendInfobar(doc, options, useShadowRoot) {
|
|
145
|
+
if (!doc.querySelector(INFOBAR_TAGNAME)) {
|
|
146
|
+
let infoData = options.infobarContent ? options.infobarContent : options.saveDate;
|
|
147
|
+
infoData = infoData || "No info";
|
|
148
|
+
const infobarElement = createElement(doc, INFOBAR_TAGNAME, doc.body);
|
|
149
|
+
let infobarContainer;
|
|
150
|
+
if (useShadowRoot) {
|
|
151
|
+
infobarContainer = infobarElement.attachShadow({ mode: "open" });
|
|
152
|
+
} else {
|
|
153
|
+
const shadowRootTemplate = doc.createElement("template");
|
|
154
|
+
shadowRootTemplate.setAttribute("shadowroot", "open");
|
|
155
|
+
infobarElement.appendChild(shadowRootTemplate);
|
|
156
|
+
infobarContainer = shadowRootTemplate;
|
|
157
|
+
}
|
|
158
|
+
const shadowRootContent = doc.createElement("div");
|
|
159
|
+
const styleElement = doc.createElement("style");
|
|
160
|
+
styleElement.textContent = INFOBAR_STYLES
|
|
161
|
+
.replace(/ {2}/g, "")
|
|
162
|
+
.replace(/\n/g, "")
|
|
163
|
+
.replace(/: /g, ":")
|
|
164
|
+
.replace(/, /g, ",");
|
|
165
|
+
shadowRootContent.appendChild(styleElement);
|
|
166
|
+
const infobarContent = doc.createElement("form");
|
|
167
|
+
infobarContent.classList.add("infobar");
|
|
168
|
+
shadowRootContent.appendChild(infobarContent);
|
|
169
|
+
const iconElement = doc.createElement("span");
|
|
170
|
+
iconElement.tabIndex = -1;
|
|
171
|
+
iconElement.classList.add("infobar-icon");
|
|
172
|
+
infobarContent.appendChild(iconElement);
|
|
173
|
+
const contentElement = doc.createElement("span");
|
|
174
|
+
contentElement.tabIndex = -1;
|
|
175
|
+
contentElement.classList.add("infobar-content");
|
|
176
|
+
const closeButtonElement = doc.createElement("input");
|
|
177
|
+
closeButtonElement.type = "checkbox";
|
|
178
|
+
closeButtonElement.required = true;
|
|
179
|
+
closeButtonElement.classList.add("infobar-close-icon");
|
|
180
|
+
contentElement.appendChild(closeButtonElement);
|
|
181
|
+
const textElement = doc.createElement("span");
|
|
182
|
+
textElement.textContent = infoData;
|
|
183
|
+
contentElement.appendChild(textElement);
|
|
184
|
+
const linkElement = doc.createElement("a");
|
|
185
|
+
linkElement.classList.add("infobar-link-icon");
|
|
186
|
+
linkElement.target = "_blank";
|
|
187
|
+
linkElement.rel = "noopener noreferrer";
|
|
188
|
+
linkElement.title = "Open source URL: " + options.saveUrl;
|
|
189
|
+
linkElement.href = options.saveUrl;
|
|
190
|
+
contentElement.appendChild(linkElement);
|
|
191
|
+
infobarContent.appendChild(contentElement);
|
|
192
|
+
if (useShadowRoot) {
|
|
193
|
+
infobarContainer.appendChild(shadowRootContent);
|
|
194
|
+
} else {
|
|
195
|
+
const scriptElement = doc.createElement("script");
|
|
196
|
+
let scriptContent = (refreshInfobarInfo.toString());
|
|
197
|
+
scriptContent += (extractInfobarData.toString());
|
|
198
|
+
scriptContent += "refreshInfobarInfo(document, extractInfobarData(document))";
|
|
199
|
+
scriptContent = scriptContent
|
|
200
|
+
.replace(/ == /g, "==")
|
|
201
|
+
.replace(/ > /g, ">")
|
|
202
|
+
.replace(/ < /g, "<")
|
|
203
|
+
.replace(/ \+ /g, "+")
|
|
204
|
+
.replace(/ - /g, "-")
|
|
205
|
+
.replace(/ = /g, "=")
|
|
206
|
+
.replace(/ \+= /g, "+=")
|
|
207
|
+
.replace(/ && /g, "&&")
|
|
208
|
+
.replace(/ \|\| /g, "||")
|
|
209
|
+
.replace(/{ /g, "{")
|
|
210
|
+
.replace(/ }/g, "}")
|
|
211
|
+
.replace(/, /g, ",")
|
|
212
|
+
.replace(/; /g, ";")
|
|
213
|
+
.replace(/ \(/g, "(")
|
|
214
|
+
.replace(/ \)/g, ")")
|
|
215
|
+
.replace(/\t/g, "")
|
|
216
|
+
.replace(/\n/g, "");
|
|
217
|
+
scriptElement.textContent = scriptContent;
|
|
218
|
+
shadowRootContent.appendChild(scriptElement);
|
|
219
|
+
infobarContainer.innerHTML = shadowRootContent.outerHTML;
|
|
220
|
+
}
|
|
221
|
+
doc.body.appendChild(infobarElement);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function extractInfobarData(doc) {
|
|
226
|
+
const result = doc.evaluate("//comment()", doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
|
|
227
|
+
let singleFileComment = result && result.singleNodeValue;
|
|
228
|
+
if (singleFileComment && singleFileComment.nodeType == Node.COMMENT_NODE && singleFileComment.textContent.includes("SingleFile")) {
|
|
229
|
+
const info = singleFileComment.textContent.split("\n");
|
|
230
|
+
const [, , urlData, ...optionalData] = info;
|
|
231
|
+
const urlMatch = urlData.match(/^ url: (.*) ?$/);
|
|
232
|
+
const saveUrl = urlMatch && urlMatch[1];
|
|
233
|
+
if (saveUrl) {
|
|
234
|
+
let infobarContent, saveDate;
|
|
235
|
+
if (optionalData.length) {
|
|
236
|
+
saveDate = optionalData[0].split("saved date: ")[1];
|
|
237
|
+
if (saveDate) {
|
|
238
|
+
optionalData.shift();
|
|
239
|
+
}
|
|
240
|
+
if (optionalData.length > 1) {
|
|
241
|
+
let content = optionalData[0].split("info: ")[1].trim();
|
|
242
|
+
for (let indexLine = 1; indexLine < optionalData.length - 1; indexLine++) {
|
|
243
|
+
content += "\n" + optionalData[indexLine].trim();
|
|
244
|
+
}
|
|
245
|
+
infobarContent = content.trim();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return { saveUrl, infobarContent, saveDate };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function refreshInfobarInfo(doc, { saveUrl, infobarContent, saveDate }) {
|
|
254
|
+
if (saveUrl) {
|
|
255
|
+
const infobarElement = doc.querySelector("single-file-infobar");
|
|
256
|
+
const shadowRootFragment = infobarElement.shadowRoot;
|
|
257
|
+
const infobarContentElement = shadowRootFragment.querySelector(".infobar-content span");
|
|
258
|
+
infobarContentElement.textContent = infobarContent || saveDate;
|
|
259
|
+
const linkElement = shadowRootFragment.querySelector(".infobar-content .infobar-link-icon");
|
|
260
|
+
linkElement.href = saveUrl;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function displayIcon(doc, useShadowRoot) {
|
|
265
|
+
const infoData = extractInfobarData(doc);
|
|
266
|
+
if (infoData.saveUrl) {
|
|
267
|
+
appendInfobar(doc, infoData, useShadowRoot);
|
|
268
|
+
refreshInfobarInfo(doc, infoData);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function createElement(doc, tagName, parentElement) {
|
|
273
|
+
const element = doc.createElement(tagName);
|
|
274
|
+
parentElement.appendChild(element);
|
|
275
|
+
Array.from(getComputedStyle(element)).forEach(property => element.style.setProperty(property, "initial", "important"));
|
|
276
|
+
return element;
|
|
277
|
+
}
|
package/package.json
CHANGED
package/single-file-core.js
CHANGED
|
@@ -494,6 +494,15 @@ class Processor {
|
|
|
494
494
|
);
|
|
495
495
|
this.doc.documentElement.insertBefore(commentNode, this.doc.documentElement.firstChild);
|
|
496
496
|
}
|
|
497
|
+
if (this.doc.querySelector("template[" + SHADOWROOT_ATTRIBUTE_NAME + "]") || (this.options.shadowRoots && this.options.shadowRoots.length)) {
|
|
498
|
+
if (this.options.blockScripts) {
|
|
499
|
+
this.doc.querySelectorAll("script[" + SCRIPT_TEMPLATE_SHADOW_ROOT + "]").forEach(element => element.remove());
|
|
500
|
+
}
|
|
501
|
+
const scriptElement = this.doc.createElement("script");
|
|
502
|
+
scriptElement.setAttribute(SCRIPT_TEMPLATE_SHADOW_ROOT, "");
|
|
503
|
+
scriptElement.textContent = `(()=>{document.currentScript.remove();processNode(document);function processNode(node){node.querySelectorAll("template[${SHADOWROOT_ATTRIBUTE_NAME}]").forEach(element=>{let shadowRoot = element.parentElement.shadowRoot;if (!shadowRoot) {try {shadowRoot=element.parentElement.attachShadow({mode:element.getAttribute("${SHADOWROOT_ATTRIBUTE_NAME}")});shadowRoot.innerHTML=element.innerHTML;element.remove()} catch (error) {} if (shadowRoot) {processNode(shadowRoot)}}})}})()`;
|
|
504
|
+
this.doc.body.appendChild(scriptElement);
|
|
505
|
+
}
|
|
497
506
|
if (this.options.insertCanonicalLink && this.options.saveUrl.match(HTTP_URI_PREFIX)) {
|
|
498
507
|
let canonicalLink = this.doc.querySelector("link[rel=canonical]");
|
|
499
508
|
if (!canonicalLink) {
|
|
@@ -724,15 +733,16 @@ class Processor {
|
|
|
724
733
|
|
|
725
734
|
removeEmbedScripts() {
|
|
726
735
|
const JAVASCRIPT_URI_PREFIX = "javascript:";
|
|
736
|
+
const DISABLED_SCRIPT = "javascript:void(0)";
|
|
727
737
|
this.onEventAttributeNames.forEach(attributeName => this.doc.querySelectorAll("[" + attributeName + "]").forEach(element => element.removeAttribute(attributeName)));
|
|
728
738
|
this.doc.querySelectorAll("[href]").forEach(element => {
|
|
729
739
|
if (element.href && element.href.match && element.href.trim().startsWith(JAVASCRIPT_URI_PREFIX)) {
|
|
730
|
-
element.
|
|
740
|
+
element.setAttribute("href", DISABLED_SCRIPT);
|
|
731
741
|
}
|
|
732
742
|
});
|
|
733
743
|
this.doc.querySelectorAll("[src]").forEach(element => {
|
|
734
744
|
if (element.src && element.src.trim().startsWith(JAVASCRIPT_URI_PREFIX)) {
|
|
735
|
-
element.
|
|
745
|
+
element.setAttribute("src", DISABLED_SCRIPT);
|
|
736
746
|
}
|
|
737
747
|
});
|
|
738
748
|
const scriptElements = this.doc.querySelectorAll("script:not([type=\"application/ld+json\"]):not([" + SCRIPT_TEMPLATE_SHADOW_ROOT + "])");
|
|
@@ -854,9 +864,9 @@ class Processor {
|
|
|
854
864
|
}
|
|
855
865
|
|
|
856
866
|
saveFavicon() {
|
|
857
|
-
let faviconElement = this.doc.querySelector("link[href][rel=\"icon\"]");
|
|
867
|
+
let faviconElement = this.doc.querySelector("link[href][rel=\"shortcut icon\"]");
|
|
858
868
|
if (!faviconElement) {
|
|
859
|
-
faviconElement = this.doc.querySelector("link[href][rel=\"
|
|
869
|
+
faviconElement = this.doc.querySelector("link[href][rel=\"icon\"]");
|
|
860
870
|
}
|
|
861
871
|
if (!faviconElement) {
|
|
862
872
|
faviconElement = this.doc.createElement("link");
|
|
@@ -874,7 +884,11 @@ class Processor {
|
|
|
874
884
|
if (attributeValue) {
|
|
875
885
|
const canvasData = this.options.canvases[Number(attributeValue)];
|
|
876
886
|
if (canvasData) {
|
|
877
|
-
|
|
887
|
+
const backgroundStyle = {};
|
|
888
|
+
if (canvasData.backgroundColor) {
|
|
889
|
+
backgroundStyle["background-color"] = canvasData.backgroundColor;
|
|
890
|
+
}
|
|
891
|
+
ProcessorHelper.setBackgroundImage(canvasElement, "url(" + canvasData.dataURI + ")", backgroundStyle);
|
|
878
892
|
this.stats.add("processed", "canvas", 1);
|
|
879
893
|
}
|
|
880
894
|
}
|
|
@@ -1139,13 +1153,6 @@ class Processor {
|
|
|
1139
1153
|
const options = this.options;
|
|
1140
1154
|
if (options.shadowRoots && options.shadowRoots.length) {
|
|
1141
1155
|
processElement(this.doc);
|
|
1142
|
-
if (options.blockScripts) {
|
|
1143
|
-
this.doc.querySelectorAll("script[" + SCRIPT_TEMPLATE_SHADOW_ROOT + "]").forEach(element => element.remove());
|
|
1144
|
-
}
|
|
1145
|
-
const scriptElement = doc.createElement("script");
|
|
1146
|
-
scriptElement.setAttribute(SCRIPT_TEMPLATE_SHADOW_ROOT, "");
|
|
1147
|
-
scriptElement.textContent = `(()=>{document.currentScript.remove();processNode(document);function processNode(node){node.querySelectorAll("template[${SHADOWROOT_ATTRIBUTE_NAME}]").forEach(element=>{let shadowRoot = element.parentElement.shadowRoot;if (!shadowRoot) {try {shadowRoot=element.parentElement.attachShadow({mode:element.getAttribute("${SHADOWROOT_ATTRIBUTE_NAME}")});shadowRoot.innerHTML=element.innerHTML;element.remove()} catch (error) {} if (shadowRoot) {processNode(shadowRoot)}}})}})()`;
|
|
1148
|
-
doc.body.appendChild(scriptElement);
|
|
1149
1156
|
}
|
|
1150
1157
|
|
|
1151
1158
|
function processElement(element) {
|
|
@@ -1506,11 +1513,14 @@ class ProcessorHelper {
|
|
|
1506
1513
|
}
|
|
1507
1514
|
|
|
1508
1515
|
static processShortcutIcons(doc) {
|
|
1509
|
-
let shortcutIcon = findShortcutIcon(Array.from(doc.querySelectorAll("link[href][rel=\"
|
|
1516
|
+
let shortcutIcon = findShortcutIcon(Array.from(doc.querySelectorAll("link[href][rel=\"shortcut icon\"]")));
|
|
1517
|
+
if (!shortcutIcon) {
|
|
1518
|
+
shortcutIcon = findShortcutIcon(Array.from(doc.querySelectorAll("link[href][rel=\"icon\"]")));
|
|
1519
|
+
}
|
|
1510
1520
|
if (!shortcutIcon) {
|
|
1511
1521
|
shortcutIcon = findShortcutIcon(Array.from(doc.querySelectorAll("link[href][rel*=\"icon\"]")));
|
|
1512
1522
|
if (shortcutIcon) {
|
|
1513
|
-
shortcutIcon.rel = "icon";
|
|
1523
|
+
shortcutIcon.rel = "shortcut icon";
|
|
1514
1524
|
}
|
|
1515
1525
|
}
|
|
1516
1526
|
if (shortcutIcon) {
|
package/single-file-helper.js
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import * as cssUnescape from "./vendor/css-unescape.js";
|
|
27
27
|
import * as hooksFrames from "./processors/hooks/content/content-hooks-frames.js";
|
|
28
|
+
import * as infobar from "./common/infobar.js";
|
|
28
29
|
|
|
29
30
|
const ON_BEFORE_CAPTURE_EVENT_NAME = "single-file-on-before-capture";
|
|
30
31
|
const ON_AFTER_CAPTURE_EVENT_NAME = "single-file-on-after-capture";
|
|
@@ -79,6 +80,7 @@ export {
|
|
|
79
80
|
getFontWeight,
|
|
80
81
|
normalizeFontFamily,
|
|
81
82
|
getShadowRoot,
|
|
83
|
+
appendInfobar,
|
|
82
84
|
ON_BEFORE_CAPTURE_EVENT_NAME,
|
|
83
85
|
ON_AFTER_CAPTURE_EVENT_NAME,
|
|
84
86
|
WIN_ID_ATTRIBUTE_NAME,
|
|
@@ -265,7 +267,10 @@ function getResourcesInfo(win, doc, element, options, data, elementHidden, compu
|
|
|
265
267
|
const tagName = element.tagName && element.tagName.toUpperCase();
|
|
266
268
|
if (tagName == "CANVAS") {
|
|
267
269
|
try {
|
|
268
|
-
data.canvases.push({
|
|
270
|
+
data.canvases.push({
|
|
271
|
+
dataURI: element.toDataURL("image/png", ""),
|
|
272
|
+
backgroundColor: computedStyle.getPropertyValue("background-color")
|
|
273
|
+
});
|
|
269
274
|
element.setAttribute(CANVAS_ATTRIBUTE_NAME, data.canvases.length - 1);
|
|
270
275
|
data.markedElements.push(element);
|
|
271
276
|
} catch (error) {
|
|
@@ -395,6 +400,10 @@ function getShadowRoot(element) {
|
|
|
395
400
|
}
|
|
396
401
|
}
|
|
397
402
|
|
|
403
|
+
function appendInfobar(doc, options, useShadowRoot) {
|
|
404
|
+
return infobar.appendInfobar(doc, options, useShadowRoot);
|
|
405
|
+
}
|
|
406
|
+
|
|
398
407
|
function normalizeFontFamily(fontFamilyName = "") {
|
|
399
408
|
return removeQuotes(cssUnescape.process(fontFamilyName.trim())).toLowerCase();
|
|
400
409
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2010-2020 Gildas Lormeau
|
|
3
|
+
* contact : gildas.lormeau <at> gmail.com
|
|
4
|
+
*
|
|
5
|
+
* This file is part of SingleFile.
|
|
6
|
+
*
|
|
7
|
+
* The code in this file is free software: you can redistribute it and/or
|
|
8
|
+
* modify it under the terms of the GNU Affero General Public License
|
|
9
|
+
* (GNU AGPL) as published by the Free Software Foundation, either version 3
|
|
10
|
+
* of the License, or (at your option) any later version.
|
|
11
|
+
*
|
|
12
|
+
* The code in this file is distributed in the hope that it will be useful,
|
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
|
|
15
|
+
* General Public License for more details.
|
|
16
|
+
*
|
|
17
|
+
* As additional permission under GNU AGPL version 3 section 7, you may
|
|
18
|
+
* distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
|
|
19
|
+
* AGPL normally required by section 4, provided you include this license
|
|
20
|
+
* notice and a URL through which recipients can access the Corresponding
|
|
21
|
+
* Source.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import * as serializer from "./modules/html-serializer.js";
|
|
25
|
+
import * as infobar from "./common/infobar.js";
|
|
26
|
+
import { getInstance } from "./single-file-util.js";
|
|
27
|
+
|
|
28
|
+
const util = getInstance();
|
|
29
|
+
const helper = {
|
|
30
|
+
serialize(doc, compressHTML) {
|
|
31
|
+
return serializer.process(doc, compressHTML);
|
|
32
|
+
},
|
|
33
|
+
getDoctypeString(doc) {
|
|
34
|
+
return util.getDoctypeString(doc);
|
|
35
|
+
},
|
|
36
|
+
appendInfobar(doc, options, useShadowRoot) {
|
|
37
|
+
return infobar.appendInfobar(doc, options, useShadowRoot);
|
|
38
|
+
},
|
|
39
|
+
extractInfobarData(doc) {
|
|
40
|
+
return infobar.extractInfobarData(doc);
|
|
41
|
+
},
|
|
42
|
+
displayIcon(doc, useShadowRoot) {
|
|
43
|
+
return infobar.displayIcon(doc, useShadowRoot);
|
|
44
|
+
},
|
|
45
|
+
INFOBAR_TAGNAME: infobar.INFOBAR_TAGNAME
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
helper
|
|
50
|
+
};
|
package/single-file-util.js
CHANGED
|
@@ -160,6 +160,9 @@ function getInstance(utilOptions) {
|
|
|
160
160
|
removeQuotes(string) {
|
|
161
161
|
return helper.removeQuotes(string);
|
|
162
162
|
},
|
|
163
|
+
appendInfobar(doc, options) {
|
|
164
|
+
return helper.appendInfobar(doc, options);
|
|
165
|
+
},
|
|
163
166
|
ON_BEFORE_CAPTURE_EVENT_NAME: helper.ON_BEFORE_CAPTURE_EVENT_NAME,
|
|
164
167
|
ON_AFTER_CAPTURE_EVENT_NAME: helper.ON_AFTER_CAPTURE_EVENT_NAME,
|
|
165
168
|
WIN_ID_ATTRIBUTE_NAME: helper.WIN_ID_ATTRIBUTE_NAME,
|