1 if (Prototype.Browser.WebKit) { 2 Object.extend(Event, { 3 // This does not appear to be the case now 4 // KEY_LEFT: 63234, 5 // KEY_UP: 63232, 6 // KEY_RIGHT: 63235, 7 // KEY_DOWN: 63233, 8 // KEY_DELETE: 63272, 9 KEY_HOME: 63273, 10 KEY_END: 63275, 11 KEY_PAGEUP: 63276, 12 KEY_PAGEDOWN: 63277 13 }); 14 } 15 16 Object.extend(Element, { 17 body: function() { 18 return $$('body')[0]; 19 }, 20 21 head: function() { 22 return $$('head')[0]; 23 }, 24 25 html: function() { 26 return $$('html')[0]; 27 }, 28 29 isRendered: function(elt) { 30 return elt.descendantOf(Element.body()); 31 }, 32 33 toPixels: function(val) { 34 if (!val) { return val; } 35 36 if (Object.isNumber(val)) { return val + "px"; } 37 if (Object.isString(val) && val.match(/^-?\d*$/)) { return val + "px"; } 38 39 return val; 40 }, 41 42 pixeledAttributes: [ 43 "width", "height", 44 "padding", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft", 45 "margin", "marginTop", "marginRight", "marginBottom", "marginLeft", 46 "top", "bottom", "left", "right", 47 "fontSize" 48 ] 49 }); 50 51 Element.addMethods({ 52 53 removeToInsertLater: function(elt) { 54 var parentNode = elt.parentNode; 55 var nextSibling = elt.nextSibling; 56 parentNode.removeChild(elt); 57 58 return function() { 59 if (nextSibling) { 60 parentNode.insertBefore(elt, nextSibling); 61 } else { 62 parentNode.appendChild(elt); 63 } 64 }; 65 }, 66 67 totalHeight: function(elt) { 68 return ["height", "margin-top", "margin-bottom", "padding-top", "padding-bottom", "border-top-width", "border-bottom-width"].inject(0, function(acc, prop) { 69 return acc + (parseInt(elt.getStyle(prop), 0) || 0); 70 }); 71 }, 72 73 addHoverClass: function(elt, hoverClass, focusClass) { 74 elt = $(elt); 75 elt.observe('mouseover', function() { 76 elt.addClassName(hoverClass); 77 }); 78 elt.observe('mouseout', function() { 79 elt.removeClassName(hoverClass); 80 }); 81 if (focusClass) { 82 elt.observe('focus', function() { 83 elt.addClassName(focusClass); 84 elt.removeClassName(hoverClass); 85 }); 86 elt.observe('blur', function() { 87 elt.removeClassName(focusClass); 88 }); 89 } 90 }, 91 92 insert: Element.insert.wrap(function(proceed, elt, insertions) { 93 var newInsertions; 94 if (insertions.html) { 95 newInsertions = insertions.html(); 96 } else if (insertions.top || insertions.bottom || insertions.before || insertions.after) { 97 newInsertions = {}; 98 Object.keys(insertions).each(function(position) { 99 newInsertions[position] = insertions[position].html ? insertions[position].html() : insertions[position]; 100 }); 101 } else { 102 newInsertions = insertions; 103 } 104 105 proceed(elt, newInsertions); 106 }), 107 108 applyStyle: function(elt, styles) { 109 var toApply = {}; 110 var styleBinding = function(val) { 111 var style = {}; 112 style[styleName] = Element.pixeledAttributes.include(styleName) ? Element.toPixels(val) : val; 113 elt.setStyle(style); 114 }; 115 for (styleName in styles) { 116 var val = styles[styleName]; //.THEME ? styles[styleName]() : styles[styleName]; 117 if (val == undefined) { 118 // Do nothing 119 } else if (val.BINDING) { 120 val.bind(styleBinding, true); 121 var newValue = Element.pixeledAttributes.include(styleName) ? Element.toPixels(val.value()) : val.value(); 122 if (newValue !== undefined) { 123 toApply[styleName] = newValue; 124 } 125 } else { 126 toApply[styleName] = Element.pixeledAttributes.include(styleName) ? Element.toPixels(val) : val; 127 } 128 } 129 elt.setStyle(toApply); 130 }, 131 132 horizontalMBP: function(elt) { 133 return elt.totalPixelsForStyles(["marginLeft", "marginRight", "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight"]); 134 }, 135 136 verticalMBP: function(elt) { 137 return elt.totalPixelsForStyles(["marginTop", "marginBottom", "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom"]); 138 }, 139 140 totalPixelsForStyles: function(elt, styles) { 141 return styles.inject(0, function(acc, s) { 142 var val = parseInt(elt.getStyle(s).stripPx() || 0, 10); 143 if (isNaN(val)) { // Test for IE!! 144 val = 0; 145 } 146 return acc + val; 147 }); 148 } 149 150 }); 151 152 if (rio.environment.logEventErrors) { 153 rio.eventCounts = {}; 154 Event.observe = Event.observe.wrap(function(proceed, element, eventName, handler) { 155 rio.eventCounts[eventName] = (rio.eventCounts[eventName] || 0) + 1; 156 var newHandler = handler.wrap(function(proceed) { 157 try { 158 proceed.apply(proceed, $A(arguments).slice(1)); 159 } catch(e) { 160 rio.error(e, "Error processing event: " + element + "#" + eventName); 161 throw(e); 162 } 163 }); 164 proceed(element, eventName, newHandler); 165 }); 166 167 Element.addMethods({ 168 observe: Event.observe 169 }); 170 171 Object.extend(document, { 172 observe: Element.Methods.observe.methodize() 173 }); 174 175 Ajax.Request.prototype.dispatchException = Ajax.Request.prototype.dispatchException.wrap(function(proceed, exception) { 176 rio.error(exception, "Error processing Ajax callback: "); 177 proceed(exception); 178 }); 179 } 180 181 Object.extend(Date.prototype, { 182 strftime: function(format) { 183 var day = this.getDay(), month = this.getMonth(); 184 var hours = this.getHours(), minutes = this.getMinutes(); 185 function pad(num) { return num.toPaddedString(2); } 186 187 return format.gsub(/\%([aAbBcdDeHiImMnpPSwyY])/, function(part) { 188 switch(part[1]) { 189 case 'a': return $w("Sun Mon Tue Wed Thu Fri Sat")[day]; 190 case 'A': return $w("Sunday Monday Tuesday Wednesday Thursday Friday Saturday")[day]; 191 case 'b': return $w("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec")[month]; 192 case 'B': return $w("January February March April May June July August September October November December")[month]; 193 case 'c': return this.toString(); 194 case 'd': return pad(this.getDate()); 195 case 'D': return pad(this.getDate()); 196 case 'e': return this.getDate(); 197 case 'H': return pad(hours); 198 case 'i': return (hours === 12 || hours === 0) ? 12 : (hours + 12) % 12; 199 case 'I': return pad((hours === 12 || hours === 0) ? 12 : (hours + 12) % 12); 200 case 'm': return pad(month + 1); 201 case 'M': return pad(minutes); 202 case 'n': return month + 1; 203 case 'p': return hours > 11 ? 'PM' : 'AM'; 204 case 'P': return hours > 11 ? 'pm' : 'am'; 205 case 'S': return pad(this.getSeconds()); 206 case 'w': return day; 207 case 'y': return pad(this.getFullYear() % 100); 208 case 'Y': return this.getFullYear().toString(); 209 } 210 }.bind(this)); 211 }, 212 213 prettyTime: function() { 214 return this.getHours() + ":" + 215 this.getMinutes().toPaddedString(2) + ":" + 216 this.getSeconds().toPaddedString(2); 217 } 218 }); 219 220 Object.extend(Date, { 221 /* 222 Adapted from (http://delete.me.uk/2005/03/iso8601.html) 223 */ 224 parseISO: function(string) { 225 var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(/.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?"; 226 var d = string.match(new RegExp(regexp)); 227 228 var offset = 0; 229 var date = new Date(d[1], 0, 1); 230 231 if (d[3]) { date.setMonth(d[3] - 1); } 232 if (d[5]) { date.setDate(d[5]); } 233 if (d[7]) { date.setHours(d[7]); } 234 if (d[8]) { date.setMinutes(d[8]); } 235 if (d[10]) { date.setSeconds(d[10]); } 236 if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); } 237 if (d[14]) { 238 offset = (Number(d[16]) * 60) + Number(d[17]); 239 offset *= ((d[15] == '-') ? 1 : -1); 240 } 241 242 // I had to add the * 2 to get it to work 243 offset -= date.getTimezoneOffset(); 244 time = (Number(date) + (offset * 60 * 1000)); 245 246 return new Date(Number(time)); 247 } 248 }); 249 250 Object.extend(String.prototype, { 251 camelize: function() { 252 var parts = this.split(/_|-/), len = parts.length; 253 if (len == 1) { return parts[0]; } 254 255 var camelized = this.charAt(0) == '-' || this.charAt(0) == '_' ? 256 parts[0].charAt(0).toUpperCase() + parts[0].substring(1) : parts[0]; 257 258 for (var i = 1; i < len; i++) { 259 camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); 260 } 261 262 return camelized; 263 }, 264 265 stripPx: function() { 266 return Number(this.endsWith("px") ? this.match(/(.*)px/)[1] : this); 267 }, 268 269 classize: function() { 270 if (this.length == 0) { return ""; } 271 if (this.length == 1) { return this.capitalize(); } 272 273 return this.capitalize().slice(0,1) + this.camelize().slice(1); 274 }, 275 276 isNumeric: function() { 277 return parseFloat(this) + '' == parseFloat(this); 278 }, 279 280 toBoolean: function() { 281 return this.toLowerCase() == "true"; 282 }, 283 284 validEmail: function() { 285 return this.match(/^([^@\s]+)@((?:[\-a-z0-9]+\.)+[a-z]{2,})$/i); 286 } 287 }); 288 289 Object.extend(Number.prototype, { 290 stripPx: function() { 291 return this; 292 } 293 }); 294 295 Object.extend(Array.prototype, { 296 destroy: function(item) { 297 this.splice(this.indexOf(item), 1); 298 item.destroy(); 299 }, 300 301 empty: function() { 302 return this.size() == 0; 303 } 304 }); 305 306 // This is a superior implementation, developed by Douglas Crockford 307 // this function unfortunately treats the HTMLSelectElement as an array :( 308 Object.isArray = function(testObject) { 309 return testObject && !(testObject.propertyIsEnumerable != undefined && testObject.propertyIsEnumerable('length')) && typeof testObject === 'object' && typeof testObject.length === 'number' && !(testObject.tagName == "SELECT"); 310 }; 311 312 Object.isDate = function(testObject) { 313 return testObject != undefined && testObject.getTimezoneOffset != undefined; 314 }; 315 316 Prototype.Browser.IE6 = Prototype.Browser.IE && parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE")+5), 10)==6; 317 Prototype.Browser.IE7 = Prototype.Browser.IE && parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE")+5), 10)==7; 318 Prototype.Browser.IE8 = Prototype.Browser.IE && parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE")+5), 10)==8; 319 320 321 322