2 LuCI2 - OpenWrt Web Interface
4 Copyright 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
13 String.prototype.format = function()
15 var html_esc = [/&/g, '&', /"/g, '"', /'/g, ''', /</g, '<', />/g, '>'];
16 var quot_esc = [/"/g, '"', /'/g, '''];
19 for( var i = 0; i < r.length; i += 2 )
20 s = s.replace(r[i], r[i+1]);
26 var re = /^(([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X|q|h|j|t|m))/;
27 var a = b = [], numSubstitutions = 0, numMatches = 0;
29 while ((a = re.exec(str)) != null)
32 var leftpart = a[2], pPad = a[3], pJustify = a[4], pMinLength = a[5];
33 var pPrecision = a[6], pType = a[7];
43 if (numSubstitutions < arguments.length)
45 var param = arguments[numSubstitutions++];
48 if (pPad && pPad.substr(0,1) == "'")
49 pad = leftpart.substr(1,1);
53 var justifyRight = true;
54 if (pJustify && pJustify === "-")
59 minLength = parseInt(pMinLength);
62 if (pPrecision && pType == 'f')
63 precision = parseInt(pPrecision.substring(1));
70 subst = (parseInt(param) || 0).toString(2);
74 subst = String.fromCharCode(parseInt(param) || 0);
78 subst = (parseInt(param) || 0);
82 subst = Math.abs(parseInt(param) || 0);
86 subst = (precision > -1)
87 ? ((parseFloat(param) || 0.0)).toFixed(precision)
88 : (parseFloat(param) || 0.0);
92 subst = (parseInt(param) || 0).toString(8);
100 subst = ('' + (parseInt(param) || 0).toString(16)).toLowerCase();
104 subst = ('' + (parseInt(param) || 0).toString(16)).toUpperCase();
108 subst = esc(param, html_esc);
112 subst = esc(param, quot_esc);
116 subst = String.serialize(param);
123 var ts = (param || 0);
126 tm = Math.floor(ts / 60);
131 th = Math.floor(tm / 60);
136 td = Math.floor(th / 24);
141 ? '%dd %dh %dm %ds'.format(td, th, tm, ts)
142 : '%dh %dm %ds'.format(th, tm, ts);
147 var mf = pMinLength ? parseInt(pMinLength) : 1000;
148 var pr = pPrecision ? Math.floor(10*parseFloat('0'+pPrecision)) : 2;
151 var val = parseFloat(param || 0);
152 var units = [ '', 'K', 'M', 'G', 'T', 'P', 'E' ];
154 for (i = 0; (i < units.length) && (val > mf); i++)
157 subst = val.toFixed(pr) + ' ' + units[i];
161 subst = (typeof(subst) == 'undefined') ? '' : subst.toString();
163 if (minLength > 0 && pad.length > 0)
164 for (var i = 0; i < (minLength - subst.length); i++)
165 subst = justifyRight ? (pad + subst) : (subst + pad);
169 out += leftpart + subst;
170 str = str.substr(m.length);
176 if (!window.location.origin)
177 window.location.origin = '%s//%s%s'.format(
178 window.location.protocol,
179 window.location.hostname,
180 (window.location.port ? ':' + window.location.port : '')
187 var Class = function() { };
189 Class.extend = function(properties)
191 Class.initializing = true;
193 var prototype = new this();
194 var superprot = this.prototype;
196 Class.initializing = false;
198 $.extend(prototype, properties, {
199 callSuper: function() {
201 var meth = arguments[0];
203 if (typeof(superprot[meth]) != 'function')
206 for (var i = 1; i < arguments.length; i++)
207 args.push(arguments[i]);
209 return superprot[meth].apply(this, args);
215 this.options = arguments[0] || { };
217 if (!Class.initializing && typeof(this.init) == 'function')
218 this.init.apply(this, arguments);
221 _class.prototype = prototype;
222 _class.prototype.constructor = _class;
224 _class.extend = Class.extend;
229 Class.require = function(name)
231 var path = '/' + name.replace(/\./g, '/') + '.js';
233 return $.ajax(path, {
238 }).then(function(text) {
239 var code = '%s\n\n//@ sourceURL=%s/%s'.format(text, window.location.origin, path);
240 var construct = eval(code);
242 var parts = name.split(/\./);
243 var cparent = L.Class || (L.Class = { });
245 for (var i = 1; i < parts.length - 1; i++)
247 cparent = cparent[parts[i]];
250 throw "Missing parent class";
253 cparent[parts[i]] = construct;
257 Class.instantiate = function(name)
259 Class.require(name).then(function() {
260 var parts = name.split(/\./);
262 var construct = L.Class;
264 for (var i = 1; i < parts.length - 1; i++)
266 iparent = iparent[parts[i]];
267 construct = construct[parts[i]];
270 throw "Missing parent class";
273 if (construct[parts[i]])
274 iparent[parts[i]] = new construct[parts[i]]();
278 this.defaults = function(obj, def)
281 if (typeof(obj[key]) == 'undefined')
287 this.isDeferred = function(x)
289 return (typeof(x) == 'object' &&
290 typeof(x.then) == 'function' &&
291 typeof(x.promise) == 'function');
294 this.deferrable = function()
296 if (this.isDeferred(arguments[0]))
299 var d = $.Deferred();
300 d.resolve.apply(d, arguments);
309 plural: function(n) { return 0 + (n != 1) },
315 var lang = (navigator.userLanguage || navigator.language || 'en').toLowerCase();
316 var langs = (lang.indexOf('-') > -1) ? [ lang, lang.split(/-/)[0] ] : [ lang ];
318 for (var i = 0; i < langs.length; i++)
319 $.ajax('%s/i18n/base.%s.json'.format(L.globals.resource, langs[i]), {
323 success: function(data) {
324 $.extend(L.i18n.catalog, data);
326 var pe = L.i18n.catalog[''];
329 delete L.i18n.catalog[''];
331 var pf = new Function('n', 'return 0 + (' + pe + ')');
338 L.i18n.loaded = true;
343 this.tr = function(msgid)
347 var msgstr = L.i18n.catalog[msgid];
349 if (typeof(msgstr) == 'undefined')
351 else if (typeof(msgstr) == 'string')
357 this.trp = function(msgid, msgid_plural, count)
361 var msgstr = L.i18n.catalog[msgid];
363 if (typeof(msgstr) == 'undefined')
364 return (count == 1) ? msgid : msgid_plural;
365 else if (typeof(msgstr) == 'string')
368 return msgstr[L.i18n.plural(count)];
371 this.trc = function(msgctx, msgid)
375 var msgstr = L.i18n.catalog[msgid + '\u0004' + msgctx];
377 if (typeof(msgstr) == 'undefined')
379 else if (typeof(msgstr) == 'string')
385 this.trcp = function(msgctx, msgid, msgid_plural, count)
389 var msgstr = L.i18n.catalog[msgid + '\u0004' + msgctx];
391 if (typeof(msgstr) == 'undefined')
392 return (count == 1) ? msgid : msgid_plural;
393 else if (typeof(msgstr) == 'string')
396 return msgstr[L.i18n.plural(count)];
399 this.setHash = function(key, value)
402 var data = this.getHash(undefined);
404 if (typeof(value) == 'undefined')
415 for (var i = 0; i < keys.length; i++)
420 h += keys[i] + ':' + data[keys[i]];
424 location.hash = '#' + h;
429 this.getHash = function(key)
432 var tuples = (location.hash || '#').substring(1).split(/,/);
434 for (var i = 0; i < tuples.length; i++)
436 var tuple = tuples[i].split(/:/);
437 if (tuple.length == 2)
438 data[tuple[0]] = tuple[1];
441 if (typeof(key) != 'undefined')
447 this.toArray = function(x)
457 var l = x.split(/\s+/);
458 for (var i = 0; i < l.length; i++)
467 for (var i = 0; i < x.length; i++)
471 else if ($.isPlainObject(x))
475 if (x.hasOwnProperty(k))
484 this.toObject = function(x)
494 var l = x.split(/\x+/);
495 for (var i = 0; i < l.length; i++)
504 for (var i = 0; i < x.length; i++)
508 else if ($.isPlainObject(x))
517 this.filterArray = function(array, item)
519 if (!$.isArray(array))
522 for (var i = 0; i < array.length; i++)
523 if (array[i] === item)
524 array.splice(i--, 1);
529 this.toClassName = function(str, suffix)
532 var l = str.split(/[\/.]/);
534 for (var i = 0; i < l.length; i++)
536 n += l[i].charAt(0).toUpperCase() + l[i].substr(1).toLowerCase();
538 if (typeof(suffix) == 'string')
544 this.toColor = function(str)
546 if (typeof(str) != 'string' || str.length == 0)
551 else if (str == 'lan')
556 while (i < str.length)
557 hash = str.charCodeAt(i++) + ((hash << 5) - hash);
559 var r = (hash & 0xFF) % 128;
560 var g = ((hash >> 8) & 0xFF) % 128;
570 var b = min + (((hash >> 16) & 0xFF) % (max - min));
572 return '#%02X%02X%02X'.format(0xFF - r, 0xFF - g, 0xFF - b);
575 this.parseIPv4 = function(str)
577 if ((typeof(str) != 'string' && !(str instanceof String)) ||
578 !str.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/))
582 var parts = str.split(/\./);
584 for (var i = 0; i < parts.length; i++)
586 var n = parseInt(parts[i], 10);
587 if (isNaN(n) || n > 255)
596 this.parseIPv6 = function(str)
598 if ((typeof(str) != 'string' && !(str instanceof String)) ||
599 !str.match(/^[a-fA-F0-9:]+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/))
602 var parts = str.split(/::/);
603 if (parts.length == 0 || parts.length > 2)
607 if (parts[0].length > 0)
609 var left = parts[0].split(/:/);
610 for (var i = 0; i < left.length; i++)
612 var n = parseInt(left[i], 16);
616 lnum.push((n / 256) >> 0);
622 if (parts.length > 1 && parts[1].length > 0)
624 var right = parts[1].split(/:/);
626 for (var i = 0; i < right.length; i++)
628 if (right[i].indexOf('.') > 0)
630 var addr = L.parseIPv4(right[i]);
634 rnum.push.apply(rnum, addr);
638 var n = parseInt(right[i], 16);
642 rnum.push((n / 256) >> 0);
647 if (rnum.length > 0 && (lnum.length + rnum.length) > 15)
652 num.push.apply(num, lnum);
654 for (var i = 0; i < (16 - lnum.length - rnum.length); i++)
657 num.push.apply(num, rnum);
665 this.isNetmask = function(addr)
667 if (!$.isArray(addr))
672 for (c = 0; (c < addr.length) && (addr[c] == 255); c++);
674 if (c == addr.length)
677 if ((addr[c] == 254) || (addr[c] == 252) || (addr[c] == 248) ||
678 (addr[c] == 240) || (addr[c] == 224) || (addr[c] == 192) ||
679 (addr[c] == 128) || (addr[c] == 0))
681 for (c++; (c < addr.length) && (addr[c] == 0); c++);
683 if (c == addr.length)
693 sid: '00000000000000000000000000000000'
696 Class.instantiate('luci2.rpc');
697 Class.instantiate('luci2.uci');
698 Class.instantiate('luci2.network');
699 Class.instantiate('luci2.wireless');
700 Class.instantiate('luci2.firewall');
701 Class.instantiate('luci2.system');
702 Class.instantiate('luci2.session');
703 Class.instantiate('luci2.ui');
704 Class.instantiate('luci2.cbi');