X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fluci2%2Fui.git;a=blobdiff_plain;f=luci2%2Fhtdocs%2Fluci2%2Fluci2.js;h=5947791600a9ace955dade058bbd8849ec29a2ce;hp=6b07f8c331ec9f775bf379ce094790a8cc533132;hb=e314622aa9ad41f5d3083dfd21ff0f61175c237f;hpb=f90935da6e6d84e5f98a90c02a63a45ffea613a1 diff --git a/luci2/htdocs/luci2/luci2.js b/luci2/htdocs/luci2/luci2.js index 6b07f8c..5947791 100644 --- a/luci2/htdocs/luci2/luci2.js +++ b/luci2/htdocs/luci2/luci2.js @@ -485,6 +485,152 @@ function LuCI2() return n; }; + this.toColor = function(str) + { + if (typeof(str) != 'string' || str.length == 0) + return '#CCCCCC'; + + if (str == 'wan') + return '#F09090'; + else if (str == 'lan') + return '#90F090'; + + var i = 0, hash = 0; + + while (i < str.length) + hash = str.charCodeAt(i++) + ((hash << 5) - hash); + + var r = (hash & 0xFF) % 128; + var g = ((hash >> 8) & 0xFF) % 128; + + var min = 0; + var max = 128; + + if ((r + g) < 128) + min = 128 - r - g; + else + max = 255 - r - g; + + var b = min + (((hash >> 16) & 0xFF) % (max - min)); + + return '#%02X%02X%02X'.format(0xFF - r, 0xFF - g, 0xFF - b); + }; + + this.parseIPv4 = function(str) + { + if ((typeof(str) != 'string' && !(str instanceof String)) || + !str.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)) + return undefined; + + var num = [ ]; + var parts = str.split(/\./); + + for (var i = 0; i < parts.length; i++) + { + var n = parseInt(parts[i], 10); + if (isNaN(n) || n > 255) + return undefined; + + num.push(n); + } + + return num; + }; + + this.parseIPv6 = function(str) + { + if ((typeof(str) != 'string' && !(str instanceof String)) || + !str.match(/^[a-fA-F0-9:]+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/)) + return undefined; + + var parts = str.split(/::/); + if (parts.length == 0 || parts.length > 2) + return undefined; + + var lnum = [ ]; + if (parts[0].length > 0) + { + var left = parts[0].split(/:/); + for (var i = 0; i < left.length; i++) + { + var n = parseInt(left[i], 16); + if (isNaN(n)) + return undefined; + + lnum.push((n / 256) >> 0); + lnum.push(n % 256); + } + } + + var rnum = [ ]; + if (parts.length > 1 && parts[1].length > 0) + { + var right = parts[1].split(/:/); + + for (var i = 0; i < right.length; i++) + { + if (right[i].indexOf('.') > 0) + { + var addr = L.parseIPv4(right[i]); + if (!addr) + return undefined; + + rnum.push.apply(rnum, addr); + continue; + } + + var n = parseInt(right[i], 16); + if (isNaN(n)) + return undefined; + + rnum.push((n / 256) >> 0); + rnum.push(n % 256); + } + } + + if (rnum.length > 0 && (lnum.length + rnum.length) > 15) + return undefined; + + var num = [ ]; + + num.push.apply(num, lnum); + + for (var i = 0; i < (16 - lnum.length - rnum.length); i++) + num.push(0); + + num.push.apply(num, rnum); + + if (num.length > 16) + return undefined; + + return num; + }; + + this.isNetmask = function(addr) + { + if (!$.isArray(addr)) + return false; + + var c; + + for (c = 0; (c < addr.length) && (addr[c] == 255); c++); + + if (c == addr.length) + return true; + + if ((addr[c] == 254) || (addr[c] == 252) || (addr[c] == 248) || + (addr[c] == 240) || (addr[c] == 224) || (addr[c] == 192) || + (addr[c] == 128) || (addr[c] == 0)) + { + for (c++; (c < addr.length) && (addr[c] == 0); c++); + + if (c == addr.length) + return true; + } + + return false; + }; + this.globals = { timeout: 15000, resource: '/luci2', @@ -674,7 +820,7 @@ function LuCI2() init: function() { this.state = { - newid: 0, + newidx: 0, values: { }, creates: { }, changes: { }, @@ -715,6 +861,19 @@ function LuCI2() params: [ 'config', 'section', 'options' ] }), + _newid: function(conf) + { + var v = this.state.values; + var n = this.state.creates; + var sid; + + do { + sid = "new%06x".format(Math.random() * 0xFFFFFF); + } while ((n[conf] && n[conf][sid]) || (v[conf] && v[conf][sid])); + + return sid; + }, + load: function(packages) { var self = this; @@ -727,7 +886,7 @@ function LuCI2() L.rpc.batch(); for (var i = 0; i < packages.length; i++) - if (!seen[packages[i]]) + if (!seen[packages[i]] && !self.state.values[packages[i]]) { pkgs.push(packages[i]); seen[packages[i]] = true; @@ -758,21 +917,21 @@ function LuCI2() add: function(conf, type, name) { - var c = this.state.creates; - var s = '.new.%d'.format(this.state.newid++); + var n = this.state.creates; + var sid = this._newid(conf); - if (!c[conf]) - c[conf] = { }; + if (!n[conf]) + n[conf] = { }; - c[conf][s] = { + n[conf][sid] = { '.type': type, - '.name': s, + '.name': sid, '.create': name, '.anonymous': !name, - '.index': 1000 + this.state.newid + '.index': 1000 + this.state.newidx++ }; - return s; + return sid; }, remove: function(conf, sid) @@ -782,10 +941,9 @@ function LuCI2() var d = this.state.deletes; /* requested deletion of a just created section */ - if (sid.indexOf('.new.') == 0) + if (n[conf] && n[conf][sid]) { - if (n[conf]) - delete n[conf][sid]; + delete n[conf][sid]; } else { @@ -845,7 +1003,7 @@ function LuCI2() return undefined; /* requested option in a just created section */ - if (sid.indexOf('.new.') == 0) + if (n[conf] && n[conf][sid]) { if (!n[conf]) return undefined; @@ -890,6 +1048,7 @@ function LuCI2() set: function(conf, sid, opt, val) { + var v = this.state.values; var n = this.state.creates; var c = this.state.changes; var d = this.state.deletes; @@ -899,15 +1058,12 @@ function LuCI2() opt.charAt(0) == '.') return; - if (sid.indexOf('.new.') == 0) + if (n[conf] && n[conf][sid]) { - if (n[conf] && n[conf][sid]) - { - if (typeof(val) != 'undefined') - n[conf][sid][opt] = val; - else - delete n[conf][sid][opt]; - } + if (typeof(val) != 'undefined') + n[conf][sid][opt] = val; + else + delete n[conf][sid][opt]; } else if (typeof(val) != 'undefined') { @@ -915,6 +1071,10 @@ function LuCI2() if (d[conf] && d[conf][sid] === true) return; + /* only set in existing sections */ + if (!v[conf] || !v[conf][sid]) + return; + if (!c[conf]) c[conf] = { }; @@ -929,6 +1089,10 @@ function LuCI2() } else { + /* only delete in existing sections */ + if (!v[conf] || !v[conf][sid]) + return; + if (!d[conf]) d[conf] = { }; @@ -945,6 +1109,35 @@ function LuCI2() return this.set(conf, sid, opt, undefined); }, + get_first: function(conf, type, opt) + { + var sid = undefined; + + L.uci.sections(conf, type, function(s) { + if (typeof(sid) != 'string') + sid = s['.name']; + }); + + return this.get(conf, sid, opt); + }, + + set_first: function(conf, type, opt, val) + { + var sid = undefined; + + L.uci.sections(conf, type, function(s) { + if (typeof(sid) != 'string') + sid = s['.name']; + }); + + return this.set(conf, sid, opt, val); + }, + + unset_first: function(conf, type, opt) + { + return this.set_first(conf, type, opt, undefined); + }, + _reload: function() { var pkgs = [ ]; @@ -976,7 +1169,7 @@ function LuCI2() { var o = [ ]; - if (n && n[c]) + if (n[c]) for (var s in n[c]) o.push(n[c][s]); @@ -1024,46 +1217,64 @@ function LuCI2() { L.rpc.batch(); + var v = this.state.values; + var n = this.state.creates; + var c = this.state.changes; + var d = this.state.deletes; + var self = this; var snew = [ ]; + var pkgs = { }; - if (self.state.creates) - for (var c in self.state.creates) - for (var s in self.state.creates[c]) + if (n) + for (var conf in n) + { + for (var sid in n[conf]) { var r = { - config: c, + config: conf, values: { } }; - for (var k in self.state.creates[c][s]) + for (var k in n[conf][sid]) { if (k == '.type') - r.type = self.state.creates[c][s][k]; + r.type = n[conf][sid][k]; else if (k == '.create') - r.name = self.state.creates[c][s][k]; + r.name = n[conf][sid][k]; else if (k.charAt(0) != '.') - r.values[k] = self.state.creates[c][s][k]; + r.values[k] = n[conf][sid][k]; } - snew.push(self.state.creates[c][s]); + snew.push(n[conf][sid]); self._add(r.config, r.type, r.name, r.values); } - if (self.state.changes) - for (var c in self.state.changes) - for (var s in self.state.changes[c]) - self._set(c, s, self.state.changes[c][s]); + pkgs[conf] = true; + } + + if (c) + for (var conf in c) + { + for (var sid in c[conf]) + self._set(conf, sid, c[conf][sid]); + + pkgs[conf] = true; + } - if (self.state.deletes) - for (var c in self.state.deletes) - for (var s in self.state.deletes[c]) + if (d) + for (var conf in d) + { + for (var sid in d[conf]) { - var o = self.state.deletes[c][s]; - self._delete(c, s, (o === true) ? undefined : o); + var o = d[conf][sid]; + self._delete(conf, sid, (o === true) ? undefined : o); } + pkgs[conf] = true; + } + return L.rpc.flush().then(function(responses) { /* array "snew" holds references to the created uci sections, @@ -1073,6 +1284,12 @@ function LuCI2() snew[i]['.name'] = responses[i]; return self._reorder(); + }).then(function() { + pkgs = L.toArray(pkgs); + + self.unload(pkgs); + + return self.load(pkgs); }); }, @@ -1441,7 +1658,9 @@ function LuCI2() _fetch_protocols: function() { var self = L.NetworkModel; - var deferreds = [ ]; + var deferreds = [ + self._fetch_protocol('none') + ]; for (var proto in self._cache.protolist) deferreds.push(self._fetch_protocol(proto)); @@ -3686,6 +3905,33 @@ function LuCI2() appendTo: function(id) { return $(id).append(this.render()); + }, + + on: function(evname, evfunc) + { + var evnames = L.toArray(evname); + + if (!this.events) + this.events = { }; + + for (var i = 0; i < evnames.length; i++) + this.events[evnames[i]] = evfunc; + + return this; + }, + + trigger: function(evname, evdata) + { + if (this.events) + { + var evnames = L.toArray(evname); + + for (var i = 0; i < evnames.length; i++) + if (this.events[evnames[i]]) + this.events[evnames[i]].call(this, evdata); + } + + return this; } }); @@ -4704,7 +4950,6 @@ function LuCI2() this.instance = { }; this.dependencies = [ ]; this.rdependency = { }; - this.events = { }; this.options = L.defaults(options, { placeholder: '', @@ -4925,8 +5170,9 @@ function LuCI2() opt: this.options.optional }; - for (var evname in this.events) - elem.on(evname, evdata, this.events[evname]); + if (this.events) + for (var evname in this.events) + elem.on(evname, evdata, this.events[evname]); if (typeof(this.options.datatype) == 'undefined' && $.isEmptyObject(this.rdependency)) return elem; @@ -5102,12 +5348,6 @@ function LuCI2() } return false; - }, - - on: function(evname, evfunc) - { - this.events[evname] = evfunc; - return this; } }); @@ -6237,12 +6477,12 @@ function LuCI2() add: function(name) { - this.map.add(this.map.uci_package, this.uci_type, name); + return this.map.add(this.map.uci_package, this.uci_type, name); }, remove: function(sid) { - this.map.remove(this.map.uci_package, sid); + return this.map.remove(this.map.uci_package, sid); }, _ev_add: function(ev) @@ -6261,7 +6501,13 @@ function LuCI2() self.active_panel = -1; self.map.save(); - self.add(name); + + ev.data.sid = self.add(name); + ev.data.type = self.uci_type; + ev.data.name = name; + + self.trigger('add', ev); + self.map.redraw(); L.ui.restoreScrollTop(); @@ -6274,6 +6520,8 @@ function LuCI2() L.ui.saveScrollTop(); + self.trigger('remove', ev); + self.map.save(); self.remove(sid); self.map.redraw(); @@ -6928,6 +7176,30 @@ function LuCI2() self.active_tab = parseInt(ev.target.getAttribute('data-luci2-tab-index')); }, + _ev_apply: function(ev) + { + var self = ev.data.self; + + self.trigger('apply', ev); + }, + + _ev_save: function(ev) + { + var self = ev.data.self; + + self.send().then(function() { + self.trigger('save', ev); + }); + }, + + _ev_reset: function(ev) + { + var self = ev.data.self; + + self.trigger('reset', ev); + self.reset(); + }, + _render_tab_head: function(tab_index) { var section = this.sections[tab_index]; @@ -7002,16 +7274,20 @@ function LuCI2() _render_footer: function() { + var evdata = { + self: this + }; + return $('
') .addClass('panel panel-default panel-body text-right') .append($('
') .addClass('btn-group') .append(L.ui.button(L.tr('Save & Apply'), 'primary') - .click({ self: this }, function(ev) { })) + .click(evdata, this._ev_apply)) .append(L.ui.button(L.tr('Save'), 'default') - .click({ self: this }, function(ev) { ev.data.self.send(); })) + .click(evdata, this._ev_save)) .append(L.ui.button(L.tr('Reset'), 'default') - .click({ self: this }, function(ev) { ev.data.self.insertInto(ev.data.self.target); }))); + .click(evdata, this._ev_reset))); }, render: function() @@ -7172,6 +7448,27 @@ function LuCI2() }); }, + revert: function() + { + var packages = { }; + + for (var i = 0; i < this.sections.length; i++) + this.sections[i].ucipackages(packages); + + packages[this.uci_package] = true; + + L.uci.unload(L.toArray(packages)); + }, + + reset: function() + { + var self = this; + + self.revert(); + + return self.insertInto(self.target); + }, + insertInto: function(id) { var self = this; @@ -7191,16 +7488,46 @@ function LuCI2() }); this.cbi.Modal = this.cbi.Map.extend({ + _ev_apply: function(ev) + { + var self = ev.data.self; + + self.trigger('apply', ev); + }, + + _ev_save: function(ev) + { + var self = ev.data.self; + + self.send().then(function() { + self.trigger('save', ev); + self.close(); + }); + }, + + _ev_reset: function(ev) + { + var self = ev.data.self; + + self.trigger('close', ev); + self.revert(); + self.close(); + }, + _render_footer: function() { + var evdata = { + self: this + }; + return $('
') .addClass('btn-group') .append(L.ui.button(L.tr('Save & Apply'), 'primary') - .click({ self: this }, function(ev) { })) + .click(evdata, this._ev_apply)) .append(L.ui.button(L.tr('Save'), 'default') - .click({ self: this }, function(ev) { ev.data.self.send(); })) + .click(evdata, this._ev_save)) .append(L.ui.button(L.tr('Cancel'), 'default') - .click({ self: this }, function(ev) { L.ui.dialog(false); })); + .click(evdata, this._ev_reset)); }, render: function() @@ -7238,6 +7565,11 @@ function LuCI2() L.ui.loading(false); }); + }, + + close: function() + { + L.ui.dialog(false); } }); };