From 4c61d8bd18a9727e6f90865a20b21a9df3454321 Mon Sep 17 00:00:00 2001 From: Ryan Voots Date: Fri, 2 Sep 2011 23:13:00 -0400 Subject: [PATCH 1/2] moving all to linode --- bin/evalserver | 8 +- deps/env.js | 20248 ++++++++++++++++++++++++++++------------------- lib/eval.pl | 44 +- 3 files changed, 11950 insertions(+), 8350 deletions(-) diff --git a/bin/evalserver b/bin/evalserver index 93114cc..e737a7a 100755 --- a/bin/evalserver +++ b/bin/evalserver @@ -1,7 +1,9 @@ -#!/usr/bin/perl +#!/home/farnsworth/perl5/perlbrew/perls/perl-5.14.0/bin/perl +use lib '/home/farnsworth/perl5/lib/perl5/x86_64-linux-gnu-thread-multi'; use lib '/home/farnsworth/perl5/lib/perl5'; -use local::lib; + +#use local::lib; # Guess we're being activated inside bin/, so go up a directory. BEGIN { if( not -e 'lib' and not -e 'etc' and -e 'bb3' ) { chdir ".."; } } @@ -9,7 +11,7 @@ use lib 'lib'; use EvalServer; use POSIX qw/setsid/; -$ENV{PATH}="/usr/bin/:/bin/"; +$ENV{PATH}="/home/farnsworth/perl5/perlbrew/perls/perl-5.14.0/bin:/usr/bin/:/bin/"; # Only daemonize if we're asked to. if( $ARGV[0] eq '-d' ) { diff --git a/deps/env.js b/deps/env.js index bb321b9..27d01f6 100644 --- a/deps/env.js +++ b/deps/env.js @@ -1,277 +1,1641 @@ /* + * Envjs core-env.1.2.13 * Pure JavaScript Browser Environment - * By John Resig - * Copyright 2008 John Resig, under the MIT License + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License */ +var Envjs = function(){ + var i, + name, + override = function(){ + for(i=0;i $cookies - see cookie.js <*/ -// read only boolean specifies whether the window has been closed -var $closed = false; - -// a read/write string that specifies the default message that appears in the status line -var $defaultStatus = "Done"; - -// a read-only reference to the Document object belonging to this window -/**> $document - See document.js <*/ - -//IE only, refers to the most recent event object - this maybe be removed after review -var $event = null; - -//A read-only array of window objects -var $frames = []; - -// a read-only reference to the History object -/**> $history - see location.js <**/ - -// read-only properties that specify the height and width, in pixels -var $innerHeight = 600, $innerWidth = 800; - -// a read-only reference to the Location object. the location object does expose read/write properties -/**> $location - see location.js <**/ - -// a read only property specifying the name of the window. Can be set when using open() -// and may be used when specifying the target attribute of links -var $name = 'Resig Env Browser'; - -// a read-only reference to the Navigator object -/**> $navigator - see navigator.js <**/ - -// a read/write reference to the Window object that contained the script that called open() to -//open this browser window. This property is valid only for top-level window objects. -var $opener; - -// Read-only properties that specify the total height and width, in pixels, of the browser window. -// These dimensions include the height and width of the menu bar, toolbars, scrollbars, window -// borders and so on. These properties are not supported by IE and IE offers no alternative -// properties; -var $outerHeight = $innerHeight, $outerWidth = $innerWidth; - -// Read-only properties that specify the number of pixels that the current document has been scrolled -//to the right and down. These are not supported by IE. -var $pageXOffset = 0, $pageYOffset = 0; - -//A read-only reference to the Window object that contains this window or frame. If the window is -// a top-level window, parent refers to the window itself. If this window is a frame, this property -// refers to the window or frame that conatins it. -var $parent; - -// a read-only refernce to the Screen object that specifies information about the screen: -// the number of available pixels and the number of available colors. -/**> $screen - see screen.js <**/ - -// read only properties that specify the coordinates of the upper-left corner of the screen. -var $screenX = 0, $screenY = 0; -var $screenLeft = $screenX, $screenTop = $screenY; - -// a read-only refernce to this window itself. -var $self; - -// a read/write string that specifies the current contents of the status line. -var $status = ''; - -// a read-only reference to the top-level window that contains this window. If this -// window is a top-level window it is simply a refernce to itself. If this window -// is a frame, the top property refers to the top-level window that contains the frame. -var $top; - -// the window property is identical to the self property. -var $window = $w; - -$debug("Initializing Window."); -__extend__($w,{ - get closed(){return $closed;}, - get defaultStatus(){return $defaultStatus;}, - set defaultStatus(_defaultStatus){$defaultStatus = _defaultStatus;}, - //get document(){return $document;}, - see document.js - get event(){return $event;}, - get frames(){return $frames;}, - //get history(){return $history;}, - see location.js - get innerHeight(){return $innerHeight;}, - get innerWidth(){return $innerWidth;}, - get clientHeight(){return $innerHeight;}, - get clientWidth(){return $innerWidth;}, - //get location(){return $location;}, see location.js - get name(){return $name;}, - //get navigator(){return $navigator;}, see navigator.js - get opener(){return $opener;}, - get outerHeight(){return $outerHeight;}, - get outerWidth(){return $outerWidth;}, - get pageXOffest(){return $pageXOffset;}, - get pageYOffset(){return $pageYOffset;}, - get parent(){return $parent;}, - //get screen(){return $screen;}, see screen.js - get screenLeft(){return $screenLeft;}, - get screenTop(){return $screenTop;}, - get screenX(){return $screenX;}, - get screenY(){return $screenY;}, - get self(){return $self;}, - get status(){return $status;}, - set status(_status){$status = _status;}, - get top(){return $top || $window;}, - get window(){return $window;} -}); - -$w.open = function(url, name, features, replace){ - //TODO -}; - -$w.close = function(){ - //TODO -}; - -/* Time related functions - see timer.js -* - clearTimeout -* - clearInterval -* - setTimeout -* - setInterval -*/ +//eg "Gecko/20070309 Firefox/2.0.0.3" +Envjs.appName = "Netscape"; +Envjs.version = "1.6";//? +Envjs.revision = ''; /* -* Events related functions - see event.js -* - addEventListener -* - attachEvent -* - detachEvent -* - removeEventListener -* -* These functions are identical to the Element equivalents. -*/ + * Envjs core-env.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ -/* -* UIEvents related functions - see uievent.js -* - blur -* - focus -* -* These functions are identical to the Element equivalents. -*/ +//CLOSURE_START +(function(){ -/* Dialog related functions - see dialog.js -* - alert -* - confirm -* - prompt -*/ -/* Screen related functions - see screen.js -* - moveBy -* - moveTo -* - print -* - resizeBy -* - resizeTo -* - scrollBy -* - scrollTo -*/ -/* CSS related functions - see css.js -* - getComputedStyle -*/ -/* -* Shared utility methods -*/ -// Helper method for extending one object with another. + +/** + * @author john resig + */ +// Helper method for extending one object with another. function __extend__(a,b) { - for ( var i in b ) { - var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i); - if ( g || s ) { - if ( g ) a.__defineGetter__(i, g); - if ( s ) a.__defineSetter__(i, s); - } else - a[i] = b[i]; - } return a; -}; - + for ( var i in b ) { + var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i); + if ( g || s ) { + if ( g ) { a.__defineGetter__(i, g); } + if ( s ) { a.__defineSetter__(i, s); } + } else { + a[i] = b[i]; + } + } return a; +} -// from ariel flesler http://flesler.blogspot.com/2008/11/fast-trim-function-for-javascript.html -// this might be a good utility function to provide in the env.core -// as in might be useful to the parser and other areas as well -function trim( str ){ +/** + * @author ariel flesler + * http://flesler.blogspot.com/2008/11/fast-trim-function-for-javascript.html + * @param {Object} str + */ +function __trim__( str ){ return (str || "").replace( /^\s+|\s+$/g, "" ); - -}; -/*function trim( str ){ - var start = -1, - end = str.length; - /*jsl:ignore* - while( str.charCodeAt(--end) < 33 ); - while( str.charCodeAt(++start) < 33 ); - /*jsl:end* - return str.slice( start, end + 1 ); -};*/ +} + +/** + * Writes message to system out + * @param {String} message + */ +Envjs.log = function(message){}; + +/** + * Constants providing enumerated levels for logging in modules + */ +Envjs.DEBUG = 1; +Envjs.INFO = 2; +Envjs.WARN = 3; +Envjs.ERROR = 3; +Envjs.NONE = 3; + +/** + * Writes error info out to console + * @param {Error} e + */ +Envjs.lineSource = function(e){}; + + +/** + * TODO: used in ./event/eventtarget.js + * @param {Object} event + */ +Envjs.defaultEventBehaviors = {}; + + +/** + * describes which script src values will trigger Envjs to load + * the script like a browser would + */ +Envjs.scriptTypes = { + "text/javascript" :false, + "text/envjs" :true +}; + +/** + * will be called when loading a script throws an error + * @param {Object} script + * @param {Object} e + */ +Envjs.onScriptLoadError = function(script, e){ + console.log('error loading script %s %s', script, e); +}; + + +/** + * load and execute script tag text content + * @param {Object} script + */ +Envjs.loadInlineScript = function(script){ + var tmpFile; + tmpFile = Envjs.writeToTempFile(script.text, 'js') ; + load(tmpFile); +}; + +/** + * Should evaluate script in some context + * @param {Object} context + * @param {Object} source + * @param {Object} name + */ +Envjs.eval = function(context, source, name){}; + + +/** + * Executes a script tag + * @param {Object} script + * @param {Object} parser + */ +Envjs.loadLocalScript = function(script){ + //console.log("loading script %s", script); + var types, + src, + i, + base, + filename, + xhr; + + if(script.type){ + types = script.type.split(";"); + for(i=0;i + * - Via an innerHTML parse of a + * - A modificiation of the 'src' attribute of an Image/HTMLImageElement + * + * NOTE: this is optional API. If this doesn't exist then the default + * 'loaded' event occurs. + * + * @param node {Object} the node + * @param node the src value + * @return 'true' to indicate the 'load' succeed, false otherwise + */ +Envjs.loadImage = function(node, src) { + return true; +}; + + +/** + * A 'link' was requested by the document. Typically this occurs when: + * - During inital parse of a + * - Via an innerHTML parse of a + * - A modificiation of the 'href' attribute on a node in the tree + * + * @param node {Object} is the link node in question + * @param href {String} is the href. + * + * Return 'true' to indicate that the 'load' was successful, or false + * otherwise. The appropriate event is then triggered. + * + * NOTE: this is optional API. If this doesn't exist then the default + * 'loaded' event occurs + */ +Envjs.loadLink = function(node, href) { + return true; +}; + +(function(){ + + +/* + * cookie handling + * Private internal helper class used to save/retreive cookies + */ + +/** + * Specifies the location of the cookie file + */ +Envjs.cookieFile = function(){ + return 'file://'+Envjs.homedir+'/.cookies'; +}; + +/** + * saves cookies to a local file + * @param {Object} htmldoc + */ +Envjs.saveCookies = function(){ + var cookiejson = JSON.stringify(Envjs.cookies.peristent,null,'\t'); + //console.log('persisting cookies %s', cookiejson); + Envjs.writeToFile(cookiejson, Envjs.cookieFile()); +}; + +/** + * loads cookies from a local file + * @param {Object} htmldoc + */ +Envjs.loadCookies = function(){ + var cookiejson, + js; + try{ + cookiejson = Envjs.readFromFile(Envjs.cookieFile()) + js = JSON.parse(cookiejson, null, '\t'); + }catch(e){ + //console.log('failed to load cookies %s', e); + js = {}; + } + return js; +}; + +Envjs.cookies = { + persistent:{ + //domain - key on domain name { + //path - key on path { + //name - key on name { + //value : cookie value + //other cookie properties + //} + //} + //} + //expire - provides a timestamp for expiring the cookie + //cookie - the cookie! + }, + temporary:{//transient is a reserved word :( + //like above + } +}; + +var __cookies__; + +//HTMLDocument cookie +Envjs.setCookie = function(url, cookie){ + var i, + index, + name, + value, + properties = {}, + attr, + attrs; + url = Envjs.urlsplit(url); + if(cookie) + attrs = cookie.split(";"); + else + return; + + //for now the strategy is to simply create a json object + //and post it to a file in the .cookies.js file. I hate parsing + //dates so I decided not to implement support for 'expires' + //(which is deprecated) and instead focus on the easier 'max-age' + //(which succeeds 'expires') + cookie = {};//keyword properties of the cookie + cookie['domain'] = url.hostname; + cookie['path'] = url.path||'/'; + for(i=0;i -1){ + name = __trim__(attrs[i].slice(0,index)); + value = __trim__(attrs[i].slice(index+1)); + if(name=='max-age'){ + //we'll have to when to check these + //and garbage collect expired cookies + cookie[name] = parseInt(value, 10); + } else if( name == 'domain' ){ + if(__domainValid__(url, value)){ + cookie['domain'] = value; + } + } else if( name == 'path' ){ + //not sure of any special logic for path + cookie['path'] = value; + } else { + //its not a cookie keyword so store it in our array of properties + //and we'll serialize individually in a moment + properties[name] = value; + } + }else{ + if( attrs[i] == 'secure' ){ + cookie[attrs[i]] = true; + } + } + } + if(!('max-age' in cookie)){ + //it's a transient cookie so it only lasts as long as + //the window.location remains the same (ie in-memory cookie) + __mergeCookie__(Envjs.cookies.temporary, cookie, properties); + }else{ + //the cookie is persistent + __mergeCookie__(Envjs.cookies.persistent, cookie, properties); + Envjs.saveCookies(); + } +}; + +function __domainValid__(url, value){ + var i, + domainParts = url.hostname.split('.').reverse(), + newDomainParts = value.split('.').reverse(); + if(newDomainParts.length > 1){ + for(i=0;i -1) { + for (name in cookies[domain][path]) { + // console.log('cookie domain path name %s', name); + cookieString += + ((i++ > 0)?'; ':'') + + name + "=" + + cookies[domain][path][name].value; + } + } + } + } + } + return cookieString; +}; + +function __mergeCookie__(target, cookie, properties){ + var name, now; + if(!target[cookie.domain]){ + target[cookie.domain] = {}; + } + if(!target[cookie.domain][cookie.path]){ + target[cookie.domain][cookie.path] = {}; + } + for(name in properties){ + now = new Date().getTime(); + target[cookie.domain][cookie.path][name] = { + "value":properties[name], + "secure":cookie.secure, + "max-age":cookie['max-age'], + "date-created":now, + "expiration":(cookie['max-age']===0) ? + 0 : + now + cookie['max-age'] + }; + //console.log('cookie is %o',target[cookie.domain][cookie.path][name]); + } +}; + +})();//end cookies +/* + http://www.JSON.org/json2.js + 2008-07-15 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. +*/ +try{ JSON; }catch(e){ +JSON = function () { + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + Date.prototype.toJSON = function (key) { + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + String.prototype.toJSON = function (key) { + return String(this); + }; + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + + escapeable.lastIndex = 0; + return escapeable.test(string) ? + '"' + string.replace(escapeable, function (a) { + var c = meta[a]; + if (typeof c === 'string') { + return c; + } + return '\\u' + ('0000' + + (+(a.charCodeAt(0))).toString(16)).slice(-4); + }) + '"' : + '"' + string + '"'; + } + + + function str(key, holder) { + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + + return String(value); + + case 'object': + + if (!value) { + return 'null'; + } + gap += indent; + partial = []; + + if (typeof value.length === 'number' && + !(value.propertyIsEnumerable('length'))) { + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + + v = partial.length === 0 ? '[]' : + gap ? '[\n' + gap + + partial.join(',\n' + gap) + '\n' + + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + k = rep[i]; + if (typeof k === 'string') { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + + v = partial.length === 0 ? '{}' : + gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + + return { + stringify: function (value, replacer, space) { + + var i; + gap = ''; + indent = ''; + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + + } else if (typeof space === 'string') { + indent = space; + } + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + + return str('', {'': value}); + }, + + + parse: function (text, reviver) { + var j; + function walk(holder, key) { + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + ('0000' + + (+(a.charCodeAt(0))).toString(16)).slice(-4); + }); + } + + + if (/^[\],:{}\s]*$/. +test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). +replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). +replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + + j = eval('(' + text + ')'); + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + + throw new SyntaxError('JSON.parse'); + } + }; +}(); + +} + +/** + * synchronizes thread modifications + * @param {Function} fn + */ +Envjs.sync = function(fn){}; + +/** + * sleep thread for specified duration + * @param {Object} millseconds + */ +Envjs.sleep = function(millseconds){}; + +/** + * Interval to wait on event loop when nothing is happening + */ +Envjs.WAIT_INTERVAL = 20;//milliseconds + +/* + * Copyright (c) 2010 Nick Galbreath + * http://code.google.com/p/stringencoders/source/browse/#svn/trunk/javascript + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * url processing in the spirit of python's urlparse module + * see `pydoc urlparse` or + * http://docs.python.org/library/urlparse.html + * + * urlsplit: break apart a URL into components + * urlunsplit: reconsistute a URL from componets + * urljoin: join an absolute and another URL + * urldefrag: remove the fragment from a URL + * + * Take a look at the tests in urlparse-test.html + * + * On URL Normalization: + * + * urlsplit only does minor normalization the components Only scheme + * and hostname are lowercased urljoin does a bit more, normalizing + * paths with "." and "..". + + * urlnormalize adds additional normalization + * + * * removes default port numbers + * http://abc.com:80/ -> http://abc.com/, etc + * * normalizes path + * http://abc.com -> http://abc.com/ + * and other "." and ".." cleanups + * * if file, remove query and fragment + * + * It does not do: + * * normalizes escaped hex values + * http://abc.com/%7efoo -> http://abc.com/%7Efoo + * * normalize '+' <--> '%20' + * + * Differences with Python + * + * The javascript urlsplit returns a normal object with the following + * properties: scheme, netloc, hostname, port, path, query, fragment. + * All properties are read-write. + * + * In python, the resulting object is not a dict, but a specialized, + * read-only, and has alternative tuple interface (e.g. obj[0] == + * obj.scheme). It's not clear why such a simple function requires + * a unique datastructure. + * + * urlunsplit in javascript takes an duck-typed object, + * { scheme: 'http', netloc: 'abc.com', ...} + * while in * python it takes a list-like object. + * ['http', 'abc.com'... ] + * + * For all functions, the javascript version use + * hostname+port if netloc is missing. In python + * hostname+port were always ignored. + * + * Similar functionality in different languages: + * + * http://php.net/manual/en/function.parse-url.php + * returns assocative array but cannot handle relative URL + * + * TODO: test allowfragments more + * TODO: test netloc missing, but hostname present + */ + +var urlparse = {}; + +// Unlike to be useful standalone +// +// NORMALIZE PATH with "../" and "./" +// http://en.wikipedia.org/wiki/URL_normalization +// http://tools.ietf.org/html/rfc3986#section-5.2.3 +// +urlparse.normalizepath = function(path) +{ + if (!path || path === '/') { + return '/'; + } + + var parts = path.split('/'); + + var newparts = []; + // make sure path always starts with '/' + if (parts[0]) { + newparts.push(''); + } + + for (var i = 0; i < parts.length; ++i) { + if (parts[i] === '..') { + if (newparts.length > 1) { + newparts.pop(); + } else { + newparts.push(parts[i]); + } + } else if (parts[i] != '.') { + newparts.push(parts[i]); + } + } + + path = newparts.join('/'); + if (!path) { + path = '/'; + } + return path; +}; + +// +// Does many of the normalizations that the stock +// python urlsplit/urlunsplit/urljoin neglects +// +// Doesn't do hex-escape normalization on path or query +// %7e -> %7E +// Nor, '+' <--> %20 translation +// +urlparse.urlnormalize = function(url) +{ + var parts = urlparse.urlsplit(url); + switch (parts.scheme) { + case 'file': + // files can't have query strings + // and we don't bother with fragments + parts.query = ''; + parts.fragment = ''; + break; + case 'http': + case 'https': + // remove default port + if ((parts.scheme === 'http' && parts.port == 80) || + (parts.scheme === 'https' && parts.port == 443)) { + parts.port = null; + // hostname is already lower case + parts.netloc = parts.hostname; + } + break; + default: + // if we don't have specific normalizations for this + // scheme, return the original url unmolested + return url; + } + + // for [file|http|https]. Not sure about other schemes + parts.path = urlparse.normalizepath(parts.path); + + return urlparse.urlunsplit(parts); +}; + +urlparse.urldefrag = function(url) +{ + var idx = url.indexOf('#'); + if (idx == -1) { + return [ url, '' ]; + } else { + return [ url.substr(0,idx), url.substr(idx+1) ]; + } +}; + +urlparse.urlsplit = function(url, default_scheme, allow_fragments) +{ + var leftover; + + if (typeof allow_fragments === 'undefined') { + allow_fragments = true; + } + + // scheme (optional), host, port + var fullurl = /^([A-Za-z]+)?(:?\/\/)([0-9.\-A-Za-z]*)(?::(\d+))?(.*)$/; + // path, query, fragment + var parse_leftovers = /([^?#]*)?(?:\?([^#]*))?(?:#(.*))?$/; + + var o = {}; + + var parts = url.match(fullurl); + if (parts) { + o.scheme = parts[1] || default_scheme || ''; + o.hostname = parts[3].toLowerCase() || ''; + o.port = parseInt(parts[4],10) || ''; + // Probably should grab the netloc from regexp + // and then parse again for hostname/port + + o.netloc = parts[3]; + if (parts[4]) { + o.netloc += ':' + parts[4]; + } + + leftover = parts[5]; + } else { + o.scheme = default_scheme || ''; + o.netloc = ''; + o.hostname = ''; + leftover = url; + } + o.scheme = o.scheme.toLowerCase(); + + parts = leftover.match(parse_leftovers); + + o.path = parts[1] || ''; + o.query = parts[2] || ''; + + if (allow_fragments) { + o.fragment = parts[3] || ''; + } else { + o.fragment = ''; + } + + return o; +}; + +urlparse.urlunsplit = function(o) { + var s = ''; + if (o.scheme) { + s += o.scheme + '://'; + } + + if (o.netloc) { + if (s == '') { + s += '//'; + } + s += o.netloc; + } else if (o.hostname) { + // extension. Python only uses netloc + if (s == '') { + s += '//'; + } + s += o.hostname; + if (o.port) { + s += ':' + o.port; + } + } + + if (o.path) { + s += o.path; + } + + if (o.query) { + s += '?' + o.query; + } + if (o.fragment) { + s += '#' + o.fragment; + } + return s; +}; + +urlparse.urljoin = function(base, url, allow_fragments) +{ + if (typeof allow_fragments === 'undefined') { + allow_fragments = true; + } + + var url_parts = urlparse.urlsplit(url); + + // if url parts has a scheme (i.e. absolute) + // then nothing to do + if (url_parts.scheme) { + if (! allow_fragments) { + return url; + } else { + return urlparse.urldefrag(url)[0]; + } + } + var base_parts = urlparse.urlsplit(base); + + // copy base, only if not present + if (!base_parts.scheme) { + base_parts.scheme = url_parts.scheme; + } + + // copy netloc, only if not present + if (!base_parts.netloc || !base_parts.hostname) { + base_parts.netloc = url_parts.netloc; + base_parts.hostname = url_parts.hostname; + base_parts.port = url_parts.port; + } + + // paths + if (url_parts.path.length > 0) { + if (url_parts.path.charAt(0) == '/') { + base_parts.path = url_parts.path; + } else { + // relative path.. get rid of "current filename" and + // replace. Same as var parts = + // base_parts.path.split('/'); parts[parts.length-1] = + // url_parts.path; base_parts.path = parts.join('/'); + var idx = base_parts.path.lastIndexOf('/'); + if (idx == -1) { + base_parts.path = url_parts.path; + } else { + base_parts.path = base_parts.path.substr(0,idx) + '/' + + url_parts.path; + } + } + } + + // clean up path + base_parts.path = urlparse.normalizepath(base_parts.path); + + // copy query string + base_parts.query = url_parts.query; + + // copy fragments + if (allow_fragments) { + base_parts.fragment = url_parts.fragment; + } else { + base_parts.fragment = ''; + } + + return urlparse.urlunsplit(base_parts); +}; + +/** + * getcwd - named after posix call of same name (see 'man 2 getcwd') + * + */ +Envjs.getcwd = function() { + return '.'; +}; + +/** + * resolves location relative to doc location + * + * @param {Object} path Relative or absolute URL + * @param {Object} base (semi-optional) The base url used in resolving "path" above + */ +Envjs.uri = function(path, base) { + //console.log('constructing uri from path %s and base %s', path, base); + + // Semi-common trick is to make an iframe with src='javascript:false' + // (or some equivalent). By returning '', the load is skipped + if (path.indexOf('javascript') === 0) { + return ''; + } + + // if path is absolute, then just normalize and return + if (path.match('^[a-zA-Z]+://')) { + return urlparse.urlnormalize(path); + } + + // interesting special case, a few very large websites use + // '//foo/bar/' to mean 'http://foo/bar' + if (path.match('^//')) { + path = 'http:' + path; + } + + // if base not passed in, try to get it from document + // Ideally I would like the caller to pass in document.baseURI to + // make this more self-sufficient and testable + if (!base && document) { + base = document.baseURI; + } + + // about:blank doesn't count + if (base === 'about:blank'){ + base = ''; + } + + // if base is still empty, then we are in QA mode loading local + // files. Get current working directory + if (!base) { + base = 'file://' + Envjs.getcwd() + '/'; + } + // handles all cases if path is abosulte or relative to base + // 3rd arg is "false" --> remove fragments + var newurl = urlparse.urlnormalize(urlparse.urljoin(base, path, false)); + + return newurl; +}; + + + +/** + * Used in the XMLHttpRquest implementation to run a + * request in a seperate thread + * @param {Object} fn + */ +Envjs.runAsync = function(fn){}; + + +/** + * Used to write to a local file + * @param {Object} text + * @param {Object} url + */ +Envjs.writeToFile = function(text, url){}; + + +/** + * Used to write to a local file + * @param {Object} text + * @param {Object} suffix + */ +Envjs.writeToTempFile = function(text, suffix){}; + +/** + * Used to read the contents of a local file + * @param {Object} url + */ +Envjs.readFromFile = function(url){}; + +/** + * Used to delete a local file + * @param {Object} url + */ +Envjs.deleteFile = function(url){}; + +/** + * establishes connection and calls responsehandler + * @param {Object} xhr + * @param {Object} responseHandler + * @param {Object} data + */ +Envjs.connection = function(xhr, responseHandler, data){}; + + +__extend__(Envjs, urlparse); + +/** + * Makes an object window-like by proxying object accessors + * @param {Object} scope + * @param {Object} parent + */ +Envjs.proxy = function(scope, parent, aliasList){}; + +Envjs.javaEnabled = false; + +Envjs.homedir = ''; +Envjs.tmpdir = ''; +Envjs.os_name = ''; +Envjs.os_arch = ''; +Envjs.os_version = ''; +Envjs.lang = ''; +Envjs.platform = ''; + +/** + * + * @param {Object} frameElement + * @param {Object} url + */ +Envjs.loadFrame = function(frame, url){ + try { + if(frame.contentWindow){ + //mark for garbage collection + frame.contentWindow = null; + } + + //create a new scope for the window proxy + //platforms will need to override this function + //to make sure the scope is global-like + frame.contentWindow = (function(){return this;})(); + new Window(frame.contentWindow, window); + + //I dont think frames load asynchronously in firefox + //and I think the tests have verified this but for + //some reason I'm less than confident... Are there cases? + frame.contentDocument = frame.contentWindow.document; + frame.contentDocument.async = false; + if(url){ + //console.log('envjs.loadFrame async %s', frame.contentDocument.async); + frame.contentWindow.location = url; + } + } catch(e) { + console.log("failed to load frame content: from %s %s", url, e); + } +}; + + +// The following are in rhino/window.js +// TODO: Envjs.unloadFrame +// TODO: Envjs.proxy + +/** + * @author john resig & the envjs team + * @uri http://www.envjs.com/ + * @copyright 2008-2010 + * @license MIT + */ +//CLOSURE_END +}()); + +/** + * @author envjs team + */ +var Console, + console; + +/* + * Envjs console.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ + +//CLOSURE_START +(function(){ + + + + + +/** + * @author envjs team + * borrowed 99%-ish with love from firebug-lite + * + * http://wiki.commonjs.org/wiki/Console + */ +Console = function(module){ + var $level, + $logger, + $null = function(){}; + + + if(Envjs[module] && Envjs[module].loglevel){ + $level = Envjs.module.loglevel; + $logger = { + log: function(level){ + logFormatted(arguments, (module)+" "); + }, + debug: $level>1 ? $null: function() { + logFormatted(arguments, (module)+" debug"); + }, + info: $level>2 ? $null:function(){ + logFormatted(arguments, (module)+" info"); + }, + warn: $level>3 ? $null:function(){ + logFormatted(arguments, (module)+" warning"); + }, + error: $level>4 ? $null:function(){ + logFormatted(arguments, (module)+" error"); + } + }; + } else { + $logger = { + log: function(level){ + logFormatted(arguments, ""); + }, + debug: $null, + info: $null, + warn: $null, + error: $null + }; + } + + return $logger; +}; + +console = new Console("console",1); + +function logFormatted(objects, className) +{ + var html = []; + + var format = objects[0]; + var objIndex = 0; + + if (typeof(format) != "string") + { + format = ""; + objIndex = -1; + } + + var parts = parseFormat(format); + for (var i = 0; i < parts.length; ++i) + { + var part = parts[i]; + if (part && typeof(part) == "object") + { + var object = objects[++objIndex]; + part.appender(object, html); + } + else { + appendText(part, html); + } + } + + for (var i = objIndex+1; i < objects.length; ++i) + { + appendText(" ", html); + + var object = objects[i]; + if (typeof(object) == "string") { + appendText(object, html); + } else { + appendObject(object, html); + } + } + + Envjs.log(html.join(' ')); +} + +function parseFormat(format) +{ + var parts = []; + + var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/; + var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat}; + + for (var m = reg.exec(format); m; m = reg.exec(format)) + { + var type = m[8] ? m[8] : m[5]; + var appender = type in appenderMap ? appenderMap[type] : appendObject; + var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); + + parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); + parts.push({appender: appender, precision: precision}); + + format = format.substr(m.index+m[0].length); + } + + parts.push(format); + + return parts; +} + +function escapeHTML(value) +{ + return value; +} + +function objectToString(object) +{ + try + { + return object+""; + } + catch (exc) + { + return null; + } +} + +// ******************************************************************************************** + +function appendText(object, html) +{ + html.push(escapeHTML(objectToString(object))); +} + +function appendNull(object, html) +{ + html.push(escapeHTML(objectToString(object))); +} + +function appendString(object, html) +{ + html.push(escapeHTML(objectToString(object))); +} + +function appendInteger(object, html) +{ + html.push(escapeHTML(objectToString(object))); +} + +function appendFloat(object, html) +{ + html.push(escapeHTML(objectToString(object))); +} + +function appendFunction(object, html) +{ + var reName = /function ?(.*?)\(/; + var m = reName.exec(objectToString(object)); + var name = m ? m[1] : "function"; + html.push(escapeHTML(name)); +} + +function appendObject(object, html) +{ + try + { + if (object == undefined) { + appendNull("undefined", html); + } else if (object == null) { + appendNull("null", html); + } else if (typeof object == "string") { + appendString(object, html); + } else if (typeof object == "number") { + appendInteger(object, html); + } else if (typeof object == "function") { + appendFunction(object, html); + } else if (object.nodeType == 1) { + appendSelector(object, html); + } else if (typeof object == "object") { + appendObjectFormatted(object, html); + } else { + appendText(object, html); + } + } + catch (exc) + { + } +} + +function appendObjectFormatted(object, html) +{ + var text = objectToString(object); + var reObject = /\[object (.*?)\]/; + + var m = reObject.exec(text); + html.push( m ? m[1] : text); +} + +function appendSelector(object, html) +{ + + html.push(escapeHTML(object.nodeName.toLowerCase())); + if (object.id) { + html.push(escapeHTML(object.id)); + } + if (object.className) { + html.push(escapeHTML(object.className)); + } +} + +function appendNode(node, html) +{ + if (node.nodeType == 1) + { + html.push( node.nodeName.toLowerCase()); + + for (var i = 0; i < node.attributes.length; ++i) + { + var attr = node.attributes[i]; + if (!attr.specified) { + continue; + } + + html.push( attr.nodeName.toLowerCase(),escapeHTML(attr.nodeValue)); + } + + if (node.firstChild) + { + for (var child = node.firstChild; child; child = child.nextSibling) { + appendNode(child, html); + } + + html.push( node.nodeName.toLowerCase()); + } + } + else if (node.nodeType === 3) + { + html.push(escapeHTML(node.nodeValue)); + } +}; + +/** + * @author john resig & the envjs team + * @uri http://www.envjs.com/ + * @copyright 2008-2010 + * @license MIT + */ +//CLOSURE_END +}()); +/* + * Envjs dom.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + * + * Parts of the implementation were originally written by:\ + * and Jon van Noort (jon@webarcana.com.au) \ + * and David Joham (djoham@yahoo.com)",\ + * and Scott Severtson + * + * This file simply provides the global definitions we need to \ + * be able to correctly implement to core browser DOM interfaces." + */ + +var Attr, + CDATASection, + CharacterData, + Comment, + Document, + DocumentFragment, + DocumentType, + DOMException, + DOMImplementation, + Element, + Entity, + EntityReference, + NamedNodeMap, + Namespace, + Node, + NodeList, + Notation, + ProcessingInstruction, + Text, + Range, + XMLSerializer, + DOMParser; + + + +/* + * Envjs dom.1.2.13 + * Pure JavaScript Browser Environment + * By John Resig and the Envjs Team + * Copyright 2008-2010 John Resig, under the MIT License + */ + +//CLOSURE_START +(function(){ + + + + + +/** + * @author john resig + */ +// Helper method for extending one object with another. +function __extend__(a,b) { + for ( var i in b ) { + var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i); + if ( g || s ) { + if ( g ) { a.__defineGetter__(i, g); } + if ( s ) { a.__defineSetter__(i, s); } + } else { + a[i] = b[i]; + } + } return a; +} + +/** + * @author john resig + */ //from jQuery function __setArray__( target, array ) { - // Resetting the length to 0, then using the native Array push - // is a super-fast way to populate an object with array-like properties - target.length = 0; - Array.prototype.push.apply( target, array ); -}; + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + target.length = 0; + Array.prototype.push.apply( target, array ); +} - -$debug("Defining NodeList"); -/* -* NodeList - DOM Level 2 -*/ /** - * @class DOMNodeList - provides the abstraction of an ordered collection of nodes + * @class NodeList - + * provides the abstraction of an ordered collection of nodes * - * @author Jon van Noort (jon@webarcana.com.au) - * - * @param ownerDocument : DOMDocument - the ownerDocument - * @param parentNode : DOMNode - the node that the DOMNodeList is attached to (or null) + * @param ownerDocument : Document - the ownerDocument + * @param parentNode : Node - the node that the NodeList is attached to (or null) */ -var DOMNodeList = function(ownerDocument, parentNode) { +NodeList = function(ownerDocument, parentNode) { this.length = 0; this.parentNode = parentNode; this.ownerDocument = ownerDocument; - this._readonly = false; - __setArray__(this, []); }; -__extend__(DOMNodeList.prototype, { + +__extend__(NodeList.prototype, { item : function(index) { var ret = null; - //$log("NodeList item("+index+") = " + this[index]); - if ((index >= 0) && (index < this.length)) { // bounds check - ret = this[index]; // return selected Node + if ((index >= 0) && (index < this.length)) { + // bounds check + ret = this[index]; } - - return ret; // if the index is out of bounds, default value null is returned + // if the index is out of bounds, default value null is returned + return ret; }, get xml() { - var ret = ""; - + var ret = "", + i; + // create string containing the concatenation of the string values of each child - for (var i=0; i < this.length; i++) { + for (i=0; i < this.length; i++) { if(this[i]){ - if(this[i].nodeType == DOMNode.TEXT_NODE && i>0 && this[i-1].nodeType == DOMNode.TEXT_NODE){ + if(this[i].nodeType == Node.TEXT_NODE && i>0 && + this[i-1].nodeType == Node.TEXT_NODE){ //add a single space between adjacent text nodes ret += " "+this[i].xml; }else{ @@ -279,60 +1643,60 @@ __extend__(DOMNodeList.prototype, { } } } - return ret; }, toArray: function () { - var children = []; - for ( var i=0; i < this.length; i++) { - children.push (this[i]); + var children = [], + i; + for ( i=0; i < this.length; i++) { + children.push (this[i]); } return children; }, toString: function(){ - return "[ "+(this.length > 0?Array.prototype.join.apply(this, [", "]):"Empty NodeList")+" ]"; + return "[object NodeList]"; } }); /** - * @method DOMNodeList._findItemIndex - find the item index of the node with the specified internal id + * @method __findItemIndex__ + * find the item index of the node * @author Jon van Noort (jon@webarcana.com.au) - * @param id : int - unique internal id + * @param node : Node * @return : int */ -var __findItemIndex__ = function (nodelist, id) { - var ret = -1; - - // test that id is valid - if (id > -1) { - for (var i=0; i= 0) && (refChildIndex < nodelist.length)) { // bounds check - - if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) { // node is a DocumentFragment + if ((refChildIndex >= 0) && (refChildIndex <= nodelist.length)) { + // bounds check + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // node is a DocumentFragment // append the children of DocumentFragment - Array.prototype.splice.apply(nodelist,[refChildIndex, 0].concat(newChild.childNodes.toArray())); + Array.prototype.splice.apply(nodelist, + [refChildIndex, 0].concat(newChild.childNodes.toArray())); } else { // append the newChild @@ -342,517 +1706,201 @@ var __insertBefore__ = function(nodelist, newChild, refChildIndex) { }; /** - * @method DOMNodeList._replaceChild - replace the specified Node in the NodeList at the specified index - * Used by DOMNode.replaceChild(). Note: DOMNode.replaceChild() is responsible for Node Pointer surgery - * DOMNodeList._replaceChild() simply modifies the internal data structure (Array). + * @method __replaceChild__ + * replace the specified Node in the NodeList at the specified index + * Used by Node.replaceChild(). Note: Node.replaceChild() is responsible + * for Node Pointer surgery __replaceChild__ simply modifies the internal + * data structure (Array). * - * @author Jon van Noort (jon@webarcana.com.au) - * @param newChild : DOMNode - the Node to be inserted + * @param newChild : Node - the Node to be inserted * @param refChildIndex : int - the array index to hold the Node */ var __replaceChild__ = function(nodelist, newChild, refChildIndex) { var ret = null; - - if ((refChildIndex >= 0) && (refChildIndex < nodelist.length)) { // bounds check - ret = nodelist[refChildIndex]; // preserve old child for return - - if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) { // node is a DocumentFragment + + // bounds check + if ((refChildIndex >= 0) && (refChildIndex < nodelist.length)) { + // preserve old child for return + ret = nodelist[refChildIndex]; + + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // node is a DocumentFragment // get array containing children prior to refChild - Array.prototype.splice.apply(nodelist,[refChildIndex, 1].concat(newChild.childNodes.toArray())); + Array.prototype.splice.apply(nodelist, + [refChildIndex, 1].concat(newChild.childNodes.toArray())); } else { - // simply replace node in array (links between Nodes are made at higher level) + // simply replace node in array (links between Nodes are + // made at higher level) nodelist[refChildIndex] = newChild; } } - - return ret; // return replaced node + // return replaced node + return ret; }; /** - * @method DOMNodeList._removeChild - remove the specified Node in the NodeList at the specified index - * Used by DOMNode.removeChild(). Note: DOMNode.removeChild() is responsible for Node Pointer surgery - * DOMNodeList._replaceChild() simply modifies the internal data structure (Array). - * - * @author Jon van Noort (jon@webarcana.com.au) + * @method __removeChild__ + * remove the specified Node in the NodeList at the specified index + * Used by Node.removeChild(). Note: Node.removeChild() is responsible + * for Node Pointer surgery __removeChild__ simply modifies the internal + * data structure (Array). * @param refChildIndex : int - the array index holding the Node to be removed */ var __removeChild__ = function(nodelist, refChildIndex) { var ret = null; - - if (refChildIndex > -1) { // found it! - ret = nodelist[refChildIndex]; // return removed node - + + if (refChildIndex > -1) { + // found it! + // return removed node + ret = nodelist[refChildIndex]; + // rebuild array without removed child Array.prototype.splice.apply(nodelist,[refChildIndex, 1]); } - - return ret; // return removed node + // return removed node + return ret; }; /** - * @method DOMNodeList._appendChild - append the specified Node to the NodeList - * Used by DOMNode.appendChild(). Note: DOMNode.appendChild() is responsible for Node Pointer surgery - * DOMNodeList._appendChild() simply modifies the internal data structure (Array). - * - * @author Jon van Noort (jon@webarcana.com.au) - * @param newChild : DOMNode - the Node to be inserted + * @method __appendChild__ + * append the specified Node to the NodeList. Used by Node.appendChild(). + * Note: Node.appendChild() is responsible for Node Pointer surgery + * __appendChild__ simply modifies the internal data structure (Array). + * @param newChild : Node - the Node to be inserted */ var __appendChild__ = function(nodelist, newChild) { - if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) { // node is a DocumentFragment + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // node is a DocumentFragment // append the children of DocumentFragment - Array.prototype.push.apply(nodelist, newChild.childNodes.toArray() ); + Array.prototype.push.apply(nodelist, newChild.childNodes.toArray() ); } else { // simply add node to array (links between Nodes are made at higher level) Array.prototype.push.apply(nodelist, [newChild]); } - + }; /** - * @method DOMNodeList._cloneNodes - Returns a NodeList containing clones of the Nodes in this NodeList - * - * @author Jon van Noort (jon@webarcana.com.au) - * @param deep : boolean - If true, recursively clone the subtree under each of the nodes; - * if false, clone only the nodes themselves (and their attributes, if it is an Element). - * @param parentNode : DOMNode - the new parent of the cloned NodeList - * @return : DOMNodeList - NodeList containing clones of the Nodes in this NodeList + * @method __cloneNodes__ - + * Returns a NodeList containing clones of the Nodes in this NodeList + * @param deep : boolean - + * If true, recursively clone the subtree under each of the nodes; + * if false, clone only the nodes themselves (and their attributes, + * if it is an Element). + * @param parentNode : Node - the new parent of the cloned NodeList + * @return : NodeList - NodeList containing clones of the Nodes in this NodeList */ var __cloneNodes__ = function(nodelist, deep, parentNode) { - var cloneNodeList = new DOMNodeList(nodelist.ownerDocument, parentNode); - + var cloneNodeList = new NodeList(nodelist.ownerDocument, parentNode); + // create list containing clones of each child for (var i=0; i < nodelist.length; i++) { __appendChild__(cloneNodeList, nodelist[i].cloneNode(deep)); } - + return cloneNodeList; }; -$w.NodeList = DOMNodeList; -/** - * @class DOMNamedNodeMap - used to represent collections of nodes that can be accessed by name - * typically a set of Element attributes - * - * @extends DOMNodeList - note W3C spec says that this is not the case, - * but we need an item() method identicle to DOMNodeList's, so why not? - * @author Jon van Noort (jon@webarcana.com.au) - * @param ownerDocument : DOMDocument - the ownerDocument - * @param parentNode : DOMNode - the node that the DOMNamedNodeMap is attached to (or null) - */ -var DOMNamedNodeMap = function(ownerDocument, parentNode) { - //$log("\t\tcreating dom namednodemap"); - this.DOMNodeList = DOMNodeList; - this.DOMNodeList(ownerDocument, parentNode); - __setArray__(this, []); -}; -DOMNamedNodeMap.prototype = new DOMNodeList; -__extend__(DOMNamedNodeMap.prototype, { - getNamedItem : function(name) { - var ret = null; - - // test that Named Node exists - var itemIndex = __findNamedItemIndex__(this, name); - - if (itemIndex > -1) { // found it! - ret = this[itemIndex]; // return NamedNode - } - - return ret; // if node is not found, default value null is returned - }, - setNamedItem : function(arg) { - // test for exceptions - if (__ownerDocument__(this).implementation.errorChecking) { - // throw Exception if arg was not created by this Document - if (this.ownerDocument != arg.ownerDocument) { - throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); - } - - // throw Exception if DOMNamedNodeMap is readonly - if (this._readonly || (this.parentNode && this.parentNode._readonly)) { - throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); - } - - // throw Exception if arg is already an attribute of another Element object - if (arg.ownerElement && (arg.ownerElement != this.parentNode)) { - throw(new DOMException(DOMException.INUSE_ATTRIBUTE_ERR)); - } - } - - // get item index - var itemIndex = __findNamedItemIndex__(this, arg.name); - var ret = null; - - if (itemIndex > -1) { // found it! - ret = this[itemIndex]; // use existing Attribute - - // throw Exception if DOMAttr is readonly - if (__ownerDocument__(this).implementation.errorChecking && ret._readonly) { - throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); - } else { - this[itemIndex] = arg; // over-write existing NamedNode - this[arg.name] = arg; - } - } else { - // add new NamedNode - Array.prototype.push.apply(this, [arg]); - this[arg.name] = arg; - } - - arg.ownerElement = this.parentNode; // update ownerElement - - return ret; // return old node or null - }, - removeNamedItem : function(name) { - var ret = null; - // test for exceptions - // throw Exception if DOMNamedNodeMap is readonly - if (__ownerDocument__(this).implementation.errorChecking && - (this._readonly || (this.parentNode && this.parentNode._readonly))) { - throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); - } - - // get item index - var itemIndex = __findNamedItemIndex__(this, name); - - // throw Exception if there is no node named name in this map - if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { - throw(new DOMException(DOMException.NOT_FOUND_ERR)); - } - - // get Node - var oldNode = this[itemIndex]; - //this[oldNode.name] = undefined; - - // throw Exception if Node is readonly - if (__ownerDocument__(this).implementation.errorChecking && oldNode._readonly) { - throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); - } - - // return removed node - return __removeChild__(this, itemIndex); - }, - getNamedItemNS : function(namespaceURI, localName) { - var ret = null; - - // test that Named Node exists - var itemIndex = __findNamedItemNSIndex__(this, namespaceURI, localName); - - if (itemIndex > -1) { // found it! - ret = this[itemIndex]; // return NamedNode - } - - return ret; // if node is not found, default value null is returned - }, - setNamedItemNS : function(arg) { - // test for exceptions - if (__ownerDocument__(this).implementation.errorChecking) { - // throw Exception if DOMNamedNodeMap is readonly - if (this._readonly || (this.parentNode && this.parentNode._readonly)) { - throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); - } - - // throw Exception if arg was not created by this Document - if (__ownerDocument__(this) != __ownerDocument__(arg)) { - throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); - } - - // throw Exception if arg is already an attribute of another Element object - if (arg.ownerElement && (arg.ownerElement != this.parentNode)) { - throw(new DOMException(DOMException.INUSE_ATTRIBUTE_ERR)); - } - } - - // get item index - var itemIndex = __findNamedItemNSIndex__(this, arg.namespaceURI, arg.localName); - var ret = null; - - if (itemIndex > -1) { // found it! - ret = this[itemIndex]; // use existing Attribute - // throw Exception if DOMAttr is readonly - if (__ownerDocument__(this).implementation.errorChecking && ret._readonly) { - throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); - } else { - this[itemIndex] = arg; // over-write existing NamedNode - } - }else { - // add new NamedNode - Array.prototype.push.apply(this, [arg]); - } - arg.ownerElement = this.parentNode; - - - return ret; // return old node or null - }, - removeNamedItemNS : function(namespaceURI, localName) { - var ret = null; - - // test for exceptions - // throw Exception if DOMNamedNodeMap is readonly - if (__ownerDocument__(this).implementation.errorChecking && (this._readonly || (this.parentNode && this.parentNode._readonly))) { - throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); - } - - // get item index - var itemIndex = __findNamedItemNSIndex__(this, namespaceURI, localName); - - // throw Exception if there is no matching node in this map - if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { - throw(new DOMException(DOMException.NOT_FOUND_ERR)); - } - - // get Node - var oldNode = this[itemIndex]; - - // throw Exception if Node is readonly - if (__ownerDocument__(this).implementation.errorChecking && oldNode._readonly) { - throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); - } - - return __removeChild__(this, itemIndex); // return removed node - }, - get xml() { - var ret = ""; - - // create string containing concatenation of all (but last) Attribute string values (separated by spaces) - for (var i=0; i < this.length -1; i++) { - ret += this[i].xml +" "; - } - - // add last Attribute to string (without trailing space) - if (this.length > 0) { - ret += this[this.length -1].xml; - } - - return ret; - } - -}); - -/** - * @method DOMNamedNodeMap._findNamedItemIndex - find the item index of the node with the specified name - * - * @author Jon van Noort (jon@webarcana.com.au) - * @param name : string - the name of the required node - * @param isnsmap : if its a DOMNamespaceNodeMap - * @return : int - */ -var __findNamedItemIndex__ = function(namednodemap, name, isnsmap) { - var ret = -1; - - // loop through all nodes - for (var i=0; i -1) { // found it! - ret = true; // return true - } + //IMPORTANT: These must come last so rhino will not iterate parent + // properties before child properties. (qunit.equiv issue) - return ret; // if node is not found, default value false is returned -} + // The parent of this node. All nodes, except Document, DocumentFragment, + // and Attr may have a parent. However, if a node has just been created + // and not yet added to the tree, or if it has been removed from the tree, + // this is null + this.parentNode = null; + // The Document object associated with this node + this.ownerDocument = ownerDocument; -/** - * @method DOMNamedNodeMap._hasAttributeNS - Returns true if specified node exists - * - * @author Jon van Noort (jon@webarcana.com.au) - * @param namespaceURI : string - the namespace URI of the required node - * @param localName : string - the local name of the required node - * @return : boolean - */ -var __hasAttributeNS__ = function(namednodemap, namespaceURI, localName) { - var ret = false; - - // test that Named Node exists - var itemIndex = __findNamedItemNSIndex__(namednodemap, namespaceURI, localName); - - if (itemIndex > -1) { // found it! - ret = true; // return true - } - - return ret; // if node is not found, default value false is returned -} - -/** - * @method DOMNamedNodeMap._cloneNodes - Returns a NamedNodeMap containing clones of the Nodes in this NamedNodeMap - * - * @author Jon van Noort (jon@webarcana.com.au) - * @param parentNode : DOMNode - the new parent of the cloned NodeList - * @param isnsmap : bool - is this a DOMNamespaceNodeMap - * @return : DOMNamedNodeMap - NamedNodeMap containing clones of the Nodes in this DOMNamedNodeMap - */ -var __cloneNamedNodes__ = function(namednodemap, parentNode, isnsmap) { - var cloneNamedNodeMap = isnsmap? - new DOMNamespaceNodeMap(namednodemap.ownerDocument, parentNode): - new DOMNamedNodeMap(namednodemap.ownerDocument, parentNode); - - // create list containing clones of all children - for (var i=0; i < namednodemap.length; i++) { - $debug("cloning node in named node map :" + namednodemap[i]); - __appendChild__(cloneNamedNodeMap, namednodemap[i].cloneNode(false)); - } - - return cloneNamedNodeMap; -}; - - -/** - * @class DOMNamespaceNodeMap - used to represent collections of namespace nodes that can be accessed by name - * typically a set of Element attributes - * - * @extends DOMNamedNodeMap - * - * @author Jon van Noort (jon@webarcana.com.au) - * - * @param ownerDocument : DOMDocument - the ownerDocument - * @param parentNode : DOMNode - the node that the DOMNamespaceNodeMap is attached to (or null) - */ -var DOMNamespaceNodeMap = function(ownerDocument, parentNode) { - //$log("\t\t\tcreating dom namespacednodemap"); - this.DOMNamedNodeMap = DOMNamedNodeMap; - this.DOMNamedNodeMap(ownerDocument, parentNode); - __setArray__(this, []); -}; -DOMNamespaceNodeMap.prototype = new DOMNamedNodeMap; -__extend__(DOMNamespaceNodeMap.prototype, { - get xml() { - var ret = ""; - - // identify namespaces declared local to this Element (ie, not inherited) - for (var ind = 0; ind < this.length; ind++) { - // if namespace declaration does not exist in the containing node's, parentNode's namespaces - var ns = null; - try { - var ns = this.parentNode.parentNode._namespaces. - getNamedItem(this[ind].localName); - } - catch (e) { - //breaking to prevent default namespace being inserted into return value - break; - } - if (!(ns && (""+ ns.nodeValue == ""+ this[ind].nodeValue))) { - // display the namespace declaration - ret += this[ind].xml +" "; - } - } - - return ret; - } -}); -$debug("Defining Node"); -/* -* Node - DOM Level 2 -*/ -/** - * @class DOMNode - The Node interface is the primary datatype for the entire Document Object Model. - * It represents a single node in the document tree. - * @author Jon van Noort (jon@webarcana.com.au), David Joham (djoham@yahoo.com) and Scott Severtson - * @param ownerDocument : DOMDocument - The Document object associated with this node. - */ -var DOMNode = function(ownerDocument) { - if (ownerDocument) { - this._id = ownerDocument._genId(); // generate unique internal id - } - - this.namespaceURI = ""; // The namespace URI of this node (Level 2) - this.prefix = ""; // The namespace prefix of this node (Level 2) - this.localName = ""; // The localName of this node (Level 2) - - this.nodeName = ""; // The name of this node - this.nodeValue = null; // The value of this node - this.className = ""; // The CSS class name of this node. - - // The parent of this node. All nodes, except Document, DocumentFragment, and Attr may have a parent. - // However, if a node has just been created and not yet added to the tree, or if it has been removed from the tree, this is null - this.parentNode = null; - - // A NodeList that contains all children of this node. If there are no children, this is a NodeList containing no nodes. - // The content of the returned NodeList is "live" in the sense that, for instance, changes to the children of the node object - // that it was created from are immediately reflected in the nodes returned by the NodeList accessors; - // it is not a static snapshot of the content of the node. This is true for every NodeList, including the ones returned by the getElementsByTagName method. - this.childNodes = new DOMNodeList(ownerDocument, this); - - this.firstChild = null; // The first child of this node. If there is no such node, this is null - this.lastChild = null; // The last child of this node. If there is no such node, this is null. - this.previousSibling = null; // The node immediately preceding this node. If there is no such node, this is null. - this.nextSibling = null; // The node immediately following this node. If there is no such node, this is null. - - this.ownerDocument = ownerDocument; // The Document object associated with this node - this.attributes = new DOMNamedNodeMap(this.ownerDocument, this); - this._namespaces = new DOMNamespaceNodeMap(ownerDocument, this); // The namespaces in scope for this node - this._readonly = false; }; // nodeType constants -DOMNode.ELEMENT_NODE = 1; -DOMNode.ATTRIBUTE_NODE = 2; -DOMNode.TEXT_NODE = 3; -DOMNode.CDATA_SECTION_NODE = 4; -DOMNode.ENTITY_REFERENCE_NODE = 5; -DOMNode.ENTITY_NODE = 6; -DOMNode.PROCESSING_INSTRUCTION_NODE = 7; -DOMNode.COMMENT_NODE = 8; -DOMNode.DOCUMENT_NODE = 9; -DOMNode.DOCUMENT_TYPE_NODE = 10; -DOMNode.DOCUMENT_FRAGMENT_NODE = 11; -DOMNode.NOTATION_NODE = 12; -DOMNode.NAMESPACE_NODE = 13; +Node.ELEMENT_NODE = 1; +Node.ATTRIBUTE_NODE = 2; +Node.TEXT_NODE = 3; +Node.CDATA_SECTION_NODE = 4; +Node.ENTITY_REFERENCE_NODE = 5; +Node.ENTITY_NODE = 6; +Node.PROCESSING_INSTRUCTION_NODE = 7; +Node.COMMENT_NODE = 8; +Node.DOCUMENT_NODE = 9; +Node.DOCUMENT_TYPE_NODE = 10; +Node.DOCUMENT_FRAGMENT_NODE = 11; +Node.NOTATION_NODE = 12; +Node.NAMESPACE_NODE = 13; -__extend__(DOMNode.prototype, { +Node.DOCUMENT_POSITION_EQUAL = 0x00; +Node.DOCUMENT_POSITION_DISCONNECTED = 0x01; +Node.DOCUMENT_POSITION_PRECEDING = 0x02; +Node.DOCUMENT_POSITION_FOLLOWING = 0x04; +Node.DOCUMENT_POSITION_CONTAINS = 0x08; +Node.DOCUMENT_POSITION_CONTAINED_BY = 0x10; +Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20; + + +__extend__(Node.prototype, { + get localName(){ + return this.prefix? + this.nodeName.substring(this.prefix.length+1, this.nodeName.length): + this.nodeName; + }, + get prefix(){ + return this.nodeName.split(':').length>1? + this.nodeName.split(':')[0]: + null; + }, + set prefix(value){ + if(value === null){ + this.nodeName = this.localName; + }else{ + this.nodeName = value+':'+this.localName; + } + }, hasAttributes : function() { if (this.attributes.length == 0) { return false; @@ -860,170 +1908,187 @@ __extend__(DOMNode.prototype, { return true; } }, + get textContent(){ + return __recursivelyGatherText__(this); + }, + set textContent(newText){ + while(this.firstChild != null){ + this.removeChild( this.firstChild ); + } + var text = this.ownerDocument.createTextNode(newText); + this.appendChild(text); + }, insertBefore : function(newChild, refChild) { var prevNode; - - if(newChild==null || refChild==null){ + + if(newChild==null){ return newChild; } - + if(refChild==null){ + this.appendChild(newChild); + return this.newChild; + } + // test for exceptions if (__ownerDocument__(this).implementation.errorChecking) { - // throw Exception if DOMNode is readonly + // throw Exception if Node is readonly if (this._readonly) { throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } - + // throw Exception if newChild was not created by this Document if (__ownerDocument__(this) != __ownerDocument__(newChild)) { throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); } - + // throw Exception if the node is an ancestor if (__isAncestor__(this, newChild)) { throw(new DOMException(DOMException.HIERARCHY_REQUEST_ERR)); } } - - if (refChild) { // if refChild is specified, insert before it + + // if refChild is specified, insert before it + if (refChild) { // find index of refChild - var itemIndex = __findItemIndex__(this.childNodes, refChild._id); - + var itemIndex = __findItemIndex__(this.childNodes, refChild); // throw Exception if there is no child node with this id if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { - throw(new DOMException(DOMException.NOT_FOUND_ERR)); + throw(new DOMException(DOMException.NOT_FOUND_ERR)); } - + // if the newChild is already in the tree, var newChildParent = newChild.parentNode; if (newChildParent) { - // remove it - newChildParent.removeChild(newChild); + // remove it + newChildParent.removeChild(newChild); } - + // insert newChild into childNodes - __insertBefore__(this.childNodes, newChild, - __findItemIndex__(this.childNodes, refChild._id)); - + __insertBefore__(this.childNodes, newChild, itemIndex); + // do node pointer surgery prevNode = refChild.previousSibling; - + // handle DocumentFragment - if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) { - if (newChild.childNodes.length > 0) { - // set the parentNode of DocumentFragment's children - for (var ind = 0; ind < newChild.childNodes.length; ind++) { - newChild.childNodes[ind].parentNode = this; + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + if (newChild.childNodes.length > 0) { + // set the parentNode of DocumentFragment's children + for (var ind = 0; ind < newChild.childNodes.length; ind++) { + newChild.childNodes[ind].parentNode = this; + } + + // link refChild to last child of DocumentFragment + refChild.previousSibling = newChild.childNodes[newChild.childNodes.length-1]; } - - // link refChild to last child of DocumentFragment - refChild.previousSibling = newChild.childNodes[newChild.childNodes.length-1]; - } }else { - newChild.parentNode = this; // set the parentNode of the newChild - refChild.previousSibling = newChild; // link refChild to newChild + // set the parentNode of the newChild + newChild.parentNode = this; + // link refChild to newChild + refChild.previousSibling = newChild; } - }else { // otherwise, append to end + + }else { + // otherwise, append to end prevNode = this.lastChild; this.appendChild(newChild); } - - if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) { + + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { // do node pointer surgery for DocumentFragment if (newChild.childNodes.length > 0) { - if (prevNode) { + if (prevNode) { prevNode.nextSibling = newChild.childNodes[0]; - }else { // this is the first child in the list + }else { + // this is the first child in the list this.firstChild = newChild.childNodes[0]; } - newChild.childNodes[0].previousSibling = prevNode; newChild.childNodes[newChild.childNodes.length-1].nextSibling = refChild; } }else { // do node pointer surgery for newChild if (prevNode) { - prevNode.nextSibling = newChild; - }else { // this is the first child in the list - this.firstChild = newChild; + prevNode.nextSibling = newChild; + }else { + // this is the first child in the list + this.firstChild = newChild; } - newChild.previousSibling = prevNode; newChild.nextSibling = refChild; } - + return newChild; }, replaceChild : function(newChild, oldChild) { var ret = null; - + if(newChild==null || oldChild==null){ return oldChild; } - + // test for exceptions if (__ownerDocument__(this).implementation.errorChecking) { - // throw Exception if DOMNode is readonly + // throw Exception if Node is readonly if (this._readonly) { throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } - + // throw Exception if newChild was not created by this Document if (__ownerDocument__(this) != __ownerDocument__(newChild)) { throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); } - + // throw Exception if the node is an ancestor if (__isAncestor__(this, newChild)) { throw(new DOMException(DOMException.HIERARCHY_REQUEST_ERR)); } } - + // get index of oldChild - var index = __findItemIndex__(this.childNodes, oldChild._id); - + var index = __findItemIndex__(this.childNodes, oldChild); + // throw Exception if there is no child node with this id if (__ownerDocument__(this).implementation.errorChecking && (index < 0)) { throw(new DOMException(DOMException.NOT_FOUND_ERR)); } - + // if the newChild is already in the tree, var newChildParent = newChild.parentNode; if (newChildParent) { // remove it newChildParent.removeChild(newChild); } - + // add newChild to childNodes ret = __replaceChild__(this.childNodes,newChild, index); - - - if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) { + + + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { // do node pointer surgery for Document Fragment if (newChild.childNodes.length > 0) { for (var ind = 0; ind < newChild.childNodes.length; ind++) { newChild.childNodes[ind].parentNode = this; } - + if (oldChild.previousSibling) { oldChild.previousSibling.nextSibling = newChild.childNodes[0]; } else { this.firstChild = newChild.childNodes[0]; } - + if (oldChild.nextSibling) { oldChild.nextSibling.previousSibling = newChild; } else { this.lastChild = newChild.childNodes[newChild.childNodes.length-1]; } - + newChild.childNodes[0].previousSibling = oldChild.previousSibling; newChild.childNodes[newChild.childNodes.length-1].nextSibling = oldChild.nextSibling; } } else { // do node pointer surgery for newChild newChild.parentNode = this; - + if (oldChild.previousSibling) { oldChild.previousSibling.nextSibling = newChild; }else{ @@ -1037,31 +2102,33 @@ __extend__(DOMNode.prototype, { newChild.previousSibling = oldChild.previousSibling; newChild.nextSibling = oldChild.nextSibling; } + return ret; }, removeChild : function(oldChild) { if(!oldChild){ return null; } - // throw Exception if DOMNamedNodeMap is readonly - if (__ownerDocument__(this).implementation.errorChecking && (this._readonly || oldChild._readonly)) { + // throw Exception if NamedNodeMap is readonly + if (__ownerDocument__(this).implementation.errorChecking && + (this._readonly || oldChild._readonly)) { throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } - + // get index of oldChild - var itemIndex = __findItemIndex__(this.childNodes, oldChild._id); - + var itemIndex = __findItemIndex__(this.childNodes, oldChild); + // throw Exception if there is no child node with this id if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { throw(new DOMException(DOMException.NOT_FOUND_ERR)); } - + // remove oldChild from childNodes __removeChild__(this.childNodes, itemIndex); - + // do node pointer surgery oldChild.parentNode = null; - + if (oldChild.previousSibling) { oldChild.previousSibling.nextSibling = oldChild.nextSibling; }else { @@ -1072,77 +2139,74 @@ __extend__(DOMNode.prototype, { }else { this.lastChild = oldChild.previousSibling; } - + oldChild.previousSibling = null; oldChild.nextSibling = null; - + return oldChild; }, appendChild : function(newChild) { if(!newChild){ return null; } - // test for exceptions - if (__ownerDocument__(this).implementation.errorChecking) { - // throw Exception if Node is readonly - if (this._readonly) { - throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + // test for exceptions + if (__ownerDocument__(this).implementation.errorChecking) { + // throw Exception if Node is readonly + if (this._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // throw Exception if arg was not created by this Document + if (__ownerDocument__(this) != __ownerDocument__(this)) { + throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); + } + + // throw Exception if the node is an ancestor + if (__isAncestor__(this, newChild)) { + throw(new DOMException(DOMException.HIERARCHY_REQUEST_ERR)); + } } - - // throw Exception if arg was not created by this Document - if (__ownerDocument__(this) != __ownerDocument__(this)) { - throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); + + // if the newChild is already in the tree, + var newChildParent = newChild.parentNode; + if (newChildParent) { + // remove it + //console.debug('removing node %s', newChild); + newChildParent.removeChild(newChild); } - - // throw Exception if the node is an ancestor - if (__isAncestor__(this, newChild)) { - throw(new DOMException(DOMException.HIERARCHY_REQUEST_ERR)); - } - } - - // if the newChild is already in the tree, - var newChildParent = newChild.parentNode; - if (newChildParent) { - // remove it - newChildParent.removeChild(newChild); - } - - // add newChild to childNodes - __appendChild__(this.childNodes, newChild); - - if (newChild.nodeType == DOMNode.DOCUMENT_FRAGMENT_NODE) { - // do node pointer surgery for DocumentFragment - if (newChild.childNodes.length > 0) { - for (var ind = 0; ind < newChild.childNodes.length; ind++) { - newChild.childNodes[ind].parentNode = this; - } - - if (this.lastChild) { - this.lastChild.nextSibling = newChild.childNodes[0]; - newChild.childNodes[0].previousSibling = this.lastChild; - this.lastChild = newChild.childNodes[newChild.childNodes.length-1]; - } - else { - this.lastChild = newChild.childNodes[newChild.childNodes.length-1]; - this.firstChild = newChild.childNodes[0]; - } - } - } - else { - // do node pointer surgery for newChild - newChild.parentNode = this; - if (this.lastChild) { - this.lastChild.nextSibling = newChild; - newChild.previousSibling = this.lastChild; - this.lastChild = newChild; - } - else { - this.lastChild = newChild; - this.firstChild = newChild; - } - } - - return newChild; + + // add newChild to childNodes + __appendChild__(this.childNodes, newChild); + + if (newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // do node pointer surgery for DocumentFragment + if (newChild.childNodes.length > 0) { + for (var ind = 0; ind < newChild.childNodes.length; ind++) { + newChild.childNodes[ind].parentNode = this; + } + + if (this.lastChild) { + this.lastChild.nextSibling = newChild.childNodes[0]; + newChild.childNodes[0].previousSibling = this.lastChild; + this.lastChild = newChild.childNodes[newChild.childNodes.length-1]; + } else { + this.lastChild = newChild.childNodes[newChild.childNodes.length-1]; + this.firstChild = newChild.childNodes[0]; + } + } + } else { + // do node pointer surgery for newChild + newChild.parentNode = this; + if (this.lastChild) { + this.lastChild.nextSibling = newChild; + newChild.previousSibling = this.lastChild; + this.lastChild = newChild; + } else { + this.lastChild = newChild; + this.firstChild = newChild; + } + } + return newChild; }, hasChildNodes : function() { return (this.childNodes.length > 0); @@ -1154,264 +2218,800 @@ __extend__(DOMNode.prototype, { return __ownerDocument__(this).importNode(this, deep); } catch (e) { //there shouldn't be any exceptions, but if there are, return null + // may want to warn: $debug("could not clone node: "+e.code); return null; } }, normalize : function() { + var i; var inode; - var nodesToRemove = new DOMNodeList(); - - if (this.nodeType == DOMNode.ELEMENT_NODE || this.nodeType == DOMNode.DOCUMENT_NODE) { + var nodesToRemove = new NodeList(); + + if (this.nodeType == Node.ELEMENT_NODE || this.nodeType == Node.DOCUMENT_NODE) { var adjacentTextNode = null; - + // loop through all childNodes - for(var i = 0; i < this.childNodes.length; i++) { + for(i = 0; i < this.childNodes.length; i++) { inode = this.childNodes.item(i); - - if (inode.nodeType == DOMNode.TEXT_NODE) { // this node is a text node - if (inode.length < 1) { // this text node is empty - __appendChild__(nodesToRemove, inode); // add this node to the list of nodes to be remove + + if (inode.nodeType == Node.TEXT_NODE) { + // this node is a text node + if (inode.length < 1) { + // this text node is empty + // add this node to the list of nodes to be remove + __appendChild__(nodesToRemove, inode); }else { - if (adjacentTextNode) { // if previous node was also text - adjacentTextNode.appendData(inode.data); // merge the data in adjacent text nodes - __appendChild__(nodesToRemove, inode); // add this node to the list of nodes to be removed - }else { - adjacentTextNode = inode; // remember this node for next cycle + if (adjacentTextNode) { + // previous node was also text + adjacentTextNode.appendData(inode.data); + // merge the data in adjacent text nodes + // add this node to the list of nodes to be removed + __appendChild__(nodesToRemove, inode); + } else { + // remember this node for next cycle + adjacentTextNode = inode; } } } else { - adjacentTextNode = null; // (soon to be) previous node is not a text node - inode.normalize(); // normalise non Text childNodes + // (soon to be) previous node is not a text node + adjacentTextNode = null; + // normalize non Text childNodes + inode.normalize(); } } - + // remove redundant Text Nodes - for(var i = 0; i < nodesToRemove.length; i++) { + for(i = 0; i < nodesToRemove.length; i++) { inode = nodesToRemove.item(i); inode.parentNode.removeChild(inode); } } }, isSupported : function(feature, version) { - // use Implementation.hasFeature to determin if this feature is supported + // use Implementation.hasFeature to determine if this feature is supported return __ownerDocument__(this).implementation.hasFeature(feature, version); }, getElementsByTagName : function(tagname) { // delegate to _getElementsByTagNameRecursive // recurse childNodes - var nodelist = new DOMNodeList(__ownerDocument__(this)); - for(var i = 0; i < this.childNodes.length; i++) { - nodeList = __getElementsByTagNameRecursive__(this.childNodes.item(i), tagname, nodelist); + var nodelist = new NodeList(__ownerDocument__(this)); + for (var i = 0; i < this.childNodes.length; i++) { + __getElementsByTagNameRecursive__(this.childNodes.item(i), + tagname, + nodelist); } return nodelist; }, getElementsByTagNameNS : function(namespaceURI, localName) { // delegate to _getElementsByTagNameNSRecursive - return __getElementsByTagNameNSRecursive__(this, namespaceURI, localName, - new DOMNodeList(__ownerDocument__(this))); + return __getElementsByTagNameNSRecursive__(this, namespaceURI, localName, + new NodeList(__ownerDocument__(this))); }, importNode : function(importedNode, deep) { - + var i; var importNode; - //$debug("importing node " + importedNode.nodeName + "(?deep = "+deep+")"); + //there is no need to perform namespace checks since everything has already gone through them //in order to have gotten into the DOM in the first place. The following line //turns namespace checking off in ._isValidNamespace - __ownerDocument__(this)._performingImportNodeOperation = true; - - if (importedNode.nodeType == DOMNode.ELEMENT_NODE) { - if (!__ownerDocument__(this).implementation.namespaceAware) { - // create a local Element (with the name of the importedNode) - importNode = __ownerDocument__(this).createElement(importedNode.tagName); - - // create attributes matching those of the importedNode - for(var i = 0; i < importedNode.attributes.length; i++) { - importNode.setAttribute(importedNode.attributes.item(i).name, importedNode.attributes.item(i).value); - } - }else { - // create a local Element (with the name & namespaceURI of the importedNode) - importNode = __ownerDocument__(this).createElementNS(importedNode.namespaceURI, importedNode.nodeName); - - // create attributes matching those of the importedNode - for(var i = 0; i < importedNode.attributes.length; i++) { - importNode.setAttributeNS(importedNode.attributes.item(i).namespaceURI, - importedNode.attributes.item(i).name, importedNode.attributes.item(i).value); - } - - // create namespace definitions matching those of the importedNode - for(var i = 0; i < importedNode._namespaces.length; i++) { - importNode._namespaces[i] = __ownerDocument__(this).createNamespace(importedNode._namespaces.item(i).localName); - importNode._namespaces[i].value = importedNode._namespaces.item(i).value; - } + __ownerDocument__(this).importing = true; + + if (importedNode.nodeType == Node.ELEMENT_NODE) { + if (!__ownerDocument__(this).implementation.namespaceAware) { + // create a local Element (with the name of the importedNode) + importNode = __ownerDocument__(this).createElement(importedNode.tagName); + + // create attributes matching those of the importedNode + for(i = 0; i < importedNode.attributes.length; i++) { + importNode.setAttribute(importedNode.attributes.item(i).name, importedNode.attributes.item(i).value); } - } else if (importedNode.nodeType == DOMNode.ATTRIBUTE_NODE) { - if (!__ownerDocument__(this).implementation.namespaceAware) { - // create a local Attribute (with the name of the importedAttribute) - importNode = __ownerDocument__(this).createAttribute(importedNode.name); - } else { - // create a local Attribute (with the name & namespaceURI of the importedAttribute) - importNode = __ownerDocument__(this).createAttributeNS(importedNode.namespaceURI, importedNode.nodeName); - - // create namespace definitions matching those of the importedAttribute - for(var i = 0; i < importedNode._namespaces.length; i++) { - importNode._namespaces[i] = __ownerDocument__(this).createNamespace(importedNode._namespaces.item(i).localName); - importNode._namespaces[i].value = importedNode._namespaces.item(i).value; - } + } else { + // create a local Element (with the name & namespaceURI of the importedNode) + importNode = __ownerDocument__(this).createElementNS(importedNode.namespaceURI, importedNode.nodeName); + + // create attributes matching those of the importedNode + for(i = 0; i < importedNode.attributes.length; i++) { + importNode.setAttributeNS(importedNode.attributes.item(i).namespaceURI, + importedNode.attributes.item(i).name, importedNode.attributes.item(i).value); } - - // set the value of the local Attribute to match that of the importedAttribute - importNode.value = importedNode.value; - - } else if (importedNode.nodeType == DOMNode.DOCUMENT_FRAGMENT) { - // create a local DocumentFragment - importNode = __ownerDocument__(this).createDocumentFragment(); - } else if (importedNode.nodeType == DOMNode.NAMESPACE_NODE) { - // create a local NamespaceNode (with the same name & value as the importedNode) - importNode = __ownerDocument__(this).createNamespace(importedNode.nodeName); - importNode.value = importedNode.value; - } else if (importedNode.nodeType == DOMNode.TEXT_NODE) { - // create a local TextNode (with the same data as the importedNode) - importNode = __ownerDocument__(this).createTextNode(importedNode.data); - } else if (importedNode.nodeType == DOMNode.CDATA_SECTION_NODE) { - // create a local CDATANode (with the same data as the importedNode) - importNode = __ownerDocument__(this).createCDATASection(importedNode.data); - } else if (importedNode.nodeType == DOMNode.PROCESSING_INSTRUCTION_NODE) { - // create a local ProcessingInstruction (with the same target & data as the importedNode) - importNode = __ownerDocument__(this).createProcessingInstruction(importedNode.target, importedNode.data); - } else if (importedNode.nodeType == DOMNode.COMMENT_NODE) { - // create a local Comment (with the same data as the importedNode) - importNode = __ownerDocument__(this).createComment(importedNode.data); - } else { // throw Exception if nodeType is not supported - throw(new DOMException(DOMException.NOT_SUPPORTED_ERR)); - } - - if (deep) { // recurse childNodes - for(var i = 0; i < importedNode.childNodes.length; i++) { - importNode.appendChild(__ownerDocument__(this).importNode(importedNode.childNodes.item(i), true)); + + // create namespace definitions matching those of the importedNode + for(i = 0; i < importedNode._namespaces.length; i++) { + importNode._namespaces[i] = __ownerDocument__(this).createNamespace(importedNode._namespaces.item(i).localName); + importNode._namespaces[i].value = importedNode._namespaces.item(i).value; } } - - //reset _performingImportNodeOperation - __ownerDocument__(this)._performingImportNodeOperation = false; - return importNode; - + } else if (importedNode.nodeType == Node.ATTRIBUTE_NODE) { + if (!__ownerDocument__(this).implementation.namespaceAware) { + // create a local Attribute (with the name of the importedAttribute) + importNode = __ownerDocument__(this).createAttribute(importedNode.name); + } else { + // create a local Attribute (with the name & namespaceURI of the importedAttribute) + importNode = __ownerDocument__(this).createAttributeNS(importedNode.namespaceURI, importedNode.nodeName); + + // create namespace definitions matching those of the importedAttribute + for(i = 0; i < importedNode._namespaces.length; i++) { + importNode._namespaces[i] = __ownerDocument__(this).createNamespace(importedNode._namespaces.item(i).localName); + importNode._namespaces[i].value = importedNode._namespaces.item(i).value; + } + } + + // set the value of the local Attribute to match that of the importedAttribute + importNode.value = importedNode.value; + + } else if (importedNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + // create a local DocumentFragment + importNode = __ownerDocument__(this).createDocumentFragment(); + } else if (importedNode.nodeType == Node.NAMESPACE_NODE) { + // create a local NamespaceNode (with the same name & value as the importedNode) + importNode = __ownerDocument__(this).createNamespace(importedNode.nodeName); + importNode.value = importedNode.value; + } else if (importedNode.nodeType == Node.TEXT_NODE) { + // create a local TextNode (with the same data as the importedNode) + importNode = __ownerDocument__(this).createTextNode(importedNode.data); + } else if (importedNode.nodeType == Node.CDATA_SECTION_NODE) { + // create a local CDATANode (with the same data as the importedNode) + importNode = __ownerDocument__(this).createCDATASection(importedNode.data); + } else if (importedNode.nodeType == Node.PROCESSING_INSTRUCTION_NODE) { + // create a local ProcessingInstruction (with the same target & data as the importedNode) + importNode = __ownerDocument__(this).createProcessingInstruction(importedNode.target, importedNode.data); + } else if (importedNode.nodeType == Node.COMMENT_NODE) { + // create a local Comment (with the same data as the importedNode) + importNode = __ownerDocument__(this).createComment(importedNode.data); + } else { // throw Exception if nodeType is not supported + throw(new DOMException(DOMException.NOT_SUPPORTED_ERR)); + } + + if (deep) { + // recurse childNodes + for(i = 0; i < importedNode.childNodes.length; i++) { + importNode.appendChild(__ownerDocument__(this).importNode(importedNode.childNodes.item(i), true)); + } + } + + //reset importing + __ownerDocument__(this).importing = false; + return importNode; + }, contains : function(node){ - while(node && node != this ){ - node = node.parentNode; - } - return !!node; + while(node && node != this ){ + node = node.parentNode; + } + return !!node; }, compareDocumentPosition : function(b){ - var a = this; - var number = (a != b && a.contains(b) && 16) + (a != b && b.contains(a) && 8); - //find position of both - var all = document.getElementsByTagName("*"); - var my_location = 0, node_location = 0; - for(var i=0; i < all.length; i++){ - if(all[i] == a) my_location = i; - if(all[i] == b) node_location = i; - if(my_location && node_location) break; + //console.log("comparing document position %s %s", this, b); + var i, + length, + a = this, + parent, + aparents, + bparents; + //handle a couple simpler case first + if(a === b) { + return Node.DOCUMENT_POSITION_EQUAL; } - number += (my_location < node_location && 4) - number += (my_location > node_location && 2) - return number; - } + if(a.ownerDocument !== b.ownerDocument) { + return Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC| + Node.DOCUMENT_POSITION_FOLLOWING| + Node.DOCUMENT_POSITION_DISCONNECTED; + } + if(a.parentNode === b.parentNode){ + length = a.parentNode.childNodes.length; + for(i=0;i aparents.length){ + return Node.DOCUMENT_POSITION_FOLLOWING; + }else if(bparents.length < aparents.length){ + return Node.DOCUMENT_POSITION_PRECEDING; + }else{ + //common ancestor diverge point + if (i === 0) { + return Node.DOCUMENT_POSITION_FOLLOWING; + } else { + parent = aparents[i-1]; + } + return parent.compareDocumentPosition(bparents.pop()); + } + } + } + + return Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC| + Node.DOCUMENT_POSITION_DISCONNECTED; + + }, + toString : function() { + return '[object Node]'; + } }); + + /** - * @method DOMNode._getElementsByTagNameRecursive - implements getElementsByTagName() - * @param elem : DOMElement - The element which are checking and then recursing into + * @method __getElementsByTagNameRecursive__ - implements getElementsByTagName() + * @param elem : Element - The element which are checking and then recursing into * @param tagname : string - The name of the tag to match on. The special value "*" matches all tags - * @param nodeList : DOMNodeList - The accumulating list of matching nodes + * @param nodeList : NodeList - The accumulating list of matching nodes * - * @return : DOMNodeList + * @return : NodeList */ var __getElementsByTagNameRecursive__ = function (elem, tagname, nodeList) { - - if (elem.nodeType == DOMNode.ELEMENT_NODE || elem.nodeType == DOMNode.DOCUMENT_NODE) { - - if(elem.nodeType !== DOMNode.DOCUMENT_NODE && - ((elem.nodeName.toUpperCase() == tagname.toUpperCase()) || + + if (elem.nodeType == Node.ELEMENT_NODE || elem.nodeType == Node.DOCUMENT_NODE) { + + if(elem.nodeType !== Node.DOCUMENT_NODE && + ((elem.nodeName.toUpperCase() == tagname.toUpperCase()) || (tagname == "*")) ){ - __appendChild__(nodeList, elem); // add matching node to nodeList + // add matching node to nodeList + __appendChild__(nodeList, elem); } - + // recurse childNodes for(var i = 0; i < elem.childNodes.length; i++) { nodeList = __getElementsByTagNameRecursive__(elem.childNodes.item(i), tagname, nodeList); } } - + return nodeList; }; /** - * @method DOMNode._getElementsByTagNameNSRecursive - implements getElementsByTagName() + * @method __getElementsByTagNameNSRecursive__ + * implements getElementsByTagName() * - * @param elem : DOMElement - The element which are checking and then recursing into + * @param elem : Element - The element which are checking and then recursing into * @param namespaceURI : string - the namespace URI of the required node * @param localName : string - the local name of the required node - * @param nodeList : DOMNodeList - The accumulating list of matching nodes + * @param nodeList : NodeList - The accumulating list of matching nodes * - * @return : DOMNodeList + * @return : NodeList */ var __getElementsByTagNameNSRecursive__ = function(elem, namespaceURI, localName, nodeList) { - if (elem.nodeType == DOMNode.ELEMENT_NODE || elem.nodeType == DOMNode.DOCUMENT_NODE) { + if (elem.nodeType == Node.ELEMENT_NODE || elem.nodeType == Node.DOCUMENT_NODE) { - if (((elem.namespaceURI == namespaceURI) || (namespaceURI == "*")) && ((elem.localName == localName) || (localName == "*"))) { - __appendChild__(nodeList, elem); // add matching node to nodeList + if (((elem.namespaceURI == namespaceURI) || (namespaceURI == "*")) && + ((elem.localName == localName) || (localName == "*"))) { + // add matching node to nodeList + __appendChild__(nodeList, elem); + } + + // recurse childNodes + for(var i = 0; i < elem.childNodes.length; i++) { + nodeList = __getElementsByTagNameNSRecursive__( + elem.childNodes.item(i), namespaceURI, localName, nodeList); + } } - // recurse childNodes - for(var i = 0; i < elem.childNodes.length; i++) { - nodeList = __getElementsByTagNameNSRecursive__(elem.childNodes.item(i), namespaceURI, localName, nodeList); - } - } - - return nodeList; + return nodeList; }; /** - * @method DOMNode._isAncestor - returns true if node is ancestor of target - * @param target : DOMNode - The node we are using as context - * @param node : DOMNode - The candidate ancestor node + * @method __isAncestor__ - returns true if node is ancestor of target + * @param target : Node - The node we are using as context + * @param node : Node - The candidate ancestor node * @return : boolean */ var __isAncestor__ = function(target, node) { - // if this node matches, return true, - // otherwise recurse up (if there is a parentNode) - return ((target == node) || ((target.parentNode) && (__isAncestor__(target.parentNode, node)))); + // if this node matches, return true, + // otherwise recurse up (if there is a parentNode) + return ((target == node) || ((target.parentNode) && (__isAncestor__(target.parentNode, node)))); }; -var __ownerDocument__ = function(node){ - return (node.nodeType == DOMNode.DOCUMENT_NODE)?node:node.ownerDocument; -}; -$w.Node = DOMNode; + +var __recursivelyGatherText__ = function(aNode) { + var accumulateText = "", + idx, + node; + for (idx=0;idx < aNode.childNodes.length;idx++){ + node = aNode.childNodes.item(idx); + if(node.nodeType == Node.TEXT_NODE) + accumulateText += node.data; + else + accumulateText += __recursivelyGatherText__(node); + } + return accumulateText; +}; /** - * @class DOMNamespace - The Namespace interface represents an namespace in an Element object - * - * @extends DOMNode - * @author Jon van Noort (jon@webarcana.com.au) - * @param ownerDocument : DOMDocument - The Document object associated with this node. + * function __escapeXML__ + * @param str : string - The string to be escaped + * @return : string - The escaped string */ -var DOMNamespace = function(ownerDocument) { - this.DOMNode = DOMNode; - this.DOMNode(ownerDocument); +var escAmpRegEx = /&(?!(amp;|lt;|gt;|quot|apos;))/g; +var escLtRegEx = //g; +var quotRegEx = /"/g; +var aposRegEx = /'/g; - this.name = ""; // the name of this attribute +function __escapeXML__(str) { + str = str.replace(escAmpRegEx, "&"). + replace(escLtRegEx, "<"). + replace(escGtRegEx, ">"). + replace(quotRegEx, """). + replace(aposRegEx, "'"); - // If this attribute was explicitly given a value in the original document, this is true; otherwise, it is false. - // Note that the implementation is in charge of this attribute, not the user. - // If the user changes the value of the attribute (even if it ends up having the same value as the default value) - // then the specified flag is automatically flipped to true - this.specified = false; + return str; }; -DOMNamespace.prototype = new DOMNode; -__extend__(DOMNamespace.prototype, { + +/* +function __escapeHTML5__(str) { + str = str.replace(escAmpRegEx, "&"). + replace(escLtRegEx, "<"). + replace(escGtRegEx, ">"); + + return str; +}; +function __escapeHTML5Atribute__(str) { + str = str.replace(escAmpRegEx, "&"). + replace(escLtRegEx, "<"). + replace(escGtRegEx, ">"). + replace(quotRegEx, """). + replace(aposRegEx, "'"); + + return str; +}; +*/ + +/** + * function __unescapeXML__ + * @param str : string - The string to be unescaped + * @return : string - The unescaped string + */ +var unescAmpRegEx = /&/g; +var unescLtRegEx = /</g; +var unescGtRegEx = />/g; +var unquotRegEx = /"/g; +var unaposRegEx = /'/g; +function __unescapeXML__(str) { + str = str.replace(unescAmpRegEx, "&"). + replace(unescLtRegEx, "<"). + replace(unescGtRegEx, ">"). + replace(unquotRegEx, "\""). + replace(unaposRegEx, "'"); + + return str; +}; + +/** + * @class NamedNodeMap - + * used to represent collections of nodes that can be accessed by name + * typically a set of Element attributes + * + * @extends NodeList - + * note W3C spec says that this is not the case, but we need an item() + * method identical to NodeList's, so why not? + * @param ownerDocument : Document - the ownerDocument + * @param parentNode : Node - the node that the NamedNodeMap is attached to (or null) + */ +NamedNodeMap = function(ownerDocument, parentNode) { + NodeList.apply(this, arguments); + __setArray__(this, []); +}; +NamedNodeMap.prototype = new NodeList(); +__extend__(NamedNodeMap.prototype, { + add: function(name){ + this[this.length] = name; + }, + getNamedItem : function(name) { + var ret = null; + //console.log('NamedNodeMap getNamedItem %s', name); + // test that Named Node exists + var itemIndex = __findNamedItemIndex__(this, name); + + if (itemIndex > -1) { + // found it! + ret = this[itemIndex]; + } + // if node is not found, default value null is returned + return ret; + }, + setNamedItem : function(arg) { + //console.log('setNamedItem %s', arg); + // test for exceptions + if (__ownerDocument__(this).implementation.errorChecking) { + // throw Exception if arg was not created by this Document + if (this.ownerDocument != arg.ownerDocument) { + throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); + } + + // throw Exception if DOMNamedNodeMap is readonly + if (this._readonly || (this.parentNode && this.parentNode._readonly)) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // throw Exception if arg is already an attribute of another Element object + if (arg.ownerElement && (arg.ownerElement != this.parentNode)) { + throw(new DOMException(DOMException.INUSE_ATTRIBUTE_ERR)); + } + } + + //console.log('setNamedItem __findNamedItemIndex__ '); + // get item index + var itemIndex = __findNamedItemIndex__(this, arg.name); + var ret = null; + + //console.log('setNamedItem __findNamedItemIndex__ %s', itemIndex); + if (itemIndex > -1) { // found it! + ret = this[itemIndex]; // use existing Attribute + + // throw Exception if DOMAttr is readonly + if (__ownerDocument__(this).implementation.errorChecking && ret._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } else { + this[itemIndex] = arg; // over-write existing NamedNode + this[arg.name.toLowerCase()] = arg; + } + } else { + // add new NamedNode + //console.log('setNamedItem add new named node map (by index)'); + Array.prototype.push.apply(this, [arg]); + //console.log('setNamedItem add new named node map (by name) %s %s', arg, arg.name); + this[arg.name] = arg; + //console.log('finsished setNamedItem add new named node map (by name) %s', arg.name); + + } + + //console.log('setNamedItem parentNode'); + arg.ownerElement = this.parentNode; // update ownerElement + // return old node or new node + //console.log('setNamedItem exit'); + return ret; + }, + removeNamedItem : function(name) { + var ret = null; + // test for exceptions + // throw Exception if NamedNodeMap is readonly + if (__ownerDocument__(this).implementation.errorChecking && + (this._readonly || (this.parentNode && this.parentNode._readonly))) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // get item index + var itemIndex = __findNamedItemIndex__(this, name); + + // throw Exception if there is no node named name in this map + if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { + throw(new DOMException(DOMException.NOT_FOUND_ERR)); + } + + // get Node + var oldNode = this[itemIndex]; + //this[oldNode.name] = undefined; + + // throw Exception if Node is readonly + if (__ownerDocument__(this).implementation.errorChecking && oldNode._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // return removed node + return __removeChild__(this, itemIndex); + }, + getNamedItemNS : function(namespaceURI, localName) { + var ret = null; + + // test that Named Node exists + var itemIndex = __findNamedItemNSIndex__(this, namespaceURI, localName); + + if (itemIndex > -1) { + // found it! return NamedNode + ret = this[itemIndex]; + } + // if node is not found, default value null is returned + return ret; + }, + setNamedItemNS : function(arg) { + //console.log('setNamedItemNS %s', arg); + // test for exceptions + if (__ownerDocument__(this).implementation.errorChecking) { + // throw Exception if NamedNodeMap is readonly + if (this._readonly || (this.parentNode && this.parentNode._readonly)) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // throw Exception if arg was not created by this Document + if (__ownerDocument__(this) != __ownerDocument__(arg)) { + throw(new DOMException(DOMException.WRONG_DOCUMENT_ERR)); + } + + // throw Exception if arg is already an attribute of another Element object + if (arg.ownerElement && (arg.ownerElement != this.parentNode)) { + throw(new DOMException(DOMException.INUSE_ATTRIBUTE_ERR)); + } + } + + // get item index + var itemIndex = __findNamedItemNSIndex__(this, arg.namespaceURI, arg.localName); + var ret = null; + + if (itemIndex > -1) { + // found it! + // use existing Attribute + ret = this[itemIndex]; + // throw Exception if Attr is readonly + if (__ownerDocument__(this).implementation.errorChecking && ret._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } else { + // over-write existing NamedNode + this[itemIndex] = arg; + } + }else { + // add new NamedNode + Array.prototype.push.apply(this, [arg]); + } + arg.ownerElement = this.parentNode; + + // return old node or null + return ret; + //console.log('finished setNamedItemNS %s', arg); + }, + removeNamedItemNS : function(namespaceURI, localName) { + var ret = null; + + // test for exceptions + // throw Exception if NamedNodeMap is readonly + if (__ownerDocument__(this).implementation.errorChecking && (this._readonly || (this.parentNode && this.parentNode._readonly))) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + // get item index + var itemIndex = __findNamedItemNSIndex__(this, namespaceURI, localName); + + // throw Exception if there is no matching node in this map + if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { + throw(new DOMException(DOMException.NOT_FOUND_ERR)); + } + + // get Node + var oldNode = this[itemIndex]; + + // throw Exception if Node is readonly + if (__ownerDocument__(this).implementation.errorChecking && oldNode._readonly) { + throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); + } + + return __removeChild__(this, itemIndex); // return removed node + }, + get xml() { + var ret = ""; + + // create string containing concatenation of all (but last) Attribute string values (separated by spaces) + for (var i=0; i < this.length -1; i++) { + ret += this[i].xml +" "; + } + + // add last Attribute to string (without trailing space) + if (this.length > 0) { + ret += this[this.length -1].xml; + } + + return ret; + }, + toString : function(){ + return "[object NamedNodeMap]"; + } + +}); + +/** + * @method __findNamedItemIndex__ + * find the item index of the node with the specified name + * + * @param name : string - the name of the required node + * @param isnsmap : if its a NamespaceNodeMap + * @return : int + */ +var __findNamedItemIndex__ = function(namednodemap, name, isnsmap) { + var ret = -1; + // loop through all nodes + for (var i=0; i -1) { + // found it! + ret = true; + } + // if node is not found, default value false is returned + return ret; +} + +/** + * @method __hasAttributeNS__ + * Returns true if specified node exists + * + * @param namespaceURI : string - the namespace URI of the required node + * @param localName : string - the local name of the required node + * @return : boolean + */ +var __hasAttributeNS__ = function(namednodemap, namespaceURI, localName) { + var ret = false; + // test that Named Node exists + var itemIndex = __findNamedItemNSIndex__(namednodemap, namespaceURI, localName); + if (itemIndex > -1) { + // found it! + ret = true; + } + // if node is not found, default value false is returned + return ret; +} + +/** + * @method __cloneNamedNodes__ + * Returns a NamedNodeMap containing clones of the Nodes in this NamedNodeMap + * + * @param parentNode : Node - the new parent of the cloned NodeList + * @param isnsmap : bool - is this a NamespaceNodeMap + * @return NamedNodeMap containing clones of the Nodes in this NamedNodeMap + */ +var __cloneNamedNodes__ = function(namednodemap, parentNode, isnsmap) { + var cloneNamedNodeMap = isnsmap? + new NamespaceNodeMap(namednodemap.ownerDocument, parentNode): + new NamedNodeMap(namednodemap.ownerDocument, parentNode); + + // create list containing clones of all children + for (var i=0; i < namednodemap.length; i++) { + __appendChild__(cloneNamedNodeMap, namednodemap[i].cloneNode(false)); + } + + return cloneNamedNodeMap; +}; + + +/** + * @class NamespaceNodeMap - + * used to represent collections of namespace nodes that can be + * accessed by name typically a set of Element attributes + * + * @extends NamedNodeMap + * + * @param ownerDocument : Document - the ownerDocument + * @param parentNode : Node - the node that the NamespaceNodeMap is attached to (or null) + */ +var NamespaceNodeMap = function(ownerDocument, parentNode) { + this.NamedNodeMap = NamedNodeMap; + this.NamedNodeMap(ownerDocument, parentNode); + __setArray__(this, []); +}; +NamespaceNodeMap.prototype = new NamedNodeMap(); +__extend__(NamespaceNodeMap.prototype, { + get xml() { + var ret = "", + ns, + ind; + // identify namespaces declared local to this Element (ie, not inherited) + for (ind = 0; ind < this.length; ind++) { + // if namespace declaration does not exist in the containing node's, parentNode's namespaces + ns = null; + try { + var ns = this.parentNode.parentNode._namespaces. + getNamedItem(this[ind].localName); + }catch (e) { + //breaking to prevent default namespace being inserted into return value + break; + } + if (!(ns && (""+ ns.nodeValue == ""+ this[ind].nodeValue))) { + // display the namespace declaration + ret += this[ind].xml +" "; + } + } + return ret; + } +}); + +/** + * @class Namespace - + * The Namespace interface represents an namespace in an Element object + * + * @param ownerDocument : The Document object associated with this node. + */ +Namespace = function(ownerDocument) { + Node.apply(this, arguments); + // the name of this attribute + this.name = ""; + + // If this attribute was explicitly given a value in the original document, + // this is true; otherwise, it is false. + // Note that the implementation is in charge of this attribute, not the user. + // If the user changes the value of the attribute (even if it ends up having + // the same value as the default value) then the specified flag is + // automatically flipped to true + this.specified = false; +}; +Namespace.prototype = new Node(); +__extend__(Namespace.prototype, { get value(){ // the value of the attribute is returned as a string return this.nodeValue; @@ -1420,7 +3020,7 @@ __extend__(DOMNamespace.prototype, { this.nodeValue = value+''; }, get nodeType(){ - return DOMNode.NAMESPACE_NODE; + return Node.NAMESPACE_NODE; }, get xml(){ var ret = ""; @@ -1432,57 +3032,58 @@ __extend__(DOMNamespace.prototype, { else { // handle default namespace ret += "xmlns=\""+ __escapeXML__(this.nodeValue) +"\""; } - + return ret; }, toString: function(){ - return "Namespace #" + this.id; + return '[object Namespace]'; } }); -$debug("Defining CharacterData"); -/* -* CharacterData - DOM Level 2 -*/ + /** - * @class DOMCharacterData - parent abstract class for DOMText and DOMComment - * @extends DOMNode - * @author Jon van Noort (jon@webarcana.com.au) - * @param ownerDocument : DOMDocument - The Document object associated with this node. + * @class CharacterData - parent abstract class for Text and Comment + * @extends Node + * @param ownerDocument : The Document object associated with this node. */ -var DOMCharacterData = function(ownerDocument) { - this.DOMNode = DOMNode; - this.DOMNode(ownerDocument); +CharacterData = function(ownerDocument) { + Node.apply(this, arguments); }; -DOMCharacterData.prototype = new DOMNode; -__extend__(DOMCharacterData.prototype,{ +CharacterData.prototype = new Node(); +__extend__(CharacterData.prototype,{ get data(){ return this.nodeValue; }, set data(data){ this.nodeValue = data; }, + get textContent(){ + return this.nodeValue; + }, + set textContent(newText){ + this.nodeValue = newText; + }, get length(){return this.nodeValue.length;}, appendData: function(arg){ - // throw Exception if DOMCharacterData is readonly + // throw Exception if CharacterData is readonly if (__ownerDocument__(this).implementation.errorChecking && this._readonly) { throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } // append data this.data = "" + this.data + arg; }, - deleteData: function(offset, count){ - // throw Exception if DOMCharacterData is readonly + deleteData: function(offset, count){ + // throw Exception if CharacterData is readonly if (__ownerDocument__(this).implementation.errorChecking && this._readonly) { throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } if (this.data) { // throw Exception if offset is negative or greater than the data length, - if (__ownerDocument__(this).implementation.errorChecking && + if (__ownerDocument__(this).implementation.errorChecking && ((offset < 0) || (offset > this.data.length) || (count < 0))) { throw(new DOMException(DOMException.INDEX_SIZE_ERR)); } - + // delete data if(!count || (offset + count) > this.data.length) { this.data = this.data.substring(0, offset); @@ -1493,43 +3094,43 @@ __extend__(DOMCharacterData.prototype,{ } }, insertData: function(offset, arg){ - // throw Exception if DOMCharacterData is readonly + // throw Exception if CharacterData is readonly if(__ownerDocument__(this).implementation.errorChecking && this._readonly){ throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } - + if(this.data){ // throw Exception if offset is negative or greater than the data length, - if (__ownerDocument__(this).implementation.errorChecking && + if (__ownerDocument__(this).implementation.errorChecking && ((offset < 0) || (offset > this.data.length))) { throw(new DOMException(DOMException.INDEX_SIZE_ERR)); } - + // insert data this.data = this.data.substring(0, offset).concat(arg, this.data.substring(offset)); }else { // throw Exception if offset is negative or greater than the data length, - if (__ownerDocument__(this).implementation.errorChecking && (offset != 0)) { + if (__ownerDocument__(this).implementation.errorChecking && (offset !== 0)) { throw(new DOMException(DOMException.INDEX_SIZE_ERR)); } - + // set data this.data = arg; } }, replaceData: function(offset, count, arg){ - // throw Exception if DOMCharacterData is readonly + // throw Exception if CharacterData is readonly if (__ownerDocument__(this).implementation.errorChecking && this._readonly) { throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } - + if (this.data) { // throw Exception if offset is negative or greater than the data length, - if (__ownerDocument__(this).implementation.errorChecking && + if (__ownerDocument__(this).implementation.errorChecking && ((offset < 0) || (offset > this.data.length) || (count < 0))) { throw(new DOMException(DOMException.INDEX_SIZE_ERR)); } - + // replace data this.data = this.data.substring(0, offset). concat(arg, this.data.substring(offset + count)); @@ -1543,7 +3144,7 @@ __extend__(DOMCharacterData.prototype,{ if (this.data) { // throw Exception if offset is negative or greater than the data length, // or the count is negative - if (__ownerDocument__(this).implementation.errorChecking && + if (__ownerDocument__(this).implementation.errorChecking && ((offset < 0) || (offset > this.data.length) || (count < 0))) { throw(new DOMException(DOMException.INDEX_SIZE_ERR)); } @@ -1555,178 +3156,182 @@ __extend__(DOMCharacterData.prototype,{ } } return ret; + }, + toString : function(){ + return "[object CharacterData]"; } }); -$w.CharacterData = DOMCharacterData;$debug("Defining Text"); -/* -* Text - DOM Level 2 -*/ /** - * @class DOMText - The Text interface represents the textual content (termed character data in XML) of an Element or Attr. - * If there is no markup inside an element's content, the text is contained in a single object implementing the Text interface - * that is the only child of the element. If there is markup, it is parsed into a list of elements and Text nodes that form the - * list of children of the element. - * @extends DOMCharacterData - * @author Jon van Noort (jon@webarcana.com.au) and David Joham (djoham@yahoo.com) - * @param ownerDocument : DOMDocument - The Document object associated with this node. + * @class Text + * The Text interface represents the textual content (termed + * character data in XML) of an Element or Attr. + * If there is no markup inside an element's content, the text is + * contained in a single object implementing the Text interface that + * is the only child of the element. If there is markup, it is + * parsed into a list of elements and Text nodes that form the + * list of children of the element. + * @extends CharacterData + * @param ownerDocument The Document object associated with this node. */ -var DOMText = function(ownerDocument) { - this.DOMCharacterData = DOMCharacterData; - this.DOMCharacterData(ownerDocument); - - this.nodeName = "#text"; +Text = function(ownerDocument) { + CharacterData.apply(this, arguments); + this.nodeName = "#text"; }; -DOMText.prototype = new DOMCharacterData; -__extend__(DOMText.prototype,{ - //Breaks this Text node into two Text nodes at the specified offset, - // keeping both in the tree as siblings. This node then only contains all the content up to the offset point. - // And a new Text node, which is inserted as the next sibling of this node, contains all the content at and after the offset point. +Text.prototype = new CharacterData(); +__extend__(Text.prototype,{ + get localName(){ + return null; + }, + // Breaks this Text node into two Text nodes at the specified offset, + // keeping both in the tree as siblings. This node then only contains + // all the content up to the offset point. And a new Text node, which + // is inserted as the next sibling of this node, contains all the + // content at and after the offset point. splitText : function(offset) { - var data, inode; - + var data, + inode; // test for exceptions if (__ownerDocument__(this).implementation.errorChecking) { // throw Exception if Node is readonly if (this._readonly) { throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } - // throw Exception if offset is negative or greater than the data length, if ((offset < 0) || (offset > this.data.length)) { throw(new DOMException(DOMException.INDEX_SIZE_ERR)); } } - if (this.parentNode) { // get remaining string (after offset) data = this.substringData(offset); - // create new TextNode with remaining string inode = __ownerDocument__(this).createTextNode(data); - // attach new TextNode if (this.nextSibling) { this.parentNode.insertBefore(inode, this.nextSibling); - } - else { + } else { this.parentNode.appendChild(inode); } - // remove remaining string from original TextNode this.deleteData(offset); } - return inode; }, get nodeType(){ - return DOMNode.TEXT_NODE; + return Node.TEXT_NODE; }, get xml(){ return __escapeXML__(""+ this.nodeValue); }, toString: function(){ - return "Text #" + this._id; + return "[object Text]"; } }); -$w.Text = DOMText;$debug("Defining CDATASection"); -/* -* CDATASection - DOM Level 2 -*/ /** - * @class DOMCDATASection - CDATA sections are used to escape blocks of text containing characters that would otherwise be regarded as markup. - * The only delimiter that is recognized in a CDATA section is the "\]\]\>" string that ends the CDATA section - * @extends DOMCharacterData - * @author Jon van Noort (jon@webarcana.com.au) and David Joham (djoham@yahoo.com) - * @param ownerDocument : DOMDocument - The Document object associated with this node. + * @class CDATASection + * CDATA sections are used to escape blocks of text containing + * characters that would otherwise be regarded as markup. + * The only delimiter that is recognized in a CDATA section is + * the "\]\]\>" string that ends the CDATA section + * @extends Text + * @param ownerDocument : The Document object associated with this node. */ -var DOMCDATASection = function(ownerDocument) { - this.DOMText = DOMText; - this.DOMText(ownerDocument); - - this.nodeName = "#cdata-section"; +CDATASection = function(ownerDocument) { + Text.apply(this, arguments); + this.nodeName = '#cdata-section'; }; -DOMCDATASection.prototype = new DOMText; -__extend__(DOMCDATASection.prototype,{ +CDATASection.prototype = new Text(); +__extend__(CDATASection.prototype,{ get nodeType(){ - return DOMNode.CDATA_SECTION_NODE; + return Node.CDATA_SECTION_NODE; }, get xml(){ return ""; }, toString : function(){ - return "CDATA #"+this._id; + return "[object CDATASection]"; } }); - -$w.CDATASection = DOMCDATASection;$debug("Defining Comment"); -/* -* Comment - DOM Level 2 -*/ /** - * @class DOMComment - This represents the content of a comment, i.e., all the characters between the starting '' - * @extends DOMCharacterData - * @author Jon van Noort (jon@webarcana.com.au) - * @param ownerDocument : DOMDocument - The Document object associated with this node. + * @class Comment + * This represents the content of a comment, i.e., all the + * characters between the starting '' + * @extends CharacterData + * @param ownerDocument : The Document object associated with this node. */ -var DOMComment = function(ownerDocument) { - this.DOMCharacterData = DOMCharacterData; - this.DOMCharacterData(ownerDocument); - - this.nodeName = "#comment"; +Comment = function(ownerDocument) { + CharacterData.apply(this, arguments); + this.nodeName = "#comment"; }; -DOMComment.prototype = new DOMCharacterData; -__extend__(DOMComment.prototype, { +Comment.prototype = new CharacterData(); +__extend__(Comment.prototype, { + get localName(){ + return null; + }, get nodeType(){ - return DOMNode.COMMENT_NODE; + return Node.COMMENT_NODE; }, get xml(){ return ""; }, toString : function(){ - return "Comment #"+this._id; + return "[object Comment]"; } }); -$w.Comment = DOMComment; -$debug("Defining DocumentType"); -;/* -* DocumentType - DOM Level 2 -*/ -var DOMDocumentType = function() { - $error("DOMDocumentType.constructor(): Not Implemented" ); -}; -$w.DocumentType = DOMDocumentType; -$debug("Defining Attr"); -/* -* Attr - DOM Level 2 -*/ /** - * @class DOMAttr - The Attr interface represents an attribute in an Element object - * @extends DOMNode - * @author Jon van Noort (jon@webarcana.com.au) - * @param ownerDocument : DOMDocument - The Document object associated with this node. + * @author envjs team + * @param {Document} onwnerDocument */ -var DOMAttr = function(ownerDocument) { - this.DOMNode = DOMNode; - this.DOMNode(ownerDocument); - - this.ownerElement = null; // set when Attr is added to NamedNodeMap +DocumentType = function(ownerDocument) { + Node.apply(this, arguments); + this.systemId = null; + this.publicId = null; }; -DOMAttr.prototype = new DOMNode; -__extend__(DOMAttr.prototype, { +DocumentType.prototype = new Node(); +__extend__({ + get name(){ + return this.nodeName; + }, + get entities(){ + return null; + }, + get internalSubsets(){ + return null; + }, + get notations(){ + return null; + }, + toString : function(){ + return "[object DocumentType]"; + } +}); + +/** + * @class Attr + * The Attr interface represents an attribute in an Element object + * @extends Node + * @param ownerDocument : The Document object associated with this node. + */ +Attr = function(ownerDocument) { + Node.apply(this, arguments); + // set when Attr is added to NamedNodeMap + this.ownerElement = null; + //TODO: our implementation of Attr is incorrect because we don't + // treat the value of the attribute as a child text node. +}; +Attr.prototype = new Node(); +__extend__(Attr.prototype, { // the name of this attribute get name(){ return this.nodeName; }, - set name(name){ - this.nodeName = name; - }, // the value of the attribute is returned as a string get value(){ - return this.nodeValue; + return this.nodeValue||''; }, set value(value){ // throw Exception if Attribute is readonly @@ -1736,46 +3341,50 @@ __extend__(DOMAttr.prototype, { // delegate to node this.nodeValue = value; }, + get textContent(){ + return this.nodeValue; + }, + set textContent(newText){ + this.nodeValue = newText; + }, get specified(){ - return (this.value.length > 0); + return (this !== null && this !== undefined); }, get nodeType(){ - return DOMNode.ATTRIBUTE_NODE; + return Node.ATTRIBUTE_NODE; }, - get xml(){ - return this.nodeName + '="' + __escapeXML__(this.nodeValue) + '" '; + get xml() { + if (this.nodeValue) { + return __escapeXML__(this.nodeValue+""); + } else { + return ''; + } }, - toString : function(){ - return "Attr #" + this._id + " " + this.name; + toString : function() { + return '[object Attr]'; } }); -$w.Attr = DOMAttr; -$debug("Defining Element"); + /** - * @class DOMElement - By far the vast majority of objects (apart from text) that authors encounter - * when traversing a document are Element nodes. - * @extends DOMNode - * @author Jon van Noort (jon@webarcana.com.au) and David Joham (djoham@yahoo.com) - * @param ownerDocument : DOMDocument - The Document object associated with this node. + * @class Element - + * By far the vast majority of objects (apart from text) + * that authors encounter when traversing a document are + * Element nodes. + * @extends Node + * @param ownerDocument : The Document object associated with this node. */ -var DOMElement = function(ownerDocument) { - this.DOMNode = DOMNode; - this.DOMNode(ownerDocument); - this.id = ""; // the ID of the element +Element = function(ownerDocument) { + Node.apply(this, arguments); + this.attributes = new NamedNodeMap(this.ownerDocument, this); }; -DOMElement.prototype = new DOMNode; -__extend__(DOMElement.prototype, { +Element.prototype = new Node(); +__extend__(Element.prototype, { // The name of the element. get tagName(){ - return this.nodeName; + return this.nodeName; }, - set tagName(name){ - this.nodeName = name; - }, - addEventListener : function(){ window.addEventListener.apply(this, arguments) }, - removeEventListener : function(){ window.removeEventListener.apply(this, arguments) }, - dispatchEvent : function(){ window.dispatchEvent.apply(this, arguments) }, + getAttribute: function(name) { var ret = null; // if attribute exists, use it @@ -1783,51 +3392,54 @@ __extend__(DOMElement.prototype, { if (attr) { ret = attr.value; } - return ret; // if Attribute exists, return its value, otherwise, return "" + // if Attribute exists, return its value, otherwise, return null + return ret; }, setAttribute : function (name, value) { // if attribute exists, use it var attr = this.attributes.getNamedItem(name); - var value = value+''; - //I had to add this check becuase as the script initializes + //console.log('attr %s', attr); + //I had to add this check because as the script initializes //the id may be set in the constructor, and the html element //overrides the id property with a getter/setter. if(__ownerDocument__(this)){ - if (!attr) { - attr = __ownerDocument__(this).createAttribute(name); // otherwise create it + if (attr===null||attr===undefined) { + // otherwise create it + attr = __ownerDocument__(this).createAttribute(name); + //console.log('attr %s', attr); } - - + + // test for exceptions if (__ownerDocument__(this).implementation.errorChecking) { // throw Exception if Attribute is readonly if (attr._readonly) { throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } - + // throw Exception if the value string contains an illegal character - if (!__isValidString__(value)) { + if (!__isValidString__(value+'')) { throw(new DOMException(DOMException.INVALID_CHARACTER_ERR)); } } - - if (__isIdDeclaration__(name)) { - // this.id = value; // cache ID for getElementById() - } - + // assign values to properties (and aliases) - attr.value = value; - + attr.value = value + ''; + // add/replace Attribute in NamedNodeMap this.attributes.setNamedItem(attr); + //console.log('element setNamedItem %s', attr); + }else{ + console.warn('Element has no owner document '+this.tagName+ + '\n\t cant set attribute ' + name + ' = '+value ); } }, removeAttribute : function removeAttribute(name) { - // delegate to DOMNamedNodeMap.removeNamedItem + // delegate to NamedNodeMap.removeNamedItem return this.attributes.removeNamedItem(name); }, getAttributeNode : function getAttributeNode(name) { - // delegate to DOMNamedNodeMap.getNamedItem + // delegate to NamedNodeMap.getNamedItem return this.attributes.getNamedItem(name); }, setAttributeNode: function(newAttr) { @@ -1835,7 +3447,7 @@ __extend__(DOMElement.prototype, { if (__isIdDeclaration__(newAttr.name)) { this.id = newAttr.value; // cache ID for getElementById() } - // delegate to DOMNamedNodeMap.setNamedItem + // delegate to NamedNodeMap.setNamedItem return this.attributes.setNamedItem(newAttr); }, removeAttributeNode: function(oldAttr) { @@ -1843,20 +3455,20 @@ __extend__(DOMElement.prototype, { if (__ownerDocument__(this).implementation.errorChecking && oldAttr._readonly) { throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } - + // get item index var itemIndex = this.attributes._findItemIndex(oldAttr._id); - + // throw Exception if node does not exist in this map if (__ownerDocument__(this).implementation.errorChecking && (itemIndex < 0)) { throw(new DOMException(DOMException.NOT_FOUND_ERR)); } - + return this.attributes._removeChild(itemIndex); }, getAttributeNS : function(namespaceURI, localName) { var ret = ""; - // delegate to DOMNAmedNodeMap.getNamedItemNS + // delegate to NAmedNodeMap.getNamedItemNS var attr = this.attributes.getNamedItemNS(namespaceURI, localName); if (attr) { ret = attr.value; @@ -1864,52 +3476,53 @@ __extend__(DOMElement.prototype, { return ret; // if Attribute exists, return its value, otherwise return "" }, setAttributeNS : function(namespaceURI, qualifiedName, value) { - // call DOMNamedNodeMap.getNamedItem + // call NamedNodeMap.getNamedItem + //console.log('setAttributeNS %s %s %s', namespaceURI, qualifiedName, value); var attr = this.attributes.getNamedItem(namespaceURI, qualifiedName); - + if (!attr) { // if Attribute exists, use it // otherwise create it attr = __ownerDocument__(this).createAttributeNS(namespaceURI, qualifiedName); } - - var value = value+''; - + + value = '' + value; + // test for exceptions if (__ownerDocument__(this).implementation.errorChecking) { // throw Exception if Attribute is readonly if (attr._readonly) { throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } - + // throw Exception if the Namespace is invalid - if (!__isValidNamespace__(namespaceURI, qualifiedName)) { + if (!__isValidNamespace__(this.ownerDocument, namespaceURI, qualifiedName, true)) { throw(new DOMException(DOMException.NAMESPACE_ERR)); } - + // throw Exception if the value string contains an illegal character if (!__isValidString__(value)) { throw(new DOMException(DOMException.INVALID_CHARACTER_ERR)); } } - + // if this Attribute is an ID - if (__isIdDeclaration__(name)) { - this.id = value; // cache ID for getElementById() - } - + //if (__isIdDeclaration__(name)) { + // this.id = value; + //} + // assign values to properties (and aliases) attr.value = value; attr.nodeValue = value; - - // delegate to DOMNamedNodeMap.setNamedItem + + // delegate to NamedNodeMap.setNamedItem this.attributes.setNamedItemNS(attr); }, removeAttributeNS : function(namespaceURI, localName) { - // delegate to DOMNamedNodeMap.removeNamedItemNS + // delegate to NamedNodeMap.removeNamedItemNS return this.attributes.removeNamedItemNS(namespaceURI, localName); }, getAttributeNodeNS : function(namespaceURI, localName) { - // delegate to DOMNamedNodeMap.getNamedItemNS + // delegate to NamedNodeMap.getNamedItemNS return this.attributes.getNamedItemNS(namespaceURI, localName); }, setAttributeNodeNS : function(newAttr) { @@ -1917,52 +3530,74 @@ __extend__(DOMElement.prototype, { if ((newAttr.prefix == "") && __isIdDeclaration__(newAttr.name)) { this.id = newAttr.value+''; // cache ID for getElementById() } - - // delegate to DOMNamedNodeMap.setNamedItemNS + + // delegate to NamedNodeMap.setNamedItemNS return this.attributes.setNamedItemNS(newAttr); }, hasAttribute : function(name) { - // delegate to DOMNamedNodeMap._hasAttribute + // delegate to NamedNodeMap._hasAttribute return __hasAttribute__(this.attributes,name); }, hasAttributeNS : function(namespaceURI, localName) { - // delegate to DOMNamedNodeMap._hasAttributeNS + // delegate to NamedNodeMap._hasAttributeNS return __hasAttributeNS__(this.attributes, namespaceURI, localName); }, get nodeType(){ - return DOMNode.ELEMENT_NODE; + return Node.ELEMENT_NODE; }, get xml() { - var ret = ""; - + var ret = "", + ns = "", + attrs, + attrstring, + i; + // serialize namespace declarations - var ns = this._namespaces.xml; - if (ns.length > 0) ns = " "+ ns; - + if (this.namespaceURI ){ + if((this === this.ownerDocument.documentElement) || + (!this.parentNode)|| + (this.parentNode && (this.parentNode.namespaceURI !== this.namespaceURI))) { + ns = ' xmlns' + (this.prefix?(':'+this.prefix):'') + + '="' + this.namespaceURI + '"'; + } + } + // serialize Attribute declarations - var attrs = this.attributes.xml; - if (attrs.length > 0) attrs = " "+ attrs; - - // serialize this Element - ret += "<" + this.nodeName.toLowerCase() + ns + attrs +">"; - ret += this.childNodes.xml; - ret += ""; - + attrs = this.attributes; + attrstring = ""; + for(i=0;i< attrs.length;i++){ + if(attrs[i].name.match('xmlns:')) { + attrstring += " "+attrs[i].name+'="'+attrs[i].xml+'"'; + } + } + for(i=0;i< attrs.length;i++){ + if(!attrs[i].name.match('xmlns:')) { + attrstring += " "+attrs[i].name+'="'+attrs[i].xml+'"'; + } + } + + if(this.hasChildNodes()){ + // serialize this Element + ret += "<" + this.tagName + ns + attrstring +">"; + ret += this.childNodes.xml; + ret += ""; + }else{ + ret += "<" + this.tagName + ns + attrstring +"/>"; + } + return ret; }, toString : function(){ - return "Element #"+this._id + " "+ this.tagName + (this.id?" => "+this.id:''); + return '[object Element]'; } }); - -$w.Element = DOMElement; /** * @class DOMException - raised when an operation is impossible to perform * @author Jon van Noort (jon@webarcana.com.au) * @param code : int - the exception code (one of the DOMException constants) */ -var DOMException = function(code) { - this.code = code; +DOMException = function(code) { + this.code = code; }; // DOMException constants @@ -1984,1267 +3619,106 @@ DOMException.SYNTAX_ERR = 12; DOMException.INVALID_MODIFICATION_ERR = 13; DOMException.NAMESPACE_ERR = 14; DOMException.INVALID_ACCESS_ERR = 15; -$debug("Defining DocumentFragment"); -/* -* DocumentFragment - DOM Level 2 -*/ + /** - * @class DOMDocumentFragment - DocumentFragment is a "lightweight" or "minimal" Document object. - * @extends DOMNode - * @author Jon van Noort (jon@webarcana.com.au) and David Joham (djoham@yahoo.com) - * @param ownerDocument : DOMDocument - The Document object associated with this node. + * @class DocumentFragment - + * DocumentFragment is a "lightweight" or "minimal" Document object. + * @extends Node + * @param ownerDocument : The Document object associated with this node. */ -var DOMDocumentFragment = function(ownerDocument) { - this.DOMNode = DOMNode; - this.DOMNode(ownerDocument); - this.nodeName = "#document-fragment"; +DocumentFragment = function(ownerDocument) { + Node.apply(this, arguments); + this.nodeName = "#document-fragment"; }; -DOMDocumentFragment.prototype = new DOMNode; -__extend__(DOMDocumentFragment.prototype,{ +DocumentFragment.prototype = new Node(); +__extend__(DocumentFragment.prototype,{ get nodeType(){ - return DOMNode.DOCUMENT_FRAGMENT_NODE; + return Node.DOCUMENT_FRAGMENT_NODE; }, get xml(){ var xml = "", - count = this.childNodes.length; - + count = this.childNodes.length; + // create string concatenating the serialized ChildNodes for (var i = 0; i < count; i++) { xml += this.childNodes.item(i).xml; } - + return xml; }, toString : function(){ - return "DocumentFragment #"+this._id; + return "[object DocumentFragment]"; + }, + get localName(){ + return null; } }); -$w.DocumentFragment = DOMDocumentFragment; -$debug("Defining ProcessingInstruction"); -/* -* ProcessingInstruction - DOM Level 2 -*/ + /** - * @class DOMProcessingInstruction - The ProcessingInstruction interface represents a "processing instruction", - * used in XML as a way to keep processor-specific information in the text of the document - * @extends DOMNode + * @class ProcessingInstruction - + * The ProcessingInstruction interface represents a + * "processing instruction", used in XML as a way to + * keep processor-specific information in the text of + * the document + * @extends Node * @author Jon van Noort (jon@webarcana.com.au) - * @param ownerDocument : DOMDocument - The Document object associated with this node. + * @param ownerDocument : The Document object associated with this node. */ -var DOMProcessingInstruction = function(ownerDocument) { - this.DOMNode = DOMNode; - this.DOMNode(ownerDocument); +ProcessingInstruction = function(ownerDocument) { + Node.apply(this, arguments); }; -DOMProcessingInstruction.prototype = new DOMNode; -__extend__(DOMProcessingInstruction.prototype, { +ProcessingInstruction.prototype = new Node(); +__extend__(ProcessingInstruction.prototype, { get data(){ return this.nodeValue; }, set data(data){ - // throw Exception if DOMNode is readonly + // throw Exception if Node is readonly if (__ownerDocument__(this).errorChecking && this._readonly) { throw(new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR)); } this.nodeValue = data; }, + get textContent(){ + return this.data; + }, + get localName(){ + return null; + }, get target(){ // The target of this processing instruction. // XML defines this as being the first token following the markup that begins the processing instruction. // The content of this processing instruction. return this.nodeName; }, + set target(value){ + // The target of this processing instruction. + // XML defines this as being the first token following the markup that begins the processing instruction. + // The content of this processing instruction. + this.nodeName = value; + }, get nodeType(){ - return DOMNode.PROCESSING_INSTRUCTION_NODE; + return Node.PROCESSING_INSTRUCTION_NODE; }, get xml(){ - return ""; + return ""; }, toString : function(){ - return "ProcessingInstruction #"+this._id; - } -}); - -$w.ProcessesingInstruction = DOMProcessingInstruction; -$debug("Defining DOMParser"); -/* -* DOMParser -*/ - -var DOMParser = function(){}; -__extend__(DOMParser.prototype,{ - parseFromString: function(xmlString){ - //$log("Parsing XML String: " +xmlString); - return document.implementation.createDocument().loadXML(xmlString); - } -}); - -$debug("Initializing Internal DOMParser."); -//keep one around for internal use -$domparser = new DOMParser(); - -$w.DOMParser = DOMParser; -// ========================================================================= -// -// xmlsax.js - an XML SAX parser in JavaScript. -// -// version 3.1 -// -// ========================================================================= -// -// Copyright (C) 2001 - 2002 David Joham (djoham@yahoo.com) and Scott Severtson -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. - -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. - -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// -// Visit the XML for