Files
web/scripts/lua/header.lp
T
0153772cf5 Swap remaining jQuery plugins for Bootstrap 5-compatible versions
- DataTables: replace the combined BS3 download-builder bundles with
  the official core + Bootstrap 5 styling-adapter package pairs
  (datatables.net(-buttons/-select) + datatables.net-bs5/-buttons-bs5/
  -select-bs5), loaded core-then-adapter.
- bootstrap-select -> Tom Select: bootstrap-select has no Bootstrap 5
  build. Add utils.createGroupSelect(), a small wrapper around Tom
  Select that recreates bootstrap-select's actionsBox (Select all/
  Select none) via a couple of buttons injected into the dropdown, and
  use it for all four "assign to group(s)" multi-selects (groups,
  groups/clients, groups/domains, groups/lists). Two behavioral fixes
  were needed to match the old widget: `hideSelected: false` (Tom
  Select refuses to open its dropdown once every option is already
  selected, which made the actions box unreachable) and
  `dropdownParent: "body"` (otherwise the dropdown is clipped by the
  surrounding .table-responsive/.card ancestors' overflow, same reason
  bootstrap-select was configured with container: "body").
- bootstrap-toggle -> bootstrap5-toggle: drop-in replacement, same
  $.fn.bootstrapToggle() API and onstyle/offstyle option names (all
  call sites already used Bootstrap 5-valid color names).
- select2: bump to 4.1.0 and add the select2-bootstrap-5-theme package
  for correct Bootstrap 5 styling; wire theme: "bootstrap-5" into both
  call sites.
- Remove now-dead bootstrap-select cleanup code (the
  "$('body > .bootstrap-select.dropdown').remove()" DataTables
  drawCallback lines across 8 files) and dead icheck/bootstrap-select
  CSS in pi-hole.css.

Also fixed a Phase 1 regression surfaced by this pass: utils.js's
loadingOverlay() still targeted the old ".wrapper" class instead of
".app-wrapper", throwing whenever a settings page triggered the
Save & Apply overlay.

Verified against a live container: groups/clients' per-row Tom Select
multiselect (open dropdown, Select all/none, Apply, restore-on-cancel),
bootstrap5-toggle switches on groups, select2 filters on the query log,
and DataTables' select/export button row on groups/lists all work with
zero console errors. Settings pages' Save & Apply overlay confirmed
fixed and no longer throwing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Adam Warner <me@adamwarner.co.uk>
2026-07-17 22:39:57 +01:00

136 lines
6.0 KiB
Lua

<!doctype html>
<!--
* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license.
-->
<?
starttime = mg.time(true)
hostname = pihole.hostname()
webhome = pihole.webhome()
theme = pihole.webtheme()
-- Get name of script by matching whatever is after the last "/" in the URI
scriptname = mg.script_name:match(".*/(.*).lp$"):gsub("-", "/")
-- Fall back to "index.lp" if no match is found (e.g. when accessing the root)
if scriptname == nil or string.len(scriptname) == 0 then scriptname = "index.lp" end
-- Boolean check if string starts with a given prefix
function startsWith(text, prefix)
return text:find(prefix, 1, true) == 1
end
-- Function returning GET parameter value (or nil if not set)
function GET(name)
if not mg.request_info.query_string then
return nil
end
return mg.request_info.query_string:match(name.."=([^&]*)")
-- mg.get_var(mg.request_info.query_string, "REQUEST_URI")
end
-- Function checking if val is in tab
function in_array (val, tab)
for index, value in ipairs(tab) do
if value == val then
return true
end
end
return false
end
-- Function to sanitize hostname containing invalid HTML characters
function sanitize_hostname(str)
return str:gsub("[&<>\"']", {
["&"] = "&amp;",
["<"] = "&lt;",
[">"] = "&gt;",
['"'] = "&quot;",
["'"] = "&#039;"
})
end
-- Sanitize hostname
hostname = sanitize_hostname(hostname)
-- Variable to check if user is already authenticated
is_authenticated = mg.request_info.is_authenticated
?>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pi-hole <?=hostname?></title>
<meta name="csrf-token" content="<?=mg.request_info.csrf_token?>">
<link rel="apple-touch-icon" href="<?=webhome?>img/favicons/apple-touch-icon.png" sizes="180x180">
<link rel="icon" href="<?=webhome?>img/favicons/favicon-32x32.png" sizes="32x32" type="image/png">
<link rel="icon" href="<?=webhome?>img/favicons/favicon-16x16.png" sizes="16x16" type="image/png">
<link rel="manifest" href="<?=webhome?>img/favicons/manifest.json">
<link rel="mask-icon" href="<?=webhome?>img/favicons/safari-pinned-tab.svg" color="<?=theme.color?>">
<link rel="shortcut icon" href="<?=webhome?>img/favicons/favicon.ico">
<meta name="msapplication-TileColor" content="<?=theme.color?>">
<meta name="msapplication-TileImage" content="<?=webhome?>img/favicons/mstile-150x150.png">
<meta name="theme-color" content="<?=theme.color?>">
<!-- Theme fonts -->
<? if theme.name == 'lcars' then ?>
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/fonts/ubuntu-mono/ubuntu-mono.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/fonts/antonio/antonio.css')?>">
<? else ?>
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/fonts/source-sans-pro/source-sans-pro.css')?>">
<? end ?>
<? if theme.dark then ?>
<style>
html { background-color: #000; }
</style>
<? end ?>
<!-- Common styles -->
<!-- AdminLTE.min.css already bundles Bootstrap 5, so no separate Bootstrap CSS is needed -->
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/adminLTE/adminlte.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/animate/animate.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/font-awesome/css/all.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/nprogress/nprogress.min.css')?>">
<? if is_authenticated then ?>
<? if startsWith(scriptname, 'groups') then ?>
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/tom-select/tom-select.bootstrap5.min.css')?>">
<? end ?>
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/bstreeview/bstreeview.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/datatables/dataTables.bootstrap5.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/datatables-buttons/buttons.bootstrap5.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/datatables-select/select.bootstrap5.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/daterangepicker/daterangepicker.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/bootstrap5-toggle/bootstrap5-toggle.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/waitMe-js/waitMe.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/select2/select2.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/select2/select2-bootstrap-5-theme.min.css')?>">
<? end ?>
<!-- Theme styles (<?= theme.name ?>) -->
<link rel="stylesheet" href="<?=pihole.fileversion('style/pi-hole.css')?>">
<? if theme.name == "default-auto" then ?>
<link rel="stylesheet" href="<?=pihole.fileversion('style/themes/default-dark.css')?>" media="(prefers-color-scheme: dark)">
<link rel="stylesheet" href="<?=pihole.fileversion('style/themes/default-light.css')?>" media="not (prefers-color-scheme: dark)">
<? else ?>
<link rel="stylesheet" href="<?=pihole.fileversion('style/themes/' ..theme.name.. '.css')?>">
<? end ?>
<noscript><link rel="stylesheet" href="<?=pihole.fileversion('vendor/js-warn/js-warn.css')?>"></noscript>
<!-- scripts -->
<script src="<?=pihole.fileversion('vendor/jquery/jquery.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/bootstrap/js/bootstrap.bundle.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/adminLTE/adminlte.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/nprogress/nprogress.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/utils.js')?>"></script>