1 var kwebapp;
    2 (function(kwebapp) {
    3 	'use strict';
    4 
    5 	function _attr(e, attr, text)
    6 	{
    7 		if (null !== e)
    8 			e.setAttribute(attr, text);
    9 	}
   10 
   11 	function _rattr(e, attr)
   12 	{
   13 		if (null !== e)
   14 			e.removeAttribute(attr);
   15 	}
   16 
   17 	function _fillEnumSelect(e, val)
   18 	{
   19 		var list, i, v;
   20 
   21 		list = e.getElementsByTagName('option');
   22 		for (i = 0; i < list.length; i++) {
   23 			v = 'number' === typeof val ? 
   24 			     parseInt((list[i]).value) :
   25 			     (list[i]).value;
   26 			if (val === v)
   27 				_attr(list[i], 'selected', 'true');
   28 			else
   29 				_rattr(list[i], 'selected');
   30 		}
   31 	}
   32 
   33 	function _attrcl(e, attr, name, text, inc)
   34 	{
   35 		var list, i;
   36 
   37 		if (null === e)
   38 			return;
   39 		list = _elemList(e, name, inc);
   40 		for (i = 0; i < list.length; i++)
   41 			_attr(list[i], attr, text);
   42 	}
   43 
   44 	function _elemList(e, cls, inc)
   45 	{
   46 		var a = [], list, i;
   47 
   48 		if (null === e)
   49 			return(a);
   50 		list = e.getElementsByClassName(cls);
   51 		for (i = 0; i < list.length; i++)
   52 			a.push(list[i]);
   53 		if (inc && e.classList.contains(cls))
   54 			a.push(e);
   55 		return(a);
   56 	}
   57 
   58 	function _repl(e, text)
   59 	{
   60 		if (null === e)
   61 			return;
   62 		while (e.firstChild)
   63 			e.removeChild(e.firstChild);
   64 		e.appendChild(document.createTextNode(text));
   65 	}
   66 
   67 	function _fillfield(e, strct, name, funcs, obj, inc, cannull, isblob, sub, isenum)
   68 	{
   69 		var i, fname;
   70 
   71 		fname = strct + '-' + name;
   72 		/* First handle the custom callback. */
   73 		if (typeof funcs !== 'undefined' && 
   74 		    null !== funcs && fname in funcs) {
   75 			if (funcs[fname] instanceof Array) {
   76 				for (i = 0; i < funcs[fname].length; i++)
   77 					funcs[fname][i](e, fname, obj);
   78 			} else {
   79 				funcs[fname](e, fname, obj);
   80 			}
   81 		}
   82 		/* Now handle our has/no null situation. */
   83 		if (cannull) {
   84 			if (null === obj) {
   85 				_hidecl(e, strct + '-has-' + name, inc);
   86 				_showcl(e, strct + '-no-' + name, inc);
   87 			} else {
   88 				_showcl(e, strct + '-has-' + name, inc);
   89 				_hidecl(e, strct + '-no-' + name, inc);
   90 			}
   91 		}
   92 		/* Don't account for blobs any more. */
   93 		if (isblob)
   94 			return;
   95 		/* Don't process null values that can be null. */
   96 		if (cannull && null === obj)
   97 			return;
   98 		/* Non-null non-structs. */
   99 		if (null !== sub) {
  100 			var list = _elemList(e, fname + '-obj', inc);
  101 			for (i = 0; i < list.length; i++) {
  102 				sub.fillInner(list[i], funcs);
  103 			}
  104 		} else {
  105 			_replcl(e, fname + '-text', obj, inc);
  106 			var list = _elemList(e, fname + '-enum-select', inc);
  107 			for (i = 0; i < list.length; i++) {
  108 				_fillEnumSelect(list[i], obj);
  109 			}
  110 			_attrcl(e, 'value', fname + '-value', obj, inc);
  111 		}
  112 	}
  113 
  114 	function _replcl(e, name, text, inc)
  115 	{
  116 		var list, i;
  117 
  118 		if (null === e)
  119 			return;
  120 		list = _elemList(e, name, inc);
  121 		for (i = 0; i < list.length; i++)
  122 			_repl(list[i], text);
  123 	}
  124 
  125 	function _classadd(e, name)
  126 	{
  127 		if (null === e)
  128 			return(null);
  129 		if ( ! e.classList.contains(name))
  130 			e.classList.add(name);
  131 		return(e);
  132 	}
  133 
  134 	function _classaddcl(e, name, cls, inc)
  135 	{
  136 		var list, i;
  137 
  138 		if (null === e)
  139 			return;
  140 		list = _elemList(e, name, inc);
  141 		for (i = 0; i < list.length; i++)
  142 			_classadd(list[i], cls);
  143 	}
  144 
  145 	function _hide(e)
  146 	{
  147 		if (null === e)
  148 			return(null);
  149 		if ( ! e.classList.contains('hide'))
  150 			e.classList.add('hide');
  151 		return(e);
  152 	}
  153 
  154 	function _hidecl(e, name, inc)
  155 	{
  156 		var list, i;
  157 
  158 		if (null === e)
  159 			return;
  160 		list = _elemList(e, name, inc);
  161 		for (i = 0; i < list.length; i++)
  162 			_hide(list[i]);
  163 	}
  164 
  165 	function _show(e)
  166 	{
  167 		if (null === e)
  168 			return(null);
  169 		if (e.classList.contains('hide'))
  170 			e.classList.remove('hide');
  171 		return(e);
  172 	}
  173 
  174 	function _showcl(e, name, inc)
  175 	{
  176 		var list, i;
  177 
  178 		if (null === e)
  179 			return;
  180 		list = _elemList(e, name, inc);
  181 		for (i = 0; i < list.length; i++)
  182 			_show(list[i]);
  183 	}
  184 
  185 	/**
  186 	 * 
  187 	 * A user within our system.<br />
  188 	 * 
  189 	 * This constructor accepts the "user" objects or array of objects 
  190 	 * serialises into a DOM tree.
  191 	 * @param {(Object|Object[])} obj - The user object or array of 
  192 	 * objects.
  193 	 * @class user
  194 	 */
  195 	function user(obj)
  196 	{
  197 		this.obj = obj;
  198 
  199 		/**
  200 		 * Fill in a "user" object at the given element in the DOM 
  201 		 * tree.
  202 		 * If the object was initialised with an array, the first element 
  203 		 * is used.
  204 		 * Elements within (and including) "e" having the following 
  205 		 * classes are manipulated as follows:
  206 		 * <ul>
  207 		 * <li>user-email-enum-select: sets the "select" option for 
  208 		 * option values matching email under the element</li>
  209 		 * <li>user-email-text: replace contents with email data</li>
  210 		 * <li>user-email-value: replace "value" attribute with email 
  211 		 * data</li>
  212 		 * <li>user-hash-enum-select: sets the "select" option for option 
  213 		 * values matching hash under the element</li>
  214 		 * <li>user-hash-text: replace contents with hash data</li>
  215 		 * <li>user-hash-value: replace "value" attribute with hash 
  216 		 * data</li>
  217 		 * <li>user-id-enum-select: sets the "select" option for option 
  218 		 * values matching id under the element</li>
  219 		 * <li>user-id-text: replace contents with id data</li>
  220 		 * <li>user-id-value: replace "value" attribute with id data</li>
  221 		 * </ul>
  222 		 * @param {Object} e - The DOM element.
  223 		 * @param {Object} custom - A dictionary of functions keyed by 
  224 		 * structure and field name (e.g., "foo" structure, "bar" field 
  225 		 * would be "foo-bar"). The value is a function for custom 
  226 		 * handling that accepts the "e" value, the name of the 
  227 		 * structure-field, and the value of the structure and field.
  228 		 * You may also specify an array of functions instead of a 
  229 		 * singleton.
  230 		 * @memberof user#
  231 		 * @method fill
  232 		 */
  233 		this.fill = function(e, custom)
  234 		{
  235 			this._fill(e, this.obj, true, custom);
  236 		};
  237 
  238 		/**
  239 		 * Like [fill]{@link user#fill} but not including the root 
  240 		 * element "e".
  241 		 * @param {Object} e - The DOM element.
  242 		 * @param {Object} custom - The custom handler dictionary (see 
  243 		 * [fill]{@link user#fill} for details).
  244 		 * @memberof user#
  245 		 * @method fillInner
  246 		 */
  247 		this.fillInner = function(e, custom)
  248 		{
  249 			this._fill(e, this.obj, false, custom);
  250 		};
  251 
  252 		/**
  253 		 * Implements all [fill]{@link user#fill} style 
  254 		 * functions.
  255 		 * @private
  256 		 * @method _fill
  257 		 * @memberof user#
  258 		 * @param {Object} e - The DOM element.
  259 		 * @param {(Object|Object[])} o - The object (or array) to 
  260 		 * fill.
  261 		 * @param {Number} inc - Whether to include the root or not when 
  262 		 * processing.
  263 		 * @param {Object} custom - The custom handler dictionary (see 
  264 		 * [fill]{@link user#fill}).
  265 		 */
  266 		this._fill = function(e, o, inc, custom)
  267 		{
  268 			var i;
  269 
  270 			if (null === o || null === e)
  271 				return;
  272 			if (o instanceof Array) {
  273 				if (0 === o.length)
  274 					return;
  275 				o = o[0];
  276 			}
  277 			if (typeof custom !== 'undefined' && 
  278 			    null !== custom && 'user' in custom) {
  279 				if (custom['user'] instanceof Array) {
  280 					for (i = 0; i < custom['user'].length; i++)
  281 						custom['user'][i](e, "user", o);
  282 				} else {
  283 					custom['user'](e, "user", o);
  284 				}
  285 			}
  286 			_fillfield(e, 'user', 'email', custom, o.email, inc, false, false, null, false);
  287 			_fillfield(e, 'user', 'hash', custom, o.hash, inc, false, false, null, false);
  288 			_fillfield(e, 'user', 'id', custom, o.id, inc, false, false, null, false);
  289 		};
  290 
  291 		/**
  292 		 * Like [fill]{@link user#fill} but for an array of user.
  293 		 * This will remove the first element within "e" then repeatedly 
  294 		 * clone and re-append it, filling in the cloned subtree with the 
  295 		 * array.
  296 		 * If "e" is not an array, it is construed as an array of one.
  297 		 * If the input array is empty, "e" is hidden by using the "hide" 
  298 		 * class.
  299 		 * Otherwise, the "hide" class is removed.
  300 		 * @param {Object} e - The DOM element.
  301 		 * @param {Object} custom - The custom handler dictionary (see 
  302 		 * [fill]{@link user#fill}).
  303 		 * @memberof user#
  304 		 * @method fillArray
  305 		 */
  306 		this.fillArray = function(e, custom)
  307 		{
  308 			var o, j, row, cln;
  309 
  310 			o = this.obj;
  311 			if (null === o || null === e)
  312 				return;
  313 			if ( ! (o instanceof Array)) {
  314 				var ar = [];
  315 				ar.push(o);
  316 				o = ar;
  317 			}
  318 			if (0 === o.length) {
  319 				_hide(e);
  320 				return;
  321 			}
  322 			_show(e);
  323 			row = e.children[0];
  324 			if (null === row)
  325 				return;
  326 			e.removeChild(row);
  327 			while (null !== e.firstChild)
  328 				e.removeChild(e.firstChild)
  329 			for (j = 0; j < o.length; j++) {
  330 				cln = row.cloneNode(true);
  331 				e.appendChild(cln);
  332 				this._fill(cln, o[j], true, custom);
  333 			}
  334 		};
  335 	}
  336 
  337 	/**
  338 	 * 
  339 	 * A logged-in user.<br />
  340 	 * 
  341 	 * This constructor accepts the "sess" objects or array of objects 
  342 	 * serialises into a DOM tree.
  343 	 * @param {(Object|Object[])} obj - The sess object or array of 
  344 	 * objects.
  345 	 * @class sess
  346 	 */
  347 	function sess(obj)
  348 	{
  349 		this.obj = obj;
  350 
  351 		/**
  352 		 * Fill in a "sess" object at the given element in the DOM 
  353 		 * tree.
  354 		 * If the object was initialised with an array, the first element 
  355 		 * is used.
  356 		 * Elements within (and including) "e" having the following 
  357 		 * classes are manipulated as follows:
  358 		 * <ul>
  359 		 * <li>sess-user-obj: invoke [fillInner]{@link user#fillInner} 
  360 		 * with user data</li>
  361 		 * <li>sess-userid-enum-select: sets the "select" option for 
  362 		 * option values matching userid under the element</li>
  363 		 * <li>sess-userid-text: replace contents with userid data</li>
  364 		 * <li>sess-userid-value: replace "value" attribute with userid 
  365 		 * data</li>
  366 		 * <li>sess-token-enum-select: sets the "select" option for 
  367 		 * option values matching token under the element</li>
  368 		 * <li>sess-token-text: replace contents with token data</li>
  369 		 * <li>sess-token-value: replace "value" attribute with token 
  370 		 * data</li>
  371 		 * <li>sess-id-enum-select: sets the "select" option for option 
  372 		 * values matching id under the element</li>
  373 		 * <li>sess-id-text: replace contents with id data</li>
  374 		 * <li>sess-id-value: replace "value" attribute with id data</li>
  375 		 * </ul>
  376 		 * @param {Object} e - The DOM element.
  377 		 * @param {Object} custom - A dictionary of functions keyed by 
  378 		 * structure and field name (e.g., "foo" structure, "bar" field 
  379 		 * would be "foo-bar"). The value is a function for custom 
  380 		 * handling that accepts the "e" value, the name of the 
  381 		 * structure-field, and the value of the structure and field.
  382 		 * You may also specify an array of functions instead of a 
  383 		 * singleton.
  384 		 * @memberof sess#
  385 		 * @method fill
  386 		 */
  387 		this.fill = function(e, custom)
  388 		{
  389 			this._fill(e, this.obj, true, custom);
  390 		};
  391 
  392 		/**
  393 		 * Like [fill]{@link sess#fill} but not including the root 
  394 		 * element "e".
  395 		 * @param {Object} e - The DOM element.
  396 		 * @param {Object} custom - The custom handler dictionary (see 
  397 		 * [fill]{@link sess#fill} for details).
  398 		 * @memberof sess#
  399 		 * @method fillInner
  400 		 */
  401 		this.fillInner = function(e, custom)
  402 		{
  403 			this._fill(e, this.obj, false, custom);
  404 		};
  405 
  406 		/**
  407 		 * Implements all [fill]{@link sess#fill} style 
  408 		 * functions.
  409 		 * @private
  410 		 * @method _fill
  411 		 * @memberof sess#
  412 		 * @param {Object} e - The DOM element.
  413 		 * @param {(Object|Object[])} o - The object (or array) to 
  414 		 * fill.
  415 		 * @param {Number} inc - Whether to include the root or not when 
  416 		 * processing.
  417 		 * @param {Object} custom - The custom handler dictionary (see 
  418 		 * [fill]{@link sess#fill}).
  419 		 */
  420 		this._fill = function(e, o, inc, custom)
  421 		{
  422 			var i;
  423 
  424 			if (null === o || null === e)
  425 				return;
  426 			if (o instanceof Array) {
  427 				if (0 === o.length)
  428 					return;
  429 				o = o[0];
  430 			}
  431 			if (typeof custom !== 'undefined' && 
  432 			    null !== custom && 'sess' in custom) {
  433 				if (custom['sess'] instanceof Array) {
  434 					for (i = 0; i < custom['sess'].length; i++)
  435 						custom['sess'][i](e, "sess", o);
  436 				} else {
  437 					custom['sess'](e, "sess", o);
  438 				}
  439 			}
  440 			_fillfield(e, 'sess', 'user', custom, o.user, inc, false, false, new user(o.user), false);
  441 			_fillfield(e, 'sess', 'userid', custom, o.userid, inc, false, false, null, false);
  442 			_fillfield(e, 'sess', 'token', custom, o.token, inc, false, false, null, false);
  443 			_fillfield(e, 'sess', 'id', custom, o.id, inc, false, false, null, false);
  444 		};
  445 
  446 		/**
  447 		 * Like [fill]{@link sess#fill} but for an array of sess.
  448 		 * This will remove the first element within "e" then repeatedly 
  449 		 * clone and re-append it, filling in the cloned subtree with the 
  450 		 * array.
  451 		 * If "e" is not an array, it is construed as an array of one.
  452 		 * If the input array is empty, "e" is hidden by using the "hide" 
  453 		 * class.
  454 		 * Otherwise, the "hide" class is removed.
  455 		 * @param {Object} e - The DOM element.
  456 		 * @param {Object} custom - The custom handler dictionary (see 
  457 		 * [fill]{@link sess#fill}).
  458 		 * @memberof sess#
  459 		 * @method fillArray
  460 		 */
  461 		this.fillArray = function(e, custom)
  462 		{
  463 			var o, j, row, cln;
  464 
  465 			o = this.obj;
  466 			var list, strct, i;
  467 			if (null === o || null === e)
  468 				return;
  469 			if ( ! (o instanceof Array)) {
  470 				var ar = [];
  471 				ar.push(o);
  472 				o = ar;
  473 			}
  474 			if (0 === o.length) {
  475 				_hide(e);
  476 				return;
  477 			}
  478 			_show(e);
  479 			row = e.children[0];
  480 			if (null === row)
  481 				return;
  482 			e.removeChild(row);
  483 			while (null !== e.firstChild)
  484 				e.removeChild(e.firstChild)
  485 			for (j = 0; j < o.length; j++) {
  486 				cln = row.cloneNode(true);
  487 				e.appendChild(cln);
  488 				this._fill(cln, o[j], true, custom);
  489 			}
  490 		};
  491 	}
  492 
  493 	kwebapp.user = user;
  494 	kwebapp.sess = sess;
  495 })(kwebapp || (kwebapp = {}));