🎄 Sync 2025-11-28 00:12:29

This commit is contained in:
actions-user
2025-11-28 00:12:29 +08:00
parent bf596d0fcb
commit 308506363e
10 changed files with 116 additions and 40 deletions

View File

@@ -6,7 +6,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=25.11.15
PKG_VERSION:=25.11.27
PKG_RELEASE:=1
PKG_PO_VERSION:=$(PKG_VERSION)

File diff suppressed because one or more lines are too long

View File

@@ -204,7 +204,7 @@ o.cfgvalue = function(t, n)
str = str ~= "" and "<br>" .. str or ""
local num = 0
m.uci:foreach(appname, "nodes", function(s)
if s["group"] ~= "" and s["group"] == remark then
if s["group"] and s["group"]:lower() == remark:lower() then
num = num + 1
end
end)

View File

@@ -618,8 +618,14 @@ o = s:option(TextValue, _n("xhttp_extra"), " ", translate("An XHttpObject in JSO
o:depends({ [_n("use_xhttp_extra")] = true })
o.rows = 15
o.wrap = "off"
o.custom_cfgvalue = function(self, section, value)
local raw = m:get(section, "xhttp_extra")
if raw then
return api.base64Decode(raw)
end
end
o.custom_write = function(self, section, value)
m:set(section, self.option:sub(1 + #option_prefix), value)
m:set(section, "xhttp_extra", api.base64Encode(value))
local success, data = pcall(jsonc.parse, value)
if success and data then
local address = (data.extra and data.extra.downloadSettings and data.extra.downloadSettings.address)
@@ -642,7 +648,7 @@ o.validate = function(self, value)
return value
end
o.custom_remove = function(self, section, value)
m:del(section, self.option:sub(1 + #option_prefix))
m:del(section, "xhttp_extra")
m:del(section, "download_address")
end

View File

@@ -113,19 +113,15 @@ function exec_call(cmd)
end
function base64Decode(text)
local raw = text
if not text then return '' end
text = text:gsub("%z", "")
text = text:gsub("%c", "")
text = text:gsub("_", "/")
text = text:gsub("-", "+")
local mod4 = #text % 4
text = text .. string.sub('====', mod4 + 1)
local result = nixio.bin.b64decode(text)
local encoded = text:gsub("%z", ""):gsub("%c", ""):gsub("_", "/"):gsub("-", "+")
local mod4 = #encoded % 4
encoded = encoded .. string.sub('====', mod4 + 1)
local result = nixio.bin.b64decode(encoded)
if result then
return result:gsub("%z", "")
else
return raw
return text
end
end

View File

@@ -223,7 +223,7 @@ function gen_outbound(flag, node, tag, proxy_table)
host = node.xhttp_host,
-- 如果包含 "extra" 节,取 "extra" 内的内容,否则直接赋值给 extra
extra = node.xhttp_extra and (function()
local success, parsed = pcall(jsonc.parse, node.xhttp_extra)
local success, parsed = pcall(jsonc.parse, api.base64Decode(node.xhttp_extra))
if success then
return parsed.extra or parsed
else

View File

@@ -52,7 +52,7 @@ local api = require "luci.passwall.api"
function add_node() {
var nodes_link = document.getElementById("nodes_link").value;
var group = (document.querySelector('#addlink_group_custom input[type="hidden"]')?.value || "default");
nodes_link = nodes_link.replace(/\t/g, "").replace(/\r\n|\r/g, "\n").trim();
nodes_link = nodes_link.replace(/\t/g, "").replace(/\r\n|\r/g, "\n").replace(/\s+/g, '').replace(/<[^>]*>/g, '').trim();
if (nodes_link != "") {
var s = nodes_link.split('://');
if (s.length > 1) {

View File

@@ -1,6 +1,7 @@
<%
local api = require "luci.passwall.api"
-%>
<script src="<%=resource%>/view/<%=api.appname%>/Sortable.min.js"></script>
<style>
table th, .table .th {
@@ -38,9 +39,9 @@ table td, .table .td {
}
@media (prefers-color-scheme: dark) {
._now_use_bg {
background: #4a90e2 !important;
}
._now_use_bg {
background: #4a90e2 !important;
}
}
.td.cbi-section-actions {
@@ -55,18 +56,46 @@ table td, .table .td {
.node-wrapper .cbi-input-checkbox {
flex-grow: 0 !important;
flex-shrink: 0;
flex-basis: auto;
}
.cbi-tabmenu > li {
margin-right: 2px !important;
margin-right: 2px !important;
}
.cbi-tabmenu > li:last-child {
margin-right: 0 !important;
margin-right: 0 !important;
}
.node-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;
color: #00000070;
align-self: stretch;
}
.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 -%>
@@ -210,21 +239,6 @@ table td, .table .td {
document.getElementById("set_node_name").innerHTML = "";
}
function row_swap(btn, up) {
const row = btn.closest("tr");
if (!row) return;
const parent = row.parentNode;
if (up) {
const prev = row.previousElementSibling;
if (prev && !prev.classList.contains("cbi-section-table-titles")) {
parent.insertBefore(row, prev);
}
} else {
const next = row.nextElementSibling;
if (next) parent.insertBefore(next, row);
}
}
function row_top(btn) {
const row = btn.closest("tr");
if (!row) return;
@@ -548,6 +562,60 @@ table td, .table .td {
}
}
}
//列表拖动重排
function initSortableForTable(table) {
if (!table) return null;
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) {
//var group = evt.to.id.replace("cbi-passwall-nodes-", "").replace("-table", "");
//save_current_page_order(group); // 自动提交保存
}
};
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_nodes) {
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_nodes) {
var table = document.getElementById("cbi-passwall-nodes-" + group + "-table");
initSortableForTable(table);
}
} else if (retries >= maxRetries) {
clearInterval(t);
}
}, 200);
} else {
for (var group in group_nodes) {
var table = document.getElementById("cbi-passwall-nodes-" + group + "-table");
initSortableForTable(table);
}
}
}
</script>
<script type="text/template" id="nodes-table-template">
@@ -584,10 +652,9 @@ table td, .table .td {
<input class="btn cbi-button cbi-button-edit" type="button" value="<%:To Top%>" onclick="row_top(this)" title="<%:To Top%>"/>
<input class="btn cbi-button cbi-button-apply" type="button" value="<%:Use%>" id="apply_{{id}}" onclick="open_set_node_div('{{id}}')"/>
<input class="btn cbi-button cbi-button-add" type="button" value="<%:Copy%>" onclick="copy_node('{{id}}')"/>
<input class="btn cbi-button cbi-button-up" type="button" value="<%:Move up%>" onclick="return row_swap(this, true)" title="<%:Move up%>">
<input class="btn cbi-button cbi-button-down" type="button" value="<%:Move down%>" onclick="return row_swap(this, false)" title="<%:Move down%>">
<input class="btn cbi-button cbi-button-edit" type="button" value="<%:Edit%>" onclick="location.href='<%=api.url("node_config")%>/{{id}}'" alt="<%:Edit%>" title="<%:Edit%>">
<input class="btn cbi-button cbi-button-remove" type="button" value="<%:Delete%>" onclick="del_node('{{id}}')" alt="<%:Delete%>" title="<%:Delete%>">
<span class="drag-handle center" title="<%:Drag to reorder%>"></span>
</div>
</td>
</tr>
@@ -749,6 +816,8 @@ table td, .table .td {
cbi_t_switch("passwall.nodes", default_group)
}
initAllSortable(group_nodes);
//clear expire data
if (localStorage && localStorage.length > 0) {
const now = Date.now();

View File

@@ -427,6 +427,9 @@ msgstr "保存当前顺序"
msgid "Saved current page order successfully."
msgstr "保存当前页面顺序成功。"
msgid "Drag to reorder"
msgstr "拖动以重排"
msgid "Type"
msgstr "类型"

View File

@@ -504,8 +504,8 @@ local function processData(szType, content, add_mode, group)
end
result.obfs_param = base64Decode(params.obfsparam)
result.protocol_param = base64Decode(params.protoparam)
local group = base64Decode(params.group)
if group then result.group = group end
-- local ssr_group = base64Decode(params.group)
-- if ssr_group then result.ssr_group = ssr_group end
result.remarks = base64Decode(params.remarks)
elseif szType == 'vmess' then
local info = jsonParse(content)
@@ -1207,7 +1207,7 @@ local function processData(szType, content, add_mode, group)
result.xhttp_path = params.path
result.xhttp_mode = params.mode or "auto"
result.use_xhttp_extra = (params.extra and params.extra ~= "") and "1" or nil
result.xhttp_extra = (params.extra and params.extra ~= "") and params.extra or nil
result.xhttp_extra = (params.extra and params.extra ~= "") and api.base64Encode(params.extra) or nil
local success, Data = pcall(jsonParse, params.extra)
if success and Data then
local address = (Data.extra and Data.extra.downloadSettings and Data.extra.downloadSettings.address)