mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-30 01:52:51 +00:00
ucentral: development update
* update luci theme Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
@@ -1,15 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 Jo-Philipp Wich <jo@mein.io>
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI Simple UI
|
||||
LUCI_DEPENDS:=+luci-base
|
||||
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
|
||||
include ../luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
@@ -1,477 +0,0 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require form';
|
||||
'require rpc';
|
||||
'require uci';
|
||||
'require ui';
|
||||
'require fs';
|
||||
|
||||
var callUciCommit = rpc.declare({
|
||||
object: 'uci',
|
||||
method: 'commit',
|
||||
params: [ 'ucentral', 'network' ]
|
||||
});
|
||||
|
||||
var callLuciSetPassword = rpc.declare({
|
||||
object: 'luci',
|
||||
method: 'setPassword',
|
||||
params: [ 'username', 'password' ],
|
||||
reject: true
|
||||
});
|
||||
|
||||
var callSystemValidateFirmwareImage = rpc.declare({
|
||||
object: 'system',
|
||||
method: 'validate_firmware_image',
|
||||
params: [ 'path' ],
|
||||
reject: true
|
||||
});
|
||||
|
||||
var callSystemBoard = rpc.declare({
|
||||
object: 'system',
|
||||
method: 'board'
|
||||
});
|
||||
|
||||
function parseAddressAndNetmask(ipaddr, netmask) {
|
||||
var m = (ipaddr || '').match(/^(.+)\/(\d+)$/);
|
||||
if (m) {
|
||||
var a = validation.parseIPv4(m[1]),
|
||||
s = network.prefixToMask(m[2]);
|
||||
|
||||
if (a && s)
|
||||
return [ m[1], s ];
|
||||
}
|
||||
else {
|
||||
m = (ipaddr || '').match(/^(.+)\/(.+)$/);
|
||||
|
||||
if (m) {
|
||||
var a = validation.parseIPv4(m[1]),
|
||||
s = network.maskToPrefix(m[2]);
|
||||
|
||||
if (a && s)
|
||||
return [ m[1], network.prefixToMask(s) ];
|
||||
}
|
||||
else {
|
||||
return [ ipaddr, netmask ];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var cbiRichListValue = form.ListValue.extend({
|
||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
||||
var choices = this.transformChoices();
|
||||
var widget = new ui.Dropdown((cfgvalue != null) ? cfgvalue : this.default, choices, {
|
||||
id: this.cbid(section_id),
|
||||
sort: this.keylist,
|
||||
optional: this.optional,
|
||||
select_placeholder: this.select_placeholder || this.placeholder,
|
||||
custom_placeholder: this.custom_placeholder || this.placeholder,
|
||||
validate: L.bind(this.validate, this, section_id),
|
||||
disabled: (this.readonly != null) ? this.readonly : this.map.readonly
|
||||
});
|
||||
|
||||
return widget.render();
|
||||
}
|
||||
});
|
||||
|
||||
var cbiPasswordStrengthIndicator = form.DummyValue.extend({
|
||||
setStrength: function(section_id, password) {
|
||||
var node = this.map.findElement('id', this.cbid(section_id)),
|
||||
segments = node ? node.firstElementChild.childNodes : [],
|
||||
colors = [ '#d44', '#d84', '#ee4', '#4e4' ],
|
||||
labels = [ _('too short', 'Password strength'), _('weak', 'Password strength'), _('medium', 'Password strength'), _('strong', 'Password strength') ],
|
||||
strongRegex = new RegExp('^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$', 'g'),
|
||||
mediumRegex = new RegExp('^(?=.{7,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$', 'g'),
|
||||
enoughRegex = new RegExp('(?=.{6,}).*', 'g'),
|
||||
strength;
|
||||
|
||||
if (strongRegex.test(password))
|
||||
strength = 3;
|
||||
else if (mediumRegex.test(password))
|
||||
strength = 2;
|
||||
else if (enoughRegex.test(password))
|
||||
strength = 1;
|
||||
else
|
||||
strength = 0;
|
||||
|
||||
for (var i = 0; i < segments.length; i++)
|
||||
segments[i].style.background = (i <= strength) ? colors[strength] : '';
|
||||
|
||||
if (node)
|
||||
node.lastElementChild.firstChild.data = labels[strength];
|
||||
},
|
||||
|
||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
||||
return E('div', { 'id': this.cbid(section_id), 'style': 'display:flex' }, [
|
||||
E('div', { 'style': 'align-self:center; display:flex; border:1px solid #aaa; height:.4rem; width:200px; margin:.2rem' }, [
|
||||
E('div', { 'style': 'flex:1 1 25%; border-right:1px solid #aaa' }),
|
||||
E('div', { 'style': 'flex:1 1 25%; border-right:1px solid #aaa' }),
|
||||
E('div', { 'style': 'flex:1 1 25%; border-right:1px solid #aaa' }),
|
||||
E('div', { 'style': 'flex:1 1 25%' })
|
||||
]),
|
||||
E('span', { 'style': 'margin-left:.5rem' }, [ '' ])
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
function showProgress(text, ongoing) {
|
||||
var dlg = ui.showModal(null, [
|
||||
E('p', ongoing ? { 'class': 'spinning' } : {}, [ text ])
|
||||
]);
|
||||
|
||||
dlg.removeChild(dlg.firstElementChild);
|
||||
|
||||
if (!ongoing) {
|
||||
window.setTimeout(function() {
|
||||
ui.hideIndicator('uci-changes');
|
||||
ui.hideModal();
|
||||
}, 750);
|
||||
}
|
||||
}
|
||||
|
||||
var formSystemBoard;
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
uci.load('network'),
|
||||
callSystemBoard().then(function(reply) {
|
||||
formSystemBoard = reply;
|
||||
})
|
||||
]);
|
||||
},
|
||||
|
||||
handleChangePassword: function() {
|
||||
var formdata = { password: {} };
|
||||
var m, s, o;
|
||||
|
||||
m = new form.JSONMap(formdata);
|
||||
s = m.section(form.NamedSection, 'password', 'password');
|
||||
|
||||
o = s.option(form.Value, 'pw1', _('Enter new password'));
|
||||
o.password = true;
|
||||
o.validate = function(section_id, value) {
|
||||
this.section.children.filter(function(oo) { return oo.option == 'strength' })[0].setStrength(section_id, value);
|
||||
return true;
|
||||
};
|
||||
|
||||
o = s.option(cbiPasswordStrengthIndicator, 'strength', ' ');
|
||||
|
||||
o = s.option(form.Value, 'pw2', _('Confirm new password'));
|
||||
o.password = true;
|
||||
o.validate = function(section_id, value) {
|
||||
var other = this.section.children.filter(function(oo) { return oo.option == 'pw1' })[0].formvalue(section_id);
|
||||
|
||||
if (other != value)
|
||||
return _('The given passwords do not match!');
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
return m.render().then(L.bind(function(nodes) {
|
||||
ui.showModal(_('Change Login Password'), [
|
||||
nodes,
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', {
|
||||
'click': ui.hideModal
|
||||
}, [ _('Cancel') ]),
|
||||
E('button', {
|
||||
'class': 'important',
|
||||
'click': ui.createHandlerFn(this, function(m) {
|
||||
return m.save(null, true).then(function() {
|
||||
showProgress(_('Setting login password…'), true);
|
||||
return callLuciSetPassword('root', formdata.password.pw1).then(function() {
|
||||
showProgress(_('Password has been changed.'), false);
|
||||
}).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, _('Unable to change the login password: %s').format(err))
|
||||
});
|
||||
}).catch(function() {
|
||||
var inval = nodes.querySelector('input.cbi-input-invalid');
|
||||
if (inval)
|
||||
inval.focus();
|
||||
});
|
||||
}, m)
|
||||
}, [ 'Change password' ])
|
||||
])
|
||||
]);
|
||||
}, this));
|
||||
},
|
||||
|
||||
|
||||
handleFirmwareFlash: function(ev) {
|
||||
return ui.uploadFile('/tmp/firmware.bin').then(function(res) {
|
||||
showProgress(_('Validating image…'), true);
|
||||
|
||||
return callSystemValidateFirmwareImage('/tmp/firmware.bin');
|
||||
}).then(function(res) {
|
||||
if (!res.valid) {
|
||||
showProgress(_('The uploaded firmware image is invalid!'), false);
|
||||
return L.resolveDefault(fs.remove('/tmp/firmware.bin'));
|
||||
}
|
||||
|
||||
var m, s, o;
|
||||
var formdata = { settings: { keep: res.allow_backup ? '1' : null } };
|
||||
|
||||
m = new form.JSONMap(formdata);
|
||||
s = m.section(form.NamedSection, 'settings', 'settings');
|
||||
|
||||
if (res.allow_backup) {
|
||||
o = s.option(form.Flag, 'keep', _('Keep current system settings over reflash'));
|
||||
}
|
||||
else {
|
||||
o = s.option(form.DummyValue, 'keep');
|
||||
o.default = '<em>%h</em>'.format(_('System settings will be reset to factory defaults.'));
|
||||
o.rawhtml = true;
|
||||
}
|
||||
|
||||
return m.render().then(function(nodes) {
|
||||
ui.showModal('Confirm Firmware Flash', [
|
||||
E('p', [ _('The uploaded file contains a valid firmware image. Press "Continue" below to start the flash process.') ]),
|
||||
nodes,
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', {
|
||||
'click': ui.createHandlerFn({}, function() {
|
||||
return L.resolveDefault(fs.remove('/tmp/firmware.bin')).then(function() {
|
||||
showProgress(_('Upgrade process aborted.'), false);
|
||||
});
|
||||
})
|
||||
}, [ _('Cancel') ]),
|
||||
E('button', {
|
||||
'class': 'cbi-button-negative',
|
||||
'click': ui.createHandlerFn({}, function() {
|
||||
return m.save(null, true).then(function() {
|
||||
var keep = (formdata.settings.keep == '1'),
|
||||
args = (keep ? [] : [ '-n' ]).concat([ '/tmp/firmware.bin' ]);
|
||||
|
||||
fs.exec('/sbin/sysupgrade', args); /* does not return */
|
||||
|
||||
showProgress(E([], [
|
||||
_('The firmware image is flashing now.'),
|
||||
E('br'),
|
||||
E('em', [ _('Do NOT power off the device until the process is complete!') ])
|
||||
]), true);
|
||||
|
||||
window.setTimeout(function() {
|
||||
/* FIXME: clarify default IP / domainname */
|
||||
ui.awaitReconnect.apply(ui, keep ? [ window.location.host ] : [ '192.168.1.1', 'openwrt.lan', 'openap.lan' ]);
|
||||
}, 3000);
|
||||
});
|
||||
})
|
||||
}, [ _('Continue') ])
|
||||
])
|
||||
]);
|
||||
});
|
||||
}).catch(function(err) {
|
||||
showProgress(_('Firmware upload failed.'), false);
|
||||
ui.addNotification(null, _('Unable to upload firmware image: %s').format(err));
|
||||
});
|
||||
},
|
||||
|
||||
handleSettingsReset: function(ev) {
|
||||
ui.showModal(_('Confirm Reset'), [
|
||||
E('p', [ _('Do you really want to reset all system settings?') ]),
|
||||
E('p', [
|
||||
E('em', [ _('Any changes made, including wireless passwords, DHCP reservations, block rules etc. will be erased!') ])
|
||||
]),
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', { 'click': ui.hideModal }, [ _('Cancel') ]),
|
||||
E('button', {
|
||||
'class': 'cbi-button-negative',
|
||||
'click': function() {
|
||||
showProgress(_('Resetting system configuration…'), true);
|
||||
|
||||
fs.exec('/sbin/firstboot', [ '-r', '-y' ]).then(function() {
|
||||
ui.awaitReconnect();
|
||||
}).catch(function(err) {
|
||||
showProgress(_('Reset command failed.'), false);
|
||||
ui.addNotification(null, _('Unable to execute reset command: %s').format(err));
|
||||
});
|
||||
}
|
||||
}, [ _('Reset') ])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
handleReboot: function(ev) {
|
||||
ui.showModal(_('Confirm Reboot'), [
|
||||
E('p', [ _('Do you really want to reboot the device?') ]),
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', { 'click': ui.hideModal }, [ _('Cancel') ]),
|
||||
E('button', {
|
||||
'class': 'important',
|
||||
'click': function() {
|
||||
showProgress(_('Rebooting device…'), true);
|
||||
|
||||
fs.exec('/sbin/reboot').then(function() {
|
||||
ui.awaitReconnect();
|
||||
}).catch(function(err) {
|
||||
showProgress(_('Reboot command failed.'), false);
|
||||
ui.addNotification(null, _('Unable to execute reboot command: %s').format(err));
|
||||
});
|
||||
}
|
||||
}, [ _('Reboot') ])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
handleCertificateUpload: function(formdata, ev) {
|
||||
var m = L.dom.findClassInstance(document.querySelector('.cbi-map'));
|
||||
|
||||
return m.save().then(L.bind(function() {
|
||||
return this.handleApply().then(function() {
|
||||
return ui.uploadFile('/tmp/certs.tar').then(function(res) {
|
||||
showProgress(_('Uploading certificate…'), false);
|
||||
fs.exec('/sbin/certupdate').then(function(res) {
|
||||
if (res.code)
|
||||
ui.addNotification(null, _('Certificate validation failed.'));
|
||||
else
|
||||
showProgress(_('Certificate uploaded successfully.'), false);
|
||||
}).catch(function(err) {
|
||||
ui.addNotification(null, _('Unable to upload certificates.'));
|
||||
});
|
||||
|
||||
return 0;
|
||||
});
|
||||
});
|
||||
}, this));
|
||||
},
|
||||
|
||||
handleSettingsSave: function(formdata, ev) {
|
||||
var m = L.dom.findClassInstance(document.querySelector('.cbi-map'));
|
||||
|
||||
return m.save().then(L.bind(function() {
|
||||
|
||||
var wan = formdata.data.data.wan
|
||||
|
||||
uci.set('network', 'wan', 'proto', wan.proto);
|
||||
uci.set('network', 'wan', 'ipaddr', wan.addr);
|
||||
uci.set('network', 'wan', 'netmask', wan.mask);
|
||||
uci.set('network', 'wan', 'gateway', wan.gateway);
|
||||
uci.set('network', 'wan', 'dns', wan.dns);
|
||||
|
||||
return this.handleApply();
|
||||
}, this));
|
||||
},
|
||||
|
||||
handleApply: function() {
|
||||
var dlg = ui.showModal(null, [ E('em', { 'class': 'spinning' }, [ _('Saving configuration…') ]) ]);
|
||||
dlg.removeChild(dlg.firstElementChild);
|
||||
|
||||
return uci.save().then(function() {
|
||||
return Promise.all([
|
||||
callUciCommit('network'),
|
||||
]);
|
||||
}).catch(function(err) {
|
||||
ui.addNotification(null, [ E('p', [ _('Failed to save configuration: %s').format(err) ]) ])
|
||||
}).finally(function() {
|
||||
ui.hideIndicator('uci-changes');
|
||||
ui.hideModal();
|
||||
});
|
||||
},
|
||||
|
||||
render: function(cert_key) {
|
||||
var m, s, o;
|
||||
|
||||
var addr_wan = parseAddressAndNetmask(
|
||||
uci.get('network', 'wan', 'ipaddr'),
|
||||
uci.get('network', 'wan', 'netmask'),
|
||||
uci.get('network', 'wan', 'gateway'),
|
||||
uci.get('network', 'wan', 'dns'));
|
||||
|
||||
var formdata = {
|
||||
information: {
|
||||
serial: formSystemBoard.hostname,
|
||||
model: formSystemBoard.model,
|
||||
version: formSystemBoard.release["tip-version"],
|
||||
revision: formSystemBoard.release["tip-revision"]
|
||||
},
|
||||
wan: {
|
||||
proto: uci.get('network', 'wan', 'proto'),
|
||||
addr: addr_wan ? addr_wan[0] : null,
|
||||
mask: addr_wan ? addr_wan[1] : null,
|
||||
gateway: addr_wan ? addr_wan[2] : null,
|
||||
dns: addr_wan ? addr_wan[3] : null
|
||||
},
|
||||
maintenance: {},
|
||||
certificates: {redirector: null}
|
||||
};
|
||||
|
||||
m = new form.JSONMap(formdata, _('Setup'));
|
||||
m.tabbed = true;
|
||||
|
||||
s = m.section(form.NamedSection, "information", 'information', _('Information'));
|
||||
o = s.option(form.Value, 'serial', _('Serial'));
|
||||
o.readonly = true;
|
||||
o = s.option(form.Value, 'model', _('Model'));
|
||||
o.readonly = true;
|
||||
o = s.option(form.Value, 'version', _('Release'));
|
||||
o.readonly = true;
|
||||
o = s.option(form.Value, 'revision', _('Revision'));
|
||||
o.readonly = true;
|
||||
|
||||
s = m.section(form.NamedSection, 'wan', 'wan', _('Connectivity'));
|
||||
|
||||
o = s.option(cbiRichListValue, 'proto', "Protocol");
|
||||
o.value('dhcp', E('div', { 'style': 'white-space:normal' }, [
|
||||
E('strong', [ _('Automatic address configuration (DHCP)') ]), E('br'),
|
||||
E('span', { 'class': 'hide-open' })
|
||||
]));
|
||||
|
||||
o.value('static', E('div', { 'style': 'white-space:normal' }, [
|
||||
E('strong', [ _('Static address configuration') ]), E('br'),
|
||||
E('span', { 'class': 'hide-open' })
|
||||
]));
|
||||
|
||||
o = s.option(form.Value, 'addr', _('IP Address'));
|
||||
o.rmempty = false;
|
||||
o.datatype = 'ip4addr("nomask")';
|
||||
o.depends('proto', 'static');
|
||||
|
||||
o = s.option(form.Value, 'mask', _('Netmask'));
|
||||
o.rmempty = false;
|
||||
o.datatype = 'ip4addr("nomask")';
|
||||
o.depends('proto', 'static');
|
||||
|
||||
o = s.option(form.Value, 'gateway', _('Gateway'));
|
||||
o.rmempty = false;
|
||||
o.datatype = 'ip4addr("nomask")';
|
||||
o.depends('proto', 'static');
|
||||
|
||||
o = s.option(form.Value, 'dns', _('Nameserver'));
|
||||
o.rmempty = false;
|
||||
o.datatype = 'ip4addr("nomask")';
|
||||
o.depends('proto', 'static');
|
||||
|
||||
o = s.option(form.Button, 'save', _(''));
|
||||
o.inputtitle = _('Save Settings');
|
||||
o.onclick = ui.createHandlerFn(this, 'handleSettingsSave', m);
|
||||
|
||||
s = m.section(form.NamedSection, 'maintenance', 'maintenance', _('System Maintenance'));
|
||||
|
||||
o = s.option(form.Button, 'upgrade', _('Flash device firmware'));
|
||||
o.inputtitle = _('Upload firmware image…');
|
||||
o.onclick = ui.createHandlerFn(this, 'handleFirmwareFlash');
|
||||
|
||||
o = s.option(form.Button, 'reset', _('Reset system settings'));
|
||||
o.inputtitle = _('Restore system defaults…');
|
||||
o.onclick = ui.createHandlerFn(this, 'handleSettingsReset');
|
||||
|
||||
o = s.option(form.Button, 'reboot', _('Restart device'));
|
||||
o.inputtitle = _('Reboot…');
|
||||
o.onclick = ui.createHandlerFn(this, 'handleReboot');
|
||||
|
||||
s = m.section(form.NamedSection, 'certificates', 'certificates', _('Upgrade Certificates'));
|
||||
|
||||
o = s.option(form.Button, 'upgrade', _('Certificate upload'));
|
||||
o.inputtitle = _('Upload certificate…');
|
||||
o.onclick = ui.createHandlerFn(this, 'handleCertificateUpload', m);
|
||||
|
||||
return m.render();
|
||||
},
|
||||
|
||||
handleSave: null,
|
||||
handleSaveApply: null,
|
||||
handleReset: null
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm /etc/ucentral/redirector.json
|
||||
cd /etc/ucentral/
|
||||
tar xf /tmp/certs.tar
|
||||
/etc/init.d/firstcontact enable
|
||||
/etc/init.d/firstcontact restart
|
||||
|
||||
return 0
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"admin/simple-setup": {
|
||||
"title": "Setup",
|
||||
"order": 10,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "setup"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"luci-mod-simple": {
|
||||
"description": "LuCI simple ui access",
|
||||
"read": {
|
||||
"cgi-io": [ "exec" ],
|
||||
"uci": [ "network", "ucentral" ]
|
||||
},
|
||||
"write": {
|
||||
"cgi-io": [ "upload" ],
|
||||
"file": {
|
||||
"/sbin/firstboot -r -y": [ "exec" ],
|
||||
"/sbin/reboot": [ "exec" ],
|
||||
"/sbin/sysupgrade": [ "exec" ],
|
||||
"/sbin/certupdate": [ "exec" ],
|
||||
"/tmp/certs.tar": [ "write" ],
|
||||
"/tmp/firmware.bin": [ "write" ]
|
||||
},
|
||||
"ubus": {
|
||||
"file": [ "exec", "remove" ],
|
||||
"luci": [ "setPassword" ],
|
||||
"system": [ "validate_firmware_image" ],
|
||||
"uci": [ "commit" ],
|
||||
"system": [ "board" ]
|
||||
},
|
||||
"uci": [ "network", "ucentral" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
#
|
||||
# Copyright (C) 2020 Jo-Philipp Wich <jo@mein.io>
|
||||
# Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io>
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI uCentral theme
|
||||
LUCI_TITLE:=LuCI theme for uCentral
|
||||
LUCI_DEPENDS:=
|
||||
|
||||
include ../luci.mk
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 970 B |
Binary file not shown.
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -1,87 +1,140 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 450 70" style="enable-background:new 0 0 450 70;" xml:space="preserve">
|
||||
viewBox="0 0 251.2 114.2" style="enable-background:new 0 0 251.2 114.2;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st0{fill:#FED206;}
|
||||
.st1{fill:#EB6F53;}
|
||||
.st2{fill:#3BA9B6;}
|
||||
.st3{fill:#414141;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M219.6,43.3C219.5,43.3,219.5,43.3,219.6,43.3c-1.3,0-2.2-1-2.2-2.2c0-0.2,0-0.4,0-0.6
|
||||
c0-11.9-9.7-21.6-21.6-21.6c-0.2,0-0.4,0-0.6,0c-1.2,0-2.2-0.9-2.2-2.1c0-1.2,0.9-2.2,2.1-2.2c0.2,0,0.5,0,0.7,0
|
||||
c14.3,0,25.9,11.6,25.9,25.9c0,0.2,0,0.5,0,0.7C221.7,42.4,220.7,43.3,219.6,43.3z"/>
|
||||
<path class="st1" d="M212.1,43.3C212,43.3,212,43.3,212.1,43.3c-1.3-0.1-2.2-1.1-2.2-2.3c0-0.2,0-0.4,0-0.6
|
||||
c0-7.7-6.3-14.1-14.1-14.1c-0.2,0-0.4,0-0.6,0c-1.2,0.1-2.2-0.9-2.3-2.1c0-1.2,0.9-2.2,2.1-2.3c0.3,0,0.5,0,0.8,0
|
||||
c10.2,0,18.4,8.3,18.4,18.4c0,0.2,0,0.5,0,0.8C214.2,42.4,213.2,43.3,212.1,43.3z"/>
|
||||
<path class="st2" d="M204.3,43.3c-0.1,0-0.1,0-0.2,0c-1.2-0.1-2.1-1.1-2-2.3c0-0.2,0-0.4,0-0.5c0-3.5-2.8-6.3-6.3-6.3
|
||||
c-0.1,0-0.3,0-0.5,0c-1.2,0.1-2.3-0.8-2.3-2c-0.1-1.2,0.8-2.3,2-2.3c0.3,0,0.6,0,0.9,0c5.9,0,10.7,4.8,10.7,10.7c0,0.3,0,0.5,0,0.9
|
||||
C206.4,42.4,205.4,43.3,204.3,43.3z"/>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M104,44.1V28.7h-5.5v-2.8h14.2v2.8h-5.5v15.3H104z"/>
|
||||
<g>
|
||||
<path class="st3" d="M61.9,89.9v-4.7h-1.7v-0.9h4.4v0.9h-1.7v4.7H61.9z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M65.6,89.9v-5.6h3.8v0.9h-2.9v1.4h2.8v0.9h-2.8V89h2.9v0.9H65.6z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M70.7,89.9v-5.6h1V89h2.5v0.9H70.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M74.9,89.9v-5.6h3.8v0.9h-2.9v1.4h2.8v0.9h-2.8V89h2.9v0.9H74.9z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M79.8,87.1c0-1.7,1.3-2.9,2.9-2.9c1.1,0,1.8,0.6,2.2,1.3l-0.8,0.4c-0.3-0.5-0.8-0.8-1.4-0.8
|
||||
c-1.1,0-1.9,0.8-1.9,2c0,1.2,0.8,2,1.9,2c0.6,0,1.1-0.4,1.4-0.8l0.8,0.4c-0.4,0.7-1.1,1.3-2.2,1.3C81.1,90,79.8,88.8,79.8,87.1z
|
||||
"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M85.5,87.1c0-1.7,1.2-2.9,2.9-2.9c1.7,0,2.9,1.2,2.9,2.9S90,90,88.3,90C86.7,90,85.5,88.8,85.5,87.1z
|
||||
M90.2,87.1c0-1.2-0.7-2-1.9-2c-1.1,0-1.9,0.9-1.9,2c0,1.1,0.7,2,1.9,2C89.5,89.1,90.2,88.3,90.2,87.1z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M96.9,89.9v-4.3l-1.7,4.3h-0.4l-1.7-4.3v4.3h-1v-5.6h1.4l1.5,3.8l1.5-3.8h1.4v5.6H96.9z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M103,89.9v-5.6h1v5.6H103z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M109.7,89.9l-2.9-4v4h-1v-5.6h1l2.9,3.9v-3.9h1v5.6H109.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M112.4,89.9v-5.6h3.8v0.9h-2.9v1.4h2.8v0.9h-2.8v2.4H112.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M120.3,89.9l-1.2-2.1h-1v2.1h-1v-5.6h2.5c1.1,0,1.8,0.7,1.8,1.8c0,1-0.7,1.5-1.3,1.6l1.4,2.2H120.3z
|
||||
M120.4,86.1c0-0.5-0.4-0.9-1-0.9h-1.4V87h1.4C120,87,120.4,86.6,120.4,86.1z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M126.6,89.9l-0.4-1.1h-2.6l-0.4,1.1h-1.1l2.2-5.6h1.2l2.2,5.6H126.6z M124.9,85.3l-1,2.7h2L124.9,85.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M131.4,89.9v-5.6h2.1c1.1,0,1.7,0.8,1.7,1.6c0,0.9-0.6,1.6-1.7,1.6h-1.6v2.3H131.4z M134.7,86
|
||||
c0-0.7-0.5-1.2-1.2-1.2h-1.6v2.4h1.6C134.2,87.2,134.7,86.6,134.7,86z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M139.4,89.9l-1.6-2.3h-1.2v2.3h-0.5v-5.6h2.1c1,0,1.7,0.6,1.7,1.6c0,1-0.7,1.6-1.6,1.6l1.6,2.3H139.4z
|
||||
M139.4,86c0-0.7-0.5-1.2-1.2-1.2h-1.6v2.4h1.6C138.9,87.2,139.4,86.7,139.4,86z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M141.2,87.1c0-1.6,1.1-2.9,2.7-2.9c1.6,0,2.7,1.3,2.7,2.9c0,1.6-1.1,2.9-2.7,2.9
|
||||
C142.3,90,141.2,88.8,141.2,87.1z M146.1,87.1c0-1.4-0.9-2.5-2.2-2.5c-1.4,0-2.2,1-2.2,2.5c0,1.4,0.9,2.5,2.2,2.5
|
||||
C145.2,89.6,146.1,88.5,146.1,87.1z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M147,89.3l0.3-0.4c0.3,0.3,0.6,0.6,1.1,0.6c0.8,0,1.2-0.5,1.2-1.3v-4h0.5v4c0,1.2-0.8,1.7-1.7,1.7
|
||||
C147.9,90,147.4,89.8,147,89.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M151.8,89.9v-5.6h3.5v0.4h-3.1v2.1h3v0.4h-3v2.2h3.1v0.4H151.8z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M156.3,87.1c0-1.7,1.3-2.9,2.8-2.9c0.9,0,1.6,0.4,2,1l-0.4,0.3c-0.4-0.5-1-0.8-1.6-0.8
|
||||
c-1.3,0-2.3,1-2.3,2.5c0,1.4,1,2.5,2.3,2.5c0.7,0,1.3-0.3,1.6-0.8l0.4,0.3c-0.5,0.6-1.2,1-2,1C157.5,90,156.3,88.8,156.3,87.1z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M163.5,89.9v-5.2h-1.8v-0.4h4.1v0.4H164v5.2H163.5z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M116.2,44.1V25.9h12.4v2.8h-9.2v4.7h9.1v2.8h-9.1v5.1h9.2v2.8H116.2z"/>
|
||||
<polygon class="st3" points="33.7,86.5 41.2,79 48.6,86.5 49.8,86.5 41.2,77.9 32.6,86.5 "/>
|
||||
<polygon class="st3" points="48.6,87.8 41.2,95.2 33.7,87.8 32.6,87.8 41.2,96.4 49.8,87.8 "/>
|
||||
<polygon class="st3" points="40.3,86.5 47.8,79 55.3,86.5 56.4,86.5 47.8,77.9 39.2,86.5 "/>
|
||||
<polygon class="st3" points="55.3,87.8 47.8,95.2 40.3,87.8 39.2,87.8 47.8,96.4 56.4,87.8 "/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M132.5,44.1V25.9h3.2v15.3h8v2.8H132.5z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M146.4,44.1V25.9h12.4v2.8h-9.2v4.7h9.1v2.8h-9.1v5.1h9.2v2.8H146.4z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M162.1,35c0-5.6,4.2-9.4,9.5-9.4c3.6,0,5.9,1.9,7.3,4.1l-2.7,1.4c-0.9-1.5-2.6-2.6-4.6-2.6
|
||||
c-3.6,0-6.3,2.7-6.3,6.6c0,3.8,2.7,6.6,6.3,6.6c1.9,0,3.7-1.1,4.6-2.6l2.7,1.4c-1.4,2.2-3.6,4.1-7.3,4.1
|
||||
C166.3,44.4,162.1,40.6,162.1,35z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M180.6,35c0-5.4,3.8-9.4,9.3-9.4c5.4,0,9.3,4,9.3,9.4s-3.9,9.4-9.3,9.4C184.4,44.4,180.6,40.4,180.6,35z
|
||||
M195.8,35c0-3.8-2.4-6.6-6-6.6c-3.7,0-6,2.8-6,6.6c0,3.7,2.3,6.6,6,6.6C193.5,41.6,195.8,38.7,195.8,35z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M217.7,44.1v-14l-5.5,14h-1.4l-5.6-14v14H202V25.9h4.5l5,12.5l4.9-12.5h4.5v18.1H217.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M237.5,44.1V25.9h3.2v18.1H237.5z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M259,44.1l-9.5-13v13h-3.2V25.9h3.3l9.3,12.6V25.9h3.2v18.1H259z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M267.8,44.1V25.9h12.4v2.8H271v4.7h9.1v2.8H271v7.9H267.8z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M293.4,44.1l-4-6.8h-3.2v6.8H283V25.9h8c3.6,0,6,2.3,6,5.7c0,3.2-2.1,5-4.3,5.3l4.5,7.1H293.4z M293.7,31.6
|
||||
c0-1.7-1.3-2.9-3.1-2.9h-4.4v5.8h4.4C292.4,34.5,293.7,33.3,293.7,31.6z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M313.7,44.1l-1.3-3.5h-8.3l-1.3,3.5h-3.6l7.1-18.1h4l7.1,18.1H313.7z M308.2,29.1l-3.3,8.7h6.5L308.2,29.1z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M329.4,44.1V25.9h6.8c3.5,0,5.5,2.4,5.5,5.3c0,2.9-2,5.3-5.5,5.3h-5.2v7.5H329.4z M340,31.2
|
||||
c0-2.3-1.6-3.9-4-3.9h-5.1v7.8h5.1C338.5,35.1,340,33.5,340,31.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M355.4,44.1l-5.1-7.5h-4v7.5h-1.6V25.9h6.8c3.1,0,5.5,2,5.5,5.3c0,3.3-2.3,5.1-5,5.2l5.2,7.6H355.4z
|
||||
M355.4,31.2c0-2.3-1.6-3.9-4-3.9h-5.1v7.8h5.1C353.8,35.1,355.4,33.5,355.4,31.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M361.1,35c0-5.3,3.5-9.4,8.8-9.4c5.3,0,8.8,4.1,8.8,9.4c0,5.3-3.5,9.4-8.8,9.4
|
||||
C364.6,44.4,361.1,40.3,361.1,35z M377.1,35c0-4.6-2.8-8-7.2-8c-4.4,0-7.2,3.4-7.2,8c0,4.6,2.8,8,7.2,8
|
||||
C374.3,43,377.1,39.6,377.1,35z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M380,42.2l1-1.2c0.8,1.1,1.9,2,3.6,2c2.5,0,4-1.7,4-4.2V25.9h1.6v12.9c0,3.8-2.5,5.6-5.5,5.6
|
||||
C382.7,44.4,381.2,43.7,380,42.2z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M395.6,44.1V25.9h11.5v1.4h-10V34h9.8v1.4h-9.8v7.2h10v1.4H395.6z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M410.1,35c0-5.6,4.1-9.4,9.2-9.4c2.9,0,5.1,1.3,6.6,3.2l-1.3,0.8c-1.1-1.6-3.1-2.6-5.3-2.6
|
||||
c-4.2,0-7.6,3.2-7.6,8c0,4.7,3.3,8,7.6,8c2.2,0,4.2-1.1,5.3-2.6l1.3,0.8c-1.6,2-3.8,3.2-6.6,3.2C414.1,44.4,410.1,40.6,410.1,35z
|
||||
"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M433.5,44.1V27.3h-5.9v-1.4H441v1.4h-5.9v16.7H433.5z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<polygon class="st0" points="12.7,32.9 36.9,8.7 61.1,32.9 64.7,32.9 36.9,5 9,32.9 "/>
|
||||
<polygon class="st0" points="61.1,37.1 36.9,61.3 12.7,37.1 9,37.1 36.9,65 64.7,37.1 "/>
|
||||
<polygon class="st0" points="34.2,32.9 58.4,8.7 82.6,32.9 86.3,32.9 58.4,5 30.5,32.9 "/>
|
||||
<polygon class="st0" points="82.6,37.1 58.4,61.3 34.2,37.1 30.5,37.1 58.4,65 86.3,37.1 "/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st3" d="M51.2,41.3c2,1.1,3.6,2.6,4.7,4.5c1.1,1.9,1.7,4,1.7,6.4c0,2.3-0.6,4.5-1.7,6.4c-1.1,1.9-2.7,3.4-4.7,4.6
|
||||
c-2,1.1-4.2,1.7-6.6,1.7c-2.4,0-4.6-0.6-6.6-1.7c-2-1.1-3.6-2.6-4.7-4.6c-1.1-1.9-1.7-4.1-1.7-6.4c0-2.3,0.6-4.5,1.7-6.4
|
||||
c1.1-1.9,2.7-3.4,4.7-4.5c2-1.1,4.2-1.6,6.6-1.6C47,39.6,49.2,40.2,51.2,41.3z M40.5,44.9c-1.3,0.7-2.3,1.7-3,3
|
||||
c-0.7,1.3-1.1,2.7-1.1,4.2s0.4,3,1.1,4.2c0.8,1.3,1.8,2.3,3,3c1.3,0.7,2.7,1.1,4.1,1.1c1.5,0,2.8-0.4,4.1-1.1c1.3-0.7,2.3-1.8,3-3
|
||||
c0.7-1.3,1.1-2.7,1.1-4.2s-0.4-2.9-1.1-4.2c-0.7-1.3-1.7-2.3-3-3c-1.3-0.7-2.6-1.1-4.1-1.1C43.2,43.8,41.8,44.2,40.5,44.9z"/>
|
||||
<path class="st3" d="M76.9,46.8c1.3,0.8,2.4,1.9,3.1,3.4c0.7,1.4,1.1,3.1,1.1,5c0,1.9-0.4,3.5-1.1,4.9c-0.7,1.4-1.8,2.5-3.1,3.3
|
||||
c-1.3,0.8-2.9,1.2-4.6,1.2c-1.4,0-2.6-0.3-3.7-0.8c-1.1-0.5-2-1.3-2.7-2.4v9.8h-4.6V45.7H66v3.1c0.7-1.1,1.5-1.8,2.6-2.4
|
||||
c1.1-0.5,2.3-0.8,3.7-0.8C74,45.6,75.6,46,76.9,46.8z M75.1,59.1c1-1.1,1.5-2.4,1.5-4.1c0-1.7-0.5-3-1.5-4.1
|
||||
c-1-1.1-2.2-1.6-3.8-1.6c-1.6,0-2.8,0.5-3.8,1.6c-1,1-1.5,2.4-1.5,4.1c0,1.7,0.5,3,1.5,4.1c1,1.1,2.3,1.6,3.8,1.6
|
||||
C72.8,60.7,74.1,60.2,75.1,59.1z"/>
|
||||
<path class="st3" d="M99.3,48.1c1.5,1.7,2.3,4.1,2.3,7.2c0,0.6,0,1.1,0,1.4H87.7c0.3,1.3,0.9,2.4,1.9,3.1c0.9,0.8,2.1,1.1,3.5,1.1
|
||||
c1,0,1.9-0.2,2.7-0.5c0.9-0.4,1.6-0.9,2.3-1.6l2.5,2.6c-0.9,1-2.1,1.8-3.4,2.4c-1.3,0.6-2.8,0.8-4.5,0.8c-1.9,0-3.6-0.4-5.1-1.2
|
||||
c-1.5-0.8-2.6-1.9-3.4-3.3c-0.8-1.4-1.2-3.1-1.2-5c0-1.9,0.4-3.5,1.2-5c0.8-1.4,1.9-2.6,3.4-3.4c1.4-0.8,3.1-1.2,4.9-1.2
|
||||
C95.5,45.6,97.8,46.4,99.3,48.1z M97.4,53.6c0-1.4-0.5-2.5-1.4-3.3c-0.9-0.8-2-1.2-3.4-1.2c-1.3,0-2.4,0.4-3.3,1.2
|
||||
c-0.9,0.8-1.5,1.9-1.7,3.3H97.4z"/>
|
||||
<path class="st3" d="M121.5,47.5c1.2,1.3,1.9,3.1,1.9,5.3v11.7h-4.6V54.1c0-1.3-0.4-2.3-1.1-3.1c-0.7-0.8-1.8-1.1-3-1.1
|
||||
c-1.5,0-2.7,0.5-3.6,1.5s-1.3,2.3-1.3,3.8v9.2h-4.5V45.7h4.5v3.5c1.3-2.4,3.5-3.6,6.7-3.7C118.5,45.5,120.2,46.2,121.5,47.5z"/>
|
||||
<path class="st3" d="M156.5,39.9h4.9l-8.3,24.5h-4.9l-5.6-18.6l-5.7,18.6h-4.8l-8.3-24.5h5l5.8,19.4l5.7-19.4h4.6l5.8,19.5
|
||||
L156.5,39.9z"/>
|
||||
<path class="st3" d="M168,38.4c0.5,0.5,0.7,1.2,0.7,2c0,0.8-0.2,1.4-0.7,1.9c-0.5,0.5-1.1,0.8-1.9,0.8c-0.7,0-1.4-0.3-1.9-0.8
|
||||
c-0.5-0.5-0.7-1.2-0.7-1.9c0-0.8,0.2-1.4,0.7-2c0.5-0.5,1.1-0.8,1.9-0.8C166.9,37.7,167.6,37.9,168,38.4z M164,45.7h4.5v18.7H164
|
||||
V45.7z"/>
|
||||
<path class="st3" d="M174,39.9h16.9l0,4.1h-12.2v6.6h11.1v4.1h-11.1v9.7H174V39.9z"/>
|
||||
<path class="st3" d="M197.9,38.4c0.5,0.5,0.7,1.2,0.7,2c0,0.8-0.2,1.4-0.7,1.9c-0.5,0.5-1.1,0.8-1.9,0.8c-0.7,0-1.4-0.3-1.9-0.8
|
||||
c-0.5-0.5-0.7-1.2-0.7-1.9c0-0.8,0.2-1.4,0.7-2c0.5-0.5,1.1-0.8,1.9-0.8C196.8,37.7,197.4,37.9,197.9,38.4z M193.8,45.7h4.5v18.7
|
||||
h-4.5V45.7z"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 7.3 KiB |
@@ -1,16 +1,13 @@
|
||||
<%#
|
||||
Copyright 2020 Jo-Philipp Wich <jo@mein.io>
|
||||
Copyright 2021 Jo-Philipp Wich <jo@mein.io>
|
||||
Licensed to the public under the Apache License 2.0.
|
||||
-%>
|
||||
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="luci">
|
||||
<% local ver = require "luci.version" -%>
|
||||
Powered by <%= ver.luciname %> (<%= ver.luciversion %>)
|
||||
</p>
|
||||
<script type="text/javascript">L.require('menu-ucentral')</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<%#
|
||||
Copyright 2020 Jo-Philipp Wich <jo@mein.io>
|
||||
Copyright 2021 Jo-Philipp Wich <jo@mein.io>
|
||||
Licensed to the public under the Apache License 2.0.
|
||||
-%>
|
||||
|
||||
@@ -17,182 +17,21 @@
|
||||
|
||||
http.prepare_content("text/html; charset=UTF-8")
|
||||
-%>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="<%=luci.i18n.context.lang%>">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="Content-Script-Type" content="text/javascript" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="<%=media%>/cascade.css" />
|
||||
<link rel="icon" href="<%=media%>/favicon.png" type="image/png" />
|
||||
<link rel="icon" href="<%=media%>/logo.svg" type="image/svg+xml" />
|
||||
<script type="text/javascript" src="<%=url('admin/translations', luci.i18n.context.lang)%><%# ?v=PKG_VERSION %>"></script>
|
||||
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
(function() {
|
||||
function get_children(node) {
|
||||
var children = [];
|
||||
|
||||
for (var k in node.children) {
|
||||
if (!node.children.hasOwnProperty(k))
|
||||
continue;
|
||||
|
||||
if (!node.children[k].satisfied)
|
||||
continue;
|
||||
|
||||
if (!node.children[k].hasOwnProperty('title'))
|
||||
continue;
|
||||
|
||||
children.push(Object.assign(node.children[k], { name: k }));
|
||||
}
|
||||
|
||||
return children.sort(function(a, b) {
|
||||
return ((a.order || 1000) - (b.order || 1000));
|
||||
});
|
||||
}
|
||||
|
||||
function handle_mainmenu_expand(ev) {
|
||||
var a = ev.target, ul1 = a.parentNode.parentNode, ul2 = a.nextElementSibling;
|
||||
|
||||
document.querySelectorAll('ul.mainmenu.l1 > li.active').forEach(function(li) {
|
||||
if (li !== a.parentNode)
|
||||
li.classList.remove('active');
|
||||
});
|
||||
|
||||
if (!ul2)
|
||||
return;
|
||||
|
||||
if (ul2.parentNode.offsetLeft + ul2.offsetWidth <= ul1.offsetLeft + ul1.offsetWidth)
|
||||
ul2.classList.add('align-left');
|
||||
|
||||
ul1.classList.add('active');
|
||||
a.parentNode.classList.add('active');
|
||||
a.blur();
|
||||
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
}
|
||||
|
||||
function render_mainmenu(tree, url, level) {
|
||||
var l = (level || 0) + 1,
|
||||
ul = E('ul', { 'class': 'mainmenu l%d'.format(l) }),
|
||||
children = get_children(tree);
|
||||
|
||||
if (children.length == 0 || l > 2)
|
||||
return E([]);
|
||||
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var isActive = (L.env.dispatchpath[l] == children[i].name),
|
||||
activeClass = 'mainmenu-item-%s%s'.format(children[i].name, isActive ? ' selected' : '');
|
||||
|
||||
ul.appendChild(E('li', { 'class': activeClass }, [
|
||||
E('a', {
|
||||
'href': L.url(url, children[i].name),
|
||||
'click': (l == 1) ? handle_mainmenu_expand : null,
|
||||
}, [ _(children[i].title) ]),
|
||||
render_mainmenu(children[i], url + '/' + children[i].name, l)
|
||||
]));
|
||||
}
|
||||
|
||||
if (l == 1) {
|
||||
var container = document.querySelector('#mainmenu');
|
||||
|
||||
container.firstElementChild.appendChild(ul);
|
||||
container.style.display = '';
|
||||
}
|
||||
|
||||
return ul;
|
||||
}
|
||||
|
||||
function render_modemenu(tree) {
|
||||
var menu = document.querySelector('#modemenu'),
|
||||
children = get_children(tree);
|
||||
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var isActive = (L.env.requestpath.length ? children[i].name == L.env.requestpath[0] : i == 0);
|
||||
|
||||
if (i > 0)
|
||||
menu.appendChild(E([], ['\u00a0|\u00a0']));
|
||||
|
||||
menu.appendChild(E('div', { 'class': isActive ? 'active' : null }, [
|
||||
E('a', { 'href': L.url(children[i].name) }, [ _(children[i].title) ])
|
||||
]));
|
||||
|
||||
if (isActive)
|
||||
render_mainmenu(children[i], children[i].name);
|
||||
}
|
||||
|
||||
if (menu.children.length > 1)
|
||||
menu.style.display = '';
|
||||
}
|
||||
|
||||
function render_tabmenu(tree, url, level) {
|
||||
var container = document.querySelector('#tabmenu'),
|
||||
l = (level || 0) + 1,
|
||||
ul = E('ul', { 'class': 'cbi-tabmenu' }),
|
||||
children = get_children(tree),
|
||||
activeNode = null;
|
||||
|
||||
if (children.length == 0)
|
||||
return E([]);
|
||||
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var isActive = (L.env.dispatchpath[l + 2] == children[i].name),
|
||||
activeClass = isActive ? ' cbi-tab' : '',
|
||||
className = 'tabmenu-item-%s %s'.format(children[i].name, activeClass);
|
||||
|
||||
ul.appendChild(E('li', { 'class': className }, [
|
||||
E('a', { 'href': L.url(url, children[i].name) }, [ _(children[i].title) ] )
|
||||
]));
|
||||
|
||||
if (isActive)
|
||||
activeNode = children[i];
|
||||
}
|
||||
|
||||
container.appendChild(ul);
|
||||
container.style.display = '';
|
||||
|
||||
if (activeNode)
|
||||
container.appendChild(render_tabmenu(activeNode, url + '/' + activeNode.name, l));
|
||||
|
||||
return ul;
|
||||
}
|
||||
|
||||
function toggle_sidebar(ev) {
|
||||
var btn = ev.currentTarget,
|
||||
bar = document.querySelector('#mainmenu');
|
||||
|
||||
if (btn.classList.contains('active')) {
|
||||
btn.classList.remove('active');
|
||||
bar.classList.remove('active');
|
||||
}
|
||||
else {
|
||||
btn.classList.add('active');
|
||||
bar.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('luci-loaded', function(ev) {
|
||||
var tree = <%= luci.http.write_json(luci.dispatcher.menu_json() or {}) %>,
|
||||
node = tree,
|
||||
url = '';
|
||||
|
||||
render_modemenu(tree);
|
||||
|
||||
if (L.env.dispatchpath.length >= 3) {
|
||||
for (var i = 0; i < 3 && node; i++) {
|
||||
node = node.children[L.env.dispatchpath[i]];
|
||||
url = url + (url ? '/' : '') + L.env.dispatchpath[i];
|
||||
}
|
||||
|
||||
if (node)
|
||||
render_tabmenu(node, url);
|
||||
}
|
||||
|
||||
document.querySelector('#menubar > .navigation').addEventListener('click', toggle_sidebar);
|
||||
});
|
||||
})();
|
||||
//]]></script>
|
||||
<title><%=striptags( (boardinfo.hostname or "?") .. ( (node and node.title) and ' - ' .. translate(node.title) or '')) %> - LuCI</title>
|
||||
<% if css then %><style title="text/css">
|
||||
<%= css %>
|
||||
</style>
|
||||
<% end -%>
|
||||
</head>
|
||||
<body class="lang_<%=luci.i18n.context.lang%>" data-page="<%= pcdata(path) %>">
|
||||
|
||||
@@ -201,35 +40,28 @@
|
||||
<span id="skiplink2"><a href="#content"><%:Skip to content%></a></span>
|
||||
</p>
|
||||
|
||||
<div id="menubar">
|
||||
<h2 class="navigation"><a id="navigation" name="navigation"><%:Navigation%></a></h2>
|
||||
|
||||
<span class="hostname"><%=(boardinfo.hostname or "?")%></span>
|
||||
<span class="distversion"><%=ver.distversion%></span>
|
||||
<span id="indicators">
|
||||
<span id="xhr_poll_status" style="display:none" onclick="XHR.running() ? XHR.halt() : XHR.run()">
|
||||
<span id="xhr_poll_status_on" style="display:none"><%:Refreshing%></span>
|
||||
<span id="xhr_poll_status_off" style="display:none"><%:Paused%></span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="modemenu" style="display:none"></div>
|
||||
|
||||
<div id="maincontainer">
|
||||
<div id="mainmenu" style="display:none">
|
||||
<div></div>
|
||||
<div id="page">
|
||||
<div id="menubar">
|
||||
<h2 class="navigation" style="visibility:hidden"><a id="navigation" name="navigation"><%:Navigation%></a></h2>
|
||||
<img src="<%=media%>/logo.svg" />
|
||||
<span id="indicators"></span>
|
||||
</div>
|
||||
|
||||
<div id="maincontent">
|
||||
<%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") and category ~= "failsafe" and path ~= "admin-system-admin-password" then -%>
|
||||
<div class="alert-message warning">
|
||||
<h4><%:No password set!%></h4>
|
||||
<p><%:There is no password set on this router. Please configure a root password to protect the web interface and enable SSH.%></p>
|
||||
<% if disp.lookup("admin/system/admin") then %>
|
||||
<div class="right"><a class="btn" href="<%=url("admin/system/admin")%>"><%:Go to password configuration...%></a></div>
|
||||
<% end %>
|
||||
</div>
|
||||
<%- end -%>
|
||||
<div id="modemenu" style="display:none"></div>
|
||||
|
||||
<div id="tabmenu" style="display:none"></div>
|
||||
<div id="maincontainer">
|
||||
<div id="mainmenu"></div>
|
||||
|
||||
<div id="maincontent">
|
||||
<%- if luci.sys.process.info("uid") == 0 and luci.sys.user.getuser("root") and not luci.sys.user.getpasswd("root") and path ~= "admin-system-admin-password" then -%>
|
||||
<div class="alert-message warning">
|
||||
<h4><%:No password set!%></h4>
|
||||
<p><%:There is no password set on this router. Please configure a root password to protect the web interface.%></p>
|
||||
<% if disp.lookup("admin/system/admin") then %>
|
||||
<div class="right"><a class="btn" href="<%=url("admin/system/admin")%>"><%:Go to password configuration...%></a></div>
|
||||
<% end %>
|
||||
</div>
|
||||
<%- end -%>
|
||||
|
||||
<div id="tabmenu" style="display:none"></div>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ "$PKG_UPGRADE" != 1 ]; then
|
||||
uci get luci.themes.uCentral >/dev/null 2>&1 || \
|
||||
uci batch <<-EOF
|
||||
set luci.themes.ucentral=/luci-static/ucentral
|
||||
set luci.themes.uCentral=/luci-static/ucentral
|
||||
set luci.main.mediaurlbase=/luci-static/ucentral
|
||||
commit luci
|
||||
EOF
|
||||
|
||||
Reference in New Issue
Block a user