Skip to content

Commit 41a806a

Browse files
committed
update LICENSE and add port highlight with special ports
1 parent ac5e65b commit 41a806a

File tree

10 files changed

+106
-250
lines changed

10 files changed

+106
-250
lines changed

htdocs/luci-static/resources/protocol/ipip6h.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ return network.registerProtocol('ipip6h', {
5656
o.datatype = 'ip4addr("nomask")';
5757
o.placeholder = '111.0.0.1';
5858

59-
o = s.taboption('general', form.Value, 'interface_id', _('IPv6 Interface ID'),
60-
_('IPv6 interface identifier (last 64 bits). Will be combined with WAN6 prefix to create a virtual IPv6 address. Example: 0011:4514:1b00:0000'));
59+
o = s.taboption('general', form.Value, 'interface_id', _('IPv6 Interface ID'));
6160
o.placeholder = '0011:4514:1b00:0000';
6261
o.rmempty = false;
6362
o.validate = function (_section_id, value) {

htdocs/luci-static/resources/view/fleth.js

Lines changed: 78 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,15 @@
88

99
// fix css paading (kusa
1010
const fleth_style = document.createElement("style");
11-
fleth_style.innerHTML = `.cbi-value-field { padding-top: 6px; }`;
11+
fleth_style.innerHTML = `
12+
.cbi-value-field { padding-top: 6px; }
13+
.port-highlight {
14+
background-color: rgb(207, 226, 255);
15+
padding: 1px 4px;
16+
border-radius: 3px;
17+
font-weight: 500;
18+
}
19+
`;
1220
document.head.appendChild(fleth_style);
1321

1422
return view.extend({
@@ -26,52 +34,29 @@ return view.extend({
2634
let areaValue = area || "UNKNOWN";
2735
const mapeIsUnknown = mape_status.length <= 1 || mape_status[0] === "UNKNOWN";
2836

29-
// Special handling for NURO
30-
if (mape_status[0] === "NURO") {
31-
areaValue = "UNKNOWN(NURO)";
32-
}
33-
// If MAP-E is UNKNOWN, check pending status first
37+
// Base return object with common fields
38+
const baseData = {
39+
mape_status: mape_status,
40+
prefix_length: prefix_length || "UNKNOWN",
41+
mapIsPatched: mapsh_status === "patched",
42+
};
43+
44+
if (mape_status[0] === "NURO") areaValue = "UNKNOWN(NURO)";
45+
3446
if (mapeIsUnknown) {
3547
return L.resolveDefault(fs.exec("/usr/sbin/fleth", ["pending_status"]), { stdout: "" })
3648
.then(function (pendingResult) {
3749
const pendingStatus = (pendingResult.stdout || "").trim();
38-
// If pending status detected, return with pending flag
3950
if (pendingStatus.endsWith("_pending")) {
40-
const detectedArea = pendingStatus.split('_')[0];
41-
return {
42-
area: detectedArea,
43-
dslite_provider: "UNKNOWN",
44-
mape_status: mape_status,
45-
prefix_length: prefix_length || "UNKNOWN",
46-
isPending: true,
47-
mapIsPatched: mapsh_status === "patched",
48-
};
51+
return { ...baseData, area: pendingStatus.split('_')[0], dslite_provider: "UNKNOWN", isPending: true };
4952
}
50-
// No pending status, check DS-Lite provider
5153
return L.resolveDefault(fs.exec("/usr/sbin/fleth", ["get_dslite_provider"]), { stdout: "" })
5254
.then(function (dsliteResult) {
53-
const dslite_provider = (dsliteResult.stdout || "").trim();
54-
return {
55-
area: areaValue,
56-
dslite_provider: dslite_provider || "UNKNOWN",
57-
mape_status: mape_status,
58-
prefix_length: prefix_length || "UNKNOWN",
59-
isPending: false,
60-
mapIsPatched: mapsh_status === "patched",
61-
};
55+
return { ...baseData, area: areaValue, dslite_provider: (dsliteResult.stdout || "").trim() || "UNKNOWN", isPending: false };
6256
});
6357
});
64-
} else {
65-
// MAP-E detected, no need to check DS-Lite or pending
66-
return {
67-
area: areaValue,
68-
dslite_provider: "UNKNOWN",
69-
mape_status: mape_status,
70-
prefix_length: prefix_length || "UNKNOWN",
71-
isPending: false,
72-
mapIsPatched: mapsh_status === "patched",
73-
};
7458
}
59+
return { ...baseData, area: areaValue, dslite_provider: "UNKNOWN", isPending: false };
7560
});
7661
},
7762

@@ -151,9 +136,49 @@ return view.extend({
151136
mapeDetailFields.forEach((field, i) => {
152137
const [fieldName, fieldLabel] = field;
153138
o = s.taboption("info", form.DummyValue, fieldName, _(fieldLabel));
154-
o.cfgvalue = function () {
155-
return data.mape_status[i + 1] || "";
156-
};
139+
140+
// Special rendering for Available ports
141+
if (fieldName === "mape_map_ports") {
142+
o.rawhtml = true;
143+
o.cfgvalue = function () {
144+
const portsString = data.mape_status[i + 1] || "";
145+
if (!portsString) return "";
146+
147+
// Split ports into individual numbers
148+
const ports = portsString.split(/\s+/).filter(p => p);
149+
const highlightedPorts = ports.map(port => {
150+
const len = port.length;
151+
const half = len / 2;
152+
const reversed = port.split('').reverse().join('');
153+
const counts = {};
154+
for (let c of port) counts[c] = (counts[c] || 0) + 1;
155+
156+
const isSpecial = /(\d)\1{2,}/.test(port) || // consecutive repeats
157+
port.endsWith('0') || // ends with 0
158+
(len >= 2 && len % 2 === 0 && port.substring(0, half) === port.substring(half)) || // ABAB
159+
(len >= 3 && port === reversed) || // palindrome
160+
Object.values(counts).some(n => n >= 3); // frequent digit
161+
162+
return isSpecial ? '<span class="port-highlight">' + port + '</span>' : port;
163+
});
164+
165+
return highlightedPorts.join(' ');
166+
};
167+
// Override render to display as div instead of input
168+
o.render = function () {
169+
const value = this.cfgvalue();
170+
const contentDiv = E('div', { 'style': 'line-height: 1.8; word-wrap: break-word;' });
171+
contentDiv.innerHTML = value;
172+
return E('div', { 'class': 'cbi-value' }, [
173+
E('label', { 'class': 'cbi-value-title' }, _(fieldLabel)),
174+
E('div', { 'class': 'cbi-value-field' }, contentDiv)
175+
]);
176+
}.bind(o);
177+
} else {
178+
o.cfgvalue = function () {
179+
return data.mape_status[i + 1] || "";
180+
};
181+
}
157182
});
158183
}
159184

@@ -252,7 +277,7 @@ return view.extend({
252277
o.title = _("map.sh Management");
253278
o.cfgvalue = function () {
254279
return _("OpenWrt's map.sh has bugs: only the first port group works and ICMP is broken. Click below to replace with the fixed version.") +
255-
' <a href="https://github.com/fakemanhk/openwrt-jp-ipoe/tree/main" target="_blank" style="color: #0088cc;">(' + _("See more") + ')</a>';
280+
' <a href="https://github.com/fakemanhk/openwrt-jp-ipoe/tree/main" target="_blank" style="color: #0088cc;">(' + _("See more") + ')</a>';
256281
};
257282
o.rawhtml = true;
258283

@@ -274,12 +299,12 @@ return view.extend({
274299
};
275300
o.rawhtml = true;
276301

277-
o = s.taboption("tools", form.Button, "_replace_mapsh");
302+
o = s.taboption("tools", form.Button, "_patch_mapsh");
278303
o.title = "&#160;";
279-
o.inputtitle = _("Replace");
304+
o.inputtitle = _("Patch");
280305
o.inputstyle = data.mapIsPatched ? "cbi-button-action" : "cbi-button-apply";
281306
o.onclick = L.bind(function (m) {
282-
return this.replaceMapSh(m);
307+
return this.patchMapSh(m);
283308
}, this, m);
284309

285310
o = s.taboption("tools", form.Button, "_restore_mapsh");
@@ -289,15 +314,15 @@ return view.extend({
289314
o.onclick = L.bind(function (m) {
290315
return this.restoreMapSh(m);
291316
}, this, m);
292-
o.depends("_replace_mapsh", "");
317+
o.depends("_patch_mapsh", "");
293318

294319
const renderedNode = await m.render();
295320

296321
// Hide footer when tools tab is active
297-
setTimeout(function() {
322+
setTimeout(function () {
298323
const footer = document.querySelector('.cbi-page-actions');
299324

300-
const toggleFooter = function() {
325+
const toggleFooter = function () {
301326
// Check if tools tab is active
302327
const toolsActive = document.querySelector('.cbi-tab[data-tab="tools"]');
303328
if (footer) {
@@ -312,8 +337,8 @@ return view.extend({
312337
const tabMenu = document.querySelector('.cbi-tabmenu');
313338
if (tabMenu) {
314339
const tabItems = tabMenu.querySelectorAll('li[data-tab]');
315-
tabItems.forEach(function(tabItem) {
316-
tabItem.addEventListener('click', function() {
340+
tabItems.forEach(function (tabItem) {
341+
tabItem.addEventListener('click', function () {
317342
setTimeout(toggleFooter, 10);
318343
});
319344
});
@@ -374,7 +399,7 @@ return view.extend({
374399

375400
manageMapSh: function (mapObj, action) {
376401
const actionConfig = {
377-
replace: { verb: _('Replacing'), gerund: _('Downloading...') },
402+
patch: { verb: _('Patching'), gerund: _('Downloading...') },
378403
restore: { verb: _('Restoring'), gerund: _('Restoring...') }
379404
};
380405

@@ -388,15 +413,15 @@ return view.extend({
388413
E('p', { 'class': 'spinning' }, config.gerund)
389414
]);
390415

391-
return fs.exec('/usr/sbin/fleth', [action + '_mapsh']);
416+
return fs.exec('/usr/sbin/fleth', [action + '_map.sh']);
392417
})
393418
.then(function (result) {
394419
ui.hideModal();
395420

396421
if (result.code === 0 && result.stdout.trim() === 'SUCCESS') {
397422
ui.addNotification(null, E('p', _('Operation completed successfully! Please restart the network interface manually.')), 'info');
398423

399-
setTimeout(function() {
424+
setTimeout(function () {
400425
window.location.reload();
401426
}, 5000);
402427
} else {
@@ -419,8 +444,8 @@ return view.extend({
419444
});
420445
},
421446

422-
replaceMapSh: function (mapObj) {
423-
return this.manageMapSh(mapObj, 'replace');
447+
patchMapSh: function (mapObj) {
448+
return this.manageMapSh(mapObj, 'patch');
424449
},
425450

426451
restoreMapSh: function (mapObj) {

po/ja/fleth.po

Lines changed: 6 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,6 @@ msgstr "トンネルインターフェース用のパブリック IPv4 アドレ
158158
msgid "IPv6 Interface ID"
159159
msgstr "IPv6 インターフェース ID"
160160

161-
msgid "IPv6 interface identifier (last 64 bits). Will be combined with WAN6 prefix to create a virtual IPv6 address. Example: 0011:4514:1b00:0000"
162-
msgstr "IPv6 インターフェース識別子(下位 64 ビット)。WAN6 プレフィックスと組み合わせて仮想 IPv6 アドレスを作成します。例:0011:4514:1b00:0000"
163161

164162
msgid "IPv6 Interface ID is required"
165163
msgstr "IPv6 インターフェース ID は必須です"
@@ -182,74 +180,20 @@ msgstr "パッチ版"
182180
msgid "Original version"
183181
msgstr "オリジナル版"
184182

185-
msgid "Replace MAP.sh"
186-
msgstr "map.sh を置き換える"
187-
188-
msgid "Restore Original MAP.sh"
189-
msgstr "オリジナル map.sh に戻す"
190-
191-
msgid "Replacing MAP.sh"
192-
msgstr "map.sh を置き換え中"
193-
194-
msgid "Downloading and replacing MAP.sh..."
195-
msgstr "map.sh をダウンロードして置き換え中..."
196-
197-
msgid "Restoring MAP.sh"
198-
msgstr "map.sh を復元中"
199-
200-
msgid "Restoring original MAP.sh..."
201-
msgstr "オリジナル map.sh を復元中..."
202-
203-
msgid "map.sh replaced successfully! Please restart the network interface if needed."
204-
msgstr "map.sh の置き換えに成功しました!変更を有効にするには、手動でネットワークインターフェースを再起動してください。"
205-
206-
msgid "Original map.sh restored successfully! Please restart the network interface if needed."
207-
msgstr "オリジナル map.sh の復元に成功しました!変更を有効にするには、手動でネットワークインターフェースを再起動してください。"
208-
209-
msgid "Failed to replace MAP.sh:"
210-
msgstr "map.sh の置き換えに失敗しました:"
211-
212-
msgid "Failed to restore MAP.sh:"
213-
msgstr "map.sh の復元に失敗しました:"
214-
215-
msgid "Error replacing MAP.sh:"
216-
msgstr "map.sh の置き換え中にエラーが発生しました:"
217-
218-
msgid "Error restoring MAP.sh:"
219-
msgstr "map.sh の復元中にエラーが発生しました:"
220-
221-
msgid "Replace"
222-
msgstr "置き換える"
183+
msgid "Patch"
184+
msgstr "パッチする"
223185

224186
msgid "Restore"
225187
msgstr "復元"
226188

227-
msgid "Replacing"
228-
msgstr "置き換え中"
189+
msgid "Patching"
190+
msgstr "パッチ中"
229191

230192
msgid "Downloading..."
231193
msgstr "ダウンロード中..."
232194

233-
msgid "Restoring"
234-
msgstr "復元中"
235-
236195
msgid "Restoring..."
237196
msgstr "復元中..."
238197

239-
msgid "Replaced successfully! Please restart the network interface manually."
240-
msgstr "置き換え完了!手動でネットワークインターフェースを再起動してください。"
241-
242-
msgid "Restored successfully! Please restart the network interface manually."
243-
msgstr "復元完了!手動でネットワークインターフェースを再起動してください。"
244-
245-
msgid "Failed to replace:"
246-
msgstr "置き換え失敗:"
247-
248-
msgid "Failed to restore:"
249-
msgstr "復元失敗:"
250-
251-
msgid "Error replacing:"
252-
msgstr "置き換えエラー:"
253-
254-
msgid "Error restoring:"
255-
msgstr "復元エラー:"
198+
msgid "Operation completed successfully! Please restart the network interface manually."
199+
msgstr "操作が完了しました!手動でネットワークインターフェースを再起動してください。"

0 commit comments

Comments
 (0)