embient 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- embient (0.0.3)
4
+ embient (0.0.4)
5
5
  emberjs-rails
6
6
  rails (>= 3.1.0)
7
7
 
@@ -37,12 +37,12 @@ GEM
37
37
  multi_json (~> 1.0)
38
38
  arel (3.0.2)
39
39
  builder (3.0.0)
40
- emberjs-rails (2012.1.25)
40
+ emberjs-rails (2012.2.22)
41
41
  hamlbars
42
42
  rails (~> 3.1)
43
43
  erubis (2.7.0)
44
44
  haml (3.1.4)
45
- hamlbars (2012.1.13)
45
+ hamlbars (2012.2.22)
46
46
  haml
47
47
  sprockets
48
48
  tilt
@@ -1,3 +1,3 @@
1
1
  module Embient
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -0,0 +1,204 @@
1
+
2
+ (function(exports) {
3
+ var get = Ember.get, set = Ember.set, meta = Ember.meta;
4
+
5
+ /**
6
+ @class
7
+ This is an extension of Ember.ContainerView who's content
8
+ is restricted to a single child dicated by a property
9
+ on another view.
10
+ */
11
+ Ember.Handlebars.FrameView = Ember.ContainerView.extend({
12
+ /**
13
+ The view corresponding to the containing template
14
+ */
15
+ blockContainer: null,
16
+
17
+ /**
18
+ The property on the blockContainer which dictates the
19
+ contents of this container.
20
+ */
21
+ childPath: 'content',
22
+
23
+ /**
24
+ Set up the listener on the view corresponding to the
25
+ containing template
26
+ */
27
+ init: function() {
28
+ this._super();
29
+ var blockContainer = get(this, 'blockContainer');
30
+ blockContainer.addObserver(get(this, 'childPath'), this, 'contentDidUpdate');
31
+ this.contentDidUpdate();
32
+ },
33
+
34
+ /** @private
35
+ Fired when the property specified by contentPath changes on
36
+ the blockContainer
37
+ */
38
+ contentDidUpdate: function() {
39
+ var blockContainer = this.get('blockContainer');
40
+ var view = blockContainer.getPath(get(this, 'childPath'));
41
+ ember_assert(view instanceof Ember.View, "dynamicView's content must be set to a subclass of Ember.View'");
42
+ var childViews = this.get('_childViews');
43
+ var len = childViews.get('length');
44
+ var views = view ? [view] : [];
45
+ childViews.replace(0, len, views);
46
+ },
47
+
48
+ destroy: function() {
49
+ this._super();
50
+ var blockContainer = get(this, 'blockContainer');
51
+ blockContainer.removeObserver(get(this, 'childPath'), this, 'contentDidUpdate');
52
+ }
53
+ });
54
+
55
+ Ember.Handlebars.dynamicViewHelper = Ember.Object.create({
56
+
57
+ findContainingBlock: function(view) {
58
+ if (!view) {
59
+ return view;
60
+ }
61
+ // We are using _parentView here, because we need to go through the virtual YieldViews, so we can treat them differently.
62
+ else if (view instanceof Ember.Handlebars.FrameView) {
63
+ var blockContainer = Ember.get(view, 'blockContainer');
64
+ return this.findContainingBlock(Ember.get(blockContainer, '_parentView'));
65
+ }
66
+ else if (view.isVirtual) {
67
+ return this.findContainingBlock(Ember.get(view, '_parentView'));
68
+ }
69
+ return view;
70
+ },
71
+
72
+ helper: function(name, options) {
73
+ // If no name is provided, use default and swap parameters
74
+ if (name && name.data && name.data.isRenderData) {
75
+ options = name;
76
+ name = false;
77
+ }
78
+
79
+ var blockContainer = Ember.Handlebars.dynamicViewHelper.findContainingBlock(options.data.view);
80
+
81
+ if(name) {
82
+ options.hash.childPath = name;
83
+ }
84
+ options.hash.blockContainer = blockContainer;
85
+ return Ember.Handlebars.helpers.view.call(this, 'Ember.Handlebars.FrameView', options);
86
+ }
87
+
88
+ });
89
+
90
+ Ember.Handlebars.registerHelper('dynamicView', Ember.Handlebars.dynamicViewHelper.helper);
91
+
92
+
93
+
94
+ })({});
95
+
96
+
97
+ (function(exports) {
98
+ var get = Ember.get, set = Ember.set;
99
+
100
+ /**
101
+ @class
102
+ A convenient extension of Ember.State which makes it easy
103
+ to swap out dynamic content during state transitions.
104
+ */
105
+ Ember.LayoutState = Ember.State.extend({
106
+ /**
107
+ Convenience property to bind to.
108
+ */
109
+ active: false,
110
+
111
+ isViewState: true,
112
+
113
+ /**
114
+ The property to set in the nearest parent view
115
+ when this state is entered.
116
+ */
117
+ contentPath: 'content',
118
+
119
+ init: function() {
120
+ // This is currently experimental. We allow
121
+ // the view itself to define it's substates
122
+ // for better encapsulation. To do this, set
123
+ // the layoutStates property.
124
+ var viewClass = get(this, 'viewClass');
125
+ if(viewClass) {
126
+ var layoutStates = get(viewClass, 'proto').layoutStates;
127
+ set(this, 'states', layoutStates);
128
+ }
129
+
130
+ this._super();
131
+ },
132
+
133
+ enter: function(stateManager, transition) {
134
+ this._super(stateManager, transition);
135
+
136
+ set(this, 'active', true);
137
+
138
+ var viewClass = get(this, 'viewClass'), view;
139
+ ember_assert('view cannot be set directly, use viewClass instead', !this.get('view'));
140
+ view = this.createView(stateManager, transition);
141
+ this.set('view', view);
142
+
143
+ if (view) {
144
+ ember_assert('view must be an Ember.View', view instanceof Ember.View);
145
+
146
+
147
+ // if there is another view in the hierarchy then
148
+ // set its content
149
+ var parentView = get(this, 'parentView') || get(stateManager, 'rootView');
150
+ if(parentView) {
151
+ Ember.setPath(parentView, get(this, 'contentPath'), view);
152
+ }
153
+ // otherwise we just append to the rootElement on the
154
+ // state manager
155
+ else {
156
+ var root = stateManager.get('rootElement') || 'body';
157
+ view.appendTo(root);
158
+ }
159
+ }
160
+ },
161
+
162
+ exit: function(stateManager, transition) {
163
+ var view = get(this, 'view');
164
+
165
+ var parentView = get(this, 'parentView') || get(stateManager, 'rootView');
166
+ if(parentView) {
167
+ Ember.setPath(parentView, get(this, 'contentPath'), null);
168
+ }
169
+ else {
170
+ view.remove();
171
+ }
172
+ set(this, 'view', null);
173
+ set(this, 'active', false);
174
+ this._super(stateManager, transition);
175
+ },
176
+
177
+ /**
178
+ Instantiates viewClass. This method can be
179
+ overridden.
180
+ */
181
+ createView: function(stateManager, transition) {
182
+ var viewClass = get(this, 'viewClass');
183
+ ember_assert('viewClass must extend Ember.View', Ember.View.detect(viewClass));
184
+ return viewClass.create();
185
+ },
186
+
187
+ /**
188
+ Recursively find the nearest parent view
189
+ in the state hierarchy
190
+ */
191
+ parentView: Ember.computed(function() {
192
+ var state = this.get('parentState');
193
+ while(state && !state.get('view')) {
194
+ state = state.get('parentState');
195
+ }
196
+ return state && state.get('view');
197
+ }).property()
198
+ });
199
+
200
+ })({});
201
+
202
+
203
+ (function(exports) {
204
+ })({});
@@ -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
+ })({});