-
Notifications
You must be signed in to change notification settings - Fork 20
/
location.js
144 lines (121 loc) · 4.19 KB
/
location.js
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
/**
* @module location
*/
modules.define(
'location',
['inherit', 'events', 'history', 'objects', 'uri__querystring'],
function(provide, inherit, events, History, objects, Querystring) {
/**
* @class BEMLocation
* @augments events:Emitter
* @exports location
*/
var BEMLocation = inherit(events.Emitter, /** @lends BEMLocation.prototype */{
/**
* @constructor
*/
__constructor : function() {
this._history = new History();
this._syncState();
this._history.on('statechange', this._onStateChange, this);
},
/**
* Reaction for the history state change.
* @param {Object} event
* @param {Object} event params
* @private
*/
_onStateChange : function() {
this._syncState();
// Some browsers (like Chromium v36) emit "popstate" event when you return from other site
// using back/forward buttons. But some doesn't (like FireFox v28).
// We don't want to track this "popstate" event like location change.
if(this._state.referer === Querystring.Uri.normalize(window.location.href)) return;
if(this._state.silent !== true) {
this.emit('change', this._state);
}
},
/**
* Sync own state with the history block state.
* @returns {Object} location
* @private
*/
_syncState : function() {
var state = this._history.state,
uri = Querystring.Uri.parse(state.url);
this._state = objects.extend(state, {
referer : this._state && this._state.url, // referer - previous url
url : uri.build(), // full page URL –
// http://yandex.ru/yandsearch?text=ololo&lr=213
hostname : uri.getHost(), // page hostname - yandex.ru
path : uri.getPath(), // path to the current page - /yandsearch
params : uri.getParams() // search params –
// { text: ['ololo'], lr: ['213'] }
});
return this;
},
/**
* Method for a location change. It's possible to change location
* by an exact url or a query params (params can be overwritten using the forceParams flag).
* Method work depends on the provided data.
* @param {Object} data
* @param {Object} data.params query params
* @param {String} data.url new url
* @param {Boolean} [data.silent=false] do not trigger change event
* @param {Boolean} data.forceParams flag to overwrite current params with new.
* By default new params are extended with old
* @param {Boolean} data.replace write history record or replace current
*/
change : function(data) {
var uri = Querystring.Uri.parse(data.url);
if(data.url) {
delete data.params;
}
data.url = uri.build();
// Build a new url if the query params exists in data
if(data.params) {
var newUrl = new Querystring.Uri(),
params = data.forceParams ? data.params : objects.extend({}, this._state.params, data.params);
objects.each(params, function(value, key) {
newUrl.addParam(key, value);
});
data.url = newUrl.build();
}
// By default trigger change event
data.silent || (data.silent = false);
try {
this._history.changeState(
(data.replace ? 'replace' : 'push'),
data
);
} catch (e) {
if(/security/i.test(e.name)) {
throw e;
}
window.location.assign(data.url);
}
},
/**
* Returns current state.
* @returns {Object} state
*/
getState : function() {
return objects.extend({}, this._state);
},
/**
* Returns an Uri instance constructed from the current state url.
* @returns {uri}
*/
getUri : function() {
return Querystring.Uri.parse(this._state.url);
},
/**
* Returns previous url.
* @returns {String} refererUrl
*/
getReferer : function() {
return this._state.referer;
}
});
provide(new BEMLocation());
});