tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DOM.js (41646B)


      1 /***
      2 
      3 MochiKit.DOM 1.4
      4 
      5 See <http://mochikit.com/> for documentation, downloads, license, etc.
      6 
      7 (c) 2005 Bob Ippolito.  All rights Reserved.
      8 
      9 ***/
     10 
     11 if (typeof(dojo) != 'undefined') {
     12    dojo.provide("MochiKit.DOM");
     13    dojo.require("MochiKit.Base");
     14 }
     15 if (typeof(JSAN) != 'undefined') {
     16    JSAN.use("MochiKit.Base", []);
     17 }
     18 
     19 try {
     20    if (typeof(MochiKit.Base) == 'undefined') {
     21        throw "";
     22    }
     23 } catch (e) {
     24    throw "MochiKit.DOM depends on MochiKit.Base!";
     25 }
     26 
     27 if (typeof(MochiKit.DOM) == 'undefined') {
     28    MochiKit.DOM = {};
     29 }
     30 
     31 MochiKit.DOM.NAME = "MochiKit.DOM";
     32 MochiKit.DOM.VERSION = "1.4";
     33 MochiKit.DOM.__repr__ = function () {
     34    return "[" + this.NAME + " " + this.VERSION + "]";
     35 };
     36 MochiKit.DOM.toString = function () {
     37    return this.__repr__();
     38 };
     39 
     40 MochiKit.DOM.EXPORT = [
     41    "removeEmptyTextNodes",
     42    "formContents",
     43    "currentWindow",
     44    "currentDocument",
     45    "withWindow",
     46    "withDocument",
     47    "registerDOMConverter",
     48    "coerceToDOM",
     49    "createDOM",
     50    "createDOMFunc",
     51    "isChildNode",
     52    "getNodeAttribute",
     53    "removeNodeAttribute",
     54    "setNodeAttribute",
     55    "updateNodeAttributes",
     56    "appendChildNodes",
     57    "insertSiblingNodesAfter",
     58    "insertSiblingNodesBefore",
     59    "replaceChildNodes",
     60    "removeElement",
     61    "swapDOM",
     62    "BUTTON",
     63    "TT",
     64    "PRE",
     65    "H1",
     66    "H2",
     67    "H3",
     68    "BR",
     69    "CANVAS",
     70    "HR",
     71    "LABEL",
     72    "TEXTAREA",
     73    "FORM",
     74    "STRONG",
     75    "SELECT",
     76    "OPTION",
     77    "OPTGROUP",
     78    "LEGEND",
     79    "FIELDSET",
     80    "P",
     81    "UL",
     82    "OL",
     83    "LI",
     84    "TD",
     85    "TR",
     86    "THEAD",
     87    "TBODY",
     88    "TFOOT",
     89    "TABLE",
     90    "TH",
     91    "INPUT",
     92    "SPAN",
     93    "A",
     94    "DIV",
     95    "IMG",
     96    "getElement",
     97    "$",
     98    "getElementsByTagAndClassName",
     99    "addToCallStack",
    100    "addLoadEvent",
    101    "focusOnLoad",
    102    "setElementClass",
    103    "toggleElementClass",
    104    "addElementClass",
    105    "removeElementClass",
    106    "swapElementClass",
    107    "hasElementClass",
    108    "escapeHTML",
    109    "toHTML",
    110    "emitHTML",
    111    "scrapeText",
    112    "isParent",
    113    "getFirstParentByTagAndClassName",
    114    "makeClipping",
    115    "undoClipping",
    116    "makePositioned",
    117    "undoPositioned",
    118    "getFirstElementByTagAndClassName"
    119 ];
    120 
    121 MochiKit.DOM.EXPORT_OK = [
    122    "domConverters"
    123 ];
    124 
    125 MochiKit.DOM.DEPRECATED = [
    126    ['computedStyle', 'MochiKit.Style.getStyle', '1.4'],
    127    /** @id MochiKit.DOM.elementDimensions  */
    128    ['elementDimensions', 'MochiKit.Style.getElementDimensions', '1.4'],
    129    /** @id MochiKit.DOM.elementPosition  */
    130    ['elementPosition', 'MochiKit.Style.getElementPosition', '1.4'],
    131    ['hideElement', 'MochiKit.Style.hideElement', '1.4'],
    132    /** @id MochiKit.DOM.setElementDimensions */
    133    ['setElementDimensions', 'MochiKit.Style.setElementDimensions', '1.4'],
    134    /** @id MochiKit.DOM.setElementPosition */
    135    ['setElementPosition', 'MochiKit.Style.setElementPosition', '1.4'],
    136    ['setDisplayForElement', 'MochiKit.Style.setDisplayForElement', '1.4'],
    137    /** @id MochiKit.DOM.setOpacity */
    138    ['setOpacity', 'MochiKit.Style.setOpacity', '1.4'],
    139    ['showElement', 'MochiKit.Style.showElement', '1.4'],
    140    /** @id MochiKit.DOM.Coordinates */
    141    ['Coordinates', 'MochiKit.Style.Coordinates', '1.4'], // FIXME: broken
    142    /** @id MochiKit.DOM.Dimensions */
    143    ['Dimensions', 'MochiKit.Style.Dimensions', '1.4'] // FIXME: broken
    144 ];
    145 
    146 /** @id MochiKit.DOM.getViewportDimensions */
    147 MochiKit.DOM.getViewportDimensions = new Function('' +
    148    'if (!MochiKit["Style"]) {' +
    149    '    throw new Error("This function has been deprecated and depends on MochiKit.Style.");' +
    150    '}' +
    151    'return MochiKit.Style.getViewportDimensions.apply(this, arguments);');
    152 
    153 MochiKit.Base.update(MochiKit.DOM, {
    154 
    155    /** @id MochiKit.DOM.currentWindow */
    156    currentWindow: function () {
    157        return MochiKit.DOM._window;
    158    },
    159 
    160    /** @id MochiKit.DOM.currentDocument */
    161    currentDocument: function () {
    162        return MochiKit.DOM._document;
    163    },
    164 
    165    /** @id MochiKit.DOM.withWindow */
    166    withWindow: function (win, func) {
    167        var self = MochiKit.DOM;
    168        var oldDoc = self._document;
    169        var oldWin = self._window;
    170        var rval;
    171        try {
    172            self._window = win;
    173            self._document = win.document;
    174            rval = func();
    175        } catch (e) {
    176            self._window = oldWin;
    177            self._document = oldDoc;
    178            throw e;
    179        }
    180        self._window = oldWin;
    181        self._document = oldDoc;
    182        return rval;
    183    },
    184 
    185    /** @id MochiKit.DOM.formContents  */
    186    formContents: function (elem/* = document.body */) {
    187        var names = [];
    188        var values = [];
    189        var m = MochiKit.Base;
    190        var self = MochiKit.DOM;
    191        if (typeof(elem) == "undefined" || elem === null) {
    192            elem = self._document.body;
    193        } else {
    194            elem = self.getElement(elem);
    195        }
    196        m.nodeWalk(elem, function (elem) {
    197            var name = elem.name;
    198            if (m.isNotEmpty(name)) {
    199                var tagName = elem.tagName.toUpperCase();
    200                if (tagName === "INPUT"
    201                    && (elem.type == "radio" || elem.type == "checkbox")
    202                    && !elem.checked
    203                ) {
    204                    return null;
    205                }
    206                if (tagName === "SELECT") {
    207                    if (elem.type == "select-one") {
    208                        if (elem.selectedIndex >= 0) {
    209                            var opt = elem.options[elem.selectedIndex];
    210                            var v = opt.value;
    211                            if (!v) {
    212                                var h = opt.outerHTML;
    213                                // internet explorer sure does suck.
    214                                if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
    215                                    v = opt.text;
    216                                }
    217                            }
    218                            names.push(name);
    219                            values.push(v);
    220                            return null;
    221                        }
    222                        // no form elements?
    223                        names.push(name);
    224                        values.push("");
    225                        return null;
    226                    } else {
    227                        var opts = elem.options;
    228                        if (!opts.length) {
    229                            names.push(name);
    230                            values.push("");
    231                            return null;
    232                        }
    233                        for (var i = 0; i < opts.length; i++) {
    234                            var opt = opts[i];
    235                            if (!opt.selected) {
    236                                continue;
    237                            }
    238                            var v = opt.value;
    239                            if (!v) {
    240                                var h = opt.outerHTML;
    241                                // internet explorer sure does suck.
    242                                if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
    243                                    v = opt.text;
    244                                }
    245                            }
    246                            names.push(name);
    247                            values.push(v);
    248                        }
    249                        return null;
    250                    }
    251                }
    252                if (tagName === "FORM" || tagName === "P" || tagName === "SPAN"
    253                    || tagName === "DIV"
    254                ) {
    255                    return elem.childNodes;
    256                }
    257                names.push(name);
    258                values.push(elem.value || '');
    259                return null;
    260            }
    261            return elem.childNodes;
    262        });
    263        return [names, values];
    264    },
    265 
    266    /** @id MochiKit.DOM.withDocument */
    267    withDocument: function (doc, func) {
    268        var self = MochiKit.DOM;
    269        var oldDoc = self._document;
    270        var rval;
    271        try {
    272            self._document = doc;
    273            rval = func();
    274        } catch (e) {
    275            self._document = oldDoc;
    276            throw e;
    277        }
    278        self._document = oldDoc;
    279        return rval;
    280    },
    281 
    282    /** @id MochiKit.DOM.registerDOMConverter */
    283    registerDOMConverter: function (name, check, wrap, /* optional */override) {
    284        MochiKit.DOM.domConverters.register(name, check, wrap, override);
    285    },
    286 
    287    /** @id MochiKit.DOM.coerceToDOM */
    288    coerceToDOM: function (node, ctx) {
    289        var m = MochiKit.Base;
    290        var im = MochiKit.Iter;
    291        var self = MochiKit.DOM;
    292        if (im) {
    293            var iter = im.iter;
    294            var repeat = im.repeat;
    295            var map = m.map;
    296        }
    297        var domConverters = self.domConverters;
    298        var coerceToDOM = arguments.callee;
    299        var NotFound = m.NotFound;
    300        while (true) {
    301            if (typeof(node) == 'undefined' || node === null) {
    302                return null;
    303            }
    304            // this is a safari childNodes object, avoiding crashes w/ attr
    305            // lookup
    306            if (typeof(node) == "function" &&
    307                    typeof(node.length) == "number" &&
    308                    !(node instanceof Function)) {
    309                node = im.list(node);
    310            }
    311            if (typeof(node.nodeType) != 'undefined' && node.nodeType > 0) {
    312                return node;
    313            }
    314            if (typeof(node) == 'number' || typeof(node) == 'boolean') {
    315                node = node.toString();
    316                // FALL THROUGH
    317            }
    318            if (typeof(node) == 'string') {
    319                return self._document.createTextNode(node);
    320            }
    321            if (typeof(node.__dom__) == 'function') {
    322                node = node.__dom__(ctx);
    323                continue;
    324            }
    325            if (typeof(node.dom) == 'function') {
    326                node = node.dom(ctx);
    327                continue;
    328            }
    329            if (typeof(node) == 'function') {
    330                node = node.apply(ctx, [ctx]);
    331                continue;
    332            }
    333 
    334            if (im) {
    335                // iterable
    336                var iterNodes = null;
    337                try {
    338                    iterNodes = iter(node);
    339                } catch (e) {
    340                    // pass
    341                }
    342                if (iterNodes) {
    343                    return map(coerceToDOM, iterNodes, repeat(ctx));
    344                }
    345            }
    346 
    347            // adapter
    348            try {
    349                node = domConverters.match(node, ctx);
    350                continue;
    351            } catch (e) {
    352                if (e != NotFound) {
    353                    throw e;
    354                }
    355            }
    356 
    357            // fallback
    358            return self._document.createTextNode(node.toString());
    359        }
    360        // mozilla warnings aren't too bright
    361        return undefined;
    362    },
    363 
    364    /** @id MochiKit.DOM.isChildNode */
    365    isChildNode: function (node, maybeparent) {
    366        var self = MochiKit.DOM;
    367        if (typeof(node) == "string") {
    368            node = self.getElement(node);
    369        }
    370        if (typeof(maybeparent) == "string") {
    371            maybeparent = self.getElement(maybeparent);
    372        }
    373        if (node === maybeparent) {
    374            return true;
    375        }
    376        while (node && node.tagName.toUpperCase() != "BODY") {
    377            node = node.parentNode;
    378            if (node === maybeparent) {
    379                return true;
    380            }
    381        }
    382        return false;
    383    },
    384 
    385    /** @id MochiKit.DOM.setNodeAttribute */
    386    setNodeAttribute: function (node, attr, value) {
    387        var o = {};
    388        o[attr] = value;
    389        try {
    390            return MochiKit.DOM.updateNodeAttributes(node, o);
    391        } catch (e) {
    392            // pass
    393        }
    394        return null;
    395    },
    396 
    397    /** @id MochiKit.DOM.getNodeAttribute */
    398    getNodeAttribute: function (node, attr) {
    399        var self = MochiKit.DOM;
    400        var rename = self.attributeArray.renames[attr];
    401        node = self.getElement(node);
    402        try {
    403            if (rename) {
    404                return node[rename];
    405            }
    406            return node.getAttribute(attr);
    407        } catch (e) {
    408            // pass
    409        }
    410        return null;
    411    },
    412 
    413    /** @id MochiKit.DOM.removeNodeAttribute */
    414    removeNodeAttribute: function (node, attr) {
    415        var self = MochiKit.DOM;
    416        var rename = self.attributeArray.renames[attr];
    417        node = self.getElement(node);
    418        try {
    419            if (rename) {
    420                return node[rename];
    421            }
    422            return node.removeAttribute(attr);
    423        } catch (e) {
    424            // pass
    425        }
    426        return null;
    427    },
    428 
    429    /** @id MochiKit.DOM.updateNodeAttributes */
    430    updateNodeAttributes: function (node, attrs) {
    431        var elem = node;
    432        var self = MochiKit.DOM;
    433        if (typeof(node) == 'string') {
    434            elem = self.getElement(node);
    435        }
    436        if (attrs) {
    437            var updatetree = MochiKit.Base.updatetree;
    438            if (self.attributeArray.compliant) {
    439                // not IE, good.
    440                for (var k in attrs) {
    441                    var v = attrs[k];
    442                    if (typeof(v) == 'object' && typeof(elem[k]) == 'object') {
    443                        if (k == "style" && MochiKit.Style) {
    444                            MochiKit.Style.setStyle(elem, v);
    445                        } else {
    446                            updatetree(elem[k], v);
    447                        }
    448                    } else if (k.substring(0, 2) == "on") {
    449                        if (typeof(v) == "string") {
    450                            v = new Function(v);
    451                        }
    452                        elem[k] = v;
    453                    } else {
    454                        elem.setAttribute(k, v);
    455                    }
    456                }
    457            } else {
    458                // IE is insane in the membrane
    459                var renames = self.attributeArray.renames;
    460                for (var k in attrs) {
    461                    v = attrs[k];
    462                    var renamed = renames[k];
    463                    if (k == "style" && typeof(v) == "string") {
    464                        elem.style.cssText = v;
    465                    } else if (typeof(renamed) == "string") {
    466                        elem[renamed] = v;
    467                    } else if (typeof(elem[k]) == 'object'
    468                            && typeof(v) == 'object') {
    469                        if (k == "style" && MochiKit.Style) {
    470                            MochiKit.Style.setStyle(elem, v);
    471                        } else {
    472                            updatetree(elem[k], v);
    473                        }
    474                    } else if (k.substring(0, 2) == "on") {
    475                        if (typeof(v) == "string") {
    476                            v = new Function(v);
    477                        }
    478                        elem[k] = v;
    479                    } else {
    480                        elem.setAttribute(k, v);
    481                    }
    482                }
    483            }
    484        }
    485        return elem;
    486    },
    487 
    488    /** @id MochiKit.DOM.appendChildNodes */
    489    appendChildNodes: function (node/*, nodes...*/) {
    490        var elem = node;
    491        var self = MochiKit.DOM;
    492        if (typeof(node) == 'string') {
    493            elem = self.getElement(node);
    494        }
    495        var nodeStack = [
    496            self.coerceToDOM(
    497                MochiKit.Base.extend(null, arguments, 1),
    498                elem
    499            )
    500        ];
    501        var concat = MochiKit.Base.concat;
    502        while (nodeStack.length) {
    503            var n = nodeStack.shift();
    504            if (typeof(n) == 'undefined' || n === null) {
    505                // pass
    506            } else if (typeof(n.nodeType) == 'number') {
    507                elem.appendChild(n);
    508            } else {
    509                nodeStack = concat(n, nodeStack);
    510            }
    511        }
    512        return elem;
    513    },
    514 
    515 
    516    /** @id MochiKit.DOM.insertSiblingNodesBefore */
    517    insertSiblingNodesBefore: function (node/*, nodes...*/) {
    518        var elem = node;
    519        var self = MochiKit.DOM;
    520        if (typeof(node) == 'string') {
    521            elem = self.getElement(node);
    522        }
    523        var nodeStack = [
    524            self.coerceToDOM(
    525                MochiKit.Base.extend(null, arguments, 1),
    526                elem
    527            )
    528        ];
    529        var parentnode = elem.parentNode;
    530        var concat = MochiKit.Base.concat;
    531        while (nodeStack.length) {
    532            var n = nodeStack.shift();
    533            if (typeof(n) == 'undefined' || n === null) {
    534                // pass
    535            } else if (typeof(n.nodeType) == 'number') {
    536                parentnode.insertBefore(n, elem);
    537            } else {
    538                nodeStack = concat(n, nodeStack);
    539            }
    540        }
    541        return parentnode;
    542    },
    543 
    544    /** @id MochiKit.DOM.insertSiblingNodesAfter */
    545    insertSiblingNodesAfter: function (node/*, nodes...*/) {
    546        var elem = node;
    547        var self = MochiKit.DOM;
    548 
    549        if (typeof(node) == 'string') {
    550            elem = self.getElement(node);
    551        }
    552        var nodeStack = [
    553            self.coerceToDOM(
    554                MochiKit.Base.extend(null, arguments, 1),
    555                elem
    556            )
    557        ];
    558 
    559        if (elem.nextSibling) {
    560            return self.insertSiblingNodesBefore(elem.nextSibling, nodeStack);
    561        }
    562        else {
    563            return self.appendChildNodes(elem.parentNode, nodeStack);
    564        }
    565    },
    566 
    567    /** @id MochiKit.DOM.replaceChildNodes */
    568    replaceChildNodes: function (node/*, nodes...*/) {
    569        var elem = node;
    570        var self = MochiKit.DOM;
    571        if (typeof(node) == 'string') {
    572            elem = self.getElement(node);
    573            arguments[0] = elem;
    574        }
    575        var child;
    576        while ((child = elem.firstChild)) {
    577            elem.removeChild(child);
    578        }
    579        if (arguments.length < 2) {
    580            return elem;
    581        } else {
    582            return self.appendChildNodes.apply(this, arguments);
    583        }
    584    },
    585 
    586    /** @id MochiKit.DOM.createDOM */
    587    createDOM: function (name, attrs/*, nodes... */) {
    588        var elem;
    589        var self = MochiKit.DOM;
    590        var m = MochiKit.Base;
    591        if (typeof(attrs) == "string" || typeof(attrs) == "number") {
    592            var args = m.extend([name, null], arguments, 1);
    593            return arguments.callee.apply(this, args);
    594        }
    595        if (typeof(name) == 'string') {
    596            // Internet Explorer is dumb
    597            var xhtml = self._xhtml;
    598            if (attrs && !self.attributeArray.compliant) {
    599                // http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/name_2.asp
    600                var contents = "";
    601                if ('name' in attrs) {
    602                    contents += ' name="' + self.escapeHTML(attrs.name) + '"';
    603                }
    604                if (name == 'input' && 'type' in attrs) {
    605                    contents += ' type="' + self.escapeHTML(attrs.type) + '"';
    606                }
    607                if (contents) {
    608                    name = "<" + name + contents + ">";
    609                    xhtml = false;
    610                }
    611            }
    612            var d = self._document;
    613            if (xhtml && d === document) {
    614                elem = d.createElementNS("http://www.w3.org/1999/xhtml", name);
    615            } else {
    616                elem = d.createElement(name);
    617            }
    618        } else {
    619            elem = name;
    620        }
    621        if (attrs) {
    622            self.updateNodeAttributes(elem, attrs);
    623        }
    624        if (arguments.length <= 2) {
    625            return elem;
    626        } else {
    627            var args = m.extend([elem], arguments, 2);
    628            return self.appendChildNodes.apply(this, args);
    629        }
    630    },
    631 
    632    /** @id MochiKit.DOM.createDOMFunc */
    633    createDOMFunc: function (/* tag, attrs, *nodes */) {
    634        var m = MochiKit.Base;
    635        return m.partial.apply(
    636            this,
    637            m.extend([MochiKit.DOM.createDOM], arguments)
    638        );
    639    },
    640 
    641    /** @id MochiKit.DOM.removeElement */
    642    removeElement: function (elem) {
    643        var e = MochiKit.DOM.getElement(elem);
    644        e.parentNode.removeChild(e);
    645        return e;
    646    },
    647 
    648    /** @id MochiKit.DOM.swapDOM */
    649    swapDOM: function (dest, src) {
    650        var self = MochiKit.DOM;
    651        dest = self.getElement(dest);
    652        var parent = dest.parentNode;
    653        if (src) {
    654            src = self.getElement(src);
    655            parent.replaceChild(src, dest);
    656        } else {
    657            parent.removeChild(dest);
    658        }
    659        return src;
    660    },
    661 
    662    /** @id MochiKit.DOM.getElement */
    663    getElement: function (id) {
    664        var self = MochiKit.DOM;
    665        if (arguments.length == 1) {
    666            return ((typeof(id) == "string") ?
    667                self._document.getElementById(id) : id);
    668        } else {
    669            return MochiKit.Base.map(self.getElement, arguments);
    670        }
    671    },
    672 
    673    /** @id MochiKit.DOM.getElementsByTagAndClassName */
    674    getElementsByTagAndClassName: function (tagName, className,
    675            /* optional */parent) {
    676        var self = MochiKit.DOM;
    677        if (typeof(tagName) == 'undefined' || tagName === null) {
    678            tagName = '*';
    679        }
    680        if (typeof(parent) == 'undefined' || parent === null) {
    681            parent = self._document;
    682        }
    683        parent = self.getElement(parent);
    684        var children = (parent.getElementsByTagName(tagName)
    685            || self._document.all);
    686        if (typeof(className) == 'undefined' || className === null) {
    687            return MochiKit.Base.extend(null, children);
    688        }
    689 
    690        var elements = [];
    691        for (var i = 0; i < children.length; i++) {
    692            var child = children[i];
    693            var cls = child.className;
    694            if (!cls) {
    695                continue;
    696            }
    697            var classNames = cls.split(' ');
    698            for (var j = 0; j < classNames.length; j++) {
    699                if (classNames[j] == className) {
    700                    elements.push(child);
    701                    break;
    702                }
    703            }
    704        }
    705 
    706        return elements;
    707    },
    708 
    709    _newCallStack: function (path, once) {
    710        var rval = function () {
    711            var callStack = arguments.callee.callStack;
    712            for (var i = 0; i < callStack.length; i++) {
    713                if (callStack[i].apply(this, arguments) === false) {
    714                    break;
    715                }
    716            }
    717            if (once) {
    718                try {
    719                    this[path] = null;
    720                } catch (e) {
    721                    // pass
    722                }
    723            }
    724        };
    725        rval.callStack = [];
    726        return rval;
    727    },
    728 
    729    /** @id MochiKit.DOM.addToCallStack */
    730    addToCallStack: function (target, path, func, once) {
    731        var self = MochiKit.DOM;
    732        var existing = target[path];
    733        var regfunc = existing;
    734        if (!(typeof(existing) == 'function'
    735                && typeof(existing.callStack) == "object"
    736                && existing.callStack !== null)) {
    737            regfunc = self._newCallStack(path, once);
    738            if (typeof(existing) == 'function') {
    739                regfunc.callStack.push(existing);
    740            }
    741            target[path] = regfunc;
    742        }
    743        regfunc.callStack.push(func);
    744    },
    745 
    746    /** @id MochiKit.DOM.addLoadEvent */
    747    addLoadEvent: function (func) {
    748        var self = MochiKit.DOM;
    749        self.addToCallStack(self._window, "onload", func, true);
    750 
    751    },
    752 
    753    /** @id MochiKit.DOM.focusOnLoad */
    754    focusOnLoad: function (element) {
    755        var self = MochiKit.DOM;
    756        self.addLoadEvent(function () {
    757            element = self.getElement(element);
    758            if (element) {
    759                element.focus();
    760            }
    761        });
    762    },
    763 
    764    /** @id MochiKit.DOM.setElementClass */
    765    setElementClass: function (element, className) {
    766        var self = MochiKit.DOM;
    767        var obj = self.getElement(element);
    768        if (self.attributeArray.compliant) {
    769            obj.setAttribute("class", className);
    770        } else {
    771            obj.setAttribute("className", className);
    772        }
    773    },
    774 
    775    /** @id MochiKit.DOM.toggleElementClass */
    776    toggleElementClass: function (className/*, element... */) {
    777        var self = MochiKit.DOM;
    778        for (var i = 1; i < arguments.length; i++) {
    779            var obj = self.getElement(arguments[i]);
    780            if (!self.addElementClass(obj, className)) {
    781                self.removeElementClass(obj, className);
    782            }
    783        }
    784    },
    785 
    786    /** @id MochiKit.DOM.addElementClass */
    787    addElementClass: function (element, className) {
    788        var self = MochiKit.DOM;
    789        var obj = self.getElement(element);
    790        var cls = obj.className;
    791        // trivial case, no className yet
    792        if (cls == undefined || cls.length === 0) {
    793            self.setElementClass(obj, className);
    794            return true;
    795        }
    796        // the other trivial case, already set as the only class
    797        if (cls == className) {
    798            return false;
    799        }
    800        var classes = cls.split(" ");
    801        for (var i = 0; i < classes.length; i++) {
    802            // already present
    803            if (classes[i] == className) {
    804                return false;
    805            }
    806        }
    807        // append class
    808        self.setElementClass(obj, cls + " " + className);
    809        return true;
    810    },
    811 
    812    /** @id MochiKit.DOM.removeElementClass */
    813    removeElementClass: function (element, className) {
    814        var self = MochiKit.DOM;
    815        var obj = self.getElement(element);
    816        var cls = obj.className;
    817        // trivial case, no className yet
    818        if (cls == undefined || cls.length === 0) {
    819            return false;
    820        }
    821        // other trivial case, set only to className
    822        if (cls == className) {
    823            self.setElementClass(obj, "");
    824            return true;
    825        }
    826        var classes = cls.split(" ");
    827        for (var i = 0; i < classes.length; i++) {
    828            // already present
    829            if (classes[i] == className) {
    830                // only check sane case where the class is used once
    831                classes.splice(i, 1);
    832                self.setElementClass(obj, classes.join(" "));
    833                return true;
    834            }
    835        }
    836        // not found
    837        return false;
    838    },
    839 
    840    /** @id MochiKit.DOM.swapElementClass */
    841    swapElementClass: function (element, fromClass, toClass) {
    842        var obj = MochiKit.DOM.getElement(element);
    843        var res = MochiKit.DOM.removeElementClass(obj, fromClass);
    844        if (res) {
    845            MochiKit.DOM.addElementClass(obj, toClass);
    846        }
    847        return res;
    848    },
    849 
    850    /** @id MochiKit.DOM.hasElementClass */
    851    hasElementClass: function (element, className/*...*/) {
    852        var obj = MochiKit.DOM.getElement(element);
    853        var cls = obj.className;
    854        if (!cls) {
    855            return false;
    856        }
    857        var classes = cls.split(" ");
    858        for (var i = 1; i < arguments.length; i++) {
    859            var good = false;
    860            for (var j = 0; j < classes.length; j++) {
    861                if (classes[j] == arguments[i]) {
    862                    good = true;
    863                    break;
    864                }
    865            }
    866            if (!good) {
    867                return false;
    868            }
    869        }
    870        return true;
    871    },
    872 
    873    /** @id MochiKit.DOM.escapeHTML */
    874    escapeHTML: function (s) {
    875        return s.replace(/&/g, "&amp;"
    876            ).replace(/"/g, "&quot;"
    877            ).replace(/</g, "&lt;"
    878            ).replace(/>/g, "&gt;");
    879    },
    880 
    881    /** @id MochiKit.DOM.toHTML */
    882    toHTML: function (dom) {
    883        return MochiKit.DOM.emitHTML(dom).join("");
    884    },
    885 
    886    /** @id MochiKit.DOM.emitHTML */
    887    emitHTML: function (dom, /* optional */lst) {
    888        if (typeof(lst) == 'undefined' || lst === null) {
    889            lst = [];
    890        }
    891        // queue is the call stack, we're doing this non-recursively
    892        var queue = [dom];
    893        var self = MochiKit.DOM;
    894        var escapeHTML = self.escapeHTML;
    895        var attributeArray = self.attributeArray;
    896        while (queue.length) {
    897            dom = queue.pop();
    898            if (typeof(dom) == 'string') {
    899                lst.push(dom);
    900            } else if (dom.nodeType == 1) {
    901                // we're not using higher order stuff here
    902                // because safari has heisenbugs.. argh.
    903                //
    904                // I think it might have something to do with
    905                // garbage collection and function calls.
    906                lst.push('<' + dom.tagName.toLowerCase());
    907                var attributes = [];
    908                var domAttr = attributeArray(dom);
    909                for (var i = 0; i < domAttr.length; i++) {
    910                    var a = domAttr[i];
    911                    attributes.push([
    912                        " ",
    913                        a.name,
    914                        '="',
    915                        escapeHTML(a.value),
    916                        '"'
    917                    ]);
    918                }
    919                attributes.sort();
    920                for (i = 0; i < attributes.length; i++) {
    921                    var attrs = attributes[i];
    922                    for (var j = 0; j < attrs.length; j++) {
    923                        lst.push(attrs[j]);
    924                    }
    925                }
    926                if (dom.hasChildNodes()) {
    927                    lst.push(">");
    928                    // queue is the FILO call stack, so we put the close tag
    929                    // on first
    930                    queue.push("</" + dom.tagName.toLowerCase() + ">");
    931                    var cnodes = dom.childNodes;
    932                    for (i = cnodes.length - 1; i >= 0; i--) {
    933                        queue.push(cnodes[i]);
    934                    }
    935                } else {
    936                    lst.push('/>');
    937                }
    938            } else if (dom.nodeType == 3) {
    939                lst.push(escapeHTML(dom.nodeValue));
    940            }
    941        }
    942        return lst;
    943    },
    944 
    945    /** @id MochiKit.DOM.scrapeText */
    946    scrapeText: function (node, /* optional */asArray) {
    947        var rval = [];
    948        (function (node) {
    949            var cn = node.childNodes;
    950            if (cn) {
    951                for (var i = 0; i < cn.length; i++) {
    952                    arguments.callee.call(this, cn[i]);
    953                }
    954            }
    955            var nodeValue = node.nodeValue;
    956            if (typeof(nodeValue) == 'string') {
    957                rval.push(nodeValue);
    958            }
    959        })(MochiKit.DOM.getElement(node));
    960        if (asArray) {
    961            return rval;
    962        } else {
    963            return rval.join("");
    964        }
    965    },
    966 
    967    /** @id MochiKit.DOM.removeEmptyTextNodes */
    968    removeEmptyTextNodes: function (element) {
    969        element = MochiKit.DOM.getElement(element);
    970        for (var i = 0; i < element.childNodes.length; i++) {
    971            var node = element.childNodes[i];
    972            if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
    973                node.parentNode.removeChild(node);
    974            }
    975        }
    976    },
    977 
    978    /** @id MochiKit.DOM.makeClipping */
    979    makeClipping: function (element) {
    980        element = MochiKit.DOM.getElement(element);
    981        var oldOverflow = element.style.overflow;
    982        if ((MochiKit.Style.getStyle(element, 'overflow') || 'visible') != 'hidden') {
    983            element.style.overflow = 'hidden';
    984        }
    985        return oldOverflow;
    986    },
    987 
    988    /** @id MochiKit.DOM.undoClipping */
    989    undoClipping: function (element, overflow) {
    990        element = MochiKit.DOM.getElement(element);
    991        if (!overflow) {
    992            return;
    993        }
    994        element.style.overflow = overflow;
    995    },
    996 
    997    /** @id MochiKit.DOM.makePositioned */
    998    makePositioned: function (element) {
    999        element = MochiKit.DOM.getElement(element);
   1000        var pos = MochiKit.Style.getStyle(element, 'position');
   1001        if (pos == 'static' || !pos) {
   1002            element.style.position = 'relative';
   1003            // Opera returns the offset relative to the positioning context,
   1004            // when an element is position relative but top and left have
   1005            // not been defined
   1006            if (/Opera/.test(navigator.userAgent)) {
   1007                element.style.top = 0;
   1008                element.style.left = 0;
   1009            }
   1010        }
   1011    },
   1012 
   1013    /** @id MochiKit.DOM.undoPositioned */
   1014    undoPositioned: function (element) {
   1015        element = MochiKit.DOM.getElement(element);
   1016        if (element.style.position == 'relative') {
   1017            element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = '';
   1018        }
   1019    },
   1020 
   1021    /** @id MochiKit.DOM.getFirstElementByTagAndClassName */
   1022    getFirstElementByTagAndClassName: function (tagName, className,
   1023            /* optional */parent) {
   1024        var self = MochiKit.DOM;
   1025        if (typeof(tagName) == 'undefined' || tagName === null) {
   1026            tagName = '*';
   1027        }
   1028        if (typeof(parent) == 'undefined' || parent === null) {
   1029            parent = self._document;
   1030        }
   1031        parent = self.getElement(parent);
   1032        var children = (parent.getElementsByTagName(tagName)
   1033            || self._document.all);
   1034        if (typeof(className) == 'undefined' || className === null) {
   1035            return children[0];
   1036        }
   1037 
   1038        for (var i = 0; i < children.length; i++) {
   1039            var child = children[i];
   1040            var classNames = child.className.split(' ');
   1041            for (var j = 0; j < classNames.length; j++) {
   1042                if (classNames[j] == className) {
   1043                    return child;
   1044                }
   1045            }
   1046        }
   1047    },
   1048 
   1049    /** @id MochiKit.DOM.getFirstParentByTagAndClassName */
   1050    getFirstParentByTagAndClassName: function (elem, tagName, className) {
   1051        var self = MochiKit.DOM;
   1052        elem = self.getElement(elem);
   1053        if (typeof(tagName) == 'undefined' || tagName === null) {
   1054            tagName = '*';
   1055        } else {
   1056            tagName = tagName.toUpperCase();
   1057        }
   1058        if (typeof(className) == 'undefined' || className === null) {
   1059            className = null;
   1060        }
   1061 
   1062        var classList = '';
   1063        var curTagName = '';
   1064        while (elem && elem.tagName) {
   1065            elem = elem.parentNode;
   1066            if (tagName == '*' && className === null) {
   1067                return elem;
   1068            }
   1069            classList = elem.className.split(' ');
   1070            curTagName = elem.tagName.toUpperCase();
   1071            if (className === null && tagName == curTagName) {
   1072                return elem;
   1073            } else if (className !== null) {
   1074                for (var i = 0; i < classList.length; i++) {
   1075                    if (tagName == '*' && classList[i] == className) {
   1076                        return elem;
   1077                    } else if (tagName == curTagName && classList[i] == className) {
   1078                        return elem;
   1079                    }
   1080                }
   1081            }
   1082        }
   1083        return elem;
   1084    },
   1085 
   1086    /** @id MochiKit.DOM.isParent */
   1087    isParent: function (child, element) {
   1088        if (!child.parentNode || child == element) {
   1089            return false;
   1090        }
   1091 
   1092        if (child.parentNode == element) {
   1093            return true;
   1094        }
   1095 
   1096        return MochiKit.DOM.isParent(child.parentNode, element);
   1097    },
   1098 
   1099    __new__: function (win) {
   1100 
   1101        var m = MochiKit.Base;
   1102        if (typeof(document) != "undefined") {
   1103            this._document = document;
   1104            var kXULNSURI = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
   1105            this._xhtml = (document.documentElement &&
   1106                document.createElementNS &&
   1107                document.documentElement.namespaceURI === kXULNSURI);
   1108        } else if (MochiKit.MockDOM) {
   1109            this._document = MochiKit.MockDOM.document;
   1110        }
   1111        this._window = win;
   1112 
   1113        this.domConverters = new m.AdapterRegistry();
   1114 
   1115        var __tmpElement = this._document.createElement("span");
   1116        var attributeArray;
   1117        if (__tmpElement && __tmpElement.attributes &&
   1118                __tmpElement.attributes.length > 0) {
   1119            // for braindead browsers (IE) that insert extra junk
   1120            var filter = m.filter;
   1121            attributeArray = function (node) {
   1122                return filter(attributeArray.ignoreAttrFilter, node.attributes);
   1123            };
   1124            attributeArray.ignoreAttr = {};
   1125            var attrs = __tmpElement.attributes;
   1126            var ignoreAttr = attributeArray.ignoreAttr;
   1127            for (var i = 0; i < attrs.length; i++) {
   1128                var a = attrs[i];
   1129                ignoreAttr[a.name] = a.value;
   1130            }
   1131            attributeArray.ignoreAttrFilter = function (a) {
   1132                return (attributeArray.ignoreAttr[a.name] != a.value);
   1133            };
   1134            attributeArray.compliant = false;
   1135            attributeArray.renames = {
   1136                "class": "className",
   1137                "checked": "defaultChecked",
   1138                "usemap": "useMap",
   1139                "for": "htmlFor",
   1140                "readonly": "readOnly",
   1141                "colspan": "colSpan",
   1142                "bgcolor": "bgColor",
   1143                "cellspacing": "cellSpacing",
   1144                "cellpadding": "cellPadding"
   1145            };
   1146        } else {
   1147            attributeArray = function (node) {
   1148                /***
   1149 
   1150                    Return an array of attributes for a given node,
   1151                    filtering out attributes that don't belong for
   1152                    that are inserted by "Certain Browsers".
   1153 
   1154                ***/
   1155                return node.attributes;
   1156            };
   1157            attributeArray.compliant = true;
   1158            attributeArray.renames = {};
   1159        }
   1160        this.attributeArray = attributeArray;
   1161 
   1162        // FIXME: this really belongs in Base, and could probably be cleaner
   1163        var _deprecated = function(fromModule, arr) {
   1164            var modules = arr[1].split('.');
   1165            var str = '';
   1166            var obj = {};
   1167 
   1168            str += 'if (!MochiKit.' + modules[1] + ') { throw new Error("';
   1169            str += 'This function has been deprecated and depends on MochiKit.';
   1170            str += modules[1] + '.");}';
   1171            str += 'return MochiKit.' + modules[1] + '.' + arr[0];
   1172            str += '.apply(this, arguments);';
   1173 
   1174            obj[modules[2]] = new Function(str);
   1175            MochiKit.Base.update(MochiKit[fromModule], obj);
   1176        }
   1177        for (var i; i < MochiKit.DOM.DEPRECATED.length; i++) {
   1178            _deprecated('DOM', MochiKit.DOM.DEPRECATED[i]);
   1179        }
   1180 
   1181        // shorthand for createDOM syntax
   1182        var createDOMFunc = this.createDOMFunc;
   1183        /** @id MochiKit.DOM.UL */
   1184        this.UL = createDOMFunc("ul");
   1185        /** @id MochiKit.DOM.OL */
   1186        this.OL = createDOMFunc("ol");
   1187        /** @id MochiKit.DOM.LI */
   1188        this.LI = createDOMFunc("li");
   1189        /** @id MochiKit.DOM.TD */
   1190        this.TD = createDOMFunc("td");
   1191        /** @id MochiKit.DOM.TR */
   1192        this.TR = createDOMFunc("tr");
   1193        /** @id MochiKit.DOM.TBODY */
   1194        this.TBODY = createDOMFunc("tbody");
   1195        /** @id MochiKit.DOM.THEAD */
   1196        this.THEAD = createDOMFunc("thead");
   1197        /** @id MochiKit.DOM.TFOOT */
   1198        this.TFOOT = createDOMFunc("tfoot");
   1199        /** @id MochiKit.DOM.TABLE */
   1200        this.TABLE = createDOMFunc("table");
   1201        /** @id MochiKit.DOM.TH */
   1202        this.TH = createDOMFunc("th");
   1203        /** @id MochiKit.DOM.INPUT */
   1204        this.INPUT = createDOMFunc("input");
   1205        /** @id MochiKit.DOM.SPAN */
   1206        this.SPAN = createDOMFunc("span");
   1207        /** @id MochiKit.DOM.A */
   1208        this.A = createDOMFunc("a");
   1209        /** @id MochiKit.DOM.DIV */
   1210        this.DIV = createDOMFunc("div");
   1211        /** @id MochiKit.DOM.IMG */
   1212        this.IMG = createDOMFunc("img");
   1213        /** @id MochiKit.DOM.BUTTON */
   1214        this.BUTTON = createDOMFunc("button");
   1215        /** @id MochiKit.DOM.TT */
   1216        this.TT = createDOMFunc("tt");
   1217        /** @id MochiKit.DOM.PRE */
   1218        this.PRE = createDOMFunc("pre");
   1219        /** @id MochiKit.DOM.H1 */
   1220        this.H1 = createDOMFunc("h1");
   1221        /** @id MochiKit.DOM.H2 */
   1222        this.H2 = createDOMFunc("h2");
   1223        /** @id MochiKit.DOM.H3 */
   1224        this.H3 = createDOMFunc("h3");
   1225        /** @id MochiKit.DOM.BR */
   1226        this.BR = createDOMFunc("br");
   1227        /** @id MochiKit.DOM.HR */
   1228        this.HR = createDOMFunc("hr");
   1229        /** @id MochiKit.DOM.LABEL */
   1230        this.LABEL = createDOMFunc("label");
   1231        /** @id MochiKit.DOM.TEXTAREA */
   1232        this.TEXTAREA = createDOMFunc("textarea");
   1233        /** @id MochiKit.DOM.FORM */
   1234        this.FORM = createDOMFunc("form");
   1235        /** @id MochiKit.DOM.P */
   1236        this.P = createDOMFunc("p");
   1237        /** @id MochiKit.DOM.SELECT */
   1238        this.SELECT = createDOMFunc("select");
   1239        /** @id MochiKit.DOM.OPTION */
   1240        this.OPTION = createDOMFunc("option");
   1241        /** @id MochiKit.DOM.OPTGROUP */
   1242        this.OPTGROUP = createDOMFunc("optgroup");
   1243        /** @id MochiKit.DOM.LEGEND */
   1244        this.LEGEND = createDOMFunc("legend");
   1245        /** @id MochiKit.DOM.FIELDSET */
   1246        this.FIELDSET = createDOMFunc("fieldset");
   1247        /** @id MochiKit.DOM.STRONG */
   1248        this.STRONG = createDOMFunc("strong");
   1249        /** @id MochiKit.DOM.CANVAS */
   1250        this.CANVAS = createDOMFunc("canvas");
   1251 
   1252        /** @id MochiKit.DOM.$ */
   1253        this.$ = this.getElement;
   1254 
   1255        this.EXPORT_TAGS = {
   1256            ":common": this.EXPORT,
   1257            ":all": m.concat(this.EXPORT, this.EXPORT_OK)
   1258        };
   1259 
   1260        m.nameFunctions(this);
   1261 
   1262    }
   1263 });
   1264 
   1265 
   1266 MochiKit.DOM.__new__(((typeof(window) == "undefined") ? this : window));
   1267 
   1268 //
   1269 // XXX: Internet Explorer blows
   1270 //
   1271 if (MochiKit.__export__) {
   1272    withWindow = MochiKit.DOM.withWindow;
   1273    withDocument = MochiKit.DOM.withDocument;
   1274 }
   1275 
   1276 MochiKit.Base._exportSymbols(this, MochiKit.DOM);