From db71623b749e889352bd43451e2708b064c83089 Mon Sep 17 00:00:00 2001 From: Martinski4GitHub <119833648+Martinski4GitHub@users.noreply.github.com> Date: Mon, 15 Dec 2025 23:26:53 -0800 Subject: [PATCH 01/14] Fine-Tuning Code Just some simple fine-tuning. --- README.md | 4 ++-- scmerlin.sh | 21 ++++++++------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 0269d31..a0f73c9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # scMerlin -## v2.5.47 -### Updated on 2025-Dec-12 +## v2.5.48 +### Updated on 2025-Dec-15 ## About scMerlin allows you to easily control the most common services/scripts on your router. scMerlin also augments your router's WebUI with a Sitemap and dynamic submenus for the main left menu of Asuswrt-Merlin. diff --git a/scmerlin.sh b/scmerlin.sh index c54fce5..0a720e3 100644 --- a/scmerlin.sh +++ b/scmerlin.sh @@ -12,7 +12,7 @@ ## Forked from: https://github.com/jackyaz/scMerlin ## ## ## ###################################################### -# Last Modified: 2025-Dec-12 +# Last Modified: 2025-Dec-15 #----------------------------------------------------- ########## Shellcheck directives ########### @@ -32,9 +32,9 @@ ### Start of script variables ### readonly SCRIPT_NAME="scMerlin" readonly SCRIPT_NAME_LOWER="$(echo "$SCRIPT_NAME" | tr 'A-Z' 'a-z' | sed 's/d//')" -readonly SCM_VERSION="v2.5.47" -readonly SCRIPT_VERSION="v2.5.47" -readonly SCRIPT_VERSTAG="25121220" +readonly SCM_VERSION="v2.5.48" +readonly SCRIPT_VERSION="v2.5.48" +readonly SCRIPT_VERSTAG="25121520" SCRIPT_BRANCH="develop" SCRIPT_REPO="https://raw.githubusercontent.com/AMTM-OSR/$SCRIPT_NAME/$SCRIPT_BRANCH" readonly SCRIPT_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d" @@ -2892,7 +2892,6 @@ _Menu_Services_() done "$exitMenu" && return 0 - ScriptHeader _Menu_Services_ } @@ -2910,7 +2909,7 @@ _Menu_OpenVPN_() if _CheckFor_OpenVPN_Clients_Available_ then printf " ${BOLDUNDERLN}${GRNct}OpenVPN Clients${CLRct}\n" - printf " ${BOLD}${WARN}(Selecting an option will restart the OpenVPN Client)${CLRct}\n\n" + printf " ${BOLD}${WARN}(Selecting an option will restart the Client)${CLRct}\n\n" vpnClientNum=1 while [ "$vpnClientNum" -lt 6 ] do @@ -2936,7 +2935,7 @@ _Menu_OpenVPN_() if _CheckFor_OpenVPN_Servers_Available_ then printf "\n ${BOLDUNDERLN}${GRNct}OpenVPN Servers${CLRct}\n" - printf " ${BOLD}${WARN}(Selecting an option will restart the OpenVPN Server)${CLRct}\n\n" + printf " ${BOLD}${WARN}(Selecting an option will restart the Server)${CLRct}\n\n" vpnServerNum=1 while [ "$vpnServerNum" -lt 3 ] do @@ -3002,7 +3001,6 @@ _Menu_OpenVPN_() done "$exitMenu" && return 0 - ScriptHeader _Menu_OpenVPN_ } @@ -3020,7 +3018,7 @@ _Menu_WireGuard_() if _CheckFor_WireGuard_Clients_Available_ then printf " ${BOLDUNDERLN}${GRNct}WireGuard Clients${CLRct}\n" - printf " ${BOLD}${WARN}(Selecting an option will restart the WireGuard Client)${CLRct}\n\n" + printf " ${BOLD}${WARN}(Selecting an option will restart the Client)${CLRct}\n\n" vpnClientNum=1 while [ "$vpnClientNum" -lt 6 ] do @@ -3047,7 +3045,7 @@ _Menu_WireGuard_() if _CheckFor_WireGuard_Servers_Available_ then printf "\n ${BOLDUNDERLN}${GRNct}WireGuard Server${CLRct}\n" - printf " ${BOLD}${WARN}(Selecting the option will restart the WireGuard Server)${CLRct}\n\n" + printf " ${BOLD}${WARN}(Selecting the option will restart the Server)${CLRct}\n\n" vpnServerNum=1 ## Currently only ONE WireGuard Server is available ## if _IsWireGuard_Server_Configured_ "$vpnServerNum" then @@ -3116,7 +3114,6 @@ _Menu_WireGuard_() done "$exitMenu" && return 0 - ScriptHeader _Menu_WireGuard_ } @@ -3311,7 +3308,6 @@ _Menu_RouterUtilities_() done "$exitMenu" && return 0 - ScriptHeader _Menu_RouterUtilities_ } @@ -3406,7 +3402,6 @@ _Menu_ToggleOptions_() done "$exitMenu" && return 0 - ScriptHeader _Menu_ToggleOptions_ } From 5069277f8e9fbf97a18bd66ef9bc5927872e389d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 20:37:30 +0000 Subject: [PATCH 02/14] Bump actions/checkout from 6.0.1 to 6.0.2 in the all-actions group Bumps the all-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 6.0.1 to 6.0.2 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6.0.1...v6.0.2) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/Create-NewReleases.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Create-NewReleases.yml b/.github/workflows/Create-NewReleases.yml index 74864b4..5fecb20 100644 --- a/.github/workflows/Create-NewReleases.yml +++ b/.github/workflows/Create-NewReleases.yml @@ -19,7 +19,7 @@ jobs: steps: # 1--- Check out master so we tag the exact merge commit - name: Checkout source code - uses: actions/checkout@v6.0.1 + uses: actions/checkout@v6.0.2 with: fetch-depth: 0 ref: 'master' From 0602454413e76fd43a34ee6638430bac458047db Mon Sep 17 00:00:00 2001 From: Martinski4GitHub <119833648+Martinski4GitHub@users.noreply.github.com> Date: Wed, 18 Feb 2026 01:18:59 -0800 Subject: [PATCH 03/14] New Functionality Initial code to support automatic script updates via AMTM. --- README.md | 2 +- scmerlin.sh | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a0f73c9..3e4777d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # scMerlin ## v2.5.48 -### Updated on 2025-Dec-15 +### Updated on 2026-Feb-18 ## About scMerlin allows you to easily control the most common services/scripts on your router. scMerlin also augments your router's WebUI with a Sitemap and dynamic submenus for the main left menu of Asuswrt-Merlin. diff --git a/scmerlin.sh b/scmerlin.sh index 0a720e3..f845eac 100644 --- a/scmerlin.sh +++ b/scmerlin.sh @@ -12,7 +12,7 @@ ## Forked from: https://github.com/jackyaz/scMerlin ## ## ## ###################################################### -# Last Modified: 2025-Dec-15 +# Last Modified: 2026-Feb-18 #----------------------------------------------------- ########## Shellcheck directives ########### @@ -34,7 +34,7 @@ readonly SCRIPT_NAME="scMerlin" readonly SCRIPT_NAME_LOWER="$(echo "$SCRIPT_NAME" | tr 'A-Z' 'a-z' | sed 's/d//')" readonly SCM_VERSION="v2.5.48" readonly SCRIPT_VERSION="v2.5.48" -readonly SCRIPT_VERSTAG="25121520" +readonly SCRIPT_VERSTAG="26021800" SCRIPT_BRANCH="develop" SCRIPT_REPO="https://raw.githubusercontent.com/AMTM-OSR/$SCRIPT_NAME/$SCRIPT_BRANCH" readonly SCRIPT_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d" @@ -102,6 +102,9 @@ readonly branchxStr_TAG="[Branch: $SCRIPT_BRANCH]" readonly versionDev_TAG="${SCRIPT_VERSION}_${SCRIPT_VERSTAG}" readonly versionMod_TAG="$SCRIPT_VERSION on $ROUTER_MODEL" +# To support automatic script updates from AMTM # +doScriptUpdateFromAMTM=true + ##-------------------------------------## ## Added by Martinski W. [2025-May-17] ## ##-------------------------------------## @@ -1167,9 +1170,11 @@ Update_Version() localver="$(echo "$updatecheckresult" | cut -f2 -d',')" serverver="$(echo "$updatecheckresult" | cut -f3 -d',')" - if [ "$isupdate" = "version" ]; then + if [ "$isupdate" = "version" ] + then Print_Output true "New version of $SCRIPT_NAME available - $serverver" "$PASS" - elif [ "$isupdate" = "md5" ]; then + elif [ "$isupdate" = "md5" ] + then Print_Output true "MD5 hash of $SCRIPT_NAME does not match - hotfix available - $serverver" "$PASS" fi @@ -1246,6 +1251,23 @@ Update_Version() fi } +##-------------------------------------## +## Added by Martinski W. [2026-Feb-18] ## +##-------------------------------------## +ScriptUpdateFromAMTM() +{ + if ! "$doScriptUpdateFromAMTM" + then + printf "Automatic script updates via AMTM are currently disabled.\n\n" + return 1 + fi + if [ $# -gt 0 ] && [ "$1" = "check" ] + then return 0 + fi + Update_Version force unattended + return "$?" +} + ##----------------------------------------## ## Modified by Martinski W. [2025-Feb-11] ## ##----------------------------------------## @@ -3950,7 +3972,7 @@ then fi ##----------------------------------------## -## Modified by Martinski W. [2025-Oct-19] ## +## Modified by Martinski W. [2026-Feb-18] ## ##----------------------------------------## case "$1" in install) @@ -4225,6 +4247,11 @@ case "$1" in Update_Version force exit 0 ;; + amtmupdate) + shift + ScriptUpdateFromAMTM "$@" + exit "$?" + ;; postupdate) Create_Dirs Create_Symlinks From e7dbea2da15c5dbae07cdc728a9c9614f1510377 Mon Sep 17 00:00:00 2001 From: ExtremeFiretop Date: Tue, 3 Mar 2026 11:19:07 -0500 Subject: [PATCH 04/14] Allow Disabling of Dropdown Submenus Initial commit to support disabling of Dropdown Sub-Menus from scMerlin --- README.md | 2 +- scmerlin.sh | 125 +++++++++++++++++++++++++++++++++++++---------- scmerlin_www.asp | 21 +++++++- scmerlin_www.js | 34 +++++++++++++ 4 files changed, 155 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 3e4777d..51a4740 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # scMerlin ## v2.5.48 -### Updated on 2026-Feb-18 +### Updated on 2026-Mar-03 ## About scMerlin allows you to easily control the most common services/scripts on your router. scMerlin also augments your router's WebUI with a Sitemap and dynamic submenus for the main left menu of Asuswrt-Merlin. diff --git a/scmerlin.sh b/scmerlin.sh index f845eac..87ea840 100644 --- a/scmerlin.sh +++ b/scmerlin.sh @@ -12,7 +12,7 @@ ## Forked from: https://github.com/jackyaz/scMerlin ## ## ## ###################################################### -# Last Modified: 2026-Feb-18 +# Last Modified: 2026-Mar-03 #----------------------------------------------------- ########## Shellcheck directives ########### @@ -46,6 +46,7 @@ readonly SHARED_WEB_DIR="$SCRIPT_WEBPAGE_DIR/shared-jy" readonly TEMP_MENU_TREE="/tmp/menuTree.js" readonly NTP_WATCHDOG_FILE="$SCRIPT_DIR/.watchdogenabled" readonly TAIL_TAINTED_FILE="$SCRIPT_DIR/.tailtaintdnsenabled" +readonly WEBUI_DROPDOWN_FILE="$SCRIPT_DIR/.webui_dropdown_submenus" ##----------------------------------------## ## Modified by Martinski W. [2024-Jun-07] ## @@ -1109,6 +1110,72 @@ function GenerateSiteMap(showurls) EOF } +##---------------------------------------## +## Added by ExtremeFiretop [2026-Mar-03] ## +##---------------------------------------## +WebUI_DropdownSubMenus() +{ + + case "$1" in + enable) + touch "$WEBUI_DROPDOWN_FILE" + WebUI_DropdownSubMenus apply >/dev/null 2>&1 + ;; + disable) + rm -f "$WEBUI_DROPDOWN_FILE" + WebUI_DropdownSubMenus apply >/dev/null 2>&1 + ;; + apply) + # Ensure we have a working copy to edit + if [ ! -f /tmp/index_style.css ]; then + cp -fp /www/index_style.css /tmp/ 2>/dev/null + fi + + # Remove any prior dropdown CSS rules (yours or legacy) + if [ -f /tmp/index_style.css ]; then + sed -i '/dropdown-content/d' /tmp/index_style.css + fi + + # Base dropdown CSS (always present) + { + echo ".dropdown-content {top: 0px; left: 185px; "\ +"visibility: hidden; position: absolute; "\ +"background-color: #3a4042; min-width: 165px; "\ +"box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); "\ +"z-index: 1000;}" + echo ".dropdown-content a {padding: 6px 8px; "\ +"text-decoration: none; display: block; height: 100%; "\ +"min-height: 20px; max-height: 40px; font-weight: bold; "\ +"text-shadow: 1px 1px 0px black; "\ +"font-family: Verdana, MS UI Gothic, MS P Gothic, "\ +"Microsoft Yahei UI, sans-serif; font-size: 12px; "\ +"border: 1px solid #6B7071;}" + echo ".dropdown-content a:hover {background-color: #77a5c6;}" + } >> /tmp/index_style.css + + # Enabled: show on hover + if [ -f "$WEBUI_DROPDOWN_FILE" ]; then + echo ".dropdown:hover .dropdown-content "\ +"{visibility: visible;}" >> /tmp/index_style.css + else + # Disabled: prevent click-toggle from making it appear + echo ".dropdown-content {display: none;}" >> /tmp/index_style.css + fi + + # Bind-mount updated CSS into WebUI + umount /www/index_style.css 2>/dev/null + mount -o bind /tmp/index_style.css /www/index_style.css + ;; + status) + if [ -f "$WEBUI_DROPDOWN_FILE" ]; then + echo "ENABLED" + else + echo "DISABLED" + fi + ;; + esac +} + ##----------------------------------------## ## Modified by Martinski W. [2025-May-17] ## ##----------------------------------------## @@ -1445,6 +1512,7 @@ Create_Symlinks() ln -s "$NTP_WATCHDOG_FILE" "$SCRIPT_WEB_DIR/watchdogenabled.htm" 2>/dev/null ln -s "$NTP_READY_CHECK_CONF" "$SCRIPT_WEB_DIR/${NTP_READY_CHECK_FILE}.htm" 2>/dev/null ln -s "$TAIL_TAINTED_FILE" "$SCRIPT_WEB_DIR/tailtaintdnsenabled.htm" 2>/dev/null + ln -s "$WEBUI_DROPDOWN_FILE" "$SCRIPT_WEB_DIR/webuidropdownenabled.htm" 2>/dev/null if [ ! -d "$SHARED_WEB_DIR" ]; then ln -s "$SHARED_DIR" "$SHARED_WEB_DIR" 2>/dev/null @@ -1699,30 +1767,13 @@ Mount_WebUI() cp -fp /www/index_style.css /tmp/ fi - if ! grep -q '.menu_Addons' /tmp/index_style.css ; then - echo ".menu_Addons { background: url(ext/shared-jy/addons.png); background-size: contain; }" >> /tmp/index_style.css - fi - - if grep -q '.menu_Addons' /tmp/index_style.css && ! grep -q 'url(ext/shared-jy/addons.png); background-size: contain;' /tmp/index_style.css; then - sed -i 's/addons.png);/addons.png); background-size: contain;/' /tmp/index_style.css - fi - - if grep -q '.dropdown-content {display: block;}' /tmp/index_style.css ; then - sed -i '/dropdown-content/d' /tmp/index_style.css - fi - - if ! grep -q '.dropdown-content {visibility: visible;}' /tmp/index_style.css - then - { - echo ".dropdown-content {top: 0px; left: 185px; visibility: hidden; position: absolute; background-color: #3a4042; min-width: 165px; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); z-index: 1000;}" - echo ".dropdown-content a {padding: 6px 8px; text-decoration: none; display: block; height: 100%; min-height: 20px; max-height: 40px; font-weight: bold; text-shadow: 1px 1px 0px black; font-family: Verdana, MS UI Gothic, MS P Gothic, Microsoft Yahei UI, sans-serif; font-size: 12px; border: 1px solid #6B7071;}" - echo ".dropdown-content a:hover {background-color: #77a5c6;}" - echo ".dropdown:hover .dropdown-content {visibility: visible;}" - } >> /tmp/index_style.css - fi - - umount /www/index_style.css 2>/dev/null - mount -o bind /tmp/index_style.css /www/index_style.css + # Apply (enable/disable) WebUI dropdown sub-menus based on saved setting + # NOTE: This function handles: + # - Removing any prior dropdown CSS rules + # - Adding base dropdown CSS + # - Adding hover-to-show rule only when enabled + # - Bind-mounting /tmp/index_style.css to /www/index_style.css + WebUI_DropdownSubMenus apply if [ ! -f "$TEMP_MENU_TREE" ]; then cp -fp /www/require/modules/menuTree.js "$TEMP_MENU_TREE" @@ -3374,6 +3425,15 @@ _Menu_ToggleOptions_() printf " ${GRNct}dns${CLRct}. Toggle dnsmasq tainted watchdog script\n" printf " Currently: ${TAILTAINT_DNS_STATUS}\n\n" + if [ "$(WebUI_DropdownSubMenus status)" = "ENABLED" ] + then + WEBUI_DROPDOWN_STATUS="${GRNct}ENABLED${CLRct}" + else + WEBUI_DROPDOWN_STATUS="${REDct}DISABLED${CLRct}" + fi + printf " ${GRNct}wui${CLRct}. Toggle WebUI dropdown sub-menus\n" + printf " Currently: ${WEBUI_DROPDOWN_STATUS}\n\n" + printf " ${GRNct}e${CLRct}. Return to Main Menu\n" printf "\n${menuSepStr}\n\n" @@ -3412,6 +3472,16 @@ _Menu_ToggleOptions_() fi break ;; + wui) + printf "\n" + WEBUI_DROPDOWN_STATUS="$(WebUI_DropdownSubMenus status)" + if [ "$WEBUI_DROPDOWN_STATUS" = "ENABLED" ] + then WebUI_DropdownSubMenus disable + elif [ "$WEBUI_DROPDOWN_STATUS" = "DISABLED" ] + then WebUI_DropdownSubMenus enable + fi + break + ;; e) exitMenu=true break ;; @@ -4005,6 +4075,11 @@ case "$1" in settingstate="$(echo "$3" | sed "s/${SCRIPT_NAME_LOWER}_DNSmasqWatchdog//")"; settingstate="$(echo "$settingstate" | tr 'A-Z' 'a-z')" TailTaintDNSmasq "$settingstate" + elif echo "$3" | grep -qE "^${SCRIPT_NAME_LOWER}_WebUIDropdowns" + then + settingstate="$(echo "$3" | sed "s/${SCRIPT_NAME_LOWER}_WebUIDropdowns//")"; + settingstate="$(echo "$settingstate" | tr 'A-Z' 'a-z')" + WebUI_DropdownSubMenus "$settingstate" elif echo "$3" | grep -qE "^${SCRIPT_NAME_LOWER}servicerestart" then rm -f "$SCRIPT_WEB_DIR/detect_service.js" diff --git a/scmerlin_www.asp b/scmerlin_www.asp index f55a307..766a1e0 100644 --- a/scmerlin_www.asp +++ b/scmerlin_www.asp @@ -531,7 +531,7 @@ function update_temperatures() } /* End firmware functions */ -var arrayproclistlines=[],sortnameproc="CPU%",sortdirproc="desc",arraycronjobs=[],sortnamecron="Name",sortdircron="asc",tmout=null;function SetCurrentPage(){document.form.next_page.value=window.location.pathname.substring(1),document.form.current_page.value=window.location.pathname.substring(1)}Chart.defaults.global.defaultFontColor="#CCC",Chart.Tooltip.positioners.cursor=function(e,t){return t};var srvnamelist=["dnsmasq","wan","httpd","wireless","vsftpd","samba","ddns","ntpd/chronyd"],srvdesclist=["DNS/DHCP Server","Internet Connection","Web Interface","WiFi","FTP Server","Samba","DDNS client","Timeserver"],srvnamevisiblelist=[!0,!1,!0,!1,!0,!1,!1,!0],sortedAddonPages=[];function initial(){SetCurrentPage(),LoadCustomSettings(),show_menu(),Draw_Chart_NoData("nvramUsage","Data loading..."),Draw_Chart_NoData("jffsUsage","Data loading..."),Draw_Chart_NoData("MemoryUsage","Data loading..."),Draw_Chart_NoData("SwapUsage","No swap file configured"),$("#sortTableCron").empty(),$("#sortTableCron").append(BuildSortTableHtmlNoData()),$("#sortTableProcesses").empty(),$("#sortTableProcesses").append(BuildSortTableHtmlNoData());let e="",t="";if(isWireGuard_Supported){e+=Build_WireGuardServer_Table(1),$("#table_config").after(e);for(var r=1;r<6;r++)t+=Build_WireGuardClient_Table(r);$("#table_config").after(t)}let s="";for(r=1;r<3;r++)s+=Build_OpenVPNServer_Table(r);$("#table_config").after(s);let a="";for(r=1;r<6;r++)a+=Build_OpenVPNClient_Table(r);$("#table_config").after(a);let n="";for(var i=0;i",'',"Data loading...","","","",'
Data loading...
'}function BuildSortTableHtml(e){var t='';if("sortTableProcesses"==e){t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+='';for(var r=0;r',t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+=""}else if("sortTableCron"==e){t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+='';for(r=0;r',t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+=""}return t+="",t+="
PIDPPIDUSERSTATVSZVSZ%CPUCPU%COMMAND
"+arrayproclistlines[r].PID+""+arrayproclistlines[r].PPID+""+arrayproclistlines[r].USER+""+arrayproclistlines[r].STAT+""+arrayproclistlines[r].VSZ+""+arrayproclistlines[r].VSZP+""+arrayproclistlines[r].CPU+""+arrayproclistlines[r].CPUP+""+arrayproclistlines[r].COMMAND+"
NameMinHourDayMMonthDayWCommand
"+arraycronjobs[r].Name+""+arraycronjobs[r].Min+""+arraycronjobs[r].Hour+""+arraycronjobs[r].DayM+""+arraycronjobs[r].Month+""+arraycronjobs[r].DayW+""+arraycronjobs[r].Command+"
"}function Get_NTPWatchdogEnabled_File(){$.ajax({url:"/ext/scmerlin/watchdogenabled.htm",dataType:"text",error:function(e){document.form.scMerlin_NTPwatchdog.value="Disable",$("#scMerlin_NTPwatchdog_Status").text("Currently: DISABLED")},success:function(e){document.form.scMerlin_NTPwatchdog.value="Enable",$("#scMerlin_NTPwatchdog_Status").text("Currently: ENABLED")}})}function Save_NTPWatchdog(){document.form.action_script.value="start_scmerlin_NTPwatchdog"+document.form.scMerlin_NTPwatchdog.value,document.form.action_wait.value=4,$("#auto_refresh").prop("checked",!1),null!=tmout&&clearTimeout(tmout),showLoading(),document.form.submit(),setTimeout(Get_NTPWatchdogEnabled_File,4e3)}function Get_DNSmasqWatchdogEnabled_File(){$.ajax({url:"/ext/scmerlin/tailtaintdnsenabled.htm",dataType:"text",error:function(e){document.form.scMerlin_DNSmasqWatchdog.value="Disable",$("#scMerlin_DNSmasqWatchdog_Status").text("Currently: DISABLED")},success:function(e){document.form.scMerlin_DNSmasqWatchdog.value="Enable",$("#scMerlin_DNSmasqWatchdog_Status").text("Currently: ENABLED")}})}function Save_DNSmasqWatchdog(){document.form.action_script.value="start_scmerlin_DNSmasqWatchdog"+document.form.scMerlin_DNSmasqWatchdog.value,document.form.action_wait.value=4,$("#auto_refresh").prop("checked",!1),null!=tmout&&clearTimeout(tmout),showLoading(),document.form.submit(),setTimeout(Get_DNSmasqWatchdogEnabled_File,4e3)}const WaitMsgPopupBox={waitCounter:0,waitMaxSecs:0,waitTimerOn:!1,waitTimerID:null,waitMsgBox:null,waitMsgTemp:"",waitMsgBoxID:"myWaitMsgPopupBoxID",CloseMsg:function(){this.waitTimerOn=!1,this.waitCounter=0,this.waitMaxSecs=0,this.waitMsgTemp="",null!=this.waitTimerID&&(clearTimeout(this.waitTimerID),this.waitTimerID=null),null!=this.waitMsgBox&&this.waitMsgBox.close()},StartMsg:function(e,t,r){this.waitTimerOn||(this.waitTimerOn=!0,this.waitCounter=0,this.waitMsgTemp="",this.waitMaxSecs=Math.round(t/1e3),this.ShowTimedMsg(e,r))},ShowTimedMsg:function(e,t){if(this.waitCounter>this.waitMaxSecs)return void this.CloseMsg();if(!this.waitTimerOn)return;this.waitMsgBox=document.getElementById(this.waitMsgBoxID),null==this.waitMsgBox&&(this.waitMsgBox=document.body.appendChild(document.createElement("dialog")),this.waitMsgBox.setAttribute("id",this.waitMsgBoxID));let r=this.waitCounter+1;0==this.waitCounter&&this.waitMsgBox.close(),t?t&&(this.waitMsgBox.innerText=e+` [${r}]`):(0==this.waitCounter?this.waitMsgTemp=e+"\n >":this.waitMsgTemp=this.waitMsgTemp+">",this.waitMsgBox.innerText=this.waitMsgTemp),0==this.waitCounter&&this.waitMsgBox.showModal(),this.waitCounter=r,this.waitTimerID=setTimeout((function(){WaitMsgPopupBox.ShowTimedMsg(e,t)}),1e3)},ShowMsg:function(e,t){this.waitMsgBox=document.getElementById(this.waitMsgBoxID),null==this.waitMsgBox&&(this.waitMsgBox=document.body.appendChild(document.createElement("dialog")),this.waitMsgBox.setAttribute("id",this.waitMsgBoxID)),this.waitMsgBox.close(),this.waitMsgBox.innerText=e,this.waitMsgBox.showModal(),setTimeout((function(){WaitMsgPopupBox.waitMsgBox.close()}),t)}},AlertMsgBox={alertMsgBox:null,alertMsgBoxID:"myAlertMsgPopupBoxID",BuildAlertBox:function(e){let t;const r=e.split("\n");t='
';for(var s=0;s"+r[s]+"

";return t+='
',t},CloseAlert:function(){null!=this.alertMsgBox&&this.alertMsgBox.close()},ShowAlert:function(e){this.alertMsgBox=document.getElementById(this.alertMsgBoxID),null==this.alertMsgBox&&(this.alertMsgBox=document.body.appendChild(document.createElement("dialog")),this.alertMsgBox.setAttribute("id",this.alertMsgBoxID)),this.alertMsgBox.close(),this.alertMsgBox.innerHTML=this.BuildAlertBox(e),this.alertMsgBox.showModal()}};var theButtonBackStyle=null;function SetButtonGenState(e,t,r){t?(document.getElementById(e).disabled=!1,document.getElementById(e).title=r,null!=theButtonBackStyle&&(document.getElementById(e).style.background=theButtonBackStyle)):(0==document.getElementById(e).disabled&&(theButtonBackStyle=document.getElementById(e).style.background),document.getElementById(e).disabled=!0,document.getElementById(e).title=r,document.getElementById(e).style.background="grey")}function SetNTPReadyCheckButtonState(e,t){let r;r=e?NTPReadyCheck.buttonHintMsg:t,SetButtonGenState("btnSaveNTPcheck",e,r)}function Get_NTPReadyCheck_Option(){$.ajax({url:"/ext/scmerlin/NTP_Ready_Config.htm",dataType:"text",error:function(e){document.form.scMerlin_NTPcheck.value="Disable",NTPReadyCheck.prevOptionValue="DISABLED",WaitMsgPopupBox.CloseMsg(),SetNTPReadyCheckButtonState(!0,null),$("#scMerlin_NTPcheck_Status").text("Currently: DISABLED")},success:function(e){let t=e.split("\n");t=t.filter(Boolean);let r,s,a,n,i,o=t.length,l="";for(var c=0;c (a."+sortfield+".toLowerCase() > b."+sortfield+".toLowerCase()) ? 1 : ((b."+sortfield+".toLowerCase() > a."+sortfield+".toLowerCase()) ? -1 : 0));"),window[sortdir]="asc"):(eval(arrayid+" = "+arrayid+".sort((a,b) => (a."+sortfield+".toLowerCase() < b."+sortfield+".toLowerCase()) ? 1 : ((b."+sortfield+".toLowerCase() < a."+sortfield+".toLowerCase()) ? -1 : 0));"),window[sortdir]="desc"):"number"==sorttype&&(-1==sorttext.indexOf("↓")&&-1==sorttext.indexOf("↑")||-1!=sorttext.indexOf("↓")?(eval(arrayid+" = "+arrayid+".sort((a,b) => parseFloat(getNum(a."+sortfield+'.replace("m","000"))) - parseFloat(getNum(b.'+sortfield+'.replace("m","000"))));'),window[sortdir]="asc"):(eval(arrayid+" = "+arrayid+".sort((a,b) => parseFloat(getNum(b."+sortfield+'.replace("m","000"))) - parseFloat(getNum(a.'+sortfield+'.replace("m","000"))));'),window[sortdir]="desc")),$("#"+tableid).empty(),$("#"+tableid).append(BuildSortTableHtml(tableid)),$("#"+tableid).find(".sortable").each((function(e,t){t.innerHTML==window[sortname]&&("asc"==window[sortdir]?t.innerHTML=window[sortname]+" ↑":t.innerHTML=window[sortname]+" ↓")}))}function getNum(e){if(isNaN(e)){if("*"==e)return-10;if(-1!=e.indexOf("*/"))return-5;if(-1!=e.indexOf("/"))return e.split("/")[0];if("Sun"==e)return 0;if("Mon"==e)return 1;if("Tue"==e)return 2;if("Wed"==e)return 3;if("Thu"==e)return 4;if("Fri"==e)return 5;if("Sat"==e)return 6}return e}function ToggleRefresh(){1==$("#auto_refresh").prop("checked")?get_proclist_file():null!=tmout&&clearTimeout(tmout)}function BuildAddonPageTable(e,t,r){var s="";if(0==r&&(s+='
 
',s+='',s+='',s+='',s+=""),0!=r&&r%4!=0||(s+=""),s+='",r>0&&(r+1)%4==0&&(s+=""),r==sortedAddonPages.length-1){if(sortedAddonPages.length%4!=0){for(var a=4-sortedAddonPages.length%4,n=0;n';s+=""}s+="
WebUI Addons (click to expand/collapse)
'+e+'
'+t.substring(t.lastIndexOf("/")+1)+"
"}return s}function BuildServiceTable(e,t,r,s){var a="";return 0==s&&(a+='
 
',a+='',a+='',a+='',a+=""),0!=s&&s%2!=0||(a+=""),a+=r?'":'",a+='",s>0&&(s+1)%2==0&&(a+=""),s==srvnamelist.length-1&&(a+="
Services (click to expand/collapse)
'+t+' ('+e+")'+t+"',a+='',a+='',a+='',a+='',a+="
"),a}function Build_OpenVPNClient_Table(theIndex){let vpnClientHTML="",vpnClientName="vpnclient"+theIndex,vpnClientDesc=eval("document.form.vpnc"+theIndex+"_desc").value;return 1==theIndex&&(vpnClientHTML+='
 
',vpnClientHTML+='',vpnClientHTML+='',vpnClientHTML+='',vpnClientHTML+=""),1!=theIndex&&(theIndex+1)%2!=0||(vpnClientHTML+=""),vpnClientHTML+='",vpnClientHTML+='",5==theIndex&&(vpnClientHTML+=''),theIndex>1&&theIndex%2==0&&(vpnClientHTML+=""),5==theIndex&&(vpnClientHTML+="
OpenVPN Clients (click to expand/collapse)
OpenVPN Client '+theIndex,vpnClientHTML+='
('+vpnClientDesc+")
',vpnClientHTML+='',vpnClientHTML+='',vpnClientHTML+='',vpnClientHTML+='',vpnClientHTML+="
"),vpnClientHTML}function Build_OpenVPNServer_Table(e){let t="",r="vpnserver"+e;return 1==e&&(t+='
 
',t+='',t+='',t+='',t+="",t+=""),t+='",t+='",2==e&&(t+="",t+="
OpenVPN Servers (click to expand/collapse)
OpenVPN Server '+e+"',t+='',t+='',t+='',t+='',t+="
"),t}function Build_WireGuardServer_Table(e){let t="",r="wgServer"+e;return 1==e&&(t+='
 
',t+='',t+='',t+='',t+="",t+=""),t+='",t+='",1==e&&(t+='',t+="
WireGuard Server (click to expand/collapse)
WireGuard Server '+e+"',t+='',t+='',t+='',t+='',t+="
"),t}function Build_WireGuardClient_Table(theIndex){let wgClientHTML="",wgClientName="wgClient"+theIndex,wgClientDesc=eval("document.form.wrgc"+theIndex+"_desc").value;return null!==wgClientDesc&&""!==wgClientDesc||(wgClientDesc="No description"),1==theIndex&&(wgClientHTML+='
 
',wgClientHTML+='',wgClientHTML+='',wgClientHTML+='',wgClientHTML+=""),1!=theIndex&&(theIndex+1)%2!=0||(wgClientHTML+=""),wgClientHTML+='",wgClientHTML+='",5==theIndex&&(wgClientHTML+=''),theIndex>1&&theIndex%2==0&&(wgClientHTML+=""),5==theIndex&&(wgClientHTML+="
WireGuard Clients (click to expand/collapse)
WireGuard Client '+theIndex,wgClientHTML+='
('+wgClientDesc+")
',wgClientHTML+='',wgClientHTML+='',wgClientHTML+='',wgClientHTML+='',wgClientHTML+="
"),wgClientHTML}function round(e,t){return Number(Math.round(e+"e"+t)+"e-"+t)}function Draw_Chart_NoData(e,t){document.getElementById("canvasChart"+e).width="265",document.getElementById("canvasChart"+e).height="250",document.getElementById("canvasChart"+e).style.width="265px",document.getElementById("canvasChart"+e).style.height="250px";var r=document.getElementById("canvasChart"+e).getContext("2d");r.save(),r.textAlign="center",r.textBaseline="middle",r.font="normal normal bolder 22px Arial",r.fillStyle="white",r.fillText(t,135,125),r.restore()}function Draw_Chart(e){var t=[],r=[],s=[],a="",n="";"MemoryUsage"==e?(t=[1*mem_stats_arr[0]-1*mem_stats_arr[1]-1*mem_stats_arr[2]-1*mem_stats_arr[3],mem_stats_arr[1],mem_stats_arr[2],mem_stats_arr[3]],r=["Used","Free","Buffers","Cache"],s=["#5eaec0","#12cf80","#ceca09","#9d12c4"],a="Memory Usage",n="MB"):"SwapUsage"==e?(t=[mem_stats_arr[4],1*mem_stats_arr[5]-1*mem_stats_arr[4]],r=["Used","Free"],s=["#135fee","#1aa658"],a="Swap Usage",n="MB"):"nvramUsage"==e?(t=[round(mem_stats_arr[6]/1024,2).toFixed(2),round(1*nvramtotal-1*mem_stats_arr[6]/1024,2).toFixed(2)],r=["Used","Free"],s=["#5eaec0","#12cf80"],a="NVRAM Usage",n="KB"):"jffsUsage"==e&&(t=[jffs_Used,jffs_Free],r=["Used","Free"],s=["#135fee","#1aa658"],a="JFFS Usage",n="MB");var i=window["Chart"+e];null!=i&&i.destroy();var o=document.getElementById("canvasChart"+e).getContext("2d");i=new Chart(o,{type:"pie",options:{segmentShowStroke:!1,segmentStrokeColor:"#000",maintainAspectRatio:!1,animation:{duration:0},hover:{animationDuration:0},responsiveAnimationDuration:0,legend:{onClick:null,display:!0,position:"left",labels:{fontColor:"#ffffff"}},title:{display:!0,text:a,position:"top"},tooltips:{callbacks:{title:function(e,t){return t.labels[e[0].index]},label:function(e,t){return round(t.datasets[e.datasetIndex].data[e.index],2).toFixed(2)+" "+n}},mode:"point",position:"cursor",intersect:!0},scales:{xAxes:[{display:!1,gridLines:{display:!1},scaleLabel:{display:!1},ticks:{display:!1}}],yAxes:[{display:!1,gridLines:{display:!1},scaleLabel:{display:!1},ticks:{display:!1}}]}},data:{labels:r,datasets:[{data:t,borderWidth:1,backgroundColor:s,borderColor:"#000000"}]}}),window["Chart"+e]=i} +var arrayproclistlines=[],sortnameproc="CPU%",sortdirproc="desc",arraycronjobs=[],sortnamecron="Name",sortdircron="asc",tmout=null;function SetCurrentPage(){document.form.next_page.value=window.location.pathname.substring(1),document.form.current_page.value=window.location.pathname.substring(1)}Chart.defaults.global.defaultFontColor="#CCC",Chart.Tooltip.positioners.cursor=function(e,t){return t};var srvnamelist=["dnsmasq","wan","httpd","wireless","vsftpd","samba","ddns","ntpd/chronyd"],srvdesclist=["DNS/DHCP Server","Internet Connection","Web Interface","WiFi","FTP Server","Samba","DDNS client","Timeserver"],srvnamevisiblelist=[!0,!1,!0,!1,!0,!1,!1,!0],sortedAddonPages=[];function initial(){SetCurrentPage(),LoadCustomSettings(),show_menu(),Draw_Chart_NoData("nvramUsage","Data loading..."),Draw_Chart_NoData("jffsUsage","Data loading..."),Draw_Chart_NoData("MemoryUsage","Data loading..."),Draw_Chart_NoData("SwapUsage","No swap file configured"),$("#sortTableCron").empty(),$("#sortTableCron").append(BuildSortTableHtmlNoData()),$("#sortTableProcesses").empty(),$("#sortTableProcesses").append(BuildSortTableHtmlNoData());let e="",t="";if(isWireGuard_Supported){e+=Build_WireGuardServer_Table(1),$("#table_config").after(e);for(var r=1;r<6;r++)t+=Build_WireGuardClient_Table(r);$("#table_config").after(t)}let s="";for(r=1;r<3;r++)s+=Build_OpenVPNServer_Table(r);$("#table_config").after(s);let a="";for(r=1;r<6;r++)a+=Build_OpenVPNClient_Table(r);$("#table_config").after(a);let n="";for(var i=0;i",'',"Data loading...","","","",'
Data loading...
'}function BuildSortTableHtml(e){var t='';if("sortTableProcesses"==e){t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+='';for(var r=0;r',t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+=""}else if("sortTableCron"==e){t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+='',t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+='';for(r=0;r',t+="",t+="",t+="",t+="",t+="",t+="",t+="",t+=""}return t+="",t+="
PIDPPIDUSERSTATVSZVSZ%CPUCPU%COMMAND
"+arrayproclistlines[r].PID+""+arrayproclistlines[r].PPID+""+arrayproclistlines[r].USER+""+arrayproclistlines[r].STAT+""+arrayproclistlines[r].VSZ+""+arrayproclistlines[r].VSZP+""+arrayproclistlines[r].CPU+""+arrayproclistlines[r].CPUP+""+arrayproclistlines[r].COMMAND+"
NameMinHourDayMMonthDayWCommand
"+arraycronjobs[r].Name+""+arraycronjobs[r].Min+""+arraycronjobs[r].Hour+""+arraycronjobs[r].DayM+""+arraycronjobs[r].Month+""+arraycronjobs[r].DayW+""+arraycronjobs[r].Command+"
"}function Get_NTPWatchdogEnabled_File(){$.ajax({url:"/ext/scmerlin/watchdogenabled.htm",dataType:"text",error:function(e){document.form.scMerlin_NTPwatchdog.value="Disable",$("#scMerlin_NTPwatchdog_Status").text("Currently: DISABLED")},success:function(e){document.form.scMerlin_NTPwatchdog.value="Enable",$("#scMerlin_NTPwatchdog_Status").text("Currently: ENABLED")}})}function Save_NTPWatchdog(){document.form.action_script.value="start_scmerlin_NTPwatchdog"+document.form.scMerlin_NTPwatchdog.value,document.form.action_wait.value=4,$("#auto_refresh").prop("checked",!1),null!=tmout&&clearTimeout(tmout),showLoading(),document.form.submit(),setTimeout(Get_NTPWatchdogEnabled_File,4e3)}function Get_DNSmasqWatchdogEnabled_File(){$.ajax({url:"/ext/scmerlin/tailtaintdnsenabled.htm",dataType:"text",error:function(e){document.form.scMerlin_DNSmasqWatchdog.value="Disable",$("#scMerlin_DNSmasqWatchdog_Status").text("Currently: DISABLED")},success:function(e){document.form.scMerlin_DNSmasqWatchdog.value="Enable",$("#scMerlin_DNSmasqWatchdog_Status").text("Currently: ENABLED")}})}function Get_WebUIDropdownsEnabled_File(){$.ajax({url:"/ext/scmerlin/webuidropdownenabled.htm",dataType:"text",cache:false,error:function(){document.form.scMerlin_WebUIDropdowns.value="Disable",$("#scMerlin_WebUIDropdowns_Status").text("Currently: DISABLED")},success:function(){document.form.scMerlin_WebUIDropdowns.value="Enable",$("#scMerlin_WebUIDropdowns_Status").text("Currently: ENABLED")}})}function Save_WebUIDropdowns(){document.form.action_script.value="start_scmerlin_WebUIDropdowns"+document.form.scMerlin_WebUIDropdowns.value,document.form.action_wait.value=4,$("#auto_refresh").prop("checked",false),null!=tmout&&clearTimeout(tmout),showLoading(),document.form.submit(),setTimeout(Get_WebUIDropdownsEnabled_File,4e3)}function Save_DNSmasqWatchdog(){document.form.action_script.value="start_scmerlin_DNSmasqWatchdog"+document.form.scMerlin_DNSmasqWatchdog.value,document.form.action_wait.value=4,$("#auto_refresh").prop("checked",!1),null!=tmout&&clearTimeout(tmout),showLoading(),document.form.submit(),setTimeout(Get_DNSmasqWatchdogEnabled_File,4e3)}const WaitMsgPopupBox={waitCounter:0,waitMaxSecs:0,waitTimerOn:!1,waitTimerID:null,waitMsgBox:null,waitMsgTemp:"",waitMsgBoxID:"myWaitMsgPopupBoxID",CloseMsg:function(){this.waitTimerOn=!1,this.waitCounter=0,this.waitMaxSecs=0,this.waitMsgTemp="",null!=this.waitTimerID&&(clearTimeout(this.waitTimerID),this.waitTimerID=null),null!=this.waitMsgBox&&this.waitMsgBox.close()},StartMsg:function(e,t,r){this.waitTimerOn||(this.waitTimerOn=!0,this.waitCounter=0,this.waitMsgTemp="",this.waitMaxSecs=Math.round(t/1e3),this.ShowTimedMsg(e,r))},ShowTimedMsg:function(e,t){if(this.waitCounter>this.waitMaxSecs)return void this.CloseMsg();if(!this.waitTimerOn)return;this.waitMsgBox=document.getElementById(this.waitMsgBoxID),null==this.waitMsgBox&&(this.waitMsgBox=document.body.appendChild(document.createElement("dialog")),this.waitMsgBox.setAttribute("id",this.waitMsgBoxID));let r=this.waitCounter+1;0==this.waitCounter&&this.waitMsgBox.close(),t?t&&(this.waitMsgBox.innerText=e+` [${r}]`):(0==this.waitCounter?this.waitMsgTemp=e+"\n >":this.waitMsgTemp=this.waitMsgTemp+">",this.waitMsgBox.innerText=this.waitMsgTemp),0==this.waitCounter&&this.waitMsgBox.showModal(),this.waitCounter=r,this.waitTimerID=setTimeout((function(){WaitMsgPopupBox.ShowTimedMsg(e,t)}),1e3)},ShowMsg:function(e,t){this.waitMsgBox=document.getElementById(this.waitMsgBoxID),null==this.waitMsgBox&&(this.waitMsgBox=document.body.appendChild(document.createElement("dialog")),this.waitMsgBox.setAttribute("id",this.waitMsgBoxID)),this.waitMsgBox.close(),this.waitMsgBox.innerText=e,this.waitMsgBox.showModal(),setTimeout((function(){WaitMsgPopupBox.waitMsgBox.close()}),t)}},AlertMsgBox={alertMsgBox:null,alertMsgBoxID:"myAlertMsgPopupBoxID",BuildAlertBox:function(e){let t;const r=e.split("\n");t='
';for(var s=0;s"+r[s]+"

";return t+='
',t},CloseAlert:function(){null!=this.alertMsgBox&&this.alertMsgBox.close()},ShowAlert:function(e){this.alertMsgBox=document.getElementById(this.alertMsgBoxID),null==this.alertMsgBox&&(this.alertMsgBox=document.body.appendChild(document.createElement("dialog")),this.alertMsgBox.setAttribute("id",this.alertMsgBoxID)),this.alertMsgBox.close(),this.alertMsgBox.innerHTML=this.BuildAlertBox(e),this.alertMsgBox.showModal()}};var theButtonBackStyle=null;function SetButtonGenState(e,t,r){t?(document.getElementById(e).disabled=!1,document.getElementById(e).title=r,null!=theButtonBackStyle&&(document.getElementById(e).style.background=theButtonBackStyle)):(0==document.getElementById(e).disabled&&(theButtonBackStyle=document.getElementById(e).style.background),document.getElementById(e).disabled=!0,document.getElementById(e).title=r,document.getElementById(e).style.background="grey")}function SetNTPReadyCheckButtonState(e,t){let r;r=e?NTPReadyCheck.buttonHintMsg:t,SetButtonGenState("btnSaveNTPcheck",e,r)}function Get_NTPReadyCheck_Option(){$.ajax({url:"/ext/scmerlin/NTP_Ready_Config.htm",dataType:"text",error:function(e){document.form.scMerlin_NTPcheck.value="Disable",NTPReadyCheck.prevOptionValue="DISABLED",WaitMsgPopupBox.CloseMsg(),SetNTPReadyCheckButtonState(!0,null),$("#scMerlin_NTPcheck_Status").text("Currently: DISABLED")},success:function(e){let t=e.split("\n");t=t.filter(Boolean);let r,s,a,n,i,o=t.length,l="";for(var c=0;c (a."+sortfield+".toLowerCase() > b."+sortfield+".toLowerCase()) ? 1 : ((b."+sortfield+".toLowerCase() > a."+sortfield+".toLowerCase()) ? -1 : 0));"),window[sortdir]="asc"):(eval(arrayid+" = "+arrayid+".sort((a,b) => (a."+sortfield+".toLowerCase() < b."+sortfield+".toLowerCase()) ? 1 : ((b."+sortfield+".toLowerCase() < a."+sortfield+".toLowerCase()) ? -1 : 0));"),window[sortdir]="desc"):"number"==sorttype&&(-1==sorttext.indexOf("↓")&&-1==sorttext.indexOf("↑")||-1!=sorttext.indexOf("↓")?(eval(arrayid+" = "+arrayid+".sort((a,b) => parseFloat(getNum(a."+sortfield+'.replace("m","000"))) - parseFloat(getNum(b.'+sortfield+'.replace("m","000"))));'),window[sortdir]="asc"):(eval(arrayid+" = "+arrayid+".sort((a,b) => parseFloat(getNum(b."+sortfield+'.replace("m","000"))) - parseFloat(getNum(a.'+sortfield+'.replace("m","000"))));'),window[sortdir]="desc")),$("#"+tableid).empty(),$("#"+tableid).append(BuildSortTableHtml(tableid)),$("#"+tableid).find(".sortable").each((function(e,t){t.innerHTML==window[sortname]&&("asc"==window[sortdir]?t.innerHTML=window[sortname]+" ↑":t.innerHTML=window[sortname]+" ↓")}))}function getNum(e){if(isNaN(e)){if("*"==e)return-10;if(-1!=e.indexOf("*/"))return-5;if(-1!=e.indexOf("/"))return e.split("/")[0];if("Sun"==e)return 0;if("Mon"==e)return 1;if("Tue"==e)return 2;if("Wed"==e)return 3;if("Thu"==e)return 4;if("Fri"==e)return 5;if("Sat"==e)return 6}return e}function ToggleRefresh(){1==$("#auto_refresh").prop("checked")?get_proclist_file():null!=tmout&&clearTimeout(tmout)}function BuildAddonPageTable(e,t,r){var s="";if(0==r&&(s+='
 
',s+='',s+='',s+='',s+=""),0!=r&&r%4!=0||(s+=""),s+='",r>0&&(r+1)%4==0&&(s+=""),r==sortedAddonPages.length-1){if(sortedAddonPages.length%4!=0){for(var a=4-sortedAddonPages.length%4,n=0;n';s+=""}s+="
WebUI Addons (click to expand/collapse)
'+e+'
'+t.substring(t.lastIndexOf("/")+1)+"
"}return s}function BuildServiceTable(e,t,r,s){var a="";return 0==s&&(a+='
 
',a+='',a+='',a+='',a+=""),0!=s&&s%2!=0||(a+=""),a+=r?'":'",a+='",s>0&&(s+1)%2==0&&(a+=""),s==srvnamelist.length-1&&(a+="
Services (click to expand/collapse)
'+t+' ('+e+")'+t+"',a+='',a+='',a+='',a+='',a+="
"),a}function Build_OpenVPNClient_Table(theIndex){let vpnClientHTML="",vpnClientName="vpnclient"+theIndex,vpnClientDesc=eval("document.form.vpnc"+theIndex+"_desc").value;return 1==theIndex&&(vpnClientHTML+='
 
',vpnClientHTML+='',vpnClientHTML+='',vpnClientHTML+='',vpnClientHTML+=""),1!=theIndex&&(theIndex+1)%2!=0||(vpnClientHTML+=""),vpnClientHTML+='",vpnClientHTML+='",5==theIndex&&(vpnClientHTML+=''),theIndex>1&&theIndex%2==0&&(vpnClientHTML+=""),5==theIndex&&(vpnClientHTML+="
OpenVPN Clients (click to expand/collapse)
OpenVPN Client '+theIndex,vpnClientHTML+='
('+vpnClientDesc+")
',vpnClientHTML+='',vpnClientHTML+='',vpnClientHTML+='',vpnClientHTML+='',vpnClientHTML+="
"),vpnClientHTML}function Build_OpenVPNServer_Table(e){let t="",r="vpnserver"+e;return 1==e&&(t+='
 
',t+='',t+='',t+='',t+="",t+=""),t+='",t+='",2==e&&(t+="",t+="
OpenVPN Servers (click to expand/collapse)
OpenVPN Server '+e+"',t+='',t+='',t+='',t+='',t+="
"),t}function Build_WireGuardServer_Table(e){let t="",r="wgServer"+e;return 1==e&&(t+='
 
',t+='',t+='',t+='',t+="",t+=""),t+='",t+='",1==e&&(t+='',t+="
WireGuard Server (click to expand/collapse)
WireGuard Server '+e+"',t+='',t+='',t+='',t+='',t+="
"),t}function Build_WireGuardClient_Table(theIndex){let wgClientHTML="",wgClientName="wgClient"+theIndex,wgClientDesc=eval("document.form.wrgc"+theIndex+"_desc").value;return null!==wgClientDesc&&""!==wgClientDesc||(wgClientDesc="No description"),1==theIndex&&(wgClientHTML+='
 
',wgClientHTML+='',wgClientHTML+='',wgClientHTML+='',wgClientHTML+=""),1!=theIndex&&(theIndex+1)%2!=0||(wgClientHTML+=""),wgClientHTML+='",wgClientHTML+='",5==theIndex&&(wgClientHTML+=''),theIndex>1&&theIndex%2==0&&(wgClientHTML+=""),5==theIndex&&(wgClientHTML+="
WireGuard Clients (click to expand/collapse)
WireGuard Client '+theIndex,wgClientHTML+='
('+wgClientDesc+")
',wgClientHTML+='',wgClientHTML+='',wgClientHTML+='',wgClientHTML+='',wgClientHTML+="
"),wgClientHTML}function round(e,t){return Number(Math.round(e+"e"+t)+"e-"+t)}function Draw_Chart_NoData(e,t){document.getElementById("canvasChart"+e).width="265",document.getElementById("canvasChart"+e).height="250",document.getElementById("canvasChart"+e).style.width="265px",document.getElementById("canvasChart"+e).style.height="250px";var r=document.getElementById("canvasChart"+e).getContext("2d");r.save(),r.textAlign="center",r.textBaseline="middle",r.font="normal normal bolder 22px Arial",r.fillStyle="white",r.fillText(t,135,125),r.restore()}function Draw_Chart(e){var t=[],r=[],s=[],a="",n="";"MemoryUsage"==e?(t=[1*mem_stats_arr[0]-1*mem_stats_arr[1]-1*mem_stats_arr[2]-1*mem_stats_arr[3],mem_stats_arr[1],mem_stats_arr[2],mem_stats_arr[3]],r=["Used","Free","Buffers","Cache"],s=["#5eaec0","#12cf80","#ceca09","#9d12c4"],a="Memory Usage",n="MB"):"SwapUsage"==e?(t=[mem_stats_arr[4],1*mem_stats_arr[5]-1*mem_stats_arr[4]],r=["Used","Free"],s=["#135fee","#1aa658"],a="Swap Usage",n="MB"):"nvramUsage"==e?(t=[round(mem_stats_arr[6]/1024,2).toFixed(2),round(1*nvramtotal-1*mem_stats_arr[6]/1024,2).toFixed(2)],r=["Used","Free"],s=["#5eaec0","#12cf80"],a="NVRAM Usage",n="KB"):"jffsUsage"==e&&(t=[jffs_Used,jffs_Free],r=["Used","Free"],s=["#135fee","#1aa658"],a="JFFS Usage",n="MB");var i=window["Chart"+e];null!=i&&i.destroy();var o=document.getElementById("canvasChart"+e).getContext("2d");i=new Chart(o,{type:"pie",options:{segmentShowStroke:!1,segmentStrokeColor:"#000",maintainAspectRatio:!1,animation:{duration:0},hover:{animationDuration:0},responsiveAnimationDuration:0,legend:{onClick:null,display:!0,position:"left",labels:{fontColor:"#ffffff"}},title:{display:!0,text:a,position:"top"},tooltips:{callbacks:{title:function(e,t){return t.labels[e[0].index]},label:function(e,t){return round(t.datasets[e.datasetIndex].data[e.index],2).toFixed(2)+" "+n}},mode:"point",position:"cursor",intersect:!0},scales:{xAxes:[{display:!1,gridLines:{display:!1},scaleLabel:{display:!1},ticks:{display:!1}}],yAxes:[{display:!1,gridLines:{display:!1},scaleLabel:{display:!1},ticks:{display:!1}}]}},data:{labels:r,datasets:[{data:t,borderWidth:1,backgroundColor:s,borderColor:"#000000"}]}}),window["Chart"+e]=i} @@ -660,6 +660,25 @@ var arrayproclistlines=[],sortnameproc="CPU%",sortdirproc="desc",arraycronjobs=[ + + + +Enable WebUI dropdown sub-menus
+ +Yes +No +       + +      + + + diff --git a/scmerlin_www.js b/scmerlin_www.js index 074caef..629505f 100644 --- a/scmerlin_www.js +++ b/scmerlin_www.js @@ -88,6 +88,7 @@ function initial() Get_NTPWatchdogEnabled_File(); Get_NTPReadyCheck_Option(); Get_DNSmasqWatchdogEnabled_File(); + Get_WebUIDropdownsEnabled_File(); update_temperatures(); update_wanuptime(); update_sysinfo(); @@ -377,6 +378,39 @@ function Get_DNSmasqWatchdogEnabled_File() }); } +function Get_WebUIDropdownsEnabled_File() +{ + $.ajax({ + url: "/ext/scmerlin/webuidropdownenabled.htm", + dataType: "text", + cache: false, + error: function(){ + document.form.scMerlin_WebUIDropdowns.value = "Disable"; + $("#scMerlin_WebUIDropdowns_Status").text("Currently: DISABLED"); + }, + success: function(){ + document.form.scMerlin_WebUIDropdowns.value = "Enable"; + $("#scMerlin_WebUIDropdowns_Status").text("Currently: ENABLED"); + } + }); +} + +function Save_WebUIDropdowns() +{ + document.form.action_script.value = + "start_scmerlin_WebUIDropdowns" + document.form.scMerlin_WebUIDropdowns.value; + + document.form.action_wait.value = 4; + + $("#auto_refresh").prop("checked", false); + if (tmout != null) clearTimeout(tmout); + + showLoading(); + document.form.submit(); + + setTimeout(Get_WebUIDropdownsEnabled_File, 4000); +} + /**-------------------------------------**/ /** Added by Martinski W. [2024-Apr-29] **/ /**-------------------------------------**/ From 725b694433b33667a64b48987a1f42731d37f18d Mon Sep 17 00:00:00 2001 From: ExtremeFiretop Date: Tue, 3 Mar 2026 21:16:03 -0500 Subject: [PATCH 05/14] Actually detach state.js modifications Actually detach state.js modifications --- scmerlin.sh | 275 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 202 insertions(+), 73 deletions(-) diff --git a/scmerlin.sh b/scmerlin.sh index 87ea840..9d2b69a 100644 --- a/scmerlin.sh +++ b/scmerlin.sh @@ -770,42 +770,14 @@ Update_Check() echo "$doupdate,$localver,$serverver" } -##----------------------------------------## -## Modified by Martinski W. [2025-May-17] ## -##----------------------------------------## -AppendTo_statejs_3004_() +##------------------------------------------## +## Modified by ExtremeFiretop [2026-Mar-03] ## +##------------------------------------------## +AppendTo_statejs_Sitemap_3004_() { - cat << 'EOF' + cat << 'EOF' +/*BEGIN:SCMERLIN_SITEMAP*/ var myMenu = []; -function AddDropdowns() -{ - if (myMenu.length == 0) - { - setTimeout(AddDropdowns,1000); - return; - } - for (var i = 0; i < myMenu.length; i++) - { - var sitemapstring = '