source: Dev/branches/rest-dojo-ui/client/rft/app/Controller.js @ 407

Last change on this file since 407 was 407, checked in by hendrikvanantwerpen, 13 years ago

Added build infrastructure and reorganised code to match it.

Page navigation is now done by the rft/app/Controller class. pages
inherit generally from rft/app/Page, which is a BorderContainer?. The
Page uses normal widget mechanism like templateString, all data-rft-*
are obsolete, use normal data-dojo-* options again in templates.
This is done so the pages of the app can be included in the build.
URLs are linked to pages through registration, which is done in
run.js. The routes are defined in the routes.js file. Page class names
and URLs are now independent.

Reduced includes in index.html to one CSS file and two JS files. Dojo
stylesheets are now included thorugh externals.css.

Dojo 1.8 doesn't require the dotted names in declares anymore. All these
are now removed (redundant with module path and JS filename anyway)
and in templates a module id is used, so iso 'dijit.form.Form' use
'dijit/form/Form' now. This is more consistent with requires in the JS
code and they are picked up by the build system.

Removed any old-style dojo.<function> code and use loaded modules
everywhere.

Lots of whitespace unification.

File size: 4.6 KB
Line 
1define([
2    'dojo/_base/declare',
3    'dojo/hash',
4    'dojo/io-query',
5    'dojo/topic',
6    './Page',
7    'dijit/registry'
8],function(declare,hash,ioQuery,topic,Page,registry){
9
10
11    var Controller = declare(null,{
12        _started: false,
13        _routes: null,
14        _container: null,
15        _previousHash: null,
16        _previousContent: null,
17
18        _paramMatch: /:(\w[\w\d]*)/g,
19        _paramReplace: "([^\\/]+)",
20
21        constructor: function() {
22            this._routes = [];
23        },
24        startup: function() {
25            if ( this._started ) { return; }
26
27            var self = this;
28
29            this._container = registry.byId('content');
30            if ( !this._container || !this._container.addChild ) {
31                throw new Error("Cannot find container widget with id 'content'.");
32            }
33            this._started = true;
34
35            if ( hash() === "" ) {
36                hash("#!/");
37            }
38            this._handlePathChange(hash());
39                        topic.subscribe("/dojo/hashchange", function(){
40                self._handlePathChange.apply(self,arguments);
41            });
42        },
43        register: function(route) {
44            var self = this;
45            var callback;
46            if ( route.callback ) {
47                callback = function(params){
48                    self._setContent(route.callback(params));
49                };
50            } else if ( route.redirect ) {
51                callback = function(params){
52                    self.go(route.redirect);
53                };
54            } else if ( route.constructor ) {
55                callback = function(params){
56                    self._setContent( new route.constructor(params) );
57                };
58            }
59            if ( callback ) {
60                if ( route.path ) {
61                    this._routes.push(this._createRoute(route.path,callback));
62                } else {
63                    this._defaultCallback = callback;
64                }
65            } else {
66                console.warn("Route "+(route.path||"default")+" has no action.");
67            }
68        },
69        _createRoute: function(path,callback) {
70            var match, route = {};
71            route.callback = callback;
72            route.paramNames = [];
73                        while((match = this._paramMatch.exec(path)) !== null){
74                                route.paramNames.push(match[1]);
75                        }
76            path = path.replace(this._paramMatch, this._paramReplace);
77            route.regexp = new RegExp('^!'+path+'(!.*)?$');
78            return route;
79        },
80        _handlePathChange: function(newHash) {
81            if ( this._previousHash === newHash ) { return; }
82            this._previousHash = newHash;
83
84            for (var i = this._routes.length-1; i >= 0; i--) {
85                var result;
86                var route = this._routes[i];
87
88                if ((result = route.regexp.exec(newHash)) !== null) {
89                    var numParams = route.paramNames.length;
90
91                    var params = {};
92                    for (var j = 0; j < numParams; j++) {
93                        params[route.paramNames[j]] = result[j+1];
94                    }
95
96                    if ( result.length > numParams+1 ) {
97                        params.options = ioQuery.queryToObject(result[numParams]);
98                    }
99
100                    try {
101                        route.callback(params);
102                    } catch(err) {
103                        console.warn("Page change failed.",err);
104                    }
105                    return;
106                }
107            }
108
109            try {
110                this._defaultCallback();
111            } catch(err) {
112                console.warn("Default page failed.",err);
113            }
114        },
115        go: function(path,args) {
116            if ( !this._started ) { return; }
117            var newHash = this._pathToHash(path,args);
118            this._handlePathChange(newHash);
119            hash(newHash);
120        },
121        _pathToHash: function(path,args) {
122            var hash = '!'+path;
123            if ( args ) {
124                hash += '!'+ioQuery.objectToQuery(args);
125            }
126            return hash;
127        },
128        _setContent: function(widget) {
129            if ( this._previousContent ) {
130                this._previousContent.destroyRecursive();
131                this._previousContent = null;
132            }
133            widget.region = 'center';
134            this._container.addChild(widget);
135            this._previousContent = widget;
136        },
137        _defaultCallback: function() {
138            this._setContent(new Page({
139                templateString: "<div>Requested page not found. Go <a href=\"#!/\">home</a>.</div>"
140            }));
141        }
142    });
143
144    return new Controller();
145});
Note: See TracBrowser for help on using the repository browser.