@@ -249,6 +249,24 @@ function $StateRefDynamicDirective($state, $timeout) {
249
249
* </li>
250
250
* </ul>
251
251
* </pre>
252
+ *
253
+ * It is also possible to pass ui-sref-active an expression that evaluates
254
+ * to an object hash, whose keys represent active class names and whose
255
+ * values represent the respective state names/globs.
256
+ * ui-sref-active will match if the current active state **includes** any of
257
+ * the specified state names/globs, even the abstract ones.
258
+ *
259
+ * @Example
260
+ * Given the following template, with "admin" being an abstract state:
261
+ * <pre>
262
+ * <div ui-sref-active="{'active': 'admin.*'}">
263
+ * <a ui-sref-active="active" ui-sref="admin.roles">Roles</a>
264
+ * </div>
265
+ * </pre>
266
+ *
267
+ * When the current state is "admin.roles" the "active" class will be applied
268
+ * to both the <div> and <a> elements. It is important to note that the state
269
+ * names/globs passed to ui-sref-active shadow the state provided by ui-sref.
252
270
*/
253
271
254
272
/**
@@ -271,35 +289,75 @@ function $StateRefActiveDirective($state, $stateParams, $interpolate) {
271
289
return {
272
290
restrict : "A" ,
273
291
controller : [ '$scope' , '$element' , '$attrs' , '$timeout' , function ( $scope , $element , $attrs , $timeout ) {
274
- var states = [ ] , activeClass , activeEqClass ;
292
+ var states = [ ] , activeClasses = { } , activeEqClass ;
275
293
276
294
// There probably isn't much point in $observing this
277
295
// uiSrefActive and uiSrefActiveEq share the same directive object with some
278
296
// slight difference in logic routing
279
- activeClass = $interpolate ( $attrs . uiSrefActive || '' , false ) ( $scope ) ;
280
297
activeEqClass = $interpolate ( $attrs . uiSrefActiveEq || '' , false ) ( $scope ) ;
281
298
299
+ var uiSrefActive = $scope . $eval ( $attrs . uiSrefActive ) || $interpolate ( $attrs . uiSrefActive || '' , false ) ( $scope ) ;
300
+ if ( isObject ( uiSrefActive ) ) {
301
+ forEach ( uiSrefActive , function ( stateOrName , activeClass ) {
302
+ if ( isString ( stateOrName ) ) {
303
+ var ref = parseStateRef ( stateOrName , $state . current . name ) ;
304
+ addState ( ref . state , $scope . $eval ( ref . paramExpr ) , activeClass ) ;
305
+ }
306
+ } ) ;
307
+ }
308
+
282
309
// Allow uiSref to communicate with uiSrefActive[Equals]
283
310
this . $$addStateInfo = function ( newState , newParams ) {
284
- var state = $state . get ( newState , stateContext ( $element ) ) ;
311
+ // we already got an explicit state provided by ui-sref-active, so we
312
+ // shadow the one that comes from ui-sref
313
+ if ( isObject ( uiSrefActive ) && states . length > 0 ) {
314
+ return ;
315
+ }
316
+ addState ( newState , newParams , uiSrefActive ) ;
317
+ update ( ) ;
318
+ } ;
319
+
320
+ $scope . $on ( '$stateChangeSuccess' , update ) ;
321
+
322
+ function addState ( stateName , stateParams , activeClass ) {
323
+ var state = $state . get ( stateName , stateContext ( $element ) ) ;
324
+ var stateHash = createStateHash ( stateName , stateParams ) ;
285
325
286
326
states . push ( {
287
- state : state || { name : newState } ,
288
- params : newParams
327
+ state : state || { name : stateName } ,
328
+ params : stateParams ,
329
+ hash : stateHash
289
330
} ) ;
290
331
291
- update ( ) ;
292
- } ;
332
+ activeClasses [ stateHash ] = activeClass ;
333
+ }
293
334
294
- $scope . $on ( '$stateChangeSuccess' , update ) ;
335
+ /**
336
+ * @param {string } state
337
+ * @param {Object|string } [params]
338
+ * @return {string }
339
+ */
340
+ function createStateHash ( state , params ) {
341
+ if ( ! isString ( state ) ) {
342
+ throw new Error ( 'state should be a string' ) ;
343
+ }
344
+ if ( isObject ( params ) ) {
345
+ return state + toJson ( params ) ;
346
+ }
347
+ params = $scope . $eval ( params ) ;
348
+ if ( isObject ( params ) ) {
349
+ return state + toJson ( params ) ;
350
+ }
351
+ return state ;
352
+ }
295
353
296
354
// Update route state
297
355
function update ( ) {
298
356
for ( var i = 0 ; i < states . length ; i ++ ) {
299
357
if ( anyMatch ( states [ i ] . state , states [ i ] . params ) ) {
300
- addClass ( $element , activeClass ) ;
358
+ addClass ( $element , activeClasses [ states [ i ] . hash ] ) ;
301
359
} else {
302
- removeClass ( $element , activeClass ) ;
360
+ removeClass ( $element , activeClasses [ states [ i ] . hash ] ) ;
303
361
}
304
362
305
363
if ( exactMatch ( states [ i ] . state , states [ i ] . params ) ) {
0 commit comments