1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 * Creates a new Navigator for navigating to links inside or outside the PDF.
9 * @param {string} originalUrl The original page URL.
10 * @param {Object} viewport The viewport info of the page.
11 * @param {Object} paramsParser The object for URL parsing.
12 * @param {Function} navigateInCurrentTabCallback The Callback function that
13 * gets called when navigation happens in the current tab.
14 * @param {Function} navigateInNewTabCallback The Callback function that gets
15 * called when navigation happens in the new tab.
17 function Navigator(originalUrl,
20 navigateInCurrentTabCallback,
21 navigateInNewTabCallback) {
22 this.originalUrl_ = originalUrl;
23 this.viewport_ = viewport;
24 this.paramsParser_ = paramsParser;
25 this.navigateInCurrentTabCallback_ = navigateInCurrentTabCallback;
26 this.navigateInNewTabCallback_ = navigateInNewTabCallback;
29 Navigator.prototype = {
32 * Function to navigate to the given URL. This might involve navigating
33 * within the PDF page or opening a new url (in the same tab or a new tab).
34 * @param {string} url The URL to navigate to.
35 * @param {boolean} newTab Whether to perform the navigation in a new tab or
38 navigate: function(url, newTab) {
42 // If |urlFragment| starts with '#', then it's for the same URL with a
43 // different URL fragment.
44 if (url.charAt(0) == '#') {
45 // if '#' is already present in |originalUrl| then remove old fragment
46 // and add new url fragment.
47 var hashIndex = this.originalUrl_.search('#');
49 url = this.originalUrl_.substring(0, hashIndex) + url;
51 url = this.originalUrl_ + url;
54 // If there's no scheme, then take a guess at the scheme.
55 if (url.indexOf('://') == -1 && url.indexOf('mailto:') == -1)
56 url = this.guessUrlWithoutScheme_(url);
58 if (!this.isValidUrl_(url))
62 this.navigateInNewTabCallback_(url);
64 this.paramsParser_.getViewportFromUrlParams(
65 url, this.onViewportReceived_.bind(this));
71 * Called when the viewport position is received.
72 * @param {Object} viewportPosition Dictionary containing the viewport
75 onViewportReceived_: function(viewportPosition) {
76 var pageNumber = viewportPosition.page;
77 if (pageNumber != undefined)
78 this.viewport_.goToPage(pageNumber);
80 this.navigateInCurrentTabCallback_(viewportPosition['url']);
85 * Checks if the URL starts with a scheme and s not just a scheme.
86 * @param {string} The input URL
87 * @return {boolean} Whether the url is valid.
89 isValidUrl_: function(url) {
90 // Make sure |url| starts with a valid scheme.
91 if (url.indexOf('http://') != 0 &&
92 url.indexOf('https://') != 0 &&
93 url.indexOf('ftp://') != 0 &&
94 url.indexOf('file://') != 0 &&
95 url.indexOf('mailto:') != 0) {
99 // Make sure |url| is not only a scheme.
100 if (url == 'http://' ||
113 * Attempt to figure out what a URL is when there is no scheme.
114 * @param {string} The input URL
115 * @return {string} The URL with a scheme or the original URL if it is not
116 * possible to determine the scheme.
118 guessUrlWithoutScheme_: function(url) {
119 // If the original URL is mailto:, that does not make sense to start with,
120 // and neither does adding |url| to it.
121 // If the original URL is not a valid URL, this cannot make a valid URL.
122 // In both cases, just bail out.
123 if (this.originalUrl_.startsWith('mailto:') ||
124 !this.isValidUrl_(this.originalUrl_)) {
128 // Check for absolute paths.
129 if (url.startsWith('/')) {
130 var schemeEndIndex = this.originalUrl_.indexOf('://');
131 var firstSlash = this.originalUrl_.indexOf('/', schemeEndIndex + 3);
132 // e.g. http://www.foo.com/bar -> http://www.foo.com
133 var domain = firstSlash != -1 ?
134 this.originalUrl_.substr(0, firstSlash) : this.originalUrl_;
138 // Check for obvious relative paths.
139 var isRelative = false;
140 if (url.startsWith('.') || url.startsWith('\\'))
143 // In Adobe Acrobat Reader XI, it looks as though links with less than
144 // 2 dot separators in the domain are considered relative links, and
145 // those with 2 of more are considered http URLs. e.g.
147 // www.foo.com/bar -> http
148 // foo.com/bar -> relative link
150 var domainSeparatorIndex = url.indexOf('/');
151 var domainName = domainSeparatorIndex == -1 ?
152 url : url.substr(0, domainSeparatorIndex);
153 var domainDotCount = (domainName.match(/\./g) || []).length;
154 if (domainDotCount < 2)
159 var slashIndex = this.originalUrl_.lastIndexOf('/');
160 var path = slashIndex != -1 ?
161 this.originalUrl_.substr(0, slashIndex) : this.originalUrl_;
162 return path + '/' + url;
165 return 'http://' + url;