LEFT | RIGHT |
1 'use strict'; | 1 'use strict'; |
2 | 2 |
3 var spinner; | 3 var spinner; |
4 | 4 |
5 /** | 5 /** |
6 * Provide the main App class, based on the YUI App framework. Also provide | 6 * Provide the main App class, based on the YUI App framework. Also provide |
7 * the routing definitions, which map the request paths to the top-level | 7 * the routing definitions, which map the request paths to the top-level |
8 * views defined by the App class. | 8 * views defined by the App class. |
9 * | 9 * |
10 * @module app | 10 * @module app |
11 */ | 11 */ |
12 | 12 |
13 // Create a global for debug console access to YUI context. | 13 // Create a global for debug console access to YUI context. |
14 var yui; | 14 var yui; |
15 | 15 |
16 YUI.add('juju-gui', function(Y) { | 16 YUI.add('juju-gui', function(Y) { |
17 | 17 |
18 // Assign the global for console access. | 18 // Assign the global for console access. |
19 yui = Y; | 19 yui = Y; |
20 | 20 |
21 var juju = Y.namespace('juju'), | 21 var juju = Y.namespace('juju'), |
22 models = Y.namespace('juju.models'), | 22 models = Y.namespace('juju.models'), |
23 views = Y.namespace('juju.views'); | 23 views = Y.namespace('juju.views'); |
24 | 24 |
25 /** | 25 /** |
26 * The main app class. | 26 * The main app class. |
27 * | 27 * |
28 * @class App | 28 * @class App |
29 */ | 29 */ |
30 var JujuGUI = Y.Base.create('juju-gui', Y.App, [], { | 30 var JujuGUI = Y.Base.create('juju-gui', Y.App, [Y.juju.SubAppRegistration], { |
31 | 31 |
32 /* | 32 /* |
33 * Views | 33 * Views |
34 * | 34 * |
35 * The views encapsulate the functionality blocks that output | 35 * The views encapsulate the functionality blocks that output |
36 * the GUI pages. The "parent" attribute defines the hierarchy. | 36 * the GUI pages. The "parent" attribute defines the hierarchy. |
37 * | 37 * |
38 * FIXME: not included in the generated doc output. | 38 * FIXME: not included in the generated doc output. |
39 * | 39 * |
40 * @attribute views | 40 * @attribute views |
(...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 return self; | 438 return self; |
439 } | 439 } |
440 | 440 |
441 req = self._getRequest(fragment, url, src); | 441 req = self._getRequest(fragment, url, src); |
442 res = self._getResponse(req); | 442 res = self._getResponse(req); |
443 | 443 |
444 // This method is a recursive closure, which mutates a number of | 444 // This method is a recursive closure, which mutates a number of |
445 // variables in the enclosing scope, most notably the callbacks and | 445 // variables in the enclosing scope, most notably the callbacks and |
446 // routes. Read carefully! | 446 // routes. Read carefully! |
447 req.next = function(err) { | 447 req.next = function(err) { |
448 var callback, route; | 448 var subApp, callback, route, callingContext; |
449 | 449 |
450 if (err) { | 450 if (err) { |
451 // Special case "route" to skip to the next route handler | 451 // Special case "route" to skip to the next route handler |
452 // avoiding any additional callbacks for the current route. | 452 // avoiding any additional callbacks for the current route. |
453 if (err === 'route') { | 453 if (err === 'route') { |
454 callbacks = []; | 454 callbacks = []; |
455 req.next(); | 455 req.next(); |
456 } else { | 456 } else { |
457 Y.error(err); | 457 Y.error(err); |
458 } | 458 } |
459 | 459 |
460 } else if ((callback = callbacks.shift())) { | 460 } else if ((callback = callbacks.shift())) { |
| 461 |
461 if (typeof callback === 'string') { | 462 if (typeof callback === 'string') { |
462 callback = self[callback]; | 463 subApp = self.get('subApps')[namespace]; |
| 464 |
| 465 if (subApp && typeof subApp[callback] === 'function') { |
| 466 callback = subApp[callback]; |
| 467 callingContext = subApp; |
| 468 subApp.verifyRendered(); |
| 469 } else if (typeof self[callback] === 'function') { |
| 470 callback = self[callback]; |
| 471 callingContext = self; |
| 472 } else { |
| 473 console.error('Callback function `', callback, |
| 474 '` does not exist under the namespace `', namespace, |
| 475 '` at the path `', path, '`.'); |
| 476 } |
463 } | 477 } |
464 | 478 |
465 // Allow access to the num or remaining callbacks for the route. | 479 // Allow access to the num or remaining callbacks for the route. |
466 req.pendingCallbacks = callbacks.length; | 480 req.pendingCallbacks = callbacks.length; |
467 // Attach the callback id to the request. | 481 // Attach the callback id to the request. |
468 req.callbackId = Y.stamp(callback, true); | 482 req.callbackId = Y.stamp(callback, true); |
469 callback.call(self, req, res, req.next); | 483 callback.call(callingContext, req, res, req.next); |
470 | 484 |
471 } else if ((route = routes.shift())) { | 485 } else if ((route = routes.shift())) { |
472 // Make a copy of this route's `callbacks` and find its matches. | 486 // Make a copy of this route's `callbacks` and find its matches. |
473 callbacks = route.callbacks.concat(); | 487 callbacks = route.callbacks.concat(); |
474 matches = route.regex.exec(fragment); | 488 matches = route.regex.exec(fragment); |
475 | 489 |
476 // Use named keys for parameter names if the route path contains | 490 // Use named keys for parameter names if the route path contains |
477 // named keys. Otherwise, use numerical match indices. | 491 // named keys. Otherwise, use numerical match indices. |
478 if (matches.length === route.keys.length + 1) { | 492 if (matches.length === route.keys.length + 1) { |
479 req.params = Y.Array.hash(route.keys, matches.slice(1)); | 493 req.params = Y.Array.hash(route.keys, matches.slice(1)); |
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1067 // further callbacks in _this_ array (remember | 1081 // further callbacks in _this_ array (remember |
1068 // route.callbacks is an array per route). | 1082 // route.callbacks is an array per route). |
1069 // But it can allow continued processing. | 1083 // But it can allow continued processing. |
1070 next('route'); | 1084 next('route'); |
1071 } | 1085 } |
1072 next(); | 1086 next(); |
1073 seen[callbackId] = true; | 1087 seen[callbackId] = true; |
1074 }, | 1088 }, |
1075 | 1089 |
1076 /** | 1090 /** |
1077 * Wrap the default routing using a whitelist to avoid extra juggling. | 1091 * Override the App route builder. This method adds the ability to |
| 1092 * send multiple callbacks, and the ability to specify arbitrary |
| 1093 * additional attributes in the options argument. |
1078 * | 1094 * |
1079 * @method route | 1095 * @method route |
1080 */ | 1096 */ |
1081 route: function(path, callback, options) { | 1097 route: function(path, callbacks, options) { |
1082 JujuGUI.superclass.route.call(this, path, callback); | 1098 callbacks = Y.Array(callbacks); |
1083 | 1099 var keys = []; |
1084 if (options.model) { | 1100 var routeData = Y.mix({ |
1085 var routes = this._routes; | 1101 callbacks: callbacks, |
1086 var idx = routes.length - 1; | 1102 keys: keys, |
1087 if (routes[idx].path === path) { | 1103 path: path, |
1088 // Combine our options with the default computed route information. | 1104 regex: this._getRegex(path, keys), |
1089 routes[idx] = Y.mix(routes[idx], options); | 1105 |
1090 } else { | 1106 // For back-compat. |
1091 console.error( | 1107 // This may no longer be required but is being left here until |
1092 'Underlying Y.Router not behaving as expected. ' + | 1108 // proper tests are written to guarantee there are no side effects |
1093 'Press the red button.'); | 1109 callback: callbacks[0] |
1094 } | 1110 }, options); |
1095 } | 1111 this._routes.push(routeData); |
| 1112 return this; |
1096 } | 1113 } |
1097 | 1114 |
1098 }, { | 1115 }, { |
1099 ATTRS: { | 1116 ATTRS: { |
1100 html5: true, | 1117 html5: true, |
1101 charm_store: {}, | 1118 charm_store: {}, |
1102 | 1119 |
1103 /* | 1120 /* |
1104 * Routes | 1121 * Routes |
1105 * | 1122 * |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1190 'juju-views', | 1207 'juju-views', |
1191 'juju-view-login', | 1208 'juju-view-login', |
1192 'juju-landscape', | 1209 'juju-landscape', |
1193 'io', | 1210 'io', |
1194 'json-parse', | 1211 'json-parse', |
1195 'app-base', | 1212 'app-base', |
1196 'app-transitions', | 1213 'app-transitions', |
1197 'base', | 1214 'base', |
1198 'node', | 1215 'node', |
1199 'model', | 1216 'model', |
| 1217 'app-subapp-extension', |
1200 'sub-app'] | 1218 'sub-app'] |
1201 }); | 1219 }); |
LEFT | RIGHT |