From c2ad23daf7a2cbd252d2dc2a8df11ae8801f8f25 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 24 Jul 2025 06:21:34 +0200 Subject: [PATCH] Better synchronize lines numbers and textarea Signed-off-by: DL6ER --- scripts/js/settings-dhcp.js | 42 ++++++++++++++++++++++++++++++------- settings-dhcp.lp | 6 +++--- style/pi-hole.css | 26 +++++++++++++++++++++++ 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/scripts/js/settings-dhcp.js b/scripts/js/settings-dhcp.js index 932c10ae..3074b97c 100644 --- a/scripts/js/settings-dhcp.js +++ b/scripts/js/settings-dhcp.js @@ -255,8 +255,8 @@ function parseStaticDHCPLine(line) { // Split the line by commas and trim whitespace const parts = line.split(",").map(s => s.trim()); - // If there are more than 3 parts, it's considered advanced - if (parts.length > 3) return "advanced"; + // If there are more than 3 parts or less than 2, it's considered advanced + if (parts.length > 3 || parts.length < 2) return "advanced"; // Check if first part is a valid MAC address const haveMAC = parts.length > 0 && utils.validateMAC(parts[0]); @@ -449,11 +449,31 @@ $(document).on("click", ".copy-to-static", function () { document.addEventListener("DOMContentLoaded", function () { const textarea = document.getElementById("dhcp-hosts"); const linesElem = document.getElementById("dhcp-hosts-lines"); - function updateLineNumbers() { + let lastLineCount = 0; + + function updateLineNumbers(force) { + if (!textarea || !linesElem) return; const lines = textarea.value.split("\n").length || 1; - linesElem.innerHTML = Array.from({ length: lines }, function (_, i) { - return i + 1; - }).join("
"); + if (!force && lines === lastLineCount) return; + lastLineCount = lines; + let html = ""; + for (let i = 1; i <= lines; i++) html += i + "
"; + linesElem.innerHTML = html; + // Apply the same styles to the lines element as the textarea + for (const property of [ + "fontFamily", + "fontSize", + "fontWeight", + "letterSpacing", + "lineHeight", + "padding", + "height", + ]) { + linesElem.style[property] = globalThis.getComputedStyle(textarea)[property]; + } + + // Match height and scroll + linesElem.style.height = textarea.offsetHeight > 0 ? textarea.offsetHeight + "px" : "auto"; } function syncScroll() { @@ -461,9 +481,15 @@ document.addEventListener("DOMContentLoaded", function () { } if (textarea && linesElem) { - textarea.addEventListener("input", updateLineNumbers); + textarea.addEventListener("input", function () { + updateLineNumbers(false); + }); textarea.addEventListener("scroll", syncScroll); - updateLineNumbers(); + window.addEventListener("resize", function () { + updateLineNumbers(true); + }); + updateLineNumbers(true); + syncScroll(); } }); diff --git a/settings-dhcp.lp b/settings-dhcp.lp index 5d8780ea..6a1deba1 100644 --- a/settings-dhcp.lp +++ b/settings-dhcp.lp @@ -193,9 +193,9 @@ mg.include('scripts/lua/settings_header.lp','r')

Specify per host parameters for the DHCP server. This allows a machine with a particular hardware address to be always allocated the same hostname, IP address and lease time. A hostname specified like this overrides any supplied by the DHCP client on the machine. It is also allowable to omit the hardware address and include the hostname, in which case the IP address and lease times will apply to any machine claiming that name.

-
- - +
+ +

Each entry should be on a separate line, and should be of the form:

[<hwaddr>][,id:<client_id>|*][,set:<tag>][,tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
diff --git a/style/pi-hole.css b/style/pi-hole.css index ca2dcc4f..3551d4be 100644 --- a/style/pi-hole.css +++ b/style/pi-hole.css @@ -1583,6 +1583,32 @@ textarea.field-sizing-content { field-sizing: content; } +textarea.no-wrap { + white-space: pre; + overflow-x: auto; + overflow-y: auto; + resize: none; +} + +div.line-numbers { + user-select: none; + text-align: right; + color: #aaa; + border-right: 1px solid #ddd; + padding: 8px 4px 8px 0; + font-family: monospace; + font-size: 13px; + min-width: 2em; + overflow-x: hidden; + overflow-y: hidden; +} + +div.dhcp-hosts-wrapper { + position: relative; + display: flex; + gap: 0.5em; +} + /* Used in interfaces page */ .list-group-item { background: transparent;