1 /** 2 * @fileOverview BTM DOM Methods. 3 * @author <a href="http://www.bobs-bits.com">Stephen Reay</a> 4 */ 5 6 /** 7 * @namespace Funtionality for selecting, traversing, reading, modifying and creating DOM elements 8 */ 9 BTM.DOM = { 10 /** 11 * Tag names for inline HTML Elements 12 * @type {Array} 13 */ 14 inlineElements : [ 15 'area', 16 'base', 17 'basefont', 18 'br', 19 'hr', 20 'input', 21 'img', 22 'link', 23 'meta' 24 ], 25 26 /** 27 * Valid attribute names for any element 28 * @type {Array} 29 */ 30 standardAttributes : [ 31 'class', 32 'id', 33 'style', 34 'title', 35 'dir', 36 'lang', 37 'accesskey', 38 'tabindex' 39 ], 40 41 /** 42 * Attributes specific to each element type 43 * @type {Object} 44 */ 45 conditionalAttributes : { 46 a : [ 47 'charset', 48 'coords', 49 'href', 50 'hreflang', 51 'name', 52 'rel', 53 'rev', 54 'shape', 55 'target', 56 'type' 57 ], 58 area : [ 59 'alt', 60 'coords', 61 'href', 62 'getShref', 63 'shape', 64 'target' 65 ], 66 base : [ 67 'href', 68 'target' 69 ], 70 bdo : [ 71 'dir' 72 ], 73 blockquote : [ 74 'cite' 75 ], 76 button: [ 77 'disabled', 78 'name', 79 'type', 80 'value' 81 ], 82 caption : [ 83 'align' 84 ], 85 col : [ 86 'align', 87 'char', 88 'charoff', 89 'span', 90 'valign', 91 'width' 92 ], 93 colgroup : [ 94 'align', 95 'char', 96 'charoff', 97 'span', 98 'valign', 99 'width' 100 ], 101 del : [ 102 'cite', 103 'datetime' 104 ], 105 form : [ 106 'action', 107 'accept', 108 'accept-charset', 109 'enctype', 110 'method', 111 'name', 112 'target' 113 ], 114 frame : [ 115 'frameborder', 116 'longdesc', 117 'marginheight', 118 'marginwidth', 119 'name', 120 'noresize', 121 'scrolling', 122 'src' 123 ], 124 frameset : [ 125 'cols', 126 'rows' 127 ], 128 iframe : [ 129 'frameborder', 130 'height', 131 'longdesc', 132 'marginheight', 133 'marginwidth', 134 'name', 135 'scrolling', 136 'src', 137 'width' 138 ], 139 img : [ 140 'alt', 141 'src' 142 ], 143 input : [ 144 'accept', 145 'alt', 146 'checked', 147 'disabled', 148 'maxlength', 149 'name', 150 'readonly', 151 'size', 152 'src', 153 'type', 154 'value' 155 ], 156 ins : [ 157 'cite', 158 'datetime' 159 ], 160 label : [ 161 'for' 162 ], 163 link : [ 164 'charset', 165 'href', 166 'hreflang', 167 'media', 168 'rel', 169 'rev', 170 'target', 171 'type' 172 ], 173 map : [ 174 'name' 175 ], 176 object : [ 177 'align', 178 'archive', 179 'border', 180 'classid', 181 'codebase', 182 'codetype', 183 'data', 184 'declare', 185 'height', 186 'hspace', 187 'name', 188 'standby', 189 'type', 190 'usemap', 191 'vspace', 192 'width' 193 ], 194 optgroup : [ 195 'label', 196 'disabled' 197 ], 198 option : [ 199 'disabled', 200 'selected', 201 'value' 202 ], 203 param : [ 204 'name', 205 'type', 206 'value', 207 'valuetype' 208 ], 209 q : [ 210 'cite' 211 ], 212 script : [ 213 'type', 214 'charset', 215 'defer', 216 'language', 217 'src' 218 ], 219 select : [ 220 'disabled', 221 'multiple', 222 'name', 223 'size' 224 ], 225 style : [ 226 'type', 227 'media' 228 ], 229 table : [ 230 'border', 231 'cellpadding', 232 'cellspacing', 233 'frame', 234 'rules', 235 'summary', 236 'width' 237 ], 238 tbody : [ 239 'align', 240 'char', 241 'charoff', 242 'valign' 243 ], 244 td : [ 245 'abbr', 246 'align', 247 'axis', 248 'char', 249 'charoff', 250 'colspan', 251 'headers', 252 'rowspan', 253 'scope', 254 'valign' 255 ], 256 textarea : [ 257 'cols', 258 'rows', 259 'disabled', 260 'name', 261 'readonly' 262 ], 263 tfoot : [ 264 'align', 265 'char', 266 'charoff', 267 'valign' 268 ], 269 th : [ 270 'abbr', 271 'align', 272 'axis', 273 'char', 274 'charoff', 275 'colspan', 276 'headers', 277 'rowspan', 278 'scope', 279 'valign' 280 ], 281 thead : [ 282 'align', 283 'char', 284 'charoff', 285 'valign' 286 ], 287 tr : [ 288 'align', 289 'char', 290 'charoff', 291 'valign' 292 ] 293 }, 294 295 /** 296 * Regular Expression used to identify a pixel length value 297 * @type RegExp 298 */ 299 pixelRegEx : /^\-?\d+(px)?$/i, 300 301 /** 302 * CSS properties that are lengths 303 * @type String[] 304 */ 305 lengthProperties : [ 306 'width', 307 'height', 308 'lineHeight', 309 'top', 310 'right', 311 'bottom', 312 'left', 313 'margin', 314 'marginLeft', 315 'marginRight', 316 'marginTop', 317 'marginBottom', 318 'padding', 319 'paddingLeft', 320 'paddingRight', 321 'paddingTop', 322 'paddingBottom', 323 'border', 324 'borderWidth', 325 'borderLeft', 326 'borderLeftWidth', 327 'borderRight', 328 'borderRightWidth', 329 'borderTop', 330 'borderTopWidth', 331 'borderBottom', 332 'borderBottomWidth' 333 ], 334 335 /** 336 * The number used for generating new IDs to identify anonymous elements. 337 * @see BTM.DOM.identify 338 * @type {Number} 339 */ 340 anonymousElements : 0 341 }; 342 343 if (BTM.Browser.is('Trident', 7, 'lte')) { 344 BTM.DOM.renamedAttributes = { 345 'class' : 'className', 346 'for' : 'htmlFor' 347 }; 348 349 BTM.DOM.newElementUnsafeAttributes = [ 350 'name', 351 'type' 352 ]; 353 } 354 355 /** 356 * Lookup an element by ID 357 * @param {HTMLElement|String} selector element ID or element reference 358 * @returns {HTMLElement|Boolean} reference to the element or false if not found 359 */ 360 BTM.DOM.$ = function $(selector) { 361 if(Object.isElement(selector) || Object.isObject(selector)) { 362 return selector; 363 } 364 else if(Object.isString(selector)) { 365 return document.getElementById(selector) || false; 366 } 367 }; 368 369 /** 370 * Convenience shortcut to {@link BTM.DOM.$} 371 * @function 372 * @see BTM.DOM.$ 373 */ 374 BTM.$ = BTM.DOM.$; 375 376 /** 377 * Get a unique reference to an element - returns existing ID if exists, if not applies and returns new, unique ID. 378 * @returns {String} the elements ID 379 */ 380 BTM.DOM.identify = function identify(element) { 381 element = BTM.$(element); 382 383 if(BTM.DOM.hasAttribute(element, 'id')) { 384 return BTM.DOM.getAttribute(element, 'id'); 385 } 386 else { 387 var newID; 388 do { 389 newID = 'anonymous_element_' + BTM.DOM.anonymousElements++; 390 } while (BTM.$(newID)); 391 392 BTM.DOM.setAttribute(element, 'id', newID); 393 return newID; 394 } 395 }; 396 397 /** 398 * Lookup multiple elements by CSS selector. This will always try to make use of the querySelector API if the browser supports it natively.<br /> 399 * If the native method exists but throws an exception (e.g.: MSIE8 using a CSS3 selector) the emulated functionality provided by an external library is used. 400 * @param {String} selector CSS selector string 401 * @returns {HTMLElement[]} elements matching the given CSS Selector 402 * @see <a href="http://www.w3.org/TR/css3-selectors/">http://www.w3.org/TR/css3-selectors/</a> 403 * @see <a href="http://dev.w3.org/2006/webapi/selectors-api/">http://dev.w3.org/2006/webapi/selectors-api/</a> 404 */ 405 BTM.DOM.$$ = function $$(selector, context) { 406 context = BTM.$(context) || document; 407 BTM.log("Finding elements matching: '" + selector + "'", context); 408 409 if (context.querySelectorAll) { 410 try { 411 BTM.log("Attempting lookup of '" + selector + "' using native querySelector"); 412 return Object.toArray(context.querySelectorAll(selector)); 413 } 414 catch (e) { 415 BTM.log('Falling back to JavaScript query selector', e); 416 } 417 418 } 419 if (BTM.library) { 420 switch (BTM.library.name) { 421 case 'Prototype': 422 return Element.select(context, selector).toArray(); 423 break; 424 425 case 'jQuery': 426 return Object.toArray(jQuery(selector, context)); 427 break; 428 429 case 'cssQuery': 430 return cssQuery(selector, context).unique(); 431 break; 432 } 433 } 434 else { 435 try { 436 return Object.toArray(document.getElementsByTagName(selector)); 437 } 438 catch(e) { 439 BTM.error("Cannot process the supplied selector string natively!"); 440 } 441 } 442 }; 443 444 /** 445 * Convenience shortcut to {@link BTM.DOM.$$} 446 * @function 447 * @see BTM.DOM.$$ 448 */ 449 BTM.$$ = BTM.DOM.$$; 450 451 452 /** 453 * Add a class to an element 454 * @param {HTMLElement|String} element element ID or element reference to add class to 455 * @param {String} className class to add to the element 456 * @returns {HTMLElement} the original element 457 */ 458 BTM.DOM.addClass = function addClass(element, className) { 459 element = BTM.$(element); 460 if (!className) { 461 return false; 462 } 463 if (Object.isString(className) && className.indexOf(' ') >= 0) { 464 className = className.trim().split(/\s/); 465 } 466 if (Object.isArray(className)) { 467 BTM.log("Adding '" + className.length + "' classes", element); 468 className.forEach(BTM.DOM.addClass.curry(element)); 469 } 470 else if (!BTM.DOM.hasClass(element, className)) { 471 BTM.log("Adding class '" + className + "'", element); 472 element.className = element.className + ' ' + className; 473 } 474 475 return element; 476 }; 477 478 /** 479 * Remove a class from an element 480 * @param {HTMLElement|String} element element ID or element reference to remove class from 481 * @param {String} className class to remove from the element 482 * @returns {HTMLElement} the original element 483 */ 484 BTM.DOM.removeClass = function removeClass(element, className) { 485 element = BTM.$(element); 486 if(className.indexOf(' ') >= 0) { 487 className = className.trim().split(/\s/); 488 } 489 if (Object.isArray(className)) { 490 className.forEach(BTM.DOM.removeClass.curry(element)); 491 } 492 else { 493 BTM.log("Removing class '" + className + "'", element); 494 element.className = element.className.replace(new RegExp('(^|\\s)' + className + '($|\\s)', 'g'),' '); 495 } 496 497 return element; 498 }; 499 500 /** 501 * Check if an element has a class 502 * @param {HTMLElement|String} element element ID or element reference to check for class 503 * @param {String} className class to check for 504 * @returns {Boolean} true if element has class, false if it does not 505 */ 506 BTM.DOM.hasClass = function hasClass(element, className) { 507 element = BTM.$(element); 508 BTM.log("Checking for class '" + className + "'", element); 509 var classes = element.className.split(' '); 510 511 return classes.inArray(className); 512 }; 513 514 /** 515 * Swap between two classes on an element 516 * @param {HTMLElement|String} element element ID or element reference to toggle classes of 517 * @param {String} className1 first class to toggle between 518 * @param {String} [className2=""] second class to toggle between. 519 * @returns {HTMLElement} the original element 520 */ 521 BTM.DOM.swapClass = function swapClass(element, className1, className2) { 522 element = BTM.$(element); 523 className2 = className2 || ''; 524 BTM.log("Swapping classes '" + className1 + "' and '" + className2 + "'", element); 525 var classToAdd = BTM.DOM.hasClass(element, className1) ? className2 : className1; 526 var classToRemove = classToAdd === className1 ? className2 : className1; 527 BTM.DOM.addClass(element, classToAdd); 528 BTM.DOM.removeClass(element, classToRemove); 529 530 return element; 531 }; 532 533 /** 534 * Wrap an element in a new element 535 * @param {HTMLElement|String} element element ID or element reference to wrap 536 * @param {String} newTag tag to wrap original element with 537 * @param {Object} [attributes] attributes to set on new element 538 * @returns {HTMLElement} the newly created element 539 */ 540 BTM.DOM.wrap = function wrap(element, newTag, attributes) { 541 element = BTM.$(element); 542 543 var newElement = BTM.DOM.createElement(newTag, attributes || {}); 544 BTM.log("Wrapping with new '" + newTag + "' element", element); 545 element.parentNode.replaceChild(newElement, element); 546 547 newElement.appendChild(element); 548 549 return newElement; 550 }; 551 552 /** 553 * Create a new element, optionally with attributes 554 * @param {String} tag of the new element to create 555 * @param {Object} [attributes] the attributes to add to the newly created element 556 * @returns {HTMLElement} the newly created element 557 */ 558 BTM.DOM.createElement = function createElement(tag, attributes, content) { 559 attributes = attributes || false; 560 if (BTM.Browser.is('Trident', 7, 'lte') && (!attributes || BTM.DOM.newElementUnsafeAttributes.some(function(el){return attributes.hasOwnProperty(el);}))) { 561 var newElStr = '<' + tag + ' '; 562 for (var i = 0; i < BTM.DOM.newElementUnsafeAttributes.length; i++) { 563 if (attributes.hasOwnProperty(BTM.DOM.newElementUnsafeAttributes[i])) { 564 newElStr += BTM.DOM.newElementUnsafeAttributes[i] + '="' + attributes[BTM.DOM.newElementUnsafeAttributes[i]] + '" '; 565 } 566 } 567 if (BTM.DOM.inlineElements.indexOf(tag) !== -1) { 568 newElStr += '/>'; 569 } 570 else { 571 newElStr += '></' + tag + '>'; 572 } 573 574 var element = document.createElement(newElStr); 575 } 576 else { 577 var element = document.createElement(tag); 578 } 579 580 BTM.log("Creating new '" + tag + "' element with " + Object.size(attributes) + " attributes", element, attributes); 581 582 if(attributes) { 583 BTM.DOM.setAttribute(element, attributes); 584 } 585 586 if (content) { 587 BTM.DOM.update(element, content); 588 } 589 590 return element; 591 }; 592 593 /** 594 * Get the specified attribute(s) for an element 595 * @param {HTMLElement|String} element element ID or element reference to get attribute(s) of 596 * @param {String|String[]} name the name of a single attribute to get, or an Array containing names of attributes to set 597 * @returns {String|String[]} the attribute value(s) from the element. 598 */ 599 BTM.DOM.getAttribute = function getAttribute(element, name) { 600 element = BTM.$(element); 601 if (!element) { 602 return element; 603 } 604 605 if (Object.isString(name)) { 606 BTM.log("Getting attribute '" + name + "'", element); 607 if (BTM.DOM.renamedAttributes && BTM.DOM.renamedAttributes.hasOwnProperty(name)) { 608 BTM.log("Using attribute name '" + BTM.DOM.renamedAttributes[name] + "' instead of '" + name + "'", element); 609 name = BTM.DOM.renamedAttributes[name]; 610 } 611 612 if (BTM.DOM.hasAttribute(element, name)) { 613 return element.getAttribute(name); 614 } 615 } 616 else if (Object.isArray(name)) { 617 var atts = {}; 618 BTM.log("Getting attributes", element); 619 name.forEach(function(att) { 620 if (BTM.DOM.renamedAttributes && BTM.DOM.renamedAttributes.hasOwnProperty(name)) { 621 var newName = BTM.DOM.renamedAttributes[att]; 622 att = newName; 623 } 624 if (BTM.DOM.hasAttribute(element, att)) { 625 atts[att] = BTM.DOM.getAttribute(element, att); 626 } 627 }); 628 return atts; 629 } 630 }; 631 632 /** 633 * Set attribute(s) on an element 634 * @param {HTMLElement|String} element element ID or element reference to set attribute(s) on 635 * @param {String|Object} name the name of a single attribute to set, or an object containing name:value pairs of attributes to set 636 * @param [value] the value to use when setting a single attribute 637 * @returns {HTMLElement} the original element 638 */ 639 BTM.DOM.setAttribute = function setAttribute(element, name, value) { 640 element = BTM.$(element); 641 642 if (Object.isString(name)) { 643 BTM.log("Setting '" + name + "' attribute to '" + value + "'", element); 644 if (BTM.DOM.renamedAttributes && BTM.DOM.renamedAttributes.hasOwnProperty(name)) { 645 BTM.log("Using attribute name '" + BTM.DOM.renamedAttributes[name] + "' instead of '" + name + "'", element); 646 name = BTM.DOM.renamedAttributes[name]; 647 } 648 element.setAttribute(name, value); 649 } 650 else { 651 BTM.log("Setting attributes", element); 652 for (var att in name) { 653 if (name.hasOwnProperty(att)) { 654 BTM.DOM.setAttribute(element, att, name[att]); 655 } 656 } 657 } 658 return element; 659 }; 660 661 /** 662 * Remove attribute(s) from an element 663 * @param {HTMLElement|String} element element ID or element reference to remove attribute(s) from 664 * @param {String|Array} name the name of a single attribute to remove, or an array containing names of attributes to remove 665 * @returns {HTMLElement} the original element 666 */ 667 BTM.DOM.removeAttribute = function removeAttribute(element, name) { 668 element = BTM.$(element); 669 670 if (Object.isString(name)) { 671 BTM.log("Removing '" + name + "' attribute", element); 672 if (BTM.DOM.renamedAttributes && BTM.DOM.renamedAttributes.hasOwnProperty(name)) { 673 BTM.log("Using attribute name '" + BTM.DOM.renamedAttributes[name] + "' instead of '" + name + "'", element); 674 name = BTM.DOM.renamedAttributes[name]; 675 } 676 element.removeAttribute(name); 677 } 678 else if (Object.isArray(name)) { 679 name.forEach(BTM.DOM.removeAttribute.curry(element)); 680 } 681 return element; 682 }; 683 684 /** 685 * Check if an element has an attribute 686 * @param {HTMLElement|String} element element ID or element reference to check for attribute 687 * @param {String} name the name of the attribute to check for 688 * @returns {Boolean} true if element has the attribute, false if it does not 689 */ 690 BTM.DOM.hasAttribute = function hasAttribute(element, name) { 691 element = BTM.$(element); 692 693 if (BTM.DOM.renamedAttributes && BTM.DOM.renamedAttributes.hasOwnProperty(name)) { 694 name = BTM.DOM.renamedAttributes[name]; 695 } 696 697 if (element.hasAttribute) { 698 return element.hasAttribute(name); 699 } 700 else { 701 return element.getAttribute(name) !== null; 702 } 703 }; 704 705 /** 706 * Set style attribute(s) on an element 707 * @param {HTMLElement|String} element element ID or element reference to set style attribute(s) on 708 * @param {String|Object} name the name of a single style attribute to set, or an object containing name:value pairs of style attributes to set 709 * @param [value] the value to use when setting a single style attribute 710 * @returns {HTMLElement} the original element 711 */ 712 BTM.DOM.setStyle = function setStyle(element, name, value) { 713 element = BTM.$(element); 714 715 if (Object.isString(name)) { 716 if (name === 'float') { 717 name = Object.isUndefined(element.style.styleFloat) ? 'cssFloat' : 'styleFloat'; 718 } 719 BTM.log("Setting '" + name + "' style property to '" + value + "'", element); 720 element.style[name.toCamelCase()] = value; 721 } 722 else { 723 for (var att in name) { 724 if (name.hasOwnProperty(att)) { 725 BTM.log("Setting '" + att + "' style property to '" + name[att] + "'", element); 726 element.style[att.toCamelCase()] = name[att]; 727 } 728 } 729 } 730 return element; 731 }; 732 733 /** 734 * Get a Pixel value for a non-pixel length type, such as em, pt, etc 735 * @param {HTMLElement|String} element element ID or element reference to get pixel value from 736 * @param {String} value the value to extract a pixel value from 737 * @returns {Number|String} the calculated pixel value, or the original value provided 738 */ 739 BTM.DOM.getPixelValue = function getPixelValue(element, value) { 740 if (BTM.DOM.pixelRegEx.test(value)) { 741 return parseInt(value); 742 } 743 try { 744 if (element.runtimeStyle) { 745 var style = element.style.left; 746 var runtimeStyle = element.runtimeStyle.left; 747 element.runtimeStyle.left = element.currentStyle.left; 748 element.style.left = value || 0; 749 value = element.style.pixelLeft; 750 element.style.left = style; 751 element.runtimeStyle.left = runtimeStyle; 752 } 753 } 754 catch (e) {} 755 756 return value; 757 }; 758 759 /** 760 * Get computed style values for an element 761 * @param {HTMLElement|String} element element ID or element reference to get style values from 762 * @param {String} styleProperty style property to get from element 763 * @returns {String} the computed value of the specified style on element 764 */ 765 BTM.DOM.getComputedStyle = function getComputedStyle(element, styleProperty) { 766 element = BTM.$(element); 767 if (styleProperty === 'float') { 768 styleProperty = element.style.styleFloat ? 'styleFloat' : 'cssFloat'; 769 } 770 771 styleProperty = styleProperty.toCamelCase(); 772 773 var hide = false; 774 775 if (styleProperty !== 'display' && element.style.display === 'none') { 776 hide = true; 777 BTM.Effect.show(element); 778 } 779 780 781 if (element.currentStyle) { 782 if (styleProperty === 'border') { 783 var style = element.currentStyle.borderStyle + " " + 784 element.currentStyle.borderWidth + " " + 785 element.currentStyle.borderColor; 786 } 787 else { 788 var style = element.currentStyle[styleProperty]; 789 } 790 } 791 else if (window.getComputedStyle && document.defaultView) { 792 var computedStyle = document.defaultView.getComputedStyle(element, null); 793 var style = computedStyle[styleProperty]; 794 } 795 if (BTM.DOM.lengthProperties.inArray(styleProperty)) { 796 style = BTM.DOM.getPixelValue(element, style); 797 } 798 799 if (hide) { 800 BTM.Effect.hide(element); 801 } 802 803 return style; 804 }; 805 806 /** 807 * Get actual style values for an element 808 * @param {HTMLElement|String} element element ID or element reference to get style values from 809 * @param {String} styleProperty style property to get from element 810 * @returns {String} the value of the specified style on element 811 */ 812 BTM.DOM.getStyle = function getStyle(element, styleProperty) { 813 element = BTM.$(element); 814 if (styleProperty === 'float') { 815 styleProperty = element.style.styleFloat ? 'styleFloat' : 'cssFloat'; 816 } 817 818 var hide = false; 819 820 if (styleProperty !== 'display' && element.style.display === 'none') { 821 hide = true; 822 BTM.Effect.show(element); 823 } 824 825 var style = element.style[styleProperty.toCamelCase()]; 826 827 if (hide) { 828 BTM.Effect.hide(element); 829 } 830 831 return style; 832 }; 833 834 /** 835 * Transform an element into a different element, keeping the same attributes 836 * @param {HTMLElement|String} element element ID or element reference to transform 837 * @param {String} newTag the tag the element should be to be transformed into 838 * @param {Object} [options] currently un-used 839 * @returns {HTMLElement} a reference to the new object 840 */ 841 BTM.DOM.morph = function morph(element, newTag, options) { 842 element = BTM.$(element); 843 844 var atts = BTM.DOM.getAttribute(element, BTM.DOM.standardAttributes.concat(BTM.DOM.conditionalAttributes[newTag])); 845 atts = Object.filter(atts, function(att) { 846 return att !== '' && att !== null; 847 }); 848 var newElement = BTM.DOM.createElement(newTag, atts); 849 850 if (!BTM.DOM.inlineElements.inArray(newTag) && atts.value && newElement.innerText === "") { 851 newElement.appendChild(document.createTextNode(atts.value)); 852 } 853 854 element.parentNode.replaceChild(newElement, element); 855 856 return newElement; 857 }; 858 859 860 /** 861 * Update the contents of an Element 862 * @param {HTMLElement|String} element element ID or element reference to update contents of 863 * @param {HTMLElement|Object|String} content the new content for the element. Can be a HTML Element, a string, or an object (requires a toHTML or toString method) 864 * @returns {HTMLElement} the original Element 865 */ 866 BTM.DOM.update = function update(element, content) { 867 element = BTM.$(element); 868 content = content || ""; 869 870 if (Object.isElement(content)) { 871 element.innerHTML = ""; 872 element.appendChild(content); 873 } 874 else if (Object.isString(content)) { 875 element.innerHTML = content; 876 } 877 else if (content.toHTML) { 878 element.innerHTML = content.toHTML(); 879 } 880 else if (content.toString) { 881 element.innerHTML = content.toString(); 882 } 883 884 return element; 885 }; 886 887 /** 888 * Make an element unselectable by the user 889 * @param {HTMLElement|String} element element ID or element reference to make unselectable 890 * @returns {HTMLElement} the original element 891 * @see BTM.DOM.makeSelectable 892 */ 893 BTM.DOM.makeUnselectable = function makeUnselectable(element) { 894 element = BTM.$(element); 895 var style = {'user-select':'none'}; 896 switch(BTM.Browser.engine) { 897 case 'Gecko': 898 style['-moz-user-select'] = 'none'; 899 break; 900 901 case 'KHTML': 902 style['-khtml-user-select'] = 'none'; 903 break; 904 905 case 'WebKit': 906 style['-webkit-user-select'] = 'none'; 907 break; 908 909 case 'Trident': 910 var makeUnselectableFunc = BTM.observe(element, 'selectstart', BTM.self.curry(false)); 911 BTM.DOM.setAttribute('makeUnselectableFunc', makeUnselectableFunc); 912 break; 913 } 914 BTM.log("Making element unselectable", element); 915 BTM.DOM.setStyle(element, style); 916 }; 917 918 /** 919 * Make an element selectable by the user 920 * @param {HTMLElement|String} element element ID or element reference to make selectable 921 * @returns {HTMLElement} the original element 922 * @see BTM.DOM.makeUnselectable 923 */ 924 BTM.DOM.makeSelectable = function makeSelectable(element) { 925 element = BTM.$(element); 926 var style = {'user-select':''}; 927 switch(BTM.Browser.engine) { 928 case 'Gecko': 929 style['-moz-user-select'] = ''; 930 break; 931 932 case 'KHTML': 933 style['-khtml-user-select'] = ''; 934 break; 935 936 case 'WebKit': 937 style['-webkit-user-select'] = ''; 938 break; 939 940 case 'Trident': 941 var makeUnselectableFunc = BTM.DOM.getAttribute('makeUnselectableFunc'); 942 BTM.stopObserving(element, 'selectstart', makeUnselectableFunc); 943 break; 944 } 945 946 BTM.log("Making element selectable", element); 947 BTM.DOM.setStyle(element, style); 948 }; 949 950 /** 951 * Get the dimensions of an element, optionally including it's margins 952 * @param {HTMLElement|String} element element ID or element reference to get dimensions of 953 * @param {Boolean} [includeMargins=false] flag to include margin width in dimension calculations 954 * @returns {Object} Object containing "height" and "width" properties. 955 */ 956 BTM.DOM.getDimensions = function getDimensions(element, includeMargins) { 957 element = BTM.$(element); 958 includeMargins = includeMargins || false; 959 960 var dimensions = { 961 'height' : element.offsetHeight, 962 'width' : element.offsetWidth 963 }; 964 965 if (includeMargins) { 966 var margins = { 967 'width' : parseInt(BTM.DOM.getComputedStyle(element,'margin-top') || 0) + parseInt(BTM.DOM.getComputedStyle(element,'margin-bottom') || 0), 968 'height' : parseInt(BTM.DOM.getComputedStyle(element,'margin-left') || 0) + parseInt(BTM.DOM.getComputedStyle(element,'margin-right') || 0) 969 }; 970 971 dimensions.height += margins.height; 972 dimensions.width += margins.width; 973 } 974 975 return dimensions; 976 }; 977 978 /** 979 * Get the inner "available" space of an element 980 * @param {HTMLElement|String} element element ID or element reference to get "available" space of 981 * @param {Object} [dimensions] manual stipulation of the original dimensions to base the calculations on 982 * @returns {Object} Object containing "height" and "width" properties. 983 */ 984 BTM.DOM.getAvailableSpace = function getAvailableSpace(element, dimensions) { 985 element = BTM.$(element); 986 dimensions = dimensions || { 987 'width' : element.clientWidth, 988 'height' : element.clientHeight 989 }; 990 991 var spacing = { 992 'width' : parseInt(BTM.DOM.getComputedStyle(element,'padding-left') || 0) + 993 parseInt(BTM.DOM.getComputedStyle(element,'padding-right') || 0) + 994 parseInt(BTM.DOM.getComputedStyle(element,'margin-left') || 0) + 995 parseInt(BTM.DOM.getComputedStyle(element,'margin-right') || 0) + 996 parseInt(BTM.DOM.getComputedStyle(element,'border-left-width') || 0) + 997 parseInt(BTM.DOM.getComputedStyle(element,'border-right-width') || 0), 998 999 'height' : parseInt(BTM.DOM.getComputedStyle(element,'padding-top') || 0) + 1000 parseInt(BTM.DOM.getComputedStyle(element,'padding-bottom') || 0) + 1001 parseInt(BTM.DOM.getComputedStyle(element,'margin-top') || 0) + 1002 parseInt(BTM.DOM.getComputedStyle(element,'margin-bottom') || 0) + 1003 parseInt(BTM.DOM.getComputedStyle(element,'border-top-width') || 0) + 1004 parseInt(BTM.DOM.getComputedStyle(element,'border-bottom-width') || 0) 1005 }; 1006 1007 var innerDimensions = { 1008 'width' : dimensions.width - spacing.width, 1009 'height' : dimensions.height - spacing.height 1010 }; 1011 1012 return innerDimensions; 1013 };