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