Subversion Repositories JSX

Compare Revisions

Last modification

Ignore whitespace Rev 535 → Rev 536

/branches/live/dom.js
97,277 → 97,257
var jsx = {};
}
 
jsx.dom = {
version: "$Id$",
//var dhtmlDocURL = dhtmlPath + "dhtml.htm";
copyright: "Copyright \xA9 2002-2013",
author: "Thomas Lahn",
email: "js@PointedEars.de",
path: "http://pointedears.de/scripts/"
};
jsx.dom.URI = jsx.dom.path + "dom.js";
//this.docURI = this.path + "dhtml.htm";
/**
* @namespace
*/
jsx.dom = (/** @constructor */ function () {
/* Imports */
var _jsx_object = jsx.object;
var _isMethod = _jsx_object.isMethod;
var _isHostMethod = _jsx_object.isHostMethod;
var _getKeys = _jsx_object.getKeys;
var _isArray = _jsx_object.isArray;
 
if (typeof document != "undefined")
{
jsx.dom.hasDocumentAll = false;
/* Private variables */
var _hasDocumentAll = false;
var _hasDocumentLayers = false;
var _hasGetElementsByTagName = false;
 
jsx.dom.getElementById = jsx.dom.getElemById = jsx.dom.getEBI = jsx.dom.gEBI = (
function () {
if (typeof document == "undefined")
{
return function () {
return null;
};
}
function _dummy()
{
return null;
}
 
var jsx_object = jsx.object;
var _getElementById = (function () {
if (typeof document == "undefined")
{
return _dummy;
}
 
if (jsx_object.isMethod(document, "getElementById"))
{
/**
* @param {string} sId
* @return {Element|Null}
* Reference to an {@link Element} object representing
* the element with the given ID, <code>null</code> or
* <code>undefined</code> if there is no such element.
* The return value varies among DOM implementations
* if there is more than one matching element (invalid markup).
*/
return function (sId) {
/* wrapper method required to avoid "invalid op. on prototype" exception */
return document.getElementById(sId);
};
}
if (_isMethod(document, "getElementById"))
{
/**
* @param {string} sId
* @return {Element|Null}
* Reference to an {@link Element} object representing
* the element with the given ID, <code>null</code> or
* <code>undefined</code> if there is no such element.
* The return value varies among DOM implementations
* if there is more than one matching element (invalid markup).
*/
return function (sId) {
/* wrapper method required to avoid "invalid op. on prototype" exception */
return document.getElementById(sId);
};
}
 
if ((jsx.dom.hasDocumentAll = jsx_object.isMethod(document, "all")))
{
return function (sId) {
return document.all(sId);
};
}
 
if ((_hasDocumentAll = _isMethod(document, "all")))
{
return function (sId) {
return document[sId];
return document.all(sId);
};
}
)();
 
jsx.dom.hasDocumentLayers = false;
return function (sId) {
return document[sId];
};
}());
 
jsx.dom.getElementsByName = jsx.dom.getElemByName = jsx.dom.gEBN = (
function () {
function dummy()
{
return null;
}
var _getElementsByName = (function () {
if (typeof document == "undefined")
{
return _dummy;
}
 
if (typeof document == "undefined")
{
return dummy;
}
if (_isMethod(document, "getElementsByName"))
{
/* W3C DOM Level 2 HTML */
/**
* @param {string} sName
* @param {number} index (optional)
* @return Element|Layer|Null|Undefined
*/
return function (sName, index) {
var result = document.getElementsByName(sName);
if (result && !isNaN(index) && index > -1)
{
result = result[index];
}
 
if (jsx.object.isMethod(document, "getElementsByName"))
{
/* W3C DOM Level 2 HTML */
/**
* @param {string} sName
* @param {number} index (optional)
* @return Element|Layer|Null|Undefined
*/
return function (sName, index) {
var result = document.getElementsByName(sName);
if (result && !isNaN(index) && index > -1)
{
result = result[index];
}
return result;
};
}
else if (_hasDocumentAll)
{
/* IE4 DOM */
return function (sName, index) {
var result = document.all(sName);
if (result && !isNaN(index) && index > -1)
{
result = result[index];
}
 
return result;
};
}
else if (jsx.dom.hasDocumentAll)
{
/* IE4 DOM */
return function (sName, index) {
var result = document.all(sName);
if (result && !isNaN(index) && index > -1)
{
result = result[index];
}
return result;
};
}
else if ((_hasDocumentLayers = (typeof document.layers == "object")))
{
/* NN4 DOM */
return function (sName, index) {
var result = document.layers[sName];
if (result && !isNaN(index) && index > -1)
{
result = result[index];
}
 
return result;
};
}
else if ((jsx.dom.hasDocumentLayers = (typeof document.layers == "object")))
{
/* NN4 DOM */
return function (sName, index) {
var result = document.layers[sName];
if (result && !isNaN(index) && index > -1)
{
result = result[index];
}
return result;
};
}
 
return result;
};
}
return _dummy;
}());
 
return dummy;
}()
);
var _getElementsByTagName = (function () {
if (_jsx_object.isNativeMethod(jsx, "xpath", "evaluate"))
{
/* W3C DOM Level 3 XPath */
/**
* @param {string} sTagName
* @param {number} index (optional)
* @param {Element} oContextNode (optional)
* @return {Array|Element}
* An <code>Array</code> of references to objects representing
* matching elements, or one reference to such an object if
* <var>index</var> was provided.
*/
return function (sTagName, index, oContextNode) {
if (!sTagName)
{
sTagName = '*';
}
 
jsx.dom.hasGetElementsByTagName = false;
if (arguments.length > 2 && typeof index != "number")
{
var tmp = oContextNode;
oContextNode = index;
index = tmp;
}
 
jsx.dom.getElementsByTagName = jsx.dom.getElemByTagName = jsx.dom.gEBTN = (
function () {
var jsx_object = jsx.object;
var result = jsx.dom.xpath.evaluate('.//' + sTagName, oContextNode || null,
null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
 
if (jsx_object.isNativeMethod(jsx, "xpath", "evaluate"))
{
/* W3C DOM Level 3 XPath */
/**
* @param {string} sTagName
* @param {number} index (optional)
* @param {Element} oContextNode (optional)
* @return {Array|Element}
* An <code>Array</code> of references to objects representing
* matching elements, or one reference to such an object if
* <var>index</var> was provided.
*/
return function (sTagName, index, oContextNode) {
if (!sTagName)
if (result)
{
if (!isNaN(index) && index > -1)
{
sTagName = '*';
result = result[index];
}
}
 
if (arguments.length > 2 && typeof index != "number")
{
var tmp = oContextNode;
oContextNode = index;
index = tmp;
}
return result;
};
}
 
var result = jsx.dom.xpath.evaluate('.//' + sTagName, oContextNode || null,
null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
if ((_hasGetElementsByTagName =
(typeof document != "undefined"
&& _isMethod(document, "getElementsByTagName"))))
{
/* W3C DOM Level 2 Core */
/**
* @param {string} sTagName
* @param {number} index (optional)
* @param {Element} oContextNode (optional)
* @return {NodeList|Element|Null}
* An <code>NodeList</code> of references to objects representing
* matching elements, or one reference to such an object if
* <var>index</var> was provided; <code>null</code> if there
* is no matching element.
*/
return function (sTagName, index, oContextNode) {
if (!sTagName)
{
sTagName = '*';
}
 
if (result)
{
if (!isNaN(index) && index > -1)
{
result = result[index];
}
}
if (arguments.length > 2 && typeof index != "number")
{
var tmp = oContextNode;
oContextNode = index;
index = tmp;
}
 
return result;
};
}
if (!oContextNode)
{
oContextNode = document;
}
 
if ((jsx.dom.hasGetElementsByTagName =
(typeof document != "undefined"
&& jsx_object.isMethod(document, "getElementsByTagName"))))
{
/* W3C DOM Level 2 Core */
/**
* @param {string} sTagName
* @param {number} index (optional)
* @param {Element} oContextNode (optional)
* @return {NodeList|Element|Null}
* An <code>NodeList</code> of references to objects representing
* matching elements, or one reference to such an object if
* <var>index</var> was provided; <code>null</code> if there
* is no matching element.
*/
return function (sTagName, index, oContextNode) {
if (!sTagName)
{
sTagName = '*';
}
if (!_isMethod(oContextNode, "getElementsByTagName"))
{
return null;
}
 
if (arguments.length > 2 && typeof index != "number")
{
var tmp = oContextNode;
oContextNode = index;
index = tmp;
}
var result = oContextNode.getElementsByTagName(sTagName);
if (result && !isNaN(index) && index > -1)
{
result = result[index];
}
 
if (!oContextNode)
{
oContextNode = document;
}
return result;
};
}
 
if (!jsx_object.isMethod(oContextNode, "getElementsByTagName"))
{
return null;
}
if (_hasDocumentAll && isMethod(document.all, "tags"))
{
/**
* @param {string} sTagName
* @param {number} index (optional)
* @param {Element} oContextNode (optional)
* @return {NodeList|Element|Undefined}
* An <code>NodeList</code> of references to objects representing
* matching elements, or one reference to such an object if
* <var>index</var> was provided; <code>null</code>
* if there is no matching element.
*/
return function (sTagName, index, oContextNode) {
if (arguments.length > 2 && typeof index != "number")
{
var tmp = oContextNode;
oContextNode = index;
index = tmp;
}
 
var result = oContextNode.getElementsByTagName(sTagName);
if (result && !isNaN(index) && index > -1)
{
result = result[index];
}
if (!oContextNode)
{
oContextNode = document;
}
 
return result;
};
}
if (!_isMethod(oContextNode, "all", "tags"))
{
return null;
}
 
if (jsx.dom.hasDocumentAll && isMethod(document.all, "tags"))
{
/**
* @param {string} sTagName
* @param {number} index (optional)
* @param {Element} oContextNode (optional)
* @return {NodeList|Element|Undefined}
* An <code>NodeList</code> of references to objects representing
* matching elements, or one reference to such an object if
* <var>index</var> was provided; <code>null</code>
* if there is no matching element.
*/
return function (sTagName, index, oContextNode) {
if (arguments.length > 2 && typeof index != "number")
{
var tmp = oContextNode;
oContextNode = index;
index = tmp;
}
var result = oContextNode.all.tags(sTagName);
if (result && !isNaN(index) && index > -1)
{
result = result[index];
}
 
if (!oContextNode)
{
oContextNode = document;
}
 
if (!jsx.object.isMethod(oContextNode, "all", "tags"))
{
return null;
}
 
var result = oContextNode.all.tags(sTagName);
if (result && !isNaN(index) && index > -1)
{
result = result[index];
}
 
return result;
};
}
 
return function () {
return null;
return result;
};
}()
);
}
 
jsx.dom.getElementByIndex = jsx.dom.getElemByIndex = jsx.dom.gEBIdx = (function () {
function dummy()
{
return function () {
return null;
}
};
}());
 
var _getElementByIndex = (function () {
if (typeof document == "undefined")
{
return dummy;
return _dummy;
}
 
if (jsx.dom.hasGetElementsByTagName)
if (_hasGetElementsByTagName)
{
/**
* @param {number} index
378,7 → 358,7
};
}
 
if (jsx.dom.hasDocumentAll)
if (_hasDocumentAll)
{
/**
* @param {number} index
389,7 → 369,7
};
}
 
if (jsx.dom.hasDocumentLayers)
if (_hasDocumentLayers)
{
/**
* @param {number} index
400,615 → 380,1099
};
}
 
return dummy;
return _dummy;
}());
}
 
/*
* Apart from isNS4DOM, none of these object-inference properties is used
* anymore; they are still here for backwards compatibility only
*/
//this.isW3CDOM = jsx.object.isMethod(document, "getElementById");
//this.isOpera = typeof window.opera != "undefined";
jsx.dom.isNS4DOM = typeof document.layers != "undefined";
//this.isIE4DOM = typeof document.all == "object" && !this.isOpera;
//this.supported = this.isW3CDOM || this.isNS4DOM || this.isOpera
// || this.isIE4DOM;
var _attrMap = {
alink: "aLink",
accesskey: "accessKey",
bgcolor: "bgColor",
cellpadding: "cellPadding",
cellspacing: "cellSpacing",
"char": "ch",
charoff: "chOff",
"class": "className",
codebase: "codeBase",
codetype: "codeType",
colspan: "colSpan",
datetime: "dateTime",
frameborder: "frameBorder",
"for": "htmlFor",
ismap: "isMap",
longdesc: "longDesc",
maxlength: "maxLength",
marginheight: "marginHeight",
marginwidth: "marginWidth",
nohref: "noHref",
noresize: "noResize",
noshade: "noShade",
nowrap: "noWrap",
readonly: "readOnly",
rowspan: "rowSpan",
tabindex: "tabIndex",
usemap: "useMap",
valuetype: "valueType",
vlink: "vLink"
};
 
/* DOM preselection (why?) */
//this.W3CDOM = 3;
//this.IE4DOM = 2;
//this.NS4DOM = 1;
//this.DOM = this.supported
// && (this.isW3CDOM && this.W3CDOM)
// || (this.isIE4DOM && this.IE4DOM)
// || (this.isNS4DOM && this.NS4DOM);
 
/* allows for de.pointedears.jsx.dom */
if (typeof de == "undefined")
{
/**
* @namespace
* Sets the value of an attribute of an HTMLElement object.
*
* @author
* (C) 2003, 2006 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @param o
* @param {string} sAttrName
* Name of the attribute for which the value should be set.
* Attribute names for which an ECMAScript language binding
* is defined in W3C DOM Level 2 HTML, are automatically
* mapped to the corresponding element object property.
* All attribute names are automatically mapped to their
* camelCased equivalent.
*
* Semicolon-separated style property declarations (in
* form of colon-separated name-value pairs each) of a
* <code>style</code> attribute value are mapped to the
* corresponding properties of the object referenced by
* the <code>style</code> property of the element object.
* Declarations are evaluated from left to right, where
* property values complement or replace the previously
* defined ones.
* @param attrValue
* Value of the attribute to be set. The value is
* converted to number if it can be interpreted as such.
* @return {any}
* The value of the attribute of the element object;
* a null-string if no matching object exists or if the DOM
* does not provide retrieval of the attribute's values.
*/
var de = {};
}
function _setAttr (o, sAttrName, attrValue)
{
var result = "";
 
if (typeof de.pointedears == "undefined")
{
/**
* @namespace
*/
de.pointedears = {};
}
if (o && sAttrName)
{
/* camel-case specific attribute names */
if (typeof attrMap[sAttrName] != "undefined")
{
sAttrName = _attrMap[sAttrName];
}
 
if (typeof de.pointedears.jsx == "undefined")
{
var strToValue =
/**
* Converts a string, if possible, to a number
*
* @param {string} s
* @return {string|number}
* The converted value
*/
function (s) {
s = s.replace(/^["']|["']$/g, "");
return isNaN(s) ? s : +s;
};
 
if (typeof attrValue != "undefined")
{
attrValue = strToValue(attrValue);
if (sAttrName == "style" && typeof attrValue == "string")
{
var styleProps = attrValue.split(/\s*;\s*/);
for (var i = 0, len = styleProps.length; i < len; i++)
{
var
stylePair = styleProps[i].split(/\s*:\s*/),
stylePropName = stylePair[0].toLowerCase();
 
jsx.dom.css.setStyleProperty(o, stylePropName,
strToValue(stylePair[1]));
result = jsx.dom.css.getStyleProperty(o, stylePropName);
}
}
else
{
result = o[sAttrName] = attrValue;
}
}
else if (!(o[sAttrName] = true))
{
result = o[sAttrName] = sAttrName;
}
}
 
return result;
}
 
/**
* @namespace
* Creates a node or several nodes from an object.
*
* Creates a DOM {@link Node} or an {@link Array} of several
* <code>Node</code>s from the argument, depending on its type:
* <table>
* <thead>
* <tr>
* <th>Type</th>
* <th>Return value</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <th>{@link String}</th>
* <td>{@link Text}</td>
* </tr>
* <tr>
* <th><code>Array</code> of {@link Object} or <code>String</code></th>
* <td><code>Array</code> of <code>Node</code>. The input
* <code>Array</code>'s elements are processed recursively.</td>
* </tr>
* <tr>
* <th><code>Object</code></th>
* <td>{@link Element}. The following of the input
* <code>Object</code>'s properties are considered:
* <table>
* <thead>
* <th>Property</th>
* <th>Expected type</th>
* <th>Meaning</th>
* </thead>
* <tbody>
* <tr>
* <th><code><var>elementType</var></code> or
* <code><var>type</var></code></th>
* <td><code>String</code></td>
* <td>Element type (case-sensitivity depends on
* the document type)</td>
* </tr>
* <!--<tr>
* <th><code><var>attributes</var></code></th>
* <td><code>Object</code></td>
* <td>Attributes of the element. All attributes
* are created in the <code>null</code> namespace.</td>
* </tr>-->
* <tr>
* <th><code><var>properties</var></code></th>
* <td><code>Object</code></td>
* <td>Properties of the element object. The property
* <code>style</code> is handled specially: Its
* value should be an <code>Object</code> whose
* property names are <code>style</code> property
* names and whose property values are the
* corresponding values, as supported by
* {@link jsx.dom.css#setStyleProperty()}.
* <!--Note that some properties may overwrite
* attributes.-->
* </tr>
* <tr>
* <th><code><var>childNodes</var></code></th>
* <td><code>Array</code> of <code>Object</code>
* or <code>String</code></td>
* <td>Child nodes of the element node.
* The elements of the <code>Array</code>
* are processed recursively.
* </tr>
* </tbody>
* </table></td>
* </tr>
* </tbody>
* </table>
* @param {Array|Object} data
* @return TextNode|Array[Node]|Element
*/
de.pointedears.jsx = jsx;
}
 
/**
* Shows an exception alert and allows for
* displaying a stack trace.
*
* @param {string} sMessage = ""
* Error message to be displayed.
* @return {boolean}
* Always <code>false</code>
*/
jsx.dom.DHTMLException = function (sMessage) {
/* Prevent exceptions from "bubbling" on (keyboard) event */
if (!jsx.dom.allowExceptionMsg)
function _createNodesFromObj (data)
{
return false;
}
if (typeof data.valueOf() == "string")
{
return document.createTextNode(data);
}
 
jsx.dom.allowExceptionMsg = false;
/* Support ES5 strict mode */
var me = _createNodesFromObj;
 
jsx.setErrorHandler();
var stackTrace =
jsx.object.isMethod(_global, "Error") && (new Error()).stack || "";
/* If input is an Array, output is an Array of Nodes */
if (_isArray(data))
{
var a = [];
 
jsx.clearErrorHandler();
for (var i = 0, len = data.length; i < len; ++i)
{
a[i] = me(data[i]);
}
 
alert(
"dhtml.js "
+ jsx.dom.version + "\n"
+ jsx.dom.copyright + " "
+ jsx.dom.author + " <" + jsx.dom.email + ">\n"
+ 'The latest version can be obtained from:\n'
+ "<" + jsx.dom.URI + ">\n\n"
+ sMessage + "\n"
+ "__________________________________________________________\n"
+ "Stack trace"
+ (stackTrace
? ":\n\n" + stackTrace
: " not available in this DOM."));
return a;
}
 
jsx.dom.allowExceptionMsg = true;
return false;
};
var el = document.createElement(data.elementType || data.type);
if (!el)
{
return null;
}
 
jsx.dom.write = function (s) {
var result = jsx.tryThis(
function () {
document.write(s);
var attributes = data.attributes;
if (attributes && _isHostMethod(el, "setAttribute"))
{
var keys = _getKeys(attributes);
 
return true;
},
function () {
return jsx.tryThis(
function () {
var result2 = false;
var ns = document.documentElement.getAttribute("xmlns");
var scripts;
if (ns)
for (var i = 0, len = keys.length; i < len; ++i)
{
var attrName = keys[i];
el.setAttribute(attrName, attributes[attrName]);
}
}
 
var properties = data.properties;
if (properties)
{
keys = _getKeys(properties);
 
for (i = 0, len = keys.length; i < len; ++i)
{
var propName = keys[i];
 
if (propName == "style")
{
var style = properties[propName];
var _setStyleProperty = jsx.object.getFeature(jsx.dom, "css", "setStyleProperty");
if (typeof style != "string" && typeof _setStyleProperty != "function")
{
scripts = document.getElementsByTagNameNS(ns, "script");
jsx.warn("JSX:dom/css.js:jsx.dom.css.setStyleProperty()"
+ " is recommended for setting style object properties");
el[propName] = style;
}
else
{
scripts = document.getElementsByTagName("script");
var styleKeys = _getKeys(style);
for (var i = 0, len = styleKeys.length; i < len; ++i)
{
var stylePropName = styleKeys[i];
_setStyleProperty(el, stylePropName, style[stylePropName]);
}
}
}
else
{
el[propName] = properties[propName];
}
}
}
 
if (scripts && scripts.length > 0)
{
var lastScript = scripts[scripts.length - 1];
result2 = !!lastScript.parentNode.insertBefore(
document.createTextNode(s), lastScript.nextSibling);
}
var nodes = data.childNodes;
for (var i = 0, len = nodes && nodes.length; i < len; ++i)
{
el.appendChild(me(nodes[i]));
}
 
return result2;
});
});
return el;
}
 
/* fix circular reference */
s = null;
 
return result;
};
 
/**
* Retrieves an HTMLElement object or a collection of such
* objects that match certain criteria.
*
* @author
* (C) 2003, 2004 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @param {string} sType
* Defines the type of <code>sValue</code>. Valid values are
* "id", "name", "tagname", "index" and "classname". The
* argument is case-insensitive.
* @param {string} sValue (optional)
* Case-sensitive ID, name or tag name of object (collection).
* @param {number} index (optional)
* Numeric index of an element of the selected
* collection. For IDs must be unique throughout a document,
* this argument is ignored if <code>sType</code> is "id".
* @return {HTMLElement|NodeList|Null}
* A reference to an object if <code>sType</code> is "id", or
* if it is "name" or "tagname" and <code>index</code> is
* specified; otherwise a collection of objects matching the
* specified criteria; <code>null</code> if no matching object
* exists.
*/
jsx.dom.getElem = function (sType, sValue, index) {
/**
* Calls DHTMLException() for an invalid type.
* Adds a class name to the <code>class</code> attribute of
* an {@link Element}.
*
* @param {Element} o
* @param {string} sClassName
* @return {boolean}
* <code>true</code> if the class name could be added successfully or
* was already there, <code>false</code> otherwise.
*/
function invalidType()
function _hasClassName (o, sClassName)
{
jsx.dom.DHTMLException(
'getElem: Invalid type "' + sType + '"\n'
+ 'Must be one of "id", "name", "tagname", "index" or "classname"'
+ ' (case-insensitive).');
}
if (sClassName)
{
if (_isHostMethod(o, "classList", "contains"))
{
/* W3C DOM Level 4 */
return o.classList.contains(sClassName);
}
 
if (!sType || typeof sType != "string" || !sType.toLowerCase)
{
jsx.dom.DHTMLException(
"getElem: Invalid type: " + sType + "\n"
+ "Must be string.");
var rx = new RegExp("(^\\s*|\\s+)" + sClassName + "(\\s*$|\\s)");
return rx.test(sClassName);
}
}
 
if (!sValue || typeof sValue != "string")
/**
* Removes all occurences of a class name from the
* <code>class</code> attribute of an {@link Element}.
*
* For compatibility, if possible removes the <code>class</code>
* attribute if it is empty afterwards.
*
* @param {Element} o
* @param {string} sClassName
* @return {boolean}
* <code>true</code> if successful, <code>false</code> otherwise.
*/
function _removeClassName (o, sClassName)
{
jsx.dom.DHTMLException(
"getElem: Invalid value: " + sValue + "\n"
+ "Must be string.");
}
if (_isHostMethod(o, "classList", "remove"))
{
/* W3C DOM Level 4 */
o.classList.remove(sClassName);
}
else
{
var curClassNames = o.className;
var newClassNames = curClassNames.replace(
new RegExp(("(^\\s*|\\s+)" + sClassName + "(\\s*$|(\\s))"), "g"),
"$3");
o.className = newClassNames;
 
var o = null;
if (!newClassNames && _isMethod(o, "removeAttribute"))
{
o.removeAttribute("class");
}
}
 
switch ((sType = sType.toLowerCase()))
{
case 'id':
case 'index':
case 'classname':
o = jsx.dom["getElemBy" + {
id: "Id",
index: "Index",
classname: "ClassName"
}[sType]](sValue);
break;
 
case 'name':
case 'tagname':
o = jsx.dom["getElemBy" + {
name: "Name",
tagname: "TagName"
}[sType]](sValue, index);
break;
 
default:
invalidType();
return !_hasClassName(o, sClassName);
}
 
return o;
};
 
/**
* Retrieves the content of an HTMLElement object.
*
* @author (C) 2003-2005, 2010 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @param {HTMLElement} oElement
* Element which content is to be retrieved.
* @param {boolean} bHTML (optional)
* If <code>true</code>, returns the HTML content instead of
* the text content in case the latter cannot be retrieved.
* @return {string}
* A string with the content of the element; a null-string if
* no such element object exists or if the DOM does not provide
* retrieval of the element's content.
*/
jsx.dom.getCont = function (oElement, bHTML) {
var sResult = "";
 
if (oElement)
/**
* Appends a child node to a parent node.
*
* @param {Node} parentNode
* @param {Node} childNode
* @return {boolean}
* <code>true</code> on success, <code>false</code> otherwise.
*/
function _appendChild (parentNode, childNode)
{
/* W3C DOM Level 2 Core */
if (typeof oElement.firstChild != "undefined")
if (parentNode)
{
if (typeof oElement.firstChild.nodeType != "undefined"
&& oElement.firstChild.nodeType ==
/* W3C-DOM 2 o.firstChild.TEXT_NODE constant is N/A in IE and O7 */
((typeof oElement.firstChild.TEXT_NODE != "undefined"
&& oElement.firstChild.TEXT_NODE)
|| 3))
if (_isMethod(parentNode, "appendChild"))
{
sResult = oElement.firstChild.nodeValue;
parentNode.appendChild(childNode);
return true;
}
else if (_isMethod(parentNode, "insertAdjacentElement"))
{
parentNode.insertAdjacentElement("beforeEnd", childNode);
return true;
}
}
else
 
return false;
}
 
function _insertBefore (parentNode, newChild, refChild)
{
if (parentNode)
{
if (typeof oElement.innerText != "undefined")
if (_isMethod(parentNode, "insertBefore"))
{
sResult = oElement.innerText;
/* W3C DOM */
parentNode.insertBefore(newChild, refChild);
return true;
}
 
if ((bHTML || typeof oElement.innerText == "undefined")
&& typeof oElement.innerHTML != "undefined")
/* MSHTML 4 DOM */
if (refChild)
{
sResult = oElement.innerHTML;
if (_isMethod(refChild, "insertAdjacentElement"))
{
refChild.insertAdjacentElement("beforeBegin", newChild);
return true;
}
}
else
{
if (_isMethod(parentNode, "insertAdjacentElement"))
{
parentNode.insertAdjacentElement("afterBegin", newChild);
return true;
}
}
}
 
return false;
}
 
return sResult;
};
 
/**
* Specifies the content of an HTMLElement object.
*
* @author (C) 2003-2005, 2010 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @param {HTMLElement} oElement
* Element which content is to be changed.
* @param {string} sNodeValue
* New content of the element.
* @return {boolean}
* <code>true</code> if successful, <code>false</code>
* otherwise.
*/
jsx.dom.setCont = function (oElement, sNodeValue) {
if (oElement)
/**
* Removes a child node from a parent node.
*
* @param {Node} parentNode
* @param {Node} childNode
* @return {boolean}
* <code>true</code> on success, <code>false</code> otherwise.
*/
function _removeChild (parentNode, childNode)
{
/* DOM Level 2 Core */
if (typeof oElement.firstChild != "undefined")
if (parentNode)
{
oElement.firstChild.nodeValue = sNodeValue;
return true;
if (_isMethod(parentNode, "removeChild"))
{
/* W3C DOM */
parentNode.removeChild(childNode);
return true;
}
else if (_isMethod(childNode, "removeNode"))
{
/* MSHTML 4 DOM */
childNode.removeNode(true);
return true;
}
}
else if (typeof oElement.nodeValue != "undefined")
 
return false;
}
 
/**
* Exception thrown if an invalid Node reference is passed
*
* @function
*/
var _InvalidNodeError = (function (contextNode) {
jsx.Error.call(this, contextNode);
}).extend(jsx.Error, {
name: "jsx.dom.InvalidNodeError"
});
 
function jsx_dom_collectNamespaces (namespaces, contextNode) {
var me = jsx_dom_collectNamespaces;
 
if (!namespaces)
{
oElement.nodeValue = sNodeValue;
return true;
jsx.warn("`namespaces' is not convertible to an Object; argument is not modified.");
namespaces = {};
}
 
/* IE4 DOM */
else if (typeof oElement.innerText != "undefined")
/* Scan entire document by default */
if (!contextNode)
{
oElement.innerText = sNodeValue;
return true;
contextNode = document.documentElement;
}
 
/* NS4 DOM */
else if (jsx.dom.isNS4DOM
&& oElement.document
&& oElement.document.open
&& oElement.document.write
&& oElement.document.close)
/* if DOCUMENT_NODE, use root element */
if (contextNode.nodeType == 9)
{
oElement.document.open();
oElement.document.write(sNodeValue);
oElement.document.close();
return true;
contextNode = contextNode.documentElement;
}
}
 
return false;
};
 
/**
* Returns the text content of a document node.
*
* @author
* (C) 2005 Thomas Lahn <dhtml.js@PointedEars.de>
* @param {Node} oNode
* Reference to the document node.
* @param {boolean} bGetHTML (optional)
* If <code>true</code>, returns the HTML content instead of
* the text content in case the latter cannot be retrieved.
* @return {string}
* The text content of @{(oNode)}.
* @todo Duplicate of getCont(..., false)?
*/
jsx.dom.getContent = function (oNode, bGetHTML) {
var text = "";
 
if (oNode)
{
/* W3C DOM Level 3 */
if (typeof oNode.textContent != "undefined")
if (!contextNode || contextNode.nodeType != 1)
{
text = oNode.textContent;
jsx.throwThis(_InvalidNodeError, contextNode);
return null;
}
 
/* W3C DOM Level 2 */
else if (oNode.childNodes && oNode.childNodes.length)
for (var i = 0, attribs = contextNode.attributes, len = attribs && attribs.length;
i < len;
++i)
{
for (var i = oNode.childNodes.length; i--;)
var attr = attribs[i];
var attr_name = attr.name;
var matches;
 
if ((matches = String(attr_name).match(/^xmlns($|:(.+))/)))
{
var o = oNode.childNodes[i];
if (o.nodeType == ((typeof Node != "undefined" && Node.TEXT_NODE)
|| 3))
var original_prefix = matches[2];
var prefix = original_prefix || "_";
 
if (typeof namespaces[prefix] == "undefined")
{
text = o.nodeValue + text;
var attr_value = attr.value;
 
/*
* Default NS declaration with empty value means _no_ namespace,
* see <http://www.w3.org/TR/REC-xml-names/#defaulting>
*/
if (!original_prefix && attr_value == "")
{
attr_value = null;
}
 
namespaces[prefix] = attr_value;
}
else
{
text = arguments.callee(o) + text;
}
}
}
 
/* proprietary: IE4+ */
else if (typeof oNode.innerText != "undefined")
for (var i = 0, childNodes = contextNode.childNodes, len = childNodes && childNodes.length;
i < len;
++i)
{
text = oNode.innerText;
var childNode = childNodes[i];
 
/* If ELEMENT_NODE, recurse */
if (childNode.nodeType == 1)
{
jsx.tryThis(
function() {
me(namespaces, childNode);
},
function (e) {
if (e.constructor == _InvalidNodeError)
{
jsx.throwThis(e);
}
});
}
}
 
return namespaces;
}
 
return text;
};
/**
* Retrieves descendant focusable elements in order of their
* "tabindex" attribute.
*
* @author
* (C) 2004 Thomas Lahn <dhtml.js@PointedEars.de>
* @requires
* http://pointedears.de/scripts/collection.js
* @param {Document|Element} o (optional)
* Reference to a {@link dom2-core#Document Document} or
* {@link dom2-core#Element Element} object from which to retrieve
* descendant elements. If omitted or evaluated to
* <code>false</code>, it is tried to use the calling object.
* @return {Collection}
* A reference to a {@link #Collection} object containing
* the descendant elements of <var>o</var> or the calling
* {@link dom2-core#Document Document}/{@link dom2-core#Element Element}
* object in "tabindex" order: Elements with "tabindex" > 0 come first,
* followed by elements with "tabindex" == 0 or where either
* "tabindex" is not set or not applicable. Note: An element
* with a "tabindex" of 1 will will be the first element
* in the resulting collection but for design reasons will
* have an index of 0 (but since the Collection prototype
* provides an iterator, this does not need to disturb you).
* Additional note: Unlike specified, disabled elements will
* participate in the tabbing order (so they can be enabled
* later without this method to be re-called.)
*/
function _getElementsByTabIndex (o)
{
var aIndexedElements = new Array();
var aUnindexedElements = new Array();
 
/**
* Sets the text content of a document node.
*
* @author
* (C) 2005 Thomas Lahn <dhtml.js@PointedEars.de>
* @param {Node} oNode
* Reference to the document node.
* @param {string} sContent
* @return {boolean}
* <code>true</code> if successful, <code<false</code> otherwise.
*/
jsx.dom.setTextContent = function (oNode, sContent) {
var result = false;
 
if (oNode)
{
/* W3C DOM Level 3 */
if (typeof oNode.textContent != "undefined")
/* makes the method applicable to Document and Element objects */
if (!o
&& typeof this.constructor != "undefined"
&& /Document|Element/.test(this.constructor))
{
oNode.textContent = sContent;
result = (oNode.textContent == sContent);
o = this;
}
 
/* W3C DOM Level 2 */
else if (oNode.removeChild && oNode.firstChild)
if (_isMethod(o, "getElementsByTagName"))
{
while (oNode.firstChild)
var es = o.getElementsByTagName("*");
 
if (es && typeof es.length != "undefined")
{
oNode.removeChild(oNode.firstChild);
var l = es.length;
 
for (var i = 0, e; i < l; i++)
{
e = es[i];
 
if (typeof e.tabIndex != "undefined")
{
/* !null && !0 */
if (e.tabIndex)
{
/*
* tabindex="1" --> index == 0; use e.tabIndex
* and a "zero dummy" if you do not like this
*/
aIndexedElements[e.tabIndex - 1] = e;
}
else
{
aUnindexedElements[aUnindexedElements.length] = e;
}
}
}
}
 
result = !!oNode.appendChild(document.createTextNode(sContent));
}
 
/* proprietary: IE4+ */
else if (typeof oNode.innerText != "undefined")
{
oNode.innerText = sContent;
result = (oNode.innerText == sContent);
}
return new Collection(aIndexedElements.concat(aUnindexedElements));
}
 
return result;
};
var _jsx_dom = {
/**
* @memberOf jsx.dom
*/
version: "$Id$",
copyright: "Copyright \xA9 2002-2013",
author: "Thomas Lahn",
email: "js@PointedEars.de",
path: "http://pointedears.de/scripts/",
 
/**
* Retrieves the value of an attribute of an HTMLElement object
* that matches certain criteria.
*
* @author
* (C) 2003, 2008, 2010 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @param {HTMLElement} oElement
* @param {string} sAttrName
* Name of the attribute from which the value
* should be retrieved.
* @return {any}
* The value of the object if <code>sType</code> is "id",
* or if it is "name" or "tagname" and <code>index</code>
* is specified;
* a null-string if no matching object exists or if the DOM
* does not provide retrieval of the attribute's values.
*/
jsx.dom.getAttr = function (oElement, sAttrName) {
var result = "";
hasDocumentAll: _hasDocumentAll,
hasDocumentLayers: _hasDocumentLayers,
hasGetElementsByTagName: _hasGetElementsByTagName,
 
if (oElement)
{
if (jsx.object.isMethod(oElement, "getAttribute"))
{
result = oElement.getAttribute(sAttrName);
}
else if (jsx.dom.isNS4DOM)
{
result = oElement[sAttrName];
}
}
/*
* Apart from isNS4DOM, none of these object-inference properties is used
* anymore; they are still here for backwards compatibility only
*/
//isW3CDOM: _isMethod(document, "getElementById"),
//isOpera: typeof window.opera != "undefined";
isNS4DOM: typeof document.layers != "undefined",
//isIE4DOM: typeof document.all == "object" && !this.isOpera,
 
return result;
};
/* DOM preselection (why?) */
//W3CDOM: 3,
//IE4DOM: 2,
//NS4DOM: 1;
 
jsx.dom.attrMap = {
alink: "aLink",
accesskey: "accessKey",
bgcolor: "bgColor",
cellpadding: "cellPadding",
cellspacing: "cellSpacing",
"char": "ch",
charoff: "chOff",
"class": "className",
codebase: "codeBase",
codetype: "codeType",
colspan: "colSpan",
datetime: "dateTime",
frameborder: "frameBorder",
"for": "htmlFor",
ismap: "isMap",
longdesc: "longDesc",
maxlength: "maxLength",
marginheight: "marginHeight",
marginwidth: "marginWidth",
nohref: "noHref",
noresize: "noResize",
noshade: "noShade",
nowrap: "noWrap",
readonly: "readOnly",
rowspan: "rowSpan",
tabindex: "tabIndex",
usemap: "useMap",
valuetype: "valueType",
vlink: "vLink"
};
getElementById: _getElementById,
getElemById: _getElementById,
getEBI: _getElementById,
gEBI: _getElementById,
 
getElementsByName: _getElementsByName,
getElemByName: _getElementsByName,
gEBN: _getElementsByName,
 
/**
* Sets the value of an attribute of an HTMLElement object.
*
* @author
* (C) 2003, 2006 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @param o
* @param {string} sAttrName
* Name of the attribute for which the value should be set.
* Attribute names for which an ECMAScript language binding
* is defined in W3C DOM Level 2 HTML, are automatically
* mapped to the corresponding element object property.
* All attribute names are automatically mapped to their
* camelCased equivalent.
*
* Semicolon-separated style property declarations (in
* form of colon-separated name-value pairs each) of a
* <code>style</code> attribute value are mapped to the
* corresponding properties of the object referenced by
* the <code>style</code> property of the element object.
* Declarations are evaluated from left to right, where
* property values complement or replace the previously
* defined ones.
* @param attrValue
* Value of the attribute to be set. The value is
* converted to number if it can be interpreted as such.
* @return {any}
* The value of the attribute of the element object;
* a null-string if no matching object exists or if the DOM
* does not provide retrieval of the attribute's values.
*/
jsx.dom.setAttr = function (o, sAttrName, attrValue) {
var result = "";
getElementsByTagName: _getElementsByTagName,
getElemByTagName: _getElementsByTagName,
gEBTN: _getElementsByTagName,
 
if (o && sAttrName)
{
var attrMap = jsx.dom.attrMap;
getElementByIndex: _getElementByIndex,
getElemByIndex: _getElementByIndex,
gEBIdx: _getElementByIndex,
 
/* camel-case specific attribute names */
if (typeof attrMap[sAttrName] != "undefined")
{
sAttrName = attrMap[sAttrName];
}
/**
* Shows an exception alert and allows for
* displaying a stack trace.
*
* @param {string} sMessage = ""
* Error message to be displayed.
* @return {boolean}
* Always <code>false</code>
* @deprecated
*/
DHTMLException: function (sMessage) {
/* Prevent exceptions from "bubbling" on (keyboard) event */
if (!jsx.dom.allowExceptionMsg)
{
return false;
}
 
var strToValue =
jsx.dom.allowExceptionMsg = false;
 
jsx.setErrorHandler();
var stackTrace =
_isMethod(_global, "Error") && (new Error()).stack || "";
 
jsx.clearErrorHandler();
 
alert(
"dhtml.js "
+ jsx.dom.version + "\n"
+ jsx.dom.copyright + " "
+ jsx.dom.author + " <" + jsx.dom.email + ">\n"
+ 'The latest version can be obtained from:\n'
+ "<" + jsx.dom.URI + ">\n\n"
+ sMessage + "\n"
+ "__________________________________________________________\n"
+ "Stack trace"
+ (stackTrace
? ":\n\n" + stackTrace
: " not available in this DOM."));
 
jsx.dom.allowExceptionMsg = true;
return false;
},
 
write: function (s) {
var result = jsx.tryThis(
function () {
document.write(s);
 
return true;
},
function () {
return jsx.tryThis(
function () {
var result2 = false;
var ns = document.documentElement.getAttribute("xmlns");
var scripts;
if (ns)
{
scripts = document.getElementsByTagNameNS(ns, "script");
}
else
{
scripts = document.getElementsByTagName("script");
}
 
if (scripts && scripts.length > 0)
{
var lastScript = scripts[scripts.length - 1];
result2 = !!_insertBefore(lastScript.parentNode,
document.createTextNode(s), lastScript.nextSibling);
}
 
return result2;
});
});
 
return result;
},
 
/**
* Retrieves an HTMLElement object or a collection of such
* objects that match certain criteria.
*
* @author
* (C) 2003, 2004 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @param {string} sType
* Defines the type of <code>sValue</code>. Valid values are
* "id", "name", "tagname", "index" and "classname". The
* argument is case-insensitive.
* @param {string} sValue (optional)
* Case-sensitive ID, name or tag name of object (collection).
* @param {number} index (optional)
* Numeric index of an element of the selected
* collection. For IDs must be unique throughout a document,
* this argument is ignored if <code>sType</code> is "id".
* @return {HTMLElement|NodeList|Null}
* A reference to an object if <code>sType</code> is "id", or
* if it is "name" or "tagname" and <code>index</code> is
* specified; otherwise a collection of objects matching the
* specified criteria; <code>null</code> if no matching object
* exists.
*/
getElem: function (sType, sValue, index) {
/**
* Converts a string, if possible, to a number
*
* @param {string} s
* @return {string|number}
* The converted value
* Calls DHTMLException() for an invalid type.
*/
function (s) {
s = s.replace(/^["']|["']$/g, "");
return isNaN(s) ? s : +s;
};
function invalidType()
{
jsx.dom.DHTMLException(
'getElem: Invalid type "' + sType + '"\n'
+ 'Must be one of "id", "name", "tagname", "index" or "classname"'
+ ' (case-insensitive).');
}
 
if (typeof attrValue != "undefined")
{
attrValue = strToValue(attrValue);
if (sAttrName == "style" && typeof attrValue == "string")
if (!sType || typeof sType != "string" || !sType.toLowerCase)
{
var styleProps = attrValue.split(/\s*;\s*/);
for (var i = 0, len = styleProps.length; i < len; i++)
jsx.dom.DHTMLException(
"getElem: Invalid type: " + sType + "\n"
+ "Must be string.");
}
 
if (!sValue || typeof sValue != "string")
{
jsx.dom.DHTMLException(
"getElem: Invalid value: " + sValue + "\n"
+ "Must be string.");
}
 
var o = null;
 
switch ((sType = sType.toLowerCase()))
{
case 'id':
case 'index':
case 'classname':
o = jsx.dom["getElemBy" + {
id: "Id",
index: "Index",
classname: "ClassName"
}[sType]](sValue);
break;
 
case 'name':
case 'tagname':
o = jsx.dom["getElemBy" + {
name: "Name",
tagname: "TagName"
}[sType]](sValue, index);
break;
 
default:
invalidType();
}
 
return o;
},
 
/**
* Retrieves the content of an HTMLElement object.
*
* @author (C) 2003-2005, 2010 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @param {HTMLElement} oElement
* Element which content is to be retrieved.
* @param {boolean} bHTML (optional)
* If <code>true</code>, returns the HTML content instead of
* the text content in case the latter cannot be retrieved.
* @return {string}
* A string with the content of the element; a null-string if
* no such element object exists or if the DOM does not provide
* retrieval of the element's content.
*/
getCont: function (oElement, bHTML) {
var sResult = "";
 
if (oElement)
{
/* W3C DOM Level 2 Core */
if (typeof oElement.firstChild != "undefined")
{
var
stylePair = styleProps[i].split(/\s*:\s*/),
stylePropName = stylePair[0].toLowerCase();
if (typeof oElement.firstChild.nodeType != "undefined"
&& oElement.firstChild.nodeType ==
/* W3C-DOM 2 o.firstChild.TEXT_NODE constant is N/A in IE and O7 */
((typeof oElement.firstChild.TEXT_NODE != "undefined"
&& oElement.firstChild.TEXT_NODE)
|| 3))
{
sResult = oElement.firstChild.nodeValue;
}
}
else
{
if (typeof oElement.innerText != "undefined")
{
sResult = oElement.innerText;
}
 
jsx.dom.css.setStyleProperty(o, stylePropName,
strToValue(stylePair[1]));
result = jsx.dom.css.getStyleProperty(o, stylePropName);
if ((bHTML || typeof oElement.innerText == "undefined")
&& typeof oElement.innerHTML != "undefined")
{
sResult = oElement.innerHTML;
}
}
}
else
 
return sResult;
},
 
/**
* Specifies the content of an HTMLElement object.
*
* @author (C) 2003-2005, 2010 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @param {HTMLElement} oElement
* Element which content is to be changed.
* @param {string} sNodeValue
* New content of the element.
* @return {boolean}
* <code>true</code> if successful, <code>false</code>
* otherwise.
*/
setCont: function (oElement, sNodeValue) {
if (oElement)
{
result = o[sAttrName] = attrValue;
/* DOM Level 2 Core */
if (typeof oElement.firstChild != "undefined")
{
oElement.firstChild.nodeValue = sNodeValue;
return true;
}
else if (typeof oElement.nodeValue != "undefined")
{
oElement.nodeValue = sNodeValue;
return true;
}
 
/* IE4 DOM */
else if (typeof oElement.innerText != "undefined")
{
oElement.innerText = sNodeValue;
return true;
}
 
/* NS4 DOM */
else if (jsx.dom.isNS4DOM
&& oElement.document
&& oElement.document.open
&& oElement.document.write
&& oElement.document.close)
{
oElement.document.open();
oElement.document.write(sNodeValue);
oElement.document.close();
return true;
}
}
}
else if (!(o[sAttrName] = true))
{
result = o[sAttrName] = sAttrName;
}
}
 
return result;
};
return false;
},
 
/**
* Creates an element of the type specified, using the
* <code>document.createElement()</code> method if supported.
* This method works with MSIE, too, for if JScript is used,
* it is tried to use the start tag as is instead of passing
* only the element type, and adding properties later.
*
* @function
* @author
* &copy; 2004, 2006, 2010 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @see <a href="dom2-core#ID-2141741547">DOM Level 2 Core: Document::createElement()</a>
* @see <a href="msdn#workshop/author/dhtml/reference/methods/createelement.asp">MSDN Library: createElement()</a>
*/
jsx.dom.createElement = (function () {
var _setAttr = jsx.dom.setAttr;
/**
* Returns the text content of a document node.
*
* @author
* (C) 2005 Thomas Lahn <dhtml.js@PointedEars.de>
* @param {Node} oNode
* Reference to the document node.
* @param {boolean} bGetHTML (optional)
* If <code>true</code>, returns the HTML content instead of
* the text content in case the latter cannot be retrieved.
* @return {string}
* The text content of @{(oNode)}.
* @todo Duplicate of getCont(..., false)?
*/
getContent: function (oNode, bGetHTML) {
var text = "";
 
/**
* @param {string} sTag
* Start tag or element type of the element to be created.
* Passing a start tag even works if the UA is not MSIE,
* as attributes and values given are parsed from left to
* right into the corresponding element object properties.
* @return {Element}
* A reference to a new <code>Element</code> object with the
* <code>nodeName</code> property set to <code>sTagName</code>,
* and the <code>localName</code>, <code>prefix</code>,
* and <code>namespaceURI</code> properties set to
* <code>null</code>.
*/
return function (sTag) {
var o = null;
if (oNode)
{
/* W3C DOM Level 3 */
if (typeof oNode.textContent != "undefined")
{
text = oNode.textContent;
}
 
if (sTag
&& typeof document != "undefined"
&& jsx.object.isMethod(document, "createElement"))
{
/*@cc_on @*/
/*@if (@_jscript)
o = document.createElement(sTag);
@end @*/
/* W3C DOM Level 2 */
else if (oNode.childNodes && oNode.childNodes.length)
{
for (var i = oNode.childNodes.length; i--;)
{
var o = oNode.childNodes[i];
if (o.nodeType == ((typeof Node != "undefined" && Node.TEXT_NODE)
|| 3))
{
text = o.nodeValue + text;
}
else
{
text = arguments.callee(o) + text;
}
}
}
 
if (!o)
/* proprietary: IE4+ */
else if (typeof oNode.innerText != "undefined")
{
text = oNode.innerText;
}
}
 
return text;
},
 
/**
* Sets the text content of a document node.
*
* @author
* (C) 2005 Thomas Lahn <dhtml.js@PointedEars.de>
* @param {Node} oNode
* Reference to the document node.
* @param {string} sContent
* @return {boolean}
* <code>true</code> if successful, <code>false</code> otherwise.
*/
setTextContent: function (oNode, sContent) {
var result = false;
 
if (oNode)
{
/* W3C DOM Level 3 */
if (typeof oNode.textContent != "undefined")
{
oNode.textContent = sContent;
result = (oNode.textContent == sContent);
}
 
/* W3C DOM Level 2 */
else if (oNode.removeChild && oNode.firstChild)
{
while (oNode.firstChild)
{
oNode.removeChild(oNode.firstChild);
}
 
result = !!oNode.appendChild(document.createTextNode(sContent));
}
 
/* proprietary: IE4+ */
else if (typeof oNode.innerText != "undefined")
{
oNode.innerText = sContent;
result = (oNode.innerText == sContent);
}
}
 
return result;
},
 
/**
* Retrieves the value of an attribute of an HTMLElement object
* that matches certain criteria.
*
* @author
* (C) 2003, 2008, 2010 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @param {HTMLElement} oElement
* @param {string} sAttrName
* Name of the attribute from which the value
* should be retrieved.
* @return {any}
* The value of the object if <code>sType</code> is "id",
* or if it is "name" or "tagname" and <code>index</code>
* is specified;
* a null-string if no matching object exists or if the DOM
* does not provide retrieval of the attribute's values.
*/
getAttr: function (oElement, sAttrName) {
var result = "";
 
if (oElement)
{
if (_isMethod(oElement, "getAttribute"))
{
result = oElement.getAttribute(sAttrName);
}
else if (jsx.dom.isNS4DOM)
{
result = oElement[sAttrName];
}
}
 
return result;
},
 
attrMap: _attrMap,
 
setAttr: _setAttr,
 
/**
* Creates an element of the type specified, using the
* <code>document.createElement()</code> method if supported.
* This method works with MSIE, too, for if JScript is used,
* it is tried to use the start tag as is instead of passing
* only the element type, and adding properties later.
*
* @param {string} sTag
* Start tag or element type of the element to be created.
* Passing a start tag even works if the UA is not MSIE,
* as attributes and values given are parsed from left to
* right into the corresponding element object properties.
* @return {Element}
* A reference to a new <code>Element</code> object with the
* <code>nodeName</code> property set to <code>sTagName</code>,
* and the <code>localName</code>, <code>prefix</code>,
* and <code>namespaceURI</code> properties set to
* <code>null</code>.
* @author
* &copy; 2004, 2006, 2010 Thomas Lahn &lt;dhtml.js@PointedEars.de&gt;
* @see <a href="dom2-core#ID-2141741547">DOM Level 2 Core: Document::createElement()</a>
* @see <a href="msdn#workshop/author/dhtml/reference/methods/createelement.asp">MSDN Library: createElement()</a>
*/
createElement: function (sTag, sNamespaceURI) {
var o = null;
 
if (sTag && typeof document != "undefined")
{
/* NOTE: Uses RegExp() to work around misconfigured PHP (short_open_tag=1) */
var aTagComponents = sTag.replace(new RegExp("^<\?\\s*|\\s*>?$", "g"), "")
.replace(/\s*=\s*/g, "=").split(/\s+/);
o = document.createElement(aTagComponents[0]);
 
var local_name = aTagComponents[0];
if (sNamespaceURI && _isMethod(document, "createElementNS"))
{
o = document.createElementNS(sNamespaceURI, local_name);
}
 
if (!o && _isMethod(document, "createElement"))
{
/*@cc_on @*/
/*@if (@_jscript)
o = document.createElement(sTag);
@end @*/
 
if (!o)
{
o = document.createElement(local_name);
}
}
 
if (o)
{
aTagComponents.shift();
1020,828 → 1484,987
}
}
}
}
 
return o;
};
}());
return o;
},
 
/**
* Creates a node or several nodes from an object.
*
* Creates a DOM {@link Node} or an {@link Array} of several
* <code>Node</code>s from the argument, depending on its type:
* <table>
* <thead>
* <tr>
* <th>Type</th>
* <th>Return value</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <th>{@link String}</th>
* <td>{@link Text}</td>
* </tr>
* <tr>
* <th><code>Array</code> of {@link Object} or <code>String</code></th>
* <td><code>Array</code> of <code>Node</code>. The input
* <code>Array</code>'s elements are processed recursively.</td>
* </tr>
* <tr>
* <th><code>Object</code></th>
* <td>{@link Element}. The following of the input
* <code>Object</code>'s properties are considered:
* <table>
* <thead>
* <th>Property</th>
* <th>Expected type</th>
* <th>Meaning</th>
* </thead>
* <tbody>
* <tr>
* <th><code><var>elementType</var></code> or
* <code><var>type</var></code></th>
* <td><code>String</code></td>
* <td>Element type (case-sensitivity depends on
* the document type)</td>
* </tr>
* <!--<tr>
* <th><code><var>attributes</var></code></th>
* <td><code>Object</code></td>
* <td>Attributes of the element. All attributes
* are created in the <code>null</code> namespace.</td>
* </tr>-->
* <tr>
* <th><code><var>properties</var></code></th>
* <td><code>Object</code></td>
* <td>Properties of the element object. The property
* <code>style</code> is handled specially: Its
* value should be an <code>Object</code> whose
* property names are <code>style</code> property
* names and whose property values are the
* corresponding values, as supported by
* {@link jsx.dom.css#setStyleProperty()}.
* <!--Note that some properties may overwrite
* attributes.-->
* </tr>
* <tr>
* <th><code><var>childNodes</var></code></th>
* <td><code>Array</code> of <code>Object</code>
* or <code>String</code></td>
* <td>Child nodes of the element node.
* The elements of the <code>Array</code>
* are processed recursively.
* </tr>
* </tbody>
* </table></td>
* </tr>
* </tbody>
* </table>
* @function
*/
jsx.dom.createElementFromObj = jsx.dom.createNodeFromObj =
jsx.dom.createNodesFromObj = (function () {
var _getKeys = jsx.object.getKeys;
var _isArray = jsx.object.isArray;
var _isHostMethod = jsx.object.isHostMethod;
/**
* Creates a SGML/HTML markup from an object.
*
* Returns a {@link string} from the argument, depending on
* its type:
* <table>
* <thead>
* <tr>
* <th>Type</th>
* <th>Return value</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <th>{@link String}</th>
* <td><code>string</code> with characters
* escaped according to the following table:
* <table>
* <tr>
* <th>Character</th>
* <th>Escape</th>
* </tr>
* <tr><td><code>"</code></td><td><code>&amp;quot;</code></td></tr>
* <tr><td><code>&amp;</code></td><td><code>&amp;amp;</code></td></tr>
* <tr><td><code>&lt;</code></td><td><code>&amp;lt;</code></td></tr>
* <tr><td><code>></code></td><td><code>&amp;gt;</code></td></tr>
* </table>
* <p>This is also used internally to ensure that
* attribute values and element content is
* properly escaped.</p></td>
* </tr>
* <tr>
* <th><code>Array</code> of {@link Object} or <code>String</code></th>
* <td>Markup s<code>string</code> of elements and text.
* The input <code>Array</code>'s elements are processed
* recursively.</td>
* </tr>
* <tr>
* <th><code>Object</code></th>
* <td>Markup <code>string</code> for one element and,
* optionally, its content. The following of
* the input <code>Object</code>'s properties
* are considered:
* <table>
* <thead>
* <th>Property</th>
* <th>Expected type</th>
* <th>Meaning</th>
* </thead>
* <tbody>
* <tr>
* <th><code><var>elementType</var></code> or
* <code><var>type</var></code></th>
* <td><code>String</code></td>
* <td>Element type (case-sensitivity depends on
* the document type)</td>
* </tr>
* <!--<tr>
* <th><code><var>attributes</var></code></th>
* <td><code>Object</code></td>
* <td>Attributes of the element. All attributes
* are created in the <code>null</code> namespace.</td>
* </tr>-->
* <tr>
* <th><code><var>properties</var></code></th>
* <td><code>Object</code></td>
* <td>Properties of the element object. The property
* <code>style</code> is handled specially: Its
* value should be an <code>Object</code> whose
* property names are <code>style</code> property
* names and whose property values are the
* corresponding values, as supported by
* {@link jsx.dom.css#setStyleProperty()}.
* <!--Note that some properties may overwrite
* attributes.-->
* </tr>
* <tr>
* <th><code><var>childNodes</var></code></th>
* <td><code>Array</code> of <code>Object</code>
* or <code>String</code></td>
* <td>Child nodes of the element node.
* The elements of the <code>Array</code>
* are processed recursively.
* </tr>
* </tbody>
* </table></td>
* </tr>
* </tbody>
* </table>
* @param {Array|Object} data
* @param {boolean} bXML
* If a true-value, empty elements use XML <code>SHORTTAG</code>
* syntax: <code>&lt;foo/></code> instead of
* <code>&lt;foo>&lt;/foo></code>.
* @return {string}
*/
createMarkupFromObj: function _createMarkupFromObj (data, bXML) {
if (typeof data.valueOf() == "string")
{
return data.replace(/["&<>]/g, function (m) {
return ({
'"': "&quot;",
"&": "&amp;",
"<": "&lt;",
">": "&gt;"
})[m];
});
}
 
/**
* @param {Array|Object} data
* @return TextNode|Array[Node]|Element
*/
return function (data) {
if (typeof data.valueOf() == "string")
{
return document.createTextNode(data);
}
/* Support ES5 strict mode */
var me = _createMarkupFromObj;
 
/* Support ES5 strict mode */
var me = jsx.dom.createNodeFromObj;
/* If input is an Array, output is string of markup */
if (_isArray(data))
{
var a = [];
 
/* If input is an Array, output is an Array of Nodes */
if (_isArray(data))
{
var a = [];
for (var i = 0, len = data.length; i < len; ++i)
{
a[i] = me(data[i]);
}
 
for (var i = 0, len = data.length; i < len; ++i)
{
a[i] = me(data[i]);
return a.join("");
}
 
return a;
}
var type = (data.elementType || data.type);
var el = ["<" + type];
 
var el = document.createElement(data.elementType || data.type);
if (!el)
{
return null;
}
var attributes = data.attributes;
if (attributes)
{
var keys = _getKeys(attributes);
 
// var attributes = data.attributes;
// if (attributes && _isHostMethod(el, "setAttribute"))
// {
// var keys = _getKeys(attributes);
//
// for (var i = 0, len = keys.length; i < len; ++i)
// {
// var attrName = keys[i];
// el.setAttribute(attrName, attributes[attrName]);
// }
// }
for (var i = 0, len = keys.length; i < len; ++i)
{
var attrName = keys[i];
el.push(" " + attrName + '="' + me(attributes[attrName]) + '"');
}
}
 
var properties = data.properties;
if (properties)
{
keys = _getKeys(properties);
 
for (i = 0, len = keys.length; i < len; ++i)
var properties = data.properties;
if (properties)
{
var propName = keys[i];
keys = _getKeys(properties);
 
if (propName == "style")
for (i = 0, len = keys.length; i < len; ++i)
{
var style = properties[propName];
var _setStyleProperty = jsx.object.getFeature(jsx.dom, "css", "setStyleProperty");
if (typeof style != "string" && typeof _setStyleProperty != "function")
var propName = keys[i];
 
if (propName == "style")
{
jsx.warn("JSX:dom/css.js:jsx.dom.css.setStyleProperty()"
+ " is recommended for setting style object properties");
el[propName] = style;
}
else
{
el.push(' style="');
 
var style = properties[propName];
var _uncamelize = jsx.object.getFeature(jsx.dom, "css", "uncamelize")
|| function (s) { return s; };
 
var styleKeys = _getKeys(style);
for (var i = 0, len = styleKeys.length; i < len; ++i)
{
var stylePropName = styleKeys[i];
_setStyleProperty(el, stylePropName, style[stylePropName]);
el.push(" " + me(_uncamelize(stylePropName)) + ": " + me(style[stylePropName]));
}
}
else
{
el.push(" " + propName + '="' + me(properties[propName]) + '"');
}
}
else
{
el[propName] = properties[propName];
}
}
}
 
var nodes = data.childNodes;
for (var i = 0, len = nodes && nodes.length; i < len; ++i)
{
el.appendChild(me(nodes[i]));
}
var nodes = data.childNodes;
var bEmpty = (!nodes || !nodes.length);
if (bXML && bEmpty)
{
el.push("/");
}
 
return el;
};
}());
el.push(">");
 
/**
* Removes all occurences of a class name from the
* <code>class</code> attribute of an {@link Element}.
*
* For compatibility, if possible removes the <code>class</code>
* attribute if it is empty afterwards.
*
* @param {Element} o
* @param {string} sClassName
* @return {boolean}
* <code>true</code> if successful, <code>false</code> otherwise.
*/
jsx.dom.removeClassName = function (o, sClassName) {
var sRxClassName = "(^\\s*|\\s+)" + sClassName + "(\\s*$|(\\s))";
for (var i = 0, len = nodes && nodes.length; i < len; ++i)
{
el.push(me(nodes[i], bXML));
}
 
if (jsx.object.isHostMethod(o, "classList", "remove"))
{
/* W3C DOM Level 4 */
o.classList.remove(sClassName);
}
else
{
var curClassNames = o.className;
var newClassNames = curClassNames.replace(
new RegExp(sRxClassName, "g"),
"$3");
o.className = newClassNames;
if (!bEmpty)
{
el.push("</" + type + ">");
}
 
if (!newClassNames && jsx.object.isMethod(o, "removeAttribute"))
{
o.removeAttribute("class");
}
}
return el.join("");
},
 
return !((new RegExp(sRxClassName)).test(o.className));
};
createElementFromObj: _createNodesFromObj,
createNodeFromObj: _createNodesFromObj,
createNodesFromObj: _createNodesFromObj,
 
jsx.dom.addClassName = (function () {
var _removeClassName = jsx.dom.removeClassName;
hasClassName: _hasClassName,
removeClassName: _removeClassName,
 
/**
* Adds a class name to the <code>class</code> attribute of
* an {@link Element}.
*
* @param {Element} o
* @param {string} sClassName
* @param {boolean} bRemove
* If the class name is already there, and this argument is
* <code>true</code>, all instances of it are removed first.
* If the class is there and this argument is <code>false</code>,
* exit without changing anything. The default is <code>false</code>,
* which is more efficient.
* @return {boolean}
* <code>true</code> if the class name could be added successfully or
* was already there, <code>false</code> otherwise.
*/
function _addClassName (o, sClassName, bRemove)
{
var rx = new RegExp("(^\\s*|\\s+)" + sClassName + "(\\s*$|\\s)");
 
if (bRemove)
{
_removeClassName(o, sClassName);
}
else if (rx.test(o.className))
{
return true;
}
 
if (sClassName)
{
if (jsx.object.isHostMethod(o, "classList", "add"))
/**
* Adds a class name to the <code>class</code> attribute of
* an {@link Element}.
*
* @param {Element} o
* @param {string} sClassName
* @param {boolean} bRemove
* If the class name is already there, and this argument is
* <code>true</code>, all instances of it are removed first.
* If the class is there and this argument is <code>false</code>,
* exit without changing anything. The default is <code>false</code>,
* which is more efficient.
* @return {boolean}
* <code>true</code> if the class name could be added successfully or
* was already there, <code>false</code> otherwise.
*/
addClassName: function (o, sClassName, bRemove) {
if (bRemove)
{
/* W3C DOM Level 4 */
o.classList.add(sClassName);
_removeClassName(o, sClassName);
}
else
else if (_hasClassName(o, sClassName))
{
if (/\S/.test(o.className))
return true;
}
 
if (sClassName)
{
if (_isHostMethod(o, "classList", "add"))
{
o.className += " " + sClassName;
/* W3C DOM Level 4 */
o.classList.add(sClassName);
}
else
{
o.className = sClassName;
if (/\S/.test(o.className))
{
o.className += " " + sClassName;
}
else
{
o.className = sClassName;
}
}
 
return _hasClassName(o, sClassName);
}
},
 
return rx.test(o.className);
}
}
appendChild: _appendChild,
 
return _addClassName;
}());
/**
* Appends several child nodes to a parent node in the specified order.
*
* @param {Node} parentNode
* @param {NodeList|Array} childNodes
* @return {boolean}
* <code>true</code> on success, <code>false</code> otherwise.
*/
appendChildren: function (parentNode, childNodes) {
if (parentNode)
{
var result = true;
 
/**
* Appends several child nodes to a parent node in the specified order.
*
* @param {Node} parentNode
* @param {NodeList|Array} childNodes
* @return {boolean}
* <code>true</code> on success, <code>false</code> otherwise.
*/
jsx.dom.appendChildren = function (parentNode, childNodes) {
if (parentNode)
{
for (var i = 0, len = childNodes.length; i < len; ++i)
{
parentNode.appendChild(childNodes[i]);
}
for (var i = 0, len = childNodes.length; i < len; ++i)
{
var success = _appendChild(parentNode, childNodes[i]);
if (!success && result)
{
result = false;
}
}
 
return true;
}
return result;
}
 
return false;
};
return false;
},
 
/**
* Removes several child nodes of a parent node in reverse order.
*
* @param {Node} parentNode
* @param {NodeList|Array} childNodes (optional)
* The child nodes to be deleted. If not provided,
* all child nodes of <var>parentNode</var> are deleted,
* the table-safe equivalent to
* <code><var>parentNode</var>.innerHTML = "";</code>
* @return {boolean}
* <code>true</code> on success, <code>false</code> otherwise.
*/
jsx.dom.removeChildren = function (parentNode, childNodes) {
if (parentNode)
{
if (arguments.length < 2)
{
childNodes = parentNode.childNodes;
}
/**
* Inserts a child node before a reference child node.
*
* @param {Node} parentNode
* @param {Node} newChild
* @param {Node} refChild
* @return {boolean}
* <code>true</code> on success, <code>false</code> otherwise.
*/
insertBefore: _insertBefore,
 
for (var i = childNodes.length; i--;)
{
parentNode.removeChild(childNodes[i]);
}
removeChild: _removeChild,
 
return true;
}
/**
* Removes several child nodes of a parent node in reverse order.
*
* @param {Node} parentNode
* @param {NodeList|Array} childNodes (optional)
* The child nodes to be deleted. If not provided,
* all child nodes of <var>parentNode</var> are deleted,
* the table-safe equivalent to
* <code><var>parentNode</var>.innerHTML = "";</code>
* @return {boolean}
* <code>true</code> on success, <code>false</code> otherwise.
*/
removeChildren: function (parentNode, childNodes) {
if (parentNode)
{
var result = true;
if (arguments.length < 2)
{
childNodes = parentNode.childNodes;
}
 
return false;
};
for (var i = childNodes.length; i--;)
{
var success = _removeChild(parentNode, childNodes[i]);
if (!success && result)
{
result = false;
}
}
 
jsx.dom.html2nodes = function (sHTML) {
var m,
rx = /(<([^\s>]+)(\s+[^>]*)?>)|([^<]+)/g,
node = document.createElement("html");
return result;
}
 
while ((m = rx.exec(sHTML)))
{
if (m[1])
{
if (m[2].charAt(0) !== "/")
return false;
},
 
html2nodes: function (sHTML) {
var m,
rx = /(<([^\s>]+)(\s+[^>]*)?>)|([^<]+)/g,
node = document.createElement("html");
 
while ((m = rx.exec(sHTML)))
{
var newNode = document.createElement(m[2]);
node.appendChild(newNode);
node = newNode;
if (m[1])
{
if (m[2].charAt(0) !== "/")
{
var newNode = document.createElement(m[2]);
node.appendChild(newNode);
node = newNode;
}
else
{
node = node.parentNode;
}
}
else
{
node.appendChild(document.createTextNode(m[4]));
}
}
else
 
return node;
},
 
InvalidNodeError: _InvalidNodeError,
 
/**
* Collects and returns the namespaces of a node and its ancestors.
*
* Collects the namespace prefixes and URIs of <var>contextNode</var> and
* its ancestor element nodes. Duplicate prefixes with different namespace
* URI are ignored and must be resolved manually using the <var>namespaces</var>
* argument of {@link jsx.dom.xpath.createFullNSResolver()}.
*
* @param {Object} namespaces
* Contains the collected namespace declarations. Existing properties
* are preserved.
* @param {Document|Element} contextNode
* The parent node from where to start searching for namespace
* declarations. If it is a Document node, the document element node
* is used instead. The default is the document element node.
* @return {Object}
* The resulting value of <var>namespaces</var> if successful,
* <code>null</code> otherwise.
* @throws jsx.dom.InvalidNodeError if a value has been specified
* for <var>contextNode</var> that is not a reference to a Document
* node or an Element node.
* @see jsx.dom.xpath.createFullNSResolver()
*/
collectNamespaces: jsx_dom_collectNamespaces,
 
DOMParser: function (text) {
if (typeof text != "undefined")
{
node = node.parentNode;
this.text = text;
}
}
else
{
node.appendChild(document.createTextNode(m[4]));
}
}
}.extend(null, {
parseFromString: function (text, contentType, namespaceURI, qualifiedName, documentType) {
function _unescape (text)
{
return text.replace(
/&(#((\d+)|x[\dA-Fa-f])|lt|gt|amp);/g,
function (m, entity, cr, dec_cr) {
if (cr)
{
if (dec_cr)
{
return String.fromCharCode(cr);
}
 
return node;
};
return String.fromCharCode(parseInt("0" + cr, 16));
}
 
jsx.dom.HTMLSerializer = (
function () {
return {
"lt": "<",
"gt": ">",
"amp": "&"
}[entity];
}
);
}
 
}
).extend("Object", {
serializeToString: (function () {
var elemInfo = {
'a': {
attribs: ["name", "href", "hreflang", "type", "rel", "rev", "charset",
"id", "class", "lang", "title", "style", "shape", "coords",
"onfocus", "onblur", "onclick", "ondblclick", "onmousedown",
"onmouseup", "onmouseover", "onmousemove", "onmouseout",
"onkeypress", "onkeydown", "onkeyup",
"target", "tabindex", "accesskey"]
},
'area': {
empty: false
},
'base': {
empty: false
},
'basefont': {
empty: false
},
'br': {
empty: false
},
'col': {
empty: false
},
'frame': {
empty: false
},
'hr': {
empty: false
},
'img': {
empty: true
},
'input': {
empty: false
},
'isindex': {
empty: false
},
'link': {
empty: false
},
'meta': {
empty: false
},
'param': {
empty: true
}
};
var text = (typeof this.text != "undefined"
? this.text
: text);
 
return function (oNode, bIncludeProprietary) {
var me = arguments.callee;
var rxAttributes = /\s+((\w+):)?(\w+)(\s*=\s*("[^"]*"|'[^']*'|([^\s\/>]|\/[^>])+))?/g;
var sMarkup = /[^<]+|<(\/?)(((\w+):)?(\w+))?/.source
+ "(" + rxAttributes.source + ")*"
+ /\s*(\/?)>/.source;
var rxTag = new RegExp(sMarkup, "g");
 
if (oNode.tagName)
{
var
t = oNode.tagName.toLowerCase(),
startTag = "<" + t,
content = [],
endTag = "";
var root_node = null;
 
for (var i = 0, c = oNode.childNodes, len = c && c.length; i < len; i++)
if (contentType || namespaceURI || qualifiedName || documentType)
{
content.push(me(oNode, bIncludeProprietary));
if (_isMethod(document, "implementation", "createDocument"))
{
root_node = document.implementation.createDocument(
namespaceURI || {
"application/xhtml+xml": "http://www.w3.org/1999/xhtml"
}[contentType] || null,
qualifiedName || "html",
documentType || null);
}
}
 
if (typeof elemInfo[t] != "undefined" && !elemInfo[t].empty)
if (!root_node && _isMethod(document, "createDocumentFragment"))
{
endTag = "</" + t + ">";
root_node = document.createDocumentFragment();
}
 
return startTag + content.join("") + endTag;
}
if (!root_node)
{
if (/\/xml$/i.test(contentType))
{
root_node = document.createElement(qualifiedName || "xml");
}
else
{
root_node = document.createElement(qualifiedName || "html");
}
}
 
return oNode.textContent;
};
})()
});
var node = root_node;
 
/**
* Returns the first child node of another node.
* <p>
* NOTE: This method was written to support the MSHTML 4 DOM as well as
* newer DOMs. It is <em>NOT</em> intended to work around the issue that
* MSHTML removes white-space text nodes from the document tree, while
* standards-compliant DOMs do not. In particular, it does <em>NOT</em>
* return the first child <em>element</em> node, and return values do vary
* across DOMs.
* </p>
* @param {Node} oNode
* @return {Node} The first child node of another node.
*/
jsx.dom.getFirstChild = function (oNode) {
var result = null;
var m;
while ((m = rxTag.exec(text)))
{
var end_tag = m[1];
var node_name = m[2];
var prefix = m[4];
var local_name = m[5];
var attributes_spec = m[6];
var self_closing = m[13];
 
if (oNode)
{
if (oNode.firstChild)
{
result = oNode.firstChild;
}
else if (oNode.document && oNode.document.all)
{
result = oNode.document.all(0);
}
}
if (node_name)
{
if (end_tag)
{
node = node.parentNode;
}
else
{
var namespace_URI = null;
 
return result;
};
if (prefix)
{
var namespaces = jsx_dom_collectNamespaces(node);
namespace_URI = namespaces && namespaces[prefix] || null;
}
 
/**
* Returns the parent node of a node
*
* @param {Node} oNode
* @return {Node} The parent node of <var>oNode</var>
*/
jsx.dom.getParent = function (oNode) {
var result = null;
if (namespace_URI)
{
var new_node = document.createElementNS(namespace_URI, local_name);
}
else
{
new_node = document.createElement(local_name);
}
 
if (oNode)
{
if (oNode.parentNode)
{
result = oNode.parentNode;
}
else if (oNode.parentElement)
{
result = oNode.parentElement;
}
}
node.appendChild(new_node);
node = new_node;
 
return result;
};
if (attributes_spec)
{
rxAttributes.lastIndex = m.index + node_name.length;
 
/**
* Loads a script resource asynchonrously by appending
* a <code>script</code> element to the current (X)HTML document.
*
* A <code>script</code> element is being created and appended as
* child to the <code>body</code> element or the <code>head</code>
* element of the document, whichever is available first. In a
* frameset document, <code>document.body</code> refers to the
* topmost <code>frameset</code> element object; in that case,
* it is attempted to find a <code>body</code> element by other
* means. If that fails, it means that there either is no such
* element, or that the element object is inaccessible because
* it is disabled by the frameset. In that case the
* <code>script</code> element is appended to the <code>head</code>
* element instead.
*
* Note that previous versions of this method appended to the
* <code>head</code> element only. However, this limited its use
* to scripts that did not modify the body content. You may still
* not load such scripts with this method if the document has
* been loaded and the script resource uses
* <code>document.write()</code>. This method intentionally does
* not use <code>document.write()</code> to avoid the possibility
* that a loaded document could be overwritten.
*
* NOTE: Tested successfully with MSIE and Mozilla/5.0; however,
* do not rely on that the script was included, but <em>test</em>
* for it.
*
* @author
* (C) 2004-2009, 2013 Thomas Lahn <dhtml.js@PointedEars.de>,
* 2004 Ulrich Kritzner <droeppez@web.de>
*
* @requires jsx.object#isMethod()
* @param {string} sURI
* URI of the script resource to be loaded.
* @param {string} sType = "text/javascript"
* MIME type of the script to be loaded. Used as value of the
* <code>type</code> attribute.
* @param {string} sLanguage (optional)
* Value of the <code>language</code> attribute (deprecated in
* HTML 4.01 and XHTML 1.0, absent from XHTML 1.1 and later
* versions) to specify the version of the script language.
* Unused by default.
* @param {boolean} bReload = false
* If <code>true</code>Force an already loaded script to be reloaded,
* i.e. another <code>script</code> element with the same URI
* in the <code>src</code> attribute to be added;
* if <code>false</code> (default), the attempt to load a script
* that has already been loaded fails silently.
* @return {boolean}
* <code>false</code> if the script could not be loaded,
* <code>true</code> otherwise.
*/
jsx.dom.loadScript =
function jsx_dom_loadScript (sURI, sType, sLanguage, bReload) {
var
jsx_object = jsx.object,
result = false;
var mAttrib;
while ((mAttrib = rxAttributes.exec(text)))
{
var attr_prefix = mAttrib[2];
var attr_local_name = mAttrib[3];
var attr_value = mAttrib[5];
attr_value = attr_value ? _unescape(attr_value) : attr_local_name;
 
if (typeof jsx_dom_loadScript.registry != "undefined"
&& jsx_object.getProperty(jsx_dom_loadScript.registry, sURI, false)
&& !bReload)
{
return true;
}
var attr_namespace_URI = null;
 
var parent = document.body;
if (!parent || parent.tagName.toLowerCase() === "frameset")
{
parent = jsx.dom.getElemByTagName("script", 0);
if (!parent)
{
parent = document.head || jsx.dom.getElemByTagName("head", 0);
}
if (attr_prefix)
{
if (!namespaces)
{
 
if (!parent)
{
return false;
}
}
}
 
if (!jsx_object.isHostMethod(document, "createElement"))
{
return false;
}
attr_namespace_URI = namespaces && namespaces[attr_prefix] || null;
}
 
var oScript = document.createElement("script");
if (!oScript)
{
return false;
}
if (attr_namespace_URI)
{
node.setAttributeNS(attr_namespace_URI, attr_local_name, attr_value);
}
else
{
node.setAttribute(attr_local_name, attr_value);
}
}
}
 
/* no exception handling for backwards compatibility reasons */
if (typeof oScript.src != "undefined")
{
oScript.src = sURI;
}
if (self_closing)
{
node = node.parentNode;
}
}
}
else
{
var text = _unescape(m[0]);
node.appendChild(document.createTextNode(text));
}
}
 
if (typeof oScript.type != "undefined")
{
oScript.type = sType || "text/javascript";
}
return root_node;
}
}),
 
if (sLanguage)
{
oScript.language = sLanguage;
}
HTMLSerializer: (
function () {}
).extend("Object", {
serializeToString: (function () {
var elemInfo = {
'a': {
attribs: ["name", "href", "hreflang", "type", "rel", "rev", "charset",
"id", "class", "lang", "title", "style", "shape", "coords",
"onfocus", "onblur", "onclick", "ondblclick", "onmousedown",
"onmouseup", "onmouseover", "onmousemove", "onmouseout",
"onkeypress", "onkeydown", "onkeyup",
"target", "tabindex", "accesskey"]
},
'area': {
empty: false
},
'base': {
empty: false
},
'basefont': {
empty: false
},
'br': {
empty: false
},
'col': {
empty: false
},
'frame': {
empty: false
},
'hr': {
empty: false
},
'img': {
empty: true
},
'input': {
empty: false
},
'isindex': {
empty: false
},
'link': {
empty: false
},
'meta': {
empty: false
},
'param': {
empty: true
}
};
 
if (typeof oScript.defer != "undefined")
{
oScript.defer = true;
}
return function (oNode, bIncludeProprietary) {
var me = arguments.callee;
 
if (jsx_object.isHostMethod(parent, "appendChild"))
{
parent.appendChild(oScript);
result = (
typeof parent.lastChild != "undefined"
&& parent.lastChild == oScript);
}
else if (jsx_object.isHostMethod(parent, "insertAdjacentElement"))
{
parent.insertAdjacentElement("beforeEnd", oScript);
result = true;
}
if (oNode.tagName)
{
var
t = oNode.tagName.toLowerCase(),
startTag = "<" + t,
content = [],
endTag = "";
 
if (result)
{
if (typeof jsx_dom_loadScript.registry == "undefined")
{
jsx_dom_loadScript.registry = {};
}
for (var i = 0, c = oNode.childNodes, len = c && c.length; i < len; i++)
{
content.push(me(oNode, bIncludeProprietary));
}
 
jsx_dom_loadScript.registry[sURI] = true;
}
if (typeof elemInfo[t] != "undefined" && !elemInfo[t].empty)
{
endTag = "</" + t + ">";
}
 
return result;
};
return startTag + content.join("") + endTag;
}
 
/**
* Retrieves descendant focusable elements in order of their
* "tabindex" attribute.
*
* @author
* (C) 2004 Thomas Lahn <dhtml.js@PointedEars.de>
* @requires
* http://pointedears.de/scripts/collection.js
* @param {Document|Element} o (optional)
* Reference to a {@link dom2-core#Document Document} or
* {@link dom2-core#Element Element} object from which to retrieve
* descendant elements. If omitted or evaluated to
* <code>false</code>, it is tried to use the calling object.
* @return {Collection}
* A reference to a {@link #Collection} object containing
* the descendant elements of <var>o</var> or the calling
* {@link dom2-core#Document Document}/{@link dom2-core#Element Element}
* object in "tabindex" order: Elements with "tabindex" > 0 come first,
* followed by elements with "tabindex" == 0 or where either
* "tabindex" is not set or not applicable. Note: An element
* with a "tabindex" of 1 will will be the first element
* in the resulting collection but for design reasons will
* have an index of 0 (but since the Collection prototype
* provides an iterator, this does not need to disturb you).
* Additional note: Unlike specified, disabled elements will
* participate in the tabbing order (so they can be enabled
* later without this method to be re-called.)
*/
jsx.dom.getElementsByTabIndex = function (o) {
var aIndexedElements = new Array();
var aUnindexedElements = new Array();
return oNode.textContent;
};
})()
}),
 
/* makes the method applicable to Document and Element objects */
if (!o
&& typeof this.constructor != "undefined"
&& /Document|Element/.test(this.constructor))
{
o = this;
}
/**
* Returns the first child node of another node.
*
* @param {Node} oNode
* @return {Node} The first child node of another node.
*/
getFirstChild: function (oNode) {
var result = null;
 
if (jsx.object.isMethod(o, "getElementsByTagName"))
{
var es = o.getElementsByTagName("*");
if (oNode)
{
if (oNode.firstChild)
{
result = oNode.firstChild;
}
else if (oNode.children)
{
result = oNode.children[0];
}
}
 
if (es && typeof es.length != "undefined")
{
var l = es.length;
return result;
},
 
for (var i = 0, e; i < l; i++)
/**
* Returns the first element child of another node.
* @param {Node} oNode
* @return {Node} The first child element of another node.
*/
getFirstElementChild: function (oNode) {
var result = null;
 
if (oNode)
{
e = es[i];
 
if (typeof e.tabIndex != "undefined")
if (oNode.firstElementChild)
{
/* !null && !0 */
if (e.tabIndex)
result = oNode.firstElementChild;
}
if (oNode.firstChild)
{
result = oNode.firstChild;
while (result && result.nodeType != 1)
{
/*
* tabindex="1" --> index == 0; use e.tabIndex
* and a "zero dummy" if you do not like this
*/
aIndexedElements[e.tabIndex - 1] = e;
result = result.nextSibling;
}
else
{
aUnindexedElements[aUnindexedElements.length] = e;
}
}
else if (oNode.document && oNode.document.all)
{
result = oNode.document.all(0);
}
}
}
}
 
return new Collection(aIndexedElements.concat(aUnindexedElements));
};
return result;
},
 
if (typeof jsx.types != "undefined"
&& jsx.types.isFeature("HTMLDocument", "prototype")
&& !jsx.object.isMethod(HTMLDocument.prototype, "getElementsByTabIndex"))
{
HTMLDocument.prototype.getElementsByTabIndex = jsx.dom.getElementsByTabIndex;
}
/**
* Returns the parent node of a node
*
* @param {Node} oNode
* @return {Node} The parent node of <var>oNode</var>
*/
getParent: function (oNode) {
var result = null;
 
if (typeof jsx.types != "undefined"
&& jsx.types.isFeature("HTMLElement", "prototype")
&& !jsx.object.isMethod(HTMLElement.prototype, "getElementsByTabIndex"))
{
HTMLElement.prototype.getElementsByTabIndex = jsx.dom.getElementsByTabIndex;
}
if (oNode)
{
if (oNode.parentNode)
{
result = oNode.parentNode;
}
else if (oNode.parentElement)
{
result = oNode.parentElement;
}
}
 
jsx.dom.isDescendantOfOrSelf = function (node, ancestor) {
if (arguments.length < 2)
{
jsx.throwThis(null, "No ancestor provided");
}
return result;
},
 
do
{
if (node == ancestor)
{
return true;
}
}
while ((node = node.parentNode));
/**
* Loads a script resource asynchonrously by appending
* a <code>script</code> element to the current (X)HTML document.
* <p>
* A <code>script</code> element is being created and appended as
* child to the <code>body</code> element or the <code>head</code>
* element of the document, whichever is available first. In a
* frameset document, <code>document.body</code> refers to the
* topmost <code>frameset</code> element object; in that case,
* it is attempted to find a <code>body</code> element by other
* means. If that fails, it means that there either is no such
* element, or that the element object is inaccessible because
* it is disabled by the frameset. In that case the
* <code>script</code> element is appended to the <code>head</code>
* element instead.
* </p><p>
* Note that previous versions of this method appended to the
* <code>head</code> element only. However, this limited its use
* to scripts that did not modify the body content. You may still
* not load such scripts with this method if the document has
* been loaded and the script resource uses
* <code>document.write()</code>. This method intentionally does
* not use <code>document.write()</code> to avoid the possibility
* that a loaded document could be overwritten.
* </p><p>
* NOTE: Tested successfully with MSIE and Mozilla/5.0; however,
* do not rely on that the script was included, but <em>test</em>
* for it.
* </p>
* @author
* (C) 2004-2009, 2013 Thomas Lahn <dhtml.js@PointedEars.de>,
* 2004 Ulrich Kritzner <droeppez@web.de>
*
* @requires jsx.object#isMethod()
* @param {string} sURI
* URI of the script resource to be loaded.
* @param {string} sType = "text/javascript"
* MIME type of the script to be loaded. Used as value of the
* <code>type</code> attribute.
* @param {string} sLanguage (optional)
* Value of the <code>language</code> attribute (deprecated in
* HTML 4.01 and XHTML 1.0, absent from XHTML 1.1 and later
* versions) to specify the version of the script language.
* Unused by default.
* @param {boolean} bReload = false
* If <code>true</code>Force an already loaded script to be reloaded,
* i.e. another <code>script</code> element with the same URI
* in the <code>src</code> attribute to be added;
* if <code>false</code> (default), the attempt to load a script
* that has already been loaded fails silently.
* @return {boolean}
* <code>false</code> if the script could not be loaded,
* <code>true</code> otherwise.
*/
loadScript: function jsx_dom_loadScript (sURI, sType, sLanguage, bReload) {
var
jsx_object = jsx.object,
result = false;
 
return false;
};
if (typeof jsx_dom_loadScript.registry != "undefined"
&& jsx_object.getProperty(jsx_dom_loadScript.registry, sURI, false)
&& !bReload)
{
return true;
}
 
/**
* Applies hyphenation to the context node.
*
* Improves the readability of text by inserting soft hyphens
* in text nodes as specified by the {@link jsx.string#hyphenation}
* dictionary.
*
* @function
* @requires jsx.string.hyphenation#hyphenate()
*/
jsx.dom.hyphenate = (function () {
var _isArray = jsx.object.isArray;
var _hyphenation, _hyphenate, _me;
var parent = document.body;
if (!parent || parent.tagName.toLowerCase() === "frameset")
{
parent = _getElementsByTagName("script", 0);
if (!parent)
{
parent = document.head || _getElementsByTagName("head", 0);
}
 
/**
* @param {Array} contextNodes = document
* Hyphenation is applied to these {@link Node}s and their
* descendant text nodes. The default is the <code>Document</code>
* node referred by the <code>document</code> property of the
* next fitting object in the scope chain (usually the Global
* Object).
* @param {boolean} hyphenateAll
* If a true-value,
*/
return function (contextNodes, hyphenateAll) {
/* imports */
if (!_hyphenate)
{
_hyphenation = jsx.string.hyphenation;
_hyphenate = _hyphenation.hyphenate;
}
if (!parent)
{
return false;
}
}
 
_hyphenation.setHyphenateAll(hyphenateAll);
if (!_isHostMethod(document, "createElement"))
{
return false;
}
 
if (!_me)
{
_me = jsx.dom.hyphenate;
}
var oScript = document.createElement("script");
if (!oScript)
{
return false;
}
 
/* optional arguments */
if (typeof contextNodes == "undefined")
{
contextNodes = document;
}
/* no exception handling for backwards compatibility reasons */
if (typeof oScript.src != "undefined")
{
oScript.src = sURI;
}
 
if (!contextNodes)
{
return jsx.warn("jsx.dom.hyphenate: Invalid context node: " + contextNodes);
}
if (typeof oScript.type != "undefined")
{
oScript.type = sType || "text/javascript";
}
 
if (!_isArray(contextNodes))
{
contextNodes = [contextNodes];
}
if (sLanguage)
{
oScript.language = sLanguage;
}
 
for (var i = 0, len = contextNodes.length; i < len; ++i)
{
var contextNode = contextNodes[i];
if (typeof oScript.defer != "undefined")
{
oScript.defer = true;
}
 
if (!contextNode)
if (_isHostMethod(parent, "appendChild"))
{
jsx.warn("jsx.dom.hyphenate: Invalid context node " + (i + 1) + ": " + contextNode);
continue;
parent.appendChild(oScript);
result = (
typeof parent.lastChild != "undefined"
&& parent.lastChild == oScript);
}
else if (_isHostMethod(parent, "insertAdjacentElement"))
{
parent.insertAdjacentElement("beforeEnd", oScript);
result = true;
}
 
for (var j = 0,
nodes = contextNode.childNodes,
len2 = nodes && nodes.length;
j < len2;
++j)
if (result)
{
var node = nodes[j];
if (typeof jsx_dom_loadScript.registry == "undefined")
{
jsx_dom_loadScript.registry = {};
}
 
if (node.nodeType == 1)
jsx_dom_loadScript.registry[sURI] = true;
}
 
return result;
},
 
getElementsByTabIndex: _getElementsByTabIndex,
 
isDescendantOfOrSelf: function (node, ancestor) {
if (arguments.length < 2)
{
jsx.throwThis(null, "No ancestor provided");
}
 
do
{
if (node == ancestor)
{
_me(node, hyphenateAll);
return true;
}
else
}
while ((node = node.parentNode));
 
return false;
},
 
/**
* Applies hyphenation to the context node.
*
* Improves the readability of text by inserting soft hyphens
* in text nodes as specified by the {@link jsx.string#hyphenation}
* dictionary.
*
* @function
* @requires jsx.string.hyphenation#hyphenate()
*/
hyphenate: (function () {
var _hyphenation, _hyphenate;
 
/**
* @param {Array} contextNodes = document
* Hyphenation is applied to these {@link Node}s and their
* descendant text nodes. The default is the <code>Document</code>
* node referred by the <code>document</code> property of the
* next fitting object in the scope chain (usually the Global
* Object).
* @param {boolean} hyphenateAll
* If a true-value,
*/
return function jsx_dom_hyphenate (contextNodes, hyphenateAll) {
/* imports */
if (!_hyphenate)
{
node.nodeValue = _hyphenate(node.nodeValue, hyphenateAll);
_hyphenation = jsx.string.hyphenation;
_hyphenate = _hyphenation.hyphenate;
}
}
}
 
_hyphenation.setHyphenateAll(hyphenateAll);
 
var me = jsx_dom_hyphenate;
 
/* optional arguments */
if (typeof contextNodes == "undefined")
{
contextNodes = document;
}
 
if (!contextNodes)
{
return jsx.warn("jsx.dom.hyphenate: Invalid context node: " + contextNodes);
}
 
if (!_isArray(contextNodes))
{
contextNodes = [contextNodes];
}
 
for (var i = 0, len = contextNodes.length; i < len; ++i)
{
var contextNode = contextNodes[i];
 
if (!contextNode)
{
jsx.warn("jsx.dom.hyphenate: Invalid context node " + (i + 1) + ": " + contextNode);
continue;
}
 
for (var j = 0,
nodes = contextNode.childNodes,
len2 = nodes && nodes.length;
j < len2;
++j)
{
var node = nodes[j];
 
if (node.nodeType == 1)
{
me(node, hyphenateAll);
}
else
{
node.nodeValue = _hyphenate(node.nodeValue, hyphenateAll);
}
}
}
};
}())
};
 
_jsx_dom.URI = _jsx_dom.path + "dom.js";
//_jsx_dom.docURI = _jsx_dom.path + "dhtml.htm";
 
// _jsx_dom.supported = _jsx_dom.isW3CDOM || _jsx_dom.isNS4DOM || _jsx_dom.isOpera
// || _jsx_dom.isIE4DOM;
 
// _jsx_dom.DOM = _jsx_dom.supported
// && (_jsx_dom.isW3CDOM && _jsx_dom.W3CDOM)
// || (_jsx_dom.isIE4DOM && _jsx_dom.IE4DOM)
// || (_jsx_dom.isNS4DOM && _jsx_dom.NS4DOM);
 
if (typeof jsx.types != "undefined"
&& jsx.types.isFeature("HTMLDocument", "prototype")
&& !_isMethod(HTMLDocument.prototype, "getElementsByTabIndex"))
{
HTMLDocument.prototype.getElementsByTabIndex = _getElementsByTabIndex;
}
 
if (typeof jsx.types != "undefined"
&& jsx.types.isFeature("HTMLElement", "prototype")
&& !_isMethod(HTMLElement.prototype, "getElementsByTabIndex"))
{
HTMLElement.prototype.getElementsByTabIndex = _getElementsByTabIndex;
}
 
return _jsx_dom;
}());
/branches/live
Property changes:
Added: svn:mergeinfo
Merged /trunk:r509-535