Changeset 602

Show
Ignore:
Timestamp:
02/04/06 08:03:33 (3 years ago)
Author:
therve@gmail.com
Message:
  • Fusion Effects into Visual
  • Update docs/examples
  • Sync with trunk
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • mochikit/branches/scriptaculous/MochiKit/Base.js

    r575 r602  
    313313        ***/ 
    314314        for (var i = 0; i < arguments.length; i++) { 
    315             if (arguments[i] != null) { 
     315            if (arguments[i] !== null) { 
    316316                return false; 
    317317            } 
     
    379379        for (var i = 0; i < arguments.length; i++) { 
    380380            var o = arguments[i]; 
    381             if (typeof(o) != "object" || typeof(o.getTime) != 'function') { 
     381            if (typeof(o) != "object" || o == null 
     382                    || typeof(o.getTime) != 'function') { 
    382383                return false; 
    383384            } 
  • mochikit/branches/scriptaculous/MochiKit/Controls.js

    r594 r602  
    505505                    }); 
    506506                } 
    507                 Effect.Appear(update, {duration:0.15}); 
     507                MochiKit.Visual.Appear(update, {duration:0.15}); 
    508508            }; 
    509509        this.options.onHide = this.options.onHide || function (element, update) { 
    510                 new Effect.Fade(update, {duration: 0.15}); 
     510                new MochiKit.Visual.Fade(update, {duration: 0.15}); 
    511511            }; 
    512512 
     
    977977            rows: 1, 
    978978            onComplete: function (transport, element) { 
    979                 new Effect.Highlight(element, {startcolor: this.options.highlightcolor}); 
     979                new MochiKit.Visual.Highlight(element, {startcolor: this.options.highlightcolor}); 
    980980            }, 
    981981            onFailure: function (transport) { 
     
    12491249            return; 
    12501250        } 
    1251         this.effect = new Effect.Highlight(this.element, { 
     1251        this.effect = new MochiKit.Visual.Highlight(this.element, { 
    12521252            startcolor: this.options.highlightcolor, 
    12531253            endcolor: this.options.highlightendcolor, 
  • mochikit/branches/scriptaculous/MochiKit/DOM.js

    r575 r602  
    137137}; 
    138138 
    139 MochiKit.DOM.elementDimensions = function (elem) { 
    140     var self = MochiKit.DOM; 
    141     if (typeof(elem.w) == 'number' || typeof(elem.h) == 'number') { 
    142         return new self.Dimensions(elem.w || 0, elem.h || 0); 
    143     } 
    144     elem = self.getElement(elem); 
    145     if (!elem) { 
    146         return undefined; 
    147     } 
    148     if (self.computedStyle(elem, 'display') != 'none') { 
    149         return new self.Dimensions(elem.offsetWidth || 0,  
    150             elem.offsetHeight || 0); 
    151     } 
    152     var s = elem.style; 
    153     var originalVisibility = s.visibility; 
    154     var originalPosition = s.position; 
    155     s.visibility = 'hidden'; 
    156     s.position = 'absolute'; 
    157     s.display = ''; 
    158     var originalWidth = elem.offsetWidth; 
    159     var originalHeight = elem.offsetHeight; 
    160     s.display = 'none'; 
    161     s.position = originalPosition; 
    162     s.visibility = originalVisibility; 
    163     return new self.Dimensions(originalWidth, originalHeight); 
    164 }; 
    165  
    166 MochiKit.DOM.elementPosition = function (elem, /* optional */relativeTo) { 
    167     var self = MochiKit.DOM; 
    168     elem = self.getElement(elem); 
    169     if (!elem) { 
    170         return undefined; 
    171     } 
    172     var x = 0; 
    173     var y = 0; 
    174     if (elem.offsetParent) { 
    175         while (elem.offsetParent) { 
    176             x += elem.offsetLeft || 0; 
    177             y += elem.offsetTop || 0; 
    178             elem = elem.offsetParent; 
    179         } 
    180     } else { 
    181         x = elem.x || 0; 
    182         y = elem.y || 0; 
    183     } 
    184     if (relativeTo) { 
    185         relativeTo = arguments.callee(relativeTo); 
     139MochiKit.Base.update(MochiKit.DOM, { 
     140    elementDimensions: function (elem) { 
     141        var self = MochiKit.DOM; 
     142        if (typeof(elem.w) == 'number' || typeof(elem.h) == 'number') { 
     143            return new self.Dimensions(elem.w || 0, elem.h || 0); 
     144        } 
     145        elem = self.getElement(elem); 
     146        if (!elem) { 
     147            return undefined; 
     148        } 
     149        if (self.computedStyle(elem, 'display') != 'none') { 
     150            return new self.Dimensions(elem.offsetWidth || 0,  
     151                elem.offsetHeight || 0); 
     152        } 
     153        var s = elem.style; 
     154        var originalVisibility = s.visibility; 
     155        var originalPosition = s.position; 
     156        s.visibility = 'hidden'; 
     157        s.position = 'absolute'; 
     158        s.display = ''; 
     159        var originalWidth = elem.offsetWidth; 
     160        var originalHeight = elem.offsetHeight; 
     161        s.display = 'none'; 
     162        s.position = originalPosition; 
     163        s.visibility = originalVisibility; 
     164        return new self.Dimensions(originalWidth, originalHeight); 
     165    }, 
     166 
     167    elementPosition: function (elem, /* optional */relativeTo) { 
     168        var self = MochiKit.DOM; 
     169        elem = self.getElement(elem); 
     170        if (!elem) { 
     171            return undefined; 
     172        } 
     173        var x = 0; 
     174        var y = 0; 
     175        if (elem.offsetParent) { 
     176            while (elem.offsetParent) { 
     177                x += elem.offsetLeft || 0; 
     178                y += elem.offsetTop || 0; 
     179                elem = elem.offsetParent; 
     180            } 
     181        } else { 
     182            x = elem.x || 0; 
     183            y = elem.y || 0; 
     184        } 
    186185        if (relativeTo) { 
    187             x -= (relativeTo.x || 0); 
    188             y -= (relativeTo.y || 0); 
    189         } 
    190     } 
    191     return new self.Coordinates(x, y); 
    192 }; 
    193      
    194 MochiKit.DOM.currentWindow = function () { 
    195     return MochiKit.DOM._window; 
    196 }; 
    197  
    198 MochiKit.DOM.currentDocument = function () { 
    199     return MochiKit.DOM._document; 
    200 }; 
    201  
    202 MochiKit.DOM.withWindow = function (win, func) { 
    203     var self = MochiKit.DOM; 
    204     var oldDoc = self._document; 
    205     var oldWin = self._win; 
    206     var rval; 
    207     try { 
    208         self._window = win; 
    209         self._document = win.document; 
    210         rval = func(); 
    211     } catch (e) { 
     186            relativeTo = arguments.callee(relativeTo); 
     187            if (relativeTo) { 
     188                x -= (relativeTo.x || 0); 
     189                y -= (relativeTo.y || 0); 
     190            } 
     191        } 
     192        return new self.Coordinates(x, y); 
     193    }, 
     194         
     195    currentWindow: function () { 
     196        return MochiKit.DOM._window; 
     197    }, 
     198 
     199    currentDocument: function () { 
     200        return MochiKit.DOM._document; 
     201    }, 
     202 
     203    withWindow: function (win, func) { 
     204        var self = MochiKit.DOM; 
     205        var oldDoc = self._document; 
     206        var oldWin = self._win; 
     207        var rval; 
     208        try { 
     209            self._window = win; 
     210            self._document = win.document; 
     211            rval = func(); 
     212        } catch (e) { 
     213            self._window = oldWin; 
     214            self._document = oldDoc; 
     215            throw e; 
     216        } 
    212217        self._window = oldWin; 
    213218        self._document = oldDoc; 
    214         throw e; 
    215     } 
    216     self._window = oldWin; 
    217     self._document = oldDoc; 
    218     return rval; 
    219 }; 
    220  
    221 MochiKit.DOM.formContents = function (elem/* = document */) { 
    222     var names = []; 
    223     var values = []; 
    224     var m = MochiKit.Base; 
    225     var self = MochiKit.DOM; 
    226     if (typeof(elem) == "undefined" || elem == null) { 
    227         elem = self._document; 
    228     } else { 
    229         elem = self.getElement(elem); 
    230     } 
    231     m.nodeWalk(elem, function (elem) { 
    232         var name = elem.name; 
    233         if (m.isNotEmpty(name)) { 
    234             var tagName = elem.nodeName; 
    235             if (tagName == "INPUT" 
    236                 && (elem.type == "radio" || elem.type == "checkbox") 
    237                 && !elem.checked 
    238             ) { 
    239                 return null; 
    240             } 
    241             if (tagName == "SELECT") { 
    242                 if (elem.type == "select-one") { 
    243                     var index = elem.selectedIndex; 
    244                     if (index >= 0) { 
    245                         var opt = elem.options[index]; 
    246                         names.push(name); 
    247                         values.push((opt.value) ? opt.value : opt.text); 
    248                     } 
     219        return rval; 
     220    }, 
     221 
     222    formContents: function (elem/* = document */) { 
     223        var names = []; 
     224        var values = []; 
     225        var m = MochiKit.Base; 
     226        var self = MochiKit.DOM; 
     227        if (typeof(elem) == "undefined" || elem == null) { 
     228            elem = self._document; 
     229        } else { 
     230            elem = self.getElement(elem); 
     231        } 
     232        m.nodeWalk(elem, function (elem) { 
     233            var name = elem.name; 
     234            if (m.isNotEmpty(name)) { 
     235                var tagName = elem.nodeName; 
     236                if (tagName == "INPUT" 
     237                    && (elem.type == "radio" || elem.type == "checkbox") 
     238                    && !elem.checked 
     239                ) { 
    249240                    return null; 
    250                 } else { 
     241                } 
     242                if (tagName == "SELECT") { 
    251243                    var opts = elem.options; 
    252244                    for (var i=0; i < opts.length; i++) { 
     
    260252                    return null; 
    261253                } 
    262             } 
    263             if (tagName == "FORM" || tagName == "P" || tagName == "SPAN" 
    264                 || tagName == "DIV" 
    265             ) { 
    266                 return elem.childNodes; 
    267             } 
    268             names.push(name); 
    269             values.push(elem.value || ''); 
    270             return null; 
    271         } 
    272         return elem.childNodes; 
    273     }); 
    274     return [names, values]; 
    275 }; 
    276  
    277 MochiKit.DOM.withDocument = function (doc, func) { 
    278     var self = MochiKit.DOM; 
    279     var oldDoc = self._document; 
    280     var rval; 
    281     try { 
    282         self._document = doc; 
    283         rval = func(); 
    284     } catch (e) { 
     254                if (tagName == "FORM" || tagName == "P" || tagName == "SPAN" 
     255                    || tagName == "DIV" 
     256                ) { 
     257                    return elem.childNodes; 
     258                } 
     259                names.push(name); 
     260                values.push(elem.value || ''); 
     261                return null; 
     262            } 
     263            return elem.childNodes; 
     264        }); 
     265        return [names, values]; 
     266    }, 
     267 
     268    withDocument: function (doc, func) { 
     269        var self = MochiKit.DOM; 
     270        var oldDoc = self._document; 
     271        var rval; 
     272        try { 
     273            self._document = doc; 
     274            rval = func(); 
     275        } catch (e) { 
     276            self._document = oldDoc; 
     277            throw e; 
     278        } 
    285279        self._document = oldDoc; 
    286         throw e; 
    287     } 
    288     self._document = oldDoc; 
    289     return rval; 
    290 }; 
    291  
    292 MochiKit.DOM.registerDOMConverter = function (name, check, wrap, /* optional */override) { 
    293     /*** 
    294  
    295         Register an adapter to convert objects that match check(obj, ctx) 
    296         to a DOM element, or something that can be converted to a DOM 
    297         element (i.e. number, bool, string, function, iterable). 
    298  
    299     ***/ 
    300     MochiKit.DOM.domConverters.register(name, check, wrap, override); 
    301 }; 
    302  
    303 MochiKit.DOM.coerceToDOM = function (node, ctx) { 
    304     /*** 
    305  
    306         Used internally by createDOM, coerces a node to null, a DOM object, 
    307         or an iterable. 
    308  
    309     ***/ 
    310  
    311     var im = MochiKit.Iter; 
    312     var self = MochiKit.DOM; 
    313     var iter = im.iter; 
    314     var repeat = im.repeat; 
    315     var imap = im.imap; 
    316     var domConverters = self.domConverters; 
    317     var coerceToDOM = self.coerceToDOM; 
    318     var NotFound = MochiKit.Base.NotFound; 
    319     while (true) { 
    320         if (typeof(node) == 'undefined' || node == null) { 
    321             return null; 
    322         } 
    323         if (typeof(node.nodeType) != 'undefined' && node.nodeType > 0) { 
    324             return node; 
    325         } 
    326         if (typeof(node) == 'number' || typeof(node) == 'bool') { 
    327             node = node.toString(); 
    328             // FALL THROUGH 
    329         } 
    330         if (typeof(node) == 'string') { 
    331             return self._document.createTextNode(node); 
    332         } 
    333         if (typeof(node.toDOM) == 'function') { 
    334             node = node.toDOM(ctx); 
    335             continue; 
    336         } 
    337         if (typeof(node) == 'function') { 
    338             node = node(ctx); 
    339             continue; 
    340         } 
    341  
    342         // iterable 
    343         var iterNodes = null; 
     280        return rval; 
     281    }, 
     282 
     283    registerDOMConverter: function (name, check, wrap, /* optional */override) { 
     284        /*** 
     285 
     286            Register an adapter to convert objects that match check(obj, ctx) 
     287            to a DOM element, or something that can be converted to a DOM 
     288            element (i.e. number, bool, string, function, iterable). 
     289 
     290        ***/ 
     291        MochiKit.DOM.domConverters.register(name, check, wrap, override); 
     292    }, 
     293 
     294    coerceToDOM: function (node, ctx) { 
     295        /*** 
     296 
     297            Used internally by createDOM, coerces a node to null, a DOM object, 
     298            or an iterable. 
     299 
     300        ***/ 
     301 
     302        var im = MochiKit.Iter; 
     303        var self = MochiKit.DOM; 
     304        var iter = im.iter; 
     305        var repeat = im.repeat; 
     306        var imap = im.imap; 
     307        var domConverters = self.domConverters; 
     308        var coerceToDOM = self.coerceToDOM; 
     309        var NotFound = MochiKit.Base.NotFound; 
     310        while (true) { 
     311            if (typeof(node) == 'undefined' || node == null) { 
     312                return null; 
     313            } 
     314            if (typeof(node.nodeType) != 'undefined' && node.nodeType > 0) { 
     315                return node; 
     316            } 
     317            if (typeof(node) == 'number' || typeof(node) == 'bool') { 
     318                node = node.toString(); 
     319                // FALL THROUGH 
     320            } 
     321            if (typeof(node) == 'string') { 
     322                return self._document.createTextNode(node); 
     323            } 
     324            if (typeof(node.toDOM) == 'function') { 
     325                node = node.toDOM(ctx); 
     326                continue; 
     327            } 
     328            if (typeof(node) == 'function') { 
     329                node = node(ctx); 
     330                continue; 
     331            } 
     332 
     333            // iterable 
     334            var iterNodes = null; 
     335            try { 
     336                iterNodes = iter(node); 
     337            } catch (e) { 
     338                // pass 
     339            } 
     340            if (iterNodes) { 
     341                return imap( 
     342                    coerceToDOM, 
     343                    iterNodes, 
     344                    repeat(ctx) 
     345                ); 
     346            } 
     347 
     348            // adapter 
     349            try { 
     350                node = domConverters.match(node, ctx); 
     351                continue; 
     352            } catch (e) { 
     353                if (e != NotFound) { 
     354                    throw e; 
     355                } 
     356            } 
     357 
     358            // fallback 
     359            return self._document.createTextNode(node.toString()); 
     360        } 
     361        // mozilla warnings aren't too bright 
     362        return undefined; 
     363    }, 
     364         
     365    setNodeAttribute: function (node, attr, value) { 
     366        var o = {}; 
     367        o[attr] = value; 
    344368        try { 
    345             iterNodes = iter(node); 
     369            return MochiKit.DOM.updateNodeAttributes(node, o); 
    346370        } catch (e) { 
    347371            // pass 
    348372        } 
    349         if (iterNodes) { 
    350             return imap( 
    351                 coerceToDOM, 
    352                 iterNodes, 
    353                 repeat(ctx) 
    354             ); 
    355         } 
    356  
    357         // adapter 
     373        return null; 
     374    }, 
     375 
     376    getNodeAttribute: function (node, attr) { 
     377        var self = MochiKit.DOM; 
     378        var rename = self.attributeArray.renames[attr]; 
     379        node = self.getElement(node); 
    358380        try { 
    359             node = domConverters.match(node, ctx); 
    360             continue; 
     381            if (rename) { 
     382                return node[rename]; 
     383            } 
     384            return node.getAttribute(attr); 
    361385        } catch (e) { 
    362             if (e != NotFound) { 
    363                 throw e; 
    364             } 
    365         } 
    366  
    367         // fallback 
    368         return self._document.createTextNode(node.toString()); 
     386            // pass 
     387        } 
     388        return null; 
     389    }, 
     390 
     391    updateNodeAttributes: function (node, attrs) { 
     392        var elem = node; 
     393        var self = MochiKit.DOM; 
     394        if (typeof(node) == 'string') { 
     395            elem = self.getElement(node); 
     396        } 
     397        if (attrs) { 
     398            var updatetree = MochiKit.Base.updatetree; 
     399            if (self.attributeArray.compliant) { 
     400                // not IE, good. 
     401                for (var k in attrs) { 
     402                    var v = attrs[k]; 
     403                    if (typeof(v) == 'object' && typeof(elem[k]) == 'object') { 
     404                        updatetree(elem[k], v); 
     405                    } else if (k.substring(0, 2) == "on") { 
     406                        if (typeof(v) == "string") { 
     407                            v = new Function(v); 
     408                        } 
     409                        elem[k] = v; 
     410                    } else { 
     411                        elem.setAttribute(k, v); 
     412                    } 
     413                } 
     414            } else { 
     415                // IE is insane in the membrane 
     416                var renames = self.attributeArray.renames; 
     417                for (k in attrs) { 
     418                    v = attrs[k]; 
     419                    var renamed = renames[k]; 
     420                    if (k == "style" && typeof(v) == "string") { 
     421                        elem.style.cssText = v; 
     422                    } else if (typeof(renamed) == "string") { 
     423                        elem[renamed] = v; 
     424                    } else if (typeof(elem[k]) == 'object' 
     425                            && typeof(v) == 'object') { 
     426                        updatetree(elem[k], v); 
     427                    } else if (k.substring(0, 2) == "on") { 
     428                        if (typeof(v) == "string") { 
     429                            v = new Function(v); 
     430                        } 
     431                        elem[k] = v; 
     432                    } else { 
     433                        elem.setAttribute(k, v); 
     434                    } 
     435                } 
     436            } 
     437        } 
     438        return elem; 
     439    }, 
     440 
     441    appendChildNodes: function (node/*, nodes...*/) { 
     442        var elem = node; 
     443        var self = MochiKit.DOM; 
     444        if (typeof(node) == 'string') { 
     445            elem = self.getElement(node); 
     446        } 
     447        var nodeStack = [ 
     448            self.coerceToDOM( 
     449                MochiKit.Base.extend(null, arguments, 1), 
     450                elem 
     451            ) 
     452        ]; 
     453        var iextend = MochiKit.Iter.iextend; 
     454        while (nodeStack.length) { 
     455            var n = nodeStack.shift(); 
     456            if (typeof(n) == 'undefined' || n == null) { 
     457                // pass 
     458            } else if (typeof(n.nodeType) == 'number') { 
     459                elem.appendChild(n); 
     460            } else { 
     461                iextend(nodeStack, n); 
     462            } 
     463        } 
     464        return elem; 
     465    }, 
     466 
     467    replaceChildNodes: function (node/*, nodes...*/) { 
     468        var elem = node; 
     469        var self = MochiKit.DOM; 
     470        if (typeof(node) == 'string') { 
     471            elem = self.getElement(node); 
     472            arguments[0] = elem; 
     473        } 
     474        var child; 
     475        while ((child = elem.firstChild)) { 
     476            elem.removeChild(child); 
     477        } 
     478        if (arguments.length < 2) { 
     479            return elem; 
     480        } else { 
     481            return self.appendChildNodes.apply(this, arguments); 
     482        } 
     483    }, 
     484 
     485    createDOM: function (name, attrs/*, nodes... */) { 
     486        /* 
     487 
     488            Create a DOM fragment in a really convenient manner, much like 
     489            Nevow's <http://nevow.com> stan. 
     490 
     491        */ 
     492 
     493        var elem; 
     494        var self = MochiKit.DOM; 
     495        if (typeof(name) == 'string') { 
     496            // Internet Explorer is dumb 
     497            if (attrs && "name" in attrs && !self.attributeArray.compliant) { 
     498                // http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/name_2.asp 
     499                name = ('<' + name + ' name="' + self.escapeHTML(attrs.name) 
     500                    + '">'); 
     501            } 
     502            elem = self._document.createElement(name); 
     503        } else { 
     504            elem = name; 
     505        } 
     506        if (attrs) { 
     507            self.updateNodeAttributes(elem, attrs); 
     508        } 
     509        if (arguments.length <= 2) { 
     510            return elem; 
     511        } else { 
     512            var args = MochiKit.Base.extend([elem], arguments, 2); 
     513            return self.appendChildNodes.apply(this, args); 
     514        } 
     515    }, 
     516 
     517    createDOMFunc: function (/* tag, attrs, *nodes */) { 
     518        /*** 
     519 
     520            Convenience function to create a partially applied createDOM 
     521 
     522            @param tag: The name of the tag 
     523 
     524            @param attrs: Optionally specify the attributes to apply 
     525 
     526            @param *notes: Optionally specify any children nodes it should have 
     527 
     528            @rtype: function 
     529 
     530        ***/ 
     531        var m = MochiKit.Base; 
     532        return m.partial.apply( 
     533            this, 
     534            m.extend([MochiKit.DOM.createDOM], arguments) 
     535        ); 
     536    }, 
     537 
     538    swapDOM: function (dest, src) { 
     539        /*** 
     540 
     541            Replace dest in a DOM tree with src, returning src 
     542 
     543            @param dest: a DOM element to be replaced 
     544 
     545            @param src: the DOM element to replace it with 
     546                        or null if the DOM element should be removed 
     547 
     548            @rtype: a DOM element (src) 
     549 
     550        ***/ 
     551        var self = MochiKit.DOM; 
     552        dest = self.getElement(dest); 
     553        var parent = dest.parentNode; 
     554        if (src) { 
     555            src = self.getElement(src); 
     556            parent.replaceChild(src, dest); 
     557        } else { 
     558            parent.removeChild(dest); 
     559        } 
     560        return src; 
     561    }, 
     562 
     563    getElement: function (id) { 
     564        /*** 
     565 
     566            A small quick little function to encapsulate the getElementById 
     567            method.  It includes a check to ensure we can use that method. 
     568 
     569            If the id isn't a string, it will be returned as-is. 
     570 
     571            Also available as $(...) for compatibility/convenience with "other" 
     572            js frameworks (bah). 
     573 
     574        ***/ 
     575        var self = MochiKit.DOM; 
     576        if (arguments.length == 1) { 
     577            return ((typeof(id) == "string") ? 
     578                self._document.getElementById(id) : id); 
     579        } else { 
     580            return MochiKit.Base.map(self.getElement, arguments); 
     581        } 
     582    }, 
     583 
     584    computedStyle: function (htmlElement, cssProperty, mozillaEquivalentCSS) { 
     585        if (arguments.length == 2) { 
     586            mozillaEquivalentCSS = cssProperty; 
     587        }    
     588        var self = MochiKit.DOM; 
     589        var el = self.getElement(htmlElement); 
     590        var document = self._document; 
     591        if (!el || el == document) { 
     592            return undefined; 
     593        } 
     594        if (el.currentStyle) { 
     595            return el.currentStyle[cssProperty]; 
     596        } 
     597        if (typeof(document.defaultView) == 'undefined') { 
     598            return undefined; 
     599        } 
     600        if (document.defaultView == null) { 
     601            return undefined; 
     602        } 
     603        var style = document.defaultView.getComputedStyle(el, null); 
     604        if (typeof(style) == "undefined" || style == null) { 
     605            return undefined; 
     606        } 
     607        return style.getPropertyValue(mozillaEquivalentCSS); 
     608    }, 
     609 
     610    getElementsByTagAndClassName: function (tagName, className, 
     611            /* optional */parent) { 
     612        var self = MochiKit.DOM; 
     613        if (typeof(tagName) == 'undefined' || tagName == null) { 
     614            tagName = '*'; 
     615        } 
     616        if (typeof(parent) == 'undefined' || parent == null) { 
     617            parent = self._document; 
     618        } 
     619        parent = self.getElement(parent); 
     620        var children = (parent.getElementsByTagName(tagName) 
     621            || self._document.all); 
     622        if (typeof(className) == 'undefined' || className == null) { 
     623            return MochiKit.Base.extend(null, children); 
     624        } 
     625 
     626        var elements = []; 
     627        for (var i = 0; i < children.length; i++) { 
     628            var child = children[i]; 
     629            var classNames = child.className.split(' '); 
     630            for (var j = 0; j < classNames.length; j++) { 
     631                if (classNames[j] == className) { 
     632                    elements.push(child); 
     633                    break; 
     634                } 
     635            } 
     636        } 
     637 
     638        return elements; 
     639    }, 
     640 
     641    _newCallStack: function (path, once) { 
     642        var rval = function () { 
     643            var callStack = arguments.callee.callStack; 
     644            for (var i = 0; i < callStack.length; i++) { 
     645                if (callStack[i].apply(this, arguments) === false) { 
     646                    break; 
     647                } 
     648            } 
     649            if (once) { 
     650                try { 
     651                    this[path] = null; 
     652                } catch (e) { 
     653                    // pass 
     654                } 
     655            } 
     656        }; 
     657        rval.callStack = []; 
     658        return rval; 
     659    }, 
     660 
     661    addToCallStack: function (target, path, func, once) { 
     662        var self = MochiKit.DOM; 
     663        var existing = target[path]; 
     664        var regfunc = existing; 
     665        if (!(typeof(existing) == 'function' 
     666                && typeof(existing.callStack) == "object" 
     667                && existing.callStack != null)) { 
     668            regfunc = self._newCallStack(path, once); 
     669            if (typeof(existing) == 'function') { 
     670                regfunc.callStack.push(existing); 
     671            } 
     672            target[path] = regfunc; 
     673        } 
     674        regfunc.callStack.push(func); 
     675    }, 
     676 
     677    addLoadEvent: function (func) { 
     678        /*** 
     679 
     680            This will stack load functions on top of each other. 
     681            Each function added will be called after onload in the 
     682            order that they were added. 
     683 
     684        ***/ 
     685        var self = MochiKit.DOM; 
     686        self.addToCallStack(self._window, "onload", func, true); 
     687         
     688    }, 
     689 
     690    focusOnLoad: function (element) { 
     691        var self = MochiKit.DOM; 
     692        self.addLoadEvent(function () { 
     693            element = self.getElement(element); 
     694            if (element) { 
     695                element.focus(); 
     696            } 
     697        }); 
     698    }, 
     699             
     700    setElementClass: function (element, className) { 
     701        /*** 
     702 
     703            Set the entire class attribute of an element to className. 
     704         
     705        ***/ 
     706        var self = MochiKit.DOM; 
     707        var obj = self.getElement(element); 
     708        if (self.attributeArray.compliant) { 
     709            obj.setAttribute("class", className); 
     710        } else { 
     711            obj.setAttribute("className", className); 
     712        } 
     713    }, 
     714             
     715    toggleElementClass: function (className/*, element... */) { 
     716        /*** 
     717         
     718            Toggle the presence of a given className in the class attribute 
     719            of all given elements. 
     720 
     721        ***/ 
     722        var self = MochiKit.DOM; 
     723        for (var i = 1; i < arguments.length; i++) { 
     724            var obj = self.getElement(arguments[i]); 
     725            if (!self.addElementClass(obj, className)) { 
     726                self.removeElementClass(obj, className); 
     727            } 
     728        } 
     729    }, 
     730 
     731    addElementClass: function (element, className) { 
     732        /*** 
     733 
     734            Ensure that the given element has className set as part of its 
     735            class attribute.  This will not disturb other class names. 
     736 
     737        ***/ 
     738        var self = MochiKit.DOM; 
     739        var obj = self.getElement(element); 
     740        var cls = obj.className; 
     741        // trivial case, no className yet 
     742        if (cls.length == 0) { 
     743            self.setElementClass(obj, className); 
     744            return true; 
     745        } 
     746        // the other trivial case, already set as the only class 
     747        if (cls == className) { 
     748            return false; 
     749        } 
     750        var classes = obj.className.split(" "); 
     751        for (var i = 0; i < classes.length; i++) { 
     752            // already present 
     753            if (classes[i] == className) { 
     754                return false; 
     755            } 
     756        } 
     757        // append class 
     758        self.setElementClass(obj, cls + " " + className); 
     759        return true; 
     760    }, 
     761 
     762    removeElementClass: function (element, className) { 
     763        /*** 
     764 
     765            Ensure that the given element does not have className set as part 
     766            of its class attribute.  This will not disturb other class names. 
     767 
     768        ***/ 
     769        var self = MochiKit.DOM; 
     770        var obj = self.getElement(element); 
     771        var cls = obj.className; 
     772        // trivial case, no className yet 
     773        if (cls.length == 0) { 
     774            return false; 
     775        } 
     776        // other trivial case, set only to className 
     777        if (cls == className) { 
     778            self.setElementClass(obj, ""); 
     779            return true; 
     780        } 
     781        var classes = obj.className.split(" "); 
     782        for (var i = 0; i < classes.length; i++) { 
     783            // already present 
     784            if (classes[i] == className) { 
     785                // only check sane case where the class is used once 
     786                classes.splice(i, 1); 
     787                self.setElementClass(obj, classes.join(" ")); 
     788                return true; 
     789            } 
     790        } 
     791        // not found 
     792        return false; 
     793    }, 
     794 
     795    swapElementClass: function (element, fromClass, toClass) { 
     796        /*** 
     797 
     798            If fromClass is set on element, replace it with toClass.  This 
     799            will not disturb other classes on that element. 
     800 
     801        ***/ 
     802        var obj = MochiKit.DOM.getElement(element); 
     803        var res = MochiKit.DOM.removeElementClass(obj, fromClass); 
     804        if (res) { 
     805            MochiKit.DOM.addElementClass(obj, toClass); 
     806        } 
     807        return res; 
     808    }, 
     809 
     810    hasElementClass: function (element, className/*...*/) { 
     811        /*** 
     812           
     813          Return true if className is found in the element 
     814 
     815        ***/ 
     816        var obj = MochiKit.DOM.getElement(element); 
     817        var classes = obj.className.split(" "); 
     818        for (var i = 1; i < arguments.length; i++) { 
     819            var good = false; 
     820            for (var j = 0; j < classes.length; j++) { 
     821                if (classes[j] == arguments[i]) { 
     822                    good = true; 
     823                    break; 
     824                } 
     825            } 
     826            if (!good) { 
     827                return false; 
     828            } 
     829        } 
     830        return true; 
     831    }, 
     832 
     833    escapeHTML: function (s) { 
     834        /*** 
     835 
     836            Make a string safe for HTML, converting the usual suspects (lt, 
     837            gt, quot, amp) 
     838 
     839        ***/ 
     840        return s.replace(/&/g, "&amp;" 
     841            ).replace(/"/g, "&quot;" 
     842            ).replace(/</g, "&lt;" 
     843            ).replace(/>/g, "&gt;"); 
     844    }, 
     845 
     846    toHTML: function (dom) { 
     847        /*** 
     848 
     849            Convert a DOM tree to a HTML string using emitHTML 
     850 
     851        ***/ 
     852        return MochiKit.DOM.emitHTML(dom).join(""); 
     853    }, 
     854 
     855    emitHTML: function (dom, /* optional */lst) { 
     856        /*** 
     857 
     858            Convert a DOM tree to a list of HTML string fragments 
     859 
     860            You probably want to use toHTML instead. 
     861 
     862        ***/ 
     863 
     864        if (typeof(lst) == 'undefined' || lst == null) { 
     865            lst = []; 
     866        } 
     867        // queue is the call stack, we're doing this non-recursively 
     868        var queue = [dom]; 
     869        var self = MochiKit.DOM; 
     870        var escapeHTML = self.escapeHTML; 
     871        var attributeArray = self.attributeArray; 
     872        while (queue.length) { 
     873            dom = queue.pop(); 
     874            if (typeof(dom) == 'string') { 
    &n