"ignore" and "once" attributes, improved performance
This commit is contained in:
parent
f4d37ebf3a
commit
6074da9a52
343
reinitializer.js
343
reinitializer.js
|
@ -1,181 +1,244 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
if (typeof window.reinitializer !== "function") {
|
if (typeof window.reinitializer !== "function") {
|
||||||
// Not initialized
|
// Not initialized
|
||||||
|
|
||||||
// Initialize of the class in global namespace
|
// Initialize of the class in global namespace
|
||||||
window.reinitializer = class reinitializer {
|
window.reinitializer = class reinitializer {
|
||||||
/**
|
/**
|
||||||
* Parent element for location <link> elements
|
* Parent element for location <link> elements
|
||||||
*/
|
*/
|
||||||
css = document.head;
|
css = document.head;
|
||||||
|
|
||||||
/**
|
|
||||||
* Parent element for location <script> elements
|
|
||||||
*/
|
|
||||||
js = document.body;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Target element for searching new <link> and <script> elements
|
* Parent element for location <script> elements
|
||||||
*/
|
*/
|
||||||
root = document.body.getElementsByTagName("main")[0];
|
js = document.body;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instance of the observer
|
* Target element for searching new <link> and <script> elements
|
||||||
*/
|
*/
|
||||||
observer = new MutationObserver(() => this.handle(this.root));
|
root = document.body.getElementsByTagName("main")[0];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct
|
* Instance of the observer
|
||||||
*
|
*/
|
||||||
* @param {object} root Entry point
|
observer = new MutationObserver(() => this.handle(this.root));
|
||||||
*/
|
|
||||||
constructor(root) {
|
|
||||||
// Initialize of the root element
|
|
||||||
this.root = root ?? this.root;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reinitialize <link> and <script> elements
|
* Construct
|
||||||
*
|
*
|
||||||
* @return {bool} Processing status
|
* @param {object} root Entry point
|
||||||
*/
|
*/
|
||||||
handle() {
|
constructor(root) {
|
||||||
// Check for a dublicate execute launch
|
// Initialize of the root element
|
||||||
if (this.started) return false;
|
this.root = root ?? this.root;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialization an observation status
|
/**
|
||||||
this.started = true;
|
* Reinitialize <link> and <script> elements
|
||||||
|
*
|
||||||
|
* @return {bool} Processing status
|
||||||
|
*/
|
||||||
|
handle() {
|
||||||
|
// Check for a dublicate execute launch
|
||||||
|
if (this.started) return false;
|
||||||
|
|
||||||
for (
|
// Initialization an observation status
|
||||||
let links;
|
this.started = true;
|
||||||
(links = this.root.getElementsByTagName("link")).length > 0;
|
|
||||||
) {
|
|
||||||
// Enumeration <link> elements
|
|
||||||
|
|
||||||
// Initialization of the <link> element
|
for (
|
||||||
const link = links[0];
|
let links;
|
||||||
|
(links = this.root.getElementsByTagName("link")).length > 0;
|
||||||
|
) {
|
||||||
|
// Enumeration <link> elements
|
||||||
|
|
||||||
// Initialization link of the <link> element
|
// Initialization of the <link> element
|
||||||
const href = link.getAttribute("href");
|
const link = links[0];
|
||||||
|
|
||||||
// Stop listening
|
if (link.getAttribute("data-reinitializer-ignore") === "true") {
|
||||||
this.stop();
|
// Marked as ignored
|
||||||
|
|
||||||
// Delete outdated <link> element from the document
|
// Move element
|
||||||
link.remove();
|
this.css.appendChild(link);
|
||||||
|
|
||||||
// Start listening
|
continue;
|
||||||
this.start();
|
}
|
||||||
|
|
||||||
// Deleting outdated elements
|
// Initialization link of the <link> element
|
||||||
for (
|
const href = link.getAttribute("href");
|
||||||
const element of this.css.querySelectorAll(
|
|
||||||
`script[href="${href}"]`,
|
|
||||||
)
|
|
||||||
) element.remove();
|
|
||||||
|
|
||||||
// Initialization of new <link> element
|
if (
|
||||||
const element = document.createElement("link");
|
link.getAttribute("data-reinitializer-once") === "true" &&
|
||||||
element.setAttribute("href", href);
|
this.css.querySelector(`:scope > link[href="${href}"]`)
|
||||||
element.setAttribute("rel", "stylesheet");
|
) {
|
||||||
|
// Marked as executing once and already executed
|
||||||
|
|
||||||
// Write new element
|
// Stop listening
|
||||||
this.css.appendChild(element);
|
this.stop();
|
||||||
}
|
|
||||||
|
|
||||||
for (
|
// Delete outdated <link> element from the document
|
||||||
let scripts;
|
link.remove();
|
||||||
(scripts = this.root.getElementsByTagName("script")).length > 0;
|
|
||||||
) {
|
|
||||||
// Enumeration of <script> elements
|
|
||||||
|
|
||||||
// Initialization of the <script> element
|
// Start listening
|
||||||
const script = scripts[0];
|
this.start();
|
||||||
|
|
||||||
// Initialization link of the <script> element
|
continue;
|
||||||
const src = script.getAttribute("src");
|
}
|
||||||
|
|
||||||
// Initialization text of the <script> element
|
// Initialization outerHTML of the <script> element
|
||||||
const text = script.textContent;
|
const html = script.outerHTML;
|
||||||
|
|
||||||
// Stop listening
|
// Stop listening
|
||||||
this.stop();
|
this.stop();
|
||||||
|
|
||||||
// Delete outdated <script> element from the document
|
// Delete outdated <link> element from the document
|
||||||
script.remove();
|
link.remove();
|
||||||
|
|
||||||
// Start listening
|
// Start listening
|
||||||
this.start();
|
this.start();
|
||||||
|
|
||||||
// Initialization of new <script> element
|
// Deleting outdated elements
|
||||||
const element = document.createElement("script");
|
for (const element of this.css.querySelectorAll(
|
||||||
|
`:scope > link[href="${href}"]`
|
||||||
|
)) element.remove();
|
||||||
|
|
||||||
if (typeof src === "string") {
|
// Initialization of new <link> element
|
||||||
// File
|
const element = document.createElement("link");
|
||||||
|
element.setAttribute("href", href);
|
||||||
|
element.setAttribute("rel", "stylesheet");
|
||||||
|
|
||||||
// Deleting outdated elements
|
// Write new element
|
||||||
for (
|
this.css.appendChild(element);
|
||||||
const element of this.js.querySelectorAll(
|
}
|
||||||
`script[src="${src}"]`,
|
|
||||||
)
|
|
||||||
) element.remove();
|
|
||||||
|
|
||||||
// Copy link from outdated <script> element
|
for (
|
||||||
element.setAttribute("src", src);
|
let scripts;
|
||||||
} else {
|
(scripts = this.root.getElementsByTagName("script")).length > 0;
|
||||||
// Script
|
) {
|
||||||
|
// Enumeration of <script> elements
|
||||||
|
|
||||||
// Deleting outdated elements
|
// Initialization of the <script> element
|
||||||
for (
|
const script = scripts[0];
|
||||||
const element of Array.from(
|
|
||||||
this.js.getElementsByTagName("script"),
|
|
||||||
)
|
|
||||||
.filter((e) => e.textContent === text)
|
|
||||||
) {
|
|
||||||
element.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy text from outdated <script> element
|
if (script.getAttribute("data-reinitializer-ignore") === "true") {
|
||||||
element.textContent = text;
|
// Marked as ignored
|
||||||
}
|
|
||||||
|
|
||||||
// Write new <script> element to end of <body> element
|
// Move element
|
||||||
this.js.appendChild(element);
|
this.js.appendChild(script);
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize of observation status
|
continue;
|
||||||
this.started = false;
|
}
|
||||||
|
|
||||||
// Return (success)
|
// Initialization link of the <script> element
|
||||||
return true;
|
const src = script.getAttribute("src");
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Initialization text of the <script> element
|
||||||
* Start observation
|
const text = script.textContent;
|
||||||
*
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
start() {
|
|
||||||
this.observer.observe(this.root, {
|
|
||||||
childList: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (
|
||||||
* Stop observation
|
script.getAttribute("data-reinitializer-once") === "true" &&
|
||||||
*
|
(this.js.querySelector(`:scope > script[src="${src}"]`) ||
|
||||||
* @return {void}
|
Array.from(this.js.querySelectorAll(`:scope > script`)).filter(
|
||||||
*/
|
(e) => e.textContent === text
|
||||||
stop() {
|
).length > 0)
|
||||||
this.observer.disconnect();
|
) {
|
||||||
}
|
// Marked as executing once and already executed
|
||||||
};
|
|
||||||
|
// Stop listening
|
||||||
|
this.stop();
|
||||||
|
|
||||||
|
// Delete outdated <script> element from the document
|
||||||
|
script.remove();
|
||||||
|
|
||||||
|
// Start listening
|
||||||
|
this.start();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialization outerHTML of the <script> element
|
||||||
|
const html = script.outerHTML;
|
||||||
|
|
||||||
|
// Stop listening
|
||||||
|
this.stop();
|
||||||
|
|
||||||
|
// Delete outdated <script> element from the document
|
||||||
|
script.remove();
|
||||||
|
|
||||||
|
// Start listening
|
||||||
|
this.start();
|
||||||
|
|
||||||
|
// Initialization of new <script> element
|
||||||
|
const element = document.createElement("script");
|
||||||
|
|
||||||
|
if (typeof src === "string") {
|
||||||
|
// File
|
||||||
|
|
||||||
|
// Deleting outdated elements
|
||||||
|
for (const element of this.js.querySelectorAll(
|
||||||
|
`:scope > script[src="${src}"]`
|
||||||
|
))
|
||||||
|
element.remove();
|
||||||
|
|
||||||
|
// Copy link from outdated <script> element
|
||||||
|
element.setAttribute("src", src);
|
||||||
|
|
||||||
|
// Write a type of <script> element
|
||||||
|
element.setAttribute('type', 'text/javascript');
|
||||||
|
} else {
|
||||||
|
// Script
|
||||||
|
|
||||||
|
// Deleting outdated elements
|
||||||
|
for (const element of Array.from(
|
||||||
|
this.js.querySelectorAll(`:scope > script`)
|
||||||
|
).filter((e) => e.textContent === text)) {
|
||||||
|
element.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy text from outdated <script> element
|
||||||
|
element.textContent = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the new <script> element to end of <body> element
|
||||||
|
this.js.appendChild(element);
|
||||||
|
|
||||||
|
// Write content to the new <script> element
|
||||||
|
element.outerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize of observation status
|
||||||
|
this.started = false;
|
||||||
|
|
||||||
|
// Return (success)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start observation
|
||||||
|
*
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
start() {
|
||||||
|
this.observer.observe(this.root, {
|
||||||
|
childList: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop observation
|
||||||
|
*
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
stop() {
|
||||||
|
this.observer.disconnect();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Вызов события: "инициализировано"
|
// Вызов события: "инициализировано"
|
||||||
document.dispatchEvent(
|
document.dispatchEvent(
|
||||||
new CustomEvent("reinitializer.initialized", {
|
new CustomEvent("reinitializer.initialized", {
|
||||||
detail: { reinitializer: window.reinitializer },
|
detail: { reinitializer: window.reinitializer },
|
||||||
}),
|
})
|
||||||
);
|
);
|
Loading…
Reference in New Issue