OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of app; | 5 part of app; |
6 | 6 |
7 abstract class LocationManager extends Observable { | 7 class LocationManager extends Observable { |
8 final _initialPath = '/vm'; | 8 final _defaultPath = '/vm'; |
9 ObservatoryApplication _app; | |
10 | 9 |
11 String _lastUrl; | 10 final ObservatoryApplication _app; |
12 | 11 |
13 void _init(ObservatoryApplication app) { | 12 /// [internalArguments] are parameters specified after a '---' in the |
14 // Called once. | 13 /// application URL. |
15 assert(_app == null); | 14 final Map<String, String> internalArguments = new Map<String, String>(); |
16 _app = app; | 15 |
17 // Register for history events. | 16 Uri _uri; |
18 window.onPopState.listen(_onLocationChange); | 17 /// [uri] is the application uri. Application uris consist of a path and |
19 _onStartup(); | 18 /// the queryParameters map. |
| 19 Uri get uri => _uri; |
| 20 |
| 21 LocationManager(this._app) { |
| 22 window.onPopState.listen(_onBrowserNavigation); |
| 23 // Determine initial application path. |
| 24 var applicationPath = '${window.location.hash}'; |
| 25 if ((window.location.hash == '') || (window.location.hash == '#')) { |
| 26 // Observatory has loaded but no application path has been specified, |
| 27 // use the default. |
| 28 applicationPath = makeLink(_defaultPath); |
| 29 } |
| 30 // Update current application path. |
| 31 window.history.replaceState(applicationPath, |
| 32 document.title, |
| 33 applicationPath); |
| 34 _updateApplicationLocation(applicationPath); |
20 } | 35 } |
21 | 36 |
22 void _onStartup(); | 37 /// Called whenever the browser changes the location bar (e.g. forward or |
23 void _onLocationChange(PopStateEvent event); | 38 /// back button press). |
24 | 39 void _onBrowserNavigation(PopStateEvent event) { |
25 void _pushUrl(String url) { | 40 _updateApplicationLocation(window.location.hash); |
26 if (_lastUrl != url) { | 41 _visit(); |
27 Logger.root.info('Navigated to ${url}'); | |
28 window.history.pushState(url, document.title, url); | |
29 _lastUrl = url; | |
30 } | |
31 } | 42 } |
32 | 43 |
33 /// Go to a specific url. | 44 /// Given an application url, generate an href link. |
34 void go(String url) { | 45 String makeLink(String url) => '#$url'; |
35 if ((url != makeLink('/vm-connect/')) && _app.vm == null) { | |
36 if (!window.confirm('Connection with VM has been lost. ' | |
37 'Proceeding will lose current page.')) { | |
38 return; | |
39 } | |
40 url = makeLink('/vm-connect/'); | |
41 } | |
42 _pushUrl(url); | |
43 _go(url); | |
44 } | |
45 | 46 |
46 void _go(String url) { | 47 /// Update the application location. After this function returns, |
| 48 /// [uri] and [debugArguments] will be updated. |
| 49 _updateApplicationLocation(String url) { |
47 // Chop off leading '#'. | 50 // Chop off leading '#'. |
48 if (url.startsWith('#')) { | 51 if (url.startsWith('#')) { |
49 url = url.substring(1); | 52 url = url.substring(1); |
50 } | 53 } |
51 // Fall through handles '#/' | 54 // Fall through handles '#/' |
52 // Chop off leading '/'. | 55 // Chop off leading '/'. |
53 if (url.startsWith('/')) { | 56 if (url.startsWith('/')) { |
54 url = url.substring(1); | 57 url = url.substring(1); |
55 } | 58 } |
56 var args; | 59 // Parse out debug arguments. |
57 // Parse out arguments. | |
58 if (url.contains('---')) { | 60 if (url.contains('---')) { |
59 var chunks = url.split('---'); | 61 var chunks = url.split('---'); |
60 url = chunks[0]; | 62 url = chunks[0]; |
61 if ((chunks.length > 1) && (chunks[1] != '')) { | 63 if ((chunks.length > 1) && (chunks[1] != '')) { |
62 args = chunks[1]; | 64 internalArguments.clear(); |
| 65 try { |
| 66 internalArguments.addAll(Uri.splitQueryString(chunks[1])); |
| 67 } catch (e) { |
| 68 Logger.root.warning('Could not parse debug arguments ${e}'); |
| 69 } |
63 } | 70 } |
64 } | 71 } |
65 _app._visit(url, args); | 72 _uri = Uri.parse(url); |
66 } | 73 } |
67 | 74 |
68 /// Go back. | 75 /// Add [url] to the browser history. |
69 void back() { | 76 _addToBrowserHistory(String url) { |
70 window.history.go(-1); | 77 window.history.pushState(url, document.title, url); |
71 } | 78 } |
72 | 79 |
73 /// Go forward. | 80 /// Notify the current page that something has changed. |
74 void forward() { | 81 _visit() { |
75 window.history.go(1); | 82 _app._visit(_uri, internalArguments); |
76 } | 83 } |
77 | 84 |
78 /// Handle clicking on an application url link. | 85 /// Navigate to [url]. |
| 86 void go(String url, [bool addToBrowserHistory = true]) { |
| 87 if ((url != makeLink('/vm-connect/')) && _app.vm == null) { |
| 88 if (!window.confirm('Connection with VM has been lost. ' |
| 89 'Proceeding will lose current page.')) { |
| 90 return; |
| 91 } |
| 92 url = makeLink('/vm-connect/'); |
| 93 } |
| 94 if (addToBrowserHistory) { |
| 95 _addToBrowserHistory(url); |
| 96 } |
| 97 _updateApplicationLocation(url); |
| 98 _visit(); |
| 99 } |
| 100 |
| 101 /// Starting with the current uri path and queryParameters, update |
| 102 /// queryParameters present in [updateParameters], then generate a new uri |
| 103 /// and navigate to that. |
| 104 goParameter(Map updatedParameters, [bool addToBrowserHistory = true]) { |
| 105 var parameters = new Map.from(_uri.queryParameters); |
| 106 updatedParameters.forEach((k, v) { |
| 107 parameters[k] = v; |
| 108 }); |
| 109 // Ensure path starts with a slash. |
| 110 var path = uri.path.startsWith('/') ? uri.path : '/${uri.path}'; |
| 111 var generatedUri = new Uri(path: path, queryParameters: parameters); |
| 112 go(makeLink(generatedUri.toString()), addToBrowserHistory); |
| 113 } |
| 114 |
| 115 /// Utility event handler when clicking on application url link. |
79 void onGoto(MouseEvent event) { | 116 void onGoto(MouseEvent event) { |
80 var target = event.target; | 117 if ((event.button > 0) || |
81 var href = target.attributes['href']; | 118 event.metaKey || |
82 if (event.button > 0 || event.metaKey || event.ctrlKey || | 119 event.ctrlKey || |
83 event.shiftKey || event.altKey) { | 120 event.shiftKey || |
84 // Not a left-click or a left-click with a modifier key: | 121 event.altKey) { |
85 // Let browser handle. | 122 // Mouse event is not a left-click OR |
| 123 // mouse event is a left-click with a modifier key: |
| 124 // let browser handle. |
86 return; | 125 return; |
87 } | 126 } |
88 go(href); | |
89 event.preventDefault(); | 127 event.preventDefault(); |
90 } | 128 var target = event.target; |
91 | 129 go(target.attributes['href']); |
92 /// Given an application url, generate a link. | |
93 String makeLink(String url); | |
94 } | |
95 | |
96 /// Uses location.hash to encode application urls. | |
97 class HashLocationManager extends LocationManager { | |
98 void _onStartup() { | |
99 String initialPath = '${window.location.hash}'; | |
100 if ((window.location.hash == '') || (window.location.hash == '#')) { | |
101 initialPath = '#${_initialPath}'; | |
102 } | |
103 window.history.pushState(initialPath, document.title, initialPath); | |
104 _go(window.location.hash); | |
105 } | |
106 | |
107 void _onLocationChange(PopStateEvent _) { | |
108 _go(window.location.hash); | |
109 } | |
110 | |
111 /// Given an application url, generate a link for an anchor tag. | |
112 String makeLink(String url) { | |
113 return '#$url'; | |
114 } | 130 } |
115 } | 131 } |
116 | |
117 /// Uses location.pathname to encode application urls. Requires server side | |
118 /// rewriting to support copy and paste linking. pub serve makes this hard. | |
119 /// STATUS: Work in progress. | |
120 class LinkLocationManager extends LocationManager { | |
121 void _onStartup() { | |
122 Logger.root.warning('Using untested LinkLocationManager'); | |
123 String initialPath = window.location.pathname; | |
124 if ((window.location.pathname == '/index.html') || | |
125 (window.location.pathname == '/')) { | |
126 initialPath = '/vm'; | |
127 } | |
128 window.history.replaceState(initialPath, document.title, initialPath); | |
129 _go(window.location.pathname); | |
130 } | |
131 | |
132 void _onLocationChange(PopStateEvent _) { | |
133 _go(window.location.pathname); | |
134 } | |
135 | |
136 /// Given an application url, generate a link for an anchor tag. | |
137 String makeLink(String url) => url; | |
138 } | |
OLD | NEW |