Source: typescript.js

/**
 * Top-level namespace of these objects.
 * @namespace
 */
var ort;
(function(ort) {
	'use strict';

	/**
	 * Convenience function to resolve a set of translated strings into a 
	 * single one depending upon the current language.
	 * @param {langmap} vals - All translations of a given word.
	 * @private
	 * @function _strlang
	 * @memberof ort
	 */
	function _strlang(vals)
	{
		var lang;
		lang = document.documentElement.lang;
		if (null !== lang && lang in vals)
			return vals[lang];
		else if ('_default' in vals)
			return vals['_default'];
		else
			return '';
	}

	/**
	 * Used exclusively by enumerations and bitfields to do language 
	 * replacement conditional upon the label (<i>jslabel</i> in the 
	 * configuration).
	 * Like {@link ort._replcl} with inclusion set to false.
	 * @param {HTMLElement} e - The root of the DOM tree in which we 
	 * query for elements to fill into.
	 * @param {String} name - The class name we search for within the 
	 * root (not inclusive).
	 * @param {langmap} vals - All possible translations.
	 * @private
	 * @function _replcllang
	 * @memberof ort
	 */
	function _replcllang(e, name, vals)
	{
		_replcl(e, name, _strlang(vals), false);
	}

	/**
	 * Used exclusively by enumerations and bitfields to do language 
	 * replacement conditional upon the label (<i>jslabel</i> in the 
	 * configuration).
	 * Like {@link ort._repl}.
	 * @param {HTMLElement} e - The root of the DOM tree in which we 
	 * query for elements to fill into.
	 * @param {langmap} vals - All possible translations.
	 * @private
	 * @function _repllang
	 * @memberof ort
	 */
	function _repllang(e, vals)
	{
		_repl(e, _strlang(vals));
	}

	function _attr(e, attr, text)
	{
		if (null !== e)
			e.setAttribute(attr, text);
	}

	function _rattr(e, attr)
	{
		if (null !== e)
			e.removeAttribute(attr);
	}

	/**
	 * Internal function for checking inputs for all elements of class 
	 * strct-name-value-checked whose value matches the object's value. 
	 * If the object is null, all elements are unchecked.
	 * @param {HTMLElement} e - The root of the DOM tree in which we 
	 * query for elements to fill into.
	 * @param {String} strct - The name of the structure that we're 
	 * filling in.
	 * @param {String} name - The name of the field.
	 * @param {Number|String|null} obj - The data itself.
	 * @param {Boolean} inc - Whether to include the root element in 
	 * looking for elements to fill.
	 * @private
	 * @function _fillValueChecked
	 * @memberof ort
	 */
	function _fillValueChecked(e, fname, val, inc)
	{
		var list;
		var i;
		var valstr;
		fname += '-value-checked';
		valstr = null === val ? null : 
			("number" === typeof val ? val.toString() : val);
		list = _elemList(e, fname, inc);
		for (i = 0; i < list.length; i++)
			if (valstr === null)
				_rattr(list[i], 'checked');
			else if (valstr === (list[i]).value)
				_attr(list[i], 'checked', 'true');
			else
				_rattr(list[i], 'checked');
	}

	/**
	 * Internal function that takes all <code>&lt;option&gt;</code> 
	 * elements in the root and sets or unsets their 
	 * <code>selected</code> status depending upon whether it matches the 
	 * object's value.
	 * @param {HTMLElement} e - The root of the DOM tree in which we 
	 * query for elements to fill into.
	 * @param {Number|String} val - The object's value.
	 * @private
	 * @function _fillValueSelect
	 * @memberof ort
	 */
	function _fillValueSelect(e, val)
	{
		var list;
		var i;
		var v;
		if (null === e)
			return;
		list = e.getElementsByTagName('option');
		for (i = 0; i < list.length; i++) {
			v = 'number' === typeof val ? 
			     parseInt((list[i]).value) :
			     (list[i]).value;
			if (val === v)
				_attr(list[i], 'selected', 'true');
			else
				_rattr(list[i], 'selected');
		}
	}

	function _attrcl(e, attr, name, text, inc)
	{
		var list;
		var i;
		if (null === e)
			return;
		list = _elemList(e, name, inc);
		for (i = 0; i < list.length; i++)
			_attr(list[i], attr, text);
	}

	function _elemList(e, cls, inc)
	{
		var a;
		var list;
		var i;
		a = [];
		if (null === e)
			return a;
		list = e.getElementsByClassName(cls);
		for (i = 0; i < list.length; i++)
			a.push(list[i]);
		if (inc && e.classList.contains(cls))
			a.push(e);
		return a;
	}

	function _repl(e, text)
	{
		if (null === e)
			return;
		while (e.firstChild)
			e.removeChild(e.firstChild);
		e.appendChild(document.createTextNode(text));
	}

	/**
	 * Internal function for filling in ISO-8601 dates.
	 * @param {HTMLElement} e - The root of the DOM tree in which we 
	 * query for elements to fill into.
	 * @param {String} strct - The name of the structure that we're 
	 * filling in.
	 * @param {String} name - The name of the field.
	 * @param {Number|null} obj - The data itself.
	 * @param {Boolean} inc - Whether to include the root element in 
	 * looking for elements to fill.
	 * @private
	 * @function _fillDateValue
	 * @memberof ort
	 */
	function _fillDateValue(e, strct, name, val, inc)
	{
		var fname;
		var year;
		var mo;
		var day;
		var full;
		var d;
		if (null === val)
			return;
		d = new Date();
		d.setTime(val * 1000);
		year = d.getFullYear();
		mo = d.getMonth() + 1;
		day = d.getDate();
		full = year + '-' +
			(mo < 10 ? '0' : '') + mo + '-' +
			(day < 10 ? '0' : '') + day;
		fname = strct + '-' + name + '-date-value';
		_attrcl(e, 'value', fname, full, inc);
		fname = strct + '-' + name + '-date-text';
		_replcl(e, fname, full, inc);
	}

	/**
	 * Internal function for checking inputs for all elements of class 
	 * strct-name-bits-checked whose value is the bit-wise AND of the 
	 * object's value. If the object is null, all elements are unchecked.
	 * @param {HTMLElement} e - The root of the DOM tree in which we 
	 * query for elements to fill into.
	 * @param {String} strct - The name of the structure that we're 
	 * filling in.
	 * @param {String} name - The name of the field.
	 * @param {Number|null} obj - The data itself.
	 * @param {Boolean} inc - Whether to include the root element in 
	 * looking for elements to fill.
	 * @private
	 * @function _fillBitsChecked
	 * @memberof ort
	 */
	function _fillBitsChecked(e, strct, name, val, inc)
	{
		var list;
		var fname;
		var i;
		var v;
		fname = strct + '-' + name + '-bits-checked';
		list = _elemList(e, fname, inc);
		for (i = 0; i < list.length; i++) {
			if (val === null) {
				_rattr(list[i], 'checked');
				continue;
			}
			v = parseInt((list[i]).value);
			if (isNaN(v))
				_rattr(list[i], 'checked');
			else if (0 === v && 0 === val)
				_attr(list[i], 'checked', 'true');
			else if ((1 << (v - 1)) & val)
				_attr(list[i], 'checked', 'true');
			else
				_rattr(list[i], 'checked');
		}
	}

	/**
	 * Internal function for filling a structure field.
	 * This first does the has/no class setting for null values, then 
	 * optionally returns if null (running the custom fields first), 
	 * otherwise the generic text/value/etc fields, then finally the 
	 * custom fields.
	 * @param {HTMLElement} e - The root of the DOM tree in which we 
	 * query for elements to fill into.
	 * @param {String} strct - The name of the structure that we're 
	 * filling in.
	 * @param {String} name - The name of the field.
	 * @param {ort.DataCallbacks|null} custom - Custom callback functions 
	 * to invoke on the field.
	 * @param obj - The data itself, which is either a native type or one 
	 * of the data interfaces for an application-specific type.
	 * @param {Boolean} inc - Whether to include the root element in 
	 * looking for elements to fill. Note that nested structures are 
	 * alwyas filled non-inclusively.
	 * @param {Boolean} cannull - Whether the data object might be null.
	 * @param {Boolean} isblob - Whether the data object is a blob.
	 * @param sub - If the data object is a nested structure interface, 
	 * this is the allocated class of that interface.
	 * @private
	 * @function _fillField
	 * @memberof ort
	 */
	function _fillField(e, strct, name, custom, obj, inc, cannull, isblob, sub)
	{
		var i;
		var fname;
		var list;
		fname = strct + '-' + name;
		/* First handle our has/no null situation. */
		if (cannull) {
			if (null === obj) {
				_hidecl(e, strct + '-has-' + name, inc);
				_showcl(e, strct + '-no-' + name, inc);
			} else {
				_showcl(e, strct + '-has-' + name, inc);
				_hidecl(e, strct + '-no-' + name, inc);
			}
		}
		/* Don't process null values that can be null. */
		if (cannull && null === obj) {
			if (null !== custom && fname in custom) {
				if (custom[fname] instanceof Array) {
					for (i = 0; i < custom[fname].length; i++)
						custom[fname][i](e, fname, null);
				} else {
					custom[fname](e, fname, null);
				}
			}
			return;
		}
		/* Non-null non-structs. */
		/* Don't account for blobs. */
		if (null !== sub) {
			list = _elemList(e, fname + '-obj', inc);
			for (i = 0; i < list.length; i++) {
				sub.fillInner(list[i], custom);
			}
		} else if ( ! isblob) {
			list = _elemList(e, fname + '-enum-select', inc);
			for (i = 0; i < list.length; i++) {
				_fillValueSelect(list[i], obj);
			}
			_replcl(e, fname + '-text', obj, inc);
			_attrcl(e, 'value', fname + '-value', obj, inc);
			_fillValueChecked(e, fname, obj, inc);
		}
		/* Lastly, handle the custom callback. */
		if (null !== custom && fname in custom) {
			if (custom[fname] instanceof Array) {
				for (i = 0; i < custom[fname].length; i++)
					custom[fname][i](e, fname, obj);
			} else {
				custom[fname](e, fname, obj);
			}
		}
	}

	function _replcl(e, name, text, inc)
	{
		var list;
		var i;
		if (null === e)
			return;
		list = _elemList(e, name, inc);
		for (i = 0; i < list.length; i++)
			_repl(list[i], text);
	}

	function _classadd(e, name)
	{
		if (null === e)
			return(null);
		if ( ! e.classList.contains(name))
			e.classList.add(name);
		return(e);
	}

	function _classaddcl(e, name, cls, inc)
	{
		var list;
		var i;
		if (null === e)
			return;
		list = _elemList(e, name, inc);
		for (i = 0; i < list.length; i++)
			_classadd(list[i], cls);
	}

	function _hide(e)
	{
		if (null === e)
			return null;
		if ( ! e.classList.contains('hide'))
			e.classList.add('hide');
		return e;
	}

	function _hidecl(e, name, inc)
	{
		var list;
		var i;
		if (null === e)
			return;
		list = _elemList(e, name, inc);
		for (i = 0; i < list.length; i++)
			_hide(list[i]);
	}

	function _show(e)
	{
		if (null === e)
			return null;
		if (e.classList.contains('hide'))
			e.classList.remove('hide');
		return e;
	}

	function _showcl(e, name, inc)
	{
		var list;
		var i;
		if (null === e)
			return;
		list = _elemList(e, name, inc);
		for (i = 0; i < list.length; i++)
			_show(list[i]);
	}

	/**
	 * All possible callback functions for passing to the "custom" 
	 * associative array when filling in DOM trees.
	 * @interface ort.DataCallbacks
	 */
	/**
	 * 
	 * @interface ort.clientData
	 */
	/**
	 * Accepts {@link ort.clientData} for writing into a DOM tree.
	 * @param {(ort.clientData|ort.clientData[])} obj - The object(s) to 
	 * write.
	 * @memberof ort
	 * @constructor
	 * @class
	 */
	var client = (function()
	{
		function client(o)
		{
			this.obj = o;
		}
		/**
		 * Write the {@link ort.clientData} into the given HTMLElement in 
		 * the DOM tree.
		 * If constructed with an array, the first element is used.
		 * Elements within (and including) "e" having the following 
		 * classes are manipulated as follows:
		 * <ul>
		 * <li>client-name-enum-select: sets the <code>select</code> 
		 * attribute for <code>&lt;option&gt;</code> values matching 
		 * <i>name</i> under the element</li>
		 * <li>client-name-value-checked: sets the <code>checked</code> 
		 * attribute under the element matching the input</li>
		 * <li>client-name-text: replace contents with <i>name</i> 
		 * data</li>
		 * <li>client-name-value: replace <code>value</code> attribute 
		 * with <i>name</i> data</li>
		 * <li>client-dob-enum-select: sets the <code>select</code> 
		 * attribute for <code>&lt;option&gt;</code> values matching 
		 * <i>dob</i> under the element</li>
		 * <li>client-dob-value-checked: sets the <code>checked</code> 
		 * attribute under the element matching the input</li>
		 * <li>client-dob-text: replace contents with <i>dob</i> 
		 * data</li>
		 * <li>client-dob-value: replace <code>value</code> attribute 
		 * with <i>dob</i> data</li>
		 * <li>client-dob-date-value: set the element's 
		 * <code>value</code> to the ISO-8601 date format of the 
		 * data</li>
		 * <li>client-dob-date-text: like client-dob-date-value, but 
		 * replacing contents
		 * <li>client-id-enum-select: sets the <code>select</code> 
		 * attribute for <code>&lt;option&gt;</code> values matching 
		 * <i>id</i> under the element</li>
		 * <li>client-id-value-checked: sets the <code>checked</code> 
		 * attribute under the element matching the input</li>
		 * <li>client-id-text: replace contents with <i>id</i> data</li>
		 * <li>client-id-value: replace <code>value</code> attribute with 
		 * <i>id</i> data</li>
		 * </ul>
		 * @param {HTMLElement} e - The DOM element.
		 * @param {ort.DataCallbacks} custom - The optional dictionary of 
		 * functions keyed by structure and field name (e.g., <i>foo</i> 
		 * structure, <i>bar</i> field would be <code>foo-bar</code>). 
		 * The value is a function for custom handling that accepts the 
		 * "e" value, the name of the structure-field, and the value of 
		 * the structure and field.
		 * You may also specify an array of functions instead of a 
		 * singleton.
		 * These callbacks are invoked <b>after</b> the generic classes 
		 * are filled.
		 * @function fill
		 * @memberof ort.client#
		 */
		client.prototype.fill = function(e, custom)
		{
			this._fill(e, this.obj, true, custom);
		};

		/**
		 * Like {@link ort.client#fill} but instead of accepting a single 
		 * element to fill, filling into all elements (non-inclusive) 
		 * matching the given class name beneath (non-inclusive) the 
		 * given root.
		 * @param {HTMLElement} e - The DOM element.
		 * @param {String} name - The name of the class into which to 
		 * fill.
		 * @param {ort.DataCallbacks} custom - The optional custom 
		 * handler dictionary (see {@link ort.client#fill} for details).
		 * @function fillByClass
		 * @memberof ort.client#
		 */
		client.prototype.fillByClass = function(e, name, custom)
		{
			this._fillByClass(e, name, true, custom);
		};

		/**
		 * Like {@link ort.client#fillByClass} but inclusive the root and 
		 * targets by class.
		 * @param {HTMLElement} e - The DOM element.
		 * @param {String} name - The name of the class into which to 
		 * fill.
		 * @param {ort.DataCallbacks} custom - The optional custom 
		 * handler dictionary (see {@link ort.client#fill} for details).
		 * @function fillInnerByClass
		 * @memberof ort.client#
		 */
		client.prototype.fillInnerByClass = function(e, name, custom)
		{
			this._fillByClass(e, name, false, custom);
		};

		/**
		 * Like {@link ort.client#fill} but not including the root 
		 * element "e".
		 * @param {HTMLElement} e - The DOM element.
		 * @param {ort.DataCallbacks} custom - The optional custom 
		 * handler dictionary (see {@link ort.client#fill} for details).
		 * @function fillInner
		 * @memberof ort.client#
		 */
		client.prototype.fillInner = function(e, custom)
		{
			this._fill(e, this.obj, false, custom);
		};

		/**
		 * Implements all {@link ort.client#fill} functions.
		 * @param {HTMLElement} e - The DOM element.
		 * @param {ort.clientData|ort.clientData[]|null} o - The object 
		 * (or array) to fill.
		 * @param {Boolean} inc - Whether to include the root or not when 
		 * processing.
		 * @param {ort.DataCallbacks} custom - The optional custom 
		 * handler dictionary (see {@link ort.client#fill}).
		 * @private
		 * @function _fill
		 * @memberof ort.client#
		 */
		client.prototype._fill = function(e, o, inc, custom)
		{
			var i;
			if (null === o || null === e)
				return;
			if (o instanceof Array) {
				if (0 === o.length)
					return;
				o = o[0];
			}
			if (typeof custom === 'undefined')
				custom = null;
			_fillField(e, 'client', 'name', custom, o.name, inc, false, false, null);
			_fillField(e, 'client', 'dob', custom, o.dob, inc, false, false, null);
			_fillDateValue(e, 'client', 'dob', o.dob, inc);
			_fillField(e, 'client', 'id', custom, o.id, inc, false, false, null);
			if (null !== custom && 'client' in custom) {
				if (custom['client'] instanceof Array) {
					for (i = 0; i < custom['client'].length; i++)
						(custom['client'])[i](e, 'client', o);
				} else {
					(custom['client'])(e, 'client', o);
				}
			}
		};

		/**
		 * Like {@link ort.client#_fill} but instead of accepting a 
		 * single element to fill, filling into all elements matching the 
		 * given class name beneath the given root.
		 * @param {HTMLElement} e - The DOM element.
		 * @param {String} name - The name of the class into which to 
		 * fill.
		 * @param {Boolean} inc - Whether to include the roots or not 
		 * when processing.
		 * @param {ort.DataCallbacks} custom - The optional custom 
		 * handler dictionary (see {@link ort.client#fill} for details).
		 * @private
		 * @function _fillByClass
		 * @memberof ort.client#
		 */
		client.prototype._fillByClass = function(e, name, inc, custom)
		{
			var i;
			var list;
			list = _elemList(e, name, inc);
			for (i = 0; i < list.length; i++)
				this._fill(list[i], this.obj, inc, custom);
		};

		/**
		 * Like {@link ort.client#fillArray}, but hiding an element if 
		 * the array is empty or null.
		 * @param {HTMLElement|null} e - The DOM element.
		 * @param {HTMLElement|null} tohide - The DOM element to hide.
		 * @param {ort.clientData|ort.clientData[]|null} o - The array 
		 * (or object) to fill.
		 * @param {ort.DataCallbacks} custom - The optional custom 
		 * handler dictionary (see {@link ort.client#fill}).
		 * @function fillArrayOrHide
		 * @memberof ort.client#
		 */
		client.prototype.fillArrayOrHide = function(e, tohide, custom)
		{
			var len;
			if (null === this.obj)
				len = 0;
			else if (this.obj instanceof Array)
				len = this.obj.length;
			else
				len = 1;
			if (null !== e)
				_hide(e);
			if (null !== tohide)
				_show(tohide);
			this.fillArray(e, custom);
			if (null !== tohide && 0 === len)
				_hide(tohide);
		};
		/**
		 * Like {@link ort.client#fillArray}, but showing an element if 
		 * the array is empty or null.
		 * @param {HTMLElement|null} e - The DOM element.
		 * @param {HTMLElement|null} toshow - The DOM element to show.
		 * @param {ort.clientData|ort.clientData[]|null} o - The array 
		 * (or object) to fill.
		 * @param {ort.DataCallbacks} custom - The optional custom 
		 * handler dictionary (see {@link ort.client#fill}).
		 * @function fillArrayOrShow
		 * @memberof ort.client#
		 */
		client.prototype.fillArrayOrShow = function(e, toshow, custom)
		{
			var len;
			if (null === this.obj)
				len = 0;
			else if (this.obj instanceof Array)
				len = this.obj.length;
			else
				len = 1;
			if (null !== e)
				_hide(e);
			if (null !== toshow)
				_hide(toshow);
			this.fillArray(e, custom);
			if (null !== toshow && 0 === len)
				_show(toshow);
		};
		/**
		 * Like {@link ort.client#fill} but for an array of {@link 
		 * ort.clientData}.
		 * If the data is not an array, it is remapped as an array of 
		 * one.
		 * This will save the first element within "e", remove all 
		 * children of "e", then repeatedly clone the saved element and 
		 * re-append it, filling in the cloned subtree with the array 
		 * (inclusive of the subtree root).
		 * If the input array is empty or null, "e" is hidden by using 
		 * the <code>hide</code> class.
		 * Otherwise, the <code>hide</code> class is removed.
		 * @param {HTMLElement} e - The DOM element.
		 * @param {ort.DataCallbacks} custom - The optional custom 
		 * handler dictionary (see {@link ort.client#fill}).
		 * @memberof ort.client#
		 * @function fillArray
		 */
		client.prototype.fillArray = function(e, custom)
		{
			var j;
			var o;
			var cln;
			var ar;
			var row;
			o = this.obj;
			if (null !== e)
				_hide(e);
			if (null === o || null === e)
				return;
			if ( ! (o instanceof Array)) {
				ar = [];
				ar.push(o);
				o = ar;
			}
			if (0 === o.length)
				return;
			_show(e);
			row = e.children[0];
			if (null === row)
				return;
			e.removeChild(row);
			while (null !== e.firstChild)
				e.removeChild(e.firstChild)
			for (j = 0; j < o.length; j++) {
				cln = row.cloneNode(true);
				e.appendChild(cln);
				this._fill(cln, o[j], true, custom);
			}
		};
		/**
		 * Like {@link ort.client#fillArray} but instead of accepting a 
		 * single element to fill, filling all elements by class name 
		 * beneath the given root (non-inclusive).
		 * @param {HTMLElement} e - The DOM element.
		 * @param {String} name - The name of the class into which to 
		 * fill.
		 * @param {ort.DataCallbacks} custom - The optional custom 
		 * handler dictionary (see {@link ort.client#fill} for details).
		 * @function fillArrayByClass
		 * @memberof ort.client#
		 */
		client.prototype.fillArrayByClass = function(e, name, custom)
		{
			var i;
			var list;
			list = _elemList(e, name, false);
			for (i = 0; i < list.length; i++)
				this.fillArray(list[i], custom);
		};

		return client;
	}());
	ort.client = client;

	ort.client = client;
})(ort || (ort = {}));