1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
/**
* Creates a new Navigator for navigating to links inside or outside the PDF.
* @param {string} originalUrl The original page URL.
* @param {Object} viewport The viewport info of the page.
* @param {Object} paramsParser The object for URL parsing.
* @param {Function} navigateInCurrentTabCallback The Callback function that
* gets called when navigation happens in the current tab.
* @param {Function} navigateInNewTabCallback The Callback function that gets
* called when navigation happens in the new tab.
*/
function Navigator(originalUrl,
viewport,
paramsParser,
navigateInCurrentTabCallback,
navigateInNewTabCallback) {
this.originalUrl_ = originalUrl;
this.viewport_ = viewport;
this.paramsParser_ = paramsParser;
this.navigateInCurrentTabCallback_ = navigateInCurrentTabCallback;
this.navigateInNewTabCallback_ = navigateInNewTabCallback;
}
Navigator.prototype = {
/**
* @private
* Function to navigate to the given URL. This might involve navigating
* within the PDF page or opening a new url (in the same tab or a new tab).
* @param {string} url The URL to navigate to.
* @param {boolean} newTab Whether to perform the navigation in a new tab or
* in the current tab.
*/
navigate: function(url, newTab) {
if (url.length == 0)
return;
// If |urlFragment| starts with '#', then it's for the same URL with a
// different URL fragment.
if (url.charAt(0) == '#') {
// if '#' is already present in |originalUrl| then remove old fragment
// and add new url fragment.
var hashIndex = this.originalUrl_.search('#');
if (hashIndex != -1)
url = this.originalUrl_.substring(0, hashIndex) + url;
else
url = this.originalUrl_ + url;
}
// If there's no scheme, then take a guess at the scheme.
if (url.indexOf('://') == -1 && url.indexOf('mailto:') == -1)
url = this.guessUrlWithoutScheme_(url);
if (!this.isValidUrl_(url))
return;
if (newTab) {
this.navigateInNewTabCallback_(url);
} else {
this.paramsParser_.getViewportFromUrlParams(
url, this.onViewportReceived_.bind(this));
}
},
/**
* @private
* Called when the viewport position is received.
* @param {Object} viewportPosition Dictionary containing the viewport
* position.
*/
onViewportReceived_: function(viewportPosition) {
var originalUrl = this.originalUrl_;
var hashIndex = originalUrl.search('#');
if (hashIndex != -1)
originalUrl = originalUrl.substring(0, hashIndex);
var newUrl = viewportPosition.url;
hashIndex = newUrl.search('#');
if (hashIndex != -1)
newUrl = newUrl.substring(0, hashIndex);
var pageNumber = viewportPosition.page;
if (pageNumber != undefined && originalUrl == newUrl)
this.viewport_.goToPage(pageNumber);
else
this.navigateInCurrentTabCallback_(viewportPosition.url);
},
/**
* @private
* Checks if the URL starts with a scheme and s not just a scheme.
* @param {string} The input URL
* @return {boolean} Whether the url is valid.
*/
isValidUrl_: function(url) {
// Make sure |url| starts with a valid scheme.
if (url.indexOf('http://') != 0 &&
url.indexOf('https://') != 0 &&
url.indexOf('ftp://') != 0 &&
url.indexOf('file://') != 0 &&
url.indexOf('mailto:') != 0) {
return false;
}
// Make sure |url| is not only a scheme.
if (url == 'http://' ||
url == 'https://' ||
url == 'ftp://' ||
url == 'file://' ||
url == 'mailto:') {
return false;
}
return true;
},
/**
* @private
* Attempt to figure out what a URL is when there is no scheme.
* @param {string} The input URL
* @return {string} The URL with a scheme or the original URL if it is not
* possible to determine the scheme.
*/
guessUrlWithoutScheme_: function(url) {
// If the original URL is mailto:, that does not make sense to start with,
// and neither does adding |url| to it.
// If the original URL is not a valid URL, this cannot make a valid URL.
// In both cases, just bail out.
if (this.originalUrl_.startsWith('mailto:') ||
!this.isValidUrl_(this.originalUrl_)) {
return url;
}
// Check for absolute paths.
if (url.startsWith('/')) {
var schemeEndIndex = this.originalUrl_.indexOf('://');
var firstSlash = this.originalUrl_.indexOf('/', schemeEndIndex + 3);
// e.g. http://www.foo.com/bar -> http://www.foo.com
var domain = firstSlash != -1 ?
this.originalUrl_.substr(0, firstSlash) : this.originalUrl_;
return domain + url;
}
// Check for obvious relative paths.
var isRelative = false;
if (url.startsWith('.') || url.startsWith('\\'))
isRelative = true;
// In Adobe Acrobat Reader XI, it looks as though links with less than
// 2 dot separators in the domain are considered relative links, and
// those with 2 of more are considered http URLs. e.g.
//
// www.foo.com/bar -> http
// foo.com/bar -> relative link
if (!isRelative) {
var domainSeparatorIndex = url.indexOf('/');
var domainName = domainSeparatorIndex == -1 ?
url : url.substr(0, domainSeparatorIndex);
var domainDotCount = (domainName.match(/\./g) || []).length;
if (domainDotCount < 2)
isRelative = true;
}
if (isRelative) {
var slashIndex = this.originalUrl_.lastIndexOf('/');
var path = slashIndex != -1 ?
this.originalUrl_.substr(0, slashIndex) : this.originalUrl_;
return path + '/' + url;
}
return 'http://' + url;
}
};
|