Select Git revision
gluon-web-model.js
Forked from
firmware / FFS Gluon
Source project has a limited visibility.
-
Kasalehlia authored
Register to 'reset' event on form element and make call to 'update' function delayed in 'data-update' handler to allow the form values to update beforehand. When using a form's 'reset' button, form field visibility was not updated. This could lead to situations where a checkbox had to be toggled again twice to display the detail text inputs. (Example taken from private wifi package)
Kasalehlia authoredRegister to 'reset' event on form element and make call to 'update' function delayed in 'data-update' handler to allow the form values to update beforehand. When using a form's 'reset' button, form field visibility was not updated. This could lead to situations where a checkbox had to be toggled again twice to display the detail text inputs. (Example taken from private wifi package)
gluon-web-model.js 11.26 KiB
/*
Copyright 2008 Steven Barth <steven@midlink.org>
Copyright 2008-2012 Jo-Philipp Wich <jow@openwrt.org>
Copyright 2017 Matthias Schiffer <mschiffer@universe-factory.net>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
*/
/*
Build using:
uglifyjs javascript/gluon-web-model.js -o files/lib/gluon/web/www/static/gluon-web-model.js -c -m --support-ie8
*/
(function() {
var dep_entries = {};
function Int(x) {
return (/^-?\d+$/.test(x) ? +x : NaN);
}
function Dec(x) {
return (/^-?\d*\.?\d+?$/.test(x) ? +x : NaN);
}
var validators = {
'integer': function() {
return !isNaN(Int(this));
},
'uinteger': function() {
return (Int(this) >= 0);
},
'float': function() {
return !isNaN(Dec(this));
},
'ufloat': function() {
return (Dec(this) >= 0);
},
'ipaddr': function() {
return validators.ip4addr.apply(this) ||
validators.ip6addr.apply(this);
},
'ip4addr': function() {
var match;
if ((match = this.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/))) {
return (match[1] >= 0) && (match[1] <= 255) &&
(match[2] >= 0) && (match[2] <= 255) &&
(match[3] >= 0) && (match[3] <= 255) &&
(match[4] >= 0) && (match[4] <= 255);
}
return false;
},
'ip6addr': function() {
if (this.indexOf('::') < 0)
return (this.match(/^(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}$/i) != null);
if (
(this.indexOf(':::') >= 0) || this.match(/::.+::/) ||
this.match(/^:[^:]/) || this.match(/[^:]:$/)
)
return false;
if (this.match(/^(?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}$/i))
return true;
if (this.match(/^(?:[a-f0-9]{1,4}:){7}:$/i))
return true;
if (this.match(/^:(?::[a-f0-9]{1,4}){7}$/i))
return true;
return false;
},
'wpakey': function() {
var v = this;
if (v.length == 64)
return (v.match(/^[a-f0-9]{64}$/i) != null);
else
return (v.length >= 8) && (v.length <= 63);
},
'range': function(min, max) {
var val = Dec(this);
return (val >= +min && val <= +max);
},
'min': function(min) {
return (Dec(this) >= +min);
},
'max': function(max) {
return (Dec(this) <= +max);
},
'irange': function(min, max) {
var val = Int(this);
return (val >= +min && val <= +max);
},
'imin': function(min) {
return (Int(this) >= +min);
},
'imax': function(max) {
return (Int(this) <= +max);
},
'minlength': function(min) {
return ((''+this).length >= +min);
},
'maxlength': function(max) {
return ((''+this).length <= +max);
},
};
function compile(type) {
var v, match;
if ((match = type.match(/^([^\(]+)\(([^,]+),([^\)]+)\)$/)) && (v = validators[match[1]]) !== undefined) {
return function() {
return v.apply(this, [match[2], match[3]]);
}
} else if ((match = type.match(/^([^\(]+)\(([^,\)]+)\)$/)) && (v = validators[match[1]]) !== undefined) {
return function() {
return v.apply(this, [match[2]]);
}
} else {
return validators[type];
}
}
function checkvalue(target, ref) {
var t = document.getElementById(target);
var value;
if (t) {
if (t.type == "checkbox") {
value = t.checked;
} else if (t.value) {
value = t.value;
} else {
value = "";
}
return (value == ref);
} else {
t = document.getElementById(target + '.' + ref);
if (t)
return (t.type == "radio" && t.checked);
}
return false;
}
function check(deps) {
for (var i=0; i < deps.length; i++) {
var stat = true;
for (var j in deps[i]) {
stat = (stat && checkvalue(j, deps[i][j]));
}
if (stat)
return true;
}
return false;
}
function update() {
window.dispatchEvent(new Event('gluon-update'));
var state = false;
for (var id in dep_entries) {
var entry = dep_entries[id];
var node = document.getElementById(id);
var parent = document.getElementById(entry.parent);
if (node && node.parentNode && !check(entry.deps)) {
node.parentNode.removeChild(node);
node.dispatchEvent(new Event('gluon-hide'));
state = true;
} else if (parent && (!node || !node.parentNode) && check(entry.deps)) {
var next = undefined;
for (next = parent.firstChild; next; next = next.nextSibling) {
if (next.getAttribute && parseInt(next.getAttribute('data-index'), 10) > entry.index) {
break;
}
}
if (!next) {
parent.appendChild(entry.node);
} else {
parent.insertBefore(entry.node, next);
}
entry.node.dispatchEvent(new Event('gluon-show'));
state = true;
}
// hide optionals widget if no choices remaining
if (parent && parent.parentNode && parent.getAttribute('data-optionals'))
parent.parentNode.style.display = (parent.options.length <= 1) ? 'none' : '';
}
if (state) {
update();
}
}
function bind(obj, type, callback, mode) {
if (!obj.addEventListener) {
obj.attachEvent('on' + type,
function() {
var e = window.event;
if (!e.target && e.srcElement)
e.target = e.srcElement;
return !!callback(e);
}
);
} else {
obj.addEventListener(type, callback, !!mode);
}
return obj;
}
function init_dynlist(parent, attr) {
var prefix = attr.prefix;
function dynlist_redraw(focus, add, del) {
var values = [];
while (parent.firstChild) {
var n = parent.firstChild;
var i = +n.index;
if (i != del) {
if (n.nodeName.toLowerCase() == 'input')
values.push(n.value || '');
else if (n.nodeName.toLowerCase() == 'select')
values[values.length-1] = n.options[n.selectedIndex].value;
}
parent.removeChild(n);
}
if (add >= 0) {
focus = add + 1;
values.splice(add, 0, '');
} else if (!attr.optional && values.length == 0) {
values.push('');
}
for (var i = 1; i <= values.length; i++) {
var t = document.createElement('input');
t.id = prefix + '.' + i;
t.name = prefix;
t.value = values[i-1];
t.type = 'text';
t.index = i;
t.className = 'gluon-input-text';
if (attr.size)
t.size = attr.size;
if (attr.placeholder)
t.placeholder = attr.placeholder;
parent.appendChild(t);
if (attr.type)
validate_field(t, false, attr.type);
bind(t, 'keydown', dynlist_keydown);
bind(t, 'keypress', dynlist_keypress);
if (i == focus) {
t.focus();
} else if (-i == focus) {
t.focus();
/* force cursor to end */
var v = t.value;
t.value = ' '
t.value = v;
}
if (attr.optional || values.length > 1) {
var b = document.createElement('span');
b.className = 'gluon-remove';
parent.appendChild(b);
bind(b, 'click', dynlist_btnclick(false));
parent.appendChild(document.createElement('br'));
}
}
var b = document.createElement('span');
b.className = 'gluon-add';
parent.appendChild(b);
bind(b, 'click', dynlist_btnclick(true));
}
function dynlist_keypress(ev) {
ev = ev ? ev : window.event;
var se = ev.target ? ev.target : ev.srcElement;
if (se.nodeType == 3)
se = se.parentNode;
switch (ev.keyCode) {
/* backspace, delete */
case 8:
case 46:
if (se.value.length == 0) {
if (ev.preventDefault)
ev.preventDefault();
return false;
}
return true;
/* enter, arrow up, arrow down */
case 13:
case 38:
case 40:
if (ev.preventDefault)
ev.preventDefault();
return false;
}
return true;
}
function dynlist_keydown(ev) {
ev = ev ? ev : window.event;
var se = ev.target ? ev.target : ev.srcElement;
var index = 0;
var prev, next;
if (se) {
if (se.nodeType == 3)
se = se.parentNode;
index = se.index;
prev = se.previousSibling;
while (prev && prev.name != prefix)
prev = prev.previousSibling;
next = se.nextSibling;
while (next && next.name != prefix)
next = next.nextSibling;
}
switch (ev.keyCode) {
/* backspace, delete */
case 8:
case 46:
var del = (se.nodeName.toLowerCase() == 'select')
? true : (se.value.length == 0);
if (del) {
if (ev.preventDefault)
ev.preventDefault();
var focus = se.index;
if (ev.keyCode == 8)
focus = -focus+1;
dynlist_redraw(focus, -1, index);
return false;
}
break;
/* enter */
case 13:
dynlist_redraw(-1, index, -1);
break;
/* arrow up */
case 38:
if (prev)
prev.focus();
break;
/* arrow down */
case 40:
if (next)
next.focus();
break;
}
return true;
}
function dynlist_btnclick(add) {
return function(ev) {
ev = ev ? ev : window.event;
var se = ev.target ? ev.target : ev.srcElement;
var input = se.previousSibling;
while (input && input.name != prefix) {
input = input.previousSibling;
}
if (add) {
dynlist_keydown({
target: input,
keyCode: 13
});
} else {
input.value = '';
dynlist_keydown({
target: input,
keyCode: 8
});
}
return false;
}
}
dynlist_redraw(NaN, -1, -1);
}
function validate_field(field, optional, type) {
var check = compile(type);
if (!check)
return;
var validator = function() {
if (!field.form)
return;
field.className = field.className.replace(/ gluon-input-invalid/g, '');
var value = (field.options && field.options.selectedIndex > -1)
? field.options[field.options.selectedIndex].value : field.value;
if (!(((value.length == 0) && optional) || check.apply(value)))
field.className += ' gluon-input-invalid';
};
bind(field, "blur", validator);
bind(field, "keyup", validator);
bind(field, "gluon-revalidate", validator);
if (field.nodeName.toLowerCase() == 'select') {
bind(field, "change", validator);
bind(field, "click", validator);
}
validator();
}
function add(obj, dep, index) {
var entry = dep_entries[obj.id];
if (!entry) {
entry = {
"node": obj,
"parent": obj.parentNode.id,
"deps": [],
"index": index
};
dep_entries[obj.id] = entry;
}
entry.deps.push(dep)
}
(function() {
var nodes;
nodes = document.querySelectorAll('[data-depends]');
for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
var index = parseInt(node.getAttribute('data-index'), 10);
var depends = JSON.parse(node.getAttribute('data-depends'));
if (!isNaN(index) && depends.length > 0) {
for (var alt = 0; alt < depends.length; alt++) {
add(node, depends[alt], index);
}
}
}
nodes = document.querySelectorAll('[data-update]');
for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
var events = node.getAttribute('data-update').split(' ');
for (var j = 0, event; (event = events[j]) !== undefined; j++) {
bind(node, event, function () {setTimeout(update, 0);});
}
}
nodes = document.querySelectorAll('[data-type]');
for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
validate_field(node, node.getAttribute('data-optional') === 'true',
node.getAttribute('data-type'));
}
nodes = document.querySelectorAll('[data-dynlist]');
for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
var attr = JSON.parse(node.getAttribute('data-dynlist'));
init_dynlist(node, attr);
}
update();
})();
})();