mirror of
https://github.com/pi-hole/web.git
synced 2025-12-20 02:38:28 +00:00
gravity: convert to vanilla JS and refactor code
Only the alerts are using jQuery for now Signed-off-by: XhmikosR <xhmikosr@gmail.com>
This commit is contained in:
@@ -15,17 +15,17 @@ mg.include('scripts/lua/header_authenticated.lp','r')
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Alerts -->
|
<!-- Alerts -->
|
||||||
<div id="alInfo" class="alert alert-info alert-dismissible fade in" role="alert" hidden>
|
<div id="alertInfo" class="alert alert-info alert-dismissible fade in" role="alert" hidden>
|
||||||
<button type="button" class="close" data-hide="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
<button type="button" class="close" data-hide="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
Updating... this may take a while. <strong>Please do not navigate away from or close this page.</strong>
|
Updating... this may take a while. <strong>Please do not navigate away from or close this page.</strong>
|
||||||
</div>
|
</div>
|
||||||
<div id="alSuccess" class="alert alert-success alert-dismissible fade in" role="alert" hidden>
|
<div id="alertSuccess" class="alert alert-success alert-dismissible fade in" role="alert" hidden>
|
||||||
<button type="button" class="close" data-hide="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
<button type="button" class="close" data-hide="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
Success!
|
Success!
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" id="gravityBtn" class="btn btn-lg btn-primary btn-block">Update</button>
|
<button type="button" id="gravityBtn" class="btn btn-lg btn-primary btn-block">Update</button>
|
||||||
<pre id="output" style="width: 100%; height: 100%;" hidden></pre>
|
<pre id="output" class="d-none"></pre>
|
||||||
|
|
||||||
<script src="<?=pihole.fileversion('scripts/js/gravity.js')?>"></script>
|
<script src="<?=pihole.fileversion('scripts/js/gravity.js')?>"></script>
|
||||||
<? mg.include('scripts/lua/footer.lp','r')?>
|
<? mg.include('scripts/lua/footer.lp','r')?>
|
||||||
|
|||||||
@@ -5,76 +5,88 @@
|
|||||||
* This file is copyright under the latest version of the EUPL.
|
* This file is copyright under the latest version of the EUPL.
|
||||||
* Please see LICENSE file for your rights under this license. */
|
* Please see LICENSE file for your rights under this license. */
|
||||||
|
|
||||||
|
/* global apiFailure:false */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function eventsource() {
|
function eventsource() {
|
||||||
const alInfo = $("#alInfo");
|
const $alertInfo = $("#alertInfo");
|
||||||
const alSuccess = $("#alSuccess");
|
const $alertSuccess = $("#alertSuccess");
|
||||||
const ta = $("#output");
|
const outputElement = document.getElementById("output");
|
||||||
|
const gravityBtn = document.getElementById("gravityBtn");
|
||||||
|
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute("content");
|
||||||
|
const url = `${document.body.dataset.apiurl}/action/gravity`;
|
||||||
|
|
||||||
ta.html("");
|
if (outputElement.innerHTML.length > 0) {
|
||||||
ta.show();
|
outputElement.innerHTML = "";
|
||||||
alInfo.show();
|
}
|
||||||
alSuccess.hide();
|
|
||||||
|
|
||||||
fetch(document.body.dataset.apiurl + "/action/gravity", {
|
if (!outputElement.classList.contains("d-none")) {
|
||||||
|
outputElement.classList.add("d-none");
|
||||||
|
}
|
||||||
|
|
||||||
|
$alertSuccess.hide();
|
||||||
|
$alertInfo.show();
|
||||||
|
|
||||||
|
fetch(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") },
|
headers: { "X-CSRF-TOKEN": csrfToken },
|
||||||
})
|
})
|
||||||
// Retrieve its body as ReadableStream
|
.then(response => (response.ok ? response : apiFailure(response)))
|
||||||
|
// Retrieve the response as ReadableStream
|
||||||
.then(response => {
|
.then(response => {
|
||||||
const reader = response.body.getReader();
|
return handleResponseStream({
|
||||||
return new ReadableStream({
|
response,
|
||||||
start(controller) {
|
outputElement,
|
||||||
return pump();
|
alertInfo: $alertInfo,
|
||||||
function pump() {
|
gravityBtn,
|
||||||
return reader.read().then(({ done, value }) => {
|
alertSuccess: $alertSuccess,
|
||||||
// When no more data needs to be consumed, close the stream
|
|
||||||
if (done) {
|
|
||||||
controller.close();
|
|
||||||
alInfo.hide();
|
|
||||||
$("#gravityBtn").prop("disabled", false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enqueue the next data chunk into our target stream
|
|
||||||
controller.enqueue(value);
|
|
||||||
const string = new TextDecoder().decode(value);
|
|
||||||
parseLines(ta, string);
|
|
||||||
|
|
||||||
if (string.includes("Done.")) {
|
|
||||||
alSuccess.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
return pump();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(error => console.error(error)); // eslint-disable-line no-console
|
.catch(error => console.error(error)); // eslint-disable-line no-console
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#gravityBtn").on("click", () => {
|
function handleResponseStream({ response, outputElement, alertInfo, gravityBtn, alertSuccess }) {
|
||||||
$("#gravityBtn").prop("disabled", true);
|
outputElement.classList.remove("d-none");
|
||||||
eventsource();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle hiding of alerts
|
const reader = response.body.getReader();
|
||||||
$(() => {
|
|
||||||
$("[data-hide]").on("click", function () {
|
function pump(controller) {
|
||||||
$(this)
|
return reader.read().then(({ done, value }) => {
|
||||||
.closest("." + $(this).attr("data-hide"))
|
// When no more data needs to be consumed, close the stream
|
||||||
.hide();
|
if (done) {
|
||||||
|
controller.close();
|
||||||
|
alertInfo.hide();
|
||||||
|
gravityBtn.removeAttribute("disabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enqueue the next data chunk into our target stream
|
||||||
|
controller.enqueue(value);
|
||||||
|
const text = new TextDecoder().decode(value);
|
||||||
|
parseLines(outputElement, text);
|
||||||
|
|
||||||
|
if (text.includes("Done.")) {
|
||||||
|
alertSuccess.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
return pump(controller);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
function parseLines(ta, str) {
|
return new ReadableStream({
|
||||||
// str can contain multiple lines.
|
start(controller) {
|
||||||
|
return pump(controller);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseLines(outputElement, text) {
|
||||||
|
// text can contain multiple lines.
|
||||||
// We want to split the text before an "OVER" escape sequence to allow overwriting previous line when needed
|
// We want to split the text before an "OVER" escape sequence to allow overwriting previous line when needed
|
||||||
|
|
||||||
// Splitting the text on "\r"
|
// Splitting the text on "\r"
|
||||||
const lines = str.split(/(?=\r)/g);
|
const lines = text.split(/(?=\r)/g);
|
||||||
|
|
||||||
for (let line of lines) {
|
for (let line of lines) {
|
||||||
if (line[0] === "\r") {
|
if (line[0] === "\r") {
|
||||||
@@ -82,7 +94,8 @@ function parseLines(ta, str) {
|
|||||||
line = line.replaceAll("\r[K", "\n").replaceAll("\r", "\n");
|
line = line.replaceAll("\r[K", "\n").replaceAll("\r", "\n");
|
||||||
|
|
||||||
// Last line from the textarea will be overwritten, so we remove it
|
// Last line from the textarea will be overwritten, so we remove it
|
||||||
ta.html(ta.html().substring(0, ta.html().lastIndexOf("\n")));
|
const lastLineIndex = outputElement.innerHTML.lastIndexOf("\n");
|
||||||
|
outputElement.innerHTML = outputElement.innerHTML.substring(0, lastLineIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track the number of opening spans
|
// Track the number of opening spans
|
||||||
@@ -125,6 +138,25 @@ function parseLines(ta, str) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Append the new text to the end of the output
|
// Append the new text to the end of the output
|
||||||
ta.append(line);
|
outputElement.append(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
const gravityBtn = document.getElementById("gravityBtn");
|
||||||
|
|
||||||
|
gravityBtn.addEventListener("click", () => {
|
||||||
|
gravityBtn.disabled = true;
|
||||||
|
eventsource();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle hiding of alerts
|
||||||
|
const dataHideElements = document.querySelectorAll("[data-hide]");
|
||||||
|
for (const element of dataHideElements) {
|
||||||
|
element.addEventListener("click", () => {
|
||||||
|
const hideClass = element.dataset.hide;
|
||||||
|
const closestElement = element.closest(`.${hideClass}`);
|
||||||
|
if (closestElement) $(closestElement).hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -1046,6 +1046,8 @@ table.dataTable tbody > tr > .selected {
|
|||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
min-height: 36px;
|
min-height: 36px;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#output.pre-taillog {
|
#output.pre-taillog {
|
||||||
|
|||||||
Reference in New Issue
Block a user