1 /**
  2                             iiii                                       jjjj                  
  3                            i::::i                                     j::::j                 
  4                             iiii                                       jjjj                  
  5                                                                                              
  6        rrrrr   rrrrrrrrr  iiiiiii    ooooooooooo                     jjjjjjj    ssssssssss   
  7        r::::rrr:::::::::r i:::::i  oo:::::::::::oo  ::::::           j:::::j  ss::::::::::s  
  8        r:::::::::::::::::r i::::i o:::::::::::::::o ::::::            j::::jss:::::::::::::s 
  9        rr::::::rrrrr::::::ri::::i o:::::ooooo:::::o ::::::            j::::js::::::ssss:::::s
 10         r:::::r     r:::::ri::::i o::::o     o::::o                   j::::j s:::::s  ssssss 
 11         r:::::r     rrrrrrri::::i o::::o     o::::o                   j::::j   s::::::s      
 12         r:::::r            i::::i o::::o     o::::o                   j::::j      s::::::s   
 13         r:::::r            i::::i o::::o     o::::o ::::::            j::::jssssss   s:::::s 
 14         r:::::r           i::::::io:::::ooooo:::::o ::::::            j::::js:::::ssss::::::s
 15         r:::::r           i::::::io:::::::::::::::o ::::::            j::::js::::::::::::::s 
 16         r:::::r           i::::::i oo:::::::::::oo                    j::::j s:::::::::::ss  
 17         rrrrrrr           iiiiiiii   ooooooooooo                      j::::j  sssssssssss    
 18                                                                       j::::j                 
 19                                                             jjjj      j::::j                 
 20                                                            j::::jj   j:::::j                 
 21                                                            j::::::jjj::::::j                 
 22                                                             jj::::::::::::j                  
 23                                                               jjj::::::jjj                   
 24                                                                  jjjjjj                      
 25        
 26 
 27 	@name rio
 28 	@namespace
 29 	
 30 	The rio namespace is the root of the entire framework, through which you can access all of the classes and 
 31 	namespaces.
 32 	
 33 	<br />
 34 	
 35 	<h2>Namespaces</h2>
 36 	
 37 	<ul>
 38 		<li>apps - contains instances of rio.Application</li>
 39 		<li>components - contains instances of rio.Component</li>
 40 		<li>models - contains instances of rio.Model</li>
 41 		<li>pages - contains instances of rio.Page</li>
 42 		<li>environment - configuration for the current environment</li>
 43 		<li>environments - configurations varying by environment</li>
 44 		<li>console - stuff related to the development console</li>
 45 		<li>boot - configuration related to the application boot process</li>
 46 	</ul>
 47 	
 48 	<h2>Classes</h2>
 49 	
 50 	<ul>
 51 		<li>AIM - manages AJAX file uploads</li>
 52 		<li>Application - root of application instances</li>
 53 		<li>Attr - root of most rio classes (Application, Component, Model, Page)</li>
 54 		<li>Binding - represents a bindable attribute</li>
 55 		<li>Tag - a collection of methods for building HTML tags</li>
 56 		<li>Utils - a collection of random helper methods</li>
 57 	</ul>
 58 	
 59 	<h2>Methods</h2>
 60 	<ul>
 61 		<li>log - adds a log message to the rio console</li>
 62 	</ul>
 63 	
 64 	<h2>Fields</h2>
 65 	<ul>
 66 		<li>app - the currently running application instance</li>
 67 	</ul>
 68 
 69 	@author Jason Tillery
 70 	@copyright 2008-2009 Thinklink LLC
 71 */
 72 var w = window;
 73 (function() {
 74 	if (!window.console) { window.console = { log: Prototype.emptyFunction }; }
 75 	
 76 	var initialWindowKeys = Object.keys(window);
 77 	
 78 	var bootOptions = window.bootOptions || {};
 79 
 80 	Object.extend(rio, {
 81 		url: function(url) {
 82 			return url + "?" + rio.cacheKey;
 83 		},
 84 		components: {},
 85 		models: {},
 86 		apps: {},
 87 		pages: {},
 88 		console: {},
 89 		log: Prototype.emptyFunction,
 90 		warn: Prototype.emptyFunction,
 91 		error: Prototype.emptyFunction,
 92 		boot: {
 93 			errors: [],
 94 			isMac: navigator.appVersion.toLowerCase().indexOf("mac") != -1,
 95 			root: "/javascripts/",
 96 			appRoot: bootOptions.appRoot || "",
 97 			rioPath: bootOptions.rioPath || "lib/",
 98 			prototypePath: bootOptions.prototypePath || "prototype/",
 99 			prototypePollution: [
100 				"$", "$$", "$A", "$F", "$H", "$R", "$break", "$continue", "$w", "_eventID", "Abstract", "Ajax", "Autocompleter", "Builder", "Class", "Draggable", "Draggables", "Droppables", "Effect", "Element", "Enumerable", "Field", "Form", "Hash", "Insertion", "ObjectRange", "PeriodicalExecuter", "Position", "Prototype", "Selector", "Sortable", "SortableObserver", "Template", "Toggle", "Try"
101 			],
102 			googleAnalyticsPollution: ["gaGlobal", "gaJsHost", "_gat", "pageTracker"],
103 			noConsole: bootOptions.noConsole,
104 			initialWindowKeys: initialWindowKeys,
105 			prototypeScripts: [],
106 			rioScripts: [],
107 			rioScriptsDigest: {},
108 			appScriptsDigest: {},
109 			prototypeScriptsDigest: {},
110 			loadedFiles: [],
111 			loadedStylesheets: [],
112 			loadedTemplates: [],
113 			loadFunctions: {},
114 			
115 			appScripts: function() {
116 				return rio.boot.loadedFiles.reject(function(f) {
117 					return rio.boot.prototypeScripts.include(f) || rio.boot.rioScripts.include(f);
118 				});
119 			},
120 			
121 			pollution: function() {
122 				return Object.keys(window).reject(function(key) {
123 					return rio.boot.initialWindowKeys.include(key) || 
124 						rio.boot.prototypePollution.include(key) || 
125 						rio.boot.googleAnalyticsPollution.include(key);
126 				}.bind(this));
127 			},
128 			
129 			failBoot: function() {
130 				if (rio.environment.bootFailedUrl) {
131 					document.location.href = rio.environment.bootFailedUrl;					
132 				} else {
133 					rio.boot.printErrors();
134 				}
135 			},
136 			
137 			printErrors: function() {
138 				$$("body")[0].update();
139 
140 				var msg = "<h1 style='font-size: 24px; color: #670800;'>Boot failed</h1>";
141 				msg += "<style>.errorLine{font-size:16px; padding:0px 2px; background-color:yellow}</style>";
142 
143 				rio.boot.errors.each(function(e) {
144 					if (e.e) {
145 						msg += "<br /><br />";
146 						msg += "<p style='font-weight: 700'>" + e.msg + "<br /><br />" + e.e + "</p>";
147 						msg += "<br />";
148 					} else if (e.lint) {
149 						e.lint.each(function(err) {
150 							msg += err.toHtml() + "<br />";
151 						});
152 					}
153 				});
154 
155 				$$("body")[0].insert("<div style='padding: 20px'>" + msg + "</div>");
156 			},
157 			
158 			abort: function() {
159 				rio.boot.abortBoot = true;
160 			}
161 		}
162 	});
163 
164 	$$("script").each(function(script) {
165 		var src = script.src;
166 		if(src.match(/boot\.js/) && src.indexOf('?') != -1) {
167 			var options = src.split('?')[1].split(',');
168 			if (options.length >= 1) { rio.boot.appName = options[0]; }
169 			if (options.length >= 2) { rio.boot.environment = options[1]; }
170 			if (options.length >= 3) { rio.boot.bootCompressed = (options[2] == "compressed"); }
171 		}
172 	});
173 	
174 	Object.extend(rio.environment, rio.environments[rio.boot.environment]);
175 	Object.extend(rio.boot, rio.environment.boot);
176 
177 	if (bootOptions.noConsole === undefined) {
178 		rio.boot.noConsole = (rio.environment.console == undefined) ? false : !rio.environment.console;
179 	}
180 	
181 	rio.require = function(fileName, options) {
182 		options = Object.extend({
183 			force: false,
184 			track: true
185 		}, options || {});
186 
187 		if (!rio.boot.loadedFiles.include(fileName)) {
188 			if (rio.boot.bootCompressed && options.force) {
189 				if (options.track) { rio.boot.loadedFiles.push(fileName); }
190 				document.write('<script type="text/javascript" src="' + (options.noPrefix ? "" : rio.assetPrefix) + rio.url(rio.boot.root + fileName + '.js') + '"></script>');
191 			} else if (!rio.boot.bootCompressed) {
192 				if (rio.boot.loadFunctions[fileName]) {
193 					rio.boot.loadFunctions[fileName]();
194 				} else {
195 					rio.require.ajax(fileName);
196 				}
197 				if (options.track) { rio.boot.loadedFiles.push(fileName); }
198 			}
199 		}
200 	};
201 	
202 	rio.require.ajax = function(fileName) {
203 		var path = rio.boot.root + fileName + ".js";
204 		new Ajax.Request(rio.url(path), {
205 			asynchronous: false,
206 			method: "get",
207 			evalJSON: false,
208 			evalJS: false,
209 			onSuccess: function(response) {
210 				try {
211 					w.eval(response.responseText);
212 				} catch(e) {
213 					rio.error(e, "Failed parsing file: " + path);
214 
215 					if (!rio.app) {
216 						if (fileName != "lib/rio_lint") {
217 							rio.require("lib/rio_lint", { track: false });
218 						}
219 						
220 						var lintIt = function(fileName) {
221 							rio.RioLint.checkFileSyntax(fileName, {
222 								onComplete: function(errors) {
223 									rio.boot.errors.push({ lint: errors });
224 								}
225 							});
226 						};
227 						if (fileName == "lib/rio_concat") {
228 							new Ajax.Request(rio.url("/javascripts/lib/rio.build"), {
229 								asynchronous: false,
230 								method: "get",
231 								evalJSON: false,
232 								evalJS: false,
233 								onSuccess: function(response) {
234 									var files = response.responseText.split("\n");
235 									files.without("lib/swfobject").each(function(f) {
236 										lintIt(f);
237 									});
238 								}
239 							});
240 						} else if (fileName == "apps/" + rio.boot.appName + "_concat") {
241 						} else {
242 							rio.boot.errors.push({ e: e, msg: "Failed parsing file: " + path });
243 							lintIt(fileName);
244 						}
245 						
246 					}
247 					throw(e);
248 				}
249 			},
250 			onFailure: function() {
251 				rio.log("Failed loading file: " + path);
252 			}
253 		});
254 	};
255 
256 	if (rio.boot.bootCompressed) {
257 		// rio.require(rio.boot.appRoot + "prototype/compressed/prototype", { force: true });
258 		rio.require(rio.boot.rioPath + "compressed/rio", { force: true });
259 		rio.require(rio.boot.appRoot + "apps/compressed/" + rio.boot.appName, { force: true });
260 		if (rio.environment.developmentTools) {
261 			rio.require(rio.boot.rioPath + "rio_development_concat", { force: true });
262 		}
263 	} else {
264 		try {
265 			rio.require(rio.boot.appRoot + "prototype/prototype_concat", { track: false });
266 			rio.require(rio.boot.rioPath + "rio_concat", { track: false });
267 			rio.require(rio.boot.appRoot + "apps/" + rio.boot.appName + "_concat", { track: false });
268 			rio.require(rio.boot.appRoot + "apps/" + rio.boot.appName);
269 		} catch(e) {
270 			// Let the errors print on load
271 		}
272 	}
273 	if (rio.environment.autoConcatCss) {
274 		if (rio.boot.bootCompressed) {
275 			document.write('<script type="text/javascript">' + 'rio.Application.injectCss();' + '</script>')
276 		} else {
277 			rio.Application.injectCss();
278 		}
279 	}
280 	
281 	if (rio.environment.supportSelenium) {
282 		rio.require(rio.boot.rioPath + "event.simulate", { force: true, noPrefix: true });
283 		rio.require(rio.boot.rioPath + "selenium_extensions", { force: true, noPrefix: true });
284 	}
285 
286 	document.observe('dom:loaded', function() {
287 		var app = rio.apps[rio.boot.appName.camelize()];
288 		var pushOverride = app.environment().push == undefined ? true : app.environment().push;
289 		if ((rio.environment.push && pushOverride) && !rio.push) {
290 			try {
291 				rio.Push.boot();
292 			} catch(e) {
293 				rio.boot.errors.push({ e: e, msg: "Failed booting push client" });
294 			}
295 		}
296 
297 		if (rio.preloadTemplates) {
298 			rio.JsTemplate.preload("apps/" + (rio.boot.bootCompressed ? "compressed/" + rio.boot.appName : rio.boot.appName + "_concat"));
299 		}
300 
301 		if (rio.environment.failOnBootError && rio.boot.errors.length > 0) {
302 			rio.boot.failBoot();
303 			return;
304 		}
305 		try {
306 			window.initialOptions = window.initialOptions || {};
307 			rio.app = new app(initialOptions);
308 			if (rio.boot.abortBoot) { return; }
309 			rio.app.launch();
310 		} catch(e) {
311 			rio.boot.errors.push({ e: e, msg: "Failed inititializing or launching application" });
312 			rio.boot.failBoot();
313 		}
314 	}.bind(this));
315 })();
316