angular-route-segment-rails 0.2.0
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +21 -0
- data/README.md +17 -0
- data/lib/angular-route-segment-rails.rb +11 -0
- data/lib/angular-route-segment-rails/engine.rb +6 -0
- data/lib/angular-route-segment-rails/sprockets.rb +3 -0
- data/lib/angular-route-segment-rails/version.rb +5 -0
- data/vendor/assets/javascripts/angular-route-segment.js +1029 -0
- metadata +64 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8e9c8e1d1e08d7c04468156e2927fc95bdab69d6
|
4
|
+
data.tar.gz: 6672145b993f8caa0313a16043ce89ba3f8fcd0c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 80d8bd252daa20b6b79ddca0ce95055f3b4c961b36db197146f7ad66e61e272f813a8d79a51fbf5250d1c51ede9077f0a1b24c63a16704127802e13443134784
|
7
|
+
data.tar.gz: fe61a90e85f8b4983639d63812bc1a2cbe0ec1dd95fad1bfaf0df499f1bed5e708690a724da34fc6a6e5953ad410962eafe38276792bd054bf9e527e9203d78a
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2016 Andy Alekseenko
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# angular-route-segment-rails
|
2
|
+
|
3
|
+
angular-route-segment-rails wraps the [angular-route-segment](https://github.com/alekseenko/angular-route-segment) library for use in Rails 3.1 and above. Assets will minify automatically during production.
|
4
|
+
It depends on [angularjs-rails gem](https://github.com/hiravgandhi/angularjs-rails).
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
|
8
|
+
Add the following to your Gemfile:
|
9
|
+
|
10
|
+
gem 'angularjs-rails'
|
11
|
+
gem 'angular-route-segment-rails'
|
12
|
+
|
13
|
+
Add the following directive to your JavaScript manifest file (application.js) after requiring angular:
|
14
|
+
|
15
|
+
//= require angular
|
16
|
+
//= require angular-route
|
17
|
+
//= require angular-route-segment
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "angular-route-segment-rails/version"
|
2
|
+
|
3
|
+
module AngularRouteSegment
|
4
|
+
module Rails
|
5
|
+
if defined? ::Rails::Engine
|
6
|
+
require 'angular-route-segment-rails/engine'
|
7
|
+
elsif defined? Sprockets
|
8
|
+
require 'angular-route-segment-rails/sprockets'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,1029 @@
|
|
1
|
+
/**
|
2
|
+
* angular-route-segment 1.5.1
|
3
|
+
* https://angular-route-segment.com
|
4
|
+
* @author Artem Chivchalov
|
5
|
+
* @license MIT License http://opensource.org/licenses/MIT
|
6
|
+
*/
|
7
|
+
'use strict';
|
8
|
+
(function(angular) {
|
9
|
+
|
10
|
+
/**
|
11
|
+
* @ngdoc module
|
12
|
+
* @module route-segment
|
13
|
+
* @name route-segment
|
14
|
+
* @packageName angular-route-segment
|
15
|
+
* @requires ngRoute
|
16
|
+
* @description
|
17
|
+
* This library is intended to provide the lacking functionality of nested routing to [AngularJS](http://angularjs.org) applications.
|
18
|
+
* It is widely known, there are no ways to keep the parent state unchanged when children are updated via routing mechanics - the
|
19
|
+
* [$route](https://docs.angularjs.org/api/ngRoute/service/$route) service re-creates the whole scope after a route is changed, losing its state completely.
|
20
|
+
* *route-segment* gives you a way to handle this.
|
21
|
+
*
|
22
|
+
* The library provides two pieces of code: {@link $routeSegment $routeSegment} service and {@link appViewSegment appViewSegment} directive.
|
23
|
+
* Both are placed in their own modules which you must include as dependencies in your app module:
|
24
|
+
*
|
25
|
+
* ```js
|
26
|
+
* var app = angular.module('app', ['ngRoute', 'route-segment', 'view-segment']);
|
27
|
+
* ```
|
28
|
+
* $routeSegment is a layer on top of built-in Angular [$route](https://docs.angularjs.org/api/ngRoute/service/$route) service and is meant to be used instead of it.
|
29
|
+
* Its provider exposes configuration methods which can be used to traverse the tree of route segments and setup it properly.
|
30
|
+
*/
|
31
|
+
var mod = angular.module( 'route-segment', [] );
|
32
|
+
/**
|
33
|
+
* @ngdoc provider
|
34
|
+
* @module route-segment
|
35
|
+
* @name $routeSegmentProvider
|
36
|
+
* @requires https://docs.angularjs.org/api/ngRoute/provider/$routeProvider $routeProvider
|
37
|
+
* @description Replaces [$routeProvider](https://docs.angularjs.org/api/ngRoute/provider/$routeProvider) for the app routing configuration
|
38
|
+
*
|
39
|
+
* Example:
|
40
|
+
* ```js
|
41
|
+
* app.config(function ($routeSegmentProvider) {
|
42
|
+
*
|
43
|
+
* $routeSegmentProvider.
|
44
|
+
*
|
45
|
+
* when('/section1', 's1').
|
46
|
+
* when('/section1/prefs', 's1.prefs').
|
47
|
+
* when('/section1/:id', 's1.itemInfo').
|
48
|
+
* when('/section1/:id/edit', 's1.itemInfo.edit').
|
49
|
+
* when('/section2', 's2').
|
50
|
+
*
|
51
|
+
* segment('s1', {
|
52
|
+
* templateUrl: 'templates/section1.html',
|
53
|
+
* controller: MainCtrl}).
|
54
|
+
*
|
55
|
+
* within().
|
56
|
+
*
|
57
|
+
* segment('home', {
|
58
|
+
* default: true,
|
59
|
+
* templateUrl: 'templates/section1/home.html'}).
|
60
|
+
*
|
61
|
+
* segment('itemInfo', {
|
62
|
+
* templateUrl: 'templates/section1/item.html',
|
63
|
+
* controller: Section1ItemCtrl,
|
64
|
+
* dependencies: ['id']}).
|
65
|
+
*
|
66
|
+
* within().
|
67
|
+
*
|
68
|
+
* segment('overview', {
|
69
|
+
* default: true
|
70
|
+
* templateUrl: 'templates/section1/item/overview.html'}).
|
71
|
+
*
|
72
|
+
* segment('edit', {
|
73
|
+
* templateUrl: 'templates/section1/item/edit.html'}).
|
74
|
+
*
|
75
|
+
* up().
|
76
|
+
*
|
77
|
+
* segment('prefs', {
|
78
|
+
* templateUrl: 'templates/section1/prefs.html'}).
|
79
|
+
*
|
80
|
+
* up().
|
81
|
+
*
|
82
|
+
* segment('s2', {
|
83
|
+
* templateUrl: 'templates/section2.html',
|
84
|
+
* controller: MainCtrl});
|
85
|
+
* });
|
86
|
+
* ```
|
87
|
+
*
|
88
|
+
* Alternatively, you can use this syntax instead of traversing (useful if you want modules to have their own separately defined routes):
|
89
|
+
* ```js
|
90
|
+
* $routeSegmentProvider.segment('s1', {
|
91
|
+
* templateUrl: 'templates/section1.html',
|
92
|
+
* controller: MainCtrl});
|
93
|
+
*
|
94
|
+
* $routeSegmentProvider.within('s1').segment('home', {
|
95
|
+
* templateUrl: 'templates/section1/home.html'});
|
96
|
+
*
|
97
|
+
* $routeSegmentProvider.within('s1').segment('itemInfo', {
|
98
|
+
* templateUrl: 'templates/section1/item.html',
|
99
|
+
* controller: Section1ItemCtrl,
|
100
|
+
* dependencies: ['id']});
|
101
|
+
*
|
102
|
+
* $routeSegmentProvider.within('s1').within('itemInfo').segment('overview', {
|
103
|
+
* templateUrl: 'templates/section1/item/overview.html'});
|
104
|
+
* ```
|
105
|
+
*
|
106
|
+
* See {@link appViewSegment appViewSegment} for details on views configuration
|
107
|
+
*/
|
108
|
+
mod.provider( '$routeSegment',
|
109
|
+
['$routeProvider', function $routeSegmentProvider ($routeProvider) {
|
110
|
+
|
111
|
+
var $routeSegmentProvider = this;
|
112
|
+
|
113
|
+
/**
|
114
|
+
* @ngdoc type
|
115
|
+
* @module route-segment
|
116
|
+
* @name $routeSegmentProvider.options
|
117
|
+
* @description Contains configuration options for {@link $routeSegmentProvider $routeSegmentProvider}
|
118
|
+
*/
|
119
|
+
/**
|
120
|
+
* @ngdoc property
|
121
|
+
* @name $routeSegmentProvider#options
|
122
|
+
* @type {$routeSegmentProvider.options}
|
123
|
+
* @description Provider configuration object
|
124
|
+
*/
|
125
|
+
var options = $routeSegmentProvider.options = {
|
126
|
+
|
127
|
+
/**
|
128
|
+
* @ngdoc property
|
129
|
+
* @name $routeSegmentProvider.options#autoLoadTemplates
|
130
|
+
* @type {Boolean}
|
131
|
+
* @description
|
132
|
+
* When true, it will resolve `templateUrl` automatically via ($http)[https://docs.angularjs.org/api/ng/service/$http]
|
133
|
+
* service and put its contents into `template`.
|
134
|
+
*/
|
135
|
+
autoLoadTemplates: true,
|
136
|
+
|
137
|
+
/**
|
138
|
+
* @ngdoc property
|
139
|
+
* @name $routeSegmentProvider.options#strictMode
|
140
|
+
* @type {Boolean}
|
141
|
+
* @description
|
142
|
+
* When true, all attempts to call `within` method on non-existing segments will throw an error (you would
|
143
|
+
* usually want this behavior in production). When false, it will transparently create new empty segment
|
144
|
+
* (can be useful in isolated tests).
|
145
|
+
*/
|
146
|
+
strictMode: false
|
147
|
+
};
|
148
|
+
|
149
|
+
/**
|
150
|
+
* @ngdoc property
|
151
|
+
* @name $routeSegmentProvider#property
|
152
|
+
* @type {Object}
|
153
|
+
* @private
|
154
|
+
* @description Registered routing segments
|
155
|
+
*/
|
156
|
+
var segments = this.segments = {},
|
157
|
+
rootPointer = pointer(segments, null),
|
158
|
+
segmentRoutes = {};
|
159
|
+
|
160
|
+
function camelCase(name) {
|
161
|
+
return name.replace(/([\:\-\_]+(.))/g, function(_, separator, letter, offset) {
|
162
|
+
return offset ? letter.toUpperCase() : letter;
|
163
|
+
});
|
164
|
+
}
|
165
|
+
|
166
|
+
/**
|
167
|
+
* @ngdoc type
|
168
|
+
* @module route-segment
|
169
|
+
* @name $routeSegmentProvider.Pointer
|
170
|
+
* @description Segment traversal element.
|
171
|
+
*
|
172
|
+
* Each {@link $routeSegmentProvider#segment $routeSegmentProvider#segment} call creates new navigation pointer
|
173
|
+
*/
|
174
|
+
function pointer(segment, parent) {
|
175
|
+
|
176
|
+
if(!segment)
|
177
|
+
throw new Error('Invalid pointer segment');
|
178
|
+
|
179
|
+
var lastAddedName;
|
180
|
+
|
181
|
+
return {
|
182
|
+
|
183
|
+
/**
|
184
|
+
* @ngdoc method
|
185
|
+
* @name $routeSegmentProvider#segment
|
186
|
+
* @see $routeSegmentProvider.Pointer#segment
|
187
|
+
*/
|
188
|
+
/**
|
189
|
+
* @ngdoc method
|
190
|
+
* @name $routeSegmentProvider.Pointer#segment
|
191
|
+
* @param {string} name Name of a segment.
|
192
|
+
* @param {Object} params Segment's parameters hash. The following params are supported:
|
193
|
+
* @param {String|Function} [params.template] provides HTML for the given segment view;
|
194
|
+
* @param {String|Function} [params.templateUrl] template to fetch from network via this URL;
|
195
|
+
* @param {String|Function} [params.controller] cotroller attached to the given segment view when compiled and linked,
|
196
|
+
* this can be any controller definition AngularJS supports;
|
197
|
+
* @param {String} [params.controllerAs] controller alias name, if present the controller will be
|
198
|
+
* published to scope under the controllerAs name
|
199
|
+
* @param {Array<String>} [params.dependencies] array of route param names which are forcing the view to recreate when changed;
|
200
|
+
* @param {Function} [params.watcher] $watch-function for recreating the view when its returning value is changed;
|
201
|
+
* @param {Object<String, Function>} resolve hash of functions or injectable names which should be resolved
|
202
|
+
* prior to instantiating the template and the controller;
|
203
|
+
* @param {Object} [params.untilResolved] alternate set of params (e.g. `template` and `controller`)
|
204
|
+
* which should be used before resolving is completed;
|
205
|
+
* @param {Object} [params.resolveFailed] alternate set of params which should be used if resolving failed;
|
206
|
+
* @param {Boolean} [params.default] when set to true this child segment should be loaded by
|
207
|
+
* default when no child is specified in the route.
|
208
|
+
* @returns {$routeSegmentProvider.Pointer} The same level pointer.
|
209
|
+
* @description Adds new segment at current pointer level.
|
210
|
+
*
|
211
|
+
*/
|
212
|
+
segment: function(name, params) {
|
213
|
+
segment[camelCase(name)] = {name: name, params: params};
|
214
|
+
lastAddedName = name;
|
215
|
+
return this;
|
216
|
+
},
|
217
|
+
|
218
|
+
/**
|
219
|
+
* @ngdoc method
|
220
|
+
* @name $routeSegmentProvider#within
|
221
|
+
* @see $routeSegmentProvider.Pointer#within
|
222
|
+
*/
|
223
|
+
/**
|
224
|
+
* @ngdoc method
|
225
|
+
* @name $routeSegmentProvider.Pointer#within
|
226
|
+
* @param {String=} childName An existing segment's name. If undefined, then the last added segment is selected.
|
227
|
+
* @returns {$routeSegmentProvider.Pointer} The pointer to the child segment.
|
228
|
+
* @throws {Error} when {@link $routeSegmentProvider.options#strictMode $routeSegmentProvider.options#strictMode} is true and segment with given name is not found
|
229
|
+
* @description Traverses into an existing segment, so that subsequent `segment` calls
|
230
|
+
* will add new segments as its descendants.
|
231
|
+
*/
|
232
|
+
within: function(childName) {
|
233
|
+
var child;
|
234
|
+
childName = childName || lastAddedName;
|
235
|
+
|
236
|
+
if(child = segment[camelCase(childName)]) {
|
237
|
+
if(child.children == undefined)
|
238
|
+
child.children = {};
|
239
|
+
}
|
240
|
+
else {
|
241
|
+
if(options.strictMode)
|
242
|
+
throw new Error('Cannot get into unknown `'+childName+'` segment');
|
243
|
+
else {
|
244
|
+
child = segment[camelCase(childName)] = {params: {}, children: {}};
|
245
|
+
}
|
246
|
+
}
|
247
|
+
return pointer(child.children, this);
|
248
|
+
},
|
249
|
+
|
250
|
+
/**
|
251
|
+
* @ngdoc method
|
252
|
+
* @name $routeSegmentProvider.Pointer#up
|
253
|
+
* @returns {$routeSegmentProvider.Pointer} The pointer which are parent to the current one;
|
254
|
+
* @description Traverses up in the tree.
|
255
|
+
*/
|
256
|
+
up: function() {
|
257
|
+
return parent;
|
258
|
+
},
|
259
|
+
|
260
|
+
/**
|
261
|
+
* @ngdoc method
|
262
|
+
* @name $routeSegmentProvider.Pointer#up
|
263
|
+
* @returns {$routeSegmentProvider.Pointer} The root pointer.
|
264
|
+
* @description Traverses to the root.
|
265
|
+
*/
|
266
|
+
root: function() {
|
267
|
+
return rootPointer;
|
268
|
+
}
|
269
|
+
}
|
270
|
+
}
|
271
|
+
|
272
|
+
/**
|
273
|
+
* @ngdoc method
|
274
|
+
* @name $routeSegmentProvider#when
|
275
|
+
* @param {String} path Route URL, e.g. '/foo/bar'
|
276
|
+
* @param {String} name Fully qualified route name, e.g. 'foo.bar'
|
277
|
+
* @param {Object} route Mapping information to be assigned to $route.current on route match.
|
278
|
+
* @returns {$routeSegmentProvider} instance
|
279
|
+
* @description The shorthand for [$routeProvider.when()](https://docs.angularjs.org/api/ngRoute/provider/$routeProvider#when) method with specified route name.
|
280
|
+
*/
|
281
|
+
$routeSegmentProvider.when = function(path, name, route) {
|
282
|
+
if (route == undefined)
|
283
|
+
route = {};
|
284
|
+
route.segment = name;
|
285
|
+
|
286
|
+
$routeProvider.when(path, route);
|
287
|
+
segmentRoutes[name] = path;
|
288
|
+
return this;
|
289
|
+
};
|
290
|
+
|
291
|
+
/**
|
292
|
+
* The shorthand for $routeProvider.otherwise() method with specified route.
|
293
|
+
* @param {string|function} route Route URL, e.g. '/'; or function that return a URL
|
294
|
+
*/
|
295
|
+
$routeSegmentProvider.otherwise = function(route) {
|
296
|
+
$routeProvider.otherwise({redirectTo: route});
|
297
|
+
return this;
|
298
|
+
};
|
299
|
+
|
300
|
+
// Extending the provider with the methods of rootPointer
|
301
|
+
// to start configuration.
|
302
|
+
angular.extend($routeSegmentProvider, rootPointer);
|
303
|
+
|
304
|
+
/**
|
305
|
+
* @ngdoc service
|
306
|
+
* @module route-segment
|
307
|
+
* @name $routeSegment
|
308
|
+
* @requires https://docs.angularjs.org/api/ng/service/$rootScope $rootScope
|
309
|
+
* @requires https://docs.angularjs.org/api/ng/service/$q $q
|
310
|
+
* @requires https://docs.angularjs.org/api/ng/service/$http $http
|
311
|
+
* @requires https://docs.angularjs.org/api/ng/service/$templateCache $templateCache
|
312
|
+
* @requires https://docs.angularjs.org/api/ngRoute/service/$route $route
|
313
|
+
* @requires https://docs.angularjs.org/api/ngRoute/service/$routeParams $routeParams
|
314
|
+
* @requires https://docs.angularjs.org/api/auto/service/$injector $injector
|
315
|
+
* @requires https://docs.angularjs.org/api/ng/service/$location $location
|
316
|
+
* @description Provides state and operations for the current segment
|
317
|
+
*/
|
318
|
+
this.$get = ['$rootScope', '$q', '$http', '$templateCache', '$route', '$routeParams', '$injector',
|
319
|
+
function($rootScope, $q, $http, $templateCache, $route, $routeParams, $injector) {
|
320
|
+
|
321
|
+
var $routeSegment = {
|
322
|
+
|
323
|
+
/**
|
324
|
+
* @ngdoc property
|
325
|
+
* @name $routeSegment#name
|
326
|
+
* @type {String}
|
327
|
+
* @description Fully qualified name of current active route
|
328
|
+
*/
|
329
|
+
name: '',
|
330
|
+
|
331
|
+
/**
|
332
|
+
* @ngdoc property
|
333
|
+
* @name $routeSegment#$routeParams
|
334
|
+
* @type {Object}
|
335
|
+
* @description A copy of `$routeParams` in its state of the latest successful segment update.
|
336
|
+
*
|
337
|
+
* It may be not equal to `$routeParams` while some resolving is not completed yet. Should be used instead of original
|
338
|
+
* `$routeParams` in most cases.
|
339
|
+
*/
|
340
|
+
$routeParams: angular.copy($routeParams),
|
341
|
+
|
342
|
+
/**
|
343
|
+
* @ngdoc property
|
344
|
+
* @name $routeSegment#chain
|
345
|
+
* @type {Array.<$routeSegment.Segment>}
|
346
|
+
* @description Array of segments splitted by each level separately. Each item contains the following properties:
|
347
|
+
*
|
348
|
+
* - `name` is the name of a segment;
|
349
|
+
* - `params` is the config params hash of a segment;
|
350
|
+
* - `locals` is a hash which contains resolve results if any;
|
351
|
+
* - `reload` is a function to reload a segment (restart resolving, reinstantiate a controller, etc)
|
352
|
+
*/
|
353
|
+
chain: [],
|
354
|
+
|
355
|
+
/**
|
356
|
+
* @ngdoc method
|
357
|
+
* @name $routeSegment#startsWith
|
358
|
+
* @param {String} val segment name to test
|
359
|
+
* @returns {Boolean}
|
360
|
+
* @description Helper method for checking whether current route starts with the given string
|
361
|
+
*/
|
362
|
+
startsWith: function (val) {
|
363
|
+
var regexp = new RegExp('^'+val);
|
364
|
+
return regexp.test($routeSegment.name);
|
365
|
+
},
|
366
|
+
|
367
|
+
/**
|
368
|
+
* @ngdoc method
|
369
|
+
* @name $routeSegment#contains
|
370
|
+
* @param {String} val segment name to test
|
371
|
+
* @returns {Boolean} true if given segment present in the current route
|
372
|
+
* @description Helper method for checking whether current route contains the given string
|
373
|
+
*/
|
374
|
+
contains: function (val) {
|
375
|
+
for(var i=0; i<this.chain.length; i++)
|
376
|
+
if(this.chain[i] && this.chain[i].name == val)
|
377
|
+
return true;
|
378
|
+
return false;
|
379
|
+
},
|
380
|
+
|
381
|
+
/**
|
382
|
+
* @ngdoc method
|
383
|
+
* @name $routeSegment#getSegmentUrl
|
384
|
+
* @param {String} segmentName The name of a segment as defined in `when()`
|
385
|
+
* @param {Object} routeParams Route params hash to be put into route URL template
|
386
|
+
* @returns {String} segment url
|
387
|
+
* @throws {Error} if url for the given name is not found
|
388
|
+
* @description A method for reverse routing which can return the route URL for the specified segment name
|
389
|
+
*/
|
390
|
+
getSegmentUrl: function(segmentName, routeParams) {
|
391
|
+
var url, i, m;
|
392
|
+
if(!segmentRoutes[segmentName])
|
393
|
+
throw new Error('Can not get URL for segment with name `'+segmentName+'`');
|
394
|
+
|
395
|
+
routeParams = angular.extend({}, $routeParams, routeParams || {});
|
396
|
+
|
397
|
+
url = segmentRoutes[segmentName];
|
398
|
+
for(i in routeParams) {
|
399
|
+
var regexp = new RegExp('\:'+i+'[\*\?]?','g');
|
400
|
+
url = url.replace(regexp, routeParams[i]);
|
401
|
+
}
|
402
|
+
url = url.replace(/\/\:.*?\?/g, '');
|
403
|
+
|
404
|
+
if(m = url.match(/\/\:([^\/]*)/))
|
405
|
+
throw new Error('Route param `'+m[1]+'` is not specified for route `'+segmentRoutes[segmentName]+'`');
|
406
|
+
|
407
|
+
return url;
|
408
|
+
}
|
409
|
+
};
|
410
|
+
|
411
|
+
var resolvingSemaphoreChain = {};
|
412
|
+
|
413
|
+
// When a route changes, all interested parties should be notified about new segment chain
|
414
|
+
$rootScope.$on('$routeChangeSuccess', function(event, args) {
|
415
|
+
|
416
|
+
var route = args.$route || args.$$route;
|
417
|
+
if(route && route.segment) {
|
418
|
+
|
419
|
+
var segmentName = route.segment;
|
420
|
+
var segmentNameChain = segmentName.split(".");
|
421
|
+
var updates = [], lastUpdateIndex = -1;
|
422
|
+
|
423
|
+
for(var i=0; i < segmentNameChain.length; i++) {
|
424
|
+
|
425
|
+
var newSegment = getSegmentInChain( i, segmentNameChain );
|
426
|
+
|
427
|
+
if(resolvingSemaphoreChain[i] != newSegment.name || updates.length > 0 || isDependenciesChanged(newSegment)) {
|
428
|
+
|
429
|
+
if($routeSegment.chain[i] && $routeSegment.chain[i].name == newSegment.name &&
|
430
|
+
updates.length == 0 && !isDependenciesChanged(newSegment))
|
431
|
+
// if we went back to the same state as we were before resolving new segment
|
432
|
+
resolvingSemaphoreChain[i] = newSegment.name;
|
433
|
+
else {
|
434
|
+
updates.push({index: i, newSegment: newSegment});
|
435
|
+
lastUpdateIndex = i;
|
436
|
+
}
|
437
|
+
}
|
438
|
+
}
|
439
|
+
|
440
|
+
var curSegmentPromise = $q.when();
|
441
|
+
|
442
|
+
if(updates.length > 0) {
|
443
|
+
|
444
|
+
for(var i=0; i<updates.length; i++) {
|
445
|
+
(function(i) {
|
446
|
+
curSegmentPromise = curSegmentPromise.then(function() {
|
447
|
+
|
448
|
+
return updateSegment(updates[i].index, updates[i].newSegment);
|
449
|
+
|
450
|
+
}).then(function(result) {
|
451
|
+
|
452
|
+
if(result.success != undefined) {
|
453
|
+
|
454
|
+
broadcast(result.success);
|
455
|
+
|
456
|
+
for(var j = updates[i].index + 1; j < $routeSegment.chain.length; j++) {
|
457
|
+
|
458
|
+
if($routeSegment.chain[j]) {
|
459
|
+
if ($routeSegment.chain[j].clearWatcher) {
|
460
|
+
$routeSegment.chain[j].clearWatcher();
|
461
|
+
}
|
462
|
+
|
463
|
+
$routeSegment.chain[j] = null;
|
464
|
+
updateSegment(j, null);
|
465
|
+
}
|
466
|
+
}
|
467
|
+
}
|
468
|
+
})
|
469
|
+
})(i);
|
470
|
+
}
|
471
|
+
}
|
472
|
+
|
473
|
+
curSegmentPromise.then(function() {
|
474
|
+
|
475
|
+
// Removing redundant segment in case if new segment chain is shorter than old one
|
476
|
+
if($routeSegment.chain.length > segmentNameChain.length) {
|
477
|
+
var oldLength = $routeSegment.chain.length;
|
478
|
+
var shortenBy = $routeSegment.chain.length - segmentNameChain.length;
|
479
|
+
$routeSegment.chain.splice(-shortenBy, shortenBy);
|
480
|
+
for(var i=segmentNameChain.length; i < oldLength; i++) {
|
481
|
+
updateSegment(i, null);
|
482
|
+
lastUpdateIndex = $routeSegment.chain.length-1;
|
483
|
+
}
|
484
|
+
}
|
485
|
+
}).then(function() {
|
486
|
+
|
487
|
+
var defaultChildUpdatePromise = $q.when();
|
488
|
+
|
489
|
+
if(lastUpdateIndex == $routeSegment.chain.length-1) {
|
490
|
+
|
491
|
+
var curSegment = getSegmentInChain(lastUpdateIndex, $routeSegment.name.split("."));
|
492
|
+
|
493
|
+
while(curSegment) {
|
494
|
+
var children = curSegment.children, index = lastUpdateIndex+1;
|
495
|
+
curSegment = null;
|
496
|
+
for (var i in children) {
|
497
|
+
(function(i, children, index) {
|
498
|
+
if (children[i].params['default']) {
|
499
|
+
defaultChildUpdatePromise = defaultChildUpdatePromise.then(function () {
|
500
|
+
return updateSegment(index, {name: children[i].name, params: children[i].params})
|
501
|
+
.then(function (result) {
|
502
|
+
if (result.success) broadcast(result.success);
|
503
|
+
});
|
504
|
+
});
|
505
|
+
curSegment = children[i];
|
506
|
+
lastUpdateIndex = index;
|
507
|
+
}
|
508
|
+
})(i, children, index);
|
509
|
+
|
510
|
+
|
511
|
+
}
|
512
|
+
}
|
513
|
+
}
|
514
|
+
|
515
|
+
return defaultChildUpdatePromise;
|
516
|
+
});
|
517
|
+
}
|
518
|
+
});
|
519
|
+
|
520
|
+
function isDependenciesChanged(segment) {
|
521
|
+
|
522
|
+
var result = false;
|
523
|
+
if(segment.params.dependencies)
|
524
|
+
angular.forEach(segment.params.dependencies, function(name) {
|
525
|
+
if(!angular.equals($routeSegment.$routeParams[name], $routeParams[name]))
|
526
|
+
result = true;
|
527
|
+
});
|
528
|
+
return result;
|
529
|
+
}
|
530
|
+
|
531
|
+
function updateSegment(index, segment) {
|
532
|
+
|
533
|
+
if($routeSegment.chain[index] && $routeSegment.chain[index].clearWatcher) {
|
534
|
+
$routeSegment.chain[index].clearWatcher();
|
535
|
+
}
|
536
|
+
|
537
|
+
if(!segment) {
|
538
|
+
resolvingSemaphoreChain[index] = null;
|
539
|
+
broadcast(index);
|
540
|
+
return;
|
541
|
+
}
|
542
|
+
|
543
|
+
resolvingSemaphoreChain[index] = segment.name;
|
544
|
+
|
545
|
+
if(segment.params.untilResolved) {
|
546
|
+
return resolve(index, segment.name, segment.params.untilResolved)
|
547
|
+
.then(function(result) {
|
548
|
+
if(result.success != undefined)
|
549
|
+
broadcast(index);
|
550
|
+
return resolve(index, segment.name, segment.params);
|
551
|
+
})
|
552
|
+
}
|
553
|
+
else
|
554
|
+
return resolve(index, segment.name, segment.params);
|
555
|
+
}
|
556
|
+
|
557
|
+
function resolve(index, name, params) {
|
558
|
+
|
559
|
+
var locals = angular.extend({}, params.resolve);
|
560
|
+
|
561
|
+
angular.forEach(locals, function(value, key) {
|
562
|
+
locals[key] = angular.isString(value) ? $injector.get(value) : $injector.invoke(value);
|
563
|
+
});
|
564
|
+
|
565
|
+
if(params.template) {
|
566
|
+
|
567
|
+
locals.$template = params.template;
|
568
|
+
if(angular.isFunction(locals.$template))
|
569
|
+
locals.$template = $injector.invoke(locals.$template);
|
570
|
+
}
|
571
|
+
|
572
|
+
if(options.autoLoadTemplates && params.templateUrl) {
|
573
|
+
|
574
|
+
locals.$template = params.templateUrl;
|
575
|
+
if(angular.isFunction(locals.$template))
|
576
|
+
locals.$template = $injector.invoke(locals.$template);
|
577
|
+
|
578
|
+
locals.$template =
|
579
|
+
$http.get(locals.$template, {cache: $templateCache})
|
580
|
+
.then(function (response) {
|
581
|
+
return response.data;
|
582
|
+
});
|
583
|
+
}
|
584
|
+
|
585
|
+
return $q.all(locals).then(
|
586
|
+
|
587
|
+
function(resolvedLocals) {
|
588
|
+
|
589
|
+
if(resolvingSemaphoreChain[index] != name)
|
590
|
+
return $q.reject();
|
591
|
+
|
592
|
+
/**
|
593
|
+
* @ngdoc type
|
594
|
+
* @module route-segment
|
595
|
+
* @name $routeSegment.Segment
|
596
|
+
* @description Segment record
|
597
|
+
*/
|
598
|
+
$routeSegment.chain[index] = {
|
599
|
+
/**
|
600
|
+
* @ngdoc property
|
601
|
+
* @name $routeSegment.Segment#name
|
602
|
+
* @type {String}
|
603
|
+
* @description segment name as registered with {@link $routeSegmentProvider#segment $routeSegmentProvider#segment}
|
604
|
+
*/
|
605
|
+
name: name,
|
606
|
+
/**
|
607
|
+
* @ngdoc property
|
608
|
+
* @name $routeSegment.Segment#params
|
609
|
+
* @type {Object=}
|
610
|
+
* @description [$routeParams](https://docs.angularjs.org/api/ngRoute/provider/$routeProvider) parameters for segment
|
611
|
+
*/
|
612
|
+
params: params,
|
613
|
+
/**
|
614
|
+
* @ngdoc property
|
615
|
+
* @name $routeSegment.Segment#locals
|
616
|
+
* @type {Object=}
|
617
|
+
* @description resolved segment data
|
618
|
+
*/
|
619
|
+
locals: resolvedLocals,
|
620
|
+
/**
|
621
|
+
* @ngdoc method
|
622
|
+
* @name $routeSegment.Segment#reload
|
623
|
+
* @description reloads current segment from scratch
|
624
|
+
*/
|
625
|
+
reload: function() {
|
626
|
+
var originalSegment = getSegmentInChain(index, $routeSegment.name.split("."));
|
627
|
+
updateSegment(index, originalSegment).then(function(result) {
|
628
|
+
if(result.success != undefined)
|
629
|
+
broadcast(index);
|
630
|
+
})
|
631
|
+
}
|
632
|
+
};
|
633
|
+
|
634
|
+
if(params.watcher) {
|
635
|
+
|
636
|
+
var getWatcherValue = function() {
|
637
|
+
if(!angular.isFunction(params.watcher) && !angular.isArray(params.watcher))
|
638
|
+
throw new Error('Watcher is not a function in segment `'+name+'`');
|
639
|
+
|
640
|
+
return $injector.invoke(
|
641
|
+
params.watcher,
|
642
|
+
{},
|
643
|
+
{segment: $routeSegment.chain[index]});
|
644
|
+
}
|
645
|
+
|
646
|
+
var lastWatcherValue = getWatcherValue();
|
647
|
+
|
648
|
+
$routeSegment.chain[index].clearWatcher = $rootScope.$watch(
|
649
|
+
getWatcherValue,
|
650
|
+
function(value) {
|
651
|
+
if(value == lastWatcherValue) // should not being run when $digest-ing at first time
|
652
|
+
return;
|
653
|
+
lastWatcherValue = value;
|
654
|
+
$routeSegment.chain[index].reload();
|
655
|
+
})
|
656
|
+
}
|
657
|
+
|
658
|
+
return {success: index};
|
659
|
+
},
|
660
|
+
|
661
|
+
function(error) {
|
662
|
+
|
663
|
+
if(params.resolveFailed) {
|
664
|
+
var newResolve = {error: function() { return $q.when(error); }};
|
665
|
+
return resolve(index, name, angular.extend({resolve: newResolve}, params.resolveFailed));
|
666
|
+
}
|
667
|
+
else
|
668
|
+
throw new Error('Resolving failed with a reason `'+error+'`, but no `resolveFailed` ' +
|
669
|
+
'provided for segment `'+name+'`');
|
670
|
+
})
|
671
|
+
}
|
672
|
+
|
673
|
+
function broadcast(index) {
|
674
|
+
|
675
|
+
$routeSegment.$routeParams = angular.copy($routeParams);
|
676
|
+
|
677
|
+
$routeSegment.name = '';
|
678
|
+
for(var i=0; i<$routeSegment.chain.length; i++)
|
679
|
+
if($routeSegment.chain[i])
|
680
|
+
$routeSegment.name += $routeSegment.chain[i].name+".";
|
681
|
+
$routeSegment.name = $routeSegment.name.substr(0, $routeSegment.name.length-1);
|
682
|
+
|
683
|
+
/**
|
684
|
+
* @ngdoc event
|
685
|
+
* @name $routeSegment#routeSegmentChange
|
686
|
+
* @eventType broadcast on $rootScope
|
687
|
+
* @param {Object} object object containing
|
688
|
+
* - `index` {number} index id in {@link $routeSegment#chain $routeSegment#chain}
|
689
|
+
* - segment {$routeSegment.Segment|Null} current segment
|
690
|
+
* @description event is thrown when segment is loaded
|
691
|
+
*/
|
692
|
+
$rootScope.$broadcast( 'routeSegmentChange', {
|
693
|
+
index: index,
|
694
|
+
segment: $routeSegment.chain[index] || null } );
|
695
|
+
}
|
696
|
+
|
697
|
+
function getSegmentInChain(segmentIdx, segmentNameChain) {
|
698
|
+
|
699
|
+
if(!segmentNameChain)
|
700
|
+
return null;
|
701
|
+
|
702
|
+
if(segmentIdx >= segmentNameChain.length)
|
703
|
+
return null;
|
704
|
+
|
705
|
+
var curSegment = segments, nextName;
|
706
|
+
for(var i=0;i<=segmentIdx;i++) {
|
707
|
+
|
708
|
+
nextName = segmentNameChain[i];
|
709
|
+
|
710
|
+
if(curSegment[ camelCase(nextName) ] != undefined)
|
711
|
+
curSegment = curSegment[ camelCase(nextName) ];
|
712
|
+
|
713
|
+
if(i < segmentIdx)
|
714
|
+
curSegment = curSegment.children;
|
715
|
+
}
|
716
|
+
|
717
|
+
return {
|
718
|
+
name: nextName,
|
719
|
+
params: curSegment.params,
|
720
|
+
children: curSegment.children
|
721
|
+
};
|
722
|
+
}
|
723
|
+
|
724
|
+
return $routeSegment;
|
725
|
+
}];
|
726
|
+
}]);
|
727
|
+
|
728
|
+
/**
|
729
|
+
* @ngdoc filter
|
730
|
+
* @module route-segment
|
731
|
+
* @name routeSegmentUrl
|
732
|
+
* @param {String} name fully qualified segment name
|
733
|
+
* @param {Object} params params to resolve segment
|
734
|
+
* @returns {string} given url
|
735
|
+
* @description Returns url for a given segment
|
736
|
+
*
|
737
|
+
* Usage:
|
738
|
+
* ```html
|
739
|
+
* <a ng-href="{{ 'index.list' | routeSegmentUrl }}">
|
740
|
+
* <a ng-href="{{ 'index.list.itemInfo' | routeSegmentUrl: {id: 123} }}">
|
741
|
+
* ```
|
742
|
+
*/
|
743
|
+
mod.filter('routeSegmentUrl', ['$routeSegment', function($routeSegment) {
|
744
|
+
var filter = function(segmentName, params) {
|
745
|
+
return $routeSegment.getSegmentUrl(segmentName, params);
|
746
|
+
};
|
747
|
+
filter.$stateful = true;
|
748
|
+
return filter;
|
749
|
+
}]);
|
750
|
+
|
751
|
+
/**
|
752
|
+
* @ngdoc filter
|
753
|
+
* @module route-segment
|
754
|
+
* @name routeSegmentEqualsTo
|
755
|
+
* @param {String} name fully qualified segment name
|
756
|
+
* @returns {boolean} true if given segment name is the active one
|
757
|
+
* @description Check whether active segment equals to the given segment name
|
758
|
+
*
|
759
|
+
* Usage:
|
760
|
+
* ```html
|
761
|
+
* <li ng-class="{active: ('index.list' | routeSegmentEqualsTo)}">
|
762
|
+
* ```
|
763
|
+
*/
|
764
|
+
mod.filter('routeSegmentEqualsTo', ['$routeSegment', function($routeSegment) {
|
765
|
+
var filter = function(value) {
|
766
|
+
return $routeSegment.name == value;
|
767
|
+
};
|
768
|
+
filter.$stateful = true;
|
769
|
+
return filter;
|
770
|
+
}]);
|
771
|
+
|
772
|
+
/**
|
773
|
+
* @ngdoc filter
|
774
|
+
* @module route-segment
|
775
|
+
* @name routeSegmentStartsWith
|
776
|
+
* @param {String} name segment name
|
777
|
+
* @returns {boolean} true if active segment name begins with given name
|
778
|
+
* @description Check whether active segment starts with the given segment name
|
779
|
+
*
|
780
|
+
* Usage:
|
781
|
+
* ```html
|
782
|
+
* <li ng-class="{active: ('section1' | routeSegmentStartsWith)}">
|
783
|
+
* ```
|
784
|
+
*/
|
785
|
+
mod.filter('routeSegmentStartsWith', ['$routeSegment', function($routeSegment) {
|
786
|
+
var filter = function(value) {
|
787
|
+
return $routeSegment.startsWith(value);
|
788
|
+
};
|
789
|
+
filter.$stateful = true;
|
790
|
+
return filter;
|
791
|
+
}]);
|
792
|
+
|
793
|
+
/**
|
794
|
+
* @ngdoc filter
|
795
|
+
* @module route-segment
|
796
|
+
* @name routeSegmentContains
|
797
|
+
* @param {String} name segment name
|
798
|
+
* @returns {boolean} true if active segment contains given name
|
799
|
+
* @description Check whether active segment contains the given segment name
|
800
|
+
*
|
801
|
+
* Usage:
|
802
|
+
* ```html
|
803
|
+
* <li ng-class="{active: ('itemInfo' | routeSegmentContains)}">
|
804
|
+
* ```
|
805
|
+
*/
|
806
|
+
mod.filter('routeSegmentContains', ['$routeSegment', function($routeSegment) {
|
807
|
+
var filter = function(value) {
|
808
|
+
return $routeSegment.contains(value);
|
809
|
+
};
|
810
|
+
filter.$stateful = true;
|
811
|
+
return filter;
|
812
|
+
}]);
|
813
|
+
|
814
|
+
/**
|
815
|
+
* @ngdoc filter
|
816
|
+
* @module route-segment
|
817
|
+
* @name routeSegmentParam
|
818
|
+
* @param {String} name param name
|
819
|
+
* @returns {string|undefined} param value or undefined
|
820
|
+
* @description Returns segment parameter by name
|
821
|
+
*
|
822
|
+
* Usage:
|
823
|
+
* ```html
|
824
|
+
* <li ng-class="{active: ('index.list.itemInfo' | routeSegmentEqualsTo) && ('id' | routeSegmentParam) == 123}">
|
825
|
+
* ```
|
826
|
+
*/
|
827
|
+
mod.filter('routeSegmentParam', ['$routeSegment', function($routeSegment) {
|
828
|
+
var filter = function(value) {
|
829
|
+
return $routeSegment.$routeParams[value];
|
830
|
+
};
|
831
|
+
filter.$stateful = true;
|
832
|
+
return filter;
|
833
|
+
}]);
|
834
|
+
|
835
|
+
|
836
|
+
})(angular);;'use strict';
|
837
|
+
|
838
|
+
/**
|
839
|
+
* @ngdoc module
|
840
|
+
* @module view-segment
|
841
|
+
* @name view-segment
|
842
|
+
* @packageName angular-route-segment
|
843
|
+
* @requires route-segment
|
844
|
+
* @description
|
845
|
+
* view-segment is a replacement for [ngView](https://docs.angularjs.org/api/ngRoute/directive/ngView) AngularJS directive.
|
846
|
+
*
|
847
|
+
* {@link appViewSegment appViewSegment} tags in the DOM will be populated with the corresponding route segment item.
|
848
|
+
* You must provide a segment index as an argument to this directive to make it aware about which segment level in the tree
|
849
|
+
* it should be linked to.
|
850
|
+
*
|
851
|
+
* *index.html*:
|
852
|
+
* ```html
|
853
|
+
* <ul>
|
854
|
+
* <li ng-class="{active: $routeSegment.startsWith('s1')}">
|
855
|
+
* <a href="/section1">Section 1</a>
|
856
|
+
* </li>
|
857
|
+
* <li ng-class="{active: $routeSegment.startsWith('s2')}">
|
858
|
+
* <a href="/section2">Section 2</a>
|
859
|
+
* </li>
|
860
|
+
* </ul>
|
861
|
+
* <div id="contents" app-view-segment="0"></div>
|
862
|
+
* ```
|
863
|
+
*
|
864
|
+
* *section1.html*: (it will be loaded to div#contents in index.html)
|
865
|
+
* ```html
|
866
|
+
* <h4>Section 1</h4>
|
867
|
+
* Section 1 contents.
|
868
|
+
* <div app-view-segment="1"></div>
|
869
|
+
* ```
|
870
|
+
*
|
871
|
+
* ...etc. You can reach any nesting level here. Every view will be handled independently, keeping the state of top-level views.
|
872
|
+
*
|
873
|
+
* You can also use filters to define link hrefs. It will resolve segment URLs automatically:
|
874
|
+
*
|
875
|
+
* ```html
|
876
|
+
* <ul>
|
877
|
+
* <li ng-class="{active: ('s1' | routeSegmentStartsWith)}">
|
878
|
+
* <a href="{{ 's1' | routeSegmentUrl }}">Section 1</a>
|
879
|
+
* </li>
|
880
|
+
* <li ng-class="{active: ('s2' | routeSegmentStartsWith)}">
|
881
|
+
* <a href="{{ 's2' | routeSegmentUrl }}">Section 2</a>
|
882
|
+
* </li>
|
883
|
+
* </ul>
|
884
|
+
* ```
|
885
|
+
*/
|
886
|
+
/**
|
887
|
+
* @ngdoc directive
|
888
|
+
* @module view-segment
|
889
|
+
* @name appViewSegment
|
890
|
+
* @requires https://docs.angularjs.org/api/ngRoute/service/$route $route
|
891
|
+
* @requires https://docs.angularjs.org/api/ng/service/$compile $compile
|
892
|
+
* @requires https://docs.angularjs.org/api/ng/service/$controller $controller
|
893
|
+
* @requires https://docs.angularjs.org/api/ngRoute/service/$routeParams $routeParams
|
894
|
+
* @requires $routeSegment
|
895
|
+
* @requires https://docs.angularjs.org/api/ng/service/$q $q
|
896
|
+
* @requires https://docs.angularjs.org/api/auto/service/$injector $injector
|
897
|
+
* @requires https://docs.angularjs.org/api/ng/service/$timeout $timeout
|
898
|
+
* @requires https://docs.angularjs.org/api/ng/service/$animate $animate
|
899
|
+
* @restrict ECA
|
900
|
+
* @priority 400
|
901
|
+
* @param {String} appViewSegment render depth level
|
902
|
+
* @description Renders active segment as specified by parameter
|
903
|
+
*
|
904
|
+
* It is based on [ngView directive code](https://github.com/angular/angular.js/blob/master/src/ngRoute/directive/ngView.js)
|
905
|
+
*/
|
906
|
+
|
907
|
+
(function(angular) {
|
908
|
+
|
909
|
+
angular.module( 'view-segment', [ 'route-segment' ] ).directive( 'appViewSegment',
|
910
|
+
['$route', '$compile', '$controller', '$routeParams', '$routeSegment', '$q', '$injector', '$timeout', '$animate',
|
911
|
+
function($route, $compile, $controller, $routeParams, $routeSegment, $q, $injector, $timeout, $animate) {
|
912
|
+
|
913
|
+
return {
|
914
|
+
restrict : 'ECA',
|
915
|
+
priority: 400,
|
916
|
+
transclude: 'element',
|
917
|
+
|
918
|
+
compile : function(tElement, tAttrs) {
|
919
|
+
|
920
|
+
return function($scope, element, attrs, ctrl, $transclude) {
|
921
|
+
|
922
|
+
var currentScope, currentElement, currentSegment = {}, onloadExp = tAttrs.onload || '',
|
923
|
+
viewSegmentIndex = parseInt(tAttrs.appViewSegment), updatePromise, previousLeaveAnimation;
|
924
|
+
|
925
|
+
if($routeSegment.chain[viewSegmentIndex]) {
|
926
|
+
updatePromise = $timeout(function () {
|
927
|
+
update($routeSegment.chain[viewSegmentIndex]);
|
928
|
+
}, 0);
|
929
|
+
}
|
930
|
+
else {
|
931
|
+
update();
|
932
|
+
}
|
933
|
+
|
934
|
+
// Watching for the specified route segment and updating contents
|
935
|
+
$scope.$on('routeSegmentChange', function(event, args) {
|
936
|
+
|
937
|
+
if(updatePromise)
|
938
|
+
$timeout.cancel(updatePromise);
|
939
|
+
|
940
|
+
if(args.index == viewSegmentIndex && currentSegment != args.segment) {
|
941
|
+
update(args.segment);
|
942
|
+
}
|
943
|
+
});
|
944
|
+
|
945
|
+
function clearContent() {
|
946
|
+
if (previousLeaveAnimation) {
|
947
|
+
$animate.cancel(previousLeaveAnimation);
|
948
|
+
previousLeaveAnimation = null;
|
949
|
+
}
|
950
|
+
|
951
|
+
if (currentScope) {
|
952
|
+
currentScope.$destroy();
|
953
|
+
currentScope = null;
|
954
|
+
}
|
955
|
+
if (currentElement) {
|
956
|
+
previousLeaveAnimation = $animate.leave(currentElement);
|
957
|
+
if(previousLeaveAnimation) {
|
958
|
+
previousLeaveAnimation.then(function () {
|
959
|
+
previousLeaveAnimation = null;
|
960
|
+
});
|
961
|
+
}
|
962
|
+
currentElement = null;
|
963
|
+
}
|
964
|
+
}
|
965
|
+
|
966
|
+
function update(segment) {
|
967
|
+
|
968
|
+
currentSegment = segment;
|
969
|
+
|
970
|
+
var newScope = $scope.$new();
|
971
|
+
|
972
|
+
var clone = $transclude(newScope, function(clone) {
|
973
|
+
if(segment) {
|
974
|
+
clone.data('viewSegment', segment);
|
975
|
+
}
|
976
|
+
$animate.enter(clone, null, currentElement || element);
|
977
|
+
clearContent();
|
978
|
+
});
|
979
|
+
|
980
|
+
currentElement = clone;
|
981
|
+
currentScope = newScope;
|
982
|
+
/*
|
983
|
+
* @ngdoc event
|
984
|
+
* @name appViewSegment#$viewContentLoaded
|
985
|
+
* @description Indicates that segment content has been loaded and transcluded
|
986
|
+
*/
|
987
|
+
currentScope.$emit('$viewContentLoaded');
|
988
|
+
currentScope.$eval(onloadExp);
|
989
|
+
}
|
990
|
+
}
|
991
|
+
}
|
992
|
+
}
|
993
|
+
}]);
|
994
|
+
|
995
|
+
angular.module( 'view-segment').directive( 'appViewSegment',
|
996
|
+
['$route', '$compile', '$controller', function($route, $compile, $controller) {
|
997
|
+
|
998
|
+
return {
|
999
|
+
restrict: 'ECA',
|
1000
|
+
priority: -400,
|
1001
|
+
link: function ($scope, element) {
|
1002
|
+
|
1003
|
+
var segment = element.data('viewSegment') || {};
|
1004
|
+
|
1005
|
+
var locals = angular.extend({}, segment.locals),
|
1006
|
+
template = locals && locals.$template;
|
1007
|
+
|
1008
|
+
if(template) {
|
1009
|
+
element.html(template);
|
1010
|
+
}
|
1011
|
+
|
1012
|
+
var link = $compile(element.contents());
|
1013
|
+
|
1014
|
+
if (segment.params && segment.params.controller) {
|
1015
|
+
locals.$scope = $scope;
|
1016
|
+
var controller = $controller(segment.params.controller, locals);
|
1017
|
+
if(segment.params.controllerAs)
|
1018
|
+
$scope[segment.params.controllerAs] = controller;
|
1019
|
+
element.data('$ngControllerController', controller);
|
1020
|
+
element.children().data('$ngControllerController', controller);
|
1021
|
+
}
|
1022
|
+
|
1023
|
+
link($scope);
|
1024
|
+
}
|
1025
|
+
}
|
1026
|
+
|
1027
|
+
}]);
|
1028
|
+
|
1029
|
+
})(angular);
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: angular-route-segment-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- alekseenko
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: angularjs-rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Injects angular-route-segment module into your asset pipeline.
|
28
|
+
email: mailto.alekseenko@gmail.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- MIT-LICENSE
|
34
|
+
- README.md
|
35
|
+
- lib/angular-route-segment-rails.rb
|
36
|
+
- lib/angular-route-segment-rails/engine.rb
|
37
|
+
- lib/angular-route-segment-rails/sprockets.rb
|
38
|
+
- lib/angular-route-segment-rails/version.rb
|
39
|
+
- vendor/assets/javascripts/angular-route-segment.js
|
40
|
+
homepage: https://github.com/alekseenko/angular-route-segment-rails/
|
41
|
+
licenses:
|
42
|
+
- MIT
|
43
|
+
metadata: {}
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 2.5.1
|
61
|
+
signing_key:
|
62
|
+
specification_version: 4
|
63
|
+
summary: angular-route-segment for Rails
|
64
|
+
test_files: []
|