X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fluci2%2Fui.git;a=blobdiff_plain;f=luci2%2Fhtdocs%2Fluci2%2Fluci2.js;h=4e872188d0082c52a1b128273e10888e0066a593;hp=a074b44a89dc40d760664c6692fa1b03e244181b;hb=dd7878e8d48e2a3606a97265b9b83ac0d80cda72;hpb=19990b36ae3f7ca9135934e7ecc92b6aa172480f diff --git a/luci2/htdocs/luci2/luci2.js b/luci2/htdocs/luci2/luci2.js index a074b44..4e87218 100644 --- a/luci2/htdocs/luci2/luci2.js +++ b/luci2/htdocs/luci2/luci2.js @@ -214,7 +214,7 @@ function LuCI2() _class.prototype = prototype; _class.prototype.constructor = _class; - _class.extend = arguments.callee; + _class.extend = Class.extend; return _class; }; @@ -364,8 +364,10 @@ function LuCI2() h += keys[i] + ':' + data[keys[i]]; } - if (h) + if (h.length) location.hash = '#' + h; + else + location.hash = ''; }; this.getHash = function(key) @@ -386,8 +388,105 @@ function LuCI2() return data; }; + this.toArray = function(x) + { + switch (typeof(x)) + { + case 'number': + case 'boolean': + return [ x ]; + + case 'string': + var r = [ ]; + var l = x.split(/\s+/); + for (var i = 0; i < l.length; i++) + if (l[i].length > 0) + r.push(l[i]); + return r; + + case 'object': + if ($.isArray(x)) + { + var r = [ ]; + for (var i = 0; i < x.length; i++) + r.push(x[i]); + return r; + } + else if ($.isPlainObject(x)) + { + var r = [ ]; + for (var k in x) + if (x.hasOwnProperty(k)) + r.push(k); + return r.sort(); + } + } + + return [ ]; + }; + + this.toObject = function(x) + { + switch (typeof(x)) + { + case 'number': + case 'boolean': + return { x: true }; + + case 'string': + var r = { }; + var l = x.split(/\x+/); + for (var i = 0; i < l.length; i++) + if (l[i].length > 0) + r[l[i]] = true; + return r; + + case 'object': + if ($.isArray(x)) + { + var r = { }; + for (var i = 0; i < x.length; i++) + r[x[i]] = true; + return r; + } + else if ($.isPlainObject(x)) + { + return x; + } + } + + return { }; + }; + + this.filterArray = function(array, item) + { + if (!$.isArray(array)) + return [ ]; + + for (var i = 0; i < array.length; i++) + if (array[i] === item) + array.splice(i--, 1); + + return array; + }; + + this.toClassName = function(str, suffix) + { + var n = ''; + var l = str.split(/[\/.]/); + + for (var i = 0; i < l.length; i++) + if (l[i].length > 0) + n += l[i].charAt(0).toUpperCase() + l[i].substr(1).toLowerCase(); + + if (typeof(suffix) == 'string') + n += suffix; + + return n; + }; + this.globals = { - timeout: 3000, + timeout: 15000, resource: '/luci2', sid: '00000000000000000000000000000000' }; @@ -406,43 +505,48 @@ function LuCI2() data: JSON.stringify(req), dataType: 'json', type: 'POST', - timeout: _luci2.globals.timeout - }).then(cb); + timeout: _luci2.globals.timeout, + _rpc_req: req + }).then(cb, cb); }, _list_cb: function(msg) { + var list = msg.result; + /* verify message frame */ - if (typeof(msg) != 'object' || msg.jsonrpc != '2.0' || !msg.id) - throw 'Invalid JSON response'; + if (typeof(msg) != 'object' || msg.jsonrpc != '2.0' || !msg.id || !$.isArray(list)) + list = [ ]; - return msg.result; + return $.Deferred().resolveWith(this, [ list ]); }, _call_cb: function(msg) { var data = [ ]; var type = Object.prototype.toString; + var reqs = this._rpc_req; - if (!$.isArray(msg)) + if (!$.isArray(reqs)) + { msg = [ msg ]; + reqs = [ reqs ]; + } for (var i = 0; i < msg.length; i++) { - /* verify message frame */ - if (typeof(msg[i]) != 'object' || msg[i].jsonrpc != '2.0' || !msg[i].id) - throw 'Invalid JSON response'; - /* fetch related request info */ - var req = _luci2.rpc._requests[msg[i].id]; + var req = _luci2.rpc._requests[reqs[i].id]; if (typeof(req) != 'object') throw 'No related request for JSON response'; /* fetch response attribute and verify returned type */ var ret = undefined; - if ($.isArray(msg[i].result) && msg[i].result[0] == 0) - ret = (msg[i].result.length > 1) ? msg[i].result[1] : msg[i].result[0]; + /* verify message frame */ + if (typeof(msg[i]) == 'object' && msg[i].jsonrpc == '2.0') + if ($.isArray(msg[i].result) && msg[i].result[0] == 0) + ret = (msg[i].result.length > 1) ? msg[i].result[1] : msg[i].result[0]; if (req.expect) { @@ -451,7 +555,7 @@ function LuCI2() if (typeof(ret) != 'undefined' && key != '') ret = ret[key]; - if (type.call(ret) != type.call(req.expect[key])) + if (typeof(ret) == 'undefined' || type.call(ret) != type.call(req.expect[key])) ret = req.expect[key]; break; @@ -473,10 +577,10 @@ function LuCI2() data = ret; /* delete request object */ - delete _luci2.rpc._requests[msg[i].id]; + delete _luci2.rpc._requests[reqs[i].id]; } - return data; + return $.Deferred().resolveWith(this, [ data ]); }, list: function() @@ -584,13 +688,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 +892,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 +921,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 +971,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 +1035,7 @@ function LuCI2() } }), - listDeviceNamestatus: _luci2.rpc.declare({ + getDeviceStatus: _luci2.rpc.declare({ object: 'network.device', method: 'status', params: [ 'name' ], @@ -912,6 +1050,88 @@ 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 } } + }), + + + 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 } } }) }; @@ -1072,6 +1292,57 @@ function LuCI2() } }; + 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', @@ -1292,6 +1563,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 +1712,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,143 +1726,126 @@ 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 = $('
') - .addClass('cbi-modal-loader') - .append($('
').text(_luci2.tr('Loading data...'))) + + var state = _luci2.ui._loading || (_luci2.ui._loading = { + modal: $('
') + .addClass('modal fade') + .append($('
') + .addClass('modal-dialog') + .append($('
') + .addClass('modal-content luci2-modal-loader') + .append($('
') + .addClass('modal-body') + .text(_luci2.tr('Loading data…'))))) .appendTo(body) - ); + .modal({ + backdrop: 'static', + keyboard: false + }) + }); - if (enable) - { - 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()); - div.show(); - } - else - { - div.hide(); - body.css('overflow', ''); - body.css('padding', ''); - body.css('width', ''); - body.css('height', ''); - } + state.modal.modal(enable ? 'show' : 'hide'); }, dialog: function(title, content, options) { var win = $(window); var body = $('body'); - var div = _luci2._dialog || ( - _luci2._dialog = $('
') - .addClass('cbi-modal-dialog') + + var state = _luci2.ui._dialog || (_luci2.ui._dialog = { + dialog: $('
') + .addClass('modal fade') .append($('
') + .addClass('modal-dialog') .append($('
') - .addClass('cbi-modal-dialog-header')) - .append($('
') - .addClass('cbi-modal-dialog-body')) - .append($('
') - .addClass('cbi-modal-dialog-footer') - .append($('