DOM.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926
  1. /***
  2. MochiKit.DOM 1.4
  3. See <http://mochikit.com/> for documentation, downloads, license, etc.
  4. (c) 2005 Bob Ippolito. All rights Reserved.
  5. ***/
  6. if (typeof(dojo) != 'undefined') {
  7. dojo.provide("MochiKit.DOM");
  8. dojo.require("MochiKit.Base");
  9. }
  10. if (typeof(JSAN) != 'undefined') {
  11. JSAN.use("MochiKit.Base", []);
  12. }
  13. try {
  14. if (typeof(MochiKit.Base) == 'undefined') {
  15. throw "";
  16. }
  17. } catch (e) {
  18. throw "MochiKit.DOM depends on MochiKit.Base!";
  19. }
  20. if (typeof(MochiKit.DOM) == 'undefined') {
  21. MochiKit.DOM = {};
  22. }
  23. MochiKit.DOM.NAME = "MochiKit.DOM";
  24. MochiKit.DOM.VERSION = "1.4";
  25. MochiKit.DOM.__repr__ = function () {
  26. return "[" + this.NAME + " " + this.VERSION + "]";
  27. };
  28. MochiKit.DOM.toString = function () {
  29. return this.__repr__();
  30. };
  31. MochiKit.DOM.EXPORT = [
  32. "removeEmptyTextNodes",
  33. "formContents",
  34. "currentWindow",
  35. "currentDocument",
  36. "withWindow",
  37. "withDocument",
  38. "registerDOMConverter",
  39. "coerceToDOM",
  40. "createDOM",
  41. "createDOMFunc",
  42. "getNodeAttribute",
  43. "setNodeAttribute",
  44. "updateNodeAttributes",
  45. "appendChildNodes",
  46. "replaceChildNodes",
  47. "removeElement",
  48. "swapDOM",
  49. "BUTTON",
  50. "TT",
  51. "PRE",
  52. "H1",
  53. "H2",
  54. "H3",
  55. "BR",
  56. "CANVAS",
  57. "HR",
  58. "LABEL",
  59. "TEXTAREA",
  60. "FORM",
  61. "STRONG",
  62. "SELECT",
  63. "OPTION",
  64. "OPTGROUP",
  65. "LEGEND",
  66. "FIELDSET",
  67. "P",
  68. "UL",
  69. "OL",
  70. "LI",
  71. "TD",
  72. "TR",
  73. "THEAD",
  74. "TBODY",
  75. "TFOOT",
  76. "TABLE",
  77. "TH",
  78. "INPUT",
  79. "SPAN",
  80. "A",
  81. "DIV",
  82. "IMG",
  83. "getElement",
  84. "$",
  85. "getElementsByTagAndClassName",
  86. "addToCallStack",
  87. "addLoadEvent",
  88. "focusOnLoad",
  89. "setElementClass",
  90. "toggleElementClass",
  91. "addElementClass",
  92. "removeElementClass",
  93. "swapElementClass",
  94. "hasElementClass",
  95. "escapeHTML",
  96. "toHTML",
  97. "emitHTML",
  98. "scrapeText"
  99. ];
  100. MochiKit.DOM.EXPORT_OK = [
  101. "domConverters"
  102. ];
  103. MochiKit.DOM.DEPRECATED = [
  104. ['computedStyle', 'MochiKit.Style.computedStyle', '1.4'],
  105. ['elementDimensions', 'MochiKit.Style.getElementDimensions', '1.4'],
  106. ['elementPosition', 'MochiKit.Style.getElementPosition', '1.4'],
  107. ['hideElement', 'MochiKit.Style.hideElement', '1.4'],
  108. ['setElementDimensions', 'MochiKit.Style.setElementDimensions', '1.4'],
  109. ['setElementPosition', 'MochiKit.Style.setElementPosition', '1.4'],
  110. ['setDisplayForElement', 'MochiKit.Style.setDisplayForElement', '1.4'],
  111. ['setOpacity', 'MochiKit.Style.setOpacity', '1.4'],
  112. ['showElement', 'MochiKit.Style.showElement', '1.4'],
  113. ['Coordinates', 'MochiKit.Style.Coordinates', '1.4'], // FIXME: broken
  114. ['Dimensions', 'MochiKit.Style.Dimensions', '1.4'] // FIXME: broken
  115. ];
  116. MochiKit.DOM.getViewportDimensions = new Function('' +
  117. 'if (!MochiKit["Style"]) {' +
  118. ' throw new Error("This function has been deprecated and depends on MochiKit.Style.");' +
  119. '}' +
  120. 'return MochiKit.Style.getViewportDimensions.apply(this, arguments);');
  121. MochiKit.Base.update(MochiKit.DOM, {
  122. currentWindow: function () {
  123. return MochiKit.DOM._window;
  124. },
  125. currentDocument: function () {
  126. return MochiKit.DOM._document;
  127. },
  128. withWindow: function (win, func) {
  129. var self = MochiKit.DOM;
  130. var oldDoc = self._document;
  131. var oldWin = self._win;
  132. var rval;
  133. try {
  134. self._window = win;
  135. self._document = win.document;
  136. rval = func();
  137. } catch (e) {
  138. self._window = oldWin;
  139. self._document = oldDoc;
  140. throw e;
  141. }
  142. self._window = oldWin;
  143. self._document = oldDoc;
  144. return rval;
  145. },
  146. formContents: function (elem/* = document */) {
  147. var names = [];
  148. var values = [];
  149. var m = MochiKit.Base;
  150. var self = MochiKit.DOM;
  151. if (typeof(elem) == "undefined" || elem === null) {
  152. elem = self._document;
  153. } else {
  154. elem = self.getElement(elem);
  155. }
  156. m.nodeWalk(elem, function (elem) {
  157. var name = elem.name;
  158. if (m.isNotEmpty(name)) {
  159. var tagName = elem.nodeName;
  160. if (tagName == "INPUT"
  161. && (elem.type == "radio" || elem.type == "checkbox")
  162. && !elem.checked
  163. ) {
  164. return null;
  165. }
  166. if (tagName == "SELECT") {
  167. if (elem.type == "select-one") {
  168. if (elem.selectedIndex >= 0) {
  169. var opt = elem.options[elem.selectedIndex];
  170. names.push(name);
  171. values.push((opt.value) ? opt.value : opt.text);
  172. return null;
  173. }
  174. // no form elements?
  175. names.push(name);
  176. values.push("");
  177. return null;
  178. } else {
  179. var opts = elem.options;
  180. if (!opts.length) {
  181. names.push(name);
  182. values.push("");
  183. return null;
  184. }
  185. for (var i = 0; i < opts.length; i++) {
  186. var opt = opts[i];
  187. if (!opt.selected) {
  188. continue;
  189. }
  190. names.push(name);
  191. values.push((opt.value) ? opt.value : opt.text);
  192. }
  193. return null;
  194. }
  195. }
  196. if (tagName == "FORM" || tagName == "P" || tagName == "SPAN"
  197. || tagName == "DIV"
  198. ) {
  199. return elem.childNodes;
  200. }
  201. names.push(name);
  202. values.push(elem.value || '');
  203. return null;
  204. }
  205. return elem.childNodes;
  206. });
  207. return [names, values];
  208. },
  209. withDocument: function (doc, func) {
  210. var self = MochiKit.DOM;
  211. var oldDoc = self._document;
  212. var rval;
  213. try {
  214. self._document = doc;
  215. rval = func();
  216. } catch (e) {
  217. self._document = oldDoc;
  218. throw e;
  219. }
  220. self._document = oldDoc;
  221. return rval;
  222. },
  223. registerDOMConverter: function (name, check, wrap, /* optional */override) {
  224. MochiKit.DOM.domConverters.register(name, check, wrap, override);
  225. },
  226. coerceToDOM: function (node, ctx) {
  227. var m = MochiKit.Base;
  228. var im = MochiKit.Iter;
  229. var self = MochiKit.DOM;
  230. if (im) {
  231. var iter = im.iter;
  232. var repeat = im.repeat;
  233. var map = m.map;
  234. }
  235. var domConverters = self.domConverters;
  236. var coerceToDOM = arguments.callee;
  237. var NotFound = m.NotFound;
  238. while (true) {
  239. if (typeof(node) == 'undefined' || node === null) {
  240. return null;
  241. }
  242. if (typeof(node.nodeType) != 'undefined' && node.nodeType > 0) {
  243. return node;
  244. }
  245. if (typeof(node) == 'number' || typeof(node) == 'boolean') {
  246. node = node.toString();
  247. // FALL THROUGH
  248. }
  249. if (typeof(node) == 'string') {
  250. return self._document.createTextNode(node);
  251. }
  252. if (typeof(node.__dom__) == 'function') {
  253. node = node.__dom__(ctx);
  254. continue;
  255. }
  256. if (typeof(node.dom) == 'function') {
  257. node = node.dom(ctx);
  258. continue;
  259. }
  260. if (typeof(node) == 'function') {
  261. node = node.apply(ctx, [ctx]);
  262. continue;
  263. }
  264. if (im) {
  265. // iterable
  266. var iterNodes = null;
  267. try {
  268. iterNodes = iter(node);
  269. } catch (e) {
  270. // pass
  271. }
  272. if (iterNodes) {
  273. return map(coerceToDOM, iterNodes, repeat(ctx));
  274. }
  275. }
  276. // adapter
  277. try {
  278. node = domConverters.match(node, ctx);
  279. continue;
  280. } catch (e) {
  281. if (e != NotFound) {
  282. throw e;
  283. }
  284. }
  285. // fallback
  286. return self._document.createTextNode(node.toString());
  287. }
  288. // mozilla warnings aren't too bright
  289. return undefined;
  290. },
  291. setNodeAttribute: function (node, attr, value) {
  292. var o = {};
  293. o[attr] = value;
  294. try {
  295. return MochiKit.DOM.updateNodeAttributes(node, o);
  296. } catch (e) {
  297. // pass
  298. }
  299. return null;
  300. },
  301. getNodeAttribute: function (node, attr) {
  302. var self = MochiKit.DOM;
  303. var rename = self.attributeArray.renames[attr];
  304. node = self.getElement(node);
  305. try {
  306. if (rename) {
  307. return node[rename];
  308. }
  309. return node.getAttribute(attr);
  310. } catch (e) {
  311. // pass
  312. }
  313. return null;
  314. },
  315. updateNodeAttributes: function (node, attrs) {
  316. var elem = node;
  317. var self = MochiKit.DOM;
  318. if (typeof(node) == 'string') {
  319. elem = self.getElement(node);
  320. }
  321. if (attrs) {
  322. var updatetree = MochiKit.Base.updatetree;
  323. if (self.attributeArray.compliant) {
  324. // not IE, good.
  325. for (var k in attrs) {
  326. var v = attrs[k];
  327. if (typeof(v) == 'object' && typeof(elem[k]) == 'object') {
  328. updatetree(elem[k], v);
  329. } else if (k.substring(0, 2) == "on") {
  330. if (typeof(v) == "string") {
  331. v = new Function(v);
  332. }
  333. elem[k] = v;
  334. } else {
  335. elem.setAttribute(k, v);
  336. }
  337. }
  338. } else {
  339. // IE is insane in the membrane
  340. var renames = self.attributeArray.renames;
  341. for (k in attrs) {
  342. v = attrs[k];
  343. var renamed = renames[k];
  344. if (k == "style" && typeof(v) == "string") {
  345. elem.style.cssText = v;
  346. } else if (typeof(renamed) == "string") {
  347. elem[renamed] = v;
  348. } else if (typeof(elem[k]) == 'object'
  349. && typeof(v) == 'object') {
  350. updatetree(elem[k], v);
  351. } else if (k.substring(0, 2) == "on") {
  352. if (typeof(v) == "string") {
  353. v = new Function(v);
  354. }
  355. elem[k] = v;
  356. } else {
  357. elem.setAttribute(k, v);
  358. }
  359. }
  360. }
  361. }
  362. return elem;
  363. },
  364. appendChildNodes: function (node/*, nodes...*/) {
  365. var elem = node;
  366. var self = MochiKit.DOM;
  367. if (typeof(node) == 'string') {
  368. elem = self.getElement(node);
  369. }
  370. var nodeStack = [
  371. self.coerceToDOM(
  372. MochiKit.Base.extend(null, arguments, 1),
  373. elem
  374. )
  375. ];
  376. var concat = MochiKit.Base.concat;
  377. while (nodeStack.length) {
  378. var n = nodeStack.shift();
  379. if (typeof(n) == 'undefined' || n === null) {
  380. // pass
  381. } else if (typeof(n.nodeType) == 'number') {
  382. elem.appendChild(n);
  383. } else {
  384. nodeStack = concat(n, nodeStack);
  385. }
  386. }
  387. return elem;
  388. },
  389. replaceChildNodes: function (node/*, nodes...*/) {
  390. var elem = node;
  391. var self = MochiKit.DOM;
  392. if (typeof(node) == 'string') {
  393. elem = self.getElement(node);
  394. arguments[0] = elem;
  395. }
  396. var child;
  397. while ((child = elem.firstChild)) {
  398. elem.removeChild(child);
  399. }
  400. if (arguments.length < 2) {
  401. return elem;
  402. } else {
  403. return self.appendChildNodes.apply(this, arguments);
  404. }
  405. },
  406. createDOM: function (name, attrs/*, nodes... */) {
  407. var elem;
  408. var self = MochiKit.DOM;
  409. var m = MochiKit.Base;
  410. if (typeof(attrs) == "string" || typeof(attrs) == "number") {
  411. var args = m.extend([name, null], arguments, 1);
  412. return arguments.callee.apply(this, args);
  413. }
  414. if (typeof(name) == 'string') {
  415. // Internet Explorer is dumb
  416. if (attrs && !self.attributeArray.compliant) {
  417. // http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/name_2.asp
  418. var contents = "";
  419. if ('name' in attrs) {
  420. contents += ' name="' + self.escapeHTML(attrs.name) + '"';
  421. }
  422. if (name == 'input' && 'type' in attrs) {
  423. contents += ' type="' + self.escapeHTML(attrs.type) + '"';
  424. }
  425. if (contents) {
  426. name = "<" + name + contents + ">";
  427. }
  428. }
  429. elem = self._document.createElement(name);
  430. } else {
  431. elem = name;
  432. }
  433. if (attrs) {
  434. self.updateNodeAttributes(elem, attrs);
  435. }
  436. if (arguments.length <= 2) {
  437. return elem;
  438. } else {
  439. var args = m.extend([elem], arguments, 2);
  440. return self.appendChildNodes.apply(this, args);
  441. }
  442. },
  443. createDOMFunc: function (/* tag, attrs, *nodes */) {
  444. var m = MochiKit.Base;
  445. return m.partial.apply(
  446. this,
  447. m.extend([MochiKit.DOM.createDOM], arguments)
  448. );
  449. },
  450. removeElement: function (elem) {
  451. var e = MochiKit.DOM.getElement(elem);
  452. e.parentNode.removeChild(e);
  453. return e;
  454. },
  455. swapDOM: function (dest, src) {
  456. var self = MochiKit.DOM;
  457. dest = self.getElement(dest);
  458. var parent = dest.parentNode;
  459. if (src) {
  460. src = self.getElement(src);
  461. parent.replaceChild(src, dest);
  462. } else {
  463. parent.removeChild(dest);
  464. }
  465. return src;
  466. },
  467. getElement: function (id) {
  468. var self = MochiKit.DOM;
  469. if (arguments.length == 1) {
  470. return ((typeof(id) == "string") ?
  471. self._document.getElementById(id) : id);
  472. } else {
  473. return MochiKit.Base.map(self.getElement, arguments);
  474. }
  475. },
  476. getElementsByTagAndClassName: function (tagName, className,
  477. /* optional */parent) {
  478. var self = MochiKit.DOM;
  479. if (typeof(tagName) == 'undefined' || tagName === null) {
  480. tagName = '*';
  481. }
  482. if (typeof(parent) == 'undefined' || parent === null) {
  483. parent = self._document;
  484. }
  485. parent = self.getElement(parent);
  486. var children = (parent.getElementsByTagName(tagName)
  487. || self._document.all);
  488. if (typeof(className) == 'undefined' || className === null) {
  489. return MochiKit.Base.extend(null, children);
  490. }
  491. var elements = [];
  492. for (var i = 0; i < children.length; i++) {
  493. var child = children[i];
  494. var classNames = child.className.split(' ');
  495. for (var j = 0; j < classNames.length; j++) {
  496. if (classNames[j] == className) {
  497. elements.push(child);
  498. break;
  499. }
  500. }
  501. }
  502. return elements;
  503. },
  504. _newCallStack: function (path, once) {
  505. var rval = function () {
  506. var callStack = arguments.callee.callStack;
  507. for (var i = 0; i < callStack.length; i++) {
  508. if (callStack[i].apply(this, arguments) === false) {
  509. break;
  510. }
  511. }
  512. if (once) {
  513. try {
  514. this[path] = null;
  515. } catch (e) {
  516. // pass
  517. }
  518. }
  519. };
  520. rval.callStack = [];
  521. return rval;
  522. },
  523. addToCallStack: function (target, path, func, once) {
  524. var self = MochiKit.DOM;
  525. var existing = target[path];
  526. var regfunc = existing;
  527. if (!(typeof(existing) == 'function'
  528. && typeof(existing.callStack) == "object"
  529. && existing.callStack !== null)) {
  530. regfunc = self._newCallStack(path, once);
  531. if (typeof(existing) == 'function') {
  532. regfunc.callStack.push(existing);
  533. }
  534. target[path] = regfunc;
  535. }
  536. regfunc.callStack.push(func);
  537. },
  538. addLoadEvent: function (func) {
  539. var self = MochiKit.DOM;
  540. self.addToCallStack(self._window, "onload", func, true);
  541. },
  542. focusOnLoad: function (element) {
  543. var self = MochiKit.DOM;
  544. self.addLoadEvent(function () {
  545. element = self.getElement(element);
  546. if (element) {
  547. element.focus();
  548. }
  549. });
  550. },
  551. setElementClass: function (element, className) {
  552. var self = MochiKit.DOM;
  553. var obj = self.getElement(element);
  554. if (self.attributeArray.compliant) {
  555. obj.setAttribute("class", className);
  556. } else {
  557. obj.setAttribute("className", className);
  558. }
  559. },
  560. toggleElementClass: function (className/*, element... */) {
  561. var self = MochiKit.DOM;
  562. for (var i = 1; i < arguments.length; i++) {
  563. var obj = self.getElement(arguments[i]);
  564. if (!self.addElementClass(obj, className)) {
  565. self.removeElementClass(obj, className);
  566. }
  567. }
  568. },
  569. addElementClass: function (element, className) {
  570. var self = MochiKit.DOM;
  571. var obj = self.getElement(element);
  572. var cls = obj.className;
  573. // trivial case, no className yet
  574. if (cls.length === 0) {
  575. self.setElementClass(obj, className);
  576. return true;
  577. }
  578. // the other trivial case, already set as the only class
  579. if (cls == className) {
  580. return false;
  581. }
  582. var classes = obj.className.split(" ");
  583. for (var i = 0; i < classes.length; i++) {
  584. // already present
  585. if (classes[i] == className) {
  586. return false;
  587. }
  588. }
  589. // append class
  590. self.setElementClass(obj, cls + " " + className);
  591. return true;
  592. },
  593. removeElementClass: function (element, className) {
  594. var self = MochiKit.DOM;
  595. var obj = self.getElement(element);
  596. var cls = obj.className;
  597. // trivial case, no className yet
  598. if (cls.length === 0) {
  599. return false;
  600. }
  601. // other trivial case, set only to className
  602. if (cls == className) {
  603. self.setElementClass(obj, "");
  604. return true;
  605. }
  606. var classes = obj.className.split(" ");
  607. for (var i = 0; i < classes.length; i++) {
  608. // already present
  609. if (classes[i] == className) {
  610. // only check sane case where the class is used once
  611. classes.splice(i, 1);
  612. self.setElementClass(obj, classes.join(" "));
  613. return true;
  614. }
  615. }
  616. // not found
  617. return false;
  618. },
  619. swapElementClass: function (element, fromClass, toClass) {
  620. var obj = MochiKit.DOM.getElement(element);
  621. var res = MochiKit.DOM.removeElementClass(obj, fromClass);
  622. if (res) {
  623. MochiKit.DOM.addElementClass(obj, toClass);
  624. }
  625. return res;
  626. },
  627. hasElementClass: function (element, className/*...*/) {
  628. var obj = MochiKit.DOM.getElement(element);
  629. var classes = obj.className.split(" ");
  630. for (var i = 1; i < arguments.length; i++) {
  631. var good = false;
  632. for (var j = 0; j < classes.length; j++) {
  633. if (classes[j] == arguments[i]) {
  634. good = true;
  635. break;
  636. }
  637. }
  638. if (!good) {
  639. return false;
  640. }
  641. }
  642. return true;
  643. },
  644. escapeHTML: function (s) {
  645. return s.replace(/&/g, "&amp;"
  646. ).replace(/"/g, "&quot;"
  647. ).replace(/</g, "&lt;"
  648. ).replace(/>/g, "&gt;");
  649. },
  650. toHTML: function (dom) {
  651. return MochiKit.DOM.emitHTML(dom).join("");
  652. },
  653. emitHTML: function (dom, /* optional */lst) {
  654. if (typeof(lst) == 'undefined' || lst === null) {
  655. lst = [];
  656. }
  657. // queue is the call stack, we're doing this non-recursively
  658. var queue = [dom];
  659. var self = MochiKit.DOM;
  660. var escapeHTML = self.escapeHTML;
  661. var attributeArray = self.attributeArray;
  662. while (queue.length) {
  663. dom = queue.pop();
  664. if (typeof(dom) == 'string') {
  665. lst.push(dom);
  666. } else if (dom.nodeType == 1) {
  667. // we're not using higher order stuff here
  668. // because safari has heisenbugs.. argh.
  669. //
  670. // I think it might have something to do with
  671. // garbage collection and function calls.
  672. lst.push('<' + dom.nodeName.toLowerCase());
  673. var attributes = [];
  674. var domAttr = attributeArray(dom);
  675. for (var i = 0; i < domAttr.length; i++) {
  676. var a = domAttr[i];
  677. attributes.push([
  678. " ",
  679. a.name,
  680. '="',
  681. escapeHTML(a.value),
  682. '"'
  683. ]);
  684. }
  685. attributes.sort();
  686. for (i = 0; i < attributes.length; i++) {
  687. var attrs = attributes[i];
  688. for (var j = 0; j < attrs.length; j++) {
  689. lst.push(attrs[j]);
  690. }
  691. }
  692. if (dom.hasChildNodes()) {
  693. lst.push(">");
  694. // queue is the FILO call stack, so we put the close tag
  695. // on first
  696. queue.push("</" + dom.nodeName.toLowerCase() + ">");
  697. var cnodes = dom.childNodes;
  698. for (i = cnodes.length - 1; i >= 0; i--) {
  699. queue.push(cnodes[i]);
  700. }
  701. } else {
  702. lst.push('/>');
  703. }
  704. } else if (dom.nodeType == 3) {
  705. lst.push(escapeHTML(dom.nodeValue));
  706. }
  707. }
  708. return lst;
  709. },
  710. scrapeText: function (node, /* optional */asArray) {
  711. var rval = [];
  712. (function (node) {
  713. var cn = node.childNodes;
  714. if (cn) {
  715. for (var i = 0; i < cn.length; i++) {
  716. arguments.callee.call(this, cn[i]);
  717. }
  718. }
  719. var nodeValue = node.nodeValue;
  720. if (typeof(nodeValue) == 'string') {
  721. rval.push(nodeValue);
  722. }
  723. })(MochiKit.DOM.getElement(node));
  724. if (asArray) {
  725. return rval;
  726. } else {
  727. return rval.join("");
  728. }
  729. },
  730. removeEmptyTextNodes: function (element) {
  731. element = MochiKit.DOM.getElement(element);
  732. for (var i = 0; i < element.childNodes.length; i++) {
  733. var node = element.childNodes[i];
  734. if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
  735. node.parentNode.removeChild(node);
  736. }
  737. }
  738. },
  739. __new__: function (win) {
  740. var m = MochiKit.Base;
  741. if (typeof(document) != "undefined") {
  742. this._document = document;
  743. } else if (MochiKit.MockDOM) {
  744. this._document = MochiKit.MockDOM.document;
  745. }
  746. this._window = win;
  747. this.domConverters = new m.AdapterRegistry();
  748. var __tmpElement = this._document.createElement("span");
  749. var attributeArray;
  750. if (__tmpElement && __tmpElement.attributes &&
  751. __tmpElement.attributes.length > 0) {
  752. // for braindead browsers (IE) that insert extra junk
  753. var filter = m.filter;
  754. attributeArray = function (node) {
  755. return filter(attributeArray.ignoreAttrFilter, node.attributes);
  756. };
  757. attributeArray.ignoreAttr = {};
  758. var attrs = __tmpElement.attributes;
  759. var ignoreAttr = attributeArray.ignoreAttr;
  760. for (var i = 0; i < attrs.length; i++) {
  761. var a = attrs[i];
  762. ignoreAttr[a.name] = a.value;
  763. }
  764. attributeArray.ignoreAttrFilter = function (a) {
  765. return (attributeArray.ignoreAttr[a.name] != a.value);
  766. };
  767. attributeArray.compliant = false;
  768. attributeArray.renames = {
  769. "class": "className",
  770. "checked": "defaultChecked",
  771. "usemap": "useMap",
  772. "for": "htmlFor",
  773. "readonly": "readOnly"
  774. };
  775. } else {
  776. attributeArray = function (node) {
  777. /***
  778. Return an array of attributes for a given node,
  779. filtering out attributes that don't belong for
  780. that are inserted by "Certain Browsers".
  781. ***/
  782. return node.attributes;
  783. };
  784. attributeArray.compliant = true;
  785. attributeArray.renames = {};
  786. }
  787. this.attributeArray = attributeArray;
  788. // FIXME: this really belongs in Base, and could probably be cleaner
  789. var _deprecated = function(fromModule, arr) {
  790. var modules = arr[1].split('.');
  791. var str = '';
  792. var obj = {};
  793. str += 'if (!MochiKit.' + modules[1] + ') { throw new Error("';
  794. str += 'This function has been deprecated and depends on MochiKit.';
  795. str += modules[1] + '.");}';
  796. str += 'return MochiKit.' + modules[1] + '.' + arr[0];
  797. str += '.apply(this, arguments);';
  798. obj[modules[2]] = new Function(str);
  799. MochiKit.Base.update(MochiKit[fromModule], obj);
  800. }
  801. for (var i; i < MochiKit.DOM.DEPRECATED.length; i++) {
  802. _deprecated('DOM', MochiKit.DOM.DEPRECATED[i]);
  803. }
  804. // shorthand for createDOM syntax
  805. var createDOMFunc = this.createDOMFunc;
  806. this.UL = createDOMFunc("ul");
  807. this.OL = createDOMFunc("ol");
  808. this.LI = createDOMFunc("li");
  809. this.TD = createDOMFunc("td");
  810. this.TR = createDOMFunc("tr");
  811. this.TBODY = createDOMFunc("tbody");
  812. this.THEAD = createDOMFunc("thead");
  813. this.TFOOT = createDOMFunc("tfoot");
  814. this.TABLE = createDOMFunc("table");
  815. this.TH = createDOMFunc("th");
  816. this.INPUT = createDOMFunc("input");
  817. this.SPAN = createDOMFunc("span");
  818. this.A = createDOMFunc("a");
  819. this.DIV = createDOMFunc("div");
  820. this.IMG = createDOMFunc("img");
  821. this.BUTTON = createDOMFunc("button");
  822. this.TT = createDOMFunc("tt");
  823. this.PRE = createDOMFunc("pre");
  824. this.H1 = createDOMFunc("h1");
  825. this.H2 = createDOMFunc("h2");
  826. this.H3 = createDOMFunc("h3");
  827. this.BR = createDOMFunc("br");
  828. this.HR = createDOMFunc("hr");
  829. this.LABEL = createDOMFunc("label");
  830. this.TEXTAREA = createDOMFunc("textarea");
  831. this.FORM = createDOMFunc("form");
  832. this.P = createDOMFunc("p");
  833. this.SELECT = createDOMFunc("select");
  834. this.OPTION = createDOMFunc("option");
  835. this.OPTGROUP = createDOMFunc("optgroup");
  836. this.LEGEND = createDOMFunc("legend");
  837. this.FIELDSET = createDOMFunc("fieldset");
  838. this.STRONG = createDOMFunc("strong");
  839. this.CANVAS = createDOMFunc("canvas");
  840. this.$ = this.getElement;
  841. this.EXPORT_TAGS = {
  842. ":common": this.EXPORT,
  843. ":all": m.concat(this.EXPORT, this.EXPORT_OK)
  844. };
  845. m.nameFunctions(this);
  846. }
  847. });
  848. MochiKit.DOM.__new__(((typeof(window) == "undefined") ? this : window));
  849. //
  850. // XXX: Internet Explorer blows
  851. //
  852. if (MochiKit.__export__) {
  853. withWindow = MochiKit.DOM.withWindow;
  854. withDocument = MochiKit.DOM.withDocument;
  855. }
  856. MochiKit.Base._exportSymbols(this, MochiKit.DOM);