};
this.globals = {
- timeout: 3000,
+ timeout: 15000,
resource: '/luci2',
sid: '00000000000000000000000000000000'
};
},
- changes: _luci2.rpc.declare({
+ configs: _luci2.rpc.declare({
+ object: 'uci',
+ method: 'configs',
+ expect: { configs: [ ] }
+ }),
+
+ _changes: _luci2.rpc.declare({
object: 'uci',
method: 'changes',
params: [ 'config' ],
expect: { changes: [ ] }
}),
+ changes: function(config)
+ {
+ if (typeof(config) == 'string')
+ return this._changes(config);
+
+ var configlist;
+ return this.configs().then(function(configs) {
+ _luci2.rpc.batch();
+ configlist = configs;
+
+ for (var i = 0; i < configs.length; i++)
+ _luci2.uci._changes(configs[i]);
+
+ return _luci2.rpc.flush();
+ }).then(function(changes) {
+ var rv = { };
+
+ for (var i = 0; i < configlist.length; i++)
+ if (changes[i].length)
+ rv[configlist[i]] = changes[i];
+
+ return rv;
+ });
+ },
+
commit: _luci2.rpc.declare({
object: 'uci',
method: 'commit',
var net = nets[i] = networks[i];
var dev = net.l3_device || net.l2_device;
if (dev)
- net.device = devs[dev] = { };
+ net.device = devs[dev] || (devs[dev] = { });
}
_luci2.rpc.batch();
for (var dev in devs)
- _luci2.network.listDeviceNamestatus(dev);
+ _luci2.network.getDeviceStatus(dev);
return _luci2.rpc.flush();
}).then(function(devices) {
if (!devs[brm[j]])
{
devs[brm[j]] = { };
- _luci2.network.listDeviceNamestatus(brm[j]);
+ _luci2.network.getDeviceStatus(brm[j]);
}
devs[devices[i]['device']].subdevices[j] = devs[brm[j]];
for (var i = 0; i < interfaces.length; i++)
{
+ if (!interfaces[i].route)
+ continue;
+
for (var j = 0; j < interfaces[i].route.length; j++)
{
var rt = interfaces[i].route[j];
}
}),
- listDeviceNamestatus: _luci2.rpc.declare({
+ getDeviceStatus: _luci2.rpc.declare({
object: 'network.device',
method: 'status',
params: [ 'name' ],
object: 'luci2.network',
method: 'conntrack_count',
expect: { '': { count: 0, limit: 0 } }
+ }),
+
+ listSwitchNames: _luci2.rpc.declare({
+ object: 'luci2.network',
+ method: 'switch_list',
+ expect: { switches: [ ] }
+ }),
+
+ getSwitchInfo: _luci2.rpc.declare({
+ object: 'luci2.network',
+ method: 'switch_info',
+ params: [ 'switch' ],
+ expect: { info: { } },
+ filter: function(data, params) {
+ data['attrs'] = data['switch'];
+ data['vlan_attrs'] = data['vlan'];
+ data['port_attrs'] = data['port'];
+ data['switch'] = params['switch'];
+
+ delete data.vlan;
+ delete data.port;
+
+ return data;
+ }
+ }),
+
+ getSwitchStatus: _luci2.rpc.declare({
+ object: 'luci2.network',
+ method: 'switch_status',
+ params: [ 'switch' ],
+ expect: { ports: [ ] }
+ }),
+
+
+ runPing: _luci2.rpc.declare({
+ object: 'luci2.network',
+ method: 'ping',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
+ }),
+
+ runPing6: _luci2.rpc.declare({
+ object: 'luci2.network',
+ method: 'ping6',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
+ }),
+
+ runTraceroute: _luci2.rpc.declare({
+ object: 'luci2.network',
+ method: 'traceroute',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
+ }),
+
+ runTraceroute6: _luci2.rpc.declare({
+ object: 'luci2.network',
+ method: 'traceroute6',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
+ }),
+
+ runNslookup: _luci2.rpc.declare({
+ object: 'luci2.network',
+ method: 'nslookup',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
+ }),
+
+
+ setUp: _luci2.rpc.declare({
+ object: 'luci2.network',
+ method: 'ifup',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
+ }),
+
+ setDown: _luci2.rpc.declare({
+ object: 'luci2.network',
+ method: 'ifdown',
+ params: [ 'data' ],
+ expect: { '': { code: -1 } }
})
};
}
};
+ this.firewall = {
+ getZoneColor: function(zone)
+ {
+ if ($.isPlainObject(zone))
+ zone = zone.name;
+
+ if (zone == 'lan')
+ return '#90f090';
+ else if (zone == 'wan')
+ return '#f09090';
+
+ for (var i = 0, hash = 0;
+ i < zone.length;
+ hash = zone.charCodeAt(i++) + ((hash << 5) - hash));
+
+ for (var i = 0, color = '#';
+ i < 3;
+ color += ('00' + ((hash >> i++ * 8) & 0xFF).tozoneing(16)).slice(-2));
+
+ return color;
+ },
+
+ findZoneByNetwork: function(network)
+ {
+ var self = this;
+ var zone = undefined;
+
+ return _luci2.uci.foreach('firewall', 'zone', function(z) {
+ if (!z.name || !z.network)
+ return;
+
+ if (!$.isArray(z.network))
+ z.network = z.network.split(/\s+/);
+
+ for (var i = 0; i < z.network.length; i++)
+ {
+ if (z.network[i] == network)
+ {
+ zone = z;
+ break;
+ }
+ }
+ }).then(function() {
+ if (zone)
+ zone.color = self.getZoneColor(zone);
+
+ return zone;
+ });
+ }
+ };
+
this.system = {
getSystemInfo: _luci2.rpc.declare({
object: 'system',
}),
+ testReset: _luci2.rpc.declare({
+ object: 'luci2.system',
+ method: 'reset_test',
+ expect: { supported: false }
+ }),
+
+ startReset: _luci2.rpc.declare({
+ object: 'luci2.system',
+ method: 'reset_start'
+ }),
+
+
performReboot: _luci2.rpc.declare({
object: 'luci2.system',
method: 'reboot'
this.ui = {
+ saveScrollTop: function()
+ {
+ this._scroll_top = $(document).scrollTop();
+ },
+
+ restoreScrollTop: function()
+ {
+ if (typeof(this._scroll_top) == 'undefined')
+ return;
+
+ $(document).scrollTop(this._scroll_top);
+
+ delete this._scroll_top;
+ },
+
loading: function(enable)
{
var win = $(window);
var body = $('body');
- var div = _luci2._modal || (
- _luci2._modal = $('<div />')
+
+ var state = _luci2.ui._loading || (_luci2.ui._loading = {
+ modal: $('<div />')
.addClass('cbi-modal-loader')
.append($('<div />').text(_luci2.tr('Loading data...')))
.appendTo(body)
- );
+ });
if (enable)
{
body.css('padding', 0);
body.css('width', win.width());
body.css('height', win.height());
- div.css('width', win.width());
- div.css('height', win.height());
- div.show();
+ state.modal.css('width', win.width());
+ state.modal.css('height', win.height());
+ state.modal.show();
}
else
{
- div.hide();
+ state.modal.hide();
body.css('overflow', '');
body.css('padding', '');
body.css('width', '');
{
var win = $(window);
var body = $('body');
- var div = _luci2._dialog || (
- _luci2._dialog = $('<div />')
+
+ var state = _luci2.ui._dialog || (_luci2.ui._dialog = {
+ dialog: $('<div />')
.addClass('cbi-modal-dialog')
.append($('<div />')
.append($('<div />')
$(this).parent().parent().parent().hide();
}))))
.appendTo(body)
- );
+ });
if (typeof(options) != 'object')
options = { };
.css('width', '')
.css('height', '');
- _luci2._dialog.hide();
+ state.dialog.hide();
return;
}
- var cnt = div.children().children('div.cbi-modal-dialog-body');
- var ftr = div.children().children('div.cbi-modal-dialog-footer');
+ var cnt = state.dialog.children().children('div.cbi-modal-dialog-body');
+ var ftr = state.dialog.children().children('div.cbi-modal-dialog-footer');
ftr.empty();
.attr('disabled', true));
}
- div.find('div.cbi-modal-dialog-header').text(title);
- div.show();
+ state.dialog.find('div.cbi-modal-dialog-header').text(title);
+ state.dialog.show();
cnt
.css('max-height', Math.floor(win.height() * 0.70) + 'px')
.empty()
.append(content);
- div.children()
- .css('margin-top', -Math.floor(div.children().height() / 2) + 'px');
+ state.dialog.children()
+ .css('margin-top', -Math.floor(state.dialog.children().height() / 2) + 'px');
body.css('overflow', 'hidden');
body.css('padding', 0);
body.css('width', win.width());
body.css('height', win.height());
- div.css('width', win.width());
- div.css('height', win.height());
+ state.dialog.css('width', win.width());
+ state.dialog.css('height', win.height());
},
upload: function(title, content, options)
{
- var form = _luci2._upload || (
- _luci2._upload = $('<form />')
+ var state = _luci2.ui._upload || (_luci2.ui._upload = {
+ form: $('<form />')
.attr('method', 'post')
.attr('action', '/cgi-bin/luci-upload')
.attr('enctype', 'multipart/form-data')
.append($('<p />'))
.append($('<input />')
.attr('type', 'hidden')
- .attr('name', 'sessionid')
- .attr('value', _luci2.globals.sid))
+ .attr('name', 'sessionid'))
.append($('<input />')
.attr('type', 'hidden')
- .attr('name', 'filename')
- .attr('value', options.filename))
+ .attr('name', 'filename'))
.append($('<input />')
.attr('type', 'file')
.attr('name', 'filedata')
.attr('name', 'cbi-fileupload-frame')
.css('width', '1px')
.css('height', '1px')
- .css('visibility', 'hidden'))
- );
+ .css('visibility', 'hidden')),
- var finish = _luci2._upload_finish_cb || (
- _luci2._upload_finish_cb = function(ev) {
+ finish_cb: function(ev) {
$(this).off('load');
var body = (this.contentDocument || this.contentWindow.document).body;
$('<p />').text(_luci2.tr('In case of network problems try uploading the file again.'))
], { style: 'close' });
}
- else if (typeof(ev.data.cb) == 'function')
+ else if (typeof(state.success_cb) == 'function')
{
- ev.data.cb(json);
+ state.success_cb(json);
}
- }
- );
+ },
- var confirm = _luci2._upload_confirm_cb || (
- _luci2._upload_confirm_cb = function() {
- var d = _luci2._upload;
- var f = d.find('.cbi-input-file');
- var b = d.find('.progressbar');
- var p = d.find('p');
+ confirm_cb: function() {
+ var f = state.form.find('.cbi-input-file');
+ var b = state.form.find('.progressbar');
+ var p = state.form.find('p');
if (!f.val())
return;
- d.find('iframe').on('load', { cb: options.success }, finish);
- d.submit();
+ state.form.find('iframe').on('load', state.finish_cb);
+ state.form.submit();
f.hide();
b.show();
p.text(_luci2.tr('File upload in progress …'));
- _luci2._dialog.find('button').prop('disabled', true);
+ state.form.parent().parent().find('button').prop('disabled', true);
}
- );
+ });
+
+ state.form.find('.progressbar').hide();
+ state.form.find('.cbi-input-file').val('').show();
+ state.form.find('p').text(content || _luci2.tr('Select the file to upload and press "%s" to proceed.').format(_luci2.tr('Ok')));
+
+ state.form.find('[name=sessionid]').val(_luci2.globals.sid);
+ state.form.find('[name=filename]').val(options.filename);
- _luci2._upload.find('.progressbar').hide();
- _luci2._upload.find('.cbi-input-file').val('').show();
- _luci2._upload.find('p').text(content || _luci2.tr('Select the file to upload and press "%s" to proceed.').format(_luci2.tr('Ok')));
+ state.success_cb = options.success;
- _luci2.ui.dialog(title || _luci2.tr('File upload'), _luci2._upload, {
+ _luci2.ui.dialog(title || _luci2.tr('File upload'), state.form, {
style: 'confirm',
- confirm: confirm
+ confirm: state.confirm_cb
});
},
login: function(invalid)
{
- if (!_luci2._login_deferred || _luci2._login_deferred.state() != 'pending')
- _luci2._login_deferred = $.Deferred();
-
- /* try to find sid from hash */
- var sid = _luci2.getHash('id');
- if (sid && sid.match(/^[a-f0-9]{32}$/))
- {
- _luci2.globals.sid = sid;
- _luci2.session.isAlive().then(function(access) {
- if (access)
- {
- _luci2.session.startHeartbeat();
- _luci2._login_deferred.resolve();
- }
- else
- {
- _luci2.setHash('id', undefined);
- _luci2.ui.login();
- }
- });
-
- return _luci2._login_deferred;
- }
-
- var form = _luci2._login || (
- _luci2._login = $('<div />')
+ var state = _luci2.ui._login || (_luci2.ui._login = {
+ form: $('<form />')
+ .attr('target', '')
+ .attr('method', 'post')
.append($('<p />')
.addClass('alert-message')
.text(_luci2.tr('Wrong username or password given!')))
.attr('type', 'text')
.attr('name', 'username')
.attr('value', 'root')
- .addClass('cbi-input-text'))))
+ .addClass('cbi-input-text')
+ .keypress(function(ev) {
+ if (ev.which == 10 || ev.which == 13)
+ state.confirm_cb();
+ }))))
.append($('<p />')
.append($('<label />')
.text(_luci2.tr('Password'))
.append($('<input />')
.attr('type', 'password')
.attr('name', 'password')
- .addClass('cbi-input-password'))))
+ .addClass('cbi-input-password')
+ .keypress(function(ev) {
+ if (ev.which == 10 || ev.which == 13)
+ state.confirm_cb();
+ }))))
.append($('<p />')
- .text(_luci2.tr('Enter your username and password above, then click "%s" to proceed.').format(_luci2.tr('Ok'))))
- );
+ .text(_luci2.tr('Enter your username and password above, then click "%s" to proceed.').format(_luci2.tr('Ok')))),
- var response_cb = _luci2._login_response_cb || (
- _luci2._login_response_cb = function(response) {
+ response_cb: function(response) {
if (!response.ubus_rpc_session)
{
_luci2.ui.login(true);
_luci2.setHash('id', _luci2.globals.sid);
_luci2.session.startHeartbeat();
_luci2.ui.dialog(false);
- _luci2._login_deferred.resolve();
+ state.deferred.resolve();
}
- }
- );
+ },
- var confirm_cb = _luci2._login_confirm_cb || (
- _luci2._login_confirm_cb = function() {
- var d = _luci2._login;
- var u = d.find('[name=username]').val();
- var p = d.find('[name=password]').val();
+ confirm_cb: function() {
+ var u = state.form.find('[name=username]').val();
+ var p = state.form.find('[name=password]').val();
if (!u)
return;
);
_luci2.globals.sid = '00000000000000000000000000000000';
- _luci2.session.login(u, p).then(response_cb);
+ _luci2.session.login(u, p).then(state.response_cb);
}
- );
+ });
+
+ if (!state.deferred || state.deferred.state() != 'pending')
+ state.deferred = $.Deferred();
+
+ /* try to find sid from hash */
+ var sid = _luci2.getHash('id');
+ if (sid && sid.match(/^[a-f0-9]{32}$/))
+ {
+ _luci2.globals.sid = sid;
+ _luci2.session.isAlive().then(function(access) {
+ if (access)
+ {
+ _luci2.session.startHeartbeat();
+ state.deferred.resolve();
+ }
+ else
+ {
+ _luci2.setHash('id', undefined);
+ _luci2.ui.login();
+ }
+ });
+
+ return state.deferred;
+ }
if (invalid)
- form.find('.alert-message').show();
+ state.form.find('.alert-message').show();
else
- form.find('.alert-message').hide();
+ state.form.find('.alert-message').hide();
- _luci2.ui.dialog(_luci2.tr('Authorization Required'), form, {
+ _luci2.ui.dialog(_luci2.tr('Authorization Required'), state.form, {
style: 'confirm',
- confirm: confirm_cb
+ confirm: state.confirm_cb
});
- return _luci2._login_deferred;
+ state.form.find('[name=password]').focus();
+
+ return state.deferred;
},
+ cryptPassword: _luci2.rpc.declare({
+ object: 'luci2.ui',
+ method: 'crypt',
+ params: [ 'data' ],
+ expect: { crypt: '' }
+ }),
+
_acl_merge_scope: function(acl_scope, scope)
{
.append(_luci2.globals.mainMenu.render(2, 900));
},
- renderView: function(node)
+ renderView: function()
{
+ var node = arguments[0];
var name = node.view.split(/\//).join('.');
+ var args = [ ];
+
+ for (var i = 1; i < arguments.length; i++)
+ args.push(arguments[i]);
+
+ if (_luci2.globals.currentView)
+ _luci2.globals.currentView.finish();
_luci2.ui.renderViewMenu();
_luci2.setHash('view', node.view);
if (_luci2._views[name] instanceof _luci2.ui.view)
- return _luci2._views[name].render();
+ {
+ _luci2.globals.currentView = _luci2._views[name];
+ return _luci2._views[name].render.apply(_luci2._views[name], args);
+ }
+
+ var url = _luci2.globals.resource + '/view/' + name + '.js';
- return $.ajax(_luci2.globals.resource + '/view/' + name + '.js', {
+ return $.ajax(url, {
method: 'GET',
cache: true,
dataType: 'text'
}).then(function(data) {
try {
- var viewConstructor = (new Function(['L', '$'], 'return ' + data))(_luci2, $);
+ var viewConstructorSource = (
+ '(function(L, $) { ' +
+ 'return %s' +
+ '})(_luci2, $);\n\n' +
+ '//@ sourceURL=%s'
+ ).format(data, url);
+
+ var viewConstructor = eval(viewConstructorSource);
_luci2._views[name] = new viewConstructor({
name: name,
acls: node.write || { }
});
- return _luci2._views[name].render();
+ _luci2.globals.currentView = _luci2._views[name];
+ return _luci2._views[name].render.apply(_luci2._views[name], args);
}
- catch(e) { };
+ catch(e) {
+ alert('Unable to instantiate view "%s": %s'.format(url, e));
+ };
return $.Deferred().resolve();
});
},
+ updateHostname: function()
+ {
+ return _luci2.system.getBoardInfo().then(function(info) {
+ if (info.hostname)
+ $('#hostname').text(info.hostname);
+ });
+ },
+
+ updateChanges: function()
+ {
+ return _luci2.uci.changes().then(function(changes) {
+ var n = 0;
+ var html = '';
+
+ for (var config in changes)
+ {
+ var log = [ ];
+
+ for (var i = 0; i < changes[config].length; i++)
+ {
+ var c = changes[config][i];
+
+ switch (c[0])
+ {
+ case 'order':
+ break;
+
+ case 'remove':
+ if (c.length < 3)
+ log.push('uci delete %s.<del>%s</del>'.format(config, c[1]));
+ else
+ log.push('uci delete %s.%s.<del>%s</del>'.format(config, c[1], c[2]));
+ break;
+
+ case 'rename':
+ if (c.length < 4)
+ log.push('uci rename %s.<ins>%s=<strong>%s</strong></ins>'.format(config, c[1], c[2], c[3]));
+ else
+ log.push('uci rename %s.%s.<ins>%s=<strong>%s</strong></ins>'.format(config, c[1], c[2], c[3], c[4]));
+ break;
+
+ case 'add':
+ log.push('uci add %s <ins>%s</ins> (= <ins><strong>%s</strong></ins>)'.format(config, c[2], c[1]));
+ break;
+
+ case 'list-add':
+ log.push('uci add_list %s.%s.<ins>%s=<strong>%s</strong></ins>'.format(config, c[1], c[2], c[3], c[4]));
+ break;
+
+ case 'list-del':
+ log.push('uci del_list %s.%s.<del>%s=<strong>%s</strong></del>'.format(config, c[1], c[2], c[3], c[4]));
+ break;
+
+ case 'set':
+ if (c.length < 4)
+ log.push('uci set %s.<ins>%s=<strong>%s</strong></ins>'.format(config, c[1], c[2]));
+ else
+ log.push('uci set %s.%s.<ins>%s=<strong>%s</strong></ins>'.format(config, c[1], c[2], c[3], c[4]));
+ break;
+ }
+ }
+
+ html += '<code>/etc/config/%s</code><pre class="uci-changes">%s</pre>'.format(config, log.join('\n'));
+ n += changes[config].length;
+ }
+
+ if (n > 0)
+ $('#changes')
+ .empty()
+ .show()
+ .append($('<a />')
+ .attr('href', '#')
+ .addClass('label')
+ .addClass('notice')
+ .text(_luci2.trcp('Pending configuration changes', '1 change', '%d changes', n).format(n))
+ .click(function(ev) {
+ _luci2.ui.dialog(_luci2.tr('Staged configuration changes'), html, { style: 'close' });
+ ev.preventDefault();
+ }));
+ else
+ $('#changes')
+ .hide();
+ });
+ },
+
init: function()
{
_luci2.ui.loading(true);
$.when(
+ _luci2.ui.updateHostname(),
+ _luci2.ui.updateChanges(),
_luci2.ui.renderMainMenu()
).then(function() {
_luci2.ui.renderView(_luci2.globals.defaultNode).then(function() {
insertInto: function(id) {
return $(id).empty().append(this.render());
+ },
+
+ appendTo: function(id) {
+ return $(id).append(this.render());
}
});
container.append($('<div />').addClass('cbi-map-descr').append(this.description));
var self = this;
+ var args = [ ];
+
+ for (var i = 0; i < arguments.length; i++)
+ args.push(arguments[i]);
+
return this._fetch_template().then(function() {
- return _luci2.deferrable(self.execute());
+ return _luci2.deferrable(self.execute.apply(self, args));
});
+ },
+
+ repeat: function(func, interval)
+ {
+ var self = this;
+
+ if (!self._timeouts)
+ self._timeouts = [ ];
+
+ var index = self._timeouts.length;
+
+ if (typeof(interval) != 'number')
+ interval = 5000;
+
+ var setTimer, runTimer;
+
+ setTimer = function() {
+ if (self._timeouts)
+ self._timeouts[index] = window.setTimeout(runTimer, interval);
+ };
+
+ runTimer = function() {
+ _luci2.deferrable(func.call(self)).then(setTimer, setTimer);
+ };
+
+ runTimer();
+ },
+
+ finish: function()
+ {
+ if ($.isArray(this._timeouts))
+ {
+ for (var i = 0; i < this._timeouts.length; i++)
+ window.clearTimeout(this._timeouts[i]);
+
+ delete this._timeouts;
+ }
}
});
var child = this.firstChildView(nodes[i]);
if (child)
{
- $.extend(node, child);
+ for (var key in child)
+ if (!node.hasOwnProperty(key) && child.hasOwnProperty(key))
+ node[key] = child[key];
+
return node;
}
}
this.ui.devicebadge = AbstractWidget.extend({
render: function()
{
- var dev = this.options.l3_device || this.options.device || '?';
+ var l2dev = this.options.l2_device || this.options.device;
+ var l3dev = this.options.l3_device;
+ var dev = l3dev || l2dev || '?';
var span = document.createElement('span');
span.className = 'ifacebadge';
var type = 'ethernet';
var desc = _luci2.tr('Ethernet device');
- if (this.options.l3_device != this.options.device)
+ if (l3dev != l2dev)
{
type = 'tunnel';
desc = _luci2.tr('Tunnel interface');
}
}
+ validation.i18n('Must be a valid IPv6 address');
return false;
},
};
- var AbstractValue = AbstractWidget.extend({
+ this.cbi.AbstractValue = AbstractWidget.extend({
init: function(name, options)
{
this.name = name;
{
if (typeof(d[i]) == 'string')
dep[d[i]] = true;
- else if (d[i] instanceof AbstractValue)
+ else if (d[i] instanceof _luci2.cbi.AbstractValue)
dep[d[i].name] = true;
}
}
- else if (d instanceof AbstractValue)
+ else if (d instanceof _luci2.cbi.AbstractValue)
{
dep = { };
dep[d.name] = (typeof(v) == 'undefined') ? true : v;
}
});
- this.cbi.CheckboxValue = AbstractValue.extend({
+ this.cbi.CheckboxValue = this.cbi.AbstractValue.extend({
widget: function(sid)
{
var o = this.options;
if (chg)
{
- val = val ? this.options.enabled : this.options.disabled;
-
if (this.options.optional && val == this.options.initial)
this.map.set(uci.config, uci.section, uci.option, undefined);
else
- this.map.set(uci.config, uci.section, uci.option, val);
+ this.map.set(uci.config, uci.section, uci.option, val ? this.options.enabled : this.options.disabled);
}
return chg;
}
});
- this.cbi.InputValue = AbstractValue.extend({
+ this.cbi.InputValue = this.cbi.AbstractValue.extend({
widget: function(sid)
{
var i = $('<input />')
}
});
- this.cbi.PasswordValue = AbstractValue.extend({
+ this.cbi.PasswordValue = this.cbi.AbstractValue.extend({
widget: function(sid)
{
var i = $('<input />')
}
});
- this.cbi.ListValue = AbstractValue.extend({
+ this.cbi.ListValue = this.cbi.AbstractValue.extend({
widget: function(sid)
{
var s = $('<select />');
}
});
- this.cbi.ComboBox = AbstractValue.extend({
+ this.cbi.ComboBox = this.cbi.AbstractValue.extend({
_change: function(ev)
{
var s = ev.target;
}
});
- this.cbi.DummyValue = AbstractValue.extend({
+ this.cbi.DummyValue = this.cbi.AbstractValue.extend({
widget: function(sid)
{
return $('<div />')
}
});
- this.cbi.NetworkList = AbstractValue.extend({
+ this.cbi.NetworkList = this.cbi.AbstractValue.extend({
load: function(sid)
{
var self = this;
if (!self.interfaces)
{
self.interfaces = [ ];
- return _luci2.network.getNetworkStatus(function(ifaces) {
+ return _luci2.network.getNetworkStatus().then(function(ifaces) {
self.interfaces = ifaces;
self = null;
});
type = 'wifi';
desc = _luci2.tr('Wireless Network');
}
- else if (dev.name.indexOf('.') > 0)
+ else if (dev.device.indexOf('.') > 0)
{
type = 'vlan';
desc = _luci2.tr('VLAN interface');
return $('<img />')
.attr('src', _luci2.globals.resource + '/icons/' + type + (dev.up ? '' : '_disabled') + '.png')
- .attr('title', '%s (%s)'.format(desc, dev.name));
+ .attr('title', '%s (%s)'.format(desc, dev.device));
},
widget: function(sid)
var iface = this.interfaces[i];
var badge = $('<span />')
.addClass('ifacebadge')
- .text('%s: '.format(iface.name));
+ .text('%s: '.format(iface['interface']));
- if (iface.subdevices)
- for (var j = 0; j < iface.subdevices.length; j++)
- badge.append(this._device_icon(iface.subdevices[j]));
+ if (iface.device && iface.device.subdevices)
+ for (var j = 0; j < iface.device.subdevices.length; j++)
+ badge.append(this._device_icon(iface.device.subdevices[j]));
else if (iface.device)
badge.append(this._device_icon(iface.device));
else
.append($('<input />')
.attr('name', itype + id)
.attr('type', itype)
- .attr('value', iface.name)
- .prop('checked', !!check[iface.name])
+ .attr('value', iface['interface'])
+ .prop('checked', !!check[iface['interface']])
.addClass('cbi-input-' + itype))
.append(badge))
.appendTo(ul);
});
- var AbstractSection = AbstractWidget.extend({
+ this.cbi.AbstractSection = AbstractWidget.extend({
id: function()
{
var s = [ arguments[0], this.map.uci_package, this.uci_type ];
var w = widget ? new widget(name, options) : null;
- if (!(w instanceof AbstractValue))
+ if (!(w instanceof _luci2.cbi.AbstractValue))
throw 'Widget must be an instance of AbstractValue';
w.section = this;
}
});
- this.cbi.TypedSection = AbstractSection.extend({
+ this.cbi.TypedSection = this.cbi.AbstractSection.extend({
init: function(uci_type, options)
{
this.uci_type = uci_type;
if (addb.prop('disabled') || name === '')
return;
+ _luci2.ui.saveScrollTop();
+
self.active_panel = -1;
self.map.save();
self.add(name);
self.map.redraw();
+
+ _luci2.ui.restoreScrollTop();
},
_remove: function(ev)
var self = ev.data.self;
var sid = ev.data.sid;
+ if (ev.data.index == (self.sections().length - 1))
+ self.active_panel = -1;
+
+ _luci2.ui.saveScrollTop();
+
self.map.save();
self.remove(sid);
self.map.redraw();
+ _luci2.ui.restoreScrollTop();
+
ev.stopPropagation();
},
for (var i = 0; i < this.options.teasers.length; i++)
{
var f = this.options.teasers[i];
- if (f instanceof AbstractValue)
+ if (f instanceof _luci2.cbi.AbstractValue)
tf.push(f);
- else if (typeof(f) == 'string' && this.fields[f] instanceof AbstractValue)
+ else if (typeof(f) == 'string' && this.fields[f] instanceof _luci2.cbi.AbstractValue)
tf.push(this.fields[f]);
}
}
return add;
},
- _render_remove: function(sid)
+ _render_remove: function(sid, index)
{
var text = _luci2.tr('Remove');
var ttip = _luci2.tr('Remove this section');
.addClass('cbi-button')
.addClass('cbi-button-remove')
.val(text).attr('title', ttip)
- .click({ self: this, sid: sid }, this._remove);
+ .click({ self: this, sid: sid, index: index }, this._remove);
},
_render_caption: function(sid)
$('<div />')
.addClass('cbi-section-remove')
.addClass('right')
- .append(this._render_remove(sid))
+ .append(this._render_remove(sid, panel_index))
.appendTo(head);
var body = $('<div />')
deletes: { }
};
- this.active_panel = 0;
+ if (typeof(this.active_panel) == 'undefined')
+ this.active_panel = 0;
var packages = { };
{
var w = widget ? new widget(uci_type, options) : null;
- if (!(w instanceof AbstractSection))
+ if (!(w instanceof _luci2.cbi.AbstractSection))
throw 'Widget must be an instance of AbstractSection';
w.map = this;
_luci2.uci['delete'](c, s, (o === true) ? undefined : o);
}
- return _luci2.rpc.flush();
+ return _luci2.rpc.flush().then(function() {
+ return _luci2.ui.updateChanges();
+ });
}, this));
var self = this;
+ _luci2.ui.saveScrollTop();
_luci2.ui.loading(true);
return this.save().then(send_cb).then(function() {
self = null;
_luci2.ui.loading(false);
- });
- },
-
- dialog: function(id)
- {
- var d = $('<div />');
- var p = $('<p />');
-
- $('<img />')
- .attr('src', _luci2.globals.resource + '/icons/loading.gif')
- .css('vertical-align', 'middle')
- .css('padding-right', '10px')
- .appendTo(p);
-
- p.append(_luci2.tr('Loading data...'));
-
- p.appendTo(d);
- d.appendTo(id);
-
- return d.dialog({
- modal: true,
- draggable: false,
- resizable: false,
- height: 90,
- open: function() {
- $(this).parent().children('.ui-dialog-titlebar').hide();
- }
+ _luci2.ui.restoreScrollTop();
});
},