Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / resources / pdf / navigator.js
blobe6bd7ad28c4531d2fe846a35ae0cc0cdd0cea6fa
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.
5 'use strict';
7 /**
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.
16  */
17 function Navigator(originalUrl,
18                    viewport,
19                    paramsParser,
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 = {
30   /**
31    * @private
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
36    *    in the current tab.
37    */
38   navigate: function(url, newTab) {
39     if (url.length == 0)
40       return;
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('#');
48       if (hashIndex != -1)
49         url = this.originalUrl_.substring(0, hashIndex) + url;
50       else
51         url = this.originalUrl_ + url;
52     }
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))
59       return;
61     if (newTab) {
62       this.navigateInNewTabCallback_(url);
63     } else {
64       this.paramsParser_.getViewportFromUrlParams(
65           url, this.onViewportReceived_.bind(this));
66     }
67   },
69   /**
70    * @private
71    * Called when the viewport position is received.
72    * @param {Object} viewportPosition Dictionary containing the viewport
73    *    position.
74    */
75   onViewportReceived_: function(viewportPosition) {
76     var pageNumber = viewportPosition.page;
77     if (pageNumber != undefined)
78       this.viewport_.goToPage(pageNumber);
79     else
80       this.navigateInCurrentTabCallback_(viewportPosition['url']);
81   },
83   /**
84    * @private
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.
88    */
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) {
96       return false;
97     }
99     // Make sure |url| is not only a scheme.
100     if (url == 'http://' ||
101         url == 'https://' ||
102         url == 'ftp://' ||
103         url == 'file://' ||
104         url == 'mailto:') {
105       return false;
106     }
108     return true;
109   },
111   /**
112    * @private
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.
117    */
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_)) {
125       return url;
126     }
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_;
135       return domain + url;
136     }
138     // Check for obvious relative paths.
139     var isRelative = false;
140     if (url.startsWith('.') || url.startsWith('\\'))
141       isRelative = true;
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.
146     //
147     // www.foo.com/bar -> http
148     // foo.com/bar -> relative link
149     if (!isRelative) {
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)
155         isRelative = true;
156     }
158     if (isRelative) {
159       var slashIndex = this.originalUrl_.lastIndexOf('/');
160       var path = slashIndex != -1 ?
161           this.originalUrl_.substr(0, slashIndex) : this.originalUrl_;
162       return path + '/' + url;
163     }
165     return 'http://' + url;
166   }