/* Copyright 2008 Steven Barth Copyright 2008-2012 Jo-Philipp Wich Copyright 2017 Matthias Schiffer 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 javascript/gluon-web-model.min.js -c -m --ie */ (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; 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(); })(); })();