Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/history/html5history.js
2868 views
1
// Copyright 2010 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview HTML5 based history implementation, compatible with
17
* goog.History.
18
*
19
* TODO(user): There should really be a history interface and multiple
20
* implementations.
21
*
22
*/
23
24
25
goog.provide('goog.history.Html5History');
26
goog.provide('goog.history.Html5History.TokenTransformer');
27
28
goog.require('goog.asserts');
29
goog.require('goog.events');
30
goog.require('goog.events.EventTarget');
31
goog.require('goog.events.EventType');
32
goog.require('goog.history.Event');
33
34
35
36
/**
37
* An implementation compatible with goog.History that uses the HTML5
38
* history APIs.
39
*
40
* @param {Window=} opt_win The window to listen/dispatch history events on.
41
* @param {goog.history.Html5History.TokenTransformer=} opt_transformer
42
* The token transformer that is used to create URL from the token
43
* when storing token without using hash fragment.
44
* @constructor
45
* @extends {goog.events.EventTarget}
46
* @final
47
*/
48
goog.history.Html5History = function(opt_win, opt_transformer) {
49
goog.events.EventTarget.call(this);
50
goog.asserts.assert(
51
goog.history.Html5History.isSupported(opt_win),
52
'HTML5 history is not supported.');
53
54
/**
55
* The window object to use for history tokens. Typically the top window.
56
* @type {Window}
57
* @private
58
*/
59
this.window_ = opt_win || window;
60
61
/**
62
* The token transformer that is used to create URL from the token
63
* when storing token without using hash fragment.
64
* @type {goog.history.Html5History.TokenTransformer}
65
* @private
66
*/
67
this.transformer_ = opt_transformer || null;
68
69
/**
70
* The fragment of the last navigation. Used to eliminate duplicate/redundant
71
* NAVIGATE events when a POPSTATE and HASHCHANGE event are triggered for the
72
* same navigation (e.g., back button click).
73
* @private {?string}
74
*/
75
this.lastFragment_ = null;
76
77
goog.events.listen(
78
this.window_, goog.events.EventType.POPSTATE, this.onHistoryEvent_, false,
79
this);
80
goog.events.listen(
81
this.window_, goog.events.EventType.HASHCHANGE, this.onHistoryEvent_,
82
false, this);
83
};
84
goog.inherits(goog.history.Html5History, goog.events.EventTarget);
85
86
87
/**
88
* Returns whether Html5History is supported.
89
* @param {Window=} opt_win Optional window to check.
90
* @return {boolean} Whether html5 history is supported.
91
*/
92
goog.history.Html5History.isSupported = function(opt_win) {
93
var win = opt_win || window;
94
return !!(win.history && win.history.pushState);
95
};
96
97
98
/**
99
* Status of when the object is active and dispatching events.
100
* @type {boolean}
101
* @private
102
*/
103
goog.history.Html5History.prototype.enabled_ = false;
104
105
106
/**
107
* Whether to use the fragment to store the token, defaults to true.
108
* @type {boolean}
109
* @private
110
*/
111
goog.history.Html5History.prototype.useFragment_ = true;
112
113
114
/**
115
* If useFragment is false the path will be used, the path prefix will be
116
* prepended to all tokens. Defaults to '/'.
117
* @type {string}
118
* @private
119
*/
120
goog.history.Html5History.prototype.pathPrefix_ = '/';
121
122
123
/**
124
* Starts or stops the History. When enabled, the History object
125
* will immediately fire an event for the current location. The caller can set
126
* up event listeners between the call to the constructor and the call to
127
* setEnabled.
128
*
129
* @param {boolean} enable Whether to enable history.
130
*/
131
goog.history.Html5History.prototype.setEnabled = function(enable) {
132
if (enable == this.enabled_) {
133
return;
134
}
135
136
this.enabled_ = enable;
137
138
if (enable) {
139
this.dispatchEvent(new goog.history.Event(this.getToken(), false));
140
}
141
};
142
143
144
/**
145
* Returns the current token.
146
* @return {string} The current token.
147
*/
148
goog.history.Html5History.prototype.getToken = function() {
149
if (this.useFragment_) {
150
return goog.asserts.assertString(this.getFragment_());
151
} else {
152
return this.transformer_ ?
153
this.transformer_.retrieveToken(
154
this.pathPrefix_, this.window_.location) :
155
this.window_.location.pathname.substr(this.pathPrefix_.length);
156
}
157
};
158
159
160
/**
161
* Sets the history state.
162
* @param {string} token The history state identifier.
163
* @param {string=} opt_title Optional title to associate with history entry.
164
*/
165
goog.history.Html5History.prototype.setToken = function(token, opt_title) {
166
if (token == this.getToken()) {
167
return;
168
}
169
170
// Per externs/gecko_dom.js document.title can be null.
171
this.window_.history.pushState(
172
null, opt_title || this.window_.document.title || '',
173
this.getUrl_(token));
174
this.dispatchEvent(new goog.history.Event(token, false));
175
};
176
177
178
/**
179
* Replaces the current history state without affecting the rest of the history
180
* stack.
181
* @param {string} token The history state identifier.
182
* @param {string=} opt_title Optional title to associate with history entry.
183
*/
184
goog.history.Html5History.prototype.replaceToken = function(token, opt_title) {
185
// Per externs/gecko_dom.js document.title can be null.
186
this.window_.history.replaceState(
187
null, opt_title || this.window_.document.title || '',
188
this.getUrl_(token));
189
this.dispatchEvent(new goog.history.Event(token, false));
190
};
191
192
193
/** @override */
194
goog.history.Html5History.prototype.disposeInternal = function() {
195
goog.events.unlisten(
196
this.window_, goog.events.EventType.POPSTATE, this.onHistoryEvent_, false,
197
this);
198
if (this.useFragment_) {
199
goog.events.unlisten(
200
this.window_, goog.events.EventType.HASHCHANGE, this.onHistoryEvent_,
201
false, this);
202
}
203
};
204
205
206
/**
207
* Sets whether to use the fragment to store tokens.
208
* @param {boolean} useFragment Whether to use the fragment.
209
*/
210
goog.history.Html5History.prototype.setUseFragment = function(useFragment) {
211
if (this.useFragment_ != useFragment) {
212
if (useFragment) {
213
goog.events.listen(
214
this.window_, goog.events.EventType.HASHCHANGE, this.onHistoryEvent_,
215
false, this);
216
} else {
217
goog.events.unlisten(
218
this.window_, goog.events.EventType.HASHCHANGE, this.onHistoryEvent_,
219
false, this);
220
}
221
this.useFragment_ = useFragment;
222
}
223
};
224
225
226
/**
227
* Sets the path prefix to use if storing tokens in the path. The path
228
* prefix should start and end with slash.
229
* @param {string} pathPrefix Sets the path prefix.
230
*/
231
goog.history.Html5History.prototype.setPathPrefix = function(pathPrefix) {
232
this.pathPrefix_ = pathPrefix;
233
};
234
235
236
/**
237
* Gets the path prefix.
238
* @return {string} The path prefix.
239
*/
240
goog.history.Html5History.prototype.getPathPrefix = function() {
241
return this.pathPrefix_;
242
};
243
244
245
/**
246
* Gets the current hash fragment, if useFragment_ is enabled.
247
* @return {?string} The hash fragment.
248
* @private
249
*/
250
goog.history.Html5History.prototype.getFragment_ = function() {
251
if (this.useFragment_) {
252
var loc = this.window_.location.href;
253
var index = loc.indexOf('#');
254
return index < 0 ? '' : loc.substring(index + 1);
255
} else {
256
return null;
257
}
258
};
259
260
261
/**
262
* Gets the URL to set when calling history.pushState
263
* @param {string} token The history token.
264
* @return {string} The URL.
265
* @private
266
*/
267
goog.history.Html5History.prototype.getUrl_ = function(token) {
268
if (this.useFragment_) {
269
return '#' + token;
270
} else {
271
return this.transformer_ ?
272
this.transformer_.createUrl(
273
token, this.pathPrefix_, this.window_.location) :
274
this.pathPrefix_ + token + this.window_.location.search;
275
}
276
};
277
278
279
/**
280
* Handles history events dispatched by the browser.
281
* @param {goog.events.BrowserEvent} e The browser event object.
282
* @private
283
*/
284
goog.history.Html5History.prototype.onHistoryEvent_ = function(e) {
285
if (this.enabled_) {
286
var fragment = this.getFragment_();
287
// Only fire NAVIGATE event if it's POPSTATE or if the fragment has changed
288
// without a POPSTATE event. The latter is an indication the browser doesn't
289
// support POPSTATE, and the event is a HASHCHANGE instead.
290
if (e.type == goog.events.EventType.POPSTATE ||
291
fragment != this.lastFragment_) {
292
this.lastFragment_ = fragment;
293
this.dispatchEvent(new goog.history.Event(this.getToken(), true));
294
}
295
}
296
};
297
298
299
300
/**
301
* A token transformer that can create a URL from a history
302
* token. This is used by {@code goog.history.Html5History} to create
303
* URL when storing token without the hash fragment.
304
*
305
* Given a {@code window.location} object containing the location
306
* created by {@code createUrl}, the token transformer allows
307
* retrieval of the token back via {@code retrieveToken}.
308
*
309
* @interface
310
*/
311
goog.history.Html5History.TokenTransformer = function() {};
312
313
314
/**
315
* Retrieves a history token given the path prefix and
316
* {@code window.location} object.
317
*
318
* @param {string} pathPrefix The path prefix to use when storing token
319
* in a path; always begin with a slash.
320
* @param {Location} location The {@code window.location} object.
321
* Treat this object as read-only.
322
* @return {string} token The history token.
323
*/
324
goog.history.Html5History.TokenTransformer.prototype.retrieveToken = function(
325
pathPrefix, location) {};
326
327
328
/**
329
* Creates a URL to be pushed into HTML5 history stack when storing
330
* token without using hash fragment.
331
*
332
* @param {string} token The history token.
333
* @param {string} pathPrefix The path prefix to use when storing token
334
* in a path; always begin with a slash.
335
* @param {Location} location The {@code window.location} object.
336
* Treat this object as read-only.
337
* @return {string} url The complete URL string from path onwards
338
* (without {@code protocol://host:port} part); must begin with a
339
* slash.
340
*/
341
goog.history.Html5History.TokenTransformer.prototype.createUrl = function(
342
token, pathPrefix, location) {};
343
344