diff --git a/doc/lucky1.png b/doc/lucky1.png
new file mode 100644
index 00000000..a5b41b6e
Binary files /dev/null and b/doc/lucky1.png differ
diff --git a/doc/lucky2.png b/doc/lucky2.png
new file mode 100644
index 00000000..ba4c026f
Binary files /dev/null and b/doc/lucky2.png differ
diff --git a/doc/lucky3.png b/doc/lucky3.png
new file mode 100644
index 00000000..6fa7982f
Binary files /dev/null and b/doc/lucky3.png differ
diff --git a/doc/taskplan1.png b/doc/taskplan1.png
deleted file mode 100644
index 1f8db7be..00000000
Binary files a/doc/taskplan1.png and /dev/null differ
diff --git a/doc/taskplan2.png b/doc/taskplan2.png
deleted file mode 100644
index edb45d6d..00000000
Binary files a/doc/taskplan2.png and /dev/null differ
diff --git a/doc/taskplan3.png b/doc/taskplan3.png
deleted file mode 100644
index d4794702..00000000
Binary files a/doc/taskplan3.png and /dev/null differ
diff --git a/doc/view.png b/doc/view.png
deleted file mode 100644
index 169e112f..00000000
Binary files a/doc/view.png and /dev/null differ
diff --git a/doc/view2.png b/doc/view2.png
deleted file mode 100644
index 9058c632..00000000
Binary files a/doc/view2.png and /dev/null differ
diff --git a/luci-app-passwall/htdocs/luci-static/resources/view/passwall/cbi.js b/luci-app-passwall/htdocs/luci-static/resources/view/passwall/cbi.js
new file mode 100644
index 00000000..3f9d6470
--- /dev/null
+++ b/luci-app-passwall/htdocs/luci-static/resources/view/passwall/cbi.js
@@ -0,0 +1,38 @@
+function is_json(str) {
+ try {
+ const result = JSON.parse(str);
+ return typeof result === 'object' && result !== null;
+ } catch (e) {
+ return false;
+ }
+}
+
+function is_timehhmm(str) {
+ const match = String(str).match(/^(\d?\d):(\d\d)$/);
+ if (match) {
+ const hour = parseInt(match[1], 10);
+ const minute = parseInt(match[2], 10);
+ if (hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59) {
+ return true;
+ }
+ }
+ return false;
+}
+
+if (typeof cbi_validators !== 'undefined' && cbi_validators !== null) {
+ cbi_validators['json'] = function() {
+ return is_json(this);
+ }
+ cbi_validators['timehhmm'] = function() {
+ return is_timehhmm(this);
+ }
+} else {
+ L.require('validation').then(function(validation) {
+ validation.types['json'] = function() {
+ return this.assert(is_json(this.value), _('Must be JSON text!'));
+ }
+ validation.types['timehhmm'] = function() {
+ return this.assert(is_timehhmm(this.value), _('valid time (hh:mm)'));
+ }
+ });
+}
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/acl.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/acl.lua
index 9d5edc7e..860f9106 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/acl.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/acl.lua
@@ -2,6 +2,8 @@ local api = require "luci.passwall.api"
local appname = "passwall"
local sys = api.sys
+api.set_default_cbi()
+
m = Map(appname)
api.set_apply_on_parse(m)
@@ -101,4 +103,4 @@ o:value("1:65535", translate("All"))
o:value("53", "53")
]]--
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua
index d908e37d..4dec1580 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua
@@ -1,6 +1,8 @@
local api = require "luci.passwall.api"
local appname = "passwall"
+api.set_default_cbi()
+
m = Map(appname)
m.redirect = api.url("acl")
api.set_apply_on_parse(m)
@@ -601,4 +603,4 @@ for k, v in pairs(nodes_table) do
end
end
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua
index 5f573a9e..3f2a7760 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua
@@ -2,6 +2,8 @@ local api = require "luci.passwall.api"
local com = require "luci.passwall.com"
local appname = "passwall"
+api.set_default_cbi()
+
m = Map(appname)
api.set_apply_on_parse(m)
@@ -34,4 +36,4 @@ o.cfgvalue = function(t, n)
return string.format('%s', translate("if you want to run from memory, change the path, /tmp beginning then save the application and update it manually."))
end
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
index ebbf3395..7a012136 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
@@ -8,6 +8,8 @@ local has_gfwlist = fs.access("/usr/share/passwall/rules/gfwlist")
local has_chnlist = fs.access("/usr/share/passwall/rules/chnlist")
local has_chnroute = fs.access("/usr/share/passwall/rules/chnroute")
+api.set_default_cbi()
+
m = Map(appname)
api.set_apply_on_parse(m)
@@ -839,4 +841,4 @@ footer.global_cfgid = global_cfgid
footer.shunt_list = api.jsonc.stringify(shunt_list)
m:append(footer)
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua
index 972a96a7..abff0091 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/haproxy.lua
@@ -15,6 +15,8 @@ for k, e in ipairs(api.get_valid_nodes()) do
end
end
+api.set_default_cbi()
+
m = Map(appname, "HAPROXY " .. translate("Load Balancing"))
api.set_apply_on_parse(m)
@@ -179,4 +181,4 @@ o.rmempty = false
m:append(Template(appname .. "/haproxy/js"))
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
index 9cbb3a9e..1f8ba7af 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
@@ -1,6 +1,8 @@
api = require "luci.passwall.api"
appname = "passwall"
+api.set_default_cbi()
+
m = Map(appname, translate("Node Config"))
m.redirect = api.url("node_list")
api.set_apply_on_parse(m)
@@ -120,7 +122,6 @@ local footer = Template(appname .. "/node_config/footer")
footer.api = api
footer.config = m.config
footer.section = arg[1]
-
m:append(footer)
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_list.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_list.lua
index 3bdf8fcc..8c16f598 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_list.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_list.lua
@@ -3,6 +3,8 @@ local appname = "passwall"
local sys = api.sys
local datatypes = api.datatypes
+api.set_default_cbi()
+
m = Map(appname)
api.set_apply_on_parse(m)
@@ -33,4 +35,4 @@ s:append(Template(appname .. "/node_list/link_add_node"))
m:append(Template(appname .. "/node_list/node_list"))
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua
index 481477aa..326b2df0 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe.lua
@@ -38,6 +38,8 @@ if has_hysteria2 then
table.insert(hysteria2_type, s)
end
+api.set_default_cbi()
+
m = Map(appname)
api.set_apply_on_parse(m)
@@ -225,4 +227,4 @@ end
m:append(Template(appname .. "/node_subscribe/js"))
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua
index e3d2c44c..98e52f7e 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua
@@ -2,6 +2,8 @@ local api = require "luci.passwall.api"
local uci = api.uci
local appname = "passwall"
+api.set_default_cbi()
+
m = Map(appname)
m.redirect = api.url("node_subscribe")
api.set_apply_on_parse(m)
@@ -244,13 +246,7 @@ o:value(0, translate("Every Sunday"))
o = s:option(Value, "update_time_mode", translate("Update Time"))
for t = 0, 23 do o:value(t .. ":00") end
o.default = "0:00"
-o.validate = function(self, value)
- local b = api.is_timehhmm(value)
- if b then
- return value
- end
- return nil
-end
+o.datatype = "timehhmm"
o:depends("update_week_mode", "0")
o:depends("update_week_mode", "1")
o:depends("update_week_mode", "2")
@@ -321,4 +317,4 @@ for k, v in pairs(nodes_table) do
end
end
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua
index 2f53c6ae..efe0cccc 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua
@@ -8,6 +8,8 @@ local port_validate = function(self, value, t)
return value:gsub("-", ":")
end
+api.set_default_cbi()
+
m = Map(appname)
api.set_apply_on_parse(m)
@@ -43,13 +45,7 @@ for index, value in ipairs({"stop", "start", "restart"}) do
o = s:option(Value, value .. "_time_mode", translate(value .. " Time"))
for t = 0, 23 do o:value(t .. ":00") end
o.default = "0:00"
- o.validate = function(self, value)
- local b = api.is_timehhmm(value)
- if b then
- return value
- end
- return nil
- end
+ o.datatype = "timehhmm"
o:depends(value .. "_week_mode", "0")
o:depends(value .. "_week_mode", "1")
o:depends(value .. "_week_mode", "2")
@@ -271,4 +267,4 @@ if has_singbox then
o.default = 0
end
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua
index c6e12ed8..8ad9e7e1 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua
@@ -3,6 +3,8 @@ local appname = "passwall"
local has_xray = api.finded_com("xray")
local has_singbox = api.finded_com("sing-box")
+api.set_default_cbi()
+
m = Map(appname)
api.set_apply_on_parse(m)
@@ -112,13 +114,7 @@ o:value(0, translate("Every Sunday"))
o = s:option(Value, "update_time_mode", translate("Update Time"))
for t = 0, 23 do o:value(t .. ":00") end
o.default = "0:00"
-o.validate = function(self, value)
- local b = api.is_timehhmm(value)
- if b then
- return value
- end
- return nil
-end
+o.datatype = "timehhmm"
o:depends("update_week_mode", "0")
o:depends("update_week_mode", "1")
o:depends("update_week_mode", "2")
@@ -169,4 +165,4 @@ if has_xray or has_singbox then
o = s:option(DummyValue, "remarks", translate("Remarks"))
end
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/rule_list.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/rule_list.lua
index 6ad3f058..030874b3 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/rule_list.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/rule_list.lua
@@ -1,5 +1,5 @@
local api = require "luci.passwall.api"
-local appname = "passwall"
+local appname = api.appname
local fs = api.fs
local sys = api.sys
local uci = api.uci
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/shunt_rules.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/shunt_rules.lua
index 85596c9b..4b45eba4 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/shunt_rules.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/shunt_rules.lua
@@ -2,6 +2,8 @@ local api = require "luci.passwall.api"
local appname = "passwall"
local datatypes = api.datatypes
+api.set_default_cbi()
+
m = Map(appname, "Sing-Box/Xray " .. translate("Shunt Rule"))
m.redirect = api.url("rule")
api.set_apply_on_parse(m)
@@ -245,4 +247,4 @@ ip_list.description = "
"
o = s:option(Flag, "invert", "Invert", translate("Invert match result.") .. " " .. translate("Only support Sing-Box."))
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua
index e2025548..7427bbf6 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua
@@ -1,6 +1,8 @@
local api = require "luci.passwall.api"
local appname = "passwall"
+api.set_default_cbi()
+
m = Map(appname)
m.redirect = api.url()
api.set_apply_on_parse(m)
@@ -166,4 +168,4 @@ o = s:option(DummyValue, "btn")
o.template = appname .. "/socks_auto_switch/btn"
o:depends("backup_node_add_mode", "manual")
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua
index 00fd19a4..ffb01c33 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua
@@ -667,6 +667,14 @@ o = s:option(TextValue, _n("xhttp_extra"), " ", translate("An XHttpObject in J
o:depends({ [_n("use_xhttp_extra")] = true })
o.rows = 10
o.wrap = "off"
+o.datatype = "json"
+local o_validate = o.validate
+o.validate = function(self, value)
+ value = api.trim(value):gsub("\r\n", "\n"):gsub("^[ \t]*\n", ""):gsub("\n[ \t]*$", ""):gsub("\n[ \t]*\n", "\n")
+ local v = o_validate(self, value)
+ if v then return v end
+ return nil, "XHTTP Extra " .. translate("Must be JSON text!")
+end
o.custom_cfgvalue = function(self, section, value)
local raw = m:get(section, "xhttp_extra")
if raw then
@@ -689,14 +697,6 @@ o.custom_write = function(self, section, value)
m:del(section, "download_address")
end
end
-o.validate = function(self, value)
- value = api.trim(value):gsub("\r\n", "\n"):gsub("^[ \t]*\n", ""):gsub("\n[ \t]*$", ""):gsub("\n[ \t]*\n", "\n")
- if api.jsonc.parse(value) then
- return value
- else
- return nil, "XHTTP Extra " .. translate("Must be JSON text!")
- end
-end
o.custom_remove = function(self, section, value)
m:del(section, "xhttp_extra")
m:del(section, "download_address")
@@ -752,6 +752,14 @@ o.rows = 10
o.wrap = "off"
o.description = translate("An FinalMaskObject in JSON format, used for sharing.") .. "
" ..
translate("Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related settings.")
+o.datatype = "json"
+local o_validate = o.validate
+o.validate = function(self, value)
+ value = api.trim(value):gsub("\r\n", "\n"):gsub("^[ \t]*\n", ""):gsub("\n[ \t]*$", ""):gsub("\n[ \t]*\n", "\n")
+ local v = o_validate(self, value)
+ if v then return v end
+ return nil, "FinalMask " .. translate("Must be JSON text!")
+end
o.custom_cfgvalue = function(self, section, value)
local raw = m:get(section, "finalmask")
if raw then
@@ -761,14 +769,6 @@ end
o.custom_write = function(self, section, value)
m:set(section, "finalmask", api.base64Encode(value) or "")
end
-o.validate = function(self, value)
- value = api.trim(value):gsub("\r\n", "\n"):gsub("^[ \t]*\n", ""):gsub("\n[ \t]*$", ""):gsub("\n[ \t]*\n", "\n")
- if api.jsonc.parse(value) then
- return value
- else
- return nil, "FinalMask " .. translate("Must be JSON text!")
- end
-end
--[[Fast Open]]
o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"), translate("Need node support required"))
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/index.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/index.lua
index d6ee9323..752c306e 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/index.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/index.lua
@@ -1,4 +1,7 @@
local api = require "luci.passwall.api"
+local appname = api.appname
+
+api.set_default_cbi()
m = Map("passwall_server", translate("Server-Side"))
api.set_apply_on_parse(m)
@@ -85,7 +88,8 @@ e = t:option(Flag, "log", translate("Log"))
e.default = "1"
e.rmempty = false
-m:append(Template("passwall/server/log"))
+m:append(Template(appname .. "/server/log"))
-m:append(Template("passwall/server/users_list_status"))
-return m
+m:append(Template(appname .. "/server/users_list_status"))
+
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua
index e3402ac3..661727d6 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua
@@ -131,12 +131,12 @@ o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
-o.validate = function(self, value, t)
- if value and api.jsonc.parse(value) then
- return value
- else
- return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
- end
+o.datatype = "json"
+local o_validate = o.validate
+o.validate = function(self, value)
+ local v = o_validate(self, value)
+ if v then return v end
+ return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua
index 17fca650..7e1cf876 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua
@@ -406,6 +406,7 @@ o = s:option(TextValue, _n("finalmask"), "FinalMask JSON")
o:depends({ [_n("use_finalmask")] = true })
o.rows = 10
o.wrap = "off"
+o.datatype = "json"
o.custom_cfgvalue = function(self, section, value)
local raw = m:get(section, "finalmask")
if raw then
@@ -415,14 +416,6 @@ end
o.custom_write = function(self, section, value)
m:set(section, "finalmask", api.base64Encode(value) or "")
end
-o.validate = function(self, value)
- value = api.trim(value):gsub("\r\n", "\n"):gsub("^[ \t]*\n", ""):gsub("\n[ \t]*$", ""):gsub("\n[ \t]*\n", "\n")
- if api.jsonc.parse(value) then
- return value
- else
- return nil, "FinalMask " .. translate("Must be JSON text!")
- end
-end
--[[acceptProxyProtocol]]
o = s:option(Flag, _n("acceptProxyProtocol"), translate("acceptProxyProtocol"), translate("Whether to receive PROXY protocol, when this node want to be fallback or forwarded by proxy, it must be enable, otherwise it cannot be used."))
@@ -517,16 +510,16 @@ for _, d in ipairs(netdev_list) do
o:value(d.name, d.label)
end
-o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
+o = s:option(TextValue, _n("custom_config"), translate("Custom Config") .. " (JSON)")
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
-o.validate = function(self, value, t)
- if value and api.jsonc.parse(value) then
- return value
- else
- return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
- end
+o.datatype = "json"
+local o_validate = o.validate
+o.validate = function(self, value)
+ local v = o_validate(self, value)
+ if v then return v end
+ return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua
index 92ff2fa2..75d2553b 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua
@@ -489,16 +489,16 @@ for _, d in ipairs(netdev_list) do
o:value(d.name, d.label)
end
-o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
+o = s:option(TextValue, _n("custom_config"), translate("Custom Config") .. " (JSON)")
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
-o.validate = function(self, value, t)
- if value and api.jsonc.parse(value) then
- return value
- else
- return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
- end
+o.datatype = "json"
+local o_validate = o.validate
+o.validate = function(self, value)
+ local v = o_validate(self, value)
+ if v then return v end
+ return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua
index ed2a2863..54b710ec 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua
@@ -49,16 +49,16 @@ o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"))
o.default = "0"
o:depends({ [_n("custom")] = false })
-o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
+o = s:option(TextValue, _n("custom_config"), translate("Custom Config") .. " (JSON)")
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
-o.validate = function(self, value, t)
- if value and api.jsonc.parse(value) then
- return value
- else
- return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
- end
+o.datatype = "json"
+local o_validate = o.validate
+o.validate = function(self, value)
+ local v = o_validate(self, value)
+ if v then return v end
+ return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua
index 02a94f61..d77cf74c 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua
@@ -76,16 +76,16 @@ o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"))
o.default = "0"
o:depends({ [_n("custom")] = false })
-o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
+o = s:option(TextValue, _n("custom_config"), translate("Custom Config") .. " (JSON)")
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
-o.validate = function(self, value, t)
- if value and api.jsonc.parse(value) then
- return value
- else
- return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
- end
+o.datatype = "json"
+local o_validate = o.validate
+o.validate = function(self, value)
+ local v = o_validate(self, value)
+ if v then return v end
+ return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/user.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/user.lua
index 35312f53..89b70292 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/user.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/user.lua
@@ -2,6 +2,8 @@ api = require "luci.passwall.api"
appname = api.appname
fs = api.fs
+api.set_default_cbi()
+
m = Map("passwall_server", translate("Server Config"))
m.redirect = api.url("server")
api.set_apply_on_parse(m)
@@ -56,4 +58,4 @@ footer.config = m.config
footer.section = arg[1]
m:append(footer)
-return m
+return api.return_map(m)
diff --git a/luci-app-passwall/luasrc/passwall/api.lua b/luci-app-passwall/luasrc/passwall/api.lua
index 3755ea3a..62b05f75 100644
--- a/luci-app-passwall/luasrc/passwall/api.lua
+++ b/luci-app-passwall/luasrc/passwall/api.lua
@@ -348,8 +348,16 @@ function strToTable(str)
return loadstring("return " .. str)()
end
-function is_timehhmm(timeStr)
- local hour, minute = string.match(timeStr, "^(%d?%d):(%d%d)$")
+function is_json(str)
+ if str and jsonc.parse(str) then
+ return true
+ end
+ return false
+end
+datatypes.json = is_json
+
+function is_timehhmm(str)
+ local hour, minute = string.match(str, "^(%d?%d):(%d%d)$")
if hour and minute then
hour = tonumber(hour)
minute = tonumber(minute)
@@ -359,6 +367,7 @@ function is_timehhmm(timeStr)
end
return false
end
+datatypes.timehhmm = is_timehhmm
function is_normal_node(e)
if e and e.type and e.protocol and (e.protocol == "_balancing" or e.protocol == "_shunt" or e.protocol == "_iface" or e.protocol == "_urltest") then
@@ -1327,6 +1336,40 @@ function to_check_self()
}
end
+function set_default_cbi()
+ local cbi = require "luci.cbi"
+ if true then
+ --TextValue
+ local TextValue = cbi.TextValue
+ local original_init = TextValue.__init__
+ function TextValue.__init__(self, ...)
+ original_init(self, ...)
+ self.template = appname .. "/cbi/tvalue"
+ end
+ end
+end
+
+function return_map(map)
+ local cbi = require "luci.cbi"
+ local api = require "luci.passwall.api"
+ if true then
+ -- header
+ local header = cbi.Template(appname .. "/cbi/header")
+ header.api = api
+ header.config = map.config
+ table.insert(map.children, 1, header)
+ end
+ if true then
+ -- footer
+ local footer = cbi.Template(appname .. "/cbi/footer")
+ footer.api = api
+ footer.config = map.config
+ map:append(footer)
+ end
+
+ return map
+end
+
function luci_types(id, m, s, type_name, option_prefix)
local fv_type
local field_type = s.fields["type"]
diff --git a/luci-app-passwall/luasrc/view/passwall/cbi/footer.htm b/luci-app-passwall/luasrc/view/passwall/cbi/footer.htm
new file mode 100644
index 00000000..46a25d3e
--- /dev/null
+++ b/luci-app-passwall/luasrc/view/passwall/cbi/footer.htm
@@ -0,0 +1 @@
+
diff --git a/luci-app-passwall/luasrc/view/passwall/cbi/header.htm b/luci-app-passwall/luasrc/view/passwall/cbi/header.htm
new file mode 100644
index 00000000..5d284d90
--- /dev/null
+++ b/luci-app-passwall/luasrc/view/passwall/cbi/header.htm
@@ -0,0 +1,2 @@
+
+
diff --git a/luci-app-passwall/luasrc/view/passwall/cbi/tvalue.htm b/luci-app-passwall/luasrc/view/passwall/cbi/tvalue.htm
new file mode 100644
index 00000000..8037b3d2
--- /dev/null
+++ b/luci-app-passwall/luasrc/view/passwall/cbi/tvalue.htm
@@ -0,0 +1,13 @@
+<%+cbi/valueheader%>
+
+<%+cbi/valuefooter%>
diff --git a/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm b/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm
index 86c49b14..654ccd54 100644
--- a/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm
+++ b/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm
@@ -635,11 +635,15 @@ table td, .table .td {
if (cacheData && cacheData.savetime && (now - cacheData.timestamp) < cacheData.savetime) {
const a = ping_value[i].firstElementChild;
let color = "red";
- if (cacheData.value < 100)
- color = "green";
- else if (cacheData.value < 200)
- color = "#fb9a05";
- a.innerText = cacheData.value + " ms";
+ if (cacheData.value >= 0) {
+ a.innerText = cacheData.value + " ms";
+ if (cacheData.value < 100)
+ color = "green";
+ else if (cacheData.value < 200)
+ color = "#fb9a05";
+ } else {
+ a.innerText = "<%:Timeout%>";
+ }
a.style.color = color;
a.onclick = function () {
ping_node(cbi_id, this, auto_detection_time);
@@ -679,15 +683,23 @@ table td, .table .td {
const cache_data = {
dom_id: strs[i],
timestamp: Date.now(),
- savetime: 60 * 1000,
+ savetime: 150 * 1000,
value: ping
};
- text = result.ping + " ms";
localStorage.setItem(auto_detection_time + ":" + dom.address + ":" + dom.port, JSON.stringify(cache_data));
+ text = result.ping + " ms";
if (ping < 100)
color = "green";
else if (ping < 200)
color = "#fb9a05";
+ } else {
+ const cache_data = {
+ dom_id: strs[i],
+ timestamp: Date.now(),
+ savetime: 60 * 1000,
+ value: -1
+ };
+ localStorage.setItem(auto_detection_time + ":" + dom.address + ":" + dom.port, JSON.stringify(cache_data));
}
a.innerText = text;
a.style.color = color;
@@ -1101,6 +1113,15 @@ table td, .table .td {
onChange("auto_detection_time", auto_detection_time);
});
});
+
+ const links = document.querySelectorAll('a');
+ links.forEach(link => {
+ link.addEventListener('click', (e) => {
+ if (link.getAttribute('target') !== '_blank') {
+ ajaxAbortAll();
+ }
+ });
+ });
});
//]]>
diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po
index 63222c62..726e5952 100644
--- a/luci-app-passwall/po/zh-cn/passwall.po
+++ b/luci-app-passwall/po/zh-cn/passwall.po
@@ -2144,3 +2144,6 @@ msgstr "Gecko 包大小(最小)"
msgid "Gecko Packet Size (max)"
msgstr "Gecko 包大小(最大)"
+
+msgid "valid time (hh:mm)"
+msgstr "有效时间(hh:mm)"