source: Dev/trunk/d3/lib/env-js/envjs/html.js @ 76

Last change on this file since 76 was 76, checked in by fpvanagthoven, 14 years ago

d3

File size: 132.6 KB
Line 
1/*
2 * Pure JavaScript Browser Environment
3 * By John Resig <http://ejohn.org/> and the Envjs Team
4 * Copyright 2008-2010 John Resig, under the MIT License
5 *
6 * This file simply provides the global definitions we need to
7 * be able to correctly implement to core browser DOM HTML interfaces.
8
9 // These are exported/leaked globally
10
11    HTMLDocument,
12    HTMLElement,
13    HTMLCollection,
14    HTMLAnchorElement,
15    HTMLAreaElement,
16    HTMLBaseElement,
17    HTMLQuoteElement,
18    HTMLBodyElement,
19    HTMLBRElement,
20    HTMLButtonElement,
21    CanvasRenderingContext2D,
22    HTMLCanvasElement,
23    HTMLTableColElement,
24    HTMLModElement,
25    HTMLDivElement,
26    HTMLDListElement,
27    HTMLFieldSetElement,
28    HTMLFormElement,
29    HTMLFrameElement,
30    HTMLFrameSetElement,
31    HTMLHeadElement,
32    HTMLHeadingElement,
33    HTMLHRElement,
34    HTMLHtmlElement,
35    HTMLIFrameElement,
36    HTMLImageElement,
37    HTMLInputElement,
38    HTMLLabelElement,
39    HTMLLegendElement,
40    HTMLLIElement,
41    HTMLLinkElement,
42    HTMLMapElement,
43    HTMLMetaElement,
44    HTMLObjectElement,
45    HTMLOListElement,
46    HTMLOptGroupElement,
47    HTMLOptionElement,
48    HTMLParagraphElement,
49    HTMLParamElement,
50    HTMLPreElement,
51    HTMLScriptElement,
52    HTMLSelectElement,
53    HTMLSpanElement,
54    HTMLStyleElement,
55    HTMLTableElement,
56    HTMLTableSectionElement,
57    HTMLTableCellElement,
58    HTMLTableDataCellElement,
59    HTMLTableHeaderCellElement,
60    HTMLTableRowElement,
61    HTMLTextAreaElement,
62    HTMLTitleElement,
63    HTMLUListElement,
64    HTMLUnknownElement,
65    Image,
66    Option,
67    __loadImage__,
68    __loadLink__;
69*/
70
71var Envjs = Envjs || require('./platform/core').Envjs,
72        After = After || require('./platform/core').After,
73        Document = Document || require('./dom').Document,
74        Element = Element || require('./dom').Element,
75        NodeList = NodeList || require('./dom').NodeList,
76        Node = Node || require('./dom').Node,
77        Event = Event || require('./event').Event;
78       
79/*
80 * Envjs html.1.3.pre03
81 * Pure JavaScript Browser Environment
82 * By John Resig <http://ejohn.org/> and the Envjs Team
83 * Copyright 2008-2010 John Resig, under the MIT License
84 */
85
86//CLOSURE_START
87(function(){
88
89
90
91
92
93/**
94 * @author ariel flesler
95 *    http://flesler.blogspot.com/2008/11/fast-trim-function-for-javascript.html
96 * @param {Object} str
97 */
98function __trim__( str ){
99    return (str || "").replace( /^\s+|\s+$/g, "" );
100}
101
102
103/**
104 * @author john resig
105 */
106// Helper method for extending one object with another.
107function __extend__(a,b) {
108    for ( var i in b ) {
109        if(b.hasOwnProperty(i)){
110            var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
111            if ( g || s ) {
112                if ( g ) { a.__defineGetter__(i, g); }
113                if ( s ) { a.__defineSetter__(i, s); }
114            } else {
115                a[i] = b[i];
116            }
117        }
118    }
119    return a;
120}
121
122/**
123 * @author john resig
124 */
125//from jQuery
126function __setArray__( target, array ) {
127    // Resetting the length to 0, then using the native Array push
128    // is a super-fast way to populate an object with array-like properties
129    target.length = 0;
130    Array.prototype.push.apply( target, array );
131}
132var __addNamedMap__,
133    __removeNamedMap__,
134    __isNamedElement__,
135    __selectparent__ ,//see option.js
136    __updateoptions__, //see option.js
137    __loadLink__; //see link.js
138/**
139 * @class  HTMLDocument
140 *      The Document interface represents the entire HTML or XML document.
141 *      Conceptually, it is the root of the document tree, and provides
142 *      the primary access to the document's data.
143 *
144 * @extends Document
145 */
146 
147(function(){
148   
149var log = Envjs.logger();
150
151Envjs.once('tick', function(){
152    log = Envjs.logger('Envjs.HTML.HTMLDocument').
153        debug('HTMLDocument available');   
154});
155
156exports.HTMLDocument = HTMLDocument = function(implementation, ownerWindow, referrer) {
157    Document.apply(this, arguments);
158    this.referrer = referrer || '';
159    this.baseURI = "about:blank";
160    this.ownerWindow = ownerWindow;
161};
162
163HTMLDocument.prototype = new Document();
164
165__extend__(HTMLDocument.prototype, {
166    createElement: function(tagName){
167        var node;
168        tagName = tagName.toUpperCase();
169        // create Element specifying 'this' as ownerDocument
170        // This is an html document so we need to use explicit interfaces per the
171        //TODO: would be much faster as a big switch
172        switch(tagName){
173        case "A":
174            node = new HTMLAnchorElement(this);break;
175        case "AREA":
176            node = new HTMLAreaElement(this);break;
177        case "BASE":
178            node = new HTMLBaseElement(this);break;
179        case "BLOCKQUOTE":
180            node = new HTMLQuoteElement(this);break;
181        case "CANVAS":
182            node = new HTMLCanvasElement(this);break;
183        case "Q":
184            node = new HTMLQuoteElement(this);break;
185        case "BODY":
186            node = new HTMLBodyElement(this);break;
187        case "BR":
188            node = new HTMLBRElement(this);break;
189        case "BUTTON":
190            node = new HTMLButtonElement(this);break;
191        case "CAPTION":
192            node = new HTMLElement(this);break;
193        case "COL":
194            node = new HTMLTableColElement(this);break;
195        case "COLGROUP":
196            node = new HTMLTableColElement(this);break;
197        case "DEL":
198            node = new HTMLModElement(this);break;
199        case "INS":
200            node = new HTMLModElement(this);break;
201        case "DIV":
202            node = new HTMLDivElement(this);break;
203        case "DL":
204            node = new HTMLDListElement(this);break;
205        case "DT":
206            node = new HTMLElement(this); break;
207        case "FIELDSET":
208            node = new HTMLFieldSetElement(this);break;
209        case "FORM":
210            node = new HTMLFormElement(this);break;
211        case "FRAME":
212            node = new HTMLFrameElement(this);break;
213        case "FRAMESET":
214            node = new HTMLFrameSetElement(this);break;
215        case "H1":
216            node = new HTMLHeadingElement(this);break;
217        case "H2":
218            node = new HTMLHeadingElement(this);break;
219        case "H3":
220            node = new HTMLHeadingElement(this);break;
221        case "H4":
222            node = new HTMLHeadingElement(this);break;
223        case "H5":
224            node = new HTMLHeadingElement(this);break;
225        case "H6":
226            node = new HTMLHeadingElement(this);break;
227        case "HEAD":
228            node = new HTMLHeadElement(this);break;
229        case "HR":
230            node = new HTMLHRElement(this);break;
231        case "HTML":
232            node = new HTMLHtmlElement(this);break;
233        case "IFRAME":
234            node = new HTMLIFrameElement(this);break;
235        case "IMG":
236            node = new HTMLImageElement(this);break;
237        case "INPUT":
238            node = new HTMLInputElement(this);break;
239        case "LABEL":
240            node = new HTMLLabelElement(this);break;
241        case "LEGEND":
242            node = new HTMLLegendElement(this);break;
243        case "LI":
244            node = new HTMLLIElement(this);break;
245        case "LINK":
246            node = new HTMLLinkElement(this);break;
247        case "MAP":
248            node = new HTMLMapElement(this);break;
249        case "META":
250            node = new HTMLMetaElement(this);break;
251        case "NOSCRIPT":
252            node = new HTMLElement(this);break;
253        case "OBJECT":
254            node = new HTMLObjectElement(this);break;
255        case "OPTGROUP":
256            node = new HTMLOptGroupElement(this);break;
257        case "OL":
258            node = new HTMLOListElement(this); break;
259        case "OPTION":
260            node = new HTMLOptionElement(this);break;
261        case "P":
262            node = new HTMLParagraphElement(this);break;
263        case "PARAM":
264            node = new HTMLParamElement(this);break;
265        case "PRE":
266            node = new HTMLPreElement(this);break;
267        case "SCRIPT":
268            node = new HTMLScriptElement(this);break;
269        case "SELECT":
270            node = new HTMLSelectElement(this);break;
271        case "SMALL":
272            node = new HTMLElement(this);break;
273        case "SPAN":
274            node = new HTMLSpanElement(this);break;
275        case "STRONG":
276            node = new HTMLElement(this);break;
277        case "STYLE":
278            node = new HTMLStyleElement(this);break;
279        case "TABLE":
280            node = new HTMLTableElement(this);break;
281        case "TBODY":
282            node = new HTMLTableSectionElement(this);break;
283        case "TFOOT":
284            node = new HTMLTableSectionElement(this);break;
285        case "THEAD":
286            node = new HTMLTableSectionElement(this);break;
287        case "TD":
288            node = new HTMLTableDataCellElement(this);break;
289        case "TH":
290            node = new HTMLTableHeaderCellElement(this);break;
291        case "TEXTAREA":
292            node = new HTMLTextAreaElement(this);break;
293        case "TITLE":
294            node = new HTMLTitleElement(this);break;
295        case "TR":
296            node = new HTMLTableRowElement(this);break;
297        case "UL":
298            node = new HTMLUListElement(this);break;
299        default:
300            node = new HTMLUnknownElement(this);
301        }
302        // assign values to properties (and aliases)
303        node.nodeName  = tagName;
304        return node;
305    },
306    createElementNS : function (uri, local) {
307        //print('createElementNS :'+uri+" "+local);
308        if(!uri){
309            return this.createElement(local);
310        }else if ("http://www.w3.org/1999/xhtml" == uri) {
311            return this.createElement(local);
312        } else if ("http://www.w3.org/1998/Math/MathML" == uri) {
313            return this.createElement(local);
314        } else if ("http://www.w3.org/2000/svg" == uri) {
315            return this.createElement(local);
316        } else {
317            return Document.prototype.createElementNS.apply(this,[uri, local]);
318        }
319    },
320    get anchors(){
321        return new HTMLCollection(this.getElementsByTagName('a'));
322    },
323    get applets(){
324        return new HTMLCollection(this.getElementsByTagName('applet'));
325    },
326    get documentElement(){
327        var html = Document.prototype.__lookupGetter__('documentElement').apply(this,[]);
328        if( html === null){
329            html = this.createElement('html');
330            this.appendChild(html);
331            html.appendChild(this.createElement('head'));
332            html.appendChild(this.createElement('body'));
333        }
334        return html;
335    },
336    //document.head is non-standard
337    get head(){
338        //console.log('get head');
339        if (!this.documentElement) {
340            this.appendChild(this.createElement('html'));
341        }
342        var element = this.documentElement,
343            length = element.childNodes.length,
344            i;
345        //check for the presence of the head element in this html doc
346        for(i=0;i<length;i++){
347            if(element.childNodes[i].nodeType === Node.ELEMENT_NODE){
348                if(element.childNodes[i].tagName.toLowerCase() === 'head'){
349                    return element.childNodes[i];
350                }
351            }
352        }
353        //no head?  ugh bad news html.. I guess we'll force the issue?
354        var head = element.appendChild(this.createElement('head'));
355        return head;
356    },
357    get title(){
358        //console.log('get title');
359        if (!this.documentElement) {
360            this.appendChild(this.createElement('html'));
361        }
362        var title,
363            head = this.head,
364            length = head.childNodes.length,
365            i;
366        //check for the presence of the title element in this head element
367        for(i=0;i<length;i++){
368            if(head.childNodes[i].nodeType === Node.ELEMENT_NODE){
369                if(head.childNodes[i].tagName.toLowerCase() === 'title'){
370                    return head.childNodes[i].textContent;
371                }
372            }
373        }
374        //no title?  ugh bad news html.. I guess we'll force the issue?
375        title = head.appendChild(this.createElement('title'));
376        return title.appendChild(this.createTextNode('Untitled Document')).nodeValue;
377    },
378    set title(titleStr){
379        //console.log('set title %s', titleStr);
380        if (!this.documentElement) {
381            this.appendChild(this.createElement('html'));
382        }
383        var title = this.title;
384        title.textContent = titleStr;
385    },
386
387    get body() {
388        var element = this.documentElement,
389            length = element.childNodes.length,
390            i;
391        for (i=0; i<length; i++) {
392            if (element.childNodes[i].nodeType === Node.ELEMENT_NODE &&
393                (element.childNodes[i].tagName === 'BODY' ||
394                 element.childNodes[i].tagName === 'FRAMESET')) {
395                return element.childNodes[i];
396            }
397        }
398        return null;
399    },
400    set body() {
401        /* in firefox this is a benevolent do nothing*/
402        console.log('set body');
403    },
404
405    get cookie(){
406        return Envjs.getCookies(this.location+'');
407    },
408    set cookie(cookie){
409        return Envjs.setCookie(this.location+'', cookie);
410    },
411
412    /**
413     * document.location
414     *
415     * should be identical to window.location
416     *
417     * HTML5:
418     * http://dev.w3.org/html5/spec/Overview.html#the-location-interface
419     *
420     * Mozilla MDC:
421     * https://developer.mozilla.org/en/DOM/document.location
422     *
423     */
424    get location() {
425        if (this.ownerWindow) {
426            return this.ownerWindow.location;
427        } else {
428            return this.baseURI;
429        }
430    },
431    set location(url) {
432        this.baseURI = url;
433        if (this.ownerWindow) {
434            this.ownerWindow.location = url;
435        }
436    },
437
438    /**
439     * document.URL (read-only)
440     *
441     * HTML DOM Level 2:
442     * http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-46183437
443     *
444     * HTML5:
445     * http://dev.w3.org/html5/spec/Overview.html#dom-document-url
446     *
447     * Mozilla MDC:
448     * https://developer.mozilla.org/en/DOM/document.URL
449     */
450    get URL() {
451        return this.location.href;
452    },
453
454    /**
455     * document.domain
456     *
457     * HTML5 Spec:
458     * http://dev.w3.org/html5/spec/Overview.html#dom-document-domain
459     *
460     * Mozilla MDC:
461     * https://developer.mozilla.org/en/DOM/document.domain
462     *
463     */
464    get domain(){
465        var HOSTNAME = new RegExp('//([^:/]+)'),
466            matches = HOSTNAME.exec(this.baseURI);
467        return matches&&matches.length>1?matches[1]:"";
468    },
469    set domain(value){
470        var i,
471            domainParts = this.domain.split('.').reverse(),
472            newDomainParts = value.split('.').reverse();
473        if(newDomainParts.length > 1){
474            for(i=0;i<newDomainParts.length;i++){
475                if(newDomainParts[i] !== domainParts[i]){
476                    return;
477                }
478            }
479            this.baseURI = this.baseURI.replace(domainParts.join('.'), value);
480        }
481    },
482
483    get forms(){
484        return new HTMLCollection(this.getElementsByTagName('form'));
485    },
486    get images(){
487        return new HTMLCollection(this.getElementsByTagName('img'));
488    },
489    get lastModified(){
490        /* TODO */
491        return this._lastModified;
492    },
493    get links(){
494        return new HTMLCollection(this.getElementsByTagName('a'));
495    },
496    getElementsByName : function(name){
497        //console.log('getting elements for name %s', name);
498        if(!(this._indexes_['@'+name])){
499            this._indexes_["@"+name] = new NodeList(this, this.documentElement);
500        }
501        return this._indexes_["@"+name];
502    },
503    toString: function(){
504        return "[object HTMLDocument]";
505    },
506    get innerHTML(){
507        return this.documentElement.outerHTML;
508    }
509});
510
511}(/*HTMLDocument*/));
512
513Aspect.around({
514    target: Node,
515    method:"appendChild"
516}, function(invocation) {
517    var event,
518        okay,
519        node = invocation.proceed(),
520        doc = node.ownerDocument,
521        target;
522
523    //console.log('element appended: %s %s %s', node+'', node.nodeName, node.namespaceURI);
524    if((node.nodeType !== Node.ELEMENT_NODE)){
525        //for now we are only handling element insertions.  probably
526        //we will need to handle text node changes to script tags and
527        //changes to src attributes
528        return node;
529    }
530   
531    if(node.tagName&&node.tagName.toLowerCase()=="input"){
532        target = node.parentNode;
533        //console.log('adding named map for input');
534        while(target&&target.tagName&&target.tagName.toLowerCase()!="form"){
535            //console.log('possible target for named map for input is %s', target);
536            target = target.parentNode;
537        }
538        if(target){
539            //console.log('target for named map for input is %s', target);
540            __addNamedMap__(target, node);
541        }
542    }
543    //console.log('appended html element %s %s %s', node.namespaceURI, node.nodeName, node);
544    switch(doc.parsing){
545        case true:
546
547            /**
548             * Very special case.  While in parsing mode, in head, a
549             * script can add another script tag to the head, and it will
550             * be evaluated.  This is tested in 'ant fulldoc-spec' tests.
551             *
552             * Not quite sure if the require that the new script tag must
553             * be in the head is correct or not.  NamespaceURI == null
554             * might also need to corrected too.
555             */
556            if (node.tagName.toLowerCase() === 'script' &&
557                (node.namespaceURI === "" ||
558                 node.namespaceURI === "http://www.w3.org/1999/xhtml" ||
559                 node.namespaceURI === null) ) {
560                //console.log('appending script while parsing');
561                if((this.nodeName.toLowerCase() === 'head')){
562                    try{
563                        okay = Envjs.loadLocalScript(node, null);
564                        //console.log('loaded script? %s %s', node.uuid, okay);
565                        // only fire event if we actually had something to load
566                        if (node.src && node.src.length > 0){
567                            event = doc.createEvent('HTMLEvents');
568                            event.initEvent( okay ? "load" : "error", false, false );
569                            node.dispatchEvent( event, false );
570                        }
571                    }catch(e){
572                        console.log('error loading html element %s %e', node, e.toString());
573                    }
574                }
575            }
576            break;
577        case false:
578            switch(node.namespaceURI){
579                case null:
580                    //fall through
581                case "":
582                    //fall through
583                case "http://www.w3.org/1999/xhtml":
584                    switch(node.tagName.toLowerCase()){
585                        case 'style':
586                            document.styleSheets.push(new CSSStyleSheet(node));
587                            break;
588                        case 'script':
589                            //console.log('appending script %s', node.src);
590                            if((this.nodeName.toLowerCase() === 'head')){
591                                try{
592                                    okay = Envjs.loadLocalScript(node, null);
593                                    //console.log('loaded script? %s %s', node.uuid, okay);
594                                    // only fire event if we actually had something to load
595                                    if (node.src && node.src.length > 0){
596                                        event = doc.createEvent('HTMLEvents');
597                                        event.initEvent( okay ? "load" : "error", false, false );
598                                        node.dispatchEvent( event, false );
599                                    }
600                                }catch(ee){
601                                    console.log('error loading html element %s %e', node, ee.toString());
602                                }
603                            }
604                            break;
605                        case 'frame':
606                        case 'iframe':
607                            node.contentWindow = { };
608                            node.contentDocument = new HTMLDocument(new DOMImplementation(), node.contentWindow);
609                            node.contentWindow.document = node.contentDocument;
610                            try{
611                                if(Window){
612                                    //console.log("iframe appended to document %s", node);
613                                }
614                            }catch(eee){
615                                node.contentDocument.addEventListener('DOMContentLoaded', function(){
616                                    event = node.contentDocument.createEvent('HTMLEvents');
617                                    event.initEvent("load", false, false);
618                                    node.dispatchEvent( event, false );
619                                });
620                                console.log('error loading html element %s %e', node, eee.toString());
621                            }
622                            try{
623                                if (node.src && node.src.length > 0){
624                                    //console.log("trigger load on frame from appendChild %s", node.src);
625                                    Envjs.loadFrame(node, Envjs.uri(node.src, doc.location+''));
626                                }else{
627                                    Envjs.loadFrame(node);
628                                }
629                            }catch(_e){
630                                console.log('error loading html element %s %e', node, _e.toString());
631                            }
632                            break;
633
634                        case 'link':
635                            if (node.href && node.href.length > 0) {
636                                Envjs.loadLink(node, node.href);
637                            }
638                            break;
639                            /*
640                              case 'img':
641                              if (node.src && node.src.length > 0){
642                              // don't actually load anything, so we're "done" immediately:
643                              event = doc.createEvent('HTMLEvents');
644                              event.initEvent("load", false, false);
645                              node.dispatchEvent( event, false );
646                              }
647                              break;
648                            */
649                        case 'option':
650                            __updateoptions__(node);
651                            break;
652                        default:
653                            if(node.getAttribute('onload')){
654                                //console.log('calling attribute onload %s | %s', node.onload, node.tagName);
655                                node.onload();
656                            }
657                    }//switch on name
658                    break;
659                default:
660                    break;
661            }//switch on ns
662            break;
663        default:
664            break;
665            // console.log('element appended: %s %s', node+'', node.namespaceURI);
666    }//switch on doc.parsing
667    return node;
668
669});
670
671Aspect.around({
672    target: Node,
673    method:"removeChild"
674}, function(invocation) {
675    var event,
676        okay,
677        target,
678        node = invocation.proceed(),
679        doc = node.ownerDocument;
680    if((node.nodeType !== Node.ELEMENT_NODE)){
681        //for now we are only handling element insertions.  probably we will need
682        //to handle text node changes to script tags and changes to src
683        //attributes
684        if(node.nodeType !== Node.DOCUMENT_NODE && node.uuid){
685            //console.log('removing event listeners, %s', node, node.uuid);
686            node.removeEventListener('*', null, null);
687        }
688        return node;
689    }
690    //console.log('appended html element %s %s %s', node.namespaceURI, node.nodeName, node);
691    if(node.tagName&&node.tagName.toLowerCase()=="input"){
692        target = node.parentNode;
693        //console.log('adding named map for input');
694        while(target&&target.tagName&&target.tagName.toLowerCase()!="form"){
695            //console.log('possible target for named map for input is %s', target);
696            target = target.parentNode;
697        }
698        if(target){
699            //console.log('target for named map for input is %s', target);
700            __removeNamedMap__(target, node);
701        }
702    }
703    switch(doc.parsing){
704        case true:
705            //handled by parser if included
706            break;
707        case false:
708            switch(node.namespaceURI){
709                case null:
710                    //fall through
711                case "":
712                    //fall through
713                case "http://www.w3.org/1999/xhtml":
714                    //this is interesting dillema since our event engine is
715                    //storing the registered events in an array accessed
716                    //by the uuid property of the node.  unforunately this
717                    //means listeners hang out way after(forever ;)) the node
718                    //has been removed and gone out of scope.
719                    //console.log('removing event listeners, %s', node, node.uuid);
720                    node.removeEventListener('*', null, null);
721                    switch(node.tagName.toLowerCase()){
722                        case 'frame':
723                        case 'iframe':
724                            try{
725                                //console.log('removing iframe document');
726                                try{
727                                    Envjs.unloadFrame(node);
728                                }catch(ee){
729                                    console.log('error freeing resources from frame %s', ee);
730                                }
731                                node.contentWindow = null;
732                                node.contentDocument = null;
733                            }catch(e){
734                                console.log('error unloading html element %s %e', node, e.toString());
735                            }
736                            break;
737                        default:
738                    }//switch on name
739                    break;
740                default:
741            }//switch on ns
742            break;
743        default:
744            console.log('element appended: %s %s', node+'', node.namespaceURI);
745    }//switch on doc.parsing
746    return node;
747
748});
749
750
751
752/**
753 * Named Element Support
754 *
755 *
756 */
757
758/*
759 *
760 * @returns 'name' if the node has a appropriate name
761 *          null if node does not have a name
762 */
763
764__isNamedElement__ = function(node) {
765    if (node.nodeType !== Node.ELEMENT_NODE) {
766        return null;
767    }
768    var tagName = node.tagName.toLowerCase();
769    var nodename = null;
770
771    switch (tagName) {
772        case 'embed':
773        case 'form':
774        case 'iframe':
775        case 'input':
776            nodename = node.getAttribute('name');
777            break;
778        case 'applet':
779            nodename = node.id;
780            break;
781        case 'object':
782            // TODO: object needs to be 'fallback free'
783            nodename = node.id;
784            break;
785        case 'img':
786            nodename = node.id;
787            if (!nodename || ! node.getAttribute('name')) {
788                nodename = null;
789            }
790            break;
791    }
792    return (nodename) ? nodename : null;
793};
794
795
796__addNamedMap__ = function(target, node) {
797    var nodename = __isNamedElement__(node);
798    if (nodename) {
799        target.__defineGetter__(nodename, function() {
800            return node;
801        });
802        target.__defineSetter__(nodename, function(value) {
803            return value;
804        });
805    }
806};
807
808__removeNamedMap__ = function(target, node) {
809    if (!node) {
810        return;
811    }
812    var nodename = __isNamedElement__(node);
813    if (nodename) {
814        delete target[nodename];
815    }
816};
817
818
819
820/**
821 * @name HTMLEvents
822 * @w3c:domlevel 2
823 * @uri http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html
824 */
825
826var __eval__ = function(script, node){
827    if (script !== "" && Envjs.scriptTypes['']){
828        // don't assemble environment if no script...
829        try{
830            Envjs['eval'](node.ownerDocument.ownerWindow, script, script+" ("+node+")");
831        }catch(e){
832            console.log('error evaluating %s', e);
833        }
834    }
835};
836
837var HTMLEvents = function(){};
838HTMLEvents.prototype = {
839    onload: function(event){
840        __eval__(this.getAttribute('onload')||'', this);
841    },
842    onunload: function(event){
843        __eval__(this.getAttribute('onunload')||'', this);
844    },
845    onabort: function(event){
846        __eval__(this.getAttribute('onabort')||'', this);
847    },
848    onerror: function(event){
849        __eval__(this.getAttribute('onerror')||'', this);
850    },
851    onselect: function(event){
852        __eval__(this.getAttribute('onselect')||'', this);
853    },
854    onchange: function(event){
855        __eval__(this.getAttribute('onchange')||'', this);
856    },
857    onsubmit: function(event){
858        if (__eval__(this.getAttribute('onsubmit')||'', this)) {
859            this.submit();
860        }
861    },
862    onreset: function(event){
863        __eval__(this.getAttribute('onreset')||'', this);
864    },
865    onfocus: function(event){
866        __eval__(this.getAttribute('onfocus')||'', this);
867    },
868    onblur: function(event){
869        __eval__(this.getAttribute('onblur')||'', this);
870    },
871    onresize: function(event){
872        __eval__(this.getAttribute('onresize')||'', this);
873    },
874    onscroll: function(event){
875        __eval__(this.getAttribute('onscroll')||'', this);
876    }
877};
878
879//HTMLDocument, HTMLFramesetElement, HTMLObjectElement
880var  __load__ = function(element){
881    var event = new Event('HTMLEvents');
882    event.initEvent("load", false, false);
883    element.dispatchEvent(event);
884    return event;
885};
886
887//HTMLFramesetElement, HTMLBodyElement
888var  __unload__ = function(element){
889    var event = new Event('HTMLEvents');
890    event.initEvent("unload", false, false);
891    element.dispatchEvent(event);
892    return event;
893};
894
895//HTMLObjectElement
896var  __abort__ = function(element){
897    var event = new Event('HTMLEvents');
898    event.initEvent("abort", true, false);
899    element.dispatchEvent(event);
900    return event;
901};
902
903//HTMLFramesetElement, HTMLObjectElement, HTMLBodyElement
904var  __error__ = function(element){
905    var event = new Event('HTMLEvents');
906    event.initEvent("error", true, false);
907    element.dispatchEvent(event);
908    return event;
909};
910
911//HTMLInputElement, HTMLTextAreaElement
912var  __select__ = function(element){
913    var event = new Event('HTMLEvents');
914    event.initEvent("select", true, false);
915    element.dispatchEvent(event);
916    return event;
917};
918
919//HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement
920var  __change__ = function(element){
921    var event = new Event('HTMLEvents');
922    event.initEvent("change", true, false);
923    element.dispatchEvent(event);
924    return event;
925};
926
927//HtmlFormElement
928var __submit__ = function(element){
929    var event = new Event('HTMLEvents');
930    event.initEvent("submit", true, true);
931    element.dispatchEvent(event);
932    return event;
933};
934
935//HtmlFormElement
936var  __reset__ = function(element){
937    var event = new Event('HTMLEvents');
938    event.initEvent("reset", false, false);
939    element.dispatchEvent(event);
940    return event;
941};
942
943//LABEL, INPUT, SELECT, TEXTAREA, and BUTTON
944var __focus__ = function(element){
945    var event = new Event('HTMLEvents');
946    event.initEvent("focus", false, false);
947    element.dispatchEvent(event);
948    return event;
949};
950
951//LABEL, INPUT, SELECT, TEXTAREA, and BUTTON
952var __blur__ = function(element){
953    var event = new Event('HTMLEvents');
954    event.initEvent("blur", false, false);
955    element.dispatchEvent(event);
956    return event;
957};
958
959//Window
960var __resize__ = function(element){
961    var event = new Event('HTMLEvents');
962    event.initEvent("resize", true, false);
963    element.dispatchEvent(event);
964    return event;
965};
966
967//Window
968var __scroll__ = function(element){
969    var event = new Event('HTMLEvents');
970    event.initEvent("scroll", true, false);
971    element.dispatchEvent(event);
972    return event;
973};
974
975/**
976 * @name KeyboardEvents
977 * @w3c:domlevel 2
978 * @uri http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html
979 */
980var KeyboardEvents= function(){};
981KeyboardEvents.prototype = {
982    onkeydown: function(event){
983        __eval__(this.getAttribute('onkeydown')||'', this);
984    },
985    onkeypress: function(event){
986        __eval__(this.getAttribute('onkeypress')||'', this);
987    },
988    onkeyup: function(event){
989        __eval__(this.getAttribute('onkeyup')||'', this);
990    }
991};
992
993
994var __registerKeyboardEventAttrs__ = function(elm){
995    if(elm.hasAttribute('onkeydown')){
996        elm.addEventListener('keydown', elm.onkeydown, false);
997    }
998    if(elm.hasAttribute('onkeypress')){
999        elm.addEventListener('keypress', elm.onkeypress, false);
1000    }
1001    if(elm.hasAttribute('onkeyup')){
1002        elm.addEventListener('keyup', elm.onkeyup, false);
1003    }
1004    return elm;
1005};
1006
1007//HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement
1008var  __keydown__ = function(element){
1009    var event = new Event('KeyboardEvents');
1010    event.initEvent("keydown", false, false);
1011    element.dispatchEvent(event);
1012};
1013
1014//HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement
1015var  __keypress__ = function(element){
1016    var event = new Event('KeyboardEvents');
1017    event.initEvent("keypress", false, false);
1018    element.dispatchEvent(event);
1019};
1020
1021//HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement
1022var  __keyup__ = function(element){
1023    var event = new Event('KeyboardEvents');
1024    event.initEvent("keyup", false, false);
1025    element.dispatchEvent(event);
1026};
1027
1028/**
1029 * @name MaouseEvents
1030 * @w3c:domlevel 2
1031 * @uri http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html
1032 */
1033var MouseEvents= function(){};
1034MouseEvents.prototype = {
1035    onclick: function(event){
1036        __eval__(this.getAttribute('onclick')||'', this);
1037    },
1038    ondblclick: function(event){
1039        __eval__(this.getAttribute('ondblclick')||'', this);
1040    },
1041    onmousedown: function(event){
1042        __eval__(this.getAttribute('onmousedown')||'', this);
1043    },
1044    onmousemove: function(event){
1045        __eval__(this.getAttribute('onmousemove')||'', this);
1046    },
1047    onmouseout: function(event){
1048        __eval__(this.getAttribute('onmouseout')||'', this);
1049    },
1050    onmouseover: function(event){
1051        __eval__(this.getAttribute('onmouseover')||'', this);
1052    },
1053    onmouseup: function(event){
1054        __eval__(this.getAttribute('onmouseup')||'', this);
1055    } 
1056};
1057
1058var __registerMouseEventAttrs__ = function(elm){
1059    if(elm.hasAttribute('onclick')){
1060        elm.addEventListener('click', elm.onclick, false);
1061    }
1062    if(elm.hasAttribute('ondblclick')){
1063        elm.addEventListener('dblclick', elm.ondblclick, false);
1064    }
1065    if(elm.hasAttribute('onmousedown')){
1066        elm.addEventListener('mousedown', elm.onmousedown, false);
1067    }
1068    if(elm.hasAttribute('onmousemove')){
1069        elm.addEventListener('mousemove', elm.onmousemove, false);
1070    }
1071    if(elm.hasAttribute('onmouseout')){
1072        elm.addEventListener('mouseout', elm.onmouseout, false);
1073    }
1074    if(elm.hasAttribute('onmouseover')){
1075        elm.addEventListener('mouseover', elm.onmouseover, false);
1076    }
1077    if(elm.hasAttribute('onmouseup')){
1078        elm.addEventListener('mouseup', elm.onmouseup, false);
1079    }
1080    return elm;
1081};
1082
1083
1084var  __click__ = function(element){
1085    var event = new Event('MouseEvents');
1086    event.initEvent("click", true, true, null, 0,
1087                0, 0, 0, 0, false, false, false,
1088                false, null, null);
1089    element.dispatchEvent(event);
1090};
1091var  __mousedown__ = function(element){
1092    var event = new Event('MouseEvents');
1093    event.initEvent("mousedown", true, true, null, 0,
1094                0, 0, 0, 0, false, false, false,
1095                false, null, null);
1096    element.dispatchEvent(event);
1097};
1098var  __mouseup__ = function(element){
1099    var event = new Event('MouseEvents');
1100    event.initEvent("mouseup", true, true, null, 0,
1101                0, 0, 0, 0, false, false, false,
1102                false, null, null);
1103    element.dispatchEvent(event);
1104};
1105var  __mouseover__ = function(element){
1106    var event = new Event('MouseEvents');
1107    event.initEvent("mouseover", true, true, null, 0,
1108                0, 0, 0, 0, false, false, false,
1109                false, null, null);
1110    element.dispatchEvent(event);
1111};
1112var  __mousemove__ = function(element){
1113    var event = new Event('MouseEvents');
1114    event.initEvent("mousemove", true, true, null, 0,
1115                0, 0, 0, 0, false, false, false,
1116                false, null, null);
1117    element.dispatchEvent(event);
1118};
1119var  __mouseout__ = function(element){
1120    var event = new Event('MouseEvents');
1121    event.initEvent("mouseout", true, true, null, 0,
1122                0, 0, 0, 0, false, false, false,
1123                false, null, null);
1124    element.dispatchEvent(event);
1125};
1126
1127/**
1128 * HTMLElement - DOM Level 2
1129 */
1130
1131
1132(function(){
1133   
1134var log = Envjs.logger();
1135
1136Envjs.once('tick', function(){
1137    log = Envjs.logger('Envjs.HTML.HTMLElement').
1138                debug('HTMLElement available');   
1139});
1140
1141/* Hack for http://www.prototypejs.org/
1142 *
1143 * Prototype 1.6 (the library) creates a new global Element, which causes
1144 * envjs to use the wrong Element.
1145 *
1146 * http://envjs.lighthouseapp.com/projects/21590/tickets/108-prototypejs-wont-load-due-it-clobbering-element
1147 *
1148 * Options:
1149 *  (1) Rename the dom/element to something else
1150 *       rejected: been done before. people want Element.
1151 *  (2) merge dom+html and not export Element to global namespace
1152 *      (meaning we would use a local var Element in a closure, so prototype
1153 *      can do what ever it wants)
1154 *       rejected: want dom and html separate
1155 *  (3) use global namespace (put everything under Envjs = {})
1156 *       rejected: massive change
1157 *  (4) use commonjs modules (similar to (3) in spirit)
1158 *       rejected: massive change
1159 *
1160 *  or
1161 *
1162 *  (5) take a reference to Element during initial loading ("compile
1163 *      time"), and use the reference instead of "Element".  That's
1164 *      what the next line does.  We use __DOMElement__ if we need to
1165 *      reference the parent class.  Only this file explcity uses
1166 *      Element so this should work, and is the most minimal change I
1167 *      could think of with no external API changes.
1168 *
1169 */
1170var  __DOMElement__ = Element;
1171
1172exports.HTMLElement = HTMLElement = function(ownerDocument) {
1173    __DOMElement__.apply(this, arguments);
1174};
1175
1176HTMLElement.prototype = new Element();
1177__extend__(HTMLElement.prototype, HTMLEvents.prototype);
1178__extend__(HTMLElement.prototype, {
1179    get className() {
1180        return this.getAttribute("class")||'';
1181    },
1182    set className(value) {
1183        return this.setAttribute("class",__trim__(value));
1184    },
1185    get dir() {
1186        return this.getAttribute("dir")||"ltr";
1187    },
1188    set dir(val) {
1189        return this.setAttribute("dir",val);
1190    },
1191    get id(){
1192        return this.getAttribute('id') || '';
1193    },
1194    set id(id){
1195        this.setAttribute('id', id);
1196    },
1197    get innerHTML(){
1198        var ret = "",
1199        i;
1200
1201        // create string containing the concatenation of the string
1202        // values of each child
1203        for (i=0; i < this.childNodes.length; i++) {
1204            if(this.childNodes[i]){
1205                if(this.childNodes[i].nodeType === Node.ELEMENT_NODE){
1206                    ret += this.childNodes[i].xhtml;
1207                } else if (this.childNodes[i].nodeType === Node.TEXT_NODE && i>0 &&
1208                           this.childNodes[i-1].nodeType === Node.TEXT_NODE){
1209                    //add a single space between adjacent text nodes
1210                    ret += " "+this.childNodes[i].xml;
1211                }else{
1212                    ret += this.childNodes[i].xml;
1213                }
1214            }
1215        }
1216        return ret;
1217    },
1218    get lang() {
1219        return this.getAttribute("lang");
1220    },
1221    set lang(val) {
1222        return this.setAttribute("lang",val);
1223    },
1224    get offsetHeight(){
1225        return Number((this.style.height || '').replace("px",""));
1226    },
1227    get offsetWidth(){
1228        return Number((this.style.width || '').replace("px",""));
1229    },
1230    offsetLeft: 0,
1231    offsetRight: 0,
1232    get offsetParent(){
1233        /* TODO */
1234        return;
1235    },
1236    set offsetParent(element){
1237        /* TODO */
1238        return;
1239    },
1240    scrollHeight: 0,
1241    scrollWidth: 0,
1242    scrollLeft: 0,
1243    scrollRight: 0,
1244    get style(){
1245        return this.getAttribute('style')||'';
1246    },
1247    get title() {
1248        return this.getAttribute("title");
1249    },
1250    set title(value) {
1251        return this.setAttribute("title", value);
1252    },
1253    get tabIndex(){
1254        var tabindex = this.getAttribute('tabindex');
1255        if(tabindex!==null){
1256            return Number(tabindex);
1257        } else {
1258            return 0;
1259        }
1260    },
1261    set tabIndex(value){
1262        if (value === undefined || value === null) {
1263            value = 0;
1264        }
1265        this.setAttribute('tabindex',Number(value));
1266    },
1267    get outerHTML(){
1268        //Not in the specs but I'll leave it here for now.
1269        return this.xhtml;
1270    },
1271    scrollIntoView: function(){
1272        /*TODO*/
1273        return;
1274    },
1275    toString: function(){
1276        return '[object HTMLElement]';
1277    },
1278    get xhtml() {
1279        // HTMLDocument.xhtml is non-standard
1280        // This is exactly like Document.xml except the tagName has to be
1281        // lower cased.  I dont like to duplicate this but its really not
1282        // a simple work around between xml and html serialization via
1283        // XMLSerializer (which uppercases html tags) and innerHTML (which
1284        // lowercases tags)
1285
1286        var ret = "",
1287            ns = "",
1288            name = (this.tagName+"").toLowerCase(),
1289            attrs,
1290            attrstring = "",
1291                        style = false,
1292            i;
1293
1294        // serialize namespace declarations
1295        if (this.namespaceURI){
1296            if((this === this.ownerDocument.documentElement) ||
1297               (!this.parentNode) ||
1298               (this.parentNode &&
1299                (this.parentNode.namespaceURI !== this.namespaceURI))) {
1300                ns = ' xmlns' + (this.prefix ? (':' + this.prefix) : '') +
1301                    '="' + this.namespaceURI + '"';
1302            }
1303        }
1304
1305        // serialize Attribute declarations
1306        attrs = this.attributes;
1307        for(i=0;i< attrs.length;i++){
1308            attrstring += " "+attrs[i].name+'="'+attrs[i].xml+'"';
1309                        if(attrs[i].name == 'style'){
1310                                style = true;
1311                        }
1312        }
1313                if(!style ){
1314                        style = this.getAttribute('style');
1315                        if(style){
1316                                attrstring += ' style="'+style+'"';
1317                        }
1318                }
1319
1320        if(this.hasChildNodes()){
1321            // serialize this Element
1322                //console.log('serializing childNodes for %s', name);
1323            ret += "<" + name + ns + attrstring +">";
1324            for(i=0;i< this.childNodes.length;i++){
1325                //console.debug('xhtml for '+ this);
1326                ret += 'xhtml' in this.childNodes[i] ?
1327                    this.childNodes[i].xhtml :
1328                    this.childNodes[i].xml;
1329            }
1330            ret += "</" + name + ">";
1331        }else{ 
1332            //console.log('no childNodes to serialize for %s', name);
1333            switch(name){
1334            case 'script':
1335            case 'noscript':
1336                ret += "<" + name + ns + attrstring +"></"+name+">";
1337                break;
1338            default:
1339                ret += "<" + name + ns + attrstring +"/>";
1340            }
1341        }
1342
1343        return ret;
1344    },
1345
1346    /**
1347     * setAttribute use a dispatch table that other tags can set to
1348     *  "listen" to various values being set.  The dispatch table
1349     * and registration functions are at the end of the file.
1350     *
1351     */
1352
1353    setAttribute: function(name, value) {
1354        var result = __DOMElement__.prototype.setAttribute.apply(this, arguments);
1355        __addNamedMap__(this.ownerDocument, this);
1356        var tagname = this.tagName;
1357        var callback = HTMLElement.getAttributeCallback('set', tagname, name);
1358        if (callback) {
1359            callback(this, value);
1360        }
1361    },
1362    setAttributeNS: function(namespaceURI, name, value) {
1363        var result = __DOMElement__.prototype.setAttributeNS.apply(this, arguments);
1364        __addNamedMap__(this.ownerDocument, this);
1365        var tagname = this.tagName;
1366        var callback = HTMLElement.getAttributeCallback('set', tagname, name);
1367        if (callback) {
1368            callback(this, value);
1369        }
1370
1371        return result;
1372    },
1373    setAttributeNode: function(newnode) {
1374        var result = __DOMElement__.prototype.setAttributeNode.apply(this, arguments);
1375        __addNamedMap__(this.ownerDocument, this);
1376        var tagname = this.tagName;
1377        var callback = HTMLElement.getAttributeCallback('set', tagname, newnode.name);
1378        if (callback) {
1379            callback(this, newnode.value);
1380        }
1381        return result;
1382    },
1383    setAttributeNodeNS: function(newnode) {
1384        var result = __DOMElement__.prototype.setAttributeNodeNS.apply(this, arguments);
1385        __addNamedMap__(this.ownerDocument, this);
1386        var tagname = this.tagName;
1387        var callback = HTMLElement.getAttributeCallback('set', tagname, newnode.name);
1388        if (callback) {
1389            callback(this, newnode.value);
1390        }
1391        return result;
1392    },
1393    removeAttribute: function(name) {
1394        __removeNamedMap__(this.ownerDocument, this);
1395        return __DOMElement__.prototype.removeAttribute.apply(this, arguments);
1396    },
1397    removeAttributeNS: function(namespace, localname) {
1398        __removeNamedMap__(this.ownerDocument, this);
1399        return __DOMElement__.prototype.removeAttributeNS.apply(this, arguments);
1400    },
1401    removeAttributeNode: function(name) {
1402        __removeNamedMap__(this.ownerDocument, this);
1403        return __DOMElement__.prototype.removeAttributeNode.apply(this, arguments);
1404    },
1405    removeChild: function(oldChild) {
1406        __removeNamedMap__(this.ownerDocument, oldChild);
1407        return __DOMElement__.prototype.removeChild.apply(this, arguments);
1408    },
1409    importNode: function(othernode, deep) {
1410        var newnode = __DOMElement__.prototype.importNode.apply(this, arguments);
1411        __addNamedMap__(this.ownerDocument, newnode);
1412        return newnode;
1413    },
1414
1415    // not actually sure if this is needed or not
1416    replaceNode: function(newchild, oldchild) {
1417        var newnode = __DOMElement__.prototype.replaceNode.apply(this, arguments);
1418        __removeNamedMap__(this.ownerDocument, oldchild);
1419        __addNamedMap__(this.ownerDocument, newnode);
1420                return newnode;
1421    }
1422});
1423
1424
1425HTMLElement.attributeCallbacks = {};
1426HTMLElement.registerSetAttribute = function(tag, attrib, callbackfn) {
1427    HTMLElement.attributeCallbacks[tag + ':set:' + attrib] = callbackfn;
1428};
1429HTMLElement.registerRemoveAttribute = function(tag, attrib, callbackfn) {
1430    HTMLElement.attributeCallbacks[tag + ':remove:' + attrib] = callbackfn;
1431};
1432
1433/**
1434 * This is really only useful internally
1435 *
1436 */
1437HTMLElement.getAttributeCallback = function(type, tag, attrib) {
1438    return HTMLElement.attributeCallbacks[tag + ':' + type + ':' + attrib] || null;
1439};
1440
1441}(/*HTMLElement*/));
1442/*
1443 * HTMLCollection
1444 *
1445 * HTML5 -- 2.7.2.1 HTMLCollection
1446 * http://dev.w3.org/html5/spec/Overview.html#htmlcollection
1447 * http://dev.w3.org/html5/spec/Overview.html#collections
1448 */
1449 
1450(function(){
1451   
1452var log = Envjs.logger();
1453
1454Envjs.once('tick', function(){
1455    log = Envjs.logger('Envjs.HTML.HTMLCollection').
1456                debug('HTMLCollection available');   
1457});
1458
1459exports.HTMLCollection = HTMLCollection = function(nodelist, type) {
1460        __extend__(nodelist,{
1461                namedItem: function (name) {
1462                return this[name] || null;
1463            },
1464
1465            toString: function() {
1466                return '[object HTMLCollection]';
1467            }
1468        });
1469    var n;
1470    for (var i=0; i<nodelist.length; i++) {
1471        n = nodelist[i].id;
1472        if (n && !nodelist[n]) {
1473            nodelist[n] = nodelist[i];
1474        }
1475        n = nodelist[i].name;
1476        if (n && !nodelist[n]) {
1477            nodelist[n] = nodelist[i];
1478        }
1479    }
1480        return nodelist;
1481};
1482
1483HTMLCollection.prototype = new NodeList();
1484__extend__(HTMLCollection.prototype, {
1485
1486    namedItem: function (name) {
1487        return this[name] || null;
1488    },
1489
1490    toString: function() {
1491        return '[object HTMLCollection]';
1492    }
1493});
1494
1495}(/*Envjs.HTML.HTMLCollection*/));
1496
1497/*
1498 *  a set of convenience classes to centralize implementation of
1499 * properties and methods across multiple in-form elements
1500 *
1501 *  the hierarchy of related HTML elements and their members is as follows:
1502 *
1503 * Condensed Version
1504 *
1505 *  HTMLInputCommon
1506 *     * legent (no value attr)
1507 *     * fieldset (no value attr)
1508 *     * label (no value attr)
1509 *     * option (custom value)
1510 *  HTMLTypeValueInputs (extends InputCommon)
1511 *     * select  (custom value)
1512 *     * button (just sets value)
1513 *  HTMLInputAreaCommon (extends TypeValueIput)
1514 *     * input  (custom)
1515 *     * textarea (just sets value)
1516 *
1517 * -----------------------
1518 *    HTMLInputCommon:  common to all elements
1519 *       .form
1520 *
1521 *    <legend>
1522 *          [common plus:]
1523 *       .align
1524 *
1525 *    <fieldset>
1526 *          [identical to "legend" plus:]
1527 *       .margin
1528 *
1529 *
1530 *  ****
1531 *
1532 *    <label>
1533 *          [common plus:]
1534 *       .dataFormatAs
1535 *       .htmlFor
1536 *       [plus data properties]
1537 *
1538 *    <option>
1539 *          [common plus:]
1540 *       .defaultSelected
1541 *       .index
1542 *       .label
1543 *       .selected
1544 *       .text
1545 *       .value   // unique implementation, not duplicated
1546 *       .form    // unique implementation, not duplicated
1547 *  ****
1548 *
1549 *    HTMLTypeValueInputs:  common to remaining elements
1550 *          [common plus:]
1551 *       .name
1552 *       .type
1553 *       .value
1554 *       [plus data properties]
1555 *
1556 *
1557 *    <select>
1558 *       .length
1559 *       .multiple
1560 *       .options[]
1561 *       .selectedIndex
1562 *       .add()
1563 *       .remove()
1564 *       .item()                                       // unimplemented
1565 *       .namedItem()                                  // unimplemented
1566 *       [plus ".onchange"]
1567 *       [plus focus events]
1568 *       [plus data properties]
1569 *       [plus ".size"]
1570 *
1571 *    <button>
1572 *       .dataFormatAs   // duplicated from above, oh well....
1573 *       [plus ".status", ".createTextRange()"]
1574 *
1575 *  ****
1576 *
1577 *    HTMLInputAreaCommon:  common to remaining elements
1578 *       .defaultValue
1579 *       .readOnly
1580 *       .handleEvent()                                // unimplemented
1581 *       .select()
1582 *       .onselect
1583 *       [plus ".size"]
1584 *       [plus ".status", ".createTextRange()"]
1585 *       [plus focus events]
1586 *       [plus ".onchange"]
1587 *
1588 *    <textarea>
1589 *       .cols
1590 *       .rows
1591 *       .wrap                                         // unimplemented
1592 *       .onscroll                                     // unimplemented
1593 *
1594 *    <input>
1595 *       .alt
1596 *       .accept                                       // unimplemented
1597 *       .checked
1598 *       .complete                                     // unimplemented
1599 *       .defaultChecked
1600 *       .dynsrc                                       // unimplemented
1601 *       .height
1602 *       .hspace                                       // unimplemented
1603 *       .indeterminate                                // unimplemented
1604 *       .loop                                         // unimplemented
1605 *       .lowsrc                                       // unimplemented
1606 *       .maxLength
1607 *       .src
1608 *       .start                                        // unimplemented
1609 *       .useMap
1610 *       .vspace                                       // unimplemented
1611 *       .width
1612 *       .onclick
1613 *       [plus ".size"]
1614 *       [plus ".status", ".createTextRange()"]
1615
1616 *    [data properties]                                // unimplemented
1617 *       .dataFld
1618 *       .dataSrc
1619
1620 *    [status stuff]                                   // unimplemented
1621 *       .status
1622 *       .createTextRange()
1623
1624 *    [focus events]
1625 *       .onblur
1626 *       .onfocus
1627
1628 */
1629
1630
1631
1632var inputElements_dataProperties = {};
1633var inputElements_status = {};
1634
1635var inputElements_onchange = {
1636    onchange: function(event){
1637        __eval__(this.getAttribute('onchange')||'', this);
1638    }
1639};
1640
1641var inputElements_size = {
1642    get size(){
1643        return Number(this.getAttribute('size'));
1644    },
1645    set size(value){
1646        this.setAttribute('size',value);
1647    }
1648};
1649
1650var inputElements_focusEvents = {
1651    blur: function(){
1652        __blur__(this);
1653
1654        if (this._oldValue != this.value){
1655            var event = document.createEvent("HTMLEvents");
1656            event.initEvent("change", true, true);
1657            this.dispatchEvent( event );
1658        }
1659    },
1660    focus: function(){
1661        __focus__(this);
1662        this._oldValue = this.value;
1663    }
1664};
1665
1666
1667/*
1668* HTMLInputCommon - convenience class, not DOM
1669*/
1670var HTMLInputCommon = function(ownerDocument) {
1671    HTMLElement.apply(this, arguments);
1672};
1673HTMLInputCommon.prototype = new HTMLElement();
1674__extend__(HTMLInputCommon.prototype, {
1675    get form() {
1676        // parent can be null if element is outside of a form
1677        // or not yet added to the document
1678        var parent = this.parentNode;
1679        while (parent && parent.nodeName.toLowerCase() !== 'form') {
1680            parent = parent.parentNode;
1681        }
1682        return parent;
1683    },
1684    get accessKey(){
1685        return this.getAttribute('accesskey');
1686    },
1687    set accessKey(value){
1688        this.setAttribute('accesskey',value);
1689    },
1690    get access(){
1691        return this.getAttribute('access');
1692    },
1693    set access(value){
1694        this.setAttribute('access', value);
1695    },
1696    get disabled(){
1697        return (this.getAttribute('disabled') === 'disabled');
1698    },
1699    set disabled(value){
1700        this.setAttribute('disabled', (value ? 'disabled' :''));
1701    }
1702});
1703
1704
1705
1706
1707/*
1708* HTMLTypeValueInputs - convenience class, not DOM
1709*/
1710var HTMLTypeValueInputs = function(ownerDocument) {
1711
1712    HTMLInputCommon.apply(this, arguments);
1713
1714    this._oldValue = "";
1715};
1716HTMLTypeValueInputs.prototype = new HTMLInputCommon();
1717__extend__(HTMLTypeValueInputs.prototype, inputElements_size);
1718__extend__(HTMLTypeValueInputs.prototype, inputElements_status);
1719__extend__(HTMLTypeValueInputs.prototype, inputElements_dataProperties);
1720__extend__(HTMLTypeValueInputs.prototype, {
1721    get name(){
1722        return this.getAttribute('name')||'';
1723    },
1724    set name(value){
1725        this.setAttribute('name',value);
1726    }
1727});
1728
1729
1730/*
1731* HTMLInputAreaCommon - convenience class, not DOM
1732*/
1733var HTMLInputAreaCommon = function(ownerDocument) {
1734    HTMLTypeValueInputs.apply(this, arguments);
1735};
1736HTMLInputAreaCommon.prototype = new HTMLTypeValueInputs();
1737__extend__(HTMLInputAreaCommon.prototype, inputElements_focusEvents);
1738__extend__(HTMLInputAreaCommon.prototype, inputElements_onchange);
1739__extend__(HTMLInputAreaCommon.prototype, {
1740    get readOnly(){
1741        return (this.getAttribute('readonly')=='readonly');
1742    },
1743    set readOnly(value){
1744        this.setAttribute('readonly', (value ? 'readonly' :''));
1745    },
1746    select:function(){
1747        __select__(this);
1748
1749    }
1750});
1751
1752
1753var __updateFormForNamedElement__ = function(node, value) {
1754    if (node.form) {
1755        // to check for ID or NAME attribute too
1756        // not, then nothing to do
1757
1758                //THATCHER - I believe this is deprecated by the new
1759                //internally managed indexes on elements
1760        //node.form._updateElements();
1761    }
1762};
1763
1764/**
1765 * HTMLAnchorElement - DOM Level 2
1766 *
1767 * HTML5: 4.6.1 The a element
1768 * http://dev.w3.org/html5/spec/Overview.html#the-a-element
1769 */
1770 
1771(function(){
1772   
1773var log = Envjs.logger();
1774
1775Envjs.once('tick', function(){
1776    log = Envjs.logger('Envjs.HTML.HTMLAnchorElement').
1777                debug('HTMLAnchorElement available');   
1778});
1779
1780exports.HTMLAnchorElement = HTMLAnchorElement = function(ownerDocument) {
1781    HTMLElement.apply(this, arguments);
1782};
1783HTMLAnchorElement.prototype = new HTMLElement();
1784__extend__(HTMLAnchorElement.prototype, {
1785    get accessKey() {
1786        return this.getAttribute("accesskey")||'';
1787    },
1788    set accessKey(val) {
1789        return this.setAttribute("accesskey",val);
1790    },
1791    get charset() {
1792        return this.getAttribute("charset")||'';
1793    },
1794    set charset(val) {
1795        return this.setAttribute("charset",val);
1796    },
1797    get coords() {
1798        return this.getAttribute("coords")||'';
1799    },
1800    set coords(val) {
1801        return this.setAttribute("coords",val);
1802    },
1803    get href() {
1804        var link = this.getAttribute('href');
1805        if (!link) {
1806            return '';
1807        }
1808        return Envjs.uri(link, this.ownerDocument.location.toString());
1809    },
1810    set href(val) {
1811        return this.setAttribute("href", val);
1812    },
1813    get hreflang() {
1814        return this.getAttribute("hreflang")||'';
1815    },
1816    set hreflang(val) {
1817        this.setAttribute("hreflang",val);
1818    },
1819    get name() {
1820        return this.getAttribute("name")||'';
1821    },
1822    set name(val) {
1823        this.setAttribute("name",val);
1824    },
1825    get rel() {
1826        return this.getAttribute("rel")||'';
1827    },
1828    set rel(val) {
1829        return this.setAttribute("rel", val);
1830    },
1831    get rev() {
1832        return this.getAttribute("rev")||'';
1833    },
1834    set rev(val) {
1835        return this.setAttribute("rev",val);
1836    },
1837    get shape() {
1838        return this.getAttribute("shape")||'';
1839    },
1840    set shape(val) {
1841        return this.setAttribute("shape",val);
1842    },
1843    get target() {
1844        return this.getAttribute("target")||'';
1845    },
1846    set target(val) {
1847        return this.setAttribute("target",val);
1848    },
1849    get type() {
1850        return this.getAttribute("type")||'';
1851    },
1852    set type(val) {
1853        return this.setAttribute("type",val);
1854    },
1855    blur: function() {
1856        __blur__(this);
1857    },
1858    focus: function() {
1859        __focus__(this);
1860    },
1861        click: function(){
1862                __click__(this);
1863        },
1864    /**
1865     * Unlike other elements, toString returns the href
1866     */
1867    toString: function() {
1868        return this.href;
1869    }
1870});
1871
1872}(/*Envjs.HTML.HTMLAnchorElement*/));
1873
1874/*
1875 * HTMLAreaElement - DOM Level 2
1876 *
1877 * HTML5: 4.8.13 The area element
1878 * http://dev.w3.org/html5/spec/Overview.html#the-area-element
1879 */
1880 
1881(function(){
1882   
1883var log = Envjs.logger();
1884
1885Envjs.once('tick', function(){
1886    log = Envjs.logger('Envjs.HTML.HTMLAreaElement').
1887                debug('HTMLAreaElement available');   
1888});
1889
1890exports.HTMLAreaElement = HTMLAreaElement = function(ownerDocument) {
1891    HTMLElement.apply(this, arguments);
1892};
1893HTMLAreaElement.prototype = new HTMLElement();
1894__extend__(HTMLAreaElement.prototype, {
1895    get accessKey(){
1896        return this.getAttribute('accesskey');
1897    },
1898    set accessKey(value){
1899        this.setAttribute('accesskey',value);
1900    },
1901    get alt(){
1902        return this.getAttribute('alt') || '';
1903    },
1904    set alt(value){
1905        this.setAttribute('alt',value);
1906    },
1907    get coords(){
1908        return this.getAttribute('coords');
1909    },
1910    set coords(value){
1911        this.setAttribute('coords',value);
1912    },
1913    get href(){
1914        return this.getAttribute('href') || '';
1915    },
1916    set href(value){
1917        this.setAttribute('href',value);
1918    },
1919    get noHref(){
1920        return this.hasAttribute('href');
1921    },
1922    get shape(){
1923        //TODO
1924        return 0;
1925    },
1926    /*get tabIndex(){
1927      return this.getAttribute('tabindex');
1928      },
1929      set tabIndex(value){
1930      this.setAttribute('tabindex',value);
1931      },*/
1932    get target(){
1933        return this.getAttribute('target');
1934    },
1935    set target(value){
1936        this.setAttribute('target',value);
1937    },
1938
1939    /**
1940     * toString like <a>, returns the href
1941     */
1942    toString: function() {
1943        return this.href;
1944    }
1945});
1946
1947}(/*Envjs.HTML.HTMLElement*/));
1948
1949/*
1950 * HTMLBaseElement - DOM Level 2
1951 *
1952 * HTML5: 4.2.3 The base element
1953 * http://dev.w3.org/html5/spec/Overview.html#the-base-element
1954 */
1955
1956(function(){
1957   
1958var log = Envjs.logger();
1959
1960Envjs.once('tick', function(){
1961    log = Envjs.logger('Envjs.HTML.HTMLBaseElement').
1962                debug('HTMLBaseElement available');   
1963});
1964
1965exports.HTMLBaseElement = HTMLBaseElement = function(ownerDocument) {
1966    HTMLElement.apply(this, arguments);
1967};
1968HTMLBaseElement.prototype = new HTMLElement();
1969__extend__(HTMLBaseElement.prototype, {
1970    get href(){
1971        return this.getAttribute('href');
1972    },
1973    set href(value){
1974        this.setAttribute('href',value);
1975    },
1976    get target(){
1977        return this.getAttribute('target');
1978    },
1979    set target(value){
1980        this.setAttribute('target',value);
1981    },
1982    toString: function() {
1983        return '[object HTMLBaseElement]';
1984    }
1985});
1986
1987}(/*Envjs.HTML.HTMLBaseElement*/));
1988
1989/*
1990 * HTMLQuoteElement - DOM Level 2
1991 * HTML5: 4.5.5 The blockquote element
1992 * http://dev.w3.org/html5/spec/Overview.html#htmlquoteelement
1993 */
1994 
1995(function(){
1996   
1997var log = Envjs.logger();
1998
1999Envjs.once('tick', function(){
2000    log = Envjs.logger('Envjs.HTML.HTMLQuoteElement').
2001                debug('HTMLQuoteElement available');   
2002});
2003
2004exports.HTMLQuoteElement = HTMLQuoteElement = function(ownerDocument) {
2005    HTMLElement.apply(this, arguments);
2006};
2007HTMLQuoteElement.prototype = new HTMLElement();
2008__extend__(HTMLQuoteElement.prototype, {
2009    /**
2010     * Quoth the spec:
2011     * """
2012     * If the cite attribute is present, it must be a valid URL. To
2013     * obtain the corresponding citation link, the value of the
2014     * attribute must be resolved relative to the element. User agents
2015     * should allow users to follow such citation links.
2016     * """
2017     *
2018     * TODO: normalize
2019     *
2020     */
2021    get cite() {
2022        return this.getAttribute('cite') || '';
2023    },
2024
2025    set cite(value) {
2026        this.setAttribute('cite', value);
2027    },
2028    toString: function() {
2029        return '[object HTMLQuoteElement]';
2030    }
2031});
2032
2033}(/*Envjs.HTML.HTMLQuoteElement*/));
2034
2035/*
2036 * HTMLBodyElement - DOM Level 2
2037 * HTML5: http://dev.w3.org/html5/spec/Overview.html#the-body-element-0
2038 */
2039 
2040(function(){
2041   
2042var log = Envjs.logger();
2043
2044Envjs.once('tick', function(){
2045    log = Envjs.logger('Envjs.HTML.HTMLBodyElement').
2046                debug('HTMLBodyElement available');   
2047});
2048
2049exports.HTMLBodyElement = HTMLBodyElement = function(ownerDocument) {
2050    HTMLElement.apply(this, arguments);
2051};
2052HTMLBodyElement.prototype = new HTMLElement();
2053__extend__(HTMLBodyElement.prototype, {
2054    onload: function(event){
2055        __eval__(this.getAttribute('onload')||'', this);
2056    },
2057    onunload: function(event){
2058        __eval__(this.getAttribute('onunload')||'', this);
2059    },
2060    toString: function() {
2061        return '[object HTMLBodyElement]';
2062    }
2063});
2064
2065}(/*Envjs.HTML.HTMLBodyElement*/));
2066
2067/*
2068 * HTMLBRElement
2069 * HTML5: 4.5.3 The hr Element
2070 * http://dev.w3.org/html5/spec/Overview.html#the-br-element
2071 */
2072 
2073(function(){
2074   
2075var log = Envjs.logger();
2076
2077Envjs.once('tick', function(){
2078    log = Envjs.logger('Envjs.HTML.HTMLBRElement').
2079                debug('HTMLBRElement available');   
2080});
2081
2082exports.HTMLBRElement = HTMLBRElement = function(ownerDocument) {
2083    HTMLElement.apply(this, arguments);
2084};
2085
2086HTMLBRElement.prototype = new HTMLElement();
2087__extend__(HTMLBRElement.prototype, {
2088
2089    // no additional properties or elements
2090    toString: function() {
2091        return '[object HTMLBRElement]';
2092    }
2093});
2094
2095}(/*Envjs.HTML.HTMLBRElement*/));
2096
2097/*
2098 * HTMLButtonElement - DOM Level 2
2099 *
2100 * HTML5: 4.10.6 The button element
2101 * http://dev.w3.org/html5/spec/Overview.html#the-button-element
2102 */
2103 
2104(function(){
2105   
2106var log = Envjs.logger();
2107
2108Envjs.once('tick', function(){
2109    log = Envjs.logger('Envjs.HTML.HTMLButtonElement').
2110                debug('HTMLButtonElement available');   
2111});
2112
2113exports.HTMLButtonElement = HTMLButtonElement = function(ownerDocument) {
2114    HTMLTypeValueInputs.apply(this, arguments);
2115};
2116HTMLButtonElement.prototype = new HTMLTypeValueInputs();
2117__extend__(HTMLButtonElement.prototype, inputElements_status);
2118__extend__(HTMLButtonElement.prototype, {
2119    get dataFormatAs(){
2120        return this.getAttribute('dataFormatAs');
2121    },
2122    set dataFormatAs(value){
2123        this.setAttribute('dataFormatAs',value);
2124    },
2125    get type() {
2126        return this.getAttribute('type') || 'submit';
2127    },
2128    set type(value) {
2129        this.setAttribute('type', value);
2130    },
2131    get value() {
2132        return this.getAttribute('value') || '';
2133    },
2134    set value(value) {
2135        this.setAttribute('value', value);
2136    },
2137    toString: function() {
2138        return '[object HTMLButtonElement]';
2139    }
2140});
2141
2142// Named Element Support
2143HTMLElement.registerSetAttribute('BUTTON', 'name', __updateFormForNamedElement__);
2144
2145}(/*Envjs.HTML.HTMLButtonElement*/));
2146
2147/*
2148 * HTMLCanvasElement - DOM Level 2
2149 * HTML5: 4.8.11 The canvas element
2150 * http://dev.w3.org/html5/spec/Overview.html#the-canvas-element
2151 */
2152
2153
2154(function(){
2155   
2156var log = Envjs.logger();
2157
2158Envjs.once('tick', function(){
2159    log = Envjs.logger('Envjs.HTML.CanvasRenderingContext2D').
2160                debug('CanvasRenderingContext2D available');   
2161});
2162/*
2163 * This is a "non-Abstract Base Class". For an implmentation that actually
2164 * did something, all these methods would need to over-written
2165 */
2166exports.CanvasRenderingContext2D = CanvasRenderingContext2D = function() {
2167    // NOP
2168};
2169
2170var nullfunction = function() {};
2171
2172CanvasRenderingContext2D.prototype = {
2173    addColorStop: nullfunction,
2174    arc: nullfunction,
2175    beginPath: nullfunction,
2176    bezierCurveTo: nullfunction,
2177    clearRect: nullfunction,
2178    clip: nullfunction,
2179    closePath: nullfunction,
2180    createLinearGradient: nullfunction,
2181    createPattern: nullfunction,
2182    createRadialGradient: nullfunction,
2183    drawImage: nullfunction,
2184    fill: nullfunction,
2185    fillRect:  nullfunction,
2186    lineTo: nullfunction,
2187    moveTo: nullfunction,
2188    quadraticCurveTo: nullfunction,
2189    rect: nullfunction,
2190    restore: nullfunction,
2191    rotate: nullfunction,
2192    save: nullfunction,
2193    scale: nullfunction,
2194    setTranform: nullfunction,
2195    stroke: nullfunction,
2196    strokeRect: nullfunction,
2197    transform: nullfunction,
2198    translate: nullfunction,
2199
2200    toString: function() {
2201        return '[object CanvasRenderingContext2D]';
2202    }
2203};
2204
2205}(/*Envjs.HTML.CanvasRenderingContext2D*/));
2206
2207
2208(function(){
2209   
2210var log = Envjs.logger();
2211
2212Envjs.once('tick', function(){
2213    log = Envjs.logger('Envjs.HTML.HTMLCanvasElement').
2214                debug('HTMLCanvasElement available');   
2215});
2216
2217exports.HTMLCanvasElement = HTMLCanvasElement = function(ownerDocument) {
2218    HTMLElement.apply(this, arguments);
2219};
2220HTMLCanvasElement.prototype = new HTMLElement();
2221__extend__(HTMLCanvasElement.prototype, {
2222
2223    getContext: function(ctxtype) {
2224        if (ctxtype === '2d') {
2225            return new CanvasRenderingContext2D();
2226        }
2227        throw new Error("Unknown context type of '" + ctxtype + '"');
2228    },
2229
2230    get height(){
2231        return Number(this.getAttribute('height')|| 150);
2232    },
2233    set height(value){
2234        this.setAttribute('height', value);
2235    },
2236
2237    get width(){
2238        return Number(this.getAttribute('width')|| 300);
2239    },
2240    set width(value){
2241        this.setAttribute('width', value);
2242    },
2243
2244    toString: function() {
2245        return '[object HTMLCanvasElement]';
2246    }
2247
2248});
2249
2250}(/*Envjs.HTML.HTMLCanvasElement*/));
2251
2252
2253/*
2254* HTMLTableColElement - DOM Level 2
2255*
2256* HTML5: 4.9.3 The colgroup element
2257* http://dev.w3.org/html5/spec/Overview.html#the-colgroup-element
2258*/
2259
2260(function(){
2261   
2262var log = Envjs.logger();
2263
2264Envjs.once('tick', function(){
2265    log = Envjs.logger('Envjs.HTML.HTMLTableColElement').
2266                debug('HTMLTableColElement available');   
2267});
2268
2269exports.HTMLTableColElement = HTMLTableColElement = function(ownerDocument) {
2270    HTMLElement.apply(this, arguments);
2271};
2272HTMLTableColElement.prototype = new HTMLElement();
2273__extend__(HTMLTableColElement.prototype, {
2274    get align(){
2275        return this.getAttribute('align');
2276    },
2277    set align(value){
2278        this.setAttribute('align', value);
2279    },
2280    get ch(){
2281        return this.getAttribute('ch');
2282    },
2283    set ch(value){
2284        this.setAttribute('ch', value);
2285    },
2286    get chOff(){
2287        return this.getAttribute('ch');
2288    },
2289    set chOff(value){
2290        this.setAttribute('ch', value);
2291    },
2292    get span(){
2293        return this.getAttribute('span');
2294    },
2295    set span(value){
2296        this.setAttribute('span', value);
2297    },
2298    get vAlign(){
2299        return this.getAttribute('valign');
2300    },
2301    set vAlign(value){
2302        this.setAttribute('valign', value);
2303    },
2304    get width(){
2305        return this.getAttribute('width');
2306    },
2307    set width(value){
2308        this.setAttribute('width', value);
2309    },
2310    toString: function() {
2311        return '[object HTMLTableColElement]';
2312    }
2313});
2314
2315}(/*Envjs.HTML.HTMLTableColElement*/));
2316
2317
2318/*
2319 * HTMLModElement - DOM Level 2
2320 * http://dev.w3.org/html5/spec/Overview.html#htmlmodelement
2321 */
2322 
2323(function(){
2324   
2325var log = Envjs.logger();
2326
2327Envjs.once('tick', function(){
2328    log = Envjs.logger('Envjs.HTML.HTMLModElement').
2329                debug('HTMLModElement available');   
2330});
2331
2332exports.HTMLModElement = HTMLModElement = function(ownerDocument) {
2333    HTMLElement.apply(this, arguments);
2334};
2335HTMLModElement.prototype = new HTMLElement();
2336__extend__(HTMLModElement.prototype, {
2337    get cite(){
2338        return this.getAttribute('cite');
2339    },
2340    set cite(value){
2341        this.setAttribute('cite', value);
2342    },
2343    get dateTime(){
2344        return this.getAttribute('datetime');
2345    },
2346    set dateTime(value){
2347        this.setAttribute('datetime', value);
2348    },
2349    toString: function() {
2350        return '[object HTMLModElement]';
2351    }
2352});
2353
2354}(/*Envjs.HTML.HTMLModElement*/));
2355
2356/*
2357 * HTMLDivElement - DOM Level 2
2358 * HTML5: 4.5.12 The Div Element
2359 * http://dev.w3.org/html5/spec/Overview.html#the-div-element
2360 */
2361(function(){
2362   
2363var log = Envjs.logger();
2364
2365Envjs.once('tick', function(){
2366    log = Envjs.logger('Envjs.HTML.HTMLDivElement').
2367                debug('HTMLDivElement available');   
2368});
2369
2370exports.HTMLDivElement = HTMLDivElement = function(ownerDocument) {
2371    HTMLElement.apply(this, arguments);
2372};
2373
2374HTMLDivElement.prototype = new HTMLElement();
2375__extend__(HTMLDivElement.prototype, {
2376    get align(){
2377        return this.getAttribute('align') || 'left';
2378    },
2379    set align(value){
2380        this.setAttribute('align', value);
2381    },
2382    toString: function() {
2383        return '[object HTMLDivElement]';
2384    }
2385});
2386
2387}(/*HTMLDivElement*/));
2388
2389/*
2390 * HTMLDListElement
2391 * HTML5: 4.5.7 The dl Element
2392 * http://dev.w3.org/html5/spec/Overview.html#the-dl-element
2393 */
2394 
2395(function(){
2396   
2397var log = Envjs.logger();
2398
2399Envjs.once('tick', function(){
2400    log = Envjs.logger('Envjs.HTML.HTMLDListElement').
2401                debug('HTMLDListElement available');   
2402});
2403
2404exports.HTMLDListElement = HTMLDListElement = function(ownerDocument) {
2405    HTMLElement.apply(this, arguments);
2406};
2407
2408HTMLDListElement.prototype = new HTMLElement();
2409__extend__(HTMLDListElement.prototype, {
2410
2411    // no additional properties or elements
2412
2413    toString: function() {
2414        return '[object HTMLDListElement]';
2415    }
2416});
2417
2418}(/*HTMLDListElement*/));
2419
2420/**
2421 * HTMLLegendElement - DOM Level 2
2422 *
2423 * HTML5: 4.10.3 The legend element
2424 * http://dev.w3.org/html5/spec/Overview.html#the-legend-element
2425 */
2426 
2427(function(){
2428   
2429var log = Envjs.logger();
2430
2431Envjs.once('tick', function(){
2432    log = Envjs.logger('Envjs.HTML.HTMLLegendElement').
2433                debug('HTMLLegendElement available');   
2434});
2435
2436exports.HTMLLegendElement = HTMLLegendElement = function(ownerDocument) {
2437    HTMLInputCommon.apply(this, arguments);
2438};
2439HTMLLegendElement.prototype = new HTMLInputCommon();
2440__extend__(HTMLLegendElement.prototype, {
2441    get align(){
2442        return this.getAttribute('align');
2443    },
2444    set align(value){
2445        this.setAttribute('align',value);
2446    }
2447});
2448
2449}(/*HTMLLegendElement*/));
2450
2451/*
2452 * HTMLFieldSetElement - DOM Level 2
2453 *
2454 * HTML5: 4.10.2 The fieldset element
2455 * http://dev.w3.org/html5/spec/Overview.html#the-fieldset-element
2456 */
2457 
2458(function(){
2459   
2460var log = Envjs.logger();
2461
2462Envjs.once('tick', function(){
2463    log = Envjs.logger('Envjs.HTML.HTMLFieldSetElement').
2464                debug('HTMLFieldSetElement available');   
2465});
2466
2467exports.HTMLFieldSetElement = HTMLFieldSetElement = function(ownerDocument) {
2468    HTMLLegendElement.apply(this, arguments);
2469};
2470HTMLFieldSetElement.prototype = new HTMLLegendElement();
2471__extend__(HTMLFieldSetElement.prototype, {
2472    get margin(){
2473        return this.getAttribute('margin');
2474    },
2475    set margin(value){
2476        this.setAttribute('margin',value);
2477    },
2478    toString: function() {
2479        return '[object HTMLFieldSetElement]';
2480    }
2481});
2482
2483// Named Element Support
2484HTMLElement.registerSetAttribute('FIELDSET', 'name', __updateFormForNamedElement__);
2485
2486}(/*HTMLFieldSetElement*/));
2487
2488/*
2489 * HTMLFormElement - DOM Level 2
2490 *
2491 * HTML5: http://dev.w3.org/html5/spec/Overview.html#the-form-element
2492 */
2493 
2494(function(){
2495   
2496var log = Envjs.logger();
2497
2498Envjs.once('tick', function(){
2499    log = Envjs.logger('Envjs.HTML.HTMLFormElement').
2500                debug('HTMLFormElement available');   
2501});
2502
2503exports.HTMLFormElement = HTMLFormElement = function(ownerDocument){
2504    HTMLElement.apply(this, arguments);
2505
2506    //TODO: on __elementPopped__ from the parser
2507    //      we need to determine all the forms default
2508    //      values
2509};
2510HTMLFormElement.prototype = new HTMLElement();
2511__extend__(HTMLFormElement.prototype,{
2512    get acceptCharset(){
2513        return this.getAttribute('accept-charset');
2514    },
2515    set acceptCharset(acceptCharset) {
2516        this.setAttribute('accept-charset', acceptCharset);
2517    },
2518    get action() {
2519        return this.getAttribute('action');
2520    },
2521    set action(action){
2522        this.setAttribute('action', action);
2523    },
2524
2525    get enctype() {
2526        return this.getAttribute('enctype');
2527    },
2528    set enctype(enctype) {
2529        this.setAttribute('enctype', enctype);
2530    },
2531    get method() {
2532        return this.getAttribute('method');
2533    },
2534    set method(method) {
2535        this.setAttribute('method', method);
2536    },
2537    get name() {
2538        return this.getAttribute("name");
2539    },
2540    set name(val) {
2541        return this.setAttribute("name",val);
2542    },
2543    get target() {
2544        return this.getAttribute("target");
2545    },
2546    set target(val) {
2547        return this.setAttribute("target",val);
2548    },
2549
2550    /**
2551     * "Named Elements"
2552     *
2553     */
2554    /**
2555     * returns HTMLFormControlsCollection
2556     * http://dev.w3.org/html5/spec/Overview.html#dom-form-elements
2557     *
2558     * button fieldset input keygen object output select textarea
2559     */
2560    get elements() {
2561        var nodes = this.getElementsByTagName('*');
2562        var alist = new NodeList(this.ownerDocument, this);
2563        var i, tmp;
2564        for (i = 0; i < nodes.length; ++i) {
2565            // would like to replace switch with something else
2566            //  since it's redundant with the SetAttribute callbacks
2567            switch (nodes[i].nodeName) {
2568            case 'BUTTON':
2569            case 'FIELDSET':
2570            case 'INPUT':
2571            case 'KEYGEN':
2572            case 'OBJECT':
2573            case 'OUTPUT':
2574            case 'SELECT':
2575            case 'TEXTAREA':
2576                alist.push(nodes[i]);
2577                this[i] = nodes[i];
2578                tmp = nodes[i].name;
2579                if (tmp) {
2580                    this[tmp] = nodes[i];
2581                }
2582                tmp = nodes[i].id;
2583                if (tmp) {
2584                    this[tmp] = nodes[i];
2585                }
2586            }
2587        }
2588        return new HTMLCollection(alist);
2589    },
2590    _updateElements: function() {
2591        var elm = this.elements;
2592    },
2593   
2594    /*get elements() {
2595        //console.log('getting form input type elements.');
2596        if(!(this._indexes_['$elements'])){
2597                        this._indexes_['$elements'] = new NodeList(this.ownerDocument, null);
2598                }
2599        return new HTMLCollection(this._indexes_['$elements']);
2600    },*/
2601    get length() {
2602        return this.elements.length;
2603    },
2604    item: function(idx) {
2605        return this.elements[idx];
2606    },
2607    namedItem: function(aname) {
2608        return this.elements.namedItem(aname);
2609    },
2610    toString: function() {
2611        return '[object HTMLFormElement]';
2612    },
2613    submit: function() {
2614        var event = __submit__(this);
2615    },
2616    reset: function() {
2617        //TODO: this needs to reset all values specified in the form
2618        //      to those which where set as defaults
2619        __reset__(this);
2620    },
2621    onsubmit: HTMLEvents.prototype.onsubmit,
2622    onreset: HTMLEvents.prototype.onreset
2623});
2624
2625}(/*HTMLFormElement*/));
2626
2627/**
2628 * HTMLFrameElement - DOM Level 2
2629 */
2630 
2631(function(){
2632   
2633var log = Envjs.logger();
2634
2635Envjs.once('tick', function(){
2636    log = Envjs.logger('Envjs.HTML.HTMLFrameElement').debug('HTMLFrameElement available');   
2637});
2638
2639exports.HTMLFrameElement = HTMLFrameElement = function(ownerDocument) {
2640    HTMLElement.apply(this, arguments);
2641    // this is normally a getter but we need to be
2642    // able to set it to correctly emulate behavior
2643    this.contentDocument = null;
2644    this.contentWindow = null;
2645};
2646HTMLFrameElement.prototype = new HTMLElement();
2647__extend__(HTMLFrameElement.prototype, {
2648
2649    get frameBorder(){
2650        return this.getAttribute('border')||"";
2651    },
2652    set frameBorder(value){
2653        this.setAttribute('border', value);
2654    },
2655    get longDesc(){
2656        return this.getAttribute('longdesc')||"";
2657    },
2658    set longDesc(value){
2659        this.setAttribute('longdesc', value);
2660    },
2661    get marginHeight(){
2662        return this.getAttribute('marginheight')||"";
2663    },
2664    set marginHeight(value){
2665        this.setAttribute('marginheight', value);
2666    },
2667    get marginWidth(){
2668        return this.getAttribute('marginwidth')||"";
2669    },
2670    set marginWidth(value){
2671        this.setAttribute('marginwidth', value);
2672    },
2673    get name(){
2674        return this.getAttribute('name')||"";
2675    },
2676    set name(value){
2677        this.setAttribute('name', value);
2678    },
2679    get noResize(){
2680        return this.getAttribute('noresize')||false;
2681    },
2682    set noResize(value){
2683        this.setAttribute('noresize', value);
2684    },
2685    get scrolling(){
2686        return this.getAttribute('scrolling')||"";
2687    },
2688    set scrolling(value){
2689        this.setAttribute('scrolling', value);
2690    },
2691    get src(){
2692        return this.getAttribute('src')||"";
2693    },
2694    set src(value){
2695        this.setAttribute('src', value);
2696    },
2697    toString: function(){
2698        return '[object HTMLFrameElement]';
2699    },
2700    onload: HTMLEvents.prototype.onload
2701});
2702
2703}(/*HTMLFrameElement*/));
2704/**
2705 * HTMLFrameSetElement - DOM Level 2
2706 *
2707 * HTML5: 12.3.3 Frames
2708 * http://dev.w3.org/html5/spec/Overview.html#frameset
2709 */
2710(function(){
2711   
2712var log = Envjs.logger();
2713
2714Envjs.once('tick', function(){
2715    log = Envjs.logger('Envjs.HTML.HTMLFrameSetElement').debug('HTMLFrameSetElement available');   
2716});
2717
2718exports.HTMLFrameSetElement = HTMLFrameSetElement = function(ownerDocument) {
2719    HTMLElement.apply(this, arguments);
2720};
2721HTMLFrameSetElement.prototype = new HTMLElement();
2722__extend__(HTMLFrameSetElement.prototype, {
2723    get cols(){
2724        return this.getAttribute('cols');
2725    },
2726    set cols(value){
2727        this.setAttribute('cols', value);
2728    },
2729    get rows(){
2730        return this.getAttribute('rows');
2731    },
2732    set rows(value){
2733        this.setAttribute('rows', value);
2734    },
2735    toString: function() {
2736        return '[object HTMLFrameSetElement]';
2737    }
2738});
2739
2740}(/*HTMLFrameSetElement*/));
2741
2742/*
2743 * HTMLHeadingElement
2744 * HTML5: 4.4.6 The h1, h2, h3, h4, h5, and h6 elements
2745 * http://dev.w3.org/html5/spec/Overview.html#the-h1-h2-h3-h4-h5-and-h6-elements
2746 */
2747 
2748(function(){
2749   
2750var log = Envjs.logger();
2751
2752Envjs.once('tick', function(){
2753    log = Envjs.logger('Envjs.HTML.HTMLHeadingElement').
2754                debug('HTMLHeadingElement available');   
2755});
2756
2757exports.HTMLHeadingElement = HTMLHeadingElement = function(ownerDocument) {
2758    HTMLElement.apply(this, arguments);
2759};
2760
2761HTMLHeadingElement.prototype = new HTMLElement();
2762__extend__(HTMLHeadingElement.prototype, {
2763    toString: function() {
2764        return '[object HTMLHeadingElement]';
2765    }
2766});
2767
2768}(/*HTMLHeadingElement*/));
2769
2770/**
2771 * HTMLHeadElement - DOM Level 2
2772 *
2773 * HTML5: 4.2.1 The head element
2774 * http://dev.w3.org/html5/spec/Overview.html#the-head-element-0
2775 */
2776(function(){
2777   
2778var log = Envjs.logger();
2779
2780Envjs.once('tick', function(){
2781    log = Envjs.logger('Envjs.HTML.HTMLHeadElement').
2782                debug('HTMLHeadElement available');   
2783});
2784
2785exports.HTMLHeadElement = HTMLHeadElement = function(ownerDocument) {
2786    HTMLElement.apply(this, arguments);
2787};
2788HTMLHeadElement.prototype = new HTMLElement();
2789__extend__(HTMLHeadElement.prototype, {
2790    get profile(){
2791        return this.getAttribute('profile');
2792    },
2793    set profile(value){
2794        this.setAttribute('profile', value);
2795    },
2796    toString: function(){
2797        return '[object HTMLHeadElement]';
2798    }
2799});
2800
2801}(/*HTMLHeadElement*/));
2802
2803/*
2804 * HTMLHRElement
2805 * HTML5: 4.5.2 The hr Element
2806 * http://dev.w3.org/html5/spec/Overview.html#the-hr-element
2807 */
2808 
2809(function(){
2810   
2811var log = Envjs.logger();
2812
2813Envjs.once('tick', function(){
2814    log = Envjs.logger('Envjs.HTML.HTMLHRElement').
2815                debug('HTMLHRElement available');   
2816});
2817
2818exports.HTMLHRElement = HTMLHRElement = function(ownerDocument) {
2819    HTMLElement.apply(this, arguments);
2820};
2821
2822HTMLHRElement.prototype = new HTMLElement();
2823__extend__(HTMLHRElement.prototype, {
2824    // no additional properties or elements
2825    toString: function() {
2826        return '[object HTMLHRElement]';
2827    }
2828});
2829
2830}(/*HTMLHRElement*/));
2831
2832/*
2833 * HTMLHtmlElement
2834 * HTML5: 4.1.1 The Html Element
2835 * http://dev.w3.org/html5/spec/Overview.html#htmlhtmlelement
2836 */
2837 
2838(function(){
2839   
2840var log = Envjs.logger();
2841
2842Envjs.once('tick', function(){
2843    log = Envjs.logger('Envjs.HTML.HTMLHtmlElement').
2844                debug('HTMLHtmlElement available');   
2845});
2846
2847exports.HTMLHtmlElement = HTMLHtmlElement = function(ownerDocument) {
2848    HTMLElement.apply(this, arguments);
2849};
2850
2851HTMLHtmlElement.prototype = new HTMLElement();
2852__extend__(HTMLHtmlElement.prototype, {
2853
2854    // no additional properties or elements
2855    toString: function() {
2856        return '[object HTMLHtmlElement]';
2857    }
2858});
2859
2860}(/*HTMLHtmlElement*/));
2861
2862/*
2863 * HTMLIFrameElement - DOM Level 2
2864 *
2865 * HTML5: 4.8.3 The iframe element
2866 * http://dev.w3.org/html5/spec/Overview.html#the-iframe-element
2867 */
2868 
2869(function(){
2870   
2871var log = Envjs.logger();
2872
2873Envjs.once('tick', function(){
2874    log = Envjs.logger('Envjs.HTML.HTMLIFrameElement').
2875                debug('HTMLIFrameElement available');   
2876});
2877
2878exports.HTMLIFrameElement = HTMLIFrameElement = function(ownerDocument) {
2879    HTMLFrameElement.apply(this, arguments);
2880};
2881HTMLIFrameElement.prototype = new HTMLFrameElement();
2882__extend__(HTMLIFrameElement.prototype, {
2883    get height() {
2884        return this.getAttribute("height") || "";
2885    },
2886    set height(val) {
2887        return this.setAttribute("height",val);
2888    },
2889    get width() {
2890        return this.getAttribute("width") || "";
2891    },
2892    set width(val) {
2893        return this.setAttribute("width",val);
2894    },
2895    toString: function(){
2896        return '[object HTMLIFrameElement]';
2897    }
2898});
2899
2900}(/*HTMLIFrameElement*/));
2901
2902/**
2903 * HTMLImageElement and Image
2904 */
2905
2906(function(){
2907   
2908var log = Envjs.logger();
2909
2910Envjs.once('tick', function(){
2911    log = Envjs.logger('Envjs.HTML.HTMLImageElement').debug('HTMLImageElement available');   
2912});
2913
2914exports.HTMLImageElement = HTMLImageElement = function(ownerDocument) {
2915    HTMLElement.apply(this, arguments);
2916};
2917HTMLImageElement.prototype = new HTMLElement();
2918__extend__(HTMLImageElement.prototype, {
2919    get alt(){
2920        return this.getAttribute('alt');
2921    },
2922    set alt(value){
2923        this.setAttribute('alt', value);
2924    },
2925    get height(){
2926        return parseInt(this.getAttribute('height'), 10) || 0;
2927    },
2928    set height(value){
2929        this.setAttribute('height', value);
2930    },
2931    get isMap(){
2932        return this.hasAttribute('map');
2933    },
2934    set useMap(value){
2935        this.setAttribute('map', value);
2936    },
2937    get longDesc(){
2938        return this.getAttribute('longdesc');
2939    },
2940    set longDesc(value){
2941        this.setAttribute('longdesc', value);
2942    },
2943    get name(){
2944        return this.getAttribute('name');
2945    },
2946    set name(value){
2947        this.setAttribute('name', value);
2948    },
2949    get src(){
2950        return this.getAttribute('src') || '';
2951    },
2952    set src(value){
2953        this.setAttribute('src', value);
2954    },
2955    get width(){
2956        return parseInt(this.getAttribute('width'), 10) || 0;
2957    },
2958    set width(value){
2959        this.setAttribute('width', value);
2960    },
2961    toString: function(){
2962        return '[object HTMLImageElement]';
2963    }
2964});
2965
2966/*
2967 * html5 4.8.1
2968 * http://dev.w3.org/html5/spec/Overview.html#the-img-element
2969 */
2970exports.Image = Image = function(width, height) {
2971    // Not sure if "[global].document" satifies this requirement:
2972    // "The element's document must be the active document of the
2973    // browsing context of the Window object on which the interface
2974    // object of the invoked constructor is found."
2975
2976    HTMLElement.apply(this, [document]);
2977    // Note: firefox will throw an error if the width/height
2978    //   is not an integer.  Safari just converts to 0 on error.
2979    this.width = parseInt(width, 10) || 0;
2980    this.height = parseInt(height, 10) || 0;
2981    this.nodeName = 'IMG';
2982};
2983Image.prototype = new HTMLImageElement();
2984
2985
2986/*
2987 * Image.src attribute events.
2988 *
2989 * Not sure where this should live... in events/img.js? in parser/img.js?
2990 * Split out to make it easy to move.
2991 */
2992
2993/**
2994 * HTMLImageElement && Image are a bit odd in that the 'src' attribute
2995 * is 'active' -- changing it triggers loading of the image from the
2996 * network.
2997 *
2998 * This can occur by
2999 *   - Directly setting the Image.src =
3000 *   - Using one of the Element.setAttributeXXX methods
3001 *   - Node.importNode an image
3002 *   - The initial creation and parsing of an <img> tag
3003 *
3004 * __onImageRequest__ is a function that handles eventing
3005 *  and dispatches to a user-callback.
3006 *
3007 */
3008
3009__extend__(HTMLImageElement.prototype, {
3010    onload: function(event){
3011        __eval__(this.getAttribute('onload') || '', this);
3012    }
3013});
3014
3015
3016/*
3017 * Image Loading
3018 *
3019 * The difference between "owner.parsing" and "owner.fragment"
3020 *
3021 * If owner.parsing === true, then during the html5 parsing then,
3022 *  __elementPopped__ is called when a compete tag (with attrs and
3023 *  children) is full parsed and added the DOM.
3024 *
3025 *   For images, __elementPopped__ is called with everything the
3026 *    tag has.  which in turn looks for a "src" attr and calls
3027 *    Envjs.loadImage
3028 *
3029 * If owner.parser === false (or non-existant), then we are not in
3030 * a parsing step.  For images, perhaps someone directly modified
3031 * a 'src' attribute of an existing image.
3032 *
3033 * 'innerHTML' is tricky since we first create a "fake document",
3034 *  parse it, then import the right parts.  This may call
3035 *  img.setAttributeNS twice.  once during the parse and once
3036 *  during the clone of the node.  We want event to trigger on the
3037 *  later and not during th fake doco.  "owner.fragment" is set by
3038 *  the fake doco parser to indicate that events should not be
3039 *  triggered on this.
3040 *
3041 * We coud make 'owner.parser' == [ 'none', 'full', 'fragment']
3042 * and just use one variable That was not done since the patch is
3043 * quite large as is.
3044 *
3045 * This same problem occurs with scripts.  innerHTML oddly does
3046 * not eval any <script> tags inside.
3047 */
3048HTMLElement.registerSetAttribute('IMG', 'src', function(node, value) {
3049    var owner = node.ownerDocument;
3050    if (!owner.parsing && !owner.fragment) {
3051        Envjs.loadImage(node, value);
3052    }
3053});
3054
3055}(/*HTMLImageElement*/));
3056/**
3057 * HTMLInputElement
3058 *
3059 * HTML5: 4.10.5 The input element
3060 * http://dev.w3.org/html5/spec/Overview.html#the-input-element
3061 */
3062 
3063(function(){
3064   
3065var log = Envjs.logger();
3066
3067Envjs.once('tick', function(){
3068    log = Envjs.logger('Envjs.HTML.HTMLInputElement').
3069                debug('HTMLInputElement available');   
3070});
3071
3072exports.HTMLInputElement = HTMLInputElement = function(ownerDocument) {
3073    HTMLInputAreaCommon.apply(this, arguments);
3074    this._dirty = false;
3075    this._checked = null;
3076    this._value = null;
3077};
3078HTMLInputElement.prototype = new HTMLInputAreaCommon();
3079__extend__(HTMLInputElement.prototype, {
3080    get alt(){
3081        return this.getAttribute('alt') || '';
3082    },
3083    set alt(value){
3084        this.setAttribute('alt', value);
3085    },
3086
3087    /**
3088     * 'checked' returns state, NOT the value of the attribute
3089     */
3090    get checked(){
3091        if (this._checked === null) {
3092            this._checked = this.defaultChecked;
3093        }
3094        return this._checked;
3095    },
3096    set checked(value){
3097        // force to boolean value
3098        this._checked = (value) ? true : false;
3099    },
3100
3101    /**
3102     * 'defaultChecked' actually reflects if the 'checked' attribute
3103     * is present or not
3104     */
3105    get defaultChecked(){
3106        return this.hasAttribute('checked');
3107    },
3108    set defaultChecked(val){
3109        if (val) {
3110            this.setAttribute('checked', '');
3111        } else {
3112            if (this.defaultChecked) {
3113                this.removeAttribute('checked');
3114            }
3115        }
3116    },
3117    get defaultValue() {
3118        return this.getAttribute('value') || '';
3119    },
3120    set defaultValue(value) {
3121        this._dirty = true;
3122        this.setAttribute('value', value);
3123    },
3124    get value() {
3125        return (this._value === null) ? this.defaultValue : this._value;
3126    },
3127    set value(newvalue) {
3128        this._value = newvalue;
3129    },
3130    /**
3131     * Height is a string
3132     */
3133    get height(){
3134        // spec says it is a string
3135        return this.getAttribute('height') || '';
3136    },
3137    set height(value){
3138        this.setAttribute('height',value);
3139    },
3140
3141    /**
3142     * MaxLength is a number
3143     */
3144    get maxLength(){
3145        return Number(this.getAttribute('maxlength')||'-1');
3146    },
3147    set maxLength(value){
3148        this.setAttribute('maxlength', value);
3149    },
3150
3151    /**
3152     * Src is a URL string
3153     */
3154    get src(){
3155        return this.getAttribute('src') || '';
3156    },
3157    set src(value){
3158        // TODO: make absolute any relative URLS
3159        this.setAttribute('src', value);
3160    },
3161
3162    get type() {
3163        return this.getAttribute('type') || 'text';
3164    },
3165    set type(value) {
3166        this.setAttribute('type', value);
3167    },
3168
3169    get useMap(){
3170        return this.getAttribute('map') || '';
3171    },
3172
3173    /**
3174     * Width: spec says it is a string
3175     */
3176    get width(){
3177        return this.getAttribute('width') || '';
3178    },
3179    set width(value){
3180        this.setAttribute('width',value);
3181    },
3182    click:function(){
3183        __click__(this);
3184    },
3185    toString: function() {
3186        return '[object HTMLInputElement]';
3187    }
3188});
3189
3190//http://dev.w3.org/html5/spec/Overview.html#dom-input-value
3191// if someone directly modifies the value attribute, then the input's value
3192// also directly changes.
3193HTMLElement.registerSetAttribute('INPUT', 'value', function(node, value) {
3194    if (!node._dirty) {
3195        node._value = value;
3196        node._dirty = true;
3197    }
3198});
3199
3200/*
3201 *The checked content attribute is a boolean attribute that gives the
3202 *default checkedness of the input element. When the checked content
3203 *attribute is added, if the control does not have dirty checkedness,
3204 *the user agent must set the checkedness of the element to true; when
3205 *the checked content attribute is removed, if the control does not
3206 *have dirty checkedness, the user agent must set the checkedness of
3207 *the element to false.
3208 */
3209// Named Element Support
3210HTMLElement.registerSetAttribute('INPUT', 'name', __updateFormForNamedElement__);
3211
3212}(/*HTMLInputElement*/));
3213
3214/**
3215 * HTMLLabelElement - DOM Level 2
3216 * HTML5 4.10.4 The label element
3217 * http://dev.w3.org/html5/spec/Overview.html#the-label-element
3218 */
3219 
3220(function(){
3221   
3222var log = Envjs.logger();
3223
3224Envjs.once('tick', function(){
3225    log = Envjs.logger('Envjs.HTML.HTMLLabelElement').
3226                debug('HTMLLabelElement available');   
3227});
3228
3229exports.HTMLLabelElement = HTMLLabelElement = function(ownerDocument) {
3230    HTMLInputCommon.apply(this, arguments);
3231};
3232HTMLLabelElement.prototype = new HTMLInputCommon();
3233__extend__(HTMLLabelElement.prototype, inputElements_dataProperties);
3234__extend__(HTMLLabelElement.prototype, {
3235    get htmlFor() {
3236        return this.getAttribute('for');
3237    },
3238    set htmlFor(value) {
3239        this.setAttribute('for',value);
3240    },
3241    get dataFormatAs() {
3242        return this.getAttribute('dataFormatAs');
3243    },
3244    set dataFormatAs(value) {
3245        this.setAttribute('dataFormatAs',value);
3246    },
3247    toString: function() {
3248        return '[object HTMLLabelElement]';
3249    }
3250});
3251
3252}(/*HTMLLabelElement*/));
3253
3254/*
3255 * HTMLLIElement
3256 * HTML5: 4.5.8 The li Element
3257 * http://dev.w3.org/html5/spec/Overview.html#the-li-element
3258 */
3259 
3260(function(){
3261   
3262var log = Envjs.logger();
3263
3264Envjs.once('tick', function(){
3265    log = Envjs.logger('Envjs.HTML.HTMLLIElement').
3266                debug('HTMLLIElement available');   
3267});
3268
3269exports.HTMLLIElement = HTMLLIElement = function(ownerDocument) {
3270    HTMLElement.apply(this, arguments);
3271};
3272
3273HTMLLIElement.prototype = new HTMLElement();
3274__extend__(HTMLLIElement.prototype, {
3275    // TODO: attribute long value;
3276    toString: function() {
3277        return '[object HTMLLIElement]';
3278    }
3279});
3280
3281}(/*HTMLLIElement*/));
3282
3283/*
3284 * HTMLLinkElement - DOM Level 2
3285 *
3286 * HTML5: 4.8.12 The link element
3287 * http://dev.w3.org/html5/spec/Overview.html#the-link-element
3288 */
3289 
3290(function(){
3291   
3292var log = Envjs.logger();
3293
3294Envjs.once('tick', function(){
3295    log = Envjs.logger('Envjs.HTML.HTMLLinkElement').
3296                debug('HTMLLinkElement available');   
3297});
3298
3299exports.HTMLLinkElement = HTMLLinkElement = function(ownerDocument) {
3300    HTMLElement.apply(this, arguments);
3301};
3302HTMLLinkElement.prototype = new HTMLElement();
3303__extend__(HTMLLinkElement.prototype, {
3304    get disabled(){
3305        return this.getAttribute('disabled');
3306    },
3307    set disabled(value){
3308        this.setAttribute('disabled',value);
3309    },
3310    get charset(){
3311        return this.getAttribute('charset');
3312    },
3313    set charset(value){
3314        this.setAttribute('charset',value);
3315    },
3316    get href(){
3317        return this.getAttribute('href');
3318    },
3319    set href(value){
3320        this.setAttribute('href',value);
3321    },
3322    get hreflang(){
3323        return this.getAttribute('hreflang');
3324    },
3325    set hreflang(value){
3326        this.setAttribute('hreflang',value);
3327    },
3328    get media(){
3329        return this.getAttribute('media');
3330    },
3331    set media(value){
3332        this.setAttribute('media',value);
3333    },
3334    get rel(){
3335        return this.getAttribute('rel');
3336    },
3337    set rel(value){
3338        this.setAttribute('rel',value);
3339    },
3340    get rev(){
3341        return this.getAttribute('rev');
3342    },
3343    set rev(value){
3344        this.setAttribute('rev',value);
3345    },
3346    get target(){
3347        return this.getAttribute('target');
3348    },
3349    set target(value){
3350        this.setAttribute('target',value);
3351    },
3352    get type(){
3353        return this.getAttribute('type');
3354    },
3355    set type(value){
3356        this.setAttribute('type',value);
3357    },
3358    toString: function() {
3359        return '[object HTMLLinkElement]';
3360    }
3361});
3362
3363}(/*HTMLLinkElement*/));
3364
3365
3366
3367
3368HTMLElement.registerSetAttribute('LINK', 'href', function(node, value) {
3369    Envjs.loadLink(node, value);
3370});
3371
3372/**
3373 * Event stuff, not sure where it goes
3374 */
3375__extend__(HTMLLinkElement.prototype, {
3376    onload: function(event){
3377        __eval__(this.getAttribute('onload')||'', this);
3378    }
3379});
3380
3381/**
3382 * HTMLMapElement
3383 *
3384 * 4.8.12 The map element
3385 * http://dev.w3.org/html5/spec/Overview.html#the-map-element
3386 */
3387 
3388(function(){
3389   
3390var log = Envjs.logger();
3391
3392Envjs.once('tick', function(){
3393    log = Envjs.logger('Envjs.HTML.HTMLMapElement').
3394                debug('HTMLMapElement available');   
3395});
3396
3397exports.HTMLMapElement = HTMLMapElement = function(ownerDocument) {
3398    HTMLElement.apply(this, arguments);
3399};
3400HTMLMapElement.prototype = new HTMLElement();
3401__extend__(HTMLMapElement.prototype, {
3402    get areas(){
3403        return this.getElementsByTagName('area');
3404    },
3405    get name(){
3406        return this.getAttribute('name') || '';
3407    },
3408    set name(value){
3409        this.setAttribute('name',value);
3410    },
3411    toString: function() {
3412        return '[object HTMLMapElement]';
3413    }
3414});
3415
3416}(/*HTMLMapElement*/));
3417
3418/**
3419 * HTMLMetaElement - DOM Level 2
3420 * HTML5: 4.2.5 The meta element
3421 * http://dev.w3.org/html5/spec/Overview.html#meta
3422 */
3423 
3424(function(){
3425   
3426var log = Envjs.logger();
3427
3428Envjs.once('tick', function(){
3429    log = Envjs.logger('Envjs.HTML.HTMLMetaElement').
3430                debug('HTMLMetaElement available');   
3431});
3432
3433exports.HTMLMetaElement = HTMLMetaElement = function(ownerDocument) {
3434    HTMLElement.apply(this, arguments);
3435};
3436HTMLMetaElement.prototype = new HTMLElement();
3437__extend__(HTMLMetaElement.prototype, {
3438    get content() {
3439        return this.getAttribute('content') || '';
3440    },
3441    set content(value){
3442        this.setAttribute('content',value);
3443    },
3444    get httpEquiv(){
3445        return this.getAttribute('http-equiv') || '';
3446    },
3447    set httpEquiv(value){
3448        this.setAttribute('http-equiv',value);
3449    },
3450    get name(){
3451        return this.getAttribute('name') || '';
3452    },
3453    set name(value){
3454        this.setAttribute('name',value);
3455    },
3456    get scheme(){
3457        return this.getAttribute('scheme');
3458    },
3459    set scheme(value){
3460        this.setAttribute('scheme',value);
3461    },
3462    toString: function() {
3463        return '[object HTMLMetaElement]';
3464    }
3465});
3466
3467}(/*HTMLMetaElement*/));
3468
3469/**
3470 * HTMLObjectElement - DOM Level 2
3471 * HTML5: 4.8.5 The object element
3472 * http://dev.w3.org/html5/spec/Overview.html#the-object-element
3473 */
3474 
3475(function(){
3476   
3477var log = Envjs.logger();
3478
3479Envjs.once('tick', function(){
3480    log = Envjs.logger('Envjs.HTML.HTMLObjectElement').
3481                debug('HTMLObjectElement available');   
3482});
3483
3484exports.HTMLObjectElement = HTMLObjectElement = function(ownerDocument) {
3485    HTMLElement.apply(this, arguments);
3486};
3487HTMLObjectElement.prototype = new HTMLElement();
3488__extend__(HTMLObjectElement.prototype, {
3489    get code(){
3490        return this.getAttribute('code');
3491    },
3492    set code(value){
3493        this.setAttribute('code',value);
3494    },
3495    get archive(){
3496        return this.getAttribute('archive');
3497    },
3498    set archive(value){
3499        this.setAttribute('archive',value);
3500    },
3501    get codeBase(){
3502        return this.getAttribute('codebase');
3503    },
3504    set codeBase(value){
3505        this.setAttribute('codebase',value);
3506    },
3507    get codeType(){
3508        return this.getAttribute('codetype');
3509    },
3510    set codeType(value){
3511        this.setAttribute('codetype',value);
3512    },
3513    get data(){
3514        return this.getAttribute('data');
3515    },
3516    set data(value){
3517        this.setAttribute('data',value);
3518    },
3519    get declare(){
3520        return this.getAttribute('declare');
3521    },
3522    set declare(value){
3523        this.setAttribute('declare',value);
3524    },
3525    get height(){
3526        return this.getAttribute('height');
3527    },
3528    set height(value){
3529        this.setAttribute('height',value);
3530    },
3531    get standby(){
3532        return this.getAttribute('standby');
3533    },
3534    set standby(value){
3535        this.setAttribute('standby',value);
3536    },
3537    /*get tabIndex(){
3538      return this.getAttribute('tabindex');
3539      },
3540      set tabIndex(value){
3541      this.setAttribute('tabindex',value);
3542      },*/
3543    get type(){
3544        return this.getAttribute('type');
3545    },
3546    set type(value){
3547        this.setAttribute('type',value);
3548    },
3549    get useMap(){
3550        return this.getAttribute('usemap');
3551    },
3552    set useMap(value){
3553        this.setAttribute('usemap',value);
3554    },
3555    get width(){
3556        return this.getAttribute('width');
3557    },
3558    set width(value){
3559        this.setAttribute('width',value);
3560    },
3561    get contentDocument(){
3562        return this.ownerDocument;
3563    },
3564    toString: function() {
3565        return '[object HTMLObjectElement]';
3566    }
3567});
3568
3569// Named Element Support
3570HTMLElement.registerSetAttribute('OBJECT', 'name', __updateFormForNamedElement__);
3571
3572}(/*HTMLObjectElement*/));
3573
3574/*
3575 * HTMLOListElement
3576 * HTML5: 4.5.6 The ol Element
3577 * http://dev.w3.org/html5/spec/Overview.html#the-ol-element
3578 */
3579 
3580 
3581(function(){
3582   
3583var log = Envjs.logger();
3584
3585Envjs.once('tick', function(){
3586    log = Envjs.logger('Envjs.HTML.HTMLOListElement').
3587                debug('HTMLOListElement available');   
3588});
3589
3590exports.HTMLOListElement = HTMLOListElement = function(ownerDocument) {
3591    HTMLElement.apply(this, arguments);
3592};
3593
3594HTMLOListElement.prototype = new HTMLElement();
3595__extend__(HTMLOListElement.prototype, {
3596    // TODO: attribute boolean reversed;
3597    // TODO:  attribute long start;
3598    toString: function() {
3599        return '[object HTMLOListElement]';
3600    }
3601});
3602
3603}(/*HTMLOListElement*/));
3604
3605/**
3606 * HTMLOptGroupElement - DOM Level 2
3607 * HTML 5: 4.10.9 The optgroup element
3608 * http://dev.w3.org/html5/spec/Overview.html#the-optgroup-element
3609 */
3610 
3611(function(){
3612   
3613var log = Envjs.logger();
3614
3615Envjs.once('tick', function(){
3616    log = Envjs.logger('Envjs.HTML.HTMLOptGroupElement').
3617        debug('HTMLOptGroupElement available');   
3618});
3619
3620exports.HTMLOptGroupElement = HTMLOptGroupElement = function(ownerDocument) {
3621    HTMLElement.apply(this, arguments);
3622};
3623HTMLOptGroupElement.prototype = new HTMLElement();
3624__extend__(HTMLOptGroupElement.prototype, {
3625    get disabled(){
3626        return this.getAttribute('disabled');
3627    },
3628    set disabled(value){
3629        this.setAttribute('disabled',value);
3630    },
3631    get label(){
3632        return this.getAttribute('label');
3633    },
3634    set label(value){
3635        this.setAttribute('label',value);
3636    },
3637    appendChild: function(node){
3638        var i,
3639            length,
3640            selected = false;
3641        //make sure at least one is selected by default
3642        if(node.nodeType === Node.ELEMENT_NODE && node.tagName === 'OPTION'){
3643            length = this.childNodes.length;
3644            for(i=0;i<length;i++){
3645                if(this.childNodes[i].nodeType === Node.ELEMENT_NODE &&
3646                   this.childNodes[i].tagName === 'OPTION'){
3647                    //check if it is selected
3648                    if(this.selected){
3649                        selected = true;
3650                        break;
3651                    }
3652                }
3653            }
3654            if(!selected){
3655                node.selected = true;
3656                this.value = node.value?node.value:'';
3657            }
3658        }
3659        return HTMLElement.prototype.appendChild.apply(this, [node]);
3660    },
3661    toString: function() {
3662        return '[object HTMLOptGroupElement]';
3663    }
3664});
3665
3666}(/*HTMLOptGroupElement*/));
3667
3668/**
3669 * HTMLOptionElement, Option
3670 * HTML5: 4.10.10 The option element
3671 * http://dev.w3.org/html5/spec/Overview.html#the-option-element
3672 */
3673 
3674(function(){
3675   
3676var log = Envjs.logger();
3677
3678Envjs.once('tick', function(){
3679    log = Envjs.logger('Envjs.HTML.HTMLOptionElement').
3680                debug('HTMLOptionElement available');   
3681});
3682
3683exports.HTMLOptionElement = HTMLOptionElement = function(ownerDocument) {
3684    HTMLInputCommon.apply(this, arguments);
3685    this._selected = null;
3686};
3687HTMLOptionElement.prototype = new HTMLInputCommon();
3688__extend__(HTMLOptionElement.prototype, {
3689
3690    /**
3691     * defaultSelected actually reflects the presence of the
3692     * 'selected' attribute.
3693     */
3694    get defaultSelected() {
3695        return this.hasAttribute('selected');
3696    },
3697    set defaultSelected(value) {
3698        if (value) {
3699            this.setAttribute('selected','');
3700        } else {
3701            if (this.hasAttribute('selected')) {
3702                this.removeAttribute('selected');
3703            }
3704        }
3705    },
3706    get form() {
3707        var parent = __selectparent__(this);
3708        return parent ? parent.form : null;
3709    },
3710    get index() {
3711        var options, i;
3712
3713        if (! this.parentNode) {
3714            return -1;
3715        }
3716        options = this.parentNode.options;
3717        for (i=0; i < options.length; ++i) {
3718            if (this === options[i]) {
3719                return i;
3720            }
3721        }
3722        return 0;
3723    },
3724    get label() {
3725        return this.getAttribute('label');
3726    },
3727    set label(value) {
3728        this.setAttribute('label', value);
3729    },
3730
3731    /*
3732     * This is not in the spec, but safari and firefox both
3733     * use this
3734     */
3735    get name() {
3736        return this.getAttribute('name');
3737    },
3738    set name(value) {
3739        this.setAttribute('name', value);
3740    },
3741
3742    /**
3743     *
3744     */
3745    get selected() {
3746        // if disabled, return false, no matter what
3747        if (this.disabled) {
3748            return false;
3749        }
3750        if (this._selected === null) {
3751            return this.defaultSelected;
3752        }
3753
3754        return this._selected;
3755    },
3756    set selected(value) {
3757        this._selected = (value) ? true : false;
3758    },
3759
3760    get text() {
3761        var val = this.nodeValue;
3762        return (val === null || this.value === undefined) ?
3763            this.innerHTML :
3764            val;
3765    },
3766    get value() {
3767        var val = this.getAttribute('value');
3768        return (val === null || val === undefined) ?
3769            this.textContent :
3770            val;
3771    },
3772    set value(value) {
3773        this.setAttribute('value', value);
3774    },
3775    toString: function() {
3776        return '[object HTMLOptionElement]';
3777    }
3778});
3779
3780exports.Option = Option = function(text, value, defaultSelected, selected) {
3781
3782    // Not sure if this is correct:
3783    //
3784    // The element's document must be the active document of the
3785    // browsing context of the Window object on which the interface
3786    // object of the invoked constructor is found.
3787    HTMLOptionElement.apply(this, [document]);
3788    this.nodeName = 'OPTION';
3789
3790    if (arguments.length >= 1) {
3791        this.appendChild(document.createTextNode('' + text));
3792    }
3793    if (arguments.length >= 2) {
3794        this.value = value;
3795    }
3796    if (arguments.length >= 3) {
3797        if (defaultSelected) {
3798            this.defaultSelected = '';
3799        }
3800    }
3801    if (arguments.length >= 4) {
3802        this.selected = (selected) ? true : false;
3803    }
3804};
3805
3806Option.prototype = new HTMLOptionElement();
3807
3808// Named Element Support
3809
3810function updater(node, value) {
3811    __updateoptions__(node);
3812}
3813HTMLElement.registerSetAttribute('OPTION', 'name', updater);
3814HTMLElement.registerSetAttribute('OPTION', 'id', updater);
3815
3816
3817
3818}(/*HTMLOptionElement*/));
3819
3820
3821/*
3822 * HTML5: The form IDL attribute's behavior depends on whether the
3823 * option element is in a select element or not. If the option has
3824 * a select element as its parent, or has a colgroup element as
3825 * its parent and that colgroup element has a select element as
3826 * its parent, then the form IDL attribute must return the same
3827 * value as the form IDL attribute on that select
3828 * element. Otherwise, it must return null.
3829 */
3830__selectparent__ = function(node) {
3831    var parent = node.parentNode;
3832    if (!parent) {
3833        return null;
3834    }
3835
3836    if (parent.tagName === 'SELECT') {
3837        return parent;
3838    }
3839    if (parent.tagName === 'COLGROUP') {
3840        parent = parent.parentNode;
3841        if (parent && parent.tagName === 'SELECT') {
3842            return parent;
3843        }
3844    }
3845};
3846//Blah this is used in parser/htmldocument, so we have to create
3847//some way to access it outside the module so Envjs.updateOptions
3848//is a temp place holder for that
3849__updateoptions__ = Envjs.updateOptions = function(node) {
3850    var parent = __selectparent__(node),
3851        s;
3852    if (parent) {
3853        // has side effects and updates owner select's options
3854        s = parent.options;
3855    }
3856};
3857
3858/*
3859* HTMLParagraphElement - DOM Level 2
3860*/
3861
3862(function(){
3863   
3864var log = Envjs.logger();
3865
3866Envjs.once('tick', function(){
3867    log = Envjs.logger('Envjs.HTML.HTMLParagraphElement').
3868                debug('HTMLParagraphElement available');   
3869});
3870
3871exports.HTMLParagraphElement = HTMLParagraphElement = function(ownerDocument) {
3872    HTMLElement.apply(this, arguments);
3873};
3874HTMLParagraphElement.prototype = new HTMLElement();
3875__extend__(HTMLParagraphElement.prototype, {
3876    toString: function(){
3877        return '[object HTMLParagraphElement]';
3878    }
3879});
3880
3881}(/*HTMLParagraphElement*/));
3882
3883
3884/**
3885 * HTMLParamElement
3886 *
3887 * HTML5: 4.8.6 The param element
3888 * http://dev.w3.org/html5/spec/Overview.html#the-param-element
3889 */
3890 
3891(function(){
3892   
3893var log = Envjs.logger();
3894
3895Envjs.once('tick', function(){
3896    log = Envjs.logger('Envjs.HTML.HTMLParamElement').
3897                debug('HTMLParamElement available');   
3898});
3899
3900exports.HTMLParamElement = HTMLParamElement = function(ownerDocument) {
3901    HTMLElement.apply(this, arguments);
3902};
3903HTMLParamElement.prototype = new HTMLElement();
3904__extend__(HTMLParamElement.prototype, {
3905    get name() {
3906        return this.getAttribute('name') || '';
3907    },
3908    set name(value) {
3909        this.setAttribute('name', value);
3910    },
3911    get type(){
3912        return this.getAttribute('type');
3913    },
3914    set type(value){
3915        this.setAttribute('type',value);
3916    },
3917    get value(){
3918        return this.getAttribute('value');
3919    },
3920    set value(value){
3921        this.setAttribute('value',value);
3922    },
3923    get valueType(){
3924        return this.getAttribute('valuetype');
3925    },
3926    set valueType(value){
3927        this.setAttribute('valuetype',value);
3928    },
3929    toString: function() {
3930        return '[object HTMLParamElement]';
3931    }
3932});
3933
3934}(/*HTMLParamElement*/));
3935
3936/*
3937 * HTMLPreElement
3938 * HTML5: 4.5.4 The pre Element
3939 * http://dev.w3.org/html5/spec/Overview.html#the-pre-element
3940 */
3941 
3942(function(){
3943   
3944var log = Envjs.logger();
3945
3946Envjs.once('tick', function(){
3947    log = Envjs.logger('Envjs.HTML.HTMLPreElement').
3948                debug('HTMLPreElement available');   
3949});
3950
3951exports.HTMLPreElement = HTMLPreElement = function(ownerDocument) {
3952    HTMLElement.apply(this, arguments);
3953};
3954
3955HTMLPreElement.prototype = new HTMLElement();
3956__extend__(HTMLPreElement.prototype, {
3957    // no additional properties or elements
3958    toString: function() {
3959        return '[object HTMLPreElement]';
3960    }
3961});
3962
3963}(/*HTMLPreElement*/));
3964
3965/**
3966 * HTMLScriptElement - DOM Level 2
3967 *
3968 * HTML5: 4.3.1 The script element
3969 * http://dev.w3.org/html5/spec/Overview.html#script
3970 */
3971 
3972(function(){
3973   
3974var log = Envjs.logger();
3975
3976Envjs.once('tick', function(){
3977    log = Envjs.logger('Envjs.HTML.HTMLScriptElement').
3978                debug('HTMLScriptElement available');   
3979});
3980
3981exports.HTMLScriptElement = HTMLScriptElement = function(ownerDocument) {
3982    HTMLElement.apply(this, arguments);
3983};
3984HTMLScriptElement.prototype = new HTMLElement();
3985__extend__(HTMLScriptElement.prototype, {
3986
3987    /**
3988     * HTML5 spec @ http://dev.w3.org/html5/spec/Overview.html#script
3989     *
3990     * "The IDL attribute text must return a concatenation of the
3991     * contents of all the text nodes that are direct children of the
3992     * script element (ignoring any other nodes such as comments or
3993     * elements), in tree order. On setting, it must act the same way
3994     * as the textContent IDL attribute."
3995     *
3996     * AND... "The term text node refers to any Text node,
3997     * including CDATASection nodes; specifically, any Node with node
3998     * type TEXT_NODE (3) or CDATA_SECTION_NODE (4)"
3999     */
4000    get text() {
4001        var kids = this.childNodes;
4002        var kid;
4003        var s = '';
4004        var imax = kids.length;
4005        for (var i = 0; i < imax; ++i) {
4006            kid = kids[i];
4007            if (kid.nodeType === Node.TEXT_NODE ||
4008                kid.nodeType === Node.CDATA_SECTION_NODE) {
4009                s += kid.nodeValue;
4010            }
4011        }
4012        return s;
4013    },
4014
4015    /**
4016     * HTML5 spec "Can be set, to replace the element's children with
4017     * the given value."
4018     */
4019    set text(value) {
4020        // this deletes all children, and make a new single text node
4021        // with value
4022        this.textContent = value;
4023
4024        /* Currently we always execute, but this isn't quite right if
4025         * the node has *not* been inserted into the document, then it
4026         * should *not* fire.  The more detailed answer from the spec:
4027         *
4028         * When a script element that is neither marked as having
4029         * "already started" nor marked as being "parser-inserted"
4030         * experiences one of the events listed in the following list,
4031         * the user agent must synchronously run the script element:
4032         *
4033         *   * The script element gets inserted into a document.
4034         *   * The script element is in a Document and its child nodes
4035         *     are changed.
4036         *   * The script element is in a Document and has a src
4037         *     attribute set where previously the element had no such
4038         *     attribute.
4039         *
4040         * And no doubt there are other cases as well.
4041         */
4042        Envjs.loadInlineScript(this);
4043    },
4044
4045    get htmlFor(){
4046        return this.getAttribute('for');
4047    },
4048    set htmlFor(value){
4049        this.setAttribute('for',value);
4050    },
4051    get event(){
4052        return this.getAttribute('event');
4053    },
4054    set event(value){
4055        this.setAttribute('event',value);
4056    },
4057    get charset(){
4058        return this.getAttribute('charset');
4059    },
4060    set charset(value){
4061        this.setAttribute('charset',value);
4062    },
4063    get defer(){
4064        return this.getAttribute('defer');
4065    },
4066    set defer(value){
4067        this.setAttribute('defer',value);
4068    },
4069    get src(){
4070        return this.getAttribute('src')||'';
4071    },
4072    set src(value){
4073        this.setAttribute('src',value);
4074    },
4075    get type(){
4076        return this.getAttribute('type')||'';
4077    },
4078    set type(value){
4079        this.setAttribute('type',value);
4080    },
4081    onload: HTMLEvents.prototype.onload,
4082    onerror: HTMLEvents.prototype.onerror,
4083    toString: function() {
4084        return '[object HTMLScriptElement]';
4085    }
4086});
4087
4088}(/*HTMLScriptElement*/));
4089
4090/**
4091 * HTMLSelectElement
4092 * HTML5: http://dev.w3.org/html5/spec/Overview.html#the-select-element
4093 */
4094 
4095(function(){
4096   
4097var log = Envjs.logger();
4098
4099Envjs.once('tick', function(){
4100    log = Envjs.logger('Envjs.HTML.HTMLSelectElement').
4101                debug('HTMLSelectElement available');   
4102});
4103
4104exports.HTMLSelectElement = HTMLSelectElement = function(ownerDocument) {
4105    HTMLTypeValueInputs.apply(this, arguments);
4106    this._oldIndex = -1;
4107};
4108
4109HTMLSelectElement.prototype = new HTMLTypeValueInputs();
4110__extend__(HTMLSelectElement.prototype, inputElements_dataProperties);
4111__extend__(HTMLButtonElement.prototype, inputElements_size);
4112__extend__(HTMLSelectElement.prototype, inputElements_onchange);
4113__extend__(HTMLSelectElement.prototype, inputElements_focusEvents);
4114__extend__(HTMLSelectElement.prototype, {
4115
4116    get value() {
4117        var index = this.selectedIndex;
4118        return (index === -1) ? '' : this.options[index].value;
4119    },
4120    set value(newValue) {
4121        var options = this.options;
4122        var imax = options.length;
4123        for (var i=0; i< imax; ++i) {
4124            if (options[i].value == newValue) {
4125                this.setAttribute('value', newValue);
4126                this.selectedIndex = i;
4127                return;
4128            }
4129        }
4130    },
4131    get multiple() {
4132        return this.hasAttribute('multiple');
4133    },
4134    set multiple(value) {
4135        if (value) {
4136            this.setAttribute('multiple', '');
4137        } else {
4138            if (this.hasAttribute('multiple')) {
4139                this.removeAttribute('multiple');
4140            }
4141        }
4142    },
4143    // Returns HTMLOptionsCollection
4144    get options() {
4145        var nodes = this.getElementsByTagName('option');
4146        var alist = new NodeList();
4147        var i, tmp;
4148        for (i = 0; i < nodes.length; ++i) {
4149            alist.push(nodes[i]);
4150            this[i] = nodes[i];
4151            tmp = nodes[i].name;
4152            if (tmp) {
4153                this[tmp] = nodes[i];
4154            }
4155            tmp = nodes[i].id;
4156            if (tmp) {
4157                this[tmp] = nodes[i];
4158            }
4159        }
4160        return new HTMLCollection(alist);
4161    },
4162    get length() {
4163        return this.options.length;
4164    },
4165    item: function(idx) {
4166        return this.options[idx];
4167    },
4168    namedItem: function(aname) {
4169        return this.options[aname];
4170    },
4171
4172    get selectedIndex() {
4173        var options = this.options;
4174        var imax = options.length;
4175        for (var i=0; i < imax; ++i) {
4176            if (options[i].selected) {
4177                //console.log('select get selectedIndex %s', i);
4178                return i;
4179            }
4180        }
4181        //console.log('select get selectedIndex %s', -1);
4182        return -1;
4183    },
4184
4185    set selectedIndex(value) {
4186        var options = this.options;
4187        var num = Number(value);
4188        var imax = options.length;
4189        for (var i = 0; i < imax; ++i) {
4190            options[i].selected = (i === num);
4191        }
4192    },
4193    get type() {
4194        return this.multiple ? 'select-multiple' : 'select-one';
4195    },
4196
4197    add: function(element, before) {
4198        this.appendChild(element);
4199        //__add__(this);
4200    },
4201    remove: function() {
4202        //__remove__(this);
4203    },
4204    toString: function() {
4205        return '[object HTMLSelectElement]';
4206    }
4207});
4208
4209// Named Element Support
4210HTMLElement.registerSetAttribute('SELECT', 'name', __updateFormForNamedElement__);
4211
4212}(/*HTMLSelectElement*/));
4213/**
4214 * HTML 5: 4.6.22 The span element
4215 * http://dev.w3.org/html5/spec/Overview.html#the-span-element
4216 *
4217 */
4218 
4219(function(){
4220   
4221var log = Envjs.logger();
4222
4223Envjs.once('tick', function(){
4224    log = Envjs.logger('Envjs.HTML.HTMLSpanElement').
4225                debug('HTMLSpanElement available');   
4226});
4227
4228exports.HTMLSpanElement = HTMLSpanElement = function(ownerDocument) {
4229    HTMLElement.apply(this, arguments);
4230};
4231HTMLSpanElement.prototype = new HTMLElement();
4232__extend__(HTMLSpanElement.prototype, {
4233    toString: function(){
4234        return '[object HTMLSpanElement]';
4235    }
4236});
4237
4238}(/*HTMLSpanElement*/));
4239
4240/**
4241 * HTMLStyleElement - DOM Level 2
4242 * HTML5 4.2.6 The style element
4243 * http://dev.w3.org/html5/spec/Overview.html#the-style-element
4244 */
4245 
4246(function(){
4247   
4248var log = Envjs.logger();
4249
4250Envjs.once('tick', function(){
4251    log = Envjs.logger('Envjs.HTML.HTMLStyleElement').
4252                debug('HTMLStyleElement available');   
4253});
4254
4255exports.HTMLStyleElement = HTMLStyleElement = function(ownerDocument) {
4256    HTMLElement.apply(this, arguments);
4257};
4258HTMLStyleElement.prototype = new HTMLElement();
4259__extend__(HTMLStyleElement.prototype, {
4260    get disabled(){
4261        return this.getAttribute('disabled');
4262    },
4263    set disabled(value){
4264        this.setAttribute('disabled',value);
4265    },
4266    get media(){
4267        return this.getAttribute('media');
4268    },
4269    set media(value){
4270        this.setAttribute('media',value);
4271    },
4272    get type(){
4273        return this.getAttribute('type');
4274    },
4275    set type(value){
4276        this.setAttribute('type',value);
4277    },
4278    toString: function() {
4279        return '[object HTMLStyleElement]';
4280    }
4281});
4282
4283}(/*HTMLStyleElement*/));
4284
4285/**
4286 * HTMLTableElement - DOM Level 2
4287 * Implementation Provided by Steven Wood
4288 *
4289 * HTML5: 4.9.1 The table element
4290 * http://dev.w3.org/html5/spec/Overview.html#the-table-element
4291 */
4292 
4293(function(){
4294   
4295var log = Envjs.logger();
4296
4297Envjs.once('tick', function(){
4298    log = Envjs.logger('Envjs.HTML.HTMLTableElement').
4299                debug('HTMLTableElement available');   
4300});
4301
4302exports.HTMLTableElement = HTMLTableElement = function(ownerDocument) {
4303    HTMLElement.apply(this, arguments);
4304};
4305HTMLTableElement.prototype = new HTMLElement();
4306__extend__(HTMLTableElement.prototype, {
4307
4308    get tFoot() {
4309        //tFoot returns the table footer.
4310        return this.getElementsByTagName("tfoot")[0];
4311    },
4312
4313    createTFoot : function () {
4314        var tFoot = this.tFoot;
4315
4316        if (!tFoot) {
4317            tFoot = document.createElement("tfoot");
4318            this.appendChild(tFoot);
4319        }
4320
4321        return tFoot;
4322    },
4323
4324    deleteTFoot : function () {
4325        var foot = this.tFoot;
4326        if (foot) {
4327            foot.parentNode.removeChild(foot);
4328        }
4329    },
4330
4331    get tHead() {
4332        //tHead returns the table head.
4333        return this.getElementsByTagName("thead")[0];
4334    },
4335
4336    createTHead : function () {
4337        var tHead = this.tHead;
4338
4339        if (!tHead) {
4340            tHead = document.createElement("thead");
4341            this.insertBefore(tHead, this.firstChild);
4342        }
4343
4344        return tHead;
4345    },
4346
4347    deleteTHead : function () {
4348        var head = this.tHead;
4349        if (head) {
4350            head.parentNode.removeChild(head);
4351        }
4352    },
4353
4354    /*appendChild : function (child) {
4355
4356      var tagName;
4357      if(child&&child.nodeType==Node.ELEMENT_NODE){
4358      tagName = child.tagName.toLowerCase();
4359      if (tagName === "tr") {
4360      // need an implcit <tbody> to contain this...
4361      if (!this.currentBody) {
4362      this.currentBody = document.createElement("tbody");
4363
4364      Node.prototype.appendChild.apply(this, [this.currentBody]);
4365      }
4366
4367      return this.currentBody.appendChild(child);
4368
4369      } else if (tagName === "tbody" || tagName === "tfoot" && this.currentBody) {
4370      this.currentBody = child;
4371      return Node.prototype.appendChild.apply(this, arguments);
4372
4373      } else {
4374      return Node.prototype.appendChild.apply(this, arguments);
4375      }
4376      }else{
4377      //tables can still have text node from white space
4378      return Node.prototype.appendChild.apply(this, arguments);
4379      }
4380      },*/
4381
4382    get tBodies() {
4383        return new HTMLCollection(this.getElementsByTagName("tbody"));
4384
4385    },
4386
4387    get rows() {
4388        return new HTMLCollection(this.getElementsByTagName("tr"));
4389    },
4390
4391    insertRow : function (idx) {
4392        if (idx === undefined) {
4393            throw new Error("Index omitted in call to HTMLTableElement.insertRow ");
4394        }
4395
4396        var rows = this.rows,
4397            numRows = rows.length,
4398            node,
4399            inserted,
4400            lastRow;
4401
4402        if (idx > numRows) {
4403            throw new Error("Index > rows.length in call to HTMLTableElement.insertRow");
4404        }
4405
4406        inserted = document.createElement("tr");
4407        // If index is -1 or equal to the number of rows,
4408        // the row is appended as the last row. If index is omitted
4409        // or greater than the number of rows, an error will result
4410        if (idx === -1 || idx === numRows) {
4411            this.appendChild(inserted);
4412        } else {
4413            rows[idx].parentNode.insertBefore(inserted, rows[idx]);
4414        }
4415
4416        return inserted;
4417    },
4418
4419    deleteRow : function (idx) {
4420        var elem = this.rows[idx];
4421        elem.parentNode.removeChild(elem);
4422    },
4423
4424    get summary() {
4425        return this.getAttribute("summary");
4426    },
4427
4428    set summary(summary) {
4429        this.setAttribute("summary", summary);
4430    },
4431
4432    get align() {
4433        return this.getAttribute("align");
4434    },
4435
4436    set align(align) {
4437        this.setAttribute("align", align);
4438    },
4439
4440    get bgColor() {
4441        return this.getAttribute("bgColor");
4442    },
4443
4444    set bgColor(bgColor) {
4445        return this.setAttribute("bgColor", bgColor);
4446    },
4447
4448    get cellPadding() {
4449        return this.getAttribute("cellPadding");
4450    },
4451
4452    set cellPadding(cellPadding) {
4453        return this.setAttribute("cellPadding", cellPadding);
4454    },
4455
4456    get cellSpacing() {
4457        return this.getAttribute("cellSpacing");
4458    },
4459
4460    set cellSpacing(cellSpacing) {
4461        this.setAttribute("cellSpacing", cellSpacing);
4462    },
4463
4464    get frame() {
4465        return this.getAttribute("frame");
4466    },
4467
4468    set frame(frame) {
4469        this.setAttribute("frame", frame);
4470    },
4471
4472    get rules() {
4473        return this.getAttribute("rules");
4474    },
4475
4476    set rules(rules) {
4477        this.setAttribute("rules", rules);
4478    },
4479
4480    get width() {
4481        return this.getAttribute("width");
4482    },
4483
4484    set width(width) {
4485        this.setAttribute("width", width);
4486    },
4487    toString: function() {
4488        return '[object HTMLTableElement]';
4489    }
4490});
4491
4492}(/*HTMLTableElement*/));
4493
4494/*
4495 * HTMLxElement - DOM Level 2
4496 * - Contributed by Steven Wood
4497 *
4498 * HTML5: 4.9.5 The tbody element
4499 * http://dev.w3.org/html5/spec/Overview.html#the-tbody-element
4500 * http://dev.w3.org/html5/spec/Overview.html#htmltablesectionelement
4501 */
4502 
4503(function(){
4504   
4505var log = Envjs.logger();
4506
4507Envjs.once('tick', function(){
4508    log = Envjs.logger('Envjs.HTML.HTMLTableSectionElement').
4509                debug('HTMLTableSectionElement available');   
4510});
4511
4512exports.HTMLTableSectionElement = HTMLTableSectionElement = function(ownerDocument) {
4513    HTMLElement.apply(this, arguments);
4514};
4515HTMLTableSectionElement.prototype = new HTMLElement();
4516__extend__(HTMLTableSectionElement.prototype, {
4517
4518    /*appendChild : function (child) {
4519
4520    // disallow nesting of these elements.
4521    if (child.tagName.match(/TBODY|TFOOT|THEAD/)) {
4522    return this.parentNode.appendChild(child);
4523    } else {
4524    return Node.prototype.appendChild.apply(this, arguments);
4525    }
4526
4527    },*/
4528
4529    get align() {
4530        return this.getAttribute("align");
4531    },
4532
4533    get ch() {
4534        return this.getAttribute("ch");
4535    },
4536
4537    set ch(ch) {
4538        this.setAttribute("ch", ch);
4539    },
4540
4541    // ch gets or sets the alignment character for cells in a column.
4542    set chOff(chOff) {
4543        this.setAttribute("chOff", chOff);
4544    },
4545
4546    get chOff() {
4547        return this.getAttribute("chOff");
4548    },
4549
4550    get vAlign () {
4551        return this.getAttribute("vAlign");
4552    },
4553
4554    get rows() {
4555        return new HTMLCollection(this.getElementsByTagName("tr"));
4556    },
4557
4558    insertRow : function (idx) {
4559        if (idx === undefined) {
4560            throw new Error("Index omitted in call to HTMLTableSectionElement.insertRow ");
4561        }
4562
4563        var numRows = this.rows.length,
4564        node = null;
4565
4566        if (idx > numRows) {
4567            throw new Error("Index > rows.length in call to HTMLTableSectionElement.insertRow");
4568        }
4569
4570        var row = document.createElement("tr");
4571        // If index is -1 or equal to the number of rows,
4572        // the row is appended as the last row. If index is omitted
4573        // or greater than the number of rows, an error will result
4574        if (idx === -1 || idx === numRows) {
4575            this.appendChild(row);
4576        } else {
4577            node = this.firstChild;
4578
4579            for (var i=0; i<idx; i++) {
4580                node = node.nextSibling;
4581            }
4582        }
4583
4584        this.insertBefore(row, node);
4585
4586        return row;
4587    },
4588
4589    deleteRow : function (idx) {
4590        var elem = this.rows[idx];
4591        this.removeChild(elem);
4592    },
4593
4594    toString: function() {
4595        return '[object HTMLTableSectionElement]';
4596    }
4597});
4598
4599}(/*HTMLTableSectionElement*/));
4600
4601
4602/**
4603 * HTMLTableCellElement
4604 * base interface for TD and TH
4605 *
4606 * HTML5: 4.9.11 Attributes common to td and th elements
4607 * http://dev.w3.org/html5/spec/Overview.html#htmltablecellelement
4608 */
4609 
4610(function(){
4611   
4612var log = Envjs.logger();
4613
4614Envjs.once('tick', function(){
4615    log = Envjs.logger('Envjs.HTML.HTMLTableCellElement').
4616                debug('HTMLTableCellElement available');   
4617});
4618
4619exports.HTMLTableCellElement = HTMLTableCellElement = function(ownerDocument) {
4620    HTMLElement.apply(this, arguments);
4621};
4622HTMLTableCellElement.prototype = new HTMLElement();
4623__extend__(HTMLTableCellElement.prototype, {
4624    // TOOD: attribute unsigned long  colSpan;
4625    // TODO: attribute unsigned long  rowSpan;
4626    // TODO: attribute DOMString      headers;
4627    // TODO: readonly attribute long  cellIndex;
4628
4629    // Not really necessary but might be helpful in debugging
4630    toString: function() {
4631        return '[object HTMLTableCellElement]';
4632    }
4633
4634});
4635
4636}(/*HTMLTableCellElement*/));
4637
4638/**
4639 * HTMLTableDataCellElement
4640 * HTML5: 4.9.9 The td Element
4641 * http://dev.w3.org/html5/spec/Overview.html#the-td-element
4642 */
4643(function(){
4644   
4645var log = Envjs.logger();
4646
4647Envjs.once('tick', function(){
4648    log = Envjs.logger('Envjs.HTML.HTMLTableDataCellElement').
4649                debug('HTMLTableDataCellElement available');   
4650});
4651
4652exports.HTMLTableDataCellElement = HTMLTableDataCellElement = function(ownerDocument) {
4653    HTMLElement.apply(this, arguments);
4654};
4655HTMLTableDataCellElement.prototype = new HTMLTableCellElement();
4656__extend__(HTMLTableDataCellElement.prototype, {
4657
4658    // adds no new properties or methods
4659
4660    toString: function() {
4661        return '[object HTMLTableDataCellElement]';
4662    }
4663});
4664
4665}(/*HTMLTableDataCellElement*/));
4666
4667
4668
4669/**
4670 * HTMLTableHeaderCellElement
4671 * HTML5: 4.9.10 The th Element
4672 * http://dev.w3.org/html5/spec/Overview.html#the-th-element
4673 */
4674(function(){
4675   
4676var log = Envjs.logger();
4677
4678Envjs.once('tick', function(){
4679    log = Envjs.logger('Envjs.HTML.HTMLTableHeaderCellElement').
4680                debug('HTMLTableHeaderCellElement available');   
4681});
4682
4683exports.HTMLTableHeaderCellElement = HTMLTableHeaderCellElement = function(ownerDocument) {
4684    HTMLElement.apply(this, arguments);
4685};
4686HTMLTableHeaderCellElement.prototype = new HTMLTableCellElement();
4687__extend__(HTMLTableHeaderCellElement.prototype, {
4688    // TODO:  attribute DOMString scope
4689    toString: function() {
4690        return '[object HTMLTableHeaderCellElement]';
4691    }
4692});
4693
4694}(/*HTMLTableHeaderCellElement*/));
4695
4696
4697/**
4698 * HTMLTextAreaElement - DOM Level 2
4699 * HTML5: 4.10.11 The textarea element
4700 * http://dev.w3.org/html5/spec/Overview.html#the-textarea-element
4701 */
4702 
4703(function(){
4704   
4705var log = Envjs.logger();
4706
4707Envjs.once('tick', function(){
4708    log = Envjs.logger('Envjs.HTML.HTMLTextAreaElement').
4709                debug('HTMLTextAreaElement available');   
4710});
4711
4712exports.HTMLTextAreaElement = HTMLTextAreaElement = function(ownerDocument) {
4713    HTMLInputAreaCommon.apply(this, arguments);
4714    this._rawvalue = null;
4715};
4716HTMLTextAreaElement.prototype = new HTMLInputAreaCommon();
4717__extend__(HTMLTextAreaElement.prototype, {
4718    get cols(){
4719        return Number(this.getAttribute('cols')||'-1');
4720    },
4721    set cols(value){
4722        this.setAttribute('cols', value);
4723    },
4724    get rows(){
4725        return Number(this.getAttribute('rows')||'-1');
4726    },
4727    set rows(value){
4728        this.setAttribute('rows', value);
4729    },
4730
4731    /*
4732     * read-only
4733     */
4734    get type() {
4735        return this.getAttribute('type') || 'textarea';
4736    },
4737
4738    /**
4739     * This modifies the text node under the widget
4740     */
4741    get defaultValue() {
4742        return this.textContent;
4743    },
4744    set defaultValue(value) {
4745        this.textContent = value;
4746    },
4747
4748    /**
4749     * http://dev.w3.org/html5/spec/Overview.html#concept-textarea-raw-value
4750     */
4751    get value() {
4752        return (this._rawvalue === null) ? this.defaultValue : this._rawvalue;
4753    },
4754    set value(value) {
4755        this._rawvalue = value;
4756    },
4757    toString: function() {
4758        return '[object HTMLTextAreaElement]';
4759    }
4760});
4761
4762// Named Element Support
4763HTMLElement.registerSetAttribute('TEXTAREA', 'name', __updateFormForNamedElement__);
4764
4765}(/*HTMLTextAreaElement*/));
4766
4767/**
4768 * HTMLTitleElement - DOM Level 2
4769 *
4770 * HTML5: 4.2.2 The title element
4771 * http://dev.w3.org/html5/spec/Overview.html#the-title-element-0
4772 */
4773 
4774(function(){
4775   
4776var log = Envjs.logger();
4777
4778Envjs.once('tick', function(){
4779    log = Envjs.logger('Envjs.HTML.HTMLTitleElement').
4780                debug('HTMLTitleElement available');   
4781});
4782
4783exports.HTMLTitleElement = HTMLTitleElement = function(ownerDocument) {
4784    HTMLElement.apply(this, arguments);
4785};
4786HTMLTitleElement.prototype = new HTMLElement();
4787__extend__(HTMLTitleElement.prototype, {
4788    get text() {
4789        return this.innerText;
4790    },
4791
4792    set text(titleStr) {
4793        this.textContent = titleStr;
4794    },
4795    toString: function() {
4796        return '[object HTMLTitleElement]';
4797    }
4798});
4799
4800}(/*HTMLTitleElement*/));
4801
4802/**
4803 * HTMLRowElement - DOM Level 2
4804 * Implementation Provided by Steven Wood
4805 *
4806 * HTML5: 4.9.8 The tr element
4807 * http://dev.w3.org/html5/spec/Overview.html#the-tr-element
4808 */
4809 
4810(function(){
4811   
4812var log = Envjs.logger();
4813
4814Envjs.once('tick', function(){
4815    log = Envjs.logger('Envjs.HTML.HTMLTableRowElement').
4816                debug('HTMLTableRowElement available');   
4817});
4818
4819exports.HTMLTableRowElement = HTMLTableRowElement = function(ownerDocument) {
4820    HTMLElement.apply(this, arguments);
4821};
4822HTMLTableRowElement.prototype = new HTMLElement();
4823__extend__(HTMLTableRowElement.prototype, {
4824
4825    /*appendChild : function (child) {
4826
4827      var retVal = Node.prototype.appendChild.apply(this, arguments);
4828      retVal.cellIndex = this.cells.length -1;
4829
4830      return retVal;
4831      },*/
4832    // align gets or sets the horizontal alignment of data within cells of the row.
4833    get align() {
4834        return this.getAttribute("align");
4835    },
4836
4837    get bgColor() {
4838        return this.getAttribute("bgcolor");
4839    },
4840
4841    get cells() {
4842        var nl = this.getElementsByTagName("td");
4843        return new HTMLCollection(nl);
4844    },
4845
4846    get ch() {
4847        return this.getAttribute("ch");
4848    },
4849
4850    set ch(ch) {
4851        this.setAttribute("ch", ch);
4852    },
4853
4854    // ch gets or sets the alignment character for cells in a column.
4855    set chOff(chOff) {
4856        this.setAttribute("chOff", chOff);
4857    },
4858
4859    get chOff() {
4860        return this.getAttribute("chOff");
4861    },
4862
4863    /**
4864     * http://dev.w3.org/html5/spec/Overview.html#dom-tr-rowindex
4865     */
4866    get rowIndex() {
4867        var nl = this.parentNode.childNodes;
4868        for (var i=0; i<nl.length; i++) {
4869            if (nl[i] === this) {
4870                return i;
4871            }
4872        }
4873        return -1;
4874    },
4875
4876    /**
4877     * http://dev.w3.org/html5/spec/Overview.html#dom-tr-sectionrowindex
4878     */
4879    get sectionRowIndex() {
4880        var nl = this.parentNode.getElementsByTagName(this.tagName);
4881        for (var i=0; i<nl.length; i++) {
4882            if (nl[i] === this) {
4883                return i;
4884            }
4885        }
4886        return -1;
4887    },
4888
4889    get vAlign () {
4890        return this.getAttribute("vAlign");
4891    },
4892
4893    insertCell : function (idx) {
4894        if (idx === undefined) {
4895            throw new Error("Index omitted in call to HTMLTableRow.insertCell");
4896        }
4897
4898        var numCells = this.cells.length,
4899        node = null;
4900
4901        if (idx > numCells) {
4902            throw new Error("Index > rows.length in call to HTMLTableRow.insertCell");
4903        }
4904
4905        var cell = document.createElement("td");
4906
4907        if (idx === -1 || idx === numCells) {
4908            this.appendChild(cell);
4909        } else {
4910
4911
4912            node = this.firstChild;
4913
4914            for (var i=0; i<idx; i++) {
4915                node = node.nextSibling;
4916            }
4917        }
4918
4919        this.insertBefore(cell, node);
4920        cell.cellIndex = idx;
4921
4922        return cell;
4923    },
4924    deleteCell : function (idx) {
4925        var elem = this.cells[idx];
4926        this.removeChild(elem);
4927    },
4928    toString: function() {
4929        return '[object HTMLTableRowElement]';
4930    }
4931
4932});
4933
4934}(/*HTMLTableRowElement*/));
4935
4936/*
4937 * HTMLUListElement
4938 * HTML5: 4.5.7 The ul Element
4939 * http://dev.w3.org/html5/spec/Overview.html#htmlhtmlelement
4940 */
4941 
4942(function(){
4943   
4944var log = Envjs.logger();
4945
4946Envjs.once('tick', function(){
4947    log = Envjs.logger('Envjs.HTML.HTMLUListElement').
4948                debug('HTMLUListElement available');   
4949});
4950
4951exports.HTMLUListElement = HTMLUListElement = function(ownerDocument) {
4952    HTMLElement.apply(this, arguments);
4953};
4954
4955HTMLUListElement.prototype = new HTMLElement();
4956__extend__(HTMLUListElement.prototype, {
4957    // no additional properties or elements
4958    toString: function() {
4959        return '[object HTMLUListElement]';
4960    }
4961});
4962
4963}(/*HTMLUListElement*/));
4964
4965/**
4966 * HTMLUnknownElement DOM Level 2
4967 */
4968 
4969(function(){
4970   
4971var log = Envjs.logger();
4972
4973Envjs.once('tick', function(){
4974    log = Envjs.logger('Envjs.HTML.HTMLUnknownElement').
4975                debug('HTMLUnknownElement available');   
4976});
4977
4978exports.HTMLUnknownElement = HTMLUnknownElement = function(ownerDocument) {
4979    HTMLElement.apply(this, arguments);
4980};
4981HTMLUnknownElement.prototype = new HTMLElement();
4982__extend__(HTMLUnknownElement.prototype,{
4983    toString: function(){
4984        return '[object HTMLUnknownElement]';
4985    }
4986});
4987
4988}(/*HTMLUnknownElement*/));
4989
4990/**
4991 * @author john resig & the envjs team
4992 * @uri http://www.envjs.com/
4993 * @copyright 2008-2010
4994 * @license MIT
4995 */
4996//CLOSURE_END
4997}());
Note: See TracBrowser for help on using the repository browser.