blob: a0e1af123e00cc27698c8011f3525362ed97198c [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of app;
class LocationManager {
final ObservatoryApplication _app;
/// [internalArguments] are parameters specified after a '---' in the
/// application URL.
final Map<String, String> internalArguments = new Map<String, String>();
Uri _uri;
/// [uri] is the application uri. Application uris consist of a path and
/// the queryParameters map.
Uri get uri => _uri;
LocationManager(this._app) {
window.onPopState.listen(_onBrowserNavigation);
// Determine initial application path.
var applicationPath = '${window.location.hash}';
if ((window.location.hash == '') || (window.location.hash == '#')) {
// Observatory has loaded but no application path has been specified,
// use the default.
// By default we navigate to the VM page.
applicationPath = Uris.vm();
}
// Update current application path.
window.history
.replaceState(applicationPath, document.title, applicationPath);
_updateApplicationLocation(applicationPath);
}
bool getBoolParameter(String name, bool defaultValue) {
var value = uri.queryParameters[name];
if ("true" == value) return true;
if ("false" == value) return false;
return defaultValue;
}
/// Called whenever the browser changes the location bar (e.g. forward or
/// back button press).
void _onBrowserNavigation(PopStateEvent event) {
_updateApplicationLocation(window.location.hash);
_visit();
}
/// Given an application url, generate an href link.
String makeLink(String url) => '#$url';
/// Update the application location. After this function returns,
/// [uri] and [debugArguments] will be updated.
_updateApplicationLocation(String url) {
if (url == Uris.vmConnect()) {
// When we go to the vm-connect page, drop all notifications.
_app.notifications.deleteAll();
}
// Chop off leading '#'.
if (url.startsWith('#')) {
url = url.substring(1);
}
// Fall through handles '#/'
// Chop off leading '/'.
if (url.startsWith('/')) {
url = url.substring(1);
}
// Parse out debug arguments.
if (url.contains('---')) {
var chunks = url.split('---');
url = chunks[0];
if ((chunks.length > 1) && (chunks[1] != '')) {
internalArguments.clear();
try {
internalArguments.addAll(Uri.splitQueryString(chunks[1]));
} catch (e) {
Logger.root.warning('Could not parse debug arguments ${e}');
}
}
}
_uri = Uri.parse(url);
}
/// Add [url] to the browser history.
_addToBrowserHistory(String url) {
window.history.pushState(url, document.title, url);
}
/// Notify the current page that something has changed.
_visit() {
Chain.capture(() => _app._visit(_uri, internalArguments), onError: (e, st) {
if (e is IsolateNotFound) {
var newPath = ((_app.vm == null || _app.vm.isDisconnected)
? '/vm-connect'
: '/isolate-reconnect');
var parameters = <String, dynamic>{};
parameters.addAll(_uri.queryParameters);
parameters['originalUri'] = _uri.toString();
parameters['isolateId'] = parameters['isolateId'];
var generatedUri = new Uri(path: newPath, queryParameters: parameters);
go(makeLink(generatedUri.toString()), true);
return;
}
// Surface any uncaught exceptions.
_app.handleException(e, st);
});
}
/// Navigate to [url].
void go(String url, [bool addToBrowserHistory = true]) {
if (addToBrowserHistory) {
_addToBrowserHistory(url);
}
_updateApplicationLocation(url);
_visit();
}
/// Starting with the current uri path and queryParameters, update
/// queryParameters present in [updateParameters], then generate a new uri
/// and navigate to that.
goReplacingParameters(Map updatedParameters,
[bool addToBrowserHistory = true]) {
go(makeLinkReplacingParameters(updatedParameters), addToBrowserHistory);
}
makeLinkReplacingParameters(Map updatedParameters) {
var parameters = new Map.from(_uri.queryParameters);
updatedParameters.forEach((k, v) {
parameters[k] = v;
});
// Ensure path starts with a slash.
var path = uri.path.startsWith('/') ? uri.path : '/${uri.path}';
var generatedUri = new Uri(path: path, queryParameters: parameters);
return makeLink(generatedUri.toString());
}
goForwardingParameters(String newPath, [bool addToBrowserHistory = true]) {
go(makeLinkForwardingParameters(newPath), addToBrowserHistory);
}
makeLinkForwardingParameters(String newPath) {
var parameters = _uri.queryParameters;
var generatedUri = new Uri(path: newPath, queryParameters: parameters);
return makeLink(generatedUri.toString());
}
/// Utility event handler when clicking on application url link.
void onGoto(MouseEvent event) {
if ((event.button > 0) ||
event.metaKey ||
event.ctrlKey ||
event.shiftKey ||
event.altKey) {
// Mouse event is not a left-click OR
// mouse event is a left-click with a modifier key:
// let browser handle.
return;
}
event.preventDefault();
// 'currentTarget' is the dom element that would process the event.
// If we use 'target' we might get an <em> element or somesuch.
Element target = event.currentTarget;
go(target.attributes['href']);
}
}