mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-10-30 15:45:13 +08:00
update 2026-08-08 16:33:49
This commit is contained in:
1 parent
d76a25e5cf
commit
74e7dc08d2
22 files changed
+794
-131
No files matched your search
+2
-2
@@ -5,12 +5,12 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=dae
|
PKG_NAME:=dae
|
||||||
PKG_VERSION:=2026.08.06
|
PKG_VERSION:=2026.08.08
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
|
|
||||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||||
PKG_SOURCE_PROTO:=git
|
PKG_SOURCE_PROTO:=git
|
||||||
PKG_SOURCE_VERSION:=c7547891533d195731507977cb36734a5a18aa14
|
PKG_SOURCE_VERSION:=f52534a912a2f0a1406740384684667c1ece89c0
|
||||||
PKG_SOURCE_URL:=https://github.com/olicesx/dae.git
|
PKG_SOURCE_URL:=https://github.com/olicesx/dae.git
|
||||||
PKG_MIRROR_HASH:=skip
|
PKG_MIRROR_HASH:=skip
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -8,12 +8,12 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=ddns-go
|
PKG_NAME:=ddns-go
|
||||||
PKG_VERSION:=6.17.4
|
PKG_VERSION:=6.17.5
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
|
|
||||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||||
PKG_SOURCE_URL:=https://codeload.github.com/jeessy2/ddns-go/tar.gz/v$(PKG_VERSION)?
|
PKG_SOURCE_URL:=https://codeload.github.com/jeessy2/ddns-go/tar.gz/v$(PKG_VERSION)?
|
||||||
PKG_HASH:=80f3816d95933949ce7306b988b2612d91b95c6992af8e956378628fde19b615
|
PKG_HASH:=910ba8e64d05fd48043f4c88492f32f459367be022ec08f0aa6e977c5c3419bf
|
||||||
|
|
||||||
PKG_LICENSE:=MIT
|
PKG_LICENSE:=MIT
|
||||||
PKG_LICENSE_FILES:=LICENSE
|
PKG_LICENSE_FILES:=LICENSE
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
function arraysEqual(a, b) {
|
||||||
|
if (a === b) return true;
|
||||||
|
if (a == null || b == null) return false;
|
||||||
|
if (a.length !== b.length) return false;
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
if (a[i] !== b[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForElement(selector, callback) {
|
||||||
|
const el = document.querySelector(selector);
|
||||||
|
if (el) return callback(el);
|
||||||
|
const observer = new MutationObserver(() => {
|
||||||
|
const el = document.querySelector(selector);
|
||||||
|
if (el) {
|
||||||
|
observer.disconnect();
|
||||||
|
callback(el);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_current_url() {
|
||||||
|
return window.location.origin + window.location.pathname;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOption(config, section, opt) {
|
||||||
|
let obj;
|
||||||
|
const id = `cbid.${config}.${section}.${opt}`;
|
||||||
|
obj = document.getElementsByName(id)[0] || document.getElementById(id);
|
||||||
|
if (obj) {
|
||||||
|
const combobox = document.getElementById('cbi.combobox.' + id);
|
||||||
|
if (combobox) {
|
||||||
|
obj.combobox = combobox;
|
||||||
|
}
|
||||||
|
const div = document.getElementById(id);
|
||||||
|
if (div && div.getElementsByTagName("li").length > 0) {
|
||||||
|
obj = div;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -79,8 +79,8 @@ function index()
|
|||||||
entry({"admin", "services", appname, "connect_status"}, call("connect_status")).leaf = true
|
entry({"admin", "services", appname, "connect_status"}, call("connect_status")).leaf = true
|
||||||
entry({"admin", "services", appname, "ping_node"}, call("ping_node")).leaf = true
|
entry({"admin", "services", appname, "ping_node"}, call("ping_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "urltest_node"}, call("urltest_node")).leaf = true
|
entry({"admin", "services", appname, "urltest_node"}, call("urltest_node")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "update_config"}, call("update_config")).leaf = true
|
||||||
entry({"admin", "services", appname, "add_node"}, call("add_node")).leaf = true
|
entry({"admin", "services", appname, "add_node"}, call("add_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "update_node"}, call("update_node")).leaf = true
|
|
||||||
entry({"admin", "services", appname, "set_node"}, call("set_node")).leaf = true
|
entry({"admin", "services", appname, "set_node"}, call("set_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "copy_node"}, call("copy_node")).leaf = true
|
entry({"admin", "services", appname, "copy_node"}, call("copy_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true
|
entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true
|
||||||
@@ -96,6 +96,10 @@ function index()
|
|||||||
entry({"admin", "services", appname, "subscribe_manual"}, call("subscribe_manual")).leaf = true
|
entry({"admin", "services", appname, "subscribe_manual"}, call("subscribe_manual")).leaf = true
|
||||||
entry({"admin", "services", appname, "subscribe_manual_all"}, call("subscribe_manual_all")).leaf = true
|
entry({"admin", "services", appname, "subscribe_manual_all"}, call("subscribe_manual_all")).leaf = true
|
||||||
entry({"admin", "services", appname, "flush_set"}, call("flush_set")).leaf = true
|
entry({"admin", "services", appname, "flush_set"}, call("flush_set")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "get_shunt_rules"}, call("get_shunt_rules")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "add_shunt_rule"}, call("add_shunt_rule")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "delete_select_shunt_rules"}, call("delete_select_shunt_rules")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "save_shunt_rule_order"}, call("save_shunt_rule_order")).leaf = true
|
||||||
|
|
||||||
--[[rule_list]]
|
--[[rule_list]]
|
||||||
entry({"admin", "services", appname, "read_rulelist"}, call("read_rulelist")).leaf = true
|
entry({"admin", "services", appname, "read_rulelist"}, call("read_rulelist")).leaf = true
|
||||||
@@ -471,6 +475,23 @@ function urltest_node()
|
|||||||
http_write_json(e)
|
http_write_json(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function update_config()
|
||||||
|
local id = http.formvalue("id") -- Node id
|
||||||
|
local data = http.formvalue("data") -- json new Data
|
||||||
|
if id and data then
|
||||||
|
local data_t = jsonParse(data) or {}
|
||||||
|
if next(data_t) then
|
||||||
|
for k, v in pairs(data_t) do
|
||||||
|
uci:set(appname, id, k, v)
|
||||||
|
end
|
||||||
|
api.uci_save(uci, appname)
|
||||||
|
http_write_json_ok()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
http_write_json_error()
|
||||||
|
end
|
||||||
|
|
||||||
function add_node()
|
function add_node()
|
||||||
local redirect = http.formvalue("redirect")
|
local redirect = http.formvalue("redirect")
|
||||||
|
|
||||||
@@ -493,23 +514,6 @@ function add_node()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function update_node()
|
|
||||||
local id = http.formvalue("id") -- Node id
|
|
||||||
local data = http.formvalue("data") -- json new Data
|
|
||||||
if id and data then
|
|
||||||
local data_t = jsonParse(data) or {}
|
|
||||||
if next(data_t) then
|
|
||||||
for k, v in pairs(data_t) do
|
|
||||||
uci:set(appname, id, k, v)
|
|
||||||
end
|
|
||||||
api.uci_save(uci, appname)
|
|
||||||
http_write_json_ok()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
http_write_json_error()
|
|
||||||
end
|
|
||||||
|
|
||||||
function set_node()
|
function set_node()
|
||||||
local protocol = http.formvalue("protocol")
|
local protocol = http.formvalue("protocol")
|
||||||
local section = http.formvalue("section")
|
local section = http.formvalue("section")
|
||||||
@@ -1134,3 +1138,87 @@ function fetch_certsha256()
|
|||||||
local data = api.fetch_cert_sha256(address, port, sni, timeout, h3)
|
local data = api.fetch_cert_sha256(address, port, sni, timeout, h3)
|
||||||
http_write_json(data ~= "" and { code = 1, data = data } or { code = 0 })
|
http_write_json(data ~= "" and { code = 1, data = data } or { code = 0 })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function get_shunt_rules()
|
||||||
|
local id = http.formvalue("id")
|
||||||
|
local result = {}
|
||||||
|
|
||||||
|
if id then
|
||||||
|
result = uci:get_all(appname, id)
|
||||||
|
else
|
||||||
|
local default_items = {}
|
||||||
|
local other_items = {}
|
||||||
|
uci:foreach(appname, "shunt_rules", function(t)
|
||||||
|
if not t.group or t.group == "" then
|
||||||
|
default_items[#default_items + 1] = t
|
||||||
|
else
|
||||||
|
other_items[#other_items + 1] = t
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
for i = 1, #default_items do result[#result + 1] = default_items[i] end
|
||||||
|
for i = 1, #other_items do result[#result + 1] = other_items[i] end
|
||||||
|
end
|
||||||
|
http_write_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
function add_shunt_rule()
|
||||||
|
local add_name = http.formvalue("add_name")
|
||||||
|
local redirect = http.formvalue("redirect")
|
||||||
|
|
||||||
|
local uuid = add_name
|
||||||
|
if add_name then
|
||||||
|
local has = uci:get(appname, uuid)
|
||||||
|
if has then
|
||||||
|
http_write_json_error({ message = "This ID already exists." })
|
||||||
|
return
|
||||||
|
end
|
||||||
|
else
|
||||||
|
uuid = api.gen_short_uuid()
|
||||||
|
end
|
||||||
|
uci:section(appname, "shunt_rules", uuid)
|
||||||
|
|
||||||
|
local group = http.formvalue("group")
|
||||||
|
if group and group ~= "default" then
|
||||||
|
uci:set(appname, uuid, "group", group)
|
||||||
|
end
|
||||||
|
|
||||||
|
if redirect == "1" then
|
||||||
|
api.uci_save(uci, appname)
|
||||||
|
http.redirect(api.url("shunt_rules", uuid))
|
||||||
|
else
|
||||||
|
api.uci_save(uci, appname)
|
||||||
|
http_write_json_ok({uuid = uuid, redirect_url = api.url("shunt_rules", uuid)})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function delete_select_shunt_rules()
|
||||||
|
local ids = http.formvalue("ids")
|
||||||
|
local redirect = http.formvalue("redirect")
|
||||||
|
string.gsub(ids, '[^' .. "," .. ']+', function(w)
|
||||||
|
uci:foreach(appname, "nodes", function(s)
|
||||||
|
if s["protocol"] and s["protocol"] == "_shunt" then
|
||||||
|
uci:delete(appname, s[".name"], w)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
uci:delete(appname, w)
|
||||||
|
end)
|
||||||
|
if redirect == "1" then
|
||||||
|
api.uci_save(uci, appname)
|
||||||
|
http.redirect(api.url("rule"))
|
||||||
|
else
|
||||||
|
api.uci_save(uci, appname, true, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function save_shunt_rule_order()
|
||||||
|
local ids = http.formvalue("ids") or ""
|
||||||
|
local new_order = {}
|
||||||
|
for id in ids:gmatch("([^,]+)") do
|
||||||
|
new_order[#new_order + 1] = id
|
||||||
|
end
|
||||||
|
for idx, name in ipairs(new_order) do
|
||||||
|
luci.sys.call(string.format("uci -q reorder %s.%s=%d", appname, name, idx - 1))
|
||||||
|
end
|
||||||
|
api.sh_uci_commit(appname)
|
||||||
|
http_write_json({ status = "ok" })
|
||||||
|
end
|
||||||
@@ -154,6 +154,7 @@ if (has_singbox or has_xray) and #nodes_table > 0 then
|
|||||||
if current_node.protocol == "_shunt" then
|
if current_node.protocol == "_shunt" then
|
||||||
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall/client/include/shunt_options.lua")
|
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall/client/include/shunt_options.lua")
|
||||||
setfenv(shunt_lua, getfenv(1))(m, s, {
|
setfenv(shunt_lua, getfenv(1))(m, s, {
|
||||||
|
s_cfgid = s:cfgsections()[1],
|
||||||
node_id = current_node_id,
|
node_id = current_node_id,
|
||||||
node = current_node,
|
node = current_node,
|
||||||
socks_list = socks_list,
|
socks_list = socks_list,
|
||||||
|
|||||||
@@ -4,9 +4,17 @@ if not data.node_id or not data.node then
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local s_cfgid = data.s_cfgid
|
||||||
local current_node_id = data.node_id
|
local current_node_id = data.node_id
|
||||||
local node_list = data.node_list or api.get_node_list()
|
local node_list = data.node_list or api.get_node_list()
|
||||||
|
|
||||||
|
local groups = {}
|
||||||
|
m.uci:foreach(appname, "shunt_rules", function(s)
|
||||||
|
if s.group and s.group ~= "" then
|
||||||
|
groups[s.group] = true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
local function get_cfgvalue()
|
local function get_cfgvalue()
|
||||||
return function(self, section)
|
return function(self, section)
|
||||||
return m:get(current_node_id, self.option)
|
return m:get(current_node_id, self.option)
|
||||||
@@ -92,15 +100,27 @@ o = add_option(Flag, "fakedns", '<a style="color:#FF8C00">FakeDNS</a>' .. " " ..
|
|||||||
translate("Suitable scenarios for let the node servers get the target domain names.") .. "<br>" ..
|
translate("Suitable scenarios for let the node servers get the target domain names.") .. "<br>" ..
|
||||||
translate("Such as: DNS unlocking of streaming media, reducing DNS query latency, etc."))
|
translate("Such as: DNS unlocking of streaming media, reducing DNS query latency, etc."))
|
||||||
|
|
||||||
|
shunt_group = add_option(ListValue, "shunt_group", translate("Shunt Rule Group"))
|
||||||
|
shunt_group:value("", translate("default"))
|
||||||
|
for k, v in pairs(groups) do
|
||||||
|
shunt_group:value(k)
|
||||||
|
end
|
||||||
|
|
||||||
|
local shunt_group_val = m:get(current_node_id, "shunt_group") or ""
|
||||||
|
shunt_group_val = shunt_group_val:lower()
|
||||||
local shunt_rules = {}
|
local shunt_rules = {}
|
||||||
m.uci:foreach(appname, "shunt_rules", function(e)
|
m.uci:foreach(appname, "shunt_rules", function(e)
|
||||||
e.id = e[".name"]
|
local group = e.group or ""
|
||||||
e.remarks = e.remarks or e[".name"]
|
group = group:lower()
|
||||||
e["_node_option"] = e[".name"]
|
if group == shunt_group_val then
|
||||||
e["_node_default"] = ""
|
e.id = e[".name"]
|
||||||
e["_fakedns_option"] = e[".name"] .. "_fakedns"
|
e.remarks = e.remarks or e[".name"]
|
||||||
e["_proxy_tag_option"] = e[".name"] .. "_proxy_tag"
|
e["_node_option"] = e[".name"]
|
||||||
table.insert(shunt_rules, e)
|
e["_node_default"] = ""
|
||||||
|
e["_fakedns_option"] = e[".name"] .. "_fakedns"
|
||||||
|
e["_proxy_tag_option"] = e[".name"] .. "_proxy_tag"
|
||||||
|
table.insert(shunt_rules, e)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
table.insert(shunt_rules, {
|
table.insert(shunt_rules, {
|
||||||
id = ".default",
|
id = ".default",
|
||||||
@@ -185,6 +205,8 @@ end
|
|||||||
|
|
||||||
local footer = Template(appname .. "/include/shunt_options")
|
local footer = Template(appname .. "/include/shunt_options")
|
||||||
footer.api = api
|
footer.api = api
|
||||||
|
footer.config = m.config
|
||||||
footer.id = current_node_id
|
footer.id = current_node_id
|
||||||
|
footer.s_cfgid = s_cfgid or current_node_id
|
||||||
footer.normal_list = api.jsonc.stringify(node_list.normal_list)
|
footer.normal_list = api.jsonc.stringify(node_list.normal_list)
|
||||||
m:append(footer)
|
m:append(footer)
|
||||||
@@ -145,34 +145,8 @@ end
|
|||||||
|
|
||||||
s:append(Template(appname .. "/rule/rule_version"))
|
s:append(Template(appname .. "/rule/rule_version"))
|
||||||
|
|
||||||
local cfgname = "shunt_rules"
|
|
||||||
|
|
||||||
if has_xray or has_singbox then
|
if has_xray or has_singbox then
|
||||||
s = m:section(TypedSection, cfgname, "Sing-Box/Xray " .. translate("Shunt Rule"), "<a style='color: red'>" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "</a>")
|
m:append(Template(appname .. "/rule/shunt_rule_list"))
|
||||||
s.template = "cbi/tblsection"
|
|
||||||
s.anonymous = false
|
|
||||||
s.addremove = true
|
|
||||||
s.sortable = true
|
|
||||||
s.extedit = api.url("shunt_rules", "%s")
|
|
||||||
function s.create(e, t)
|
|
||||||
TypedSection.create(e, t)
|
|
||||||
luci.http.redirect(e.extedit:format(t))
|
|
||||||
end
|
|
||||||
function s.remove(e, t)
|
|
||||||
m.uci:foreach(appname, "nodes", function(s)
|
|
||||||
if s["protocol"] and s["protocol"] == "_shunt" then
|
|
||||||
m:del(s[".name"], t)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
TypedSection.remove(e, t)
|
|
||||||
end
|
|
||||||
|
|
||||||
o = s:option(DummyValue, "remarks", translate("Remarks"))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local sortable = Template(appname .. "/cbi/sortable")
|
|
||||||
sortable.api = api
|
|
||||||
sortable.target_cfgname = cfgname
|
|
||||||
m:append(sortable)
|
|
||||||
|
|
||||||
return api.return_map(m)
|
return api.return_map(m)
|
||||||
@@ -44,6 +44,19 @@ function clean_text(text)
|
|||||||
:gsub("[ \t]*\n[ \t]*", "\n")
|
:gsub("[ \t]*\n[ \t]*", "\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local remarks_lookup = {}
|
||||||
|
local groups = {}
|
||||||
|
m.uci:foreach(appname, "shunt_rules", function(s)
|
||||||
|
if s[".name"] ~= arg[1] then
|
||||||
|
if s.remarks then
|
||||||
|
remarks_lookup[s.remarks] = s[".name"]
|
||||||
|
end
|
||||||
|
if s.group and s.group ~= "" then
|
||||||
|
groups[s.group] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
s = m:section(NamedSection, arg[1], "shunt_rules", "")
|
s = m:section(NamedSection, arg[1], "shunt_rules", "")
|
||||||
s.addremove = false
|
s.addremove = false
|
||||||
s.dynamic = false
|
s.dynamic = false
|
||||||
@@ -56,9 +69,34 @@ remarks.validate = function(self, value, section)
|
|||||||
if value == "" then
|
if value == "" then
|
||||||
return nil, translate("Remark cannot be empty.")
|
return nil, translate("Remark cannot be empty.")
|
||||||
end
|
end
|
||||||
|
if remarks_lookup[value] then
|
||||||
|
return nil, translate("This remark already exists, please change a new remark.")
|
||||||
|
end
|
||||||
return value
|
return value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
o = s:option(Value, "group", translate("Shunt Rule Group"))
|
||||||
|
o.default = ""
|
||||||
|
o:value("", translate("default"))
|
||||||
|
for k, v in pairs(groups) do
|
||||||
|
o:value(k)
|
||||||
|
end
|
||||||
|
o.write = function(self, section, value)
|
||||||
|
value = api.trim(value)
|
||||||
|
local lower = value:lower()
|
||||||
|
|
||||||
|
if lower == "" or lower == "default" then
|
||||||
|
return m:del(section, self.option)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, v in ipairs(self.keylist or {}) do
|
||||||
|
if v:lower() == lower then
|
||||||
|
return m:set(section, self.option, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
m:set(section, self.option, value)
|
||||||
|
end
|
||||||
|
|
||||||
protocol = s:option(MultiValue, "protocol", translate("Protocol"))
|
protocol = s:option(MultiValue, "protocol", translate("Protocol"))
|
||||||
protocol:value("http")
|
protocol:value("http")
|
||||||
protocol:value("tls")
|
protocol:value("tls")
|
||||||
|
|||||||
@@ -1594,11 +1594,15 @@ function gen_config(var)
|
|||||||
[".name"] = "GFW_Mode_List",
|
[".name"] = "GFW_Mode_List",
|
||||||
remarks = "GFW_Mode_List",
|
remarks = "GFW_Mode_List",
|
||||||
domain_list = (domain_list ~= "") and domain_list or nil,
|
domain_list = (domain_list ~= "") and domain_list or nil,
|
||||||
ip_list = (ip_list ~= "") and ip_list or nil
|
ip_list = (ip_list ~= "") and ip_list or nil,
|
||||||
|
group = node["shunt_group"]
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
foreach_shunt_rule(function(e)
|
foreach_shunt_rule(function(e)
|
||||||
|
if node["shunt_group"] ~= e.group then
|
||||||
|
return
|
||||||
|
end
|
||||||
local outboundTag = gen_shunt_node(e[".name"])
|
local outboundTag = gen_shunt_node(e[".name"])
|
||||||
if outboundTag and e.remarks then
|
if outboundTag and e.remarks then
|
||||||
if outboundTag == "default" then
|
if outboundTag == "default" then
|
||||||
|
|||||||
@@ -1405,11 +1405,15 @@ function gen_config(var)
|
|||||||
[".name"] = "GFW_Mode_List",
|
[".name"] = "GFW_Mode_List",
|
||||||
remarks = "GFW_Mode_List",
|
remarks = "GFW_Mode_List",
|
||||||
domain_list = (domain_list ~= "") and domain_list or nil,
|
domain_list = (domain_list ~= "") and domain_list or nil,
|
||||||
ip_list = (ip_list ~= "") and ip_list or nil
|
ip_list = (ip_list ~= "") and ip_list or nil,
|
||||||
|
group = node["shunt_group"]
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
foreach_shunt_rule(function(e)
|
foreach_shunt_rule(function(e)
|
||||||
|
if node["shunt_group"] ~= e.group then
|
||||||
|
return
|
||||||
|
end
|
||||||
local outbound_tag = gen_shunt_node(e[".name"])
|
local outbound_tag = gen_shunt_node(e[".name"])
|
||||||
if outbound_tag and e.remarks then
|
if outbound_tag and e.remarks then
|
||||||
if outbound_tag == "default" then
|
if outbound_tag == "default" then
|
||||||
|
|||||||
@@ -1,2 +1,24 @@
|
|||||||
<!-- map header -->
|
<!-- map header -->
|
||||||
<script src="<%=resource%>/view/<%=self.api.appname%>/cbi.js"></script>
|
<script src="<%=resource%>/view/<%=self.api.appname%>/cbi.js"></script>
|
||||||
|
<script src="<%=resource%>/view/<%=self.api.appname%>/func.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
//<![CDATA[
|
||||||
|
function update_config(cfgid, data, redirect_url) {
|
||||||
|
XHR.get('<%=self.api.url("update_config")%>', {
|
||||||
|
id: cfgid,
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
},
|
||||||
|
function(x, data) {
|
||||||
|
if (x && x.status == 200 && data.code == 1) {
|
||||||
|
if (redirect_url) {
|
||||||
|
window.location.href = redirect_url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert("<%:Error%>");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
@@ -256,7 +256,7 @@ local appname = api.appname
|
|||||||
let new_val = el.target.value
|
let new_val = el.target.value
|
||||||
const new_hasItem = shunt_list.find(element => element.id == new_val);
|
const new_hasItem = shunt_list.find(element => element.id == new_val);
|
||||||
if (new_hasItem) {
|
if (new_hasItem) {
|
||||||
XHR.get('<%=api.url("update_node")%>', {
|
XHR.get('<%=api.url("update_config")%>', {
|
||||||
id: "<%=self.global_cfgid%>",
|
id: "<%=self.global_cfgid%>",
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
tcp_node: new_val
|
tcp_node: new_val
|
||||||
|
|||||||
@@ -53,6 +53,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
waitForElement('select[name*="<%=self.config%>"][name*="shunt_group"]', function(el) {
|
||||||
|
let o_val = el.value;
|
||||||
|
el.addEventListener("change", () => {
|
||||||
|
el.blur();
|
||||||
|
if (o_val != el.value) {
|
||||||
|
let save = true;
|
||||||
|
if (save) {
|
||||||
|
update_config("<%=self.id%>", {
|
||||||
|
shunt_group: getOption("<%=self.config%>", "<%=self.s_cfgid%>", "shunt_group").value,
|
||||||
|
}, get_current_url());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
document.addEventListener("DOMContentLoaded", () => setTimeout(() => {
|
document.addEventListener("DOMContentLoaded", () => setTimeout(() => {
|
||||||
refresh_depends();
|
refresh_depends();
|
||||||
const table_dom = document.getElementById("cbi-passwall-shunt_option_list");
|
const table_dom = document.getElementById("cbi-passwall-shunt_option_list");
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<%
|
|
||||||
local api = self.api
|
|
||||||
-%>
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
//<![CDATA[
|
//<![CDATA[
|
||||||
|
let node_id = "<%=self.section%>";
|
||||||
|
let node_config_url = '<%=self.api.url("node_config")%>/' + node_id;
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
waitForElement('select[name*="<%=self.config%>"][name*="type"]', function(el) {
|
waitForElement('select[name*="<%=self.config%>"][name*="type"]', function(el) {
|
||||||
let o_val = el.value;
|
let o_val = el.value;
|
||||||
@@ -11,13 +11,18 @@ local api = self.api
|
|||||||
if (o_val != el.value) {
|
if (o_val != el.value) {
|
||||||
let save = true;
|
let save = true;
|
||||||
if (save) {
|
if (save) {
|
||||||
//document.getElementsByClassName('cbi-button-save')[0].click();
|
/*
|
||||||
update_node({
|
const saveBtn = document.getElementsByClassName('cbi-button-save');
|
||||||
remarks: getOption("remarks").value,
|
if (saveBtn && saveBtn.length > 0) {
|
||||||
group: getOption("group").value,
|
saveBtn[saveBtn.length - 1].click();
|
||||||
type: getOption("type").value,
|
}
|
||||||
|
*/
|
||||||
|
update_config(node_id, {
|
||||||
|
remarks: getOption("<%=self.config%>", "<%=self.section%>", "remarks").value,
|
||||||
|
group: getOption("<%=self.config%>", "<%=self.section%>", "group").value,
|
||||||
|
type: getOption("<%=self.config%>", "<%=self.section%>", "type").value,
|
||||||
//protocol: ''
|
//protocol: ''
|
||||||
});
|
}, node_config_url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -31,12 +36,17 @@ local api = self.api
|
|||||||
let name = name_split[name_split.length - 1];
|
let name = name_split[name_split.length - 1];
|
||||||
let save = true;
|
let save = true;
|
||||||
if (save) {
|
if (save) {
|
||||||
//document.getElementsByClassName('cbi-button-save')[0].click();
|
/*
|
||||||
update_node({
|
const saveBtn = document.getElementsByClassName('cbi-button-save');
|
||||||
remarks: getOption("remarks").value,
|
if (saveBtn && saveBtn.length > 0) {
|
||||||
group: getOption("group").value,
|
saveBtn[saveBtn.length - 1].click();
|
||||||
protocol: getOption(name).value
|
}
|
||||||
});
|
*/
|
||||||
|
update_config(node_id, {
|
||||||
|
remarks: getOption("<%=self.config%>", "<%=self.section%>", "remarks").value,
|
||||||
|
group: getOption("<%=self.config%>", "<%=self.section%>", "group").value,
|
||||||
|
protocol: getOption("<%=self.config%>", "<%=self.section%>", name).value,
|
||||||
|
}, node_config_url);
|
||||||
} else {
|
} else {
|
||||||
window.location.href = node_config_url + "?select_proto=" + el.value;
|
window.location.href = node_config_url + "?select_proto=" + el.value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +1,11 @@
|
|||||||
<%
|
|
||||||
local api = self.api
|
|
||||||
-%>
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
//<![CDATA[
|
//<![CDATA[
|
||||||
let node_id = "<%=self.section%>";
|
|
||||||
let node_config_url = '<%=api.url("node_config")%>/' + node_id;
|
|
||||||
|
|
||||||
function waitForElement(selector, callback) {
|
|
||||||
const el = document.querySelector(selector);
|
|
||||||
if (el) return callback(el);
|
|
||||||
const observer = new MutationObserver(() => {
|
|
||||||
const el = document.querySelector(selector);
|
|
||||||
if (el) {
|
|
||||||
observer.disconnect();
|
|
||||||
callback(el);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
observer.observe(document.body, { childList: true, subtree: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
function getOption(opt) {
|
|
||||||
var obj;
|
|
||||||
var id = 'cbid.<%=self.config%>.' + node_id + '.' + opt;
|
|
||||||
obj = document.getElementsByName(id)[0] || document.getElementById(id);
|
|
||||||
if (obj) {
|
|
||||||
var combobox = document.getElementById('cbi.combobox.' + id);
|
|
||||||
if (combobox) {
|
|
||||||
obj.combobox = combobox;
|
|
||||||
}
|
|
||||||
var div = document.getElementById(id);
|
|
||||||
if (div && div.getElementsByTagName("li").length > 0) {
|
|
||||||
obj = div;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_node(data) {
|
|
||||||
XHR.get('<%=api.url("update_node")%>', {
|
|
||||||
id: node_id,
|
|
||||||
data: JSON.stringify(data)
|
|
||||||
},
|
|
||||||
function(x, data) {
|
|
||||||
if (x && x.status == 200 && data.code == 1) {
|
|
||||||
window.location.href = node_config_url;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
alert("<%:Error%>");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetchCertSha256(el) {
|
function fetchCertSha256(el) {
|
||||||
if (el.getAttribute("data-loading") === "1") return;
|
if (el.getAttribute("data-loading") === "1") return;
|
||||||
el.setAttribute("data-loading", "1");
|
el.setAttribute("data-loading", "1");
|
||||||
el.style.pointerEvents = "none";
|
el.style.pointerEvents = "none";
|
||||||
el.style.color = "red";
|
el.style.color = "red";
|
||||||
XHR.get('<%=api.url("fetch_certsha256")%>', { id: node_id }, function(x, res) {
|
XHR.get('<%=self.api.url("fetch_certsha256")%>', { id: "<%=self.section%>" }, function(x, res) {
|
||||||
el.setAttribute("data-loading", "0");
|
el.setAttribute("data-loading", "0");
|
||||||
el.style.pointerEvents = "";
|
el.style.pointerEvents = "";
|
||||||
el.style.color = "";
|
el.style.color = "";
|
||||||
|
|||||||
@@ -0,0 +1,475 @@
|
|||||||
|
<%
|
||||||
|
local api = require "luci.passwall.api"
|
||||||
|
local appname = api.appname
|
||||||
|
local uci = api.uci
|
||||||
|
-%>
|
||||||
|
<script src="<%=resource%>/view/<%=appname%>/Sortable.min.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
table th, .table .th {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td, .table .td {
|
||||||
|
text-align: center;
|
||||||
|
/* white-space: nowrap; */
|
||||||
|
word-break: keep-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td.cbi-section-actions {
|
||||||
|
text-align: right !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shunt_rule-wrapper {
|
||||||
|
align-items: center;
|
||||||
|
display: inline-flex !important;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cbi-tabmenu > li {
|
||||||
|
margin-right: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cbi-tabmenu > li:last-child {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shunt_rule-wrapper .drag-handle {
|
||||||
|
cursor: grab !important;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 100;
|
||||||
|
padding: 0 !important;
|
||||||
|
line-height: inherit;
|
||||||
|
user-select: none;
|
||||||
|
align-self: stretch;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shunt_rule-wrapper .drag-handle:hover {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable flex for small screens*/
|
||||||
|
@media screen and (max-width: 1152px) {
|
||||||
|
.cbi-section-table-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cbi-section-table-titles {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td-actions {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
border-top-width: 0 !important;
|
||||||
|
flex: 1 1 350px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shrink actionbar even further for mobile devices */
|
||||||
|
@media screen and (max-width: 500px) {
|
||||||
|
.shunt_rule-wrapper {
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cbi-button {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
margin-right: 1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td-actions {
|
||||||
|
padding-left: 5px!important;
|
||||||
|
padding-right: 5px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortable-chosen {
|
||||||
|
background-color: rgba(220, 235, 245, 0.4) !important;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortable-ghost {
|
||||||
|
background: #cce5ff !important;
|
||||||
|
height: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dragging-row {
|
||||||
|
background-color: rgba(131, 191, 255, 0.7) !important;
|
||||||
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<% if api.is_js_luci() then -%>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var cbi_t = [];
|
||||||
|
function cbi_t_add(section, tab) {
|
||||||
|
var t = document.getElementById('tab.' + section + '.' + tab);
|
||||||
|
var c = document.getElementById('container.' + section + '.' + tab);
|
||||||
|
|
||||||
|
if( t && c ) {
|
||||||
|
cbi_t[section] = (cbi_t[section] || [ ]);
|
||||||
|
cbi_t[section][tab] = { 'tab': t, 'container': c, 'cid': c.id };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cbi_t_switch(section, tab) {
|
||||||
|
if( cbi_t[section] && cbi_t[section][tab] ) {
|
||||||
|
// Before switching tabs, first deselect all currently active tabs.
|
||||||
|
var o = cbi_t[section][tab];
|
||||||
|
var h = document.getElementById('tab.' + section);
|
||||||
|
for( var tid in cbi_t[section] ) {
|
||||||
|
var o2 = cbi_t[section][tid];
|
||||||
|
if( o.tab.id != o2.tab.id ) {
|
||||||
|
o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab( |$)/, " cbi-tab-disabled ");
|
||||||
|
o2.container.style.display = 'none';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(h) h.value = tab;
|
||||||
|
o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab-disabled( |$)/, " cbi-tab ");
|
||||||
|
o2.container.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<%- end %>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
//<![CDATA[
|
||||||
|
function toPage(action, cbi_id) {
|
||||||
|
if (action == "add") {
|
||||||
|
const dom = document.getElementsByClassName("cbi-tab")[0];
|
||||||
|
const current_group = dom ? (dom.getAttribute("group_name") || "default") : "default";
|
||||||
|
const add_name_val = document.getElementById("add_name_" + current_group).value;
|
||||||
|
if (add_name_val.length > 1) {
|
||||||
|
XHR.get('<%=api.url("add_shunt_rule")%>', {
|
||||||
|
add_name: add_name_val,
|
||||||
|
group: current_group
|
||||||
|
},
|
||||||
|
function(x, result) {
|
||||||
|
if (x && x.status === 200) {
|
||||||
|
if (result.code == 1) {
|
||||||
|
window.location.href = result.data.redirect_url;
|
||||||
|
} else {
|
||||||
|
alert(result.data.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert("<%:Save failed!%>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (action == "edit") {
|
||||||
|
window.location.href='<%=api.url("shunt_rules")%>/' + cbi_id;
|
||||||
|
}
|
||||||
|
if (action == "del") {
|
||||||
|
window.location.href = '<%=api.url("delete_select_shunt_rules")%>' + "?redirect=1&ids=" + cbi_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function row_top(btn, group) {
|
||||||
|
const row = btn.closest("tr");
|
||||||
|
if (!row) return;
|
||||||
|
const parent = row.parentNode;
|
||||||
|
let firstDataRow = parent.querySelector("tr:not(.cbi-section-table-titles)");
|
||||||
|
if (firstDataRow && firstDataRow !== row) {
|
||||||
|
parent.insertBefore(row, firstDataRow);
|
||||||
|
let save_order_btn = document.getElementById("save_order_btn_" + group);
|
||||||
|
if (save_order_btn) {
|
||||||
|
const new_order = get_shunt_rule_order(group);
|
||||||
|
if (!arraysEqual(new_order, origin_group_shunt_rule_order[group])) {
|
||||||
|
save_order_btn.style.display = null;
|
||||||
|
} else {
|
||||||
|
save_order_btn.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_shunt_rule_order(group) {
|
||||||
|
let table = document.getElementById("cbi-<%=appname%>-shunt_rules-" + group + "-table");
|
||||||
|
if (!table) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let rows = table.querySelectorAll("tr.cbi-section-table-row");
|
||||||
|
if (!rows || rows.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var ids = [];
|
||||||
|
rows.forEach(function(row) {
|
||||||
|
var id = row.id.replace("cbi-<%=appname%>-", "");
|
||||||
|
ids.push(id);
|
||||||
|
});
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
function save_current_page_order(group) {
|
||||||
|
var table = document.getElementById("cbi-<%=appname%>-shunt_rules-" + group + "-table");
|
||||||
|
if (!table) {
|
||||||
|
alert("<%:No table!%>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var rows = table.querySelectorAll("tr.cbi-section-table-row");
|
||||||
|
if (!rows || rows.length === 0) {
|
||||||
|
alert("<%:No shunt_rules!%>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var btn = document.getElementById("save_order_btn_" + group);
|
||||||
|
if (btn) {
|
||||||
|
btn.style.display = "none";
|
||||||
|
btn.disabled = true;
|
||||||
|
}
|
||||||
|
var ids = [];
|
||||||
|
rows.forEach(function(row) {
|
||||||
|
var id = row.id.replace("cbi-<%=appname%>-", "");
|
||||||
|
ids.push(id);
|
||||||
|
});
|
||||||
|
XHR.get('<%=api.url("save_shunt_rule_order")%>', {
|
||||||
|
group: group,
|
||||||
|
ids: ids.join(",")
|
||||||
|
},
|
||||||
|
function(x, result) {
|
||||||
|
if (btn) {
|
||||||
|
btn.style.display = null;
|
||||||
|
btn.disabled = false;
|
||||||
|
}
|
||||||
|
if (x && x.status === 200) {
|
||||||
|
origin_group_shunt_rule_order[group] = get_shunt_rule_order(group);
|
||||||
|
alert("<%:Saved current page order successfully.%>");
|
||||||
|
if (btn) {
|
||||||
|
btn.style.display = "none";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert("<%:Save failed!%>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function arraysEqual(a, b) {
|
||||||
|
if (a === b) return true;
|
||||||
|
if (a == null || b == null) return false;
|
||||||
|
if (a.length !== b.length) return false;
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
if (a[i] !== b[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// List drag and rearrange
|
||||||
|
function initSortableForTable(table) {
|
||||||
|
if (!table) return null;
|
||||||
|
let group = table.id.replace("cbi-<%=appname%>-shunt_rules-", "").replace("-table", "")
|
||||||
|
var root = table.querySelector('tbody') || table;
|
||||||
|
if (root._sortable_initialized) return root._sortable_instance;
|
||||||
|
root._sortable_initialized = true;
|
||||||
|
var opts = {
|
||||||
|
handle: ".drag-handle",
|
||||||
|
draggable: "tr.cbi-section-table-row",
|
||||||
|
animation: 150,
|
||||||
|
ghostClass: "dragging-row",
|
||||||
|
fallbackOnBody: true,
|
||||||
|
forceFallback: false,
|
||||||
|
swapThreshold: 0.65,
|
||||||
|
onEnd: function (evt) {
|
||||||
|
//save_current_page_order(group); // Auto save
|
||||||
|
let save_order_btn = document.getElementById("save_order_btn_" + group);
|
||||||
|
if (save_order_btn) {
|
||||||
|
const new_order = get_shunt_rule_order(group);
|
||||||
|
if (!arraysEqual(new_order, origin_group_shunt_rule_order[group])) {
|
||||||
|
save_order_btn.style.display = null;
|
||||||
|
} else {
|
||||||
|
save_order_btn.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
var instance = Sortable.create(root, opts);
|
||||||
|
root._sortable_instance = instance;
|
||||||
|
return instance;
|
||||||
|
} catch (err) {
|
||||||
|
root._sortable_initialized = false;
|
||||||
|
console.error("Sortable init failed:", err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initAllSortable(group_shunt_rules) {
|
||||||
|
if (typeof Sortable === 'undefined') {
|
||||||
|
var retries = 0;
|
||||||
|
var maxRetries = 25;
|
||||||
|
var t = setInterval(function () {
|
||||||
|
retries++;
|
||||||
|
if (typeof Sortable !== 'undefined') {
|
||||||
|
clearInterval(t);
|
||||||
|
for (var group in group_shunt_rules) {
|
||||||
|
var table = document.getElementById("cbi-<%=appname%>-shunt_rules-" + group + "-table");
|
||||||
|
initSortableForTable(table);
|
||||||
|
}
|
||||||
|
} else if (retries >= maxRetries) {
|
||||||
|
clearInterval(t);
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
} else {
|
||||||
|
for (var group in group_shunt_rules) {
|
||||||
|
var table = document.getElementById("cbi-<%=appname%>-shunt_rules-" + group + "-table");
|
||||||
|
initSortableForTable(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function escape_html(s) {
|
||||||
|
return s.replace(/[&<>"']/g, c => ({
|
||||||
|
"&":"&", "<":"<", ">":">", '"':""", "'":"'"
|
||||||
|
}[c]));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/template" id="shunt_rules-table-template">
|
||||||
|
<fieldset class="cbi-section cbi-tblsection" id="cbi-<%=appname%>-shunt_rules-{{group}}-fieldset">
|
||||||
|
<table class="table cbi-section-table" id="cbi-<%=appname%>-shunt_rules-{{group}}-table" style="">
|
||||||
|
<tr class="tr cbi-section-table-titles anonymous">
|
||||||
|
<th class="th cbi-section-table-cell" style="width:30%">ID</th>
|
||||||
|
<th class="th cbi-section-table-cell" style="width:30%"><%:Remarks%></th>
|
||||||
|
<th class="th cbi-section-table-cell cbi-section-actions"></th>
|
||||||
|
</tr>
|
||||||
|
{{shunt_rule-tr}}
|
||||||
|
</table>
|
||||||
|
<div class="cbi-section-create cbi-tblsection-create">
|
||||||
|
<input type="text" id="add_name_{{group}}">
|
||||||
|
<input class="cbi-button cbi-button-add" type="button" value="<%:Add%>" onclick="toPage('add')">
|
||||||
|
<input class="cbi-button cbi-button-apply" style="display: none" type="button" id="save_order_btn_{{group}}" value="<%:Save Order%>" onclick="save_current_page_order('{{group}}')">
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/template" id="shunt_rule-tr-template">
|
||||||
|
<tr class="tr cbi-section-table-row" id="cbi-<%=appname%>-{{id}}">
|
||||||
|
<td class="td cbi-value-field"><b>{{id}}</b></td>
|
||||||
|
<td class="td cbi-value-field">{{remarks}}</td>
|
||||||
|
<td class="td cbi-section-table-cell nowrap cbi-section-actions td-actions">
|
||||||
|
<div class="shunt_rule-wrapper">
|
||||||
|
<input class="btn cbi-button cbi-button-edit" type="button" value="<%:To Top%>" onclick="row_top(this, '{{group}}')" title="<%:To Top%>"/>
|
||||||
|
<input class="btn cbi-button cbi-button-edit" type="button" value="<%:Edit%>" onclick="toPage('edit', '{{id}}')" alt="<%:Edit%>" title="<%:Edit%>">
|
||||||
|
<input class="btn cbi-button cbi-button-remove" type="button" value="<%:Delete%>" onclick="toPage('del', '{{id}}')" alt="<%:Delete%>" title="<%:Delete%>">
|
||||||
|
<span class="drag-handle center" title="<%:Drag to reorder%>">⠿</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="cbi-section">
|
||||||
|
<h3>Sing-Box/Xray <%:Shunt Rule%></h3>
|
||||||
|
<div class="cbi-section-descr"><a style="color: red"><%:Please note attention to the priority, the higher the order, the higher the priority.%></a></div>
|
||||||
|
<div id="shunt_rule_list"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function loadNodeList() {
|
||||||
|
XHR.get('<%=api.url("get_shunt_rules")%>', null, function(x, result) {
|
||||||
|
var shunt_rule_list = result
|
||||||
|
|
||||||
|
var group_shunt_rules = {}
|
||||||
|
for (let i = 0; i < shunt_rule_list.length; i++) {
|
||||||
|
let _shunt_rule = shunt_rule_list[i]
|
||||||
|
if (!_shunt_rule.group || _shunt_rule.group === "") {
|
||||||
|
_shunt_rule.group = "default"
|
||||||
|
}
|
||||||
|
if (!group_shunt_rules[_shunt_rule.group]) {
|
||||||
|
group_shunt_rules[_shunt_rule.group] = []
|
||||||
|
}
|
||||||
|
group_shunt_rules[_shunt_rule.group].push(_shunt_rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tab_ul_li_html = '';
|
||||||
|
var tab_content_html = '';
|
||||||
|
var shunt_rules_table_template = document.getElementById("shunt_rules-table-template");
|
||||||
|
var shunt_rule_template = document.getElementById("shunt_rule-tr-template");
|
||||||
|
var default_group = null
|
||||||
|
for (let group in group_shunt_rules) {
|
||||||
|
if (default_group == null)
|
||||||
|
default_group = group
|
||||||
|
|
||||||
|
var table_html = "";
|
||||||
|
if (true) {
|
||||||
|
var new_shunt_rules_table_dom = shunt_rules_table_template.cloneNode(true);
|
||||||
|
var _html = new_shunt_rules_table_dom.innerHTML;
|
||||||
|
_html = _html.split("{{group}}").join(group);
|
||||||
|
var shunt_rule_tr_html = "";
|
||||||
|
for (var i = 0; i < group_shunt_rules[group].length; i++) {
|
||||||
|
let o = group_shunt_rules[group][i]
|
||||||
|
var newDom = shunt_rule_template.cloneNode(true);
|
||||||
|
newDom.classList.add("cbi-rowstyle-" + (i % 2 + 1));
|
||||||
|
var innerHTML = newDom.innerHTML;
|
||||||
|
innerHTML = innerHTML.split("{{id}}").join(o[".name"]);
|
||||||
|
innerHTML = innerHTML.split("{{group}}").join(o["group"] || "");
|
||||||
|
innerHTML = innerHTML.split("{{remarks}}").join(o["remarks"] || "");
|
||||||
|
|
||||||
|
shunt_rule_tr_html += innerHTML
|
||||||
|
}
|
||||||
|
_html = _html.split("{{shunt_rule-tr}}").join(shunt_rule_tr_html);
|
||||||
|
table_html = _html;
|
||||||
|
}
|
||||||
|
|
||||||
|
var group_name = group
|
||||||
|
if (group === "default") {
|
||||||
|
group_name = "<%:default%>"
|
||||||
|
}
|
||||||
|
|
||||||
|
tab_ul_li_html +=
|
||||||
|
'<li group_name="' + group + '" id="tab.<%=appname%>.shunt_rules.' + group + '" class="cbi-tab">' +
|
||||||
|
'<a onclick="this.blur(); return cbi_t_switch(\'<%=appname%>.shunt_rules\', \'' + group + '\')" href="<%=REQUEST_URI%>?tab.<%=appname%>.shunt_rules=' + group + '">' + escape_html(group_name) + " | " + "<font style='color: red'>" + group_shunt_rules[group].length + '</font></a>' +
|
||||||
|
'</li>'
|
||||||
|
tab_content_html +=
|
||||||
|
'<div class="cbi-tabcontainer" id="container.<%=appname%>.shunt_rules.' + group + '" style="display: none;">' +
|
||||||
|
'' + table_html +
|
||||||
|
'</div>'
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTabDOM(li, content) {
|
||||||
|
let tab_ul_html = '<ul class="cbi-tabmenu">';
|
||||||
|
let tab_content_html = '<fieldset class="cbi-section-shunt_rule cbi-section-shunt_rule-tabbed" id="cbi-<%=appname%>-shunt_rules">';
|
||||||
|
if (li) {
|
||||||
|
tab_ul_html += li;
|
||||||
|
}
|
||||||
|
if (content) {
|
||||||
|
tab_content_html += content;
|
||||||
|
}
|
||||||
|
tab_ul_html += '</ul>';
|
||||||
|
tab_content_html += '</fieldset>';
|
||||||
|
return tab_ul_html + tab_content_html;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("shunt_rule_list").innerHTML = addTabDOM(tab_ul_li_html, tab_content_html);
|
||||||
|
|
||||||
|
for (let group in group_shunt_rules) {
|
||||||
|
cbi_t_add("<%=appname%>.shunt_rules", group)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (default_group) {
|
||||||
|
cbi_t_switch("<%=appname%>.shunt_rules", default_group)
|
||||||
|
}
|
||||||
|
|
||||||
|
origin_group_shunt_rule_order = {};
|
||||||
|
for (let group in group_shunt_rules) {
|
||||||
|
origin_group_shunt_rule_order[group] = get_shunt_rule_order(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
initAllSortable(group_shunt_rules);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadNodeList();
|
||||||
|
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
@@ -1094,6 +1094,9 @@ msgstr "启用后,规则列表可以支持 GeoIP/Geosite 规则。"
|
|||||||
msgid "Shunt Rule"
|
msgid "Shunt Rule"
|
||||||
msgstr "分流规则"
|
msgstr "分流规则"
|
||||||
|
|
||||||
|
msgid "Shunt Rule Group"
|
||||||
|
msgstr "分流规则组"
|
||||||
|
|
||||||
msgid "Please note attention to the priority, the higher the order, the higher the priority."
|
msgid "Please note attention to the priority, the higher the order, the higher the priority."
|
||||||
msgstr "请注意优先级问题,排序越上面优先级越高。"
|
msgstr "请注意优先级问题,排序越上面优先级越高。"
|
||||||
|
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ if IS_SHUNT_NODE then
|
|||||||
local default_node_id = t["default_node"] or "_direct"
|
local default_node_id = t["default_node"] or "_direct"
|
||||||
uci:foreach(appname, "shunt_rules", function(s)
|
uci:foreach(appname, "shunt_rules", function(s)
|
||||||
local _node_id = t[s[".name"]]
|
local _node_id = t[s[".name"]]
|
||||||
if _node_id and _node_id ~= "_blackhole" then
|
if _node_id and _node_id ~= "_blackhole" and t["shunt_group"] == s.group then
|
||||||
if _node_id == "_default" then
|
if _node_id == "_default" then
|
||||||
_node_id = default_node_id
|
_node_id = default_node_id
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -619,7 +619,7 @@ function add_rule(var)
|
|||||||
local default_node_id = t["default_node"] or "_direct"
|
local default_node_id = t["default_node"] or "_direct"
|
||||||
uci:foreach(appname, "shunt_rules", function(s)
|
uci:foreach(appname, "shunt_rules", function(s)
|
||||||
local _node_id = t[s[".name"]]
|
local _node_id = t[s[".name"]]
|
||||||
if _node_id and _node_id ~= "_blackhole" then
|
if _node_id and _node_id ~= "_blackhole" and t["shunt_group"] == s.group then
|
||||||
if _node_id == "_default" then
|
if _node_id == "_default" then
|
||||||
_node_id = default_node_id
|
_node_id = default_node_id
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -559,7 +559,7 @@ if IS_SHUNT_NODE then
|
|||||||
local default_node_id = t["default_node"] or "_direct"
|
local default_node_id = t["default_node"] or "_direct"
|
||||||
uci:foreach(appname, "shunt_rules", function(s)
|
uci:foreach(appname, "shunt_rules", function(s)
|
||||||
local _node_id = t[s[".name"]]
|
local _node_id = t[s[".name"]]
|
||||||
if _node_id and _node_id ~= "_blackhole" then
|
if _node_id and _node_id ~= "_blackhole" and t["shunt_group"] == s.group then
|
||||||
if _node_id == "_default" then
|
if _node_id == "_default" then
|
||||||
_node_id = default_node_id
|
_node_id = default_node_id
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -952,7 +952,14 @@ add_firewall_rule() {
|
|||||||
[ "$USE_SHUNT_NODE" = "1" ] && {
|
[ "$USE_SHUNT_NODE" = "1" ] && {
|
||||||
local GEOIP_CODE=""
|
local GEOIP_CODE=""
|
||||||
local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
|
local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
|
||||||
|
local shunt_group
|
||||||
|
if [ "${USE_SHUNT_TCP}" = "1" ]; then
|
||||||
|
shunt_group=$(config_n_get $_TCP_NODE shunt_group)
|
||||||
|
elif [ "${USE_SHUNT_UDP}" = "1" ]; then
|
||||||
|
shunt_group=$(config_n_get $_UDP_NODE shunt_group)
|
||||||
|
fi
|
||||||
for shunt_id in $shunt_ids; do
|
for shunt_id in $shunt_ids; do
|
||||||
|
[ "${shunt_group}" != "$(config_n_get ${shunt_id} group)" ] && continue
|
||||||
config_n_get $shunt_id ip_list | tr -s "\r\n" "\n" | grep -v "^#" | sed -e "/^$/d" | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | sed -e "s/^/add $IPSET_SHUNT &/g" -e "s/$/ timeout 0/g" | ipset -! -R
|
config_n_get $shunt_id ip_list | tr -s "\r\n" "\n" | grep -v "^#" | sed -e "/^$/d" | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | sed -e "s/^/add $IPSET_SHUNT &/g" -e "s/$/ timeout 0/g" | ipset -! -R
|
||||||
config_n_get $shunt_id ip_list | tr -s "\r\n" "\n" | grep -v "^#" | sed -e "/^$/d" | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | sed -e "s/^/add $IPSET_SHUNT6 &/g" -e "s/$/ timeout 0/g" | ipset -! -R
|
config_n_get $shunt_id ip_list | tr -s "\r\n" "\n" | grep -v "^#" | sed -e "/^$/d" | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | sed -e "s/^/add $IPSET_SHUNT6 &/g" -e "s/$/ timeout 0/g" | ipset -! -R
|
||||||
[ "$USE_GEOVIEW" = "1" ] && {
|
[ "$USE_GEOVIEW" = "1" ] && {
|
||||||
|
|||||||
@@ -1054,7 +1054,14 @@ add_firewall_rule() {
|
|||||||
[ "$USE_SHUNT_NODE" = "1" ] && {
|
[ "$USE_SHUNT_NODE" = "1" ] && {
|
||||||
local GEOIP_CODE=""
|
local GEOIP_CODE=""
|
||||||
local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
|
local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
|
||||||
|
local shunt_group
|
||||||
|
if [ "${USE_SHUNT_TCP}" = "1" ]; then
|
||||||
|
shunt_group=$(config_n_get $_TCP_NODE shunt_group)
|
||||||
|
elif [ "${USE_SHUNT_UDP}" = "1" ]; then
|
||||||
|
shunt_group=$(config_n_get $_UDP_NODE shunt_group)
|
||||||
|
fi
|
||||||
for shunt_id in $shunt_ids; do
|
for shunt_id in $shunt_ids; do
|
||||||
|
[ "${shunt_group}" != "$(config_n_get ${shunt_id} group)" ] && continue
|
||||||
config_n_get $shunt_id ip_list | sed 's/#.*//' | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_SHUNT_STATIC
|
config_n_get $shunt_id ip_list | sed 's/#.*//' | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_SHUNT_STATIC
|
||||||
config_n_get $shunt_id ip_list | sed 's/#.*//' | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_SHUNT6_STATIC
|
config_n_get $shunt_id ip_list | sed 's/#.*//' | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_SHUNT6_STATIC
|
||||||
[ "$USE_GEOVIEW" = "1" ] && {
|
[ "$USE_GEOVIEW" = "1" ] && {
|
||||||
|
|||||||
Reference in new issue
Block a user