| 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); |
|---|
| | 139 | MochiKit.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 | } |
|---|
| 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; |
|---|
| 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, "&" |
|---|
| | 841 | ).replace(/"/g, """ |
|---|
| | 842 | ).replace(/</g, "<" |
|---|
| | 843 | ).replace(/>/g, ">"); |
|---|
| | 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 |
|---|