| 1 | // small but works-for-me stuff for testing javascripts |
|---|
| 2 | // not ready for "production" use |
|---|
| 3 | |
|---|
| 4 | Object.inspect = function(obj) { |
|---|
| 5 | var info = []; |
|---|
| 6 | |
|---|
| 7 | if(typeof obj=="string" || |
|---|
| 8 | typeof obj=="number") { |
|---|
| 9 | return obj; |
|---|
| 10 | } else { |
|---|
| 11 | for(property in obj) |
|---|
| 12 | if(typeof obj[property]!="function") |
|---|
| 13 | info.push(property + ' => "' + obj[property] + '"'); |
|---|
| 14 | } |
|---|
| 15 | |
|---|
| 16 | return ("'" + obj + "' #" + typeof obj + |
|---|
| 17 | ": {" + info.join(", ") + "}"); |
|---|
| 18 | } |
|---|
| 19 | |
|---|
| 20 | // borrowed from http://www.schuerig.de/michael/javascript/stdext.js |
|---|
| 21 | // Copyright (c) 2005, Michael Schuerig, michael@schuerig.de |
|---|
| 22 | |
|---|
| 23 | Array.flatten = function(array, excludeUndefined) { |
|---|
| 24 | if (excludeUndefined === undefined) { |
|---|
| 25 | excludeUndefined = false; |
|---|
| 26 | } |
|---|
| 27 | var result = []; |
|---|
| 28 | var len = array.length; |
|---|
| 29 | for (var i = 0; i < len; i++) { |
|---|
| 30 | var el = array[i]; |
|---|
| 31 | if (el instanceof Array) { |
|---|
| 32 | var flat = el.flatten(excludeUndefined); |
|---|
| 33 | result = result.concat(flat); |
|---|
| 34 | } else if (!excludeUndefined || el != undefined) { |
|---|
| 35 | result.push(el); |
|---|
| 36 | } |
|---|
| 37 | } |
|---|
| 38 | return result; |
|---|
| 39 | }; |
|---|
| 40 | |
|---|
| 41 | if (!Array.prototype.flatten) { |
|---|
| 42 | Array.prototype.flatten = function(excludeUndefined) { |
|---|
| 43 | return Array.flatten(this, excludeUndefined); |
|---|
| 44 | } |
|---|
| 45 | } |
|---|
| 46 | |
|---|
| 47 | /*--------------------------------------------------------------------------*/ |
|---|
| 48 | |
|---|
| 49 | var Builder = { |
|---|
| 50 | node: function(elementName) { |
|---|
| 51 | var element = document.createElement(elementName); |
|---|
| 52 | |
|---|
| 53 | // attributes (or text) |
|---|
| 54 | |
|---|
| 55 | if(arguments[1]) { |
|---|
| 56 | if(this._isStringOrNumber(arguments[1]) || |
|---|
| 57 | (arguments[1] instanceof Array)) |
|---|
| 58 | this._children(element, arguments[1]); |
|---|
| 59 | else |
|---|
| 60 | this._attributes(element, arguments[1]); |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | // text, or array of children |
|---|
| 64 | if(arguments[2]) |
|---|
| 65 | this._children(element, arguments[2]); |
|---|
| 66 | |
|---|
| 67 | return element; |
|---|
| 68 | }, |
|---|
| 69 | _text: function(text) { |
|---|
| 70 | return document.createTextNode(text); |
|---|
| 71 | }, |
|---|
| 72 | _attributes: function(element, attributes) { |
|---|
| 73 | for(attribute in attributes) |
|---|
| 74 | if(this._isStringOrNumber(attributes[attribute])) |
|---|
| 75 | element.setAttribute( |
|---|
| 76 | attribute=='className' ? 'class' : attribute, |
|---|
| 77 | attributes[attribute]); |
|---|
| 78 | }, |
|---|
| 79 | _children: function(element, children) { |
|---|
| 80 | if(typeof children=='object') { // array can hold nodes and text |
|---|
| 81 | children = children.flatten(); |
|---|
| 82 | for(var i = 0; i<children.length; i++) |
|---|
| 83 | if(typeof children[i]=='object') |
|---|
| 84 | element.appendChild(children[i]); |
|---|
| 85 | else |
|---|
| 86 | if(this._isStringOrNumber(children[i])) |
|---|
| 87 | element.appendChild(this._text(children[i])); |
|---|
| 88 | } else |
|---|
| 89 | if(this._isStringOrNumber(children)) |
|---|
| 90 | element.appendChild(this._text(children)); |
|---|
| 91 | }, |
|---|
| 92 | _isStringOrNumber: function(param) { |
|---|
| 93 | return(typeof param=='string' || typeof param=='number'); |
|---|
| 94 | } |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | /* ------------- element ext -------------- */ |
|---|
| 98 | |
|---|
| 99 | // adapted from http://dhtmlkitchen.com/learn/js/setstyle/index4.jsp |
|---|
| 100 | // note: Safari return null on elements with display:none; see http://bugzilla.opendarwin.org/show_bug.cgi?id=4125 |
|---|
| 101 | // instead of "auto" values returns null so it's easier to use with || constructs |
|---|
| 102 | |
|---|
| 103 | String.prototype.camelize = function() { |
|---|
| 104 | var oStringList = this.split('-'); |
|---|
| 105 | if(oStringList.length == 1) |
|---|
| 106 | return oStringList[0]; |
|---|
| 107 | var ret = this.indexOf("-") == 0 ? |
|---|
| 108 | oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) : oStringList[0]; |
|---|
| 109 | for(var i = 1, len = oStringList.length; i < len; i++){ |
|---|
| 110 | var s = oStringList[i]; |
|---|
| 111 | ret += s.charAt(0).toUpperCase() + s.substring(1) |
|---|
| 112 | } |
|---|
| 113 | return ret; |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | Element.getStyle = function(element, style) { |
|---|
| 117 | element = $(element); |
|---|
| 118 | var value = element.style[style.camelize()]; |
|---|
| 119 | if(!value) |
|---|
| 120 | if(document.defaultView && document.defaultView.getComputedStyle) { |
|---|
| 121 | var css = document.defaultView.getComputedStyle(element, null); |
|---|
| 122 | value = (css!=null) ? css.getPropertyValue(style) : null; |
|---|
| 123 | } else if(element.currentStyle) { |
|---|
| 124 | value = element.currentStyle[style.camelize()]; |
|---|
| 125 | } |
|---|
| 126 | if(value=='auto') value = null; |
|---|
| 127 | return value; |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | Element.makePositioned = function(element) { |
|---|
| 131 | element = $(element); |
|---|
| 132 | if(Element.getStyle(element, 'position')=='static') |
|---|
| 133 | element.style.position = "relative"; |
|---|
| 134 | } |
|---|
| 135 | |
|---|
| 136 | Element.makeClipping = function(element) { |
|---|
| 137 | element = $(element); |
|---|
| 138 | element._overflow = Element.getStyle(element, 'overflow') || 'visible'; |
|---|
| 139 | if(element._overflow!='hidden') element.style.overflow = 'hidden'; |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | Element.undoClipping = function(element) { |
|---|
| 143 | element = $(element); |
|---|
| 144 | if(element._overflow!='hidden') element.style.overflow = element._overflow; |
|---|
| 145 | } |
|---|
| 146 | |
|---|
| 147 | /*--------------------------------------------------------------------------*/ |
|---|
| 148 | |
|---|
| 149 | Position.absolutize = function(element) { |
|---|
| 150 | element = $(element); |
|---|
| 151 | if(element.style.position=='absolute') return; |
|---|
| 152 | Position.prepare(); |
|---|
| 153 | |
|---|
| 154 | var offsets = Position.cumulativeOffset(element); |
|---|
| 155 | var top = offsets[1]; |
|---|
| 156 | var left = offsets[0]; |
|---|
| 157 | var width = element.clientWidth; |
|---|
| 158 | var height = element.clientHeight; |
|---|
| 159 | |
|---|
| 160 | element._originalLeft = left - parseFloat(element.style.left || 0); |
|---|
| 161 | element._originalTop = top - parseFloat(element.style.top || 0); |
|---|
| 162 | element._originalWidth = element.style.width; |
|---|
| 163 | element._originalHeight = element.style.height; |
|---|
| 164 | |
|---|
| 165 | element.style.position = 'absolute'; |
|---|
| 166 | element.style.top = top + 'px';; |
|---|
| 167 | element.style.left = left + 'px';; |
|---|
| 168 | element.style.width = width + 'px';; |
|---|
| 169 | element.style.height = height + 'px';; |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | Position.relativize = function(element) { |
|---|
| 173 | element = $(element); |
|---|
| 174 | if(element.style.position=='relative') return; |
|---|
| 175 | Position.prepare(); |
|---|
| 176 | |
|---|
| 177 | element.style.position = 'relative'; |
|---|
| 178 | var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); |
|---|
| 179 | var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); |
|---|
| 180 | |
|---|
| 181 | element.style.top = top + 'px'; |
|---|
| 182 | element.style.left = left + 'px'; |
|---|
| 183 | element.style.height = element._originalHeight; |
|---|
| 184 | element.style.width = element._originalWidth; |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | /*--------------------------------------------------------------------------*/ |
|---|
| 188 | |
|---|
| 189 | Element.Class = { |
|---|
| 190 | // Element.toggleClass(element, className) toggles the class being on/off |
|---|
| 191 | // Element.toggleClass(element, className1, className2) toggles between both classes, |
|---|
| 192 | // defaulting to className1 if neither exist |
|---|
| 193 | toggle: function(element, className) { |
|---|
| 194 | if(Element.Class.has(element, className)) { |
|---|
| 195 | Element.Class.remove(element, className); |
|---|
| 196 | if(arguments.length == 3) Element.Class.add(element, arguments[2]); |
|---|
| 197 | } else { |
|---|
| 198 | Element.Class.add(element, className); |
|---|
| 199 | if(arguments.length == 3) Element.Class.remove(element, arguments[2]); |
|---|
| 200 | } |
|---|
| 201 | }, |
|---|
| 202 | |
|---|
| 203 | // gets space-delimited classnames of an element as an array |
|---|
| 204 | get: function(element) { |
|---|
| 205 | element = $(element); |
|---|
| 206 | return element.className.split(' '); |
|---|
| 207 | }, |
|---|
| 208 | |
|---|
| 209 | // functions adapted from original functions by Gavin Kistner |
|---|
| 210 | remove: function(element) { |
|---|
| 211 | element = $(element); |
|---|
| 212 | var regEx; |
|---|
| 213 | for(var i = 1; i < arguments.length; i++) { |
|---|
| 214 | regEx = new RegExp("^" + arguments[i] + "\\b\\s*|\\s*\\b" + arguments[i] + "\\b", 'g'); |
|---|
| 215 | element.className = element.className.replace(regEx, '') |
|---|
| 216 | } |
|---|
| 217 | }, |
|---|
| 218 | |
|---|
| 219 | add: function(element) { |
|---|
| 220 | element = $(element); |
|---|
| 221 | for(var i = 1; i < arguments.length; i++) { |
|---|
| 222 | Element.Class.remove(element, arguments[i]); |
|---|
| 223 | element.className += (element.className.length > 0 ? ' ' : '') + arguments[i]; |
|---|
| 224 | } |
|---|
| 225 | }, |
|---|
| 226 | |
|---|
| 227 | // returns true if all given classes exist in said element |
|---|
| 228 | has: function(element) { |
|---|
| 229 | element = $(element); |
|---|
| 230 | if(!element || !element.className) return false; |
|---|
| 231 | var regEx; |
|---|
| 232 | for(var i = 1; i < arguments.length; i++) { |
|---|
| 233 | regEx = new RegExp("\\b" + arguments[i] + "\\b"); |
|---|
| 234 | if(!regEx.test(element.className)) return false; |
|---|
| 235 | } |
|---|
| 236 | return true; |
|---|
| 237 | }, |
|---|
| 238 | |
|---|
| 239 | // expects arrays of strings and/or strings as optional paramters |
|---|
| 240 | // Element.Class.has_any(element, ['classA','classB','classC'], 'classD') |
|---|
| 241 | has_any: function(element) { |
|---|
| 242 | element = $(element); |
|---|
| 243 | if(!element || !element.className) return false; |
|---|
| 244 | var regEx; |
|---|
| 245 | for(var i = 1; i < arguments.length; i++) { |
|---|
| 246 | if((typeof arguments[i] == 'object') && |
|---|
| 247 | (arguments[i].constructor == Array)) { |
|---|
| 248 | for(var j = 0; j < arguments[i].length; j++) { |
|---|
| 249 | regEx = new RegExp("\\b" + arguments[i][j] + "\\b"); |
|---|
| 250 | if(regEx.test(element.className)) return true; |
|---|
| 251 | } |
|---|
| 252 | } else { |
|---|
| 253 | regEx = new RegExp("\\b" + arguments[i] + "\\b"); |
|---|
| 254 | if(regEx.test(element.className)) return true; |
|---|
| 255 | } |
|---|
| 256 | } |
|---|
| 257 | return false; |
|---|
| 258 | }, |
|---|
| 259 | |
|---|
| 260 | childrenWith: function(element, className) { |
|---|
| 261 | var children = $(element).getElementsByTagName('*'); |
|---|
| 262 | var elements = new Array(); |
|---|
| 263 | |
|---|
| 264 | for (var i = 0; i < children.length; i++) { |
|---|
| 265 | if (Element.Class.has(children[i], className)) { |
|---|
| 266 | elements.push(children[i]); |
|---|
| 267 | break; |
|---|
| 268 | } |
|---|
| 269 | } |
|---|
| 270 | |
|---|
| 271 | return elements; |
|---|
| 272 | } |
|---|
| 273 | } |
|---|