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 /// Utility class to decode and encode the fragment (starts with '#') portion |
8 final _initialPath = '/vm'; | 8 /// of a url, including any query parameters. |
9 class FragmentUri { | |
turnidge
2015/04/07 21:24:31
Do we need to introduce this class? What if we ju
Cutch
2015/04/14 21:45:15
I've redone this part of the CL.
| |
10 String _path; | |
11 String get path => _path; | |
12 final Map<String, String> parameters = new Map<String, String>(); | |
13 | |
14 FragmentUri(String url) { | |
15 // Chop off leading '#'. | |
16 if (url.startsWith('#')) { | |
17 url = url.substring(1); | |
18 } | |
19 var queryStringIndex = url.indexOf('?'); | |
20 if (queryStringIndex == -1) { | |
21 _path = url; | |
22 } else { | |
23 _path = url.substring(0, queryStringIndex); | |
24 parameters.addAll( | |
25 Uri.splitQueryString(url.substring(queryStringIndex + 1))); | |
26 } | |
27 } | |
28 | |
29 FragmentUri.from(FragmentUri other) { | |
30 _path = other._path; | |
31 parameters.addAll(other.parameters); | |
32 } | |
33 | |
34 String toString() { | |
35 if (parameters.isEmpty) { | |
36 return '#$_path'; | |
37 } | |
38 var encodedParameters = new Uri(queryParameters: parameters).query; | |
39 return '#${_path}?${encodedParameters}'; | |
40 } | |
41 } | |
42 | |
43 class LocationManager extends Observable { | |
44 final _defaultPath = '/vm'; | |
9 ObservatoryApplication _app; | 45 ObservatoryApplication _app; |
10 | 46 FragmentUri _fragment; |
11 String _lastUrl; | 47 FragmentUri get fragment => _fragment; |
48 String _url; | |
12 | 49 |
13 void _init(ObservatoryApplication app) { | 50 void _init(ObservatoryApplication app) { |
14 // Called once. | 51 // Called once. |
15 assert(_app == null); | 52 assert(_app == null); |
16 _app = app; | 53 _app = app; |
17 // Register for history events. | 54 // Register for history events. |
18 window.onPopState.listen(_onLocationChange); | 55 window.onPopState.listen(_onLocationChange); |
19 _onStartup(); | 56 |
57 var applicationPath = '${window.location.hash}'; | |
58 if ((window.location.hash == '') || (window.location.hash == '#')) { | |
59 // Observatory has loaded but no application path has been specified, | |
60 // use the default. | |
61 applicationPath = '#${_defaultPath}'; | |
62 } | |
63 // Update current application path. | |
64 window.history.replaceState(applicationPath, | |
65 document.title, | |
66 applicationPath); | |
67 _updateCurrent(applicationPath); | |
68 _go(applicationPath); | |
20 } | 69 } |
21 | 70 |
22 void _onStartup(); | 71 void _updateCurrent(String url) { |
23 void _onLocationChange(PopStateEvent event); | 72 _url = url; |
73 _fragment = new FragmentUri(url); | |
74 } | |
24 | 75 |
25 void _pushUrl(String url) { | 76 void _pushUrl(String url) { |
26 if (_lastUrl != url) { | 77 if (_url != url) { |
27 Logger.root.info('Navigated to ${url}'); | 78 Logger.root.info('Navigated to ${url}'); |
28 window.history.pushState(url, document.title, url); | 79 window.history.pushState(url, document.title, url); |
29 _lastUrl = url; | 80 _updateCurrent(url); |
30 } | 81 } |
31 } | 82 } |
32 | 83 |
33 /// Go to a specific url. | |
34 void go(String 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 void _go(String url) { | 84 void _go(String url) { |
47 // Chop off leading '#'. | 85 // Chop off leading '#'. |
48 if (url.startsWith('#')) { | 86 if (url.startsWith('#')) { |
49 url = url.substring(1); | 87 url = url.substring(1); |
50 } | 88 } |
51 // Fall through handles '#/' | 89 // Fall through handles '#/' |
52 // Chop off leading '/'. | 90 // Chop off leading '/'. |
53 if (url.startsWith('/')) { | 91 if (url.startsWith('/')) { |
54 url = url.substring(1); | 92 url = url.substring(1); |
55 } | 93 } |
56 var args; | 94 var args; |
57 // Parse out arguments. | 95 // Parse out arguments. |
58 if (url.contains('---')) { | 96 if (url.contains('---')) { |
59 var chunks = url.split('---'); | 97 var chunks = url.split('---'); |
60 url = chunks[0]; | 98 url = chunks[0]; |
61 if ((chunks.length > 1) && (chunks[1] != '')) { | 99 if ((chunks.length > 1) && (chunks[1] != '')) { |
62 args = chunks[1]; | 100 args = chunks[1]; |
63 } | 101 } |
64 } | 102 } |
65 _app._visit(url, args); | 103 _app._visit(url, args); |
66 } | 104 } |
67 | 105 |
68 /// Go back. | 106 /// Go to a specific url. |
69 void back() { | 107 void go(String url) { |
70 window.history.go(-1); | 108 if ((url != makeLink('/vm-connect/')) && _app.vm == null) { |
109 if (!window.confirm('Connection with VM has been lost. ' | |
110 'Proceeding will lose current page.')) { | |
111 return; | |
112 } | |
113 url = makeLink('/vm-connect/'); | |
114 } | |
115 _pushUrl(url); | |
116 _go(url); | |
71 } | 117 } |
72 | 118 |
73 /// Go forward. | 119 /// Starting with the current url, update all parameters present in |
74 void forward() { | 120 /// [updatedParameters], then generate a new url and navigate to that. |
75 window.history.go(1); | 121 goParameter(Map updatedParameters) { |
122 var fragment = new FragmentUri.from(_fragment); | |
123 updatedParameters.forEach((k, v) { | |
124 fragment.parameters[k] = v; | |
125 }); | |
126 go(fragment.toString()); | |
76 } | 127 } |
77 | 128 |
78 /// Handle clicking on an application url link. | 129 /// Handle clicking on an application url link. |
79 void onGoto(MouseEvent event) { | 130 void onGoto(MouseEvent event) { |
80 var target = event.target; | 131 var target = event.target; |
81 var href = target.attributes['href']; | 132 var href = target.attributes['href']; |
82 if (event.button > 0 || event.metaKey || event.ctrlKey || | 133 if (event.button > 0 || event.metaKey || event.ctrlKey || |
83 event.shiftKey || event.altKey) { | 134 event.shiftKey || event.altKey) { |
84 // Not a left-click or a left-click with a modifier key: | 135 // Not a left-click or a left-click with a modifier key: |
85 // Let browser handle. | 136 // Let browser handle. |
86 return; | 137 return; |
87 } | 138 } |
88 go(href); | 139 go(href); |
89 event.preventDefault(); | 140 event.preventDefault(); |
90 } | 141 } |
91 | 142 |
92 /// Given an application url, generate a link. | 143 /// Called whenever the browser changes the location bar (e.g. back button). |
93 String makeLink(String url); | 144 void _onLocationChange(PopStateEvent event) { |
94 } | 145 _updateCurrent(window.location.hash); |
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); | 146 _go(window.location.hash); |
105 } | 147 } |
106 | 148 |
107 void _onLocationChange(PopStateEvent _) { | 149 /// Given an application url, generate a link. |
108 _go(window.location.hash); | 150 String makeLink(String url) => '#$url'; |
109 } | |
110 | |
111 /// Given an application url, generate a link for an anchor tag. | |
112 String makeLink(String url) { | |
113 return '#$url'; | |
114 } | |
115 } | 151 } |
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 |