1 /* 2 * Copyright © 2009 Apple Inc. All rights reserved. 3 */ 4 5 /** 6 * @class 7 * @name Element 8 * @description Extensions to the DOM Core <a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-745549614"><code>Element</code></a> interface. 9 * @since TuneKit 1.0 10 */ 11 12 /* ==================== Element Extensions ==================== */ 13 14 /** 15 * Indicates whether the element has a given class name within its <code>class</code> attribute. 16 * 17 * @param {String} className The CSS class name. 18 * @returns {bool} Whether the element has this class name within its <code>class</code> attribute. 19 * @memberOf Element.prototype 20 */ 21 Element.prototype.hasClassName = function (className) { 22 return new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)').test(this.className); 23 }; 24 25 /** 26 * Adds the given class name to the element's <code>class</code> attribute if it's not already there. 27 * 28 * @param {String} className The CSS class name. 29 * @memberOf Element.prototype 30 */ 31 Element.prototype.addClassName = function (className) { 32 if (!this.hasClassName(className)) { 33 this.className = [this.className, className].join(' '); 34 } 35 }; 36 37 /** 38 * Removes the given class name from the element's <code>class</code> attribute if it's there. 39 * 40 * @param {String} className The CSS class name. 41 * @memberOf Element.prototype 42 */ 43 Element.prototype.removeClassName = function (className) { 44 if (this.hasClassName(className)) { 45 var curClasses = this.className; 46 this.className = curClasses.replace(new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', 'g'), ' '); 47 } 48 }; 49 50 /** 51 * Adds the given class name to the element's <code>class</code> attribute if it's not there, or removes it if it's already set. 52 * 53 * @param {String} className The CSS class name. 54 * @memberOf Element.prototype 55 */ 56 Element.prototype.toggleClassName = function (className) { 57 this[this.hasClassName(className) ? 'removeClassName' : 'addClassName'](className); 58 }; 59 60 /** 61 * Removes all the children from an element. 62 * 63 * @memberOf Element.prototype 64 */ 65 // XXX: should this be on Node? 66 Element.prototype.removeAllChildren = function () { 67 while (this.firstChild) { 68 this.removeChild(this.firstChild); 69 } 70 }; 71 72 /** 73 * Returns true if the element has the given child node 74 * FIXME: should this be on Node? 75 * 76 * @param {Element} child The child to search for 77 * @memberOf Element.prototype 78 */ 79 Element.prototype.hasChild = function (child) { 80 for (var i=0; i < this.childNodes.length; i++) { 81 if (this.childNodes[i] === child) { 82 return true; 83 } 84 } 85 return false; 86 }; 87 88 /** 89 * Applies a transition definition to the element, allowing the transition to be reversed. If this method is called 90 * within a {@link TKTransaction}, the transition will only be commited when the transaction is completed. 91 * 92 * @param {TKTransitionDefinition} transitionDefinition The transition applied to the element. 93 * @param {bool} reversed Indicates whether the transition is to be applied in reverse. 94 */ 95 Element.prototype.applyTransition = function (definition, reversed) { 96 // nothing to do if we have no definition 97 if (definition === null) { 98 return; 99 } 100 // create a TKTransition from the definition 101 var transition = new TKTransition(definition); 102 // this view will be the target 103 transition.target = this; 104 // revert from / to values as instructed 105 if (reversed) { 106 var from = transition.from; 107 transition.from = transition.to; 108 transition.to = from; 109 } 110 // set up base properties, if any 111 if (definition.base) { 112 for (var i = 0; i < definition.base.length; i += 2) { 113 this.style.setProperty(definition.base[i], definition.base[i+1], ''); 114 } 115 } 116 // start the transition 117 transition.start(); 118 }; 119 120 Element.prototype.getBounds = function () { 121 return TKRect.rectFromClientRect(this.getBoundingClientRect()); 122 }; 123 124 Element.prototype.isNavigable = function () { 125 var is_navigable = false; 126 if (this._controller !== undefined && this._controller !== null && this._controller.navigableElements.indexOf(this) !== -1) { 127 var style = window.getComputedStyle(this); 128 is_navigable = ( 129 style.display != 'none' && style.visibility != 'hidden' && 130 !this.hasClassName(TKSpatialNavigationManagerInactiveCSSClass) 131 ); 132 } 133 return is_navigable; 134 }; 135 136 TKUtils.setupDisplayNames(Element, 'Element'); 137