source: Dev/trunk/src/client/qed-client/app/Router.js @ 490

Last change on this file since 490 was 490, checked in by hendrikvanantwerpen, 11 years ago
  • Mark content as dirty to prevent moving away from unsaved data.
  • Better change propagation from lists and our own widgets.
  • Generate notifications for errors and show correct message.
  • Moved all path/url generation to the class stores, not everywhere we use it.
  • Give user always a choice between Save and Save & Close.
  • Better refresh behaviour on form changes and saves.
  • Don't generate duplicate code error when existing object is the one you're storing.
File size: 4.2 KB
Line 
1define([
2    "./Content",
3    "./Page",
4    "./Path",
5    "dojo/_base/declare",
6    "dojo/_base/event",
7    "dojo/_base/lang",
8    "dojo/_base/window",
9    "dojo/hash",
10    "dojo/on",
11    "dojo/topic"
12], function(Content, Page, Path, declare, event, lang, window, hash, on, topic) {
13
14    var Router = declare(null,{
15        _started: false,
16        _routes: null,
17        _previousHash: null,
18        _beforePreviousHash: null,
19
20        constructor: function() {
21            this._routes = [];
22        },
23        startup: function() {
24            if ( this._started ) { return; }
25            Content.startup();
26            this._started = true;
27            if ( hash() === "" ) {
28                hash(Path.getDefault());
29            }
30            this._handleHashChange(hash());
31            window.onbeforeunload = function() {
32                return Content.isDirty() && "Unsaved changes, leave anyway?";
33            };
34                        topic.subscribe("/dojo/hashchange",
35                            lang.hitch(this,'_handleHashChange'));
36        },
37        register: function(route) {
38            if ( this._started ) {
39                console.warn('Registering routes after startup() is called is discouraged.');
40            }
41            var callback = this._normalizeCallback(route);
42            if ( callback ) {
43                if ( route.path ) {
44                    route.callback = callback;
45                    route.path = new Path(route.path);
46                    this._routes.push(route);
47                } else {
48                    this._defaultCallback = callback;
49                }
50            } else {
51                console.warn("Route "+(route.path||"default")+" has no action.");
52            }
53        },
54        _normalizeCallback: function(route) {
55            var self = this;
56            var callback = null;
57            if ( route.callback ) {
58                callback = function(params){
59                    Content.set(route.callback(params));
60                };
61            } else if ( route.redirect ) {
62                callback = function(params){
63                    self.go(route.redirect);
64                };
65            } else if ( route.constructor ) {
66                callback = function(params){
67                    Content.set( new route.constructor(params) );
68                };
69            }
70            return callback;
71        },
72        _handleHashChange: function(newHash) {
73            if ( this._previousHash === newHash ) {
74                return false;
75            }
76            if ( Content.isDirty() ) {
77                if ( !confirm("Unsaved changes, leave anyway?") ) {
78                    var probablyBack = this._beforePreviousHash === newHash;
79                    // if we think we go backwards, we re-add the history
80                    // entry, otherwise we reset the current one,
81                    // resulting in minor annoyance of double back
82                    // behaviour.
83                    hash(this._previousHash,!probablyBack);
84                    return false;
85                } else {
86                    Content.markClean();
87                }
88            }
89            this._beforePreviousHash = this._previousHash;
90            this._previousHash = newHash;
91            for (var i = this._routes.length-1; i >= 0; i--) {
92                var route = this._routes[i];
93                var params = null;
94                if ((params = route.path.match(newHash)) !== null) {
95                    try {
96                        route.callback(params);
97                    } catch(err) {
98                        console.error("Page change failed with",err,err.stack,err.toString());
99                    }
100                    return true;
101                }
102            }
103            try {
104                this._defaultCallback();
105            } catch(err) {
106                console.error("Default page failed.",err);
107            }
108            return true;
109        },
110        go: function(path,args) {
111            if ( !this._started ) { return; }
112            var newHash = Path.format(path,args);
113            hash(newHash);
114        },
115        _defaultCallback: function() {
116            Content.set(new Page({
117                templateString: "<div>Requested page not found. Go <a href=\"#"+Path.getDefault()+"\">home</a>.</div>"
118            }));
119        }
120    });
121
122    return new Router();
123});
Note: See TracBrowser for help on using the repository browser.