update 2025-01-15 16:16:42

This commit is contained in:
actions-user 2025-01-15 16:16:42 +08:00
parent d486cd3a96
commit 29bc41f295
8 changed files with 217 additions and 217 deletions

View File

@ -26,9 +26,9 @@ const monospacefonts = [
]; ];
return baseclass.extend({ return baseclass.extend({
rulesetdoc: rulesetdoc, rulesetdoc,
sharktaikogif: sharktaikogif, sharktaikogif,
monospacefonts: monospacefonts, monospacefonts,
dashrepos: [ dashrepos: [
['zephyruso/zashboard', _('zashboard')], ['zephyruso/zashboard', _('zashboard')],
@ -231,8 +231,8 @@ return baseclass.extend({
], ],
CBIListValue: form.ListValue.extend({ CBIListValue: form.ListValue.extend({
renderWidget: function(/* ... */) { renderWidget(/* ... */) {
var frameEl = form.ListValue.prototype.renderWidget.apply(this, arguments); let frameEl = form.ListValue.prototype.renderWidget.apply(this, arguments);
frameEl.querySelector('select').style["min-width"] = '10em'; frameEl.querySelector('select').style["min-width"] = '10em';
@ -243,8 +243,8 @@ return baseclass.extend({
CBIStaticList: form.DynamicList.extend({ CBIStaticList: form.DynamicList.extend({
__name__: 'CBI.StaticList', __name__: 'CBI.StaticList',
renderWidget: function(/* ... */) { renderWidget(/* ... */) {
var El = form.DynamicList.prototype.renderWidget.apply(this, arguments); let El = form.DynamicList.prototype.renderWidget.apply(this, arguments);
El.querySelector('.add-item ul > li[data-value="-"]')?.remove(); El.querySelector('.add-item ul > li[data-value="-"]')?.remove();
@ -253,8 +253,8 @@ return baseclass.extend({
}), }),
CBITextValue: form.TextValue.extend({ CBITextValue: form.TextValue.extend({
renderWidget: function(/* ... */) { renderWidget(/* ... */) {
var frameEl = form.TextValue.prototype.renderWidget.apply(this, arguments); let frameEl = form.TextValue.prototype.renderWidget.apply(this, arguments);
frameEl.querySelector('textarea').style.fontFamily = monospacefonts.join(','); frameEl.querySelector('textarea').style.fontFamily = monospacefonts.join(',');
@ -263,7 +263,7 @@ return baseclass.extend({
}), }),
// thanks to homeproxy // thanks to homeproxy
calcStringMD5: function(e) { calcStringMD5(e) {
/* Thanks to https://stackoverflow.com/a/41602636 */ /* Thanks to https://stackoverflow.com/a/41602636 */
function h(a, b) { function h(a, b) {
var c, d, e, f, g; var c, d, e, f, g;
@ -345,13 +345,13 @@ return baseclass.extend({
}, },
// thanks to homeproxy // thanks to homeproxy
decodeBase64Str: function(str) { decodeBase64Str(str) {
if (!str) if (!str)
return null; return null;
/* Thanks to luci-app-ssr-plus */ /* Thanks to luci-app-ssr-plus */
str = str.replace(/-/g, '+').replace(/_/g, '/'); str = str.replace(/-/g, '+').replace(/_/g, '/');
var padding = (4 - (str.length % 4)) % 4; let padding = (4 - (str.length % 4)) % 4;
if (padding) if (padding)
str = str + Array(padding + 1).join('='); str = str + Array(padding + 1).join('=');
@ -360,8 +360,8 @@ return baseclass.extend({
).join('')); ).join(''));
}, },
generateRand: function(type, length) { generateRand(type, length) {
var byteArr; let byteArr;
if (['base64', 'hex'].includes(type)) if (['base64', 'hex'].includes(type))
byteArr = crypto.getRandomValues(new Uint8Array(length)); byteArr = crypto.getRandomValues(new Uint8Array(length));
switch (type) { switch (type) {
@ -393,7 +393,7 @@ return baseclass.extend({
return false; return false;
}, },
removeBlankAttrs: function(self, res) { removeBlankAttrs(self, res) {
if (Array.isArray(res)) { if (Array.isArray(res)) {
return res return res
.filter(item => !self.isEmpty(item)) .filter(item => !self.isEmpty(item))
@ -411,7 +411,7 @@ return baseclass.extend({
return res; return res;
}, },
getFeatures: function() { getFeatures() {
const callGetFeatures = rpc.declare({ const callGetFeatures = rpc.declare({
object: 'luci.fchomo', object: 'luci.fchomo',
method: 'get_features', method: 'get_features',
@ -421,7 +421,7 @@ return baseclass.extend({
return L.resolveDefault(callGetFeatures(), {}); return L.resolveDefault(callGetFeatures(), {});
}, },
getServiceStatus: function(instance) { getServiceStatus(instance) {
var conf = 'fchomo'; var conf = 'fchomo';
const callServiceList = rpc.declare({ const callServiceList = rpc.declare({
object: 'service', object: 'service',
@ -432,7 +432,7 @@ return baseclass.extend({
return L.resolveDefault(callServiceList(conf), {}) return L.resolveDefault(callServiceList(conf), {})
.then((res) => { .then((res) => {
var isRunning = false; let isRunning = false;
try { try {
isRunning = res[conf]['instances'][instance].running; isRunning = res[conf]['instances'][instance].running;
} catch (e) {} } catch (e) {}
@ -440,7 +440,7 @@ return baseclass.extend({
}); });
}, },
getClashAPI: function(instance) { getClashAPI(instance) {
const callGetClashAPI = rpc.declare({ const callGetClashAPI = rpc.declare({
object: 'luci.fchomo', object: 'luci.fchomo',
method: 'get_clash_api', method: 'get_clash_api',
@ -452,8 +452,8 @@ return baseclass.extend({
}, },
// thanks to homeproxy // thanks to homeproxy
loadDefaultLabel: function(section_id) { loadDefaultLabel(section_id) {
var label = uci.get(this.config, section_id, 'label'); const label = uci.get(this.config, section_id, 'label');
if (label) { if (label) {
return label; return label;
} else { } else {
@ -463,12 +463,12 @@ return baseclass.extend({
}, },
// thanks to homeproxy // thanks to homeproxy
loadModalTitle: function(title, addtitle, section_id) { loadModalTitle(title, addtitle, section_id) {
var label = uci.get(this.config, section_id, 'label'); const label = uci.get(this.config, section_id, 'label');
return label ? title + ' » ' + label : addtitle; return label ? title + ' » ' + label : addtitle;
}, },
loadProxyGroupLabel: function(preadds, section_id) { loadProxyGroupLabel(preadds, section_id) {
delete this.keylist; delete this.keylist;
delete this.vallist; delete this.vallist;
@ -483,7 +483,7 @@ return baseclass.extend({
return this.super('load', section_id); return this.super('load', section_id);
}, },
loadNodeLabel: function(section_id) { loadNodeLabel(section_id) {
delete this.keylist; delete this.keylist;
delete this.vallist; delete this.vallist;
@ -496,7 +496,7 @@ return baseclass.extend({
return this.super('load', section_id); return this.super('load', section_id);
}, },
loadProviderLabel: function(section_id) { loadProviderLabel(section_id) {
delete this.keylist; delete this.keylist;
delete this.vallist; delete this.vallist;
@ -509,7 +509,7 @@ return baseclass.extend({
return this.super('load', section_id); return this.super('load', section_id);
}, },
loadRulesetLabel: function(behaviors, section_id) { loadRulesetLabel(behaviors, section_id) {
delete this.keylist; delete this.keylist;
delete this.vallist; delete this.vallist;
@ -523,7 +523,7 @@ return baseclass.extend({
return this.super('load', section_id); return this.super('load', section_id);
}, },
loadSubRuleGroup: function(section_id) { loadSubRuleGroup(section_id) {
delete this.keylist; delete this.keylist;
delete this.vallist; delete this.vallist;
@ -540,8 +540,8 @@ return baseclass.extend({
return this.super('load', section_id); return this.super('load', section_id);
}, },
renderStatus: function(self, ElId, isRunning, instance, noGlobal) { renderStatus(self, ElId, isRunning, instance, noGlobal) {
var visible = isRunning && (isRunning.http || isRunning.https); const visible = isRunning && (isRunning.http || isRunning.https);
return E([ return E([
E('button', { E('button', {
@ -557,7 +557,7 @@ return baseclass.extend({
}, [ _('Open Dashboard') ]) }, [ _('Open Dashboard') ])
]); ]);
}, },
updateStatus: function(self, El, isRunning, instance, noGlobal) { updateStatus(self, El, isRunning, instance, noGlobal) {
if (El) { if (El) {
El.style.color = isRunning ? 'green' : 'red'; El.style.color = isRunning ? 'green' : 'red';
El.innerHTML = ' %s%s '.format(noGlobal ? instance + ' ' : '', isRunning ? _('Running') : _('Not Running')); El.innerHTML = ' %s%s '.format(noGlobal ? instance + ' ' : '', isRunning ? _('Running') : _('Not Running'));
@ -576,24 +576,24 @@ return baseclass.extend({
return El; return El;
}, },
getDashURL: function(self, isRunning) { getDashURL(self, isRunning) {
var tls = isRunning.https ? 's' : '', const tls = isRunning.https ? 's' : '';
host = window.location.hostname, const host = window.location.hostname;
port = isRunning.https ? isRunning.https.split(':').pop() : isRunning.http.split(':').pop(), const port = isRunning.https ? isRunning.https.split(':').pop() : isRunning.http.split(':').pop();
secret = isRunning.secret, const secret = isRunning.secret;
repo = isRunning.dashboard_repo; const repo = isRunning.dashboard_repo;
return 'http%s://%s:%s/ui/'.format(tls, host, port) + return 'http%s://%s:%s/ui/'.format(tls, host, port) +
String.format(self.dashrepos_urlparams[repo] || '', host, port, secret) String.format(self.dashrepos_urlparams[repo] || '', host, port, secret)
}, },
renderResDownload: function(self, section_id) { renderResDownload(self, section_id) {
var section_type = this.section.sectiontype; const section_type = this.section.sectiontype;
var type = uci.get(this.config, section_id, 'type'), const type = uci.get(this.config, section_id, 'type');
url = uci.get(this.config, section_id, 'url'), const url = uci.get(this.config, section_id, 'url');
header = uci.get(this.config, section_id, 'header'); const header = uci.get(this.config, section_id, 'header');
var El = E([ let El = E([
E('button', { E('button', {
class: 'cbi-button cbi-button-add', class: 'cbi-button cbi-button-add',
disabled: (type !== 'http') || null, disabled: (type !== 'http') || null,
@ -613,13 +613,13 @@ return baseclass.extend({
return El; return El;
}, },
renderSectionAdd: function(prefmt, LC, extra_class) { renderSectionAdd(prefmt, LC, extra_class) {
var el = form.GridSection.prototype.renderSectionAdd.apply(this, [ extra_class ]), let el = form.GridSection.prototype.renderSectionAdd.apply(this, [ extra_class ]),
nameEl = el.querySelector('.cbi-section-create-name'); nameEl = el.querySelector('.cbi-section-create-name');
ui.addValidator(nameEl, 'uciname', true, (v) => { ui.addValidator(nameEl, 'uciname', true, (v) => {
var button = el.querySelector('.cbi-section-create > .cbi-button-add'); let button = el.querySelector('.cbi-section-create > .cbi-button-add');
var prefix = prefmt?.prefix ? prefmt.prefix : '', const prefix = prefmt?.prefix ? prefmt.prefix : '';
suffix = prefmt?.suffix ? prefmt.suffix : ''; const suffix = prefmt?.suffix ? prefmt.suffix : '';
if (!v) { if (!v) {
button.disabled = true; button.disabled = true;
@ -642,14 +642,14 @@ return baseclass.extend({
return el; return el;
}, },
handleAdd: function(prefmt, ev, name) { handleAdd(prefmt, ev, name) {
var prefix = prefmt?.prefix ? prefmt.prefix : '', const prefix = prefmt?.prefix ? prefmt.prefix : '';
suffix = prefmt?.suffix ? prefmt.suffix : ''; const suffix = prefmt?.suffix ? prefmt.suffix : '';
return form.GridSection.prototype.handleAdd.apply(this, [ ev, prefix + name + suffix ]); return form.GridSection.prototype.handleAdd.apply(this, [ ev, prefix + name + suffix ]);
}, },
handleReload: function(instance, ev, section_id) { handleReload(instance, ev, section_id) {
instance = instance || ''; instance = instance || '';
return fs.exec('/etc/init.d/fchomo', ['reload', instance]) return fs.exec('/etc/init.d/fchomo', ['reload', instance])
.then((res) => { /* return window.location = window.location.href.split('#')[0] */ }) .then((res) => { /* return window.location = window.location.href.split('#')[0] */ })
@ -658,8 +658,8 @@ return baseclass.extend({
}) })
}, },
handleRemoveIdles: function(self) { handleRemoveIdles(self) {
var section_type = this.sectiontype; const section_type = this.sectiontype;
let loaded = []; let loaded = [];
uci.sections(this.config, section_type, (section, sid) => loaded.push(sid)); uci.sections(this.config, section_type, (section, sid) => loaded.push(sid));
@ -702,14 +702,14 @@ return baseclass.extend({
}); });
}, },
textvalue2Value: function(section_id) { textvalue2Value(section_id) {
var cval = this.cfgvalue(section_id); let cval = this.cfgvalue(section_id);
var i = this.keylist.indexOf(cval); let i = this.keylist.indexOf(cval);
return this.vallist[i]; return this.vallist[i];
}, },
validateAuth: function(section_id, value) { validateAuth(section_id, value) {
if (!value) if (!value)
return true; return true;
if (!value.match(/^[\w-]{3,}:[^:]+$/)) if (!value.match(/^[\w-]{3,}:[^:]+$/))
@ -717,7 +717,7 @@ return baseclass.extend({
return true; return true;
}, },
validateAuthUsername: function(section_id, value) { validateAuthUsername(section_id, value) {
if (!value) if (!value)
return true; return true;
if (!value.match(/^[\w-]{3,}$/)) if (!value.match(/^[\w-]{3,}$/))
@ -725,7 +725,7 @@ return baseclass.extend({
return true; return true;
}, },
validateAuthPassword: function(section_id, value) { validateAuthPassword(section_id, value) {
if (!value) if (!value)
return true; return true;
if (!value.match(/^[^:]+$/)) if (!value.match(/^[^:]+$/))
@ -734,24 +734,24 @@ return baseclass.extend({
return true; return true;
}, },
validateCommonPort: function(section_id, value) { validateCommonPort(section_id, value) {
// thanks to homeproxy // thanks to homeproxy
var stubValidator = { let stubValidator = {
factory: validation, factory: validation,
apply: function(type, value, args) { apply(type, value, args) {
if (value != null) if (value != null)
this.value = value; this.value = value;
return validation.types[type].apply(this, args); return validation.types[type].apply(this, args);
}, },
assert: function(condition) { assert(condition) {
return !!condition; return !!condition;
} }
}; };
if (value && !value.match(/common(_stun)?/)) { if (value && !value.match(/common(_stun)?/)) {
var ports = []; let ports = [];
for (var i of value.split(',')) { for (let i of value.split(',')) {
if (!stubValidator.apply('port', i) && !stubValidator.apply('portrange', i)) if (!stubValidator.apply('port', i) && !stubValidator.apply('portrange', i))
return _('Expecting: %s').format(_('valid port value')); return _('Expecting: %s').format(_('valid port value'));
if (ports.includes(i)) if (ports.includes(i))
@ -763,12 +763,12 @@ return baseclass.extend({
return true; return true;
}, },
validateJson: function(section_id, value) { validateJson(section_id, value) {
if (!value) if (!value)
return true; return true;
try { try {
var obj = JSON.parse(value.trim()); let obj = JSON.parse(value.trim());
if (!obj) if (!obj)
return _('Expecting: %s').format(_('valid JSON format')); return _('Expecting: %s').format(_('valid JSON format'));
} }
@ -779,7 +779,7 @@ return baseclass.extend({
return true; return true;
}, },
validateBase64Key: function(length, section_id, value) { validateBase64Key(length, section_id, value) {
/* Thanks to luci-proto-wireguard */ /* Thanks to luci-proto-wireguard */
if (value) if (value)
if (value.length !== length || !value.match(/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/) || value[length-1] !== '=') if (value.length !== length || !value.match(/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/) || value[length-1] !== '=')
@ -788,8 +788,8 @@ return baseclass.extend({
return true; return true;
}, },
validateShadowsocksPassword: function(self, encmode, section_id, value) { validateShadowsocksPassword(self, encmode, section_id, value) {
var length = self.shadowsocks_cipher_length[encmode]; let length = self.shadowsocks_cipher_length[encmode];
if (typeof length !== 'undefined') { if (typeof length !== 'undefined') {
length = Math.ceil(length/3)*4; length = Math.ceil(length/3)*4;
if (encmode.match(/^2022-/)) { if (encmode.match(/^2022-/)) {
@ -806,7 +806,7 @@ return baseclass.extend({
return true; return true;
}, },
validateBytesize: function(section_id, value) { validateBytesize(section_id, value) {
if (!value) if (!value)
return true; return true;
@ -815,7 +815,7 @@ return baseclass.extend({
return true; return true;
}, },
validateTimeDuration: function(section_id, value) { validateTimeDuration(section_id, value) {
if (!value) if (!value)
return true; return true;
@ -825,11 +825,11 @@ return baseclass.extend({
return true; return true;
}, },
validateUniqueValue: function(section_id, value) { validateUniqueValue(section_id, value) {
if (!value) if (!value)
return _('Expecting: %s').format(_('non-empty value')); return _('Expecting: %s').format(_('non-empty value'));
var duplicate = false; let duplicate = false;
uci.sections(this.config, this.section.sectiontype, (res) => { uci.sections(this.config, this.section.sectiontype, (res) => {
if (res['.name'] !== section_id) if (res['.name'] !== section_id)
if (res[this.option] === value) if (res[this.option] === value)
@ -841,12 +841,12 @@ return baseclass.extend({
return true; return true;
}, },
validateUrl: function(section_id, value) { validateUrl(section_id, value) {
if (!value) if (!value)
return true; return true;
try { try {
var url = new URL(value); let url = new URL(value);
if (!url.hostname) if (!url.hostname)
return _('Expecting: %s').format(_('valid URL')); return _('Expecting: %s').format(_('valid URL'));
} }
@ -857,7 +857,7 @@ return baseclass.extend({
return true; return true;
}, },
validateUUID: function(section_id, value) { validateUUID(section_id, value) {
if (!value) if (!value)
return true; return true;
else if (value.match('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$') === null) else if (value.match('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$') === null)
@ -866,7 +866,7 @@ return baseclass.extend({
return true; return true;
}, },
lsDir: function(type) { lsDir(type) {
const callLsDir = rpc.declare({ const callLsDir = rpc.declare({
object: 'luci.fchomo', object: 'luci.fchomo',
method: 'dir_ls', method: 'dir_ls',
@ -882,7 +882,7 @@ return baseclass.extend({
}); });
}, },
readFile: function(type, filename) { readFile(type, filename) {
const callReadFile = rpc.declare({ const callReadFile = rpc.declare({
object: 'luci.fchomo', object: 'luci.fchomo',
method: 'file_read', method: 'file_read',
@ -898,7 +898,7 @@ return baseclass.extend({
}); });
}, },
writeFile: function(type, filename, content) { writeFile(type, filename, content) {
const callWriteFile = rpc.declare({ const callWriteFile = rpc.declare({
object: 'luci.fchomo', object: 'luci.fchomo',
method: 'file_write', method: 'file_write',
@ -914,7 +914,7 @@ return baseclass.extend({
}); });
}, },
downloadFile: function(type, filename, url, header) { downloadFile(type, filename, url, header) {
const callDownloadFile = rpc.declare({ const callDownloadFile = rpc.declare({
object: 'luci.fchomo', object: 'luci.fchomo',
method: 'file_download', method: 'file_download',
@ -930,7 +930,7 @@ return baseclass.extend({
}); });
}, },
removeFile: function(type, filename) { removeFile(type, filename) {
const callRemoveFile = rpc.declare({ const callRemoveFile = rpc.declare({
object: 'luci.fchomo', object: 'luci.fchomo',
method: 'file_remove', method: 'file_remove',
@ -947,7 +947,7 @@ return baseclass.extend({
}, },
// thanks to homeproxy // thanks to homeproxy
uploadCertificate: function(type, filename, ev) { uploadCertificate(type, filename, ev) {
const callWriteCertificate = rpc.declare({ const callWriteCertificate = rpc.declare({
object: 'luci.fchomo', object: 'luci.fchomo',
method: 'certificate_write', method: 'certificate_write',
@ -966,7 +966,7 @@ return baseclass.extend({
}, this, ev.target)) }, this, ev.target))
.catch((e) => { ui.addNotification(null, E('p', e.message)) }); .catch((e) => { ui.addNotification(null, E('p', e.message)) });
}, },
uploadInitialPack: function(ev, section_id) { uploadInitialPack(ev, section_id) {
const callWriteInitialPack = rpc.declare({ const callWriteInitialPack = rpc.declare({
object: 'luci.fchomo', object: 'luci.fchomo',
method: 'initialpack_write', method: 'initialpack_write',

View File

@ -211,15 +211,15 @@ function flagToBool(flag) {
function renderPayload(s, total, uciconfig) { function renderPayload(s, total, uciconfig) {
// common payload // common payload
var initPayload = function(o, n, key, uciconfig) { let initPayload = function(o, n, key, uciconfig) {
o.load = L.bind(function(n, key, uciconfig, section_id) { o.load = L.bind(function(n, key, uciconfig, section_id) {
return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getPayload(n)[key]; return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getPayload(n)[key];
}, o, n, key, uciconfig); }, o, n, key, uciconfig);
o.onchange = function(ev, section_id, value) { o.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
let n = this.option.match(/^payload(\d+)_/)[1]; let n = this.option.match(/^payload(\d+)_/)[1];
var rule = new RulesEntry(UIEl.getValue()).setPayload(n, {factor: value}); let rule = new RulesEntry(UIEl.getValue()).setPayload(n, {factor: value});
UIEl.node.previousSibling.innerText = rule.toString('mihomo'); UIEl.node.previousSibling.innerText = rule.toString('mihomo');
UIEl.setValue(rule.toString('json')); UIEl.setValue(rule.toString('json'));
@ -228,14 +228,14 @@ function renderPayload(s, total, uciconfig) {
o.rmempty = false; o.rmempty = false;
o.modalonly = true; o.modalonly = true;
} }
var initDynamicPayload = function(o, n, key, uciconfig) { let initDynamicPayload = function(o, n, key, uciconfig) {
o.load = L.bind(function(n, key, uciconfig, section_id) { o.load = L.bind(function(n, key, uciconfig, section_id) {
return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getPayloads().slice(n).map(e => e[key] ?? ''); return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getPayloads().slice(n).map(e => e[key] ?? '');
}, o, n, key, uciconfig); }, o, n, key, uciconfig);
o.validate = function(section_id, value) { o.validate = function(section_id, value) {
value = this.formvalue(section_id); value = this.formvalue(section_id);
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
var rule = new RulesEntry(UIEl.getValue()); let rule = new RulesEntry(UIEl.getValue());
let n = this.option.match(/^payload(\d+)_/)[1]; let n = this.option.match(/^payload(\d+)_/)[1];
let limit = rule.getPayloads().length; let limit = rule.getPayloads().length;
@ -254,9 +254,9 @@ function renderPayload(s, total, uciconfig) {
o.modalonly = true; o.modalonly = true;
} }
var o, prefix; let o, prefix;
// StaticList payload // StaticList payload
for (var n=0; n<total; n++) { for (let n=0; n<total; n++) {
prefix = `payload${n}_`; prefix = `payload${n}_`;
o = s.option(form.ListValue, prefix + 'type', _('Type') + ` ${n+1}`); o = s.option(form.ListValue, prefix + 'type', _('Type') + ` ${n+1}`);
@ -270,10 +270,10 @@ function renderPayload(s, total, uciconfig) {
}) })
initPayload(o, n, 'type', uciconfig); initPayload(o, n, 'type', uciconfig);
o.onchange = function(ev, section_id, value) { o.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
let n = this.option.match(/^payload(\d+)_/)[1]; let n = this.option.match(/^payload(\d+)_/)[1];
var rule = new RulesEntry(UIEl.getValue()).setPayload(n, {type: value}); let rule = new RulesEntry(UIEl.getValue()).setPayload(n, {type: value});
UIEl.node.previousSibling.innerText = rule.toString('mihomo'); UIEl.node.previousSibling.innerText = rule.toString('mihomo');
UIEl.setValue(rule.toString('json')); UIEl.setValue(rule.toString('json'));
@ -344,10 +344,10 @@ function renderPayload(s, total, uciconfig) {
return boolToFlag(new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getPayload(n)[key]); return boolToFlag(new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getPayload(n)[key]);
}, o, n, 'deny', uciconfig); }, o, n, 'deny', uciconfig);
o.onchange = function(ev, section_id, value) { o.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
let n = this.option.match(/^payload(\d+)_/)[1]; let n = this.option.match(/^payload(\d+)_/)[1];
var rule = new RulesEntry(UIEl.getValue()).setPayload(n, {deny: flagToBool(value) || null}); let rule = new RulesEntry(UIEl.getValue()).setPayload(n, {deny: flagToBool(value) || null});
UIEl.node.previousSibling.innerText = rule.toString('mihomo'); UIEl.node.previousSibling.innerText = rule.toString('mihomo');
UIEl.setValue(rule.toString('json')); UIEl.setValue(rule.toString('json'));
@ -355,7 +355,7 @@ function renderPayload(s, total, uciconfig) {
} }
// DynamicList payload // DynamicList payload
var extenbox = {}; let extenbox = {};
Object.entries(hm.rules_logical_payload_count).filter(e => e[1].high === undefined).forEach((e) => { Object.entries(hm.rules_logical_payload_count).filter(e => e[1].high === undefined).forEach((e) => {
let low = e[1].low; let low = e[1].low;
let type = e[0]; let type = e[0];
@ -377,8 +377,8 @@ function renderPayload(s, total, uciconfig) {
initDynamicPayload(o, n, 'type', uciconfig); initDynamicPayload(o, n, 'type', uciconfig);
o.validate = function(section_id, value) { o.validate = function(section_id, value) {
value = this.formvalue(section_id); value = this.formvalue(section_id);
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
var rule = new RulesEntry(UIEl.getValue()); let rule = new RulesEntry(UIEl.getValue());
let n = this.option.match(/^payload(\d+)_/)[1]; let n = this.option.match(/^payload(\d+)_/)[1];
value.forEach((val) => { value.forEach((val) => {
@ -428,8 +428,8 @@ function renderPayload(s, total, uciconfig) {
}, o, n, 'deny', uciconfig); }, o, n, 'deny', uciconfig);
o.validate = function(section_id, value) { o.validate = function(section_id, value) {
value = this.formvalue(section_id); value = this.formvalue(section_id);
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
var rule = new RulesEntry(UIEl.getValue()); let rule = new RulesEntry(UIEl.getValue());
let n = this.option.match(/^payload(\d+)_/)[1]; let n = this.option.match(/^payload(\d+)_/)[1];
let limit = rule.getPayloads().length; let limit = rule.getPayloads().length;
@ -447,11 +447,11 @@ function renderPayload(s, total, uciconfig) {
} }
function renderRules(s, uciconfig) { function renderRules(s, uciconfig) {
var o; let o;
o = s.option(form.DummyValue, 'entry', _('Entry')); o = s.option(form.DummyValue, 'entry', _('Entry'));
o.renderWidget = function(/* ... */) { o.renderWidget = function(/* ... */) {
var El = form.DummyValue.prototype.renderWidget.apply(this, arguments); let El = form.DummyValue.prototype.renderWidget.apply(this, arguments);
El.firstChild.innerText = new RulesEntry(El.querySelector('input').value).toString('mihomo'); El.firstChild.innerText = new RulesEntry(El.querySelector('input').value).toString('mihomo');
@ -488,9 +488,9 @@ function renderRules(s, uciconfig) {
UIEl.node.querySelector('input').disabled = 'true'; UIEl.node.querySelector('input').disabled = 'true';
}); });
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
var rule = new RulesEntry(UIEl.getValue()).setParam('no-resolve').setParam('src'); let rule = new RulesEntry(UIEl.getValue()).setParam('no-resolve').setParam('src');
UIEl.node.previousSibling.innerText = rule.toString('mihomo'); UIEl.node.previousSibling.innerText = rule.toString('mihomo');
UIEl.setValue(rule.toString('json')); UIEl.setValue(rule.toString('json'));
@ -499,9 +499,9 @@ function renderRules(s, uciconfig) {
return true; return true;
} }
o.onchange = function(ev, section_id, value) { o.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
var rule = new RulesEntry(UIEl.getValue()).setKey('type', value); let rule = new RulesEntry(UIEl.getValue()).setKey('type', value);
UIEl.node.previousSibling.innerText = rule.toString('mihomo'); UIEl.node.previousSibling.innerText = rule.toString('mihomo');
UIEl.setValue(rule.toString('json')); UIEl.setValue(rule.toString('json'));
@ -519,9 +519,9 @@ function renderRules(s, uciconfig) {
return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).detour; return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).detour;
} }
o.onchange = function(ev, section_id, value) { o.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
var rule = new RulesEntry(UIEl.getValue()).setKey('detour', value); let rule = new RulesEntry(UIEl.getValue()).setKey('detour', value);
UIEl.node.previousSibling.innerText = rule.toString('mihomo'); UIEl.node.previousSibling.innerText = rule.toString('mihomo');
UIEl.setValue(rule.toString('json')); UIEl.setValue(rule.toString('json'));
@ -536,9 +536,9 @@ function renderRules(s, uciconfig) {
return boolToFlag(new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getParam('src')); return boolToFlag(new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getParam('src'));
} }
o.onchange = function(ev, section_id, value) { o.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
var rule = new RulesEntry(UIEl.getValue()).setParam('src', flagToBool(value) || null); let rule = new RulesEntry(UIEl.getValue()).setParam('src', flagToBool(value) || null);
UIEl.node.previousSibling.innerText = rule.toString('mihomo'); UIEl.node.previousSibling.innerText = rule.toString('mihomo');
UIEl.setValue(rule.toString('json')); UIEl.setValue(rule.toString('json'));
@ -553,9 +553,9 @@ function renderRules(s, uciconfig) {
return boolToFlag(new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getParam('no-resolve')); return boolToFlag(new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getParam('no-resolve'));
} }
o.onchange = function(ev, section_id, value) { o.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
var rule = new RulesEntry(UIEl.getValue()).setParam('no-resolve', flagToBool(value) || null); let rule = new RulesEntry(UIEl.getValue()).setParam('no-resolve', flagToBool(value) || null);
UIEl.node.previousSibling.innerText = rule.toString('mihomo'); UIEl.node.previousSibling.innerText = rule.toString('mihomo');
UIEl.setValue(rule.toString('json')); UIEl.setValue(rule.toString('json'));
@ -566,14 +566,14 @@ function renderRules(s, uciconfig) {
} }
return view.extend({ return view.extend({
load: function() { load() {
return Promise.all([ return Promise.all([
uci.load('fchomo') uci.load('fchomo')
]); ]);
}, },
render: function(data) { render(data) {
var dashboard_repo = uci.get(data[0], 'api', 'dashboard_repo'); const dashboard_repo = uci.get(data[0], 'api', 'dashboard_repo');
let m, s, o, ss, so; let m, s, o, ss, so;
@ -836,9 +836,9 @@ return view.extend({
return true; return true;
} }
so.onchange = function(ev, section_id, value) { so.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
var rule = new RulesEntry(UIEl.getValue()).setKey('subrule', value === '1' ? ' ' : false); let rule = new RulesEntry(UIEl.getValue()).setKey('subrule', value === '1' ? ' ' : false);
UIEl.node.previousSibling.innerText = rule.toString('mihomo'); UIEl.node.previousSibling.innerText = rule.toString('mihomo');
UIEl.setValue(rule.toString('json')); UIEl.setValue(rule.toString('json'));
@ -853,9 +853,9 @@ return view.extend({
return new RulesEntry(uci.get(data[0], section_id, 'entry')).subrule || ''; return new RulesEntry(uci.get(data[0], section_id, 'entry')).subrule || '';
} }
so.onchange = function(ev, section_id, value) { so.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'entry'); let UIEl = this.section.getUIElement(section_id, 'entry');
var rule = new RulesEntry(UIEl.getValue()).setKey('subrule', value); let rule = new RulesEntry(UIEl.getValue()).setKey('subrule', value);
UIEl.node.previousSibling.innerText = rule.toString('mihomo'); UIEl.node.previousSibling.innerText = rule.toString('mihomo');
UIEl.setValue(rule.toString('json')); UIEl.setValue(rule.toString('json'));
@ -941,8 +941,8 @@ return view.extend({
so.load = L.bind(loadDNSServerLabel, so); so.load = L.bind(loadDNSServerLabel, so);
so.validate = L.bind(validateNameserver, so); so.validate = L.bind(validateNameserver, so);
so.onchange = function(ev, section_id, value) { so.onchange = function(ev, section_id, value) {
var ddesc = this.section.getUIElement(section_id, 'default_server').node.nextSibling; let ddesc = this.section.getUIElement(section_id, 'default_server').node.nextSibling;
var fdesc = ev.target.nextSibling; let fdesc = ev.target.nextSibling;
if (value.length > 0) { if (value.length > 0) {
ddesc.innerHTML = _('Final DNS server (Used to Domestic-IP response)'); ddesc.innerHTML = _('Final DNS server (Used to Domestic-IP response)');
fdesc.innerHTML = _('Final DNS server (Used to Overseas-IP response)'); fdesc.innerHTML = _('Final DNS server (Used to Overseas-IP response)');
@ -998,9 +998,9 @@ return view.extend({
this.section.getUIElement(section_id, 'ecs').node.querySelector('input').disabled = null; this.section.getUIElement(section_id, 'ecs').node.querySelector('input').disabled = null;
this.section.getUIElement(section_id, 'ecs-override').node.querySelector('input').disabled = null; this.section.getUIElement(section_id, 'ecs-override').node.querySelector('input').disabled = null;
} else { } else {
var UIEl = this.section.getUIElement(section_id, 'address'); let UIEl = this.section.getUIElement(section_id, 'address');
var newvalue = new DNSAddress(UIEl.getValue()).setParam('h3').setParam('ecs').setParam('ecs-override').toString(); let newvalue = new DNSAddress(UIEl.getValue()).setParam('h3').setParam('ecs').setParam('ecs-override').toString();
UIEl.node.previousSibling.innerText = newvalue; UIEl.node.previousSibling.innerText = newvalue;
UIEl.setValue(newvalue); UIEl.setValue(newvalue);
@ -1015,9 +1015,9 @@ return view.extend({
return true; return true;
} }
so.onchange = function(ev, section_id, value) { so.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'address'); let UIEl = this.section.getUIElement(section_id, 'address');
var newvalue = ('N' + UIEl.getValue()).replace(/^[^#]+/, value); let newvalue = ('N' + UIEl.getValue()).replace(/^[^#]+/, value);
UIEl.node.previousSibling.innerText = newvalue; UIEl.node.previousSibling.innerText = newvalue;
UIEl.setValue(newvalue); UIEl.setValue(newvalue);
@ -1033,9 +1033,9 @@ return view.extend({
return new DNSAddress(uci.get(data[0], section_id, 'address')).parseParam('detour'); return new DNSAddress(uci.get(data[0], section_id, 'address')).parseParam('detour');
} }
so.onchange = function(ev, section_id, value) { so.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'address'); let UIEl = this.section.getUIElement(section_id, 'address');
var newvalue = new DNSAddress(UIEl.getValue()).setParam('detour', value).toString(); let newvalue = new DNSAddress(UIEl.getValue()).setParam('detour', value).toString();
UIEl.node.previousSibling.innerText = newvalue; UIEl.node.previousSibling.innerText = newvalue;
UIEl.setValue(newvalue); UIEl.setValue(newvalue);
@ -1049,9 +1049,9 @@ return view.extend({
return boolToFlag(new DNSAddress(uci.get(data[0], section_id, 'address')).parseParam('h3')); return boolToFlag(new DNSAddress(uci.get(data[0], section_id, 'address')).parseParam('h3'));
} }
so.onchange = function(ev, section_id, value) { so.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'address'); let UIEl = this.section.getUIElement(section_id, 'address');
var newvalue = new DNSAddress(UIEl.getValue()).setParam('h3', flagToBool(value) || null).toString(); let newvalue = new DNSAddress(UIEl.getValue()).setParam('h3', flagToBool(value) || null).toString();
UIEl.node.previousSibling.innerText = newvalue; UIEl.node.previousSibling.innerText = newvalue;
UIEl.setValue(newvalue); UIEl.setValue(newvalue);
@ -1065,9 +1065,9 @@ return view.extend({
return new DNSAddress(uci.get(data[0], section_id, 'address')).parseParam('ecs'); return new DNSAddress(uci.get(data[0], section_id, 'address')).parseParam('ecs');
} }
so.onchange = function(ev, section_id, value) { so.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'address'); let UIEl = this.section.getUIElement(section_id, 'address');
var newvalue = new DNSAddress(UIEl.getValue()).setParam('ecs', value).toString(); let newvalue = new DNSAddress(UIEl.getValue()).setParam('ecs', value).toString();
UIEl.node.previousSibling.innerText = newvalue; UIEl.node.previousSibling.innerText = newvalue;
UIEl.setValue(newvalue); UIEl.setValue(newvalue);
@ -1082,9 +1082,9 @@ return view.extend({
return boolToFlag(new DNSAddress(uci.get(data[0], section_id, 'address')).parseParam('ecs-override')); return boolToFlag(new DNSAddress(uci.get(data[0], section_id, 'address')).parseParam('ecs-override'));
} }
so.onchange = function(ev, section_id, value) { so.onchange = function(ev, section_id, value) {
var UIEl = this.section.getUIElement(section_id, 'address'); let UIEl = this.section.getUIElement(section_id, 'address');
var newvalue = new DNSAddress(UIEl.getValue()).setParam('ecs-override', flagToBool(value) || null).toString(); let newvalue = new DNSAddress(UIEl.getValue()).setParam('ecs-override', flagToBool(value) || null).toString();
UIEl.node.previousSibling.innerText = newvalue; UIEl.node.previousSibling.innerText = newvalue;
UIEl.setValue(newvalue); UIEl.setValue(newvalue);
@ -1144,7 +1144,7 @@ return view.extend({
so = ss.option(form.DummyValue, '_entry', _('Entry')); so = ss.option(form.DummyValue, '_entry', _('Entry'));
so.load = function(section_id) { so.load = function(section_id) {
var option = uci.get(data[0], section_id, 'type'); const option = uci.get(data[0], section_id, 'type');
return uci.get(data[0], section_id, option)?.join(','); return uci.get(data[0], section_id, option)?.join(',');
} }

View File

@ -45,10 +45,10 @@ function handleResUpdate(type, repo) {
}); });
// Dynamic repo // Dynamic repo
var label; let label;
if (repo) { if (repo) {
var section_id = this.section.section; const section_id = this.section.section;
var weight = document.getElementById(this.cbid(section_id)); let weight = document.getElementById(this.cbid(section_id));
if (weight) if (weight)
repo = weight.firstChild.value, repo = weight.firstChild.value,
label = weight.firstChild.selectedOptions[0].label; label = weight.firstChild.selectedOptions[0].label;
@ -79,7 +79,7 @@ function handleResUpdate(type, repo) {
function renderResVersion(El, type, repo) { function renderResVersion(El, type, repo) {
return L.resolveDefault(callResVersion(type, repo), {}).then((res) => { return L.resolveDefault(callResVersion(type, repo), {}).then((res) => {
var resEl = E([ let resEl = E([
E('button', { E('button', {
'class': 'cbi-button cbi-button-apply', 'class': 'cbi-button cbi-button-apply',
'click': ui.createHandlerFn(this, handleResUpdate, type, repo) 'click': ui.createHandlerFn(this, handleResUpdate, type, repo)
@ -107,7 +107,7 @@ function updateResVersion(El, version) {
} }
function renderNATBehaviorTest(El) { function renderNATBehaviorTest(El) {
var resEl = E('div', { 'class': 'control-group' }, [ let resEl = E('div', { 'class': 'control-group' }, [
E('select', { E('select', {
'id': '_status_nattest_l4proto', 'id': '_status_nattest_l4proto',
'class': 'cbi-input-select', 'class': 'cbi-input-select',
@ -119,9 +119,9 @@ function renderNATBehaviorTest(El) {
E('button', { E('button', {
'class': 'cbi-button cbi-button-apply', 'class': 'cbi-button cbi-button-apply',
'click': ui.createHandlerFn(this, function() { 'click': ui.createHandlerFn(this, function() {
var stun = this.formvalue(this.section.section); const stun = this.formvalue(this.section.section);
var l4proto = document.getElementById('_status_nattest_l4proto').value; const l4proto = document.getElementById('_status_nattest_l4proto').value;
var l4proto_idx = document.getElementById('_status_nattest_l4proto').selectedIndex; const l4proto_idx = document.getElementById('_status_nattest_l4proto').selectedIndex;
return fs.exec_direct('/etc/fchomo/scripts/natcheck.sh', [stun, l4proto, getRandom(32768, 61000)]).then((stdout) => { return fs.exec_direct('/etc/fchomo/scripts/natcheck.sh', [stun, l4proto, getRandom(32768, 61000)]).then((stdout) => {
this.description = '<details><summary>' + _('Expand/Collapse result') + '</summary>' + stdout + '</details>'; this.description = '<details><summary>' + _('Expand/Collapse result') + '</summary>' + stdout + '</details>';
@ -144,7 +144,7 @@ function renderNATBehaviorTest(El) {
} }
return view.extend({ return view.extend({
load: function() { load() {
return Promise.all([ return Promise.all([
uci.load('fchomo'), uci.load('fchomo'),
hm.getFeatures(), hm.getFeatures(),
@ -158,17 +158,17 @@ return view.extend({
]); ]);
}, },
render: function(data) { render(data) {
var features = data[1], const features = data[1];
hosts = data[2]?.hosts, const hosts = data[2]?.hosts;
CisRunning = data[3], const CisRunning = data[3];
CclashAPI = data[4], const CclashAPI = data[4];
SisRunning = data[5], const SisRunning = data[5];
SclashAPI = data[6], const SclashAPI = data[6];
res_ver_geoip = data[7], const res_ver_geoip = data[7];
res_ver_geosite = data[8]; const res_ver_geosite = data[8];
var dashboard_repo = uci.get(data[0], 'api', 'dashboard_repo'); const dashboard_repo = uci.get(data[0], 'api', 'dashboard_repo');
let m, s, o, ss, so; let m, s, o, ss, so;
@ -224,13 +224,13 @@ return view.extend({
expect: { '': {} } expect: { '': {} }
}); });
var ElId = '_connection_check_results'; const ElId = '_connection_check_results';
return E([ return E([
E('button', { E('button', {
'class': 'cbi-button cbi-button-apply', 'class': 'cbi-button cbi-button-apply',
'click': ui.createHandlerFn(this, function() { 'click': ui.createHandlerFn(this, function() {
var weight = document.getElementById(ElId); let weight = document.getElementById(ElId);
weight.innerHTML = ''; weight.innerHTML = '';
return hm.checkurls.forEach((site) => { return hm.checkurls.forEach((site) => {
@ -258,7 +258,7 @@ return view.extend({
so.readonly = true; so.readonly = true;
} else { } else {
so.renderWidget = function(/* ... */) { so.renderWidget = function(/* ... */) {
var El = form.Value.prototype.renderWidget.apply(this, arguments); let El = form.Value.prototype.renderWidget.apply(this, arguments);
return renderNATBehaviorTest.call(this, El); return renderNATBehaviorTest.call(this, El);
} }
@ -317,7 +317,7 @@ return view.extend({
so.value.apply(so, repo); so.value.apply(so, repo);
}) })
so.renderWidget = function(/* ... */) { so.renderWidget = function(/* ... */) {
var El = form.ListValue.prototype.renderWidget.apply(this, arguments); let El = form.ListValue.prototype.renderWidget.apply(this, arguments);
El.classList.add('control-group'); El.classList.add('control-group');
El.firstChild.style.width = '10em'; El.firstChild.style.width = '10em';
@ -327,7 +327,7 @@ return view.extend({
so.onchange = function(ev, section_id, value) { so.onchange = function(ev, section_id, value) {
this.default = value; this.default = value;
var weight = ev.target; let weight = ev.target;
if (weight) if (weight)
return L.resolveDefault(callResVersion('dashboard', value), {}).then((res) => { return L.resolveDefault(callResVersion('dashboard', value), {}).then((res) => {
updateResVersion(weight.lastChild, res.version); updateResVersion(weight.lastChild, res.version);

View File

@ -4,15 +4,15 @@
'require fchomo as hm'; 'require fchomo as hm';
var isReadonlyView = !L.hasViewPermission() || null; const isReadonlyView = !L.hasViewPermission() || null;
return view.extend({ return view.extend({
load: function() { load() {
return L.resolveDefault(hm.readFile('templates', 'hosts.yaml'), ''); return L.resolveDefault(hm.readFile('templates', 'hosts.yaml'), '');
}, },
handleSave: function(ev) { handleSave(ev) {
var value = (document.querySelector('textarea').value || '').trim().replace(/\r\n/g, '\n') + '\n'; let value = (document.querySelector('textarea').value || '').trim().replace(/\r\n/g, '\n') + '\n';
return hm.writeFile('templates', 'hosts.yaml', value).then(function(rc) { return hm.writeFile('templates', 'hosts.yaml', value).then(function(rc) {
document.querySelector('textarea').value = value; document.querySelector('textarea').value = value;
@ -22,7 +22,7 @@ return view.extend({
}); });
}, },
render: function(content) { render(content) {
return E([ return E([
E('h2', _('Hosts')), E('h2', _('Hosts')),
E('p', { 'class': 'cbi-section-descr' }, _('Custom internal hosts. Support <code>yaml</code> or <code>json</code> format.')), E('p', { 'class': 'cbi-section-descr' }, _('Custom internal hosts. Support <code>yaml</code> or <code>json</code> format.')),

View File

@ -9,7 +9,7 @@
'require view'; 'require view';
/* Thanks to luci-app-aria2 */ /* Thanks to luci-app-aria2 */
var css = ' \ const css = ' \
#log_textarea { \ #log_textarea { \
padding: 10px; \ padding: 10px; \
text-align: left; \ text-align: left; \
@ -23,7 +23,7 @@ var css = ' \
background-color: #33ccff; \ background-color: #33ccff; \
}'; }';
var hm_dir = '/var/run/fchomo'; const hm_dir = '/var/run/fchomo';
function getRuntimeLog(name, filename) { function getRuntimeLog(name, filename) {
const callLogClean = rpc.declare({ const callLogClean = rpc.declare({
@ -33,13 +33,13 @@ function getRuntimeLog(name, filename) {
expect: { '': {} } expect: { '': {} }
}); });
var log_textarea = E('div', { 'id': 'log_textarea' }, let log_textarea = E('div', { 'id': 'log_textarea' },
E('pre', { E('pre', {
'class': 'spinning' 'class': 'spinning'
}, _('Collecting data...')) }, _('Collecting data...'))
); );
var log; let log;
poll.add(L.bind(function() { poll.add(L.bind(function() {
return fs.read_direct(String.format('%s/%s.log', hm_dir, filename), 'text') return fs.read_direct(String.format('%s/%s.log', hm_dir, filename), 'text')
.then(function(res) { .then(function(res) {
@ -86,7 +86,7 @@ function getRuntimeLog(name, filename) {
} }
return view.extend({ return view.extend({
render: function(data) { render(data) {
let m, s, o, ss, so; let m, s, o, ss, so;
m = new form.Map('fchomo'); m = new form.Map('fchomo');

View File

@ -8,13 +8,13 @@
'require tools.widgets as widgets'; 'require tools.widgets as widgets';
return view.extend({ return view.extend({
load: function() { load() {
return Promise.all([ return Promise.all([
uci.load('fchomo') uci.load('fchomo')
]); ]);
}, },
render: function(data) { render(data) {
let m, s, o, ss, so; let m, s, o, ss, so;
m = new form.Map('fchomo', _('Edit node')); m = new form.Map('fchomo', _('Edit node'));
@ -151,7 +151,7 @@ return view.extend({
so = ss.taboption('field_general', form.Value, 'shadowsocks_password', _('Password')); so = ss.taboption('field_general', form.Value, 'shadowsocks_password', _('Password'));
so.password = true; so.password = true;
so.validate = function(section_id, value) { so.validate = function(section_id, value) {
var encmode = this.section.getOption('shadowsocks_chipher').formvalue(section_id); const encmode = this.section.getOption('shadowsocks_chipher').formvalue(section_id);
return hm.validateShadowsocksPassword.call(this, hm, encmode, section_id, value); return hm.validateShadowsocksPassword.call(this, hm, encmode, section_id, value);
} }
so.depends({type: 'ss', shadowsocks_chipher: /.+/}); so.depends({type: 'ss', shadowsocks_chipher: /.+/});
@ -278,7 +278,7 @@ return view.extend({
so = ss.taboption('field_general', form.Value, 'trojan_ss_password', _('Shadowsocks password')); so = ss.taboption('field_general', form.Value, 'trojan_ss_password', _('Shadowsocks password'));
so.password = true; so.password = true;
so.validate = function(section_id, value) { so.validate = function(section_id, value) {
var encmode = this.section.getOption('trojan_ss_chipher').formvalue(section_id); const encmode = this.section.getOption('trojan_ss_chipher').formvalue(section_id);
return hm.validateShadowsocksPassword.call(this, hm, encmode, section_id, value); return hm.validateShadowsocksPassword.call(this, hm, encmode, section_id, value);
} }
so.depends({type: 'trojan', trojan_ss_enabled: '1'}); so.depends({type: 'trojan', trojan_ss_enabled: '1'});
@ -470,9 +470,9 @@ return view.extend({
so = ss.taboption('field_general', form.Flag, 'tls', _('TLS')); so = ss.taboption('field_general', form.Flag, 'tls', _('TLS'));
so.default = so.disabled; so.default = so.disabled;
so.validate = function(section_id, value) { so.validate = function(section_id, value) {
var type = this.section.getOption('type').formvalue(section_id); const type = this.section.getOption('type').formvalue(section_id);
var tls = this.section.getUIElement(section_id, 'tls').node.querySelector('input'); let tls = this.section.getUIElement(section_id, 'tls').node.querySelector('input');
var tls_alpn = this.section.getUIElement(section_id, 'tls_alpn'); let tls_alpn = this.section.getUIElement(section_id, 'tls_alpn');
// Force enabled // Force enabled
if (['trojan', 'hysteria', 'hysteria2', 'tuic'].includes(type)) { if (['trojan', 'hysteria', 'hysteria2', 'tuic'].includes(type)) {
@ -585,7 +585,7 @@ return view.extend({
so.value('grpc', _('gRPC')); so.value('grpc', _('gRPC'));
so.value('ws', _('WebSocket')); so.value('ws', _('WebSocket'));
so.validate = function(section_id, value) { so.validate = function(section_id, value) {
var type = this.section.getOption('type').formvalue(section_id); const type = this.section.getOption('type').formvalue(section_id);
switch (type) { switch (type) {
case 'vmess': case 'vmess':
@ -793,7 +793,7 @@ return view.extend({
ss.sectiontitle = L.bind(hm.loadDefaultLabel, ss); ss.sectiontitle = L.bind(hm.loadDefaultLabel, ss);
/* Remove idle files start */ /* Remove idle files start */
ss.renderSectionAdd = function(/* ... */) { ss.renderSectionAdd = function(/* ... */) {
var el = hm.renderSectionAdd.apply(this, [prefmt, false].concat(Array.prototype.slice.call(arguments))); let el = hm.renderSectionAdd.apply(this, [prefmt, false].concat(Array.prototype.slice.call(arguments)));
el.appendChild(E('button', { el.appendChild(E('button', {
'class': 'cbi-button cbi-button-add', 'class': 'cbi-button cbi-button-add',
@ -828,7 +828,7 @@ return view.extend({
so = ss.option(form.DummyValue, '_value', _('Value')); so = ss.option(form.DummyValue, '_value', _('Value'));
so.load = function(section_id) { so.load = function(section_id) {
var option = uci.get(data[0], section_id, 'type'); const option = uci.get(data[0], section_id, 'type');
switch (option) { switch (option) {
case 'file': case 'file':
@ -1079,8 +1079,8 @@ return view.extend({
so = ss.option(form.DummyValue, '_value', _('Value')); so = ss.option(form.DummyValue, '_value', _('Value'));
so.load = function(section_id) { so.load = function(section_id) {
var type = uci.get(data[0], section_id, 'type'); const type = uci.get(data[0], section_id, 'type');
var detour = uci.get(data[0], section_id, 'chain_tail_group') || uci.get(data[0], section_id, 'chain_tail'); const detour = uci.get(data[0], section_id, 'chain_tail_group') || uci.get(data[0], section_id, 'chain_tail');
switch (type) { switch (type) {
case 'node': case 'node':
@ -1111,7 +1111,7 @@ return view.extend({
so.load = L.bind(hm.loadNodeLabel, so); so.load = L.bind(hm.loadNodeLabel, so);
so.rmempty = false; so.rmempty = false;
so.validate = function(section_id, value) { so.validate = function(section_id, value) {
var chain_tail = this.section.getUIElement(section_id, 'chain_tail').getValue(); const chain_tail = this.section.getUIElement(section_id, 'chain_tail').getValue();
if (value === chain_tail) if (value === chain_tail)
return _('Expecting: %s').format(_('Different chain head/tail')); return _('Expecting: %s').format(_('Different chain head/tail'));
@ -1126,8 +1126,8 @@ return view.extend({
so.value('', _('-- Please choose --')); so.value('', _('-- Please choose --'));
so.load = L.bind(hm.loadNodeLabel, so); so.load = L.bind(hm.loadNodeLabel, so);
so.validate = function(section_id, value) { so.validate = function(section_id, value) {
var chain_head = this.section.getUIElement(section_id, 'chain_head').getValue(); const chain_head = this.section.getUIElement(section_id, 'chain_head').getValue();
var chain_tail = this.section.getUIElement(section_id, 'chain_tail').getValue(); const chain_tail = this.section.getUIElement(section_id, 'chain_tail').getValue();
value = this.getUIElement(section_id).getValue(); value = this.getUIElement(section_id).getValue();
if (value.includes(chain_head) || value.includes(chain_tail)) if (value.includes(chain_head) || value.includes(chain_tail))
@ -1136,10 +1136,10 @@ return view.extend({
return true; return true;
} }
so.textvalue = function(section_id) { so.textvalue = function(section_id) {
var cvals = this.cfgvalue(section_id); let cvals = this.cfgvalue(section_id);
//alert(Array.prototype.join.call(cvals, ':')); //alert(Array.prototype.join.call(cvals, ':'));
return cvals ? '» ' + cvals.map((cval) => { return cvals ? '» ' + cvals.map((cval) => {
var i = this.keylist.indexOf(cval); let i = this.keylist.indexOf(cval);
return this.vallist[i]; return this.vallist[i];
}).join(' » ') + ' »' : '»'; }).join(' » ') + ' »' : '»';
@ -1159,7 +1159,7 @@ return view.extend({
so.load = L.bind(hm.loadNodeLabel, so); so.load = L.bind(hm.loadNodeLabel, so);
so.rmempty = false; so.rmempty = false;
so.validate = function(section_id, value) { so.validate = function(section_id, value) {
var chain_head = this.section.getUIElement(section_id, 'chain_head').getValue(); const chain_head = this.section.getUIElement(section_id, 'chain_head').getValue();
if (value === chain_head) if (value === chain_head)
return _('Expecting: %s').format(_('Different chain head/tail')); return _('Expecting: %s').format(_('Different chain head/tail'));

View File

@ -7,7 +7,7 @@
'require fchomo as hm'; 'require fchomo as hm';
function parseRulesetLink(uri) { function parseRulesetLink(uri) {
var config, let config,
filefmt = new RegExp(/^(text|yaml|mrs)$/), filefmt = new RegExp(/^(text|yaml|mrs)$/),
filebehav = new RegExp(/^(domain|ipcidr|classical)$/), filebehav = new RegExp(/^(domain|ipcidr|classical)$/),
unuciname = new RegExp(/[^a-zA-Z0-9_]+/, "g"); unuciname = new RegExp(/[^a-zA-Z0-9_]+/, "g");
@ -26,7 +26,7 @@ function parseRulesetLink(uri) {
.replace(/[\s\.-]/g, '_').replace(unuciname, ''); .replace(/[\s\.-]/g, '_').replace(unuciname, '');
if (filefmt.test(format) && filebehav.test(behavior)) { if (filefmt.test(format) && filebehav.test(behavior)) {
var fullpath = (url.username ? url.username + '@' : '') + url.host + url.pathname + (rawquery ? '?' + decodeURIComponent(rawquery) : ''); let fullpath = (url.username ? url.username + '@' : '') + url.host + url.pathname + (rawquery ? '?' + decodeURIComponent(rawquery) : '');
config = { config = {
label: url.hash ? decodeURIComponent(url.hash.slice(1)) : name ? name : null, label: url.hash ? decodeURIComponent(url.hash.slice(1)) : name ? name : null,
type: 'http', type: 'http',
@ -90,13 +90,13 @@ function parseRulesetLink(uri) {
} }
return view.extend({ return view.extend({
load: function() { load() {
return Promise.all([ return Promise.all([
uci.load('fchomo') uci.load('fchomo')
]); ]);
}, },
render: function(data) { render(data) {
let m, s, o; let m, s, o;
m = new form.Map('fchomo', _('Edit ruleset')); m = new form.Map('fchomo', _('Edit ruleset'));
@ -113,7 +113,7 @@ return view.extend({
s.sectiontitle = L.bind(hm.loadDefaultLabel, s); s.sectiontitle = L.bind(hm.loadDefaultLabel, s);
/* Import rule-set links and Remove idle files start */ /* Import rule-set links and Remove idle files start */
s.handleLinkImport = function() { s.handleLinkImport = function() {
var textarea = new ui.Textarea('', { let textarea = new ui.Textarea('', {
'placeholder': 'http(s)://github.com/ACL4SSR/ACL4SSR/raw/refs/heads/master/Clash/Providers/BanAD.yaml?fmt=yaml&behav=classical&rawq=good%3Djob#BanAD\n' + 'placeholder': 'http(s)://github.com/ACL4SSR/ACL4SSR/raw/refs/heads/master/Clash/Providers/BanAD.yaml?fmt=yaml&behav=classical&rawq=good%3Djob#BanAD\n' +
'file:///example.txt?fmt=text&behav=domain&fill=LmNuCg#CN%20TLD\n' + 'file:///example.txt?fmt=text&behav=domain&fill=LmNuCg#CN%20TLD\n' +
'inline://LSAnLmhrJwoK?behav=domain#HK%20TLD\n' 'inline://LSAnLmhrJwoK?behav=domain#HK%20TLD\n'
@ -133,17 +133,17 @@ return view.extend({
E('button', { E('button', {
class: 'btn cbi-button-action', class: 'btn cbi-button-action',
click: ui.createHandlerFn(this, function() { click: ui.createHandlerFn(this, function() {
var input_links = textarea.getValue().trim().split('\n'); let input_links = textarea.getValue().trim().split('\n');
if (input_links && input_links[0]) { if (input_links && input_links[0]) {
/* Remove duplicate lines */ /* Remove duplicate lines */
input_links = input_links.reduce((pre, cur) => input_links = input_links.reduce((pre, cur) =>
(!pre.includes(cur) && pre.push(cur), pre), []); (!pre.includes(cur) && pre.push(cur), pre), []);
var imported_ruleset = 0; let imported_ruleset = 0;
input_links.forEach((l) => { input_links.forEach((l) => {
var config = parseRulesetLink(l); let config = parseRulesetLink(l);
if (config) { if (config) {
var sid = uci.add(data[0], 'ruleset', config.id); let sid = uci.add(data[0], 'ruleset', config.id);
config.id = null; config.id = null;
Object.keys(config).forEach((k) => { Object.keys(config).forEach((k) => {
uci.set(data[0], sid, k, config[k] || ''); uci.set(data[0], sid, k, config[k] || '');
@ -172,7 +172,7 @@ return view.extend({
]) ])
} }
s.renderSectionAdd = function(/* ... */) { s.renderSectionAdd = function(/* ... */) {
var el = hm.renderSectionAdd.apply(this, [prefmt, false].concat(Array.prototype.slice.call(arguments))); let el = hm.renderSectionAdd.apply(this, [prefmt, false].concat(Array.prototype.slice.call(arguments)));
el.appendChild(E('button', { el.appendChild(E('button', {
'class': 'cbi-button cbi-button-add', 'class': 'cbi-button cbi-button-add',
@ -212,7 +212,7 @@ return view.extend({
o.value('mrs', _('Binary file')); o.value('mrs', _('Binary file'));
o.default = 'yaml'; o.default = 'yaml';
o.validate = function(section_id, value) { o.validate = function(section_id, value) {
var behavior = this.section.getUIElement(section_id, 'behavior').getValue(); const behavior = this.section.getUIElement(section_id, 'behavior').getValue();
if (value === 'mrs' && behavior === 'classical') if (value === 'mrs' && behavior === 'classical')
return _('Expecting: %s').format(_('Binary format only supports domain / ipcidr')); return _('Expecting: %s').format(_('Binary format only supports domain / ipcidr'));
@ -220,8 +220,8 @@ return view.extend({
return true; return true;
} }
o.textvalue = function(section_id) { o.textvalue = function(section_id) {
var cval = this.cfgvalue(section_id) || this.default; let cval = this.cfgvalue(section_id) || this.default;
var inline = L.bind(function() { let inline = L.bind(function() {
let cval = this.cfgvalue(section_id) || this.default; let cval = this.cfgvalue(section_id) || this.default;
return (cval === 'inline') ? true : false; return (cval === 'inline') ? true : false;
}, s.getOption('type')); }, s.getOption('type'));
@ -235,7 +235,7 @@ return view.extend({
o.value('ipcidr'); o.value('ipcidr');
o.default = 'classical'; o.default = 'classical';
o.validate = function(section_id, value) { o.validate = function(section_id, value) {
var format = this.section.getUIElement(section_id, 'format').getValue(); const format = this.section.getUIElement(section_id, 'format').getValue();
if (value === 'classical' && format === 'mrs') if (value === 'classical' && format === 'mrs')
return _('Expecting: %s').format(_('Binary format only supports domain / ipcidr')); return _('Expecting: %s').format(_('Binary format only supports domain / ipcidr'));
@ -245,7 +245,7 @@ return view.extend({
o = s.option(form.DummyValue, '_value', _('Value')); o = s.option(form.DummyValue, '_value', _('Value'));
o.load = function(section_id) { o.load = function(section_id) {
var option = uci.get(data[0], section_id, 'type'); const option = uci.get(data[0], section_id, 'type');
switch (option) { switch (option) {
case 'file': case 'file':

View File

@ -8,10 +8,10 @@
'require fchomo as hm'; 'require fchomo as hm';
function handleGenKey(option) { function handleGenKey(option) {
var section_id = this.section.section; const section_id = this.section.section;
var type = this.section.getOption('type').formvalue(section_id); const type = this.section.getOption('type').formvalue(section_id);
var widget = this.map.findElement('id', 'widget.cbid.fchomo.%s.%s'.format(section_id, option)); let widget = this.map.findElement('id', 'widget.cbid.fchomo.%s.%s'.format(section_id, option));
var password, required_method; let password, required_method;
if (option === 'uuid' || option.match(/_uuid/)) if (option === 'uuid' || option.match(/_uuid/))
required_method = 'uuid'; required_method = 'uuid';
@ -44,8 +44,8 @@ function handleGenKey(option) {
const CBIPWGenValue = form.Value.extend({ const CBIPWGenValue = form.Value.extend({
__name__: 'CBI.PWGenValue', __name__: 'CBI.PWGenValue',
renderWidget: function() { renderWidget() {
var node = form.Value.prototype.renderWidget.apply(this, arguments); let node = form.Value.prototype.renderWidget.apply(this, arguments);
(node.querySelector('.control-group') || node).appendChild(E('button', { (node.querySelector('.control-group') || node).appendChild(E('button', {
'class': 'cbi-button cbi-button-add', 'class': 'cbi-button cbi-button-add',
@ -58,16 +58,16 @@ const CBIPWGenValue = form.Value.extend({
}); });
return view.extend({ return view.extend({
load: function() { load() {
return Promise.all([ return Promise.all([
uci.load('fchomo'), uci.load('fchomo'),
hm.getFeatures() hm.getFeatures()
]); ]);
}, },
render: function(data) { render(data) {
var dashboard_repo = uci.get(data[0], 'api', 'dashboard_repo'), const dashboard_repo = uci.get(data[0], 'api', 'dashboard_repo');
features = data[1]; const features = data[1];
let m, s, o; let m, s, o;
@ -210,7 +210,7 @@ return view.extend({
o = s.option(CBIPWGenValue, 'shadowsocks_password', _('Password')); o = s.option(CBIPWGenValue, 'shadowsocks_password', _('Password'));
o.password = true; o.password = true;
o.validate = function(section_id, value) { o.validate = function(section_id, value) {
var encmode = this.section.getOption('shadowsocks_chipher').formvalue(section_id); const encmode = this.section.getOption('shadowsocks_chipher').formvalue(section_id);
return hm.validateShadowsocksPassword.call(this, hm, encmode, section_id, value); return hm.validateShadowsocksPassword.call(this, hm, encmode, section_id, value);
} }
o.depends({type: 'shadowsocks', shadowsocks_chipher: /.+/}); o.depends({type: 'shadowsocks', shadowsocks_chipher: /.+/});
@ -270,9 +270,9 @@ return view.extend({
o = s.option(form.Flag, 'tls', _('TLS')); o = s.option(form.Flag, 'tls', _('TLS'));
o.default = o.disabled; o.default = o.disabled;
o.validate = function(section_id, value) { o.validate = function(section_id, value) {
var type = this.section.getOption('type').formvalue(section_id); const type = this.section.getOption('type').formvalue(section_id);
var tls = this.section.getUIElement(section_id, 'tls').node.querySelector('input'); let tls = this.section.getUIElement(section_id, 'tls').node.querySelector('input');
var tls_alpn = this.section.getUIElement(section_id, 'tls_alpn'); let tls_alpn = this.section.getUIElement(section_id, 'tls_alpn');
// Force enabled // Force enabled
if (['tuic', 'hysteria2'].includes(type)) { if (['tuic', 'hysteria2'].includes(type)) {