X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fluci2%2Fui.git;a=blobdiff_plain;f=luci2%2Fhtdocs%2Fluci2%2Fluci2.js;h=ffa58ea0de2d8ceedf9c119a711c57624940caab;hp=a074b44a89dc40d760664c6692fa1b03e244181b;hb=b7e255f6d02885cb0d093812e32f4632734d4b6f;hpb=19990b36ae3f7ca9135934e7ecc92b6aa172480f diff --git a/luci2/htdocs/luci2/luci2.js b/luci2/htdocs/luci2/luci2.js index a074b44..ffa58ea 100644 --- a/luci2/htdocs/luci2/luci2.js +++ b/luci2/htdocs/luci2/luci2.js @@ -387,7 +387,7 @@ function LuCI2() }; this.globals = { - timeout: 3000, + timeout: 15000, resource: '/luci2', sid: '00000000000000000000000000000000' }; @@ -584,13 +584,44 @@ function LuCI2() }, - 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', @@ -757,13 +788,13 @@ function LuCI2() 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) { @@ -786,7 +817,7 @@ function LuCI2() 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]]; @@ -836,6 +867,9 @@ function LuCI2() 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]; @@ -897,7 +931,7 @@ function LuCI2() } }), - listDeviceNamestatus: _luci2.rpc.declare({ + getDeviceStatus: _luci2.rpc.declare({ object: 'network.device', method: 'status', params: [ 'name' ], @@ -912,6 +946,73 @@ function LuCI2() 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 } } }) }; @@ -1292,6 +1393,18 @@ function LuCI2() }), + 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' @@ -1429,7 +1542,7 @@ function LuCI2() startHeartbeat: function() { this._hearbeatInterval = window.setInterval(function() { - _luci2.session.isAlive(function(alive) { + _luci2.session.isAlive().then(function(alive) { if (!alive) { _luci2.session.stopHeartbeat(); @@ -1443,22 +1556,41 @@ function LuCI2() stopHeartbeat: function() { if (typeof(this._hearbeatInterval) != 'undefined') + { window.clearInterval(this._hearbeatInterval); + delete this._hearbeatInterval; + } } }; 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 = $('
') + + var state = _luci2.ui._loading || (_luci2.ui._loading = { + modal: $('
') .addClass('cbi-modal-loader') .append($('
').text(_luci2.tr('Loading data...'))) .appendTo(body) - ); + }); if (enable) { @@ -1466,13 +1598,13 @@ function LuCI2() 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', ''); @@ -1484,8 +1616,9 @@ function LuCI2() { var win = $(window); var body = $('body'); - var div = _luci2._dialog || ( - _luci2._dialog = $('
') + + var state = _luci2.ui._dialog || (_luci2.ui._dialog = { + dialog: $('
') .addClass('cbi-modal-dialog') .append($('
') .append($('
') @@ -1507,7 +1640,7 @@ function LuCI2() $(this).parent().parent().parent().hide(); })))) .appendTo(body) - ); + }); if (typeof(options) != 'object') options = { }; @@ -1520,13 +1653,13 @@ function LuCI2() .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(); @@ -1557,29 +1690,29 @@ function LuCI2() .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 = $('
') + var state = _luci2.ui._upload || (_luci2.ui._upload = { + form: $('') .attr('method', 'post') .attr('action', '/cgi-bin/luci-upload') .attr('enctype', 'multipart/form-data') @@ -1587,12 +1720,10 @@ function LuCI2() .append($('

')) .append($('') .attr('type', 'hidden') - .attr('name', 'sessionid') - .attr('value', _luci2.globals.sid)) + .attr('name', 'sessionid')) .append($('') .attr('type', 'hidden') - .attr('name', 'filename') - .attr('value', options.filename)) + .attr('name', 'filename')) .append($('') .attr('type', 'file') .attr('name', 'filedata') @@ -1607,11 +1738,9 @@ function LuCI2() .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; @@ -1636,41 +1765,43 @@ function LuCI2() $('

').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'))); - _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.form.find('[name=sessionid]').val(_luci2.globals.sid); + state.form.find('[name=filename]').val(options.filename); - _luci2.ui.dialog(title || _luci2.tr('File upload'), _luci2._upload, { + state.success_cb = options.success; + + _luci2.ui.dialog(title || _luci2.tr('File upload'), state.form, { style: 'confirm', - confirm: confirm + confirm: state.confirm_cb }); }, @@ -1748,31 +1879,10 @@ function LuCI2() 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._login_deferred.resolve(); - } - else - { - _luci2.setHash('id', undefined); - _luci2.ui.login(); - } - }); - - return _luci2._login_deferred; - } - - var form = _luci2._login || ( - _luci2._login = $('

') + var state = _luci2.ui._login || (_luci2.ui._login = { + form: $('') + .attr('target', '') + .attr('method', 'post') .append($('

') .addClass('alert-message') .text(_luci2.tr('Wrong username or password given!'))) @@ -1784,7 +1894,11 @@ function LuCI2() .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($('

') .append($('

') - .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); @@ -1809,16 +1925,13 @@ function LuCI2() _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; @@ -1836,23 +1949,56 @@ function LuCI2() ); _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) { @@ -1958,6 +2104,9 @@ function LuCI2() { var name = node.view.split(/\//).join('.'); + if (_luci2.globals.currentView) + _luci2.globals.currentView.finish(); + _luci2.ui.renderViewMenu(); if (!_luci2._views) @@ -1966,34 +2115,136 @@ function LuCI2() _luci2.setHash('view', node.view); if (_luci2._views[name] instanceof _luci2.ui.view) + { + _luci2.globals.currentView = _luci2._views[name]; return _luci2._views[name].render(); + } - return $.ajax(_luci2.globals.resource + '/view/' + name + '.js', { + var url = _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 || { } }); + _luci2.globals.currentView = _luci2._views[name]; return _luci2._views[name].render(); } - 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.%s'.format(config, c[1])); + else + log.push('uci delete %s.%s.%s'.format(config, c[1], c[2])); + break; + + case 'rename': + if (c.length < 4) + log.push('uci rename %s.%s=%s'.format(config, c[1], c[2], c[3])); + else + log.push('uci rename %s.%s.%s=%s'.format(config, c[1], c[2], c[3], c[4])); + break; + + case 'add': + log.push('uci add %s %s (= %s)'.format(config, c[2], c[1])); + break; + + case 'list-add': + log.push('uci add_list %s.%s.%s=%s'.format(config, c[1], c[2], c[3], c[4])); + break; + + case 'list-del': + log.push('uci del_list %s.%s.%s=%s'.format(config, c[1], c[2], c[3], c[4])); + break; + + case 'set': + if (c.length < 4) + log.push('uci set %s.%s=%s'.format(config, c[1], c[2])); + else + log.push('uci set %s.%s.%s=%s'.format(config, c[1], c[2], c[3], c[4])); + break; + } + } + + html += '/etc/config/%s

%s
'.format(config, log.join('\n')); + n += changes[config].length; + } + + if (n > 0) + $('#changes') + .empty() + .show() + .append($('') + .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() { @@ -2072,6 +2323,42 @@ function LuCI2() return this._fetch_template().then(function() { return _luci2.deferrable(self.execute()); }); + }, + + 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() { + self._timeouts[index] = window.setTimeout(runTimer, interval); + }; + + runTimer = function() { + _luci2.deferrable(func.call(self)).then(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; + } } }); @@ -2125,7 +2412,10 @@ function LuCI2() 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; } } @@ -2410,7 +2700,9 @@ function LuCI2() 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'; @@ -2451,7 +2743,7 @@ function LuCI2() 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'); @@ -2701,6 +2993,7 @@ function LuCI2() } } + validation.i18n('Must be a valid IPv6 address'); return false; }, @@ -2973,7 +3266,7 @@ function LuCI2() }; - var AbstractValue = AbstractWidget.extend({ + this.cbi.AbstractValue = AbstractWidget.extend({ init: function(name, options) { this.name = name; @@ -3239,11 +3532,11 @@ function LuCI2() { 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; @@ -3351,7 +3644,7 @@ function LuCI2() } }); - this.cbi.CheckboxValue = AbstractValue.extend({ + this.cbi.CheckboxValue = this.cbi.AbstractValue.extend({ widget: function(sid) { var o = this.options; @@ -3404,19 +3697,17 @@ function LuCI2() 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 = $('') @@ -3429,7 +3720,7 @@ function LuCI2() } }); - this.cbi.PasswordValue = AbstractValue.extend({ + this.cbi.PasswordValue = this.cbi.AbstractValue.extend({ widget: function(sid) { var i = $('') @@ -3458,7 +3749,7 @@ function LuCI2() } }); - this.cbi.ListValue = AbstractValue.extend({ + this.cbi.ListValue = this.cbi.AbstractValue.extend({ widget: function(sid) { var s = $('') .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); @@ -4100,7 +4391,7 @@ function LuCI2() }); - var AbstractSection = AbstractWidget.extend({ + this.cbi.AbstractSection = AbstractWidget.extend({ id: function() { var s = [ arguments[0], this.map.uci_package, this.uci_type ]; @@ -4150,7 +4441,7 @@ function LuCI2() 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; @@ -4246,7 +4537,7 @@ function LuCI2() } }); - this.cbi.TypedSection = AbstractSection.extend({ + this.cbi.TypedSection = this.cbi.AbstractSection.extend({ init: function(uci_type, options) { this.uci_type = uci_type; @@ -4301,10 +4592,14 @@ function LuCI2() 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) @@ -4312,10 +4607,17 @@ function LuCI2() 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(); }, @@ -4377,9 +4679,9 @@ function LuCI2() 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]); } } @@ -4458,7 +4760,7 @@ function LuCI2() return add; }, - _render_remove: function(sid) + _render_remove: function(sid, index) { var text = _luci2.tr('Remove'); var ttip = _luci2.tr('Remove this section'); @@ -4473,7 +4775,7 @@ function LuCI2() .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) @@ -4557,7 +4859,7 @@ function LuCI2() $('
') .addClass('cbi-section-remove') .addClass('right') - .append(this._render_remove(sid)) + .append(this._render_remove(sid, panel_index)) .appendTo(head); var body = $('
') @@ -4900,7 +5202,8 @@ function LuCI2() deletes: { } }; - this.active_panel = 0; + if (typeof(this.active_panel) == 'undefined') + this.active_panel = 0; var packages = { }; @@ -5050,7 +5353,7 @@ function LuCI2() { 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; @@ -5296,11 +5599,11 @@ function LuCI2() for (var k in this.uci.creates[c][s]) { if (k == '.type') - r.type = this.uci.creates[i][k]; + r.type = this.uci.creates[c][s][k]; else if (k == '.create') - r.name = this.uci.creates[i][k]; + r.name = this.uci.creates[c][s][k]; else if (k.charAt(0) != '.') - r.values[k] = this.uci.creates[i][k]; + r.values[k] = this.uci.creates[c][s][k]; } _luci2.uci.add(r.config, r.type, r.name, r.values); @@ -5319,11 +5622,14 @@ function LuCI2() _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() { @@ -5333,33 +5639,7 @@ function LuCI2() self = null; _luci2.ui.loading(false); - }); - }, - - dialog: function(id) - { - var d = $('
'); - var p = $('

'); - - $('') - .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(); }); },