ember-routemanager 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +35 -0
- data/Rakefile +2 -0
- data/ember-routemanager.gemspec +17 -0
- data/lib/ember-routemanager/version.rb +5 -0
- data/lib/ember-routemanager.rb +6 -0
- data/vendor/assets/javascripts/ember-routemanager.js +553 -0
- metadata +55 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2012 Hedtek Ltd. and Gordon L. Hempton
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Ember::Routemanager
|
|
2
|
+
|
|
3
|
+
Ember routemanager packaged for the rails asset pipeline.
|
|
4
|
+
|
|
5
|
+
Original routemanager package is here: https://github.com/ghempton/ember-routemanager
|
|
6
|
+
|
|
7
|
+
Commit d6bf04c289f34caeb63f70a0666b241f1638776e
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Add this line to your application's Gemfile:
|
|
12
|
+
|
|
13
|
+
gem 'ember-routemanager'
|
|
14
|
+
|
|
15
|
+
And then execute:
|
|
16
|
+
|
|
17
|
+
$ bundle
|
|
18
|
+
|
|
19
|
+
Or install it yourself as:
|
|
20
|
+
|
|
21
|
+
$ gem install ember-routemanager
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
Add the gem to your application and then add the line
|
|
26
|
+
//= require ember-routemanager
|
|
27
|
+
to your applicaton's javascript manifest
|
|
28
|
+
|
|
29
|
+
## Contributing
|
|
30
|
+
|
|
31
|
+
1. Fork it
|
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
33
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
35
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.expand_path('../lib/ember-routemanager/version', __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |gem|
|
|
5
|
+
gem.authors = ["David Workman", "Hedtek Ltd."]
|
|
6
|
+
gem.email = ["gems@hedtek.com"]
|
|
7
|
+
gem.description = %q{Ember routemanager for rails asset pipeline}
|
|
8
|
+
gem.summary = %q{Ember routemanager for rails asset pipeline}
|
|
9
|
+
gem.homepage = ""
|
|
10
|
+
|
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
14
|
+
gem.name = "ember-routemanager"
|
|
15
|
+
gem.require_paths = ["lib"]
|
|
16
|
+
gem.version = Ember::Routemanager::VERSION
|
|
17
|
+
end
|
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
|
|
2
|
+
(function(exports) {
|
|
3
|
+
var get = Ember.get, set = Ember.set;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
Whether the browser supports HTML5 history.
|
|
7
|
+
*/
|
|
8
|
+
var supportsHistory = !!(window.history && window.history.pushState);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
Whether the browser supports the hashchange event.
|
|
12
|
+
*/
|
|
13
|
+
var supportsHashChange = ('onhashchange' in window) && (document.documentMode === undefined || document.documentMode > 7);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
@class
|
|
17
|
+
Ember.RouteManager manages the browser location and changes states accordingly
|
|
18
|
+
to the current location. The location can be programmatically set as follows:
|
|
19
|
+
|
|
20
|
+
routeManager.set('location', 'notes/edit/4');
|
|
21
|
+
|
|
22
|
+
Ember.RouteManager also supports HTML5 history, which uses a '/' instead of a
|
|
23
|
+
'#' in the URLs, so that all your website's URLs are consistent.
|
|
24
|
+
*/
|
|
25
|
+
Ember.RouteManager = Ember.StateManager.extend({
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
Set this property to true if you want to use HTML5 history, if available on
|
|
29
|
+
the browser, instead of the location hash.
|
|
30
|
+
|
|
31
|
+
HTML 5 history uses the history.pushState method and the window's popstate
|
|
32
|
+
event.
|
|
33
|
+
|
|
34
|
+
By default it is false, so your URLs will look like:
|
|
35
|
+
|
|
36
|
+
http://domain.tld/my_app#notes/edit/4
|
|
37
|
+
|
|
38
|
+
If set to true and the browser supports pushState(), your URLs will look
|
|
39
|
+
like:
|
|
40
|
+
|
|
41
|
+
http://domain.tld/my_app/notes/edit/4
|
|
42
|
+
|
|
43
|
+
You will also need to make sure that baseURI is properly configured, as
|
|
44
|
+
well as your server so that your routes are properly pointing to your
|
|
45
|
+
SproutCore application.
|
|
46
|
+
|
|
47
|
+
@see http://dev.w3.org/html5/spec/history.html#the-history-interface
|
|
48
|
+
@property
|
|
49
|
+
@type {Boolean}
|
|
50
|
+
*/
|
|
51
|
+
wantsHistory: false,
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
A read-only boolean indicating whether or not HTML5 history is used. Based
|
|
55
|
+
on the value of wantsHistory and the browser's support for pushState.
|
|
56
|
+
|
|
57
|
+
@see wantsHistory
|
|
58
|
+
@property
|
|
59
|
+
@type {Boolean}
|
|
60
|
+
*/
|
|
61
|
+
usesHistory: null,
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
The base URI used to resolve routes (which are relative URLs). Only used
|
|
65
|
+
when usesHistory is equal to true.
|
|
66
|
+
|
|
67
|
+
The build tools automatically configure this value if you have the
|
|
68
|
+
html5_history option activated in the Buildfile:
|
|
69
|
+
|
|
70
|
+
config :my_app, :html5_history => true
|
|
71
|
+
|
|
72
|
+
Alternatively, it uses by default the value of the href attribute of the
|
|
73
|
+
<base> tag of the HTML document. For example:
|
|
74
|
+
|
|
75
|
+
<base href="http://domain.tld/my_app">
|
|
76
|
+
|
|
77
|
+
The value can also be customized before or during the exectution of the
|
|
78
|
+
main() method.
|
|
79
|
+
|
|
80
|
+
@see http://www.w3.org/TR/html5/semantics.html#the-base-element
|
|
81
|
+
@property
|
|
82
|
+
@type {String}
|
|
83
|
+
*/
|
|
84
|
+
baseURI: document.baseURI,
|
|
85
|
+
|
|
86
|
+
/** @private
|
|
87
|
+
A boolean value indicating whether or not the ping method has been called
|
|
88
|
+
to setup the Ember.routes.
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
@type {Boolean}
|
|
92
|
+
*/
|
|
93
|
+
_didSetup: false,
|
|
94
|
+
|
|
95
|
+
/** @private
|
|
96
|
+
Internal representation of the current location hash.
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
@type {String}
|
|
100
|
+
*/
|
|
101
|
+
_location: null,
|
|
102
|
+
|
|
103
|
+
/** @private
|
|
104
|
+
Internal method used to extract and merge the parameters of a URL.
|
|
105
|
+
|
|
106
|
+
@returns {Hash}
|
|
107
|
+
*/
|
|
108
|
+
_extractParametersAndRoute: function(obj) {
|
|
109
|
+
var params = {}, route = obj.route || '', separator, parts, i, len, crumbs, key;
|
|
110
|
+
separator = (route.indexOf('?') < 0 && route.indexOf('&') >= 0) ? '&' : '?';
|
|
111
|
+
parts = route.split(separator);
|
|
112
|
+
route = parts[0];
|
|
113
|
+
if(parts.length === 1) {
|
|
114
|
+
parts = [];
|
|
115
|
+
} else if(parts.length === 2) {
|
|
116
|
+
parts = parts[1].split('&');
|
|
117
|
+
} else if(parts.length > 2) {
|
|
118
|
+
parts.shift();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// extract the parameters from the route string
|
|
122
|
+
len = parts.length;
|
|
123
|
+
for( i = 0; i < len; ++i) {
|
|
124
|
+
crumbs = parts[i].split('=');
|
|
125
|
+
params[crumbs[0]] = crumbs[1];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// overlay any parameter passed in obj
|
|
129
|
+
for(key in obj) {
|
|
130
|
+
if(obj.hasOwnProperty(key) && key !== 'route') {
|
|
131
|
+
params[key] = '' + obj[key];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// build the route
|
|
136
|
+
parts = [];
|
|
137
|
+
for(key in params) {
|
|
138
|
+
parts.push([key, params[key]].join('='));
|
|
139
|
+
}
|
|
140
|
+
params.params = separator + parts.join('&');
|
|
141
|
+
params.route = route;
|
|
142
|
+
|
|
143
|
+
return params;
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
The current location hash. It is the part in the browser's location after
|
|
148
|
+
the '#' mark.
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
@type {String}
|
|
152
|
+
*/
|
|
153
|
+
location: Ember.computed(function(key, value) {
|
|
154
|
+
this._skipRoute = false;
|
|
155
|
+
return this._extractLocation(key, value);
|
|
156
|
+
}).property(),
|
|
157
|
+
|
|
158
|
+
_extractLocation: function(key, value) {
|
|
159
|
+
var crumbs, encodedValue;
|
|
160
|
+
|
|
161
|
+
if(value !== undefined) {
|
|
162
|
+
if(value === null) {
|
|
163
|
+
value = '';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if( typeof (value) === 'object') {
|
|
167
|
+
crumbs = this._extractParametersAndRoute(value);
|
|
168
|
+
value = crumbs.route + crumbs.params;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if(!this._skipPush && (!Ember.empty(value) || (this._location && this._location !== value))) {
|
|
172
|
+
encodedValue = encodeURI(value);
|
|
173
|
+
|
|
174
|
+
if(this.usesHistory) {
|
|
175
|
+
if(encodedValue.length > 0) {
|
|
176
|
+
encodedValue = '/' + encodedValue;
|
|
177
|
+
}
|
|
178
|
+
window.history.pushState(null, null, get(this, 'baseURI') + encodedValue);
|
|
179
|
+
} else if(encodedValue.length > 0 || window.location.hash.length > 0) {
|
|
180
|
+
window.location.hash = encodedValue;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
this._location = value;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return this._location;
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
updateLocation: function(loc) {
|
|
191
|
+
this._skipRoute = true;
|
|
192
|
+
return this._extractLocation('location', loc);
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
You usually don't need to call this method. It is done automatically after
|
|
197
|
+
the application has been initialized.
|
|
198
|
+
|
|
199
|
+
It registers for the hashchange event if available. If not, it creates a
|
|
200
|
+
timer that looks for location changes every 150ms.
|
|
201
|
+
*/
|
|
202
|
+
ping: function() {
|
|
203
|
+
if(!this._didSetup) {
|
|
204
|
+
this._didSetup = true;
|
|
205
|
+
var state;
|
|
206
|
+
|
|
207
|
+
if(get(this, 'wantsHistory') && supportsHistory) {
|
|
208
|
+
this.usesHistory = true;
|
|
209
|
+
|
|
210
|
+
// Move any hash state to url state
|
|
211
|
+
// TODO: Make sure we have a hash before adding slash
|
|
212
|
+
state = window.location.hash.slice(1);
|
|
213
|
+
if(state.length > 0) {
|
|
214
|
+
state = '/' + state;
|
|
215
|
+
window.history.replaceState(null, null, get(this, 'baseURI') + state);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
this.popState();
|
|
219
|
+
this.popState = jQuery.proxy(this.popState, this);
|
|
220
|
+
jQuery(window).bind('popstate', this.popState);
|
|
221
|
+
|
|
222
|
+
} else {
|
|
223
|
+
this.usesHistory = false;
|
|
224
|
+
|
|
225
|
+
if(get(this, 'wantsHistory')) {
|
|
226
|
+
// Move any url state to hash
|
|
227
|
+
var base = get(this, 'baseURI');
|
|
228
|
+
var loc = (base.charAt(0) === '/') ? document.location.pathname : document.location.href.replace(document.location.hash, '');
|
|
229
|
+
state = loc.slice(base.length + 1);
|
|
230
|
+
if(state.length > 0) {
|
|
231
|
+
window.location.href = base + '#' + state;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if(supportsHashChange) {
|
|
236
|
+
this.hashChange();
|
|
237
|
+
this.hashChange = jQuery.proxy(this.hashChange, this);
|
|
238
|
+
jQuery(window).bind('hashchange', this.hashChange);
|
|
239
|
+
|
|
240
|
+
} else {
|
|
241
|
+
// we don't use a Ember.Timer because we don't want
|
|
242
|
+
// a run loop to be triggered at each ping
|
|
243
|
+
var invokeHashChange = function() {
|
|
244
|
+
this.hashChange();
|
|
245
|
+
this._timerId = setTimeout(invokeHashChange, 100);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
invokeHashChange();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
destroy: function() {
|
|
255
|
+
if(this._didSetup) {
|
|
256
|
+
if(get(this, 'wantsHistory') && supportsHistory) {
|
|
257
|
+
jQuery(window).unbind('popstate', this.popState);
|
|
258
|
+
} else {
|
|
259
|
+
if(supportsHashChange) {
|
|
260
|
+
jQuery(window).unbind('hashchange', this.hashChange);
|
|
261
|
+
} else {
|
|
262
|
+
clearTimeout(this._timerId);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
this._super();
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
Ember.RouteManager currently automatically starts listening
|
|
271
|
+
for browser location changes when created.
|
|
272
|
+
*/
|
|
273
|
+
init: function() {
|
|
274
|
+
this._super();
|
|
275
|
+
if(!this._didSetup) {
|
|
276
|
+
this.ping();
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
Observer of the 'location' property that calls the correct route handler
|
|
282
|
+
when the location changes.
|
|
283
|
+
*/
|
|
284
|
+
locationDidChange: Ember.observer(function() {
|
|
285
|
+
this.trigger();
|
|
286
|
+
}, 'location'),
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
Triggers a route even if already in that route (does change the location, if
|
|
290
|
+
it is not already changed, as well).
|
|
291
|
+
|
|
292
|
+
If the location is not the same as the supplied location, this simply lets
|
|
293
|
+
"location" handle it (which ends up coming back to here).
|
|
294
|
+
*/
|
|
295
|
+
trigger: function() {
|
|
296
|
+
var location = get(this, 'location'), params, route;
|
|
297
|
+
params = this._extractParametersAndRoute({
|
|
298
|
+
route: location
|
|
299
|
+
});
|
|
300
|
+
location = params.route;
|
|
301
|
+
delete params.route;
|
|
302
|
+
delete params.params;
|
|
303
|
+
|
|
304
|
+
var result = this.getState(location, params);
|
|
305
|
+
if(result) {
|
|
306
|
+
set(this, 'params', result.params);
|
|
307
|
+
|
|
308
|
+
// We switch states in two phases. The point of this is to handle
|
|
309
|
+
// parameter-only location changes. This will correspond to the same
|
|
310
|
+
// state path in the manager, but states with parts with changed
|
|
311
|
+
// parameters should be re-entered:
|
|
312
|
+
|
|
313
|
+
// 1. We go to the earliest clean state. This prevents
|
|
314
|
+
// unnecessary transitions.
|
|
315
|
+
if(result.cleanStates.length > 0) {
|
|
316
|
+
var cleanState = result.cleanStates.join('.');
|
|
317
|
+
this.goToState(cleanState);
|
|
318
|
+
}
|
|
319
|
+
// 2. We transition to the dirty state. This forces dirty
|
|
320
|
+
// states to be transitioned.
|
|
321
|
+
if(result.dirtyStates.length > 0) {
|
|
322
|
+
var dirtyState = result.cleanStates.concat(result.dirtyStates).join('.');
|
|
323
|
+
this.goToState(dirtyState);
|
|
324
|
+
}
|
|
325
|
+
} else {
|
|
326
|
+
var states = get(this, 'states');
|
|
327
|
+
if(states && get(states, "404")) {
|
|
328
|
+
this.goToState("404");
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
|
|
333
|
+
getState: function(route, params) {
|
|
334
|
+
var parts = route.split('/');
|
|
335
|
+
parts = parts.filter(function(part) {
|
|
336
|
+
return part !== '';
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
return this._findState(parts, this, [], [], params, false);
|
|
340
|
+
},
|
|
341
|
+
|
|
342
|
+
/** @private
|
|
343
|
+
Recursive helper that the state and the params if a match is found
|
|
344
|
+
*/
|
|
345
|
+
_findState: function(parts, state, cleanStates, dirtyStates, params) {
|
|
346
|
+
parts = Ember.copy(parts);
|
|
347
|
+
|
|
348
|
+
var hasChildren = false, name, states, childState;
|
|
349
|
+
// sort desc based on priority
|
|
350
|
+
states = [];
|
|
351
|
+
for(name in state.states) {
|
|
352
|
+
// 404 state is special and not matched
|
|
353
|
+
childState = state.states[name];
|
|
354
|
+
if(name == "404" || !Ember.State.detect(childState) && !( childState instanceof Ember.State)) {
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
states.push({
|
|
358
|
+
name: name,
|
|
359
|
+
state: childState
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
states = states.sort(function(a, b) {
|
|
363
|
+
return (b.state.get('priority') || 0) - (a.state.get('priority') || 0);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
for(var i = 0; i < states.length; i++) {
|
|
367
|
+
name = states[i].name;
|
|
368
|
+
childState = states[i].state;
|
|
369
|
+
if(!( childState instanceof Ember.State)) {
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
hasChildren = true;
|
|
373
|
+
|
|
374
|
+
var result = this._matchState(parts, childState, params);
|
|
375
|
+
if(!result) {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
var newParams = Ember.copy(params);
|
|
380
|
+
jQuery.extend(newParams, result.params);
|
|
381
|
+
|
|
382
|
+
var dirty = dirtyStates.length > 0 || result.dirty;
|
|
383
|
+
var newCleanStates = cleanStates;
|
|
384
|
+
var newDirtyStates = dirtyStates;
|
|
385
|
+
if(dirty) {
|
|
386
|
+
newDirtyStates = Ember.copy(newDirtyStates);
|
|
387
|
+
newDirtyStates.push(name);
|
|
388
|
+
} else {
|
|
389
|
+
newCleanStates = Ember.copy(newCleanStates);
|
|
390
|
+
newCleanStates.push(name);
|
|
391
|
+
}
|
|
392
|
+
result = this._findState(result.parts, childState, newCleanStates, newDirtyStates, newParams);
|
|
393
|
+
if(result) {
|
|
394
|
+
return result;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if(!hasChildren && parts.length === 0) {
|
|
399
|
+
return {
|
|
400
|
+
state: state,
|
|
401
|
+
params: params,
|
|
402
|
+
cleanStates: cleanStates,
|
|
403
|
+
dirtyStates: dirtyStates
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
return null;
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
/** @private
|
|
410
|
+
Check if a state accepts the parts with the params
|
|
411
|
+
|
|
412
|
+
Returns the remaining parts as well as merged params if
|
|
413
|
+
the state accepts.
|
|
414
|
+
|
|
415
|
+
Will also set the dirty flag if the route is the same but
|
|
416
|
+
the parameters have changed
|
|
417
|
+
*/
|
|
418
|
+
_matchState: function(parts, state, params) {
|
|
419
|
+
parts = Ember.copy(parts);
|
|
420
|
+
params = Ember.copy(params);
|
|
421
|
+
var dirty = false;
|
|
422
|
+
var route = get(state, 'route');
|
|
423
|
+
if(route) {
|
|
424
|
+
var partDefinitions;
|
|
425
|
+
// route could be either a string or regex
|
|
426
|
+
if( typeof route == "string") {
|
|
427
|
+
partDefinitions = route.split('/');
|
|
428
|
+
} else if( route instanceof RegExp) {
|
|
429
|
+
partDefinitions = [route];
|
|
430
|
+
} else {
|
|
431
|
+
ember_assert("route must be either a string or regexp", false);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
for(var i = 0; i < partDefinitions.length; i++) {
|
|
435
|
+
if(parts.length === 0) {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
var part = parts.shift();
|
|
439
|
+
var partDefinition = partDefinitions[i];
|
|
440
|
+
var partParams = this._matchPart(partDefinition, part);
|
|
441
|
+
if(!partParams) {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
var oldParams = this.get('params') || {};
|
|
446
|
+
for(var param in partParams) {
|
|
447
|
+
dirty = dirty || (oldParams[param] != partParams[param]);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
jQuery.extend(params, partParams);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if(Ember.typeOf(state.willAccept) == 'function') {
|
|
455
|
+
if(!state.willAccept(params)) {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return {
|
|
461
|
+
parts: parts,
|
|
462
|
+
params: params,
|
|
463
|
+
dirty: dirty
|
|
464
|
+
};
|
|
465
|
+
},
|
|
466
|
+
|
|
467
|
+
/** @private
|
|
468
|
+
Returns params if the part matches the partDefinition
|
|
469
|
+
*/
|
|
470
|
+
_matchPart: function(partDefinition, part) {
|
|
471
|
+
// Handle string parts
|
|
472
|
+
if( typeof partDefinition == "string") {
|
|
473
|
+
|
|
474
|
+
switch (partDefinition.slice(0, 1)) {
|
|
475
|
+
// 1. dynamic routes
|
|
476
|
+
case ':':
|
|
477
|
+
var name = partDefinition.slice(1, partDefinition.length);
|
|
478
|
+
var params = {};
|
|
479
|
+
params[name] = part;
|
|
480
|
+
return params;
|
|
481
|
+
|
|
482
|
+
// 2. wildcard routes
|
|
483
|
+
case '*':
|
|
484
|
+
return {};
|
|
485
|
+
|
|
486
|
+
// 3. static routes
|
|
487
|
+
default:
|
|
488
|
+
if(partDefinition == part)
|
|
489
|
+
return {};
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Handle RegExp parts
|
|
497
|
+
return partDefinition.test(part) ? {} : false;
|
|
498
|
+
},
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
Event handler for the hashchange event. Called automatically by the browser
|
|
502
|
+
if it supports the hashchange event, or by our timer if not.
|
|
503
|
+
*/
|
|
504
|
+
hashChange: function(event) {
|
|
505
|
+
var loc = window.location.hash;
|
|
506
|
+
var routes = this;
|
|
507
|
+
|
|
508
|
+
// Remove the '#' prefix
|
|
509
|
+
loc = (loc && loc.length > 0) ? loc.slice(1, loc.length) : '';
|
|
510
|
+
|
|
511
|
+
if(!jQuery.browser.mozilla) {
|
|
512
|
+
// because of bug https://bugzilla.mozilla.org/show_bug.cgi?id=483304
|
|
513
|
+
loc = decodeURI(loc);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if(get(routes, 'location') !== loc && !routes._skipRoute) {
|
|
517
|
+
Ember.run.once(function() {
|
|
518
|
+
routes._skipPush = true;
|
|
519
|
+
set(routes, 'location', loc);
|
|
520
|
+
routes._skipPush = false;
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
}
|
|
524
|
+
routes._skipRoute = false;
|
|
525
|
+
},
|
|
526
|
+
|
|
527
|
+
popState: function(event) {
|
|
528
|
+
var routes = this;
|
|
529
|
+
var base = get(routes, 'baseURI'), loc = (base.charAt(0) === '/') ? document.location.pathname : document.location.href;
|
|
530
|
+
|
|
531
|
+
if(loc.slice(0, base.length) === base) {
|
|
532
|
+
// Remove the base prefix and the extra '/'
|
|
533
|
+
loc = loc.slice(base.length + 1, loc.length);
|
|
534
|
+
|
|
535
|
+
if(get(routes, 'location') !== loc && !routes._skipRoute) {
|
|
536
|
+
Ember.run.once(function() {
|
|
537
|
+
routes._skipPush = true;
|
|
538
|
+
set(routes, 'location', loc);
|
|
539
|
+
routes._skipPush = false;
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
routes._skipRoute = false;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
})({});
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
(function(exports) {
|
|
553
|
+
})({});
|
metadata
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ember-routemanager
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- David Workman
|
|
9
|
+
- Hedtek Ltd.
|
|
10
|
+
autorequire:
|
|
11
|
+
bindir: bin
|
|
12
|
+
cert_chain: []
|
|
13
|
+
date: 2012-03-26 00:00:00.000000000 Z
|
|
14
|
+
dependencies: []
|
|
15
|
+
description: Ember routemanager for rails asset pipeline
|
|
16
|
+
email:
|
|
17
|
+
- gems@hedtek.com
|
|
18
|
+
executables: []
|
|
19
|
+
extensions: []
|
|
20
|
+
extra_rdoc_files: []
|
|
21
|
+
files:
|
|
22
|
+
- .gitignore
|
|
23
|
+
- Gemfile
|
|
24
|
+
- LICENSE
|
|
25
|
+
- README.md
|
|
26
|
+
- Rakefile
|
|
27
|
+
- ember-routemanager.gemspec
|
|
28
|
+
- lib/ember-routemanager.rb
|
|
29
|
+
- lib/ember-routemanager/version.rb
|
|
30
|
+
- vendor/assets/javascripts/ember-routemanager.js
|
|
31
|
+
homepage: ''
|
|
32
|
+
licenses: []
|
|
33
|
+
post_install_message:
|
|
34
|
+
rdoc_options: []
|
|
35
|
+
require_paths:
|
|
36
|
+
- lib
|
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
38
|
+
none: false
|
|
39
|
+
requirements:
|
|
40
|
+
- - ! '>='
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '0'
|
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
|
+
none: false
|
|
45
|
+
requirements:
|
|
46
|
+
- - ! '>='
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
requirements: []
|
|
50
|
+
rubyforge_project:
|
|
51
|
+
rubygems_version: 1.8.16
|
|
52
|
+
signing_key:
|
|
53
|
+
specification_version: 3
|
|
54
|
+
summary: Ember routemanager for rails asset pipeline
|
|
55
|
+
test_files: []
|