1 /**
    2  * Top-level namespace of these objects.
    3  * @namespace
    4  */
    5 var kwebapp;
    6 (function(kwebapp) {
    7 	'use strict';
    8 
    9 	function _strlang(vals)
   10 	{
   11 		var lang;
   12 		lang = document.documentElement.lang;
   13 		if (null !== lang && lang in vals)
   14 			return vals[lang];
   15 		else if ('_default' in vals)
   16 			return vals['_default'];
   17 		else
   18 			return '';
   19 	}
   20 
   21 	function _replcllang(e, name, vals)
   22 	{
   23 		_replcl(e, name, _strlang(vals), false);
   24 	}
   25 
   26 	function _attr(e, attr, text)
   27 	{
   28 		if (null !== e)
   29 			e.setAttribute(attr, text);
   30 	}
   31 
   32 	function _rattr(e, attr)
   33 	{
   34 		if (null !== e)
   35 			e.removeAttribute(attr);
   36 	}
   37 
   38 	/**
   39 	 * Internal function for checking inputs for all elements of class 
   40 	 * strct-name-value-checked whose value matches the object's value. 
   41 	 * If the object is null, all elements are unchecked.
   42 	 * @param {HTMLElement} e - The root of the DOM tree in which we 
   43 	 * query for elements to fill into.
   44 	 * @param {String} strct - The name of the structure that we're 
   45 	 * filling in.
   46 	 * @param {String} name - The name of the field.
   47 	 * @param {Number|String|null} obj - The data itself.
   48 	 * @param {Boolean} inc - Whether to include the root element in 
   49 	 * looking for elements to fill.
   50 	 * @private
   51 	 * @function _fillValueChecked
   52 	 * @memberof kwebapp
   53 	 */
   54 	function _fillValueChecked(e, fname, val, inc)
   55 	{
   56 		var list;
   57 		var i;
   58 		var valstr;
   59 		fname += '-value-checked';
   60 		valstr = null === val ? null : 
   61 			("number" === typeof val ? val.toString() : val);
   62 		list = _elemList(e, fname, inc);
   63 		for (i = 0; i < list.length; i++)
   64 			if (valstr === null)
   65 				_rattr(list[i], 'checked');
   66 			else if (valstr === (list[i]).value)
   67 				_attr(list[i], 'checked', 'true');
   68 			else
   69 				_rattr(list[i], 'checked');
   70 	}
   71 
   72 	/**
   73 	 * Internal function that takes all <code>&lt;option&gt;</code> 
   74 	 * elements in the root and sets or unsets their 
   75 	 * <code>selected</code> status depending upon whether it matches the 
   76 	 * object's value.
   77 	 * @param {HTMLElement} e - The root of the DOM tree in which we 
   78 	 * query for elements to fill into.
   79 	 * @param {Number|String} val - The object's 
   80 	 * value.
   81 	 * @private
   82 	 * @function _fillValueSelect
   83 	 * @memberof kwebapp
   84 	 */
   85 	function _fillValueSelect(e, val)
   86 	{
   87 		var list;
   88 		var i;
   89 		var v;
   90 		if (null === e)
   91 			return;
   92 		list = e.getElementsByTagName('option');
   93 		for (i = 0; i < list.length; i++) {
   94 			v = 'number' === typeof val ? 
   95 			     parseInt((list[i]).value) :
   96 			     (list[i]).value;
   97 			if (val === v)
   98 				_attr(list[i], 'selected', 'true');
   99 			else
  100 				_rattr(list[i], 'selected');
  101 		}
  102 	}
  103 
  104 	function _attrcl(e, attr, name, text, inc)
  105 	{
  106 		var list;
  107 		var i;
  108 		if (null === e)
  109 			return;
  110 		list = _elemList(e, name, inc);
  111 		for (i = 0; i < list.length; i++)
  112 			_attr(list[i], attr, text);
  113 	}
  114 
  115 	function _elemList(e, cls, inc)
  116 	{
  117 		var a;
  118 		var list;
  119 		var i;
  120 		a = [];
  121 		if (null === e)
  122 			return a;
  123 		list = e.getElementsByClassName(cls);
  124 		for (i = 0; i < list.length; i++)
  125 			a.push(list[i]);
  126 		if (inc && e.classList.contains(cls))
  127 			a.push(e);
  128 		return a;
  129 	}
  130 
  131 	function _repl(e, text)
  132 	{
  133 		if (null === e)
  134 			return;
  135 		while (e.firstChild)
  136 			e.removeChild(e.firstChild);
  137 		e.appendChild(document.createTextNode(text));
  138 	}
  139 
  140 	/**
  141 	 * Internal function for filling in ISO-8601 dates.
  142 	 * @param {HTMLElement} e - The root of the DOM tree in which we 
  143 	 * query for elements to fill into.
  144 	 * @param {String} strct - The name of the structure that we're 
  145 	 * filling in.
  146 	 * @param {String} name - The name of the field.
  147 	 * @param {Number|null} obj - The data itself.
  148 	 * @param {Boolean} inc - Whether to include the root element in 
  149 	 * looking for elements to fill.
  150 	 * @private
  151 	 * @function _fillDateValue
  152 	 * @memberof kwebapp
  153 	 */
  154 	function _fillDateValue(e, strct, name, val, inc)
  155 	{
  156 		var fname;
  157 		var year;
  158 		var mo;
  159 		var day;
  160 		var full;
  161 		var d;
  162 		if (null === val)
  163 			return;
  164 		d = new Date();
  165 		d.setTime(val * 1000);
  166 		year = d.getFullYear();
  167 		mo = d.getMonth() + 1;
  168 		day = d.getDate();
  169 		full = year + '-' +
  170 			(mo < 10 ? '0' : '') + mo + '-' +
  171 			(day < 10 ? '0' : '') + day;
  172 		fname = strct + '-' + name + '-date-value';
  173 		_attrcl(e, 'value', fname, full, inc);
  174 		fname = strct + '-' + name + '-date-text';
  175 		_replcl(e, fname, full, inc);
  176 	}
  177 
  178 	/**
  179 	 * Internal function for checking inputs for all elements of class 
  180 	 * strct-name-bits-checked whose value is the bit-wise AND of the 
  181 	 * object's value. If the object is null, all elements are 
  182 	 * unchecked.
  183 	 * @param {HTMLElement} e - The root of the DOM tree in which we 
  184 	 * query for elements to fill into.
  185 	 * @param {String} strct - The name of the structure that we're 
  186 	 * filling in.
  187 	 * @param {String} name - The name of the field.
  188 	 * @param {Number|null} obj - The data itself.
  189 	 * @param {Boolean} inc - Whether to include the root element in 
  190 	 * looking for elements to fill.
  191 	 * @private
  192 	 * @function _fillBitsChecked
  193 	 * @memberof kwebapp
  194 	 */
  195 	function _fillBitsChecked(e, strct, name, val, inc)
  196 	{
  197 		var list;
  198 		var fname;
  199 		var i;
  200 		var v;
  201 		fname = strct + '-' + name + '-bits-checked';
  202 		list = _elemList(e, fname, inc);
  203 		for (i = 0; i < list.length; i++) {
  204 			if (val === null) {
  205 				_rattr(list[i], 'checked');
  206 				continue;
  207 			}
  208 			v = parseInt((list[i]).value);
  209 			if (isNaN(v))
  210 				_rattr(list[i], 'checked');
  211 			else if (0 === v && 0 === val)
  212 				_attr(list[i], 'checked', 'true');
  213 			else if ((1 << (v - 1)) & val)
  214 				_attr(list[i], 'checked', 'true');
  215 			else
  216 				_rattr(list[i], 'checked');
  217 		}
  218 	}
  219 
  220 	/**
  221 	 * Internal function for filling a structure field.
  222 	 * @param {HTMLElement} e - The root of the DOM tree in which we 
  223 	 * query for elements to fill into.
  224 	 * @param {String} strct - The name of the structure that we're 
  225 	 * filling in.
  226 	 * @param {String} name - The name of the field.
  227 	 * @param {kwebapp.DataCallbacks|null} funcs - Custom callback 
  228 	 * functions to invoke on the field.
  229 	 * @param obj - The data itself, which is either a native type or one 
  230 	 * of the data interfaces for an application-specific type.
  231 	 * @param {Boolean} inc - Whether to include the root element in 
  232 	 * looking for elements to fill. Note that nested structures are 
  233 	 * alwyas filled non-inclusively.
  234 	 * @param {Boolean} cannull - Whether the data object might be 
  235 	 * null.
  236 	 * @param {Boolean} isblob - Whether the data object is a 
  237 	 * blob.
  238 	 * @param sub - If the data object is a nested structure interface, 
  239 	 * this is the allocated class of that interface.
  240 	 * @private
  241 	 * @function _fillfield
  242 	 * @memberof kwebapp
  243 	 */
  244 	function _fillfield(e, strct, name, funcs, obj, inc, cannull, isblob, sub)
  245 	{
  246 		var i;
  247 		var fname;
  248 		var list;
  249 		fname = strct + '-' + name;
  250 		/* First handle the custom callback. */
  251 		if (null !== funcs && fname in funcs) {
  252 			if (funcs[fname] instanceof Array) {
  253 				for (i = 0; i < funcs[fname].length; i++)
  254 					funcs[fname][i](e, fname, obj);
  255 			} else {
  256 				funcs[fname](e, fname, obj);
  257 			}
  258 		}
  259 		/* Now handle our has/no null situation. */
  260 		if (cannull) {
  261 			if (null === obj) {
  262 				_hidecl(e, strct + '-has-' + name, inc);
  263 				_showcl(e, strct + '-no-' + name, inc);
  264 			} else {
  265 				_showcl(e, strct + '-has-' + name, inc);
  266 				_hidecl(e, strct + '-no-' + name, inc);
  267 			}
  268 		}
  269 		/* Don't account for blobs any more. */
  270 		if (isblob)
  271 			return;
  272 		/* Don't process null values that can be null. */
  273 		if (cannull && null === obj)
  274 			return;
  275 		/* Non-null non-structs. */
  276 		if (null !== sub) {
  277 			list = _elemList(e, fname + '-obj', inc);
  278 			for (i = 0; i < list.length; i++) {
  279 				sub.fillInner(list[i], funcs);
  280 			}
  281 		} else {
  282 			list = _elemList(e, fname + '-enum-select', inc);
  283 			for (i = 0; i < list.length; i++) {
  284 				_fillValueSelect(list[i], obj);
  285 			}
  286 			_replcl(e, fname + '-text', obj, inc);
  287 			_attrcl(e, 'value', fname + '-value', obj, inc);
  288 			_fillValueChecked(e, fname, obj, inc);
  289 		}
  290 	}
  291 
  292 	function _replcl(e, name, text, inc)
  293 	{
  294 		var list;
  295 		var i;
  296 		if (null === e)
  297 			return;
  298 		list = _elemList(e, name, inc);
  299 		for (i = 0; i < list.length; i++)
  300 			_repl(list[i], text);
  301 	}
  302 
  303 	function _classadd(e, name)
  304 	{
  305 		if (null === e)
  306 			return(null);
  307 		if ( ! e.classList.contains(name))
  308 			e.classList.add(name);
  309 		return(e);
  310 	}
  311 
  312 	function _classaddcl(e, name, cls, inc)
  313 	{
  314 		var list;
  315 		var i;
  316 		if (null === e)
  317 			return;
  318 		list = _elemList(e, name, inc);
  319 		for (i = 0; i < list.length; i++)
  320 			_classadd(list[i], cls);
  321 	}
  322 
  323 	function _hide(e)
  324 	{
  325 		if (null === e)
  326 			return null;
  327 		if ( ! e.classList.contains('hide'))
  328 			e.classList.add('hide');
  329 		return e;
  330 	}
  331 
  332 	function _hidecl(e, name, inc)
  333 	{
  334 		var list;
  335 		var i;
  336 		if (null === e)
  337 			return;
  338 		list = _elemList(e, name, inc);
  339 		for (i = 0; i < list.length; i++)
  340 			_hide(list[i]);
  341 	}
  342 
  343 	function _show(e)
  344 	{
  345 		if (null === e)
  346 			return null;
  347 		if (e.classList.contains('hide'))
  348 			e.classList.remove('hide');
  349 		return e;
  350 	}
  351 
  352 	function _showcl(e, name, inc)
  353 	{
  354 		var list;
  355 		var i;
  356 		if (null === e)
  357 			return;
  358 		list = _elemList(e, name, inc);
  359 		for (i = 0; i < list.length; i++)
  360 			_show(list[i]);
  361 	}
  362 
  363 	/**
  364 	 * All possible callback functions for passing to the "custom" 
  365 	 * associative array when filling in DOM trees.
  366 	 * @interface kwebapp.DataCallbacks
  367 	 */
  368 	/**
  369 	 * 
  370 	 * Controlling organisation.<br/>
  371 	 * 
  372 	 * @interface kwebapp.companyData
  373 	 */
  374 	/**
  375 	 * 
  376 	 * A regular user.<br/>
  377 	 * 
  378 	 * @interface kwebapp.userData
  379 	 */
  380 	/**
  381 	 * 
  382 	 * Authenticated session.<br/>
  383 	 * 
  384 	 * @interface kwebapp.sessionData
  385 	 */
  386 	/**
  387 	 * Accepts {@link kwebapp.companyData} for writing into a DOM 
  388 	 * tree.
  389 	 * @param {(kwebapp.companyData|kwebapp.companyData[])} obj - The 
  390 	 * object(s) to write.
  391 	 * @memberof kwebapp
  392 	 * @constructor
  393 	 * @class
  394 	 */
  395 	var company = (function()
  396 	{
  397 		function company(o)
  398 		{
  399 			this.obj = o;
  400 		}
  401 		/**
  402 		 * Write the {@link kwebapp.companyData} into the given 
  403 		 * HTMLElement in the DOM tree.
  404 		 * If constructed with an array, the first element is 
  405 		 * used.
  406 		 * Elements within (and including) "e" having the following 
  407 		 * classes are manipulated as follows:
  408 		 * <ul>
  409 		 * <li>company-name-enum-select: sets the <code>select</code> 
  410 		 * attribute for <code>&lt;option&gt;</code> values matching 
  411 		 * <i>name</i> under the element</li>
  412 		 * <li>company-name-value-checked: sets the <code>checked</code> 
  413 		 * attribute under the element matching the input</li>
  414 		 * <li>company-name-text: replace contents with <i>name</i> 
  415 		 * data</li>
  416 		 * <li>company-name-value: replace <code>value</code> attribute 
  417 		 * with <i>name</i> data</li>
  418 		 * <li>company-id-enum-select: sets the <code>select</code> 
  419 		 * attribute for <code>&lt;option&gt;</code> values matching 
  420 		 * <i>id</i> under the element</li>
  421 		 * <li>company-id-value-checked: sets the <code>checked</code> 
  422 		 * attribute under the element matching the input</li>
  423 		 * <li>company-id-text: replace contents with <i>id</i> data</li>
  424 		 * <li>company-id-value: replace <code>value</code> attribute 
  425 		 * with <i>id</i> data</li>
  426 		 * <li>company-has-somenum: <code>hide</code> class removed if 
  427 		 * <i>somenum</i> not null, otherwise <code>hide</code> class is 
  428 		 * added</li>
  429 		 * <li>company-no-somenum: <code>hide</code> class added if 
  430 		 * <i>somenum</i> not null, otherwise <code>hide</code> class is 
  431 		 * removed</li>
  432 		 * <li>company-somenum-enum-select: sets the <code>select</code> 
  433 		 * attribute for <code>&lt;option&gt;</code> values matching 
  434 		 * <i>somenum</i> under the element (if non-null)</li>
  435 		 * <li>company-somenum-value-checked: sets the 
  436 		 * <code>checked</code> attribute under the element matching the 
  437 		 * input (if non-null)</li>
  438 		 * <li>company-somenum-text: replace contents with <i>somenum</i> 
  439 		 * data (if non-null)</li>
  440 		 * <li>company-somenum-value: replace <code>value</code> 
  441 		 * attribute with <i>somenum</i> data (if non-null)</li>
  442 		 * </ul>
  443 		 * @param {HTMLElement} e - The DOM element.
  444 		 * @param {kwebapp.DataCallbacks} custom - The optional 
  445 		 * dictionary of functions keyed by structure and field name 
  446 		 * (e.g., <i>foo</i> structure, <i>bar</i> field would be 
  447 		 * <code>foo-bar</code>). The value is a function for custom 
  448 		 * handling that accepts the "e" value, the name of the 
  449 		 * structure-field, and the value of the structure and field.
  450 		 * You may also specify an array of functions instead of a 
  451 		 * singleton.
  452 		 * @function fill
  453 		 * @memberof kwebapp.company#
  454 		 */
  455 		company.prototype.fill = function(e, custom)
  456 		{
  457 			this._fill(e, this.obj, true, custom);
  458 		};
  459 
  460 		/**
  461 		 * Like {@link kwebapp.company#fill} but not including the root 
  462 		 * element "e".
  463 		 * @param {HTMLElement} e - The DOM element.
  464 		 * @param {kwebapp.DataCallbacks} custom - The optional custom 
  465 		 * handler dictionary (see {@link kwebapp.company#fill} for 
  466 		 * details).
  467 		 * @function fillInner
  468 		 * @memberof kwebapp.company#
  469 		 */
  470 		company.prototype.fillInner = function(e, custom)
  471 		{
  472 			this._fill(e, this.obj, false, custom);
  473 		};
  474 
  475 		/**
  476 		 * Implements all {@link kwebapp.company#fill} functions.
  477 		 * @param {HTMLElement} e - The DOM element.
  478 		 * @param {kwebapp.companyData|kwebapp.companyData[]|null} o - 
  479 		 * The object (or array) to fill.
  480 		 * @param {Number} inc - Whether to include the root or not when 
  481 		 * processing.
  482 		 * @param {kwebapp.DataCallbacks} custom - The optional custom 
  483 		 * handler dictionary (see {@link 
  484 		 * kwebapp.company#fill}).
  485 		 * @private
  486 		 * @function _fill
  487 		 * @memberof kwebapp.company#
  488 		 */
  489 		company.prototype._fill = function(e, o, inc, custom)
  490 		{
  491 			var i;
  492 			if (null === o || null === e)
  493 				return;
  494 			if (o instanceof Array) {
  495 				if (0 === o.length)
  496 					return;
  497 				o = o[0];
  498 			}
  499 			if (typeof custom === 'undefined')
  500 				custom = null;
  501 			if (null !== custom && 'company' in custom) {
  502 				if (custom['company'] instanceof Array) {
  503 					for (i = 0; i < custom['company'].length; i++)
  504 						(custom['company'])[i](e, 'company', o);
  505 				} else {
  506 					(custom['company'])(e, 'company', o);
  507 				}
  508 			}
  509 			_fillfield(e, 'company', 'name', custom, o.name, inc, false, false, null);
  510 			_fillfield(e, 'company', 'id', custom, o.id, inc, false, false, null);
  511 			_fillfield(e, 'company', 'somenum', custom, o.somenum, inc, true, false, null);
  512 		};
  513 
  514 		/**
  515 		 * Like {@link kwebapp.company#fill} but for an array of {@link 
  516 		 * kwebapp.companyData}.
  517 		 * This will save the first element within "e", remove all 
  518 		 * children of "e", then repeatedly clone the saved element and 
  519 		 * re-append it, filling in the cloned subtree with the array 
  520 		 * (inclusive of the subtree root).
  521 		 * If "e" is not an array, it is construed as an array of one.
  522 		 * If the input array is empty, "e" is hidden by using the 
  523 		 * <code>hide</code> class.
  524 		 * Otherwise, the <code>hide</code> class is removed.
  525 		 * @param {HTMLElement} e - The DOM element.
  526 		 * @param {kwebapp.DataCallbacks} custom - The optional custom 
  527 		 * handler dictionary (see {@link 
  528 		 * kwebapp.company#fill}).
  529 		 * @memberof kwebapp.company#
  530 		 * @function fillArray
  531 		 */
  532 		company.prototype.fillArray = function(e, custom)
  533 		{
  534 			var j;
  535 			var o;
  536 			var cln;
  537 			var ar;
  538 			var row;
  539 			o = this.obj;
  540 			if (null === o || null === e)
  541 				return;
  542 			if ( ! (o instanceof Array)) {
  543 				ar = [];
  544 				ar.push(o);
  545 				o = ar;
  546 			}
  547 			if (0 === o.length) {
  548 				_hide(e);
  549 				return;
  550 			}
  551 			_show(e);
  552 			row = e.children[0];
  553 			if (null === row)
  554 				return;
  555 			e.removeChild(row);
  556 			while (null !== e.firstChild)
  557 				e.removeChild(e.firstChild)
  558 			for (j = 0; j < o.length; j++) {
  559 				cln = row.cloneNode(true);
  560 				e.appendChild(cln);
  561 				this._fill(cln, o[j], true, custom);
  562 			}
  563 		};
  564 		return company;
  565 	}());
  566 	kwebapp.company = company;
  567 
  568 	/**
  569 	 * Accepts {@link kwebapp.userData} for writing into a DOM 
  570 	 * tree.
  571 	 * @param {(kwebapp.userData|kwebapp.userData[])} obj - The object(s) 
  572 	 * to write.
  573 	 * @memberof kwebapp
  574 	 * @constructor
  575 	 * @class
  576 	 */
  577 	var user = (function()
  578 	{
  579 		function user(o)
  580 		{
  581 			this.obj = o;
  582 		}
  583 		/**
  584 		 * Write the {@link kwebapp.userData} into the given HTMLElement 
  585 		 * in the DOM tree.
  586 		 * If constructed with an array, the first element is 
  587 		 * used.
  588 		 * Elements within (and including) "e" having the following 
  589 		 * classes are manipulated as follows:
  590 		 * <ul>
  591 		 * <li>user-company-obj: invoke {@link kwebapp.company#fillInner} 
  592 		 * with company data</li>
  593 		 * <li>user-cid-enum-select: sets the <code>select</code> 
  594 		 * attribute for <code>&lt;option&gt;</code> values matching 
  595 		 * <i>cid</i> under the element</li>
  596 		 * <li>user-cid-value-checked: sets the <code>checked</code> 
  597 		 * attribute under the element matching the input</li>
  598 		 * <li>user-cid-text: replace contents with <i>cid</i> data</li>
  599 		 * <li>user-cid-value: replace <code>value</code> attribute with 
  600 		 * <i>cid</i> data</li>
  601 		 * <li>user-sex-enum-select: sets the <code>select</code> 
  602 		 * attribute for <code>&lt;option&gt;</code> values matching 
  603 		 * <i>sex</i> under the element</li>
  604 		 * <li>user-sex-value-checked: sets the <code>checked</code> 
  605 		 * attribute under the element matching the input</li>
  606 		 * <li>user-sex-text: replace contents with <i>sex</i> data</li>
  607 		 * <li>user-sex-value: replace <code>value</code> attribute with 
  608 		 * <i>sex</i> data</li>
  609 		 * <li>user-hash-enum-select: sets the <code>select</code> 
  610 		 * attribute for <code>&lt;option&gt;</code> values matching 
  611 		 * <i>hash</i> under the element</li>
  612 		 * <li>user-hash-value-checked: sets the <code>checked</code> 
  613 		 * attribute under the element matching the input</li>
  614 		 * <li>user-hash-text: replace contents with <i>hash</i> 
  615 		 * data</li>
  616 		 * <li>user-hash-value: replace <code>value</code> attribute with 
  617 		 * <i>hash</i> data</li>
  618 		 * <li>user-email-enum-select: sets the <code>select</code> 
  619 		 * attribute for <code>&lt;option&gt;</code> values matching 
  620 		 * <i>email</i> under the element</li>
  621 		 * <li>user-email-value-checked: sets the <code>checked</code> 
  622 		 * attribute under the element matching the input</li>
  623 		 * <li>user-email-text: replace contents with <i>email</i> 
  624 		 * data</li>
  625 		 * <li>user-email-value: replace <code>value</code> attribute 
  626 		 * with <i>email</i> data</li>
  627 		 * <li>user-name-enum-select: sets the <code>select</code> 
  628 		 * attribute for <code>&lt;option&gt;</code> values matching 
  629 		 * <i>name</i> under the element</li>
  630 		 * <li>user-name-value-checked: sets the <code>checked</code> 
  631 		 * attribute under the element matching the input</li>
  632 		 * <li>user-name-text: replace contents with <i>name</i> 
  633 		 * data</li>
  634 		 * <li>user-name-value: replace <code>value</code> attribute with 
  635 		 * <i>name</i> data</li>
  636 		 * <li>user-uid-enum-select: sets the <code>select</code> 
  637 		 * attribute for <code>&lt;option&gt;</code> values matching 
  638 		 * <i>uid</i> under the element</li>
  639 		 * <li>user-uid-value-checked: sets the <code>checked</code> 
  640 		 * attribute under the element matching the input</li>
  641 		 * <li>user-uid-text: replace contents with <i>uid</i> data</li>
  642 		 * <li>user-uid-value: replace <code>value</code> attribute with 
  643 		 * <i>uid</i> data</li>
  644 		 * </ul>
  645 		 * @param {HTMLElement} e - The DOM element.
  646 		 * @param {kwebapp.DataCallbacks} custom - The optional 
  647 		 * dictionary of functions keyed by structure and field name 
  648 		 * (e.g., <i>foo</i> structure, <i>bar</i> field would be 
  649 		 * <code>foo-bar</code>). The value is a function for custom 
  650 		 * handling that accepts the "e" value, the name of the 
  651 		 * structure-field, and the value of the structure and field.
  652 		 * You may also specify an array of functions instead of a 
  653 		 * singleton.
  654 		 * @function fill
  655 		 * @memberof kwebapp.user#
  656 		 */
  657 		user.prototype.fill = function(e, custom)
  658 		{
  659 			this._fill(e, this.obj, true, custom);
  660 		};
  661 
  662 		/**
  663 		 * Like {@link kwebapp.user#fill} but not including the root 
  664 		 * element "e".
  665 		 * @param {HTMLElement} e - The DOM element.
  666 		 * @param {kwebapp.DataCallbacks} custom - The optional custom 
  667 		 * handler dictionary (see {@link kwebapp.user#fill} for 
  668 		 * details).
  669 		 * @function fillInner
  670 		 * @memberof kwebapp.user#
  671 		 */
  672 		user.prototype.fillInner = function(e, custom)
  673 		{
  674 			this._fill(e, this.obj, false, custom);
  675 		};
  676 
  677 		/**
  678 		 * Implements all {@link kwebapp.user#fill} functions.
  679 		 * @param {HTMLElement} e - The DOM element.
  680 		 * @param {kwebapp.userData|kwebapp.userData[]|null} o - The 
  681 		 * object (or array) to fill.
  682 		 * @param {Number} inc - Whether to include the root or not when 
  683 		 * processing.
  684 		 * @param {kwebapp.DataCallbacks} custom - The optional custom 
  685 		 * handler dictionary (see {@link 
  686 		 * kwebapp.user#fill}).
  687 		 * @private
  688 		 * @function _fill
  689 		 * @memberof kwebapp.user#
  690 		 */
  691 		user.prototype._fill = function(e, o, inc, custom)
  692 		{
  693 			var i;
  694 			if (null === o || null === e)
  695 				return;
  696 			if (o instanceof Array) {
  697 				if (0 === o.length)
  698 					return;
  699 				o = o[0];
  700 			}
  701 			if (typeof custom === 'undefined')
  702 				custom = null;
  703 			if (null !== custom && 'user' in custom) {
  704 				if (custom['user'] instanceof Array) {
  705 					for (i = 0; i < custom['user'].length; i++)
  706 						(custom['user'])[i](e, 'user', o);
  707 				} else {
  708 					(custom['user'])(e, 'user', o);
  709 				}
  710 			}
  711 			_fillfield(e, 'user', 'company', custom, o.company, inc, false, false, new company(o.company));
  712 			_fillfield(e, 'user', 'cid', custom, o.cid, inc, false, false, null);
  713 			_fillfield(e, 'user', 'sex', custom, o.sex, inc, false, false, null);
  714 			_fillfield(e, 'user', 'hash', custom, o.hash, inc, false, false, null);
  715 			_fillfield(e, 'user', 'email', custom, o.email, inc, false, false, null);
  716 			_fillfield(e, 'user', 'name', custom, o.name, inc, false, false, null);
  717 			_fillfield(e, 'user', 'uid', custom, o.uid, inc, false, false, null);
  718 		};
  719 
  720 		/**
  721 		 * Like {@link kwebapp.user#fill} but for an array of {@link 
  722 		 * kwebapp.userData}.
  723 		 * This will save the first element within "e", remove all 
  724 		 * children of "e", then repeatedly clone the saved element and 
  725 		 * re-append it, filling in the cloned subtree with the array 
  726 		 * (inclusive of the subtree root).
  727 		 * If "e" is not an array, it is construed as an array of one.
  728 		 * If the input array is empty, "e" is hidden by using the 
  729 		 * <code>hide</code> class.
  730 		 * Otherwise, the <code>hide</code> class is removed.
  731 		 * @param {HTMLElement} e - The DOM element.
  732 		 * @param {kwebapp.DataCallbacks} custom - The optional custom 
  733 		 * handler dictionary (see {@link kwebapp.user#fill}).
  734 		 * @memberof kwebapp.user#
  735 		 * @function fillArray
  736 		 */
  737 		user.prototype.fillArray = function(e, custom)
  738 		{
  739 			var j;
  740 			var o;
  741 			var cln;
  742 			var ar;
  743 			var row;
  744 			o = this.obj;
  745 			if (null === o || null === e)
  746 				return;
  747 			if ( ! (o instanceof Array)) {
  748 				ar = [];
  749 				ar.push(o);
  750 				o = ar;
  751 			}
  752 			if (0 === o.length) {
  753 				_hide(e);
  754 				return;
  755 			}
  756 			_show(e);
  757 			row = e.children[0];
  758 			if (null === row)
  759 				return;
  760 			e.removeChild(row);
  761 			while (null !== e.firstChild)
  762 				e.removeChild(e.firstChild)
  763 			for (j = 0; j < o.length; j++) {
  764 				cln = row.cloneNode(true);
  765 				e.appendChild(cln);
  766 				this._fill(cln, o[j], true, custom);
  767 			}
  768 		};
  769 		return user;
  770 	}());
  771 	kwebapp.user = user;
  772 
  773 	/**
  774 	 * Accepts {@link kwebapp.sessionData} for writing into a DOM 
  775 	 * tree.
  776 	 * @param {(kwebapp.sessionData|kwebapp.sessionData[])} obj - The 
  777 	 * object(s) to write.
  778 	 * @memberof kwebapp
  779 	 * @constructor
  780 	 * @class
  781 	 */
  782 	var session = (function()
  783 	{
  784 		function session(o)
  785 		{
  786 			this.obj = o;
  787 		}
  788 		/**
  789 		 * Write the {@link kwebapp.sessionData} into the given 
  790 		 * HTMLElement in the DOM tree.
  791 		 * If constructed with an array, the first element is 
  792 		 * used.
  793 		 * Elements within (and including) "e" having the following 
  794 		 * classes are manipulated as follows:
  795 		 * <ul>
  796 		 * <li>session-user-obj: invoke {@link kwebapp.user#fillInner} 
  797 		 * with user data</li>
  798 		 * <li>session-userid-enum-select: sets the <code>select</code> 
  799 		 * attribute for <code>&lt;option&gt;</code> values matching 
  800 		 * <i>userid</i> under the element</li>
  801 		 * <li>session-userid-value-checked: sets the 
  802 		 * <code>checked</code> attribute under the element matching the 
  803 		 * input</li>
  804 		 * <li>session-userid-text: replace contents with <i>userid</i> 
  805 		 * data</li>
  806 		 * <li>session-userid-value: replace <code>value</code> attribute 
  807 		 * with <i>userid</i> data</li>
  808 		 * <li>session-token-enum-select: sets the <code>select</code> 
  809 		 * attribute for <code>&lt;option&gt;</code> values matching 
  810 		 * <i>token</i> under the element</li>
  811 		 * <li>session-token-value-checked: sets the <code>checked</code> 
  812 		 * attribute under the element matching the input</li>
  813 		 * <li>session-token-text: replace contents with <i>token</i> 
  814 		 * data</li>
  815 		 * <li>session-token-value: replace <code>value</code> attribute 
  816 		 * with <i>token</i> data</li>
  817 		 * <li>session-mtime-enum-select: sets the <code>select</code> 
  818 		 * attribute for <code>&lt;option&gt;</code> values matching 
  819 		 * <i>mtime</i> under the element</li>
  820 		 * <li>session-mtime-value-checked: sets the <code>checked</code> 
  821 		 * attribute under the element matching the input</li>
  822 		 * <li>session-mtime-text: replace contents with <i>mtime</i> 
  823 		 * data</li>
  824 		 * <li>session-mtime-value: replace <code>value</code> attribute 
  825 		 * with <i>mtime</i> data</li>
  826 		 * <li>session-mtime-date-value: set the element's 
  827 		 * <code>value</code> to the ISO-8601 date format of the 
  828 		 * data</li>
  829 		 * <li>session-id-enum-select: sets the <code>select</code> 
  830 		 * attribute for <code>&lt;option&gt;</code> values matching 
  831 		 * <i>id</i> under the element</li>
  832 		 * <li>session-id-value-checked: sets the <code>checked</code> 
  833 		 * attribute under the element matching the input</li>
  834 		 * <li>session-id-text: replace contents with <i>id</i> data</li>
  835 		 * <li>session-id-value: replace <code>value</code> attribute 
  836 		 * with <i>id</i> data</li>
  837 		 * </ul>
  838 		 * @param {HTMLElement} e - The DOM element.
  839 		 * @param {kwebapp.DataCallbacks} custom - The optional 
  840 		 * dictionary of functions keyed by structure and field name 
  841 		 * (e.g., <i>foo</i> structure, <i>bar</i> field would be 
  842 		 * <code>foo-bar</code>). The value is a function for custom 
  843 		 * handling that accepts the "e" value, the name of the 
  844 		 * structure-field, and the value of the structure and field.
  845 		 * You may also specify an array of functions instead of a 
  846 		 * singleton.
  847 		 * @function fill
  848 		 * @memberof kwebapp.session#
  849 		 */
  850 		session.prototype.fill = function(e, custom)
  851 		{
  852 			this._fill(e, this.obj, true, custom);
  853 		};
  854 
  855 		/**
  856 		 * Like {@link kwebapp.session#fill} but not including the root 
  857 		 * element "e".
  858 		 * @param {HTMLElement} e - The DOM element.
  859 		 * @param {kwebapp.DataCallbacks} custom - The optional custom 
  860 		 * handler dictionary (see {@link kwebapp.session#fill} for 
  861 		 * details).
  862 		 * @function fillInner
  863 		 * @memberof kwebapp.session#
  864 		 */
  865 		session.prototype.fillInner = function(e, custom)
  866 		{
  867 			this._fill(e, this.obj, false, custom);
  868 		};
  869 
  870 		/**
  871 		 * Implements all {@link kwebapp.session#fill} functions.
  872 		 * @param {HTMLElement} e - The DOM element.
  873 		 * @param {kwebapp.sessionData|kwebapp.sessionData[]|null} o - 
  874 		 * The object (or array) to fill.
  875 		 * @param {Number} inc - Whether to include the root or not when 
  876 		 * processing.
  877 		 * @param {kwebapp.DataCallbacks} custom - The optional custom 
  878 		 * handler dictionary (see {@link 
  879 		 * kwebapp.session#fill}).
  880 		 * @private
  881 		 * @function _fill
  882 		 * @memberof kwebapp.session#
  883 		 */
  884 		session.prototype._fill = function(e, o, inc, custom)
  885 		{
  886 			var i;
  887 			if (null === o || null === e)
  888 				return;
  889 			if (o instanceof Array) {
  890 				if (0 === o.length)
  891 					return;
  892 				o = o[0];
  893 			}
  894 			if (typeof custom === 'undefined')
  895 				custom = null;
  896 			if (null !== custom && 'session' in custom) {
  897 				if (custom['session'] instanceof Array) {
  898 					for (i = 0; i < custom['session'].length; i++)
  899 						(custom['session'])[i](e, 'session', o);
  900 				} else {
  901 					(custom['session'])(e, 'session', o);
  902 				}
  903 			}
  904 			_fillfield(e, 'session', 'user', custom, o.user, inc, false, false, new user(o.user));
  905 			_fillfield(e, 'session', 'userid', custom, o.userid, inc, false, false, null);
  906 			_fillfield(e, 'session', 'token', custom, o.token, inc, false, false, null);
  907 			_fillfield(e, 'session', 'mtime', custom, o.mtime, inc, false, false, null);
  908 			_fillDateValue(e, 'session', 'mtime', o.mtime, inc);
  909 			_fillfield(e, 'session', 'id', custom, o.id, inc, false, false, null);
  910 		};
  911 
  912 		/**
  913 		 * Like {@link kwebapp.session#fill} but for an array of {@link 
  914 		 * kwebapp.sessionData}.
  915 		 * This will save the first element within "e", remove all 
  916 		 * children of "e", then repeatedly clone the saved element and 
  917 		 * re-append it, filling in the cloned subtree with the array 
  918 		 * (inclusive of the subtree root).
  919 		 * If "e" is not an array, it is construed as an array of one.
  920 		 * If the input array is empty, "e" is hidden by using the 
  921 		 * <code>hide</code> class.
  922 		 * Otherwise, the <code>hide</code> class is removed.
  923 		 * @param {HTMLElement} e - The DOM element.
  924 		 * @param {kwebapp.DataCallbacks} custom - The optional custom 
  925 		 * handler dictionary (see {@link 
  926 		 * kwebapp.session#fill}).
  927 		 * @memberof kwebapp.session#
  928 		 * @function fillArray
  929 		 */
  930 		session.prototype.fillArray = function(e, custom)
  931 		{
  932 			var j;
  933 			var o;
  934 			var cln;
  935 			var ar;
  936 			var row;
  937 			o = this.obj;
  938 			if (null === o || null === e)
  939 				return;
  940 			if ( ! (o instanceof Array)) {
  941 				ar = [];
  942 				ar.push(o);
  943 				o = ar;
  944 			}
  945 			if (0 === o.length) {
  946 				_hide(e);
  947 				return;
  948 			}
  949 			_show(e);
  950 			row = e.children[0];
  951 			if (null === row)
  952 				return;
  953 			e.removeChild(row);
  954 			while (null !== e.firstChild)
  955 				e.removeChild(e.firstChild)
  956 			for (j = 0; j < o.length; j++) {
  957 				cln = row.cloneNode(true);
  958 				e.appendChild(cln);
  959 				this._fill(cln, o[j], true, custom);
  960 			}
  961 		};
  962 		return session;
  963 	}());
  964 	kwebapp.session = session;
  965 
  966 	/**
  967 	 * Birthsex of individual<br/>
  968 	 * This object consists of all values for the <i>sex</i> 
  969 	 * enumeration.
  970 	 * It also contains a formatting function designed to work as a 
  971 	 * custom callback for <code>fill</code> functions.
  972 	 * All of these values are static: <strong>do not use the 
  973 	 * constructor</strong>.
  974 	 * @memberof kwebapp
  975 	 * @class
  976 	 */
  977 	var sex = (function()
  978 	{
  979 		function sex() { }
  980 		/**
  981 		 * Male<br/>
  982 		 * @memberof kwebapp.sex#
  983 		 * @readonly
  984 		 * @const {number} male
  985 		 */
  986 		sex.male = 0;
  987 		/**
  988 		 * Female<br/>
  989 		 * @memberof kwebapp.sex#
  990 		 * @readonly
  991 		 * @const {number} female
  992 		 */
  993 		sex.female = 1;
  994 		/**
  995 		 * Other<br/>
  996 		 * @memberof kwebapp.sex#
  997 		 * @readonly
  998 		 * @const {number} other
  999 		 */
 1000 		sex.other = 2;
 1001 		/**
 1002 		 * Uses the enumeration item's <i>jslabel</i> (or just the name, 
 1003 		 * if no <i>jslabel</i> is defined) to format a custom label as 
 1004 		 * invoked on an object's <code>fill</code> function. This will 
 1005 		 * act on <code>xxx-yyy-label</code> classes, where 
 1006 		 * <code>xxx</code> is the structure name and <code>yyy</code> is 
 1007 		 * the field name. For example, <code>xxx.fill(e, { 'xxx-yyy': 
 1008 		 * kwebapp.sex.format });</code>, where <code>yyy</code> is a 
 1009 		 * field of type <i>enum sex</i>.
 1010 		 * @static
 1011 		 * @function format
 1012 		 * @param {HTMLElement} e - The DOM element.
 1013 		 * @param {String} name - The class name root.
 1014 		 * @param {Number} v - The enumeration value.
 1015 		 * @memberof kwebapp.sex#
 1016 		 */
 1017 		sex.format = function(e, name, v)
 1018 		{
 1019 			name += '-label';
 1020 			if (null === v) {
 1021 				_replcl(e, name, 'not given', false);
 1022 				_classaddcl(e, name, 'noanswer', false);
 1023 				return;
 1024 			}
 1025 			switch(v) {
 1026 			case sex.male:
 1027 				_replcllang(e, name, {_default: 'male'});
 1028 				break;
 1029 			case sex.female:
 1030 				_replcllang(e, name, {_default: 'female'});
 1031 				break;
 1032 			case sex.other:
 1033 				_replcllang(e, name, {_default: 'other'});
 1034 				break;
 1035 			default:
 1036 				console.log('sex.format: unknown value: ' + v);
 1037 				_replcl(e, name, '', false);
 1038 				break;
 1039 			}
 1040 		};
 1041 		return sex;
 1042 	}());
 1043 
 1044 	kwebapp.company = company;
 1045 	kwebapp.user = user;
 1046 	kwebapp.session = session;
 1047 	kwebapp.sex = sex;
 1048 })(kwebapp || (kwebapp = {}));