diff --git a/.gitignore b/.gitignore
index 71641545..25983d20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ vendor
.env
locale/**/*.mo
app/net_activity
+app/js/plugins/
diff --git a/app/js/custom.js b/app/js/ajax/main.js
similarity index 53%
rename from app/js/custom.js
rename to app/js/ajax/main.js
index 090cc826..c9dae9ea 100644
--- a/app/js/custom.js
+++ b/app/js/ajax/main.js
@@ -1,21 +1,3 @@
-function msgShow(retcode,msg) {
- if(retcode == 0) { var alertType = 'success';
- } else if(retcode == 2 || retcode == 1) {
- var alertType = 'danger';
- }
- var htmlMsg = '
'+msg+'
';
- return htmlMsg;
-}
-
-function createNetmaskAddr(bitCount) {
- var mask=[];
- for(i=0;i<4;i++) {
- var n = Math.min(bitCount, 8);
- mask.push(256 - Math.pow(2, 8-n));
- bitCount -= n;
- }
- return mask.join('.');
-}
function loadSummary(strInterface) {
var csrfToken = $('meta[name=csrf_token]').attr('content');
@@ -38,94 +20,6 @@ function getAllInterfaces() {
});
}
-function setupTabs() {
- $('a[data-bs-toggle="tab"]').on('shown.bs.tab',function(e){
- var target = $(e.target).attr('href');
- if(!target.match('summary')) {
- var int = target.replace("#","");
- // loadCurrentSettings(int);
- }
- });
-}
-
-$(document).on("click", ".js-add-dhcp-static-lease", function(e) {
- e.preventDefault();
- var container = $(".js-new-dhcp-static-lease");
- var mac = $("input[name=mac]", container).val().trim();
- var ip = $("input[name=ip]", container).val().trim();
- var comment = $("input[name=comment]", container).val().trim();
- if (mac == "" || ip == "") {
- return;
- }
- var row = $("#js-dhcp-static-lease-row").html()
- .replace("{{ mac }}", mac)
- .replace("{{ ip }}", ip)
- .replace("{{ comment }}", comment);
- $(".js-dhcp-static-lease-container").append(row);
-
- $("input[name=mac]", container).val("");
- $("input[name=ip]", container).val("");
- $("input[name=comment]", container).val("");
-});
-
-$(document).on("click", ".js-remove-dhcp-static-lease", function(e) {
- e.preventDefault();
- $(this).parents(".js-dhcp-static-lease-row").remove();
-});
-
-$(document).on("submit", ".js-dhcp-settings-form", function(e) {
- $(".js-add-dhcp-static-lease").trigger("click");
-});
-
-$(document).on("click", ".js-add-dhcp-upstream-server", function(e) {
- e.preventDefault();
-
- var field = $("#add-dhcp-upstream-server-field")
- var row = $("#dhcp-upstream-server").html().replace("{{ server }}", field.val())
-
- if (field.val().trim() == "") { return }
-
- $(".js-dhcp-upstream-servers").append(row)
-
- field.val("")
-});
-
-$(document).on("click", ".js-remove-dhcp-upstream-server", function(e) {
- e.preventDefault();
- $(this).parents(".js-dhcp-upstream-server").remove();
-});
-
-$(document).on("submit", ".js-dhcp-settings-form", function(e) {
- $(".js-add-dhcp-upstream-server").trigger("click");
-});
-
-/**
- * mark a form field, e.g. a select box, with the class `.js-field-preset`
- * and give it an attribute `data-field-preset-target` with a text field's
- * css selector.
- *
- * now, if the element marked `.js-field-preset` receives a `change` event,
- * its value will be copied to all elements matching the selector in
- * data-field-preset-target.
- */
-$(document).on("change", ".js-field-preset", function(e) {
- var selector = this.getAttribute("data-field-preset-target")
- var value = "" + this.value
- var syncValue = function(el) { el.value = value }
-
- if (value.trim() === "") { return }
-
- document.querySelectorAll(selector).forEach(syncValue)
-});
-
-$(document).on("click", "#gen_wpa_passphrase", function(e) {
- $('#txtwpapassphrase').val(genPassword(63));
-});
-
-$(document).on("click", "#gen_apikey", function(e) {
- $('#txtapikey').val(genPassword(32).toLowerCase());
-});
-
$(document).on("click", "#js-clearhostapd-log", function(e) {
var csrfToken = $('meta[name=csrf_token]').attr('content');
$.post('ajax/logging/clearlog.php?',{'logfile':'/tmp/hostapd.log', 'csrf_token': csrfToken},function(data){
@@ -150,54 +44,6 @@ $(document).on("click", "#js-clearopenvpn-log", function(e) {
});
});
-
-// Enable Bootstrap tooltips
-$(function () {
- $('[data-bs-toggle="tooltip"]').tooltip()
-})
-
-function genPassword(pwdLen) {
- var pwdChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
- var rndPass = Array(pwdLen).fill(pwdChars).map(function(x) { return x[Math.floor(Math.random() * x.length)] }).join('');
- return rndPass;
-}
-
-function setupBtns() {
- $('#btnSummaryRefresh').click(function(){getAllInterfaces();});
- $('.intsave').click(function(){
- var int = $(this).data('int');
- saveNetworkSettings(int);
- });
- $('.intapply').click(function(){
- applyNetworkSettings();
- });
-}
-
-function setCSRFTokenHeader(event, xhr, settings) {
- var csrfToken = $('meta[name=csrf_token]').attr('content');
- if (/^(POST|PATCH|PUT|DELETE)$/i.test(settings.type)) {
- xhr.setRequestHeader("X-CSRF-Token", csrfToken);
- }
-}
-
-function contentLoaded() {
- pageCurrent = window.location.href.split("/").pop();
- switch(pageCurrent) {
- case "network_conf":
- getAllInterfaces();
- setupTabs();
- setupBtns();
- break;
- case "hostapd_conf":
- getChannel();
- setHardwareModeTooltip();
- break;
- case "dhcpd_conf":
- loadInterfaceDHCPSelect();
- break;
- }
-}
-
function loadWifiStations(refresh) {
return function() {
var complete = function() { $(this).removeClass('loading-spinner'); }
@@ -257,26 +103,6 @@ function loadInterfaceDHCPSelect() {
});
}
-function setDHCPToggles(state) {
- if ($('#chkfallback').is(':checked') && state) {
- $('#chkfallback').prop('checked', state);
- }
- if ($('#dhcp-iface').is(':checked') && !state) {
- $('#dhcp-iface').prop('checked', state);
- setDhcpFieldsDisabled();
- }
- $('#chkfallback').prop('disabled', state);
- $('#dhcp-iface').prop('disabled', !state);
-}
-
-$('#chkfallback').change(function() {
- if ($('#chkfallback').is(':checked')) {
- setStaticFieldsEnabled();
- } else {
- setStaticFieldsDisabled();
- }
-});
-
$('#debugModal').on('shown.bs.modal', function (e) {
var csrfToken = $('meta[name=csrf_token]').attr('content');
$.post('ajax/system/sys_debug.php',{'csrf_token': csrfToken},function(data){
@@ -327,10 +153,6 @@ $('#performUpdate').on('submit', function(event) {
$('#performupdateModal').modal('show');
});
-$('#performupdateModal').on('shown.bs.modal', function (e) {
- fetchUpdateResponse();
-});
-
function fetchUpdateResponse() {
const complete = 6;
const error = 7;
@@ -372,22 +194,6 @@ function fetchUpdateResponse() {
});
}
-$('#hostapdModal').on('shown.bs.modal', function (e) {
- var seconds = 3;
- var pct = 0;
- var countDown = setInterval(function(){
- if(seconds <= 0){
- clearInterval(countDown);
- }
- document.getElementsByClassName('progress-bar').item(0).setAttribute('style','width:'+Number(pct)+'%');
- seconds --;
- pct = Math.floor(100-(seconds*100/4));
- }, 500);
-});
-
-$('#configureClientModal').on('shown.bs.modal', function (e) {
-});
-
$('#ovpn-confirm-delete').on('click', '.btn-delete', function (e) {
var cfg_id = $(this).data('recordId');
var csrfToken = $('meta[name=csrf_token]').attr('content');
@@ -418,21 +224,6 @@ $('#ovpn-confirm-activate').on('click', '.btn-activate', function (e) {
});
});
-$('#ovpn-confirm-activate').on('shown.bs.modal', function (e) {
- var data = $(e.relatedTarget).data();
- $('.btn-activate', this).data('recordId', data.recordId);
-});
-
-$('#ovpn-userpw,#ovpn-certs').on('click', function (e) {
- if (this.id == 'ovpn-userpw') {
- $('#PanelCerts').hide();
- $('#PanelUserPW').show();
- } else if (this.id == 'ovpn-certs') {
- $('#PanelUserPW').hide();
- $('#PanelCerts').show();
- }
-});
-
$('#js-system-reset-confirm').on('click', function (e) {
var progressText = $('#js-system-reset-confirm').attr('data-message');
var successHtml = $('#system-reset-message').attr('data-message');
@@ -463,49 +254,6 @@ $('#js-sys-reboot, #js-sys-shutdown').on('click', function (e) {
});
});
-$('#install-user-plugin').on('shown.bs.modal', function (e) {
- var button = $(e.relatedTarget);
- $(this).data('button', button);
- var manifestData = button.data('plugin-manifest');
- var installed = button.data('plugin-installed') || false;
- var repoPublic = button.data('repo-public') || false;
- var installPath = manifestData.install_path;
-
- if (!installed && repoPublic && installPath === 'plugins-available') {
- insidersHTML = 'Available with Insiders';
- $('#plugin-additional').html(insidersHTML);
- } else {
- $('#plugin-additional').empty();
- }
- if (manifestData) {
- $('#plugin-docs').html(manifestData.plugin_docs
- ? `${manifestData.plugin_docs}`
- : 'Unknown');
- $('#plugin-icon').attr('class', `${manifestData.icon || 'fas fa-plug'} link-secondary h5 me-2`);
- $('#plugin-name').text(manifestData.name || 'Unknown');
- $('#plugin-version').text(manifestData.version || 'Unknown');
- $('#plugin-description').text(manifestData.description || 'No description provided');
- $('#plugin-author').html(manifestData.author
- ? manifestData.author + (manifestData.author_uri
- ? ` (profile)` : '') : 'Unknown');
- $('#plugin-license').text(manifestData.license || 'Unknown');
- $('#plugin-locale').text(manifestData.default_locale || 'Unknown');
- $('#plugin-configuration').html(formatProperty(manifestData.configuration || 'None'));
- $('#plugin-packages').html(formatProperty(manifestData.keys || 'None'));
- $('#plugin-dependencies').html(formatProperty(manifestData.dependencies || 'None'));
- $('#plugin-javascript').html(formatProperty(manifestData.javascript || 'None'));
- $('#plugin-sudoers').html(formatProperty(manifestData.sudoers || 'None'));
- $('#plugin-user-name').html((manifestData.user_nonprivileged && manifestData.user_nonprivileged.name) || 'None');
- }
- if (installed) {
- $('#js-install-plugin-confirm').html('OK');
- } else if (!installed && repoPublic && installPath == 'plugins-available') {
- $('#js-install-plugin-confirm').html('Get Insiders');
- } else {
- $('#js-install-plugin-confirm').html('Install now');
- }
-});
-
$('#js-install-plugin-confirm').on('click', function (e) {
var button = $('#install-user-plugin').data('button');
var manifestData = button.data('plugin-manifest');
@@ -572,75 +320,7 @@ $('#js-install-plugin-confirm').on('click', function (e) {
}
});
-$('#js-install-plugin-ok').on('click', function (e) {
- $("#install-plugin-progress").modal('hide');
- window.location.reload();
-});
-
-function formatProperty(prop) {
- if (Array.isArray(prop)) {
- if (typeof prop[0] === 'object') {
- return prop.map(item => {
- return Object.entries(item)
- .map(([key, value]) => `${key}: ${value}`)
- .join('
');
- }).join('
');
- }
- return prop.map(line => `${line}
`).join('');
- }
- if (typeof prop === 'object') {
- return Object.entries(prop)
- .map(([key, value]) => `${key}: ${value}`)
- .join('
');
- }
- return prop || 'None';
-}
-
-$(document).ready(function(){
- $("#PanelManual").hide();
- $('.ip_address').mask('0ZZ.0ZZ.0ZZ.0ZZ', {
- translation: {
- 'Z': {
- pattern: /[0-9]/, optional: true
- }
- },
- placeholder: "___.___.___.___"
- });
- $('.mac_address').mask('FF:FF:FF:FF:FF:FF', {
- translation: {
- 'F': {
- pattern: /[0-9a-fA-F]/, optional: false
- }
- },
- placeholder: "__:__:__:__:__:__"
- });
-});
-
-$(document).ready(function() {
- $('.cidr').mask('099.099.099.099/099', {
- translation: {
- '0': { pattern: /[0-9]/ }
- },
- placeholder: "___.___.___.___/___"
- });
-});
-
-$('#wg-upload,#wg-manual').on('click', function (e) {
- if (this.id == 'wg-upload') {
- $('#PanelManual').hide();
- $('#PanelUpload').show();
- } else if (this.id == 'wg-manual') {
- $('#PanelUpload').hide();
- $('#PanelManual').show();
- }
-});
-
-$(".custom-file-input").on("change", function() {
- var fileName = $(this).val().split("\\").pop();
- $(this).siblings(".custom-file-label").addClass("selected").html(fileName);
-});
-
- // Retrieves the 'channel' value specified in hostapd.conf
+// Retrieves the 'channel' value specified in hostapd.conf
function getChannel() {
$.get('ajax/networking/get_channel.php',function(data){
jsonData = JSON.parse(data);
@@ -827,22 +507,6 @@ $('.wg-client-dl').click(function(){
req.send();
})
-// Event listener for Bootstrap's form validation
-window.addEventListener('load', function() {
- // Fetch all the forms we want to apply custom Bootstrap validation styles to
- var forms = document.getElementsByClassName('needs-validation');
- // Loop over them and prevent submission
- var validation = Array.prototype.filter.call(forms, function(form) {
- form.addEventListener('submit', function(event) {
- if (form.checkValidity() === false) {
- event.preventDefault();
- event.stopPropagation();
- }
- form.classList.add('was-validated');
- }, false);
- });
-}, false);
-
let sessionCheckInterval = setInterval(checkSession, 5000);
function checkSession() {
@@ -861,249 +525,3 @@ function checkSession() {
});
}
-function showSessionExpiredModal() {
- $('#sessionTimeoutModal').modal('show');
-}
-
-$(document).on("click", "#js-session-expired-login", function(e) {
- const loginModal = $('#modal-admin-login');
- const redirectUrl = window.location.pathname;
- window.location.href = `/login?action=${encodeURIComponent(redirectUrl)}`;
-});
-
-// show modal login on page load
-$(document).ready(function () {
- const params = new URLSearchParams(window.location.search);
- const redirectUrl = $('#redirect-url').val() || params.get('action') || '/';
- $('#modal-admin-login').modal('show');
- $('#redirect-url').val(redirectUrl);
- $('#username').focus();
- $('#username').addClass("focusedInput");
-});
-
-// DHCP or Static IP option group
-$('#chkstatic').on('change', function() {
- if (this.checked) {
- setStaticFieldsEnabled();
- }
-});
-
-$('#chkdhcp').on('change', function() {
- this.checked ? setStaticFieldsDisabled() : null;
-});
-
-
-$('input[name="dhcp-iface"]').change(function() {
- if ($('input[name="dhcp-iface"]:checked').val() == '1') {
- setDhcpFieldsEnabled();
- } else {
- setDhcpFieldsDisabled();
- }
-});
-
-
-function setStaticFieldsEnabled() {
- $('#txtipaddress').prop('required', true);
- $('#txtsubnetmask').prop('required', true);
- $('#txtgateway').prop('required', true);
-
- $('#txtipaddress').removeAttr('disabled');
- $('#txtsubnetmask').removeAttr('disabled');
- $('#txtgateway').removeAttr('disabled');
-}
-
-function setStaticFieldsDisabled() {
- $('#txtipaddress').prop('disabled', true);
- $('#txtsubnetmask').prop('disabled', true);
- $('#txtgateway').prop('disabled', true);
-
- $('#txtipaddress').removeAttr('required');
- $('#txtsubnetmask').removeAttr('required');
- $('#txtgateway').removeAttr('required');
-}
-
-function setDhcpFieldsEnabled() {
- $('#txtrangestart').prop('required', true);
- $('#txtrangeend').prop('required', true);
- $('#txtrangeleasetime').prop('required', true);
- $('#cbxrangeleasetimeunits').prop('required', true);
-
- $('#txtrangestart').removeAttr('disabled');
- $('#txtrangeend').removeAttr('disabled');
- $('#txtrangeleasetime').removeAttr('disabled');
- $('#cbxrangeleasetimeunits').removeAttr('disabled');
- $('#txtdns1').removeAttr('disabled');
- $('#txtdns2').removeAttr('disabled');
- $('#txtmetric').removeAttr('disabled');
-}
-
-function setDhcpFieldsDisabled() {
- $('#txtrangestart').removeAttr('required');
- $('#txtrangeend').removeAttr('required');
- $('#txtrangeleasetime').removeAttr('required');
- $('#cbxrangeleasetimeunits').removeAttr('required');
-
- $('#txtrangestart').prop('disabled', true);
- $('#txtrangeend').prop('disabled', true);
- $('#txtrangeleasetime').prop('disabled', true);
- $('#cbxrangeleasetimeunits').prop('disabled', true);
- $('#txtdns1').prop('disabled', true);
- $('#txtdns2').prop('disabled', true);
- $('#txtmetric').prop('disabled', true);
-}
-
-// Static Array method
-Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);
-
-$(document).on("click", ".js-toggle-password", function(e) {
- var button = $(e.currentTarget);
- var field = $(button.data("bsTarget"));
- if (field.is(":input")) {
- e.preventDefault();
-
- if (!button.data("__toggle-with-initial")) {
- $("i", button).removeClass("fas fa-eye").addClass(button.attr("data-toggle-with"));
- }
-
- if (field.attr("type") === "password") {
- field.attr("type", "text");
- } else {
- $("i", button).removeClass("fas fa-eye-slash").addClass("fas fa-eye");
- field.attr("type", "password");
- }
- }
-});
-
-$(function() {
- $('#theme-select').change(function() {
- var theme = themes[$( "#theme-select" ).val() ];
-
- var hasDarkTheme = theme === 'custom.php';
- var nightModeChecked = $("#night-mode").prop("checked");
-
- if (nightModeChecked && hasDarkTheme) {
- if (theme === "custom.php") {
- set_theme("dark.css");
- }
- } else {
- set_theme(theme);
- }
- });
-});
-
-function set_theme(theme) {
- $('link[title="main"]').attr('href', 'app/css/' + theme);
- // persist selected theme in cookie
- setCookie('theme',theme,90);
-}
-
-$(function() {
- var currentTheme = getCookie('theme');
- // Check if the current theme is a dark theme
- var isDarkTheme = currentTheme === 'dark.css';
-
- $('#night-mode').prop('checked', isDarkTheme);
- $('#night-mode').change(function() {
- var state = $(this).is(':checked');
- var currentTheme = getCookie('theme');
-
- if (state == true) {
- if (currentTheme == 'custom.php') {
- set_theme('dark.css');
- }
- } else {
- if (currentTheme == 'dark.css') {
- set_theme('custom.php');
- }
- }
- });
-});
-
-function setCookie(cname, cvalue, exdays) {
- var d = new Date();
- d.setTime(d.getTime() + (exdays*24*60*60*1000));
- var expires = "expires="+ d.toUTCString();
- document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
-}
-
-function getCookie(cname) {
- var regx = new RegExp(cname + "=([^;]+)");
- var value = regx.exec(document.cookie);
- return (value != null) ? unescape(value[1]) : null;
-}
-
-// Define themes
-var themes = {
- "default": "custom.php",
- "hackernews" : "hackernews.css"
-}
-
-// Adds active class to current nav-item
-$(window).bind("load", function() {
- var url = window.location;
- $('.sb-nav-link-icon a').filter(function() {
- return this.href == url;
- }).parent().addClass('active');
-});
-
-// Sets focus on a specified tab
-document.addEventListener("DOMContentLoaded", function () {
- const params = new URLSearchParams(window.location.search);
- const targetTab = params.get("tab");
- if (targetTab) {
- let tabElement = document.querySelector(`[data-bs-toggle="tab"][href="#${targetTab}"]`);
- if (tabElement) {
- let tab = new bootstrap.Tab(tabElement);
- tab.show();
- }
- }
-});
-
-function disableValidation(form) {
- form.removeAttribute("novalidate");
- form.classList.remove("needs-validation");
- form.querySelectorAll("[required]").forEach(function (field) {
- field.removeAttribute("required");
- });
-}
-
-function updateActivityLED() {
- const threshold_bytes = 300;
- fetch('/app/net_activity')
- .then(res => res.text())
- .then(data => {
- const activity = parseInt(data.trim());
- const leds = document.querySelectorAll('.hostapd-led');
-
- if (!isNaN(activity)) {
- leds.forEach(led => {
- if (activity > threshold_bytes) {
- led.classList.add('led-pulse');
- setTimeout(() => {
- led.classList.remove('led-pulse');
- }, 50);
- } else {
- led.classList.remove('led-pulse');
- }
- });
- }
- })
- .catch(() => { /* ignore fetch errors */ });
-}
-setInterval(updateActivityLED, 100);
-
-$(document).ready(function() {
- const $htmlElement = $('html');
- const $modeswitch = $('#night-mode');
- $modeswitch.on('change', function() {
- const isChecked = $(this).is(':checked');
- const newTheme = isChecked ? 'dark' : 'light';
- $htmlElement.attr('data-bs-theme', newTheme);
- localStorage.setItem('bsTheme', newTheme);
- });
-});
-
-$(document)
- .ajaxSend(setCSRFTokenHeader)
- .ready(contentLoaded)
- .ready(loadWifiStations());
diff --git a/app/js/bandwidthcharts.js b/app/js/bandwidthcharts.js
deleted file mode 100644
index 2bc63d72..00000000
--- a/app/js/bandwidthcharts.js
+++ /dev/null
@@ -1,147 +0,0 @@
-(function($, _t) {
- "use strict";
-
- /**
- * Create a Chart.js barchart.
- */
- function CreateChart(ctx, labels) {
- var barchart = new Chart(ctx,{
- type: 'line',
- options: {
- responsive: true,
- scales: {
- xAxes: [{
- scaleLabel: {
- display: true,
- labelString: 'date',
- },
- ticks: {
- maxRotation: 90,
- minRotation: 80
- }
- }],
- yAxes: [{
- id: 'y-axis-1',
- type: 'linear',
- display: true,
- position: 'left',
- ticks: {
- beginAtZero: true
- }
- }]
- }
- },
- data: {
- labels: labels,
- datasets: []
- }
- });
-
- return barchart;
- }
-
- /**
- * Create a jquery bootstrap datatable.
- */
- function CreateDataTable(placeholder, timeunits) {
- $("#"+placeholder).append('');
- }
-
- /**
- * Figure out which tab is selected and remove all existing charts and then
- * construct the proper barchart.
- */
- function ShowBandwidthChartHandler(e) {
- // Remove all chartjs charts
- $('#divChartBandwidthhourly').empty();
- $('#divChartBandwidthdaily').empty();
- $('#divChartBandwidthmonthly').empty();
- // Remove all datatables
- $('#divTableBandwidthhourly').empty();
- $('#divTableBandwidthdaily').empty();
- $('#divTableBandwidthmonthly').empty();
- // Construct ajax uri for getting the proper data.
- var timeunit = $('ul#tabbarBandwidth li.nav-item a.nav-link.active').attr('href').substr(1);
- var uri = 'ajax/bandwidth/get_bandwidth.php?';
- uri += 'inet=';
- uri += encodeURIComponent($('#cbxInterface'+timeunit+' option:selected').text());
- uri += '&tu=';
- uri += encodeURIComponent(timeunit.substr(0, 1));
- var datasizeunits = 'mb';
- uri += '&dsu='+encodeURIComponent(datasizeunits);
- // Init. datatable html
- var datatable = CreateDataTable('divTableBandwidth'+timeunit, timeunit);
- // Get data for chart
- $.ajax({
- url: uri,
- dataType: 'json',
- beforeSend: function() {
- $('#divLoaderBandwidth'+timeunit).show();
- }
- }).done(function(jsondata) {
- $('#divLoaderBandwidth'+timeunit).hide();
- // Map json values to label array
- var labels = jsondata.map(function(e) {
- return e.date;
- });
- // Init. chart with label series
- var barchart = CreateChart('divChartBandwidth'+timeunit, labels);
- var dataRx = jsondata.map(function(e) {
- return e.rx;
- });
- var dataTx = jsondata.map(function(e) {
- return e.tx;
- });
-
- addData(barchart, dataRx, dataTx, datasizeunits);
- $('#tableBandwidth'+timeunit).DataTable({
- 'searching': false,
- 'paging': false,
- 'data': jsondata,
- 'order': [[ 0, 'ASC' ]],
- 'columns': [
- { 'data': 'date' },
- { 'data': 'rx', "title": _t['receive']+' '+datasizeunits.toUpperCase() },
- { 'data': 'tx', "title": _t['send']+' '+datasizeunits.toUpperCase() }]
- });
- }).fail(function(xhr, textStatus) {
- if (window.console) {
- console.error('server error');
- } else {
- alert("server error");
- }
- });
- }
- /**
- * Add data array to datasets of current chart.
- */
- function addData(chart, dataRx, dataTx, datasizeunits) {
- chart.data.datasets.push({
- label: 'Receive'+' '+datasizeunits.toUpperCase(),
- yAxisID: 'y-axis-1',
- borderColor: 'rgba(75, 192, 192, 1)',
- backgroundColor: 'rgba(75, 192, 192, 0.2)',
- data: dataRx
- });
- chart.data.datasets.push({
- label: 'Send'+' '+datasizeunits.toUpperCase(),
- yAxisID: 'y-axis-1',
- borderColor: 'rgba(192, 192, 192, 1)',
- backgroundColor: 'rgba(192, 192, 192, 0.2)',
- data: dataTx
- });
- chart.update();
- }
-
- $(document).ready(function() {
- $('#tabbarBandwidth a[data-toggle="tab"]').on('shown.bs.tab', ShowBandwidthChartHandler);
- $('#cbxInterfacehourly').on('change', ShowBandwidthChartHandler);
- $('#cbxInterfacedaily').on('change', ShowBandwidthChartHandler);
- $('#cbxInterfacemonthly').on('change', ShowBandwidthChartHandler);
- ShowBandwidthChartHandler();
- });
-
-})(jQuery, t);
-
diff --git a/app/js/bandwidthcharts.min.js b/app/js/bandwidthcharts.min.js
deleted file mode 100644
index 400015dd..00000000
--- a/app/js/bandwidthcharts.min.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * RaspAP - RaspAP WiFi Configuration Portal v1.6.1 (https://github.com/billz/raspap-webgui)
- * Copyright 2013-2019 RaspAP Developers
- * Licensed under MIT (https://github.com/raspap-webgui/raspap-webgui/blob/master/LICENSE)
- */
-
-!function(r,i){"use strict";function t(t){r("#divChartBandwidthhourly").empty(),r("#divChartBandwidthdaily").empty(),r("#divChartBandwidthmonthly").empty(),r("#divTableBandwidthhourly").empty(),r("#divTableBandwidthdaily").empty(),r("#divTableBandwidthmonthly").empty();var e=r("ul#tabbarBandwidth li.active a").attr("href").substr(1),a="ajax/bandwidth/get_bandwidth.php?";a+="inet=",a+=encodeURIComponent(r("#cbxInterface"+e+" option:selected").text()),a+="&tu=",a+=encodeURIComponent(e.substr(0,1));var d="mb";a+="&dsu="+encodeURIComponent(d);var n=function(t,e){return new Morris.Bar({element:t,xkey:"date",ykeys:["rx","tx"],labels:[i.receive+" "+e.toUpperCase(),i.send+" "+e.toUpperCase()]})}("divChartBandwidth"+e,d);!function(t,e){r("#"+t).append('')}("divTableBandwidth"+e,e);r.ajax({url:a,dataType:"json",beforeSend:function(){r("#divLoaderBandwidth"+e).removeClass("hidden")}}).done(function(t){r("#divLoaderBandwidth"+e).addClass("hidden"),n.setData(t),r("#tableBandwidth"+e).DataTable({searching:!1,paging:!1,data:t,order:[[0,"ASC"]],columns:[{data:"date"},{data:"rx",title:i.receive+" "+d.toUpperCase()},{data:"tx",title:i.send+" "+d.toUpperCase()}]})}).fail(function(t,e){window.console?console.error("server error"):alert("server error")})}r(document).ready(function(){r('#tabbarBandwidth a[data-toggle="tab"]').on("shown.bs.tab",t),r("#cbxInterfacehourly").on("change",t),r("#cbxInterfacedaily").on("change",t),r("#cbxInterfacemonthly").on("change",t),t()})}(jQuery,t);
\ No newline at end of file
diff --git a/app/js/custom.min.js b/app/js/custom.min.js
deleted file mode 100644
index 67444fb6..00000000
--- a/app/js/custom.min.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * RaspAP - RaspAP WiFi Configuration Portal v1.6.1 (https://github.com/billz/raspap-webgui)
- * Copyright 2013-2019 RaspAP Developers
- * Licensed under MIT (https://github.com/raspap-webgui/raspap-webgui/blob/master/LICENSE)
- */
-
-function msgShow(t,a){if(0==t)var e="success";else if(2==t||1==t)e="danger";return''+a+"
"}function createNetmaskAddr(t){var a=[];for(i=0;i<4;i++){var e=Math.min(t,8);a.push(256-Math.pow(2,8-e)),t-=e}return a.join(".")}function loadSummary(a){$.post("/ajax/networking/get_ip_summary.php",{interface:a},function(t){jsonData=JSON.parse(t),console.log(jsonData),0==jsonData.return?$("#"+a+"-summary").html(jsonData.output.join("
")):2==jsonData.return&&$("#"+a+"-summary").append(''+jsonData.output.join("
")+"
")})}function getAllInterfaces(){$.get("/ajax/networking/get_all_interfaces.php",function(t){jsonData=JSON.parse(t),$.each(jsonData,function(t,a){loadSummary(a)})})}function setupTabs(){$('a[data-toggle="tab"]').on("shown.bs.tab",function(t){var a=$(t.target).attr("href");a.match("summary")||loadCurrentSettings(a.replace("#",""))})}function loadCurrentSettings(t){$.post("/ajax/networking/get_int_config.php",{interface:t},function(t){jsonData=JSON.parse(t),$.each(jsonData.output,function(t,a){var n=a.interface;$.each(a,function(t,a){switch(t){case"static":"true"==a?($("#"+n+"-static").click(),$("#"+n+"-nofailover").click()):$("#"+n+"-dhcp").click();break;case"failover":"true"===a?$("#"+n+"-failover").click():$("#"+n+"-nofailover").click();break;case"ip_address":var e=a.split("/");$("#"+n+"-ipaddress").val(e[0]),$("#"+n+"-netmask").val(createNetmaskAddr(e[1]));break;case"routers":$("#"+n+"-gateway").val(a);break;case"domain_name_server":svrsDNS=a.split(" "),$("#"+n+"-dnssvr").val(svrsDNS[0]),$("#"+n+"-dnssvralt").val(svrsDNS[1])}})})})}function saveNetworkSettings(t){var a=$("#frm-"+t).find(":input"),e={};$.each(a,function(t,a){"radio"==$(a).attr("type")?e[$(a).attr("id")]=$(a).prop("checked"):e[$(a).attr("id")]=$(a).val()}),e.interface=t,$.post("/ajax/networking/save_int_config.php",e,function(t){var a=JSON.parse(t);$("#msgNetworking").html(msgShow(a.return,a.output))})}function applyNetworkSettings(){$(this).data("int");arrFormData={generate:""},$.post("/ajax/networking/gen_int_config.php",arrFormData,function(t){console.log(t);var a=JSON.parse(t);$("#msgNetworking").html(msgShow(a.return,a.output))})}function setupBtns(){$("#btnSummaryRefresh").click(function(){getAllInterfaces()}),$(".intsave").click(function(){saveNetworkSettings($(this).data("int"))}),$(".intapply").click(function(){applyNetworkSettings()})}function setCSRFTokenHeader(t,a,e){var n=$("meta[name=csrf_token]").attr("content");/^(POST|PATCH|PUT|DELETE)$/i.test(e.type)&&a.setRequestHeader("X-CSRF-Token",n)}function contentLoaded(){switch(pageCurrent=window.location.href.split("?")[1].split("=")[1],pageCurrent=pageCurrent.replace("#",""),$("#side-menu").metisMenu(),pageCurrent){case"network_conf":getAllInterfaces(),setupTabs(),setupBtns()}}function loadWifiStations(a){return function(){var t=!0===a?"?refresh":"";$(".js-wifi-stations").addClass("loading-spinner").empty().load("/ajax/networking/wifi_stations.php"+t,function(){$(this).removeClass("loading-spinner")})}}$(document).on("click",".js-add-dhcp-static-lease",function(t){t.preventDefault();var a=$(".js-new-dhcp-static-lease"),e=$("input[name=mac]",a).val().trim(),n=$("input[name=ip]",a).val().trim();if(""!=e&&""!=n){var i=$("#js-dhcp-static-lease-row").html().replace("{{ mac }}",e).replace("{{ ip }}",n);$(".js-dhcp-static-lease-container").append(i),$("input[name=mac]",a).val(""),$("input[name=ip]",a).val("")}}),$(document).on("click",".js-remove-dhcp-static-lease",function(t){t.preventDefault(),$(this).parents(".js-dhcp-static-lease-row").remove()}),$(document).on("submit",".js-dhcp-settings-form",function(t){$(".js-add-dhcp-static-lease").trigger("click")}),$(".js-reload-wifi-stations").on("click",loadWifiStations(!0)),$(document).on("click",".js-toggle-password",function(t){var a=$(t.target),e=$(a.data("target"));e.is(":input")&&(t.preventDefault(),a.data("__toggle-with-initial")||a.data("__toggle-with-initial",a.text()),"password"===e.attr("type")?(a.text(a.data("toggle-with")),e.attr("type","text")):(a.text(a.data("__toggle-with-initial")),e.attr("type","password")))}),$(document).on("keyup",".js-validate-psk",function(t){var a=$(t.target),e=a.data("colors").split(","),n=$(a.data("target"));a.val().length<8||63'+msg+'';
+ return htmlMsg;
+}
+
+function createNetmaskAddr(bitCount) {
+ var mask=[];
+ for(i=0;i<4;i++) {
+ var n = Math.min(bitCount, 8);
+ mask.push(256 - Math.pow(2, 8-n));
+ bitCount -= n;
+ }
+ return mask.join('.');
+}
+
+function setupTabs() {
+ $('a[data-bs-toggle="tab"]').on('shown.bs.tab',function(e){
+ var target = $(e.target).attr('href');
+ if(!target.match('summary')) {
+ var int = target.replace("#","");
+ }
+ });
+}
+
+$(document).on("click", ".js-add-dhcp-static-lease", function(e) {
+ e.preventDefault();
+ var container = $(".js-new-dhcp-static-lease");
+ var mac = $("input[name=mac]", container).val().trim();
+ var ip = $("input[name=ip]", container).val().trim();
+ var comment = $("input[name=comment]", container).val().trim();
+ if (mac == "" || ip == "") {
+ return;
+ }
+ var row = $("#js-dhcp-static-lease-row").html()
+ .replace("{{ mac }}", mac)
+ .replace("{{ ip }}", ip)
+ .replace("{{ comment }}", comment);
+ $(".js-dhcp-static-lease-container").append(row);
+
+ $("input[name=mac]", container).val("");
+ $("input[name=ip]", container).val("");
+ $("input[name=comment]", container).val("");
+});
+
+$(document).on("click", ".js-remove-dhcp-static-lease", function(e) {
+ e.preventDefault();
+ $(this).parents(".js-dhcp-static-lease-row").remove();
+});
+
+$(document).on("submit", ".js-dhcp-settings-form", function(e) {
+ $(".js-add-dhcp-static-lease").trigger("click");
+});
+
+$(document).on("click", ".js-add-dhcp-upstream-server", function(e) {
+ e.preventDefault();
+
+ var field = $("#add-dhcp-upstream-server-field")
+ var row = $("#dhcp-upstream-server").html().replace("{{ server }}", field.val())
+
+ if (field.val().trim() == "") { return }
+
+ $(".js-dhcp-upstream-servers").append(row)
+
+ field.val("")
+});
+
+$(document).on("click", ".js-remove-dhcp-upstream-server", function(e) {
+ e.preventDefault();
+ $(this).parents(".js-dhcp-upstream-server").remove();
+});
+
+$(document).on("submit", ".js-dhcp-settings-form", function(e) {
+ $(".js-add-dhcp-upstream-server").trigger("click");
+});
+
+/**
+ * mark a form field, e.g. a select box, with the class `.js-field-preset`
+ * and give it an attribute `data-field-preset-target` with a text field's
+ * css selector.
+ *
+ * now, if the element marked `.js-field-preset` receives a `change` event,
+ * its value will be copied to all elements matching the selector in
+ * data-field-preset-target.
+ */
+$(document).on("change", ".js-field-preset", function(e) {
+ var selector = this.getAttribute("data-field-preset-target")
+ var value = "" + this.value
+ var syncValue = function(el) { el.value = value }
+
+ if (value.trim() === "") { return }
+
+ document.querySelectorAll(selector).forEach(syncValue)
+});
+
+$(document).on("click", "#gen_wpa_passphrase", function(e) {
+ $('#txtwpapassphrase').val(genPassword(63));
+});
+
+$(document).on("click", "#gen_apikey", function(e) {
+ $('#txtapikey').val(genPassword(32).toLowerCase());
+});
+
+// Enable Bootstrap tooltips
+$(function () {
+ $('[data-bs-toggle="tooltip"]').tooltip()
+})
+
+function genPassword(pwdLen) {
+ var pwdChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ var rndPass = Array(pwdLen).fill(pwdChars).map(function(x) { return x[Math.floor(Math.random() * x.length)] }).join('');
+ return rndPass;
+}
+
+function setupBtns() {
+ $('#btnSummaryRefresh').click(function(){getAllInterfaces();});
+ $('.intsave').click(function(){
+ var int = $(this).data('int');
+ saveNetworkSettings(int);
+ });
+ $('.intapply').click(function(){
+ applyNetworkSettings();
+ });
+}
+
+function setCSRFTokenHeader(event, xhr, settings) {
+ var csrfToken = $('meta[name=csrf_token]').attr('content');
+ if (/^(POST|PATCH|PUT|DELETE)$/i.test(settings.type)) {
+ xhr.setRequestHeader("X-CSRF-Token", csrfToken);
+ }
+}
+
+function contentLoaded() {
+ pageCurrent = window.location.href.split("/").pop();
+ switch(pageCurrent) {
+ case "network_conf":
+ getAllInterfaces();
+ setupTabs();
+ setupBtns();
+ break;
+ case "hostapd_conf":
+ getChannel();
+ setHardwareModeTooltip();
+ break;
+ case "dhcpd_conf":
+ loadInterfaceDHCPSelect();
+ break;
+ }
+}
+
+function setDHCPToggles(state) {
+ if ($('#chkfallback').is(':checked') && state) {
+ $('#chkfallback').prop('checked', state);
+ }
+ if ($('#dhcp-iface').is(':checked') && !state) {
+ $('#dhcp-iface').prop('checked', state);
+ setDhcpFieldsDisabled();
+ }
+ $('#chkfallback').prop('disabled', state);
+ $('#dhcp-iface').prop('disabled', !state);
+}
+
+$('#chkfallback').change(function() {
+ if ($('#chkfallback').is(':checked')) {
+ setStaticFieldsEnabled();
+ } else {
+ setStaticFieldsDisabled();
+ }
+});
+
+$('#performupdateModal').on('shown.bs.modal', function (e) {
+ fetchUpdateResponse();
+});
+
+$('#hostapdModal').on('shown.bs.modal', function (e) {
+ var seconds = 3;
+ var pct = 0;
+ var countDown = setInterval(function(){
+ if(seconds <= 0){
+ clearInterval(countDown);
+ }
+ document.getElementsByClassName('progress-bar').item(0).setAttribute('style','width:'+Number(pct)+'%');
+ seconds --;
+ pct = Math.floor(100-(seconds*100/4));
+ }, 500);
+});
+
+$('#configureClientModal').on('shown.bs.modal', function (e) {
+});
+
+$('#ovpn-confirm-activate').on('shown.bs.modal', function (e) {
+ var data = $(e.relatedTarget).data();
+ $('.btn-activate', this).data('recordId', data.recordId);
+});
+
+$('#ovpn-userpw,#ovpn-certs').on('click', function (e) {
+ if (this.id == 'ovpn-userpw') {
+ $('#PanelCerts').hide();
+ $('#PanelUserPW').show();
+ } else if (this.id == 'ovpn-certs') {
+ $('#PanelUserPW').hide();
+ $('#PanelCerts').show();
+ }
+});
+
+$('#install-user-plugin').on('shown.bs.modal', function (e) {
+ var button = $(e.relatedTarget);
+ $(this).data('button', button);
+ var manifestData = button.data('plugin-manifest');
+ var installed = button.data('plugin-installed') || false;
+ var repoPublic = button.data('repo-public') || false;
+ var installPath = manifestData.install_path;
+
+ if (!installed && repoPublic && installPath === 'plugins-available') {
+ insidersHTML = 'Available with Insiders';
+ $('#plugin-additional').html(insidersHTML);
+ } else {
+ $('#plugin-additional').empty();
+ }
+ if (manifestData) {
+ $('#plugin-docs').html(manifestData.plugin_docs
+ ? `${manifestData.plugin_docs}`
+ : 'Unknown');
+ $('#plugin-icon').attr('class', `${manifestData.icon || 'fas fa-plug'} link-secondary h5 me-2`);
+ $('#plugin-name').text(manifestData.name || 'Unknown');
+ $('#plugin-version').text(manifestData.version || 'Unknown');
+ $('#plugin-description').text(manifestData.description || 'No description provided');
+ $('#plugin-author').html(manifestData.author
+ ? manifestData.author + (manifestData.author_uri
+ ? ` (profile)` : '') : 'Unknown');
+ $('#plugin-license').text(manifestData.license || 'Unknown');
+ $('#plugin-locale').text(manifestData.default_locale || 'Unknown');
+ $('#plugin-configuration').html(formatProperty(manifestData.configuration || 'None'));
+ $('#plugin-packages').html(formatProperty(manifestData.keys || 'None'));
+ $('#plugin-dependencies').html(formatProperty(manifestData.dependencies || 'None'));
+ $('#plugin-javascript').html(formatProperty(manifestData.javascript || 'None'));
+ $('#plugin-sudoers').html(formatProperty(manifestData.sudoers || 'None'));
+ $('#plugin-user-name').html((manifestData.user_nonprivileged && manifestData.user_nonprivileged.name) || 'None');
+ }
+ if (installed) {
+ $('#js-install-plugin-confirm').html('OK');
+ } else if (!installed && repoPublic && installPath == 'plugins-available') {
+ $('#js-install-plugin-confirm').html('Get Insiders');
+ } else {
+ $('#js-install-plugin-confirm').html('Install now');
+ }
+});
+
+$('#js-install-plugin-ok').on('click', function (e) {
+ $("#install-plugin-progress").modal('hide');
+ window.location.reload();
+});
+
+function formatProperty(prop) {
+ if (Array.isArray(prop)) {
+ if (typeof prop[0] === 'object') {
+ return prop.map(item => {
+ return Object.entries(item)
+ .map(([key, value]) => `${key}: ${value}`)
+ .join('
');
+ }).join('
');
+ }
+ return prop.map(line => `${line}
`).join('');
+ }
+ if (typeof prop === 'object') {
+ return Object.entries(prop)
+ .map(([key, value]) => `${key}: ${value}`)
+ .join('
');
+ }
+ return prop || 'None';
+}
+
+$(document).ready(function(){
+ $("#PanelManual").hide();
+ $('.ip_address').mask('0ZZ.0ZZ.0ZZ.0ZZ', {
+ translation: {
+ 'Z': {
+ pattern: /[0-9]/, optional: true
+ }
+ },
+ placeholder: "___.___.___.___"
+ });
+ $('.mac_address').mask('FF:FF:FF:FF:FF:FF', {
+ translation: {
+ 'F': {
+ pattern: /[0-9a-fA-F]/, optional: false
+ }
+ },
+ placeholder: "__:__:__:__:__:__"
+ });
+});
+
+$(document).ready(function() {
+ $('.cidr').mask('099.099.099.099/099', {
+ translation: {
+ '0': { pattern: /[0-9]/ }
+ },
+ placeholder: "___.___.___.___/___"
+ });
+});
+
+$('#wg-upload,#wg-manual').on('click', function (e) {
+ if (this.id == 'wg-upload') {
+ $('#PanelManual').hide();
+ $('#PanelUpload').show();
+ } else if (this.id == 'wg-manual') {
+ $('#PanelUpload').hide();
+ $('#PanelManual').show();
+ }
+});
+
+$(".custom-file-input").on("change", function() {
+ var fileName = $(this).val().split("\\").pop();
+ $(this).siblings(".custom-file-label").addClass("selected").html(fileName);
+});
+
+// Event listener for Bootstrap's form validation
+window.addEventListener('load', function() {
+ // Fetch all the forms we want to apply custom Bootstrap validation styles to
+ var forms = document.getElementsByClassName('needs-validation');
+ // Loop over them and prevent submission
+ var validation = Array.prototype.filter.call(forms, function(form) {
+ form.addEventListener('submit', function(event) {
+ if (form.checkValidity() === false) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ form.classList.add('was-validated');
+ }, false);
+ });
+}, false);
+
+function showSessionExpiredModal() {
+ $('#sessionTimeoutModal').modal('show');
+}
+
+$(document).on("click", "#js-session-expired-login", function(e) {
+ const loginModal = $('#modal-admin-login');
+ const redirectUrl = window.location.pathname;
+ window.location.href = `/login?action=${encodeURIComponent(redirectUrl)}`;
+});
+
+// show modal login on page load
+$(document).ready(function () {
+ const params = new URLSearchParams(window.location.search);
+ const redirectUrl = $('#redirect-url').val() || params.get('action') || '/';
+ $('#modal-admin-login').modal('show');
+ $('#redirect-url').val(redirectUrl);
+ $('#username').focus();
+ $('#username').addClass("focusedInput");
+});
+
+// DHCP or Static IP option group
+$('#chkstatic').on('change', function() {
+ if (this.checked) {
+ setStaticFieldsEnabled();
+ }
+});
+
+$('#chkdhcp').on('change', function() {
+ this.checked ? setStaticFieldsDisabled() : null;
+});
+
+
+$('input[name="dhcp-iface"]').change(function() {
+ if ($('input[name="dhcp-iface"]:checked').val() == '1') {
+ setDhcpFieldsEnabled();
+ } else {
+ setDhcpFieldsDisabled();
+ }
+});
+
+
+function setStaticFieldsEnabled() {
+ $('#txtipaddress').prop('required', true);
+ $('#txtsubnetmask').prop('required', true);
+ $('#txtgateway').prop('required', true);
+
+ $('#txtipaddress').removeAttr('disabled');
+ $('#txtsubnetmask').removeAttr('disabled');
+ $('#txtgateway').removeAttr('disabled');
+}
+
+function setStaticFieldsDisabled() {
+ $('#txtipaddress').prop('disabled', true);
+ $('#txtsubnetmask').prop('disabled', true);
+ $('#txtgateway').prop('disabled', true);
+
+ $('#txtipaddress').removeAttr('required');
+ $('#txtsubnetmask').removeAttr('required');
+ $('#txtgateway').removeAttr('required');
+}
+
+function setDhcpFieldsEnabled() {
+ $('#txtrangestart').prop('required', true);
+ $('#txtrangeend').prop('required', true);
+ $('#txtrangeleasetime').prop('required', true);
+ $('#cbxrangeleasetimeunits').prop('required', true);
+
+ $('#txtrangestart').removeAttr('disabled');
+ $('#txtrangeend').removeAttr('disabled');
+ $('#txtrangeleasetime').removeAttr('disabled');
+ $('#cbxrangeleasetimeunits').removeAttr('disabled');
+ $('#txtdns1').removeAttr('disabled');
+ $('#txtdns2').removeAttr('disabled');
+ $('#txtmetric').removeAttr('disabled');
+}
+
+function setDhcpFieldsDisabled() {
+ $('#txtrangestart').removeAttr('required');
+ $('#txtrangeend').removeAttr('required');
+ $('#txtrangeleasetime').removeAttr('required');
+ $('#cbxrangeleasetimeunits').removeAttr('required');
+
+ $('#txtrangestart').prop('disabled', true);
+ $('#txtrangeend').prop('disabled', true);
+ $('#txtrangeleasetime').prop('disabled', true);
+ $('#cbxrangeleasetimeunits').prop('disabled', true);
+ $('#txtdns1').prop('disabled', true);
+ $('#txtdns2').prop('disabled', true);
+ $('#txtmetric').prop('disabled', true);
+}
+
+// Static Array method
+Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);
+
+$(document).on("click", ".js-toggle-password", function(e) {
+ var button = $(e.currentTarget);
+ var field = $(button.data("bsTarget"));
+ if (field.is(":input")) {
+ e.preventDefault();
+
+ if (!button.data("__toggle-with-initial")) {
+ $("i", button).removeClass("fas fa-eye").addClass(button.attr("data-toggle-with"));
+ }
+
+ if (field.attr("type") === "password") {
+ field.attr("type", "text");
+ } else {
+ $("i", button).removeClass("fas fa-eye-slash").addClass("fas fa-eye");
+ field.attr("type", "password");
+ }
+ }
+});
+
+$(function() {
+ $('#theme-select').change(function() {
+ var theme = themes[$( "#theme-select" ).val() ];
+
+ var hasDarkTheme = theme === 'custom.php';
+ var nightModeChecked = $("#night-mode").prop("checked");
+
+ if (nightModeChecked && hasDarkTheme) {
+ if (theme === "custom.php") {
+ set_theme("dark.css");
+ }
+ } else {
+ set_theme(theme);
+ }
+ });
+});
+
+function set_theme(theme) {
+ $('link[title="main"]').attr('href', 'app/css/' + theme);
+ // persist selected theme in cookie
+ setCookie('theme',theme,90);
+}
+
+$(function() {
+ var currentTheme = getCookie('theme');
+ // Check if the current theme is a dark theme
+ var isDarkTheme = currentTheme === 'dark.css';
+
+ $('#night-mode').prop('checked', isDarkTheme);
+ $('#night-mode').change(function() {
+ var state = $(this).is(':checked');
+ var currentTheme = getCookie('theme');
+
+ if (state == true) {
+ if (currentTheme == 'custom.php') {
+ set_theme('dark.css');
+ }
+ } else {
+ if (currentTheme == 'dark.css') {
+ set_theme('custom.php');
+ }
+ }
+ });
+});
+
+function setCookie(cname, cvalue, exdays) {
+ var d = new Date();
+ d.setTime(d.getTime() + (exdays*24*60*60*1000));
+ var expires = "expires="+ d.toUTCString();
+ document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
+}
+
+function getCookie(cname) {
+ var regx = new RegExp(cname + "=([^;]+)");
+ var value = regx.exec(document.cookie);
+ return (value != null) ? unescape(value[1]) : null;
+}
+
+// Define themes
+var themes = {
+ "default": "custom.php",
+ "hackernews" : "hackernews.css"
+}
+
+// Adds active class to current nav-item
+$(window).bind("load", function() {
+ var url = window.location;
+ $('.sb-nav-link-icon a').filter(function() {
+ return this.href == url;
+ }).parent().addClass('active');
+});
+
+// Sets focus on a specified tab
+document.addEventListener("DOMContentLoaded", function () {
+ const params = new URLSearchParams(window.location.search);
+ const targetTab = params.get("tab");
+ if (targetTab) {
+ let tabElement = document.querySelector(`[data-bs-toggle="tab"][href="#${targetTab}"]`);
+ if (tabElement) {
+ let tab = new bootstrap.Tab(tabElement);
+ tab.show();
+ }
+ }
+});
+
+function disableValidation(form) {
+ form.removeAttribute("novalidate");
+ form.classList.remove("needs-validation");
+ form.querySelectorAll("[required]").forEach(function (field) {
+ field.removeAttribute("required");
+ });
+}
+
+function updateActivityLED() {
+ const threshold_bytes = 300;
+ fetch('/app/net_activity')
+ .then(res => res.text())
+ .then(data => {
+ const activity = parseInt(data.trim());
+ const leds = document.querySelectorAll('.hostapd-led');
+
+ if (!isNaN(activity)) {
+ leds.forEach(led => {
+ if (activity > threshold_bytes) {
+ led.classList.add('led-pulse');
+ setTimeout(() => {
+ led.classList.remove('led-pulse');
+ }, 50);
+ } else {
+ led.classList.remove('led-pulse');
+ }
+ });
+ }
+ })
+ .catch(() => { /* ignore fetch errors */ });
+}
+setInterval(updateActivityLED, 100);
+
+$(document).ready(function() {
+ const $htmlElement = $('html');
+ const $modeswitch = $('#night-mode');
+ $modeswitch.on('change', function() {
+ const isChecked = $(this).is(':checked');
+ const newTheme = isChecked ? 'dark' : 'light';
+ $htmlElement.attr('data-bs-theme', newTheme);
+ localStorage.setItem('bsTheme', newTheme);
+ });
+});
+
+$(document)
+ .ajaxSend(setCSRFTokenHeader)
+ .ready(contentLoaded)
+ .ready(loadWifiStations());
+
diff --git a/includes/dashboard.php b/includes/dashboard.php
index f0f6e3e8..f01917ca 100755
--- a/includes/dashboard.php
+++ b/includes/dashboard.php
@@ -123,7 +123,7 @@ function DisplayDashboard(&$extraFooterScripts): void
"status"
)
);
- $extraFooterScripts[] = array('src'=>'app/js/dashboardchart.js', 'defer'=>false);
+ $extraFooterScripts[] = array('src'=>'app/js/vendor/dashboardchart.js', 'defer'=>false);
}
/**
diff --git a/includes/data_usage.php b/includes/data_usage.php
index 3c7753bd..8ea698d6 100755
--- a/includes/data_usage.php
+++ b/includes/data_usage.php
@@ -9,5 +9,5 @@ function DisplayDataUsage(&$extraFooterScripts)
echo renderTemplate("data_usage", [ "interfaces" => $interfacesWlo ]);
$extraFooterScripts[] = array('src'=>'dist/datatables/jquery.dataTables.min.js', 'defer'=>false);
- $extraFooterScripts[] = array('src'=>'app/js/bandwidthcharts.js', 'defer'=>false);
+ $extraFooterScripts[] = array('src'=>'app/js/vendor/bandwidthcharts.js', 'defer'=>false);
}
diff --git a/includes/networking.php b/includes/networking.php
index 83c587ed..5ebfffe4 100755
--- a/includes/networking.php
+++ b/includes/networking.php
@@ -23,5 +23,5 @@ function DisplayNetworkingConfig(&$extraFooterScripts)
"routeInfoRaw",
"bridgedEnabled")
);
- $extraFooterScripts[] = array('src'=>'app/js/speedtestUI.js', 'defer'=>false);
+ $extraFooterScripts[] = array('src'=>'app/js/vendor/speedtestUI.js', 'defer'=>false);
}
diff --git a/includes/system.php b/includes/system.php
index 343e1aab..6bc73875 100755
--- a/includes/system.php
+++ b/includes/system.php
@@ -122,7 +122,7 @@ function DisplaySystem(&$extraFooterScripts)
];
$selectedTheme = array_search($_COOKIE['theme'], $themeFiles);
$extraFooterScripts[] = array('src'=>'dist/huebee/huebee.pkgd.min.js', 'defer'=>false);
- $extraFooterScripts[] = array('src'=>'app/js/huebee.js', 'defer'=>false);
+ $extraFooterScripts[] = array('src'=>'app/js/vendor/huebee.js', 'defer'=>false);
$logLimit = isset($_SESSION['log_limit']) ? $_SESSION['log_limit'] : RASPI_LOG_SIZE_LIMIT;
$plugins = $pluginInstaller->getUserPlugins();
diff --git a/index.php b/index.php
index c5b8d4fa..8250a153 100755
--- a/index.php
+++ b/index.php
@@ -147,8 +147,9 @@ initializeApp();
-
-
+
+
+