Skip to content

Commit faa341e

Browse files
feat(common): defaults() now allows multiple default objs to be merged
feat(Transition): exported default transition options test(uiSref): wrapped params compare in obj()
1 parent c2db1ba commit faa341e

File tree

6 files changed

+62
-83
lines changed

6 files changed

+62
-83
lines changed

src/common.ts

+12-31
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,20 @@ export function inherit(parent, extra) {
88
return extend(new (extend(function() {}, { prototype: parent }))(), extra);
99
}
1010

11-
export function defaults(opts, defs) {
12-
return extend({}, defs, pick(opts || {}, objectKeys(defs)));
11+
/**
12+
* Applies a set of defaults to an options object. The options object is filtered
13+
* to only those properties of the objects in the defaultsList.
14+
* Earlier objects in the defaultsList take precedence when applying defaults.
15+
*/
16+
export function defaults(opts = {}, ...defaultsList) {
17+
var defaults = merge.apply(null, [{}].concat(defaultsList));
18+
return extend({}, defaults, pick(opts || {}, objectKeys(defaults)));
1319
}
1420

21+
/**
22+
* Merges properties from the list of objects to the destination object.
23+
* If a property already exists in the destination object, then it is not overwritten.
24+
*/
1525
export function merge(dst, ...objs: Object[]) {
1626
forEach(objs, function(obj) {
1727
forEach(obj, function(value, key) {
@@ -21,35 +31,6 @@ export function merge(dst, ...objs: Object[]) {
2131
return dst;
2232
}
2333

24-
///**
25-
// * Recursive function iterator
26-
// */
27-
//export function FunctionIterator(items) {
28-
// var self = this;
29-
//
30-
// var it = function(initial) {
31-
// var get = function() { return this.next() || noop; }.bind(self);
32-
// var next = function() { return get()(initial, next); };
33-
// return next();
34-
// };
35-
//
36-
// extend(this, {
37-
// items: items,
38-
// _current: -1
39-
// });
40-
//
41-
// return it.bind(this);
42-
//}
43-
//
44-
//FunctionIterator.prototype.current = function() {
45-
// return this.items[this._current];
46-
//};
47-
//
48-
//FunctionIterator.prototype.next = function() {
49-
// this._current++;
50-
// return this.current();
51-
//};
52-
5334
/**
5435
* Finds the common ancestor path between two states.
5536
*

src/state.ts

+11-23
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {extend, inherit, pluck, defaults, copy, abstractKey, equalForKeys, forEa
22
import {not, prop, pipe, val} from "./common";
33
import {isDefined, isFunction, isArray, isObject, isString} from "./common";
44
import {Glob} from "./glob";
5-
import {TransitionRejection} from "./transition";
5+
import {TransitionRejection, defaultTransOpts} from "./transition";
66
import {Param} from "./param";
77
import {ParamSet} from "./paramSet";
88
import {IServiceProviderFactory} from "angular";
@@ -20,7 +20,7 @@ export function StateQueueManager(states, builder, $urlRouterProvider, $state) {
2020
var queue = [];
2121

2222
var queueManager = extend(this, {
23-
register: function(config, pre) {
23+
register: function(config: IPublicState, pre?: boolean) {
2424
// Wrap a new object around the state so we can store our private details easily.
2525
var state = inherit(new State(), extend({}, config, {
2626
self: config,
@@ -294,7 +294,7 @@ export function StateMatcher(states) {
294294
*
295295
* @returns {Object} Returns a new `State` object.
296296
*/
297-
function State(config?: any) {
297+
function State(config?: IPublicState) {
298298
extend(this, config);
299299
}
300300

@@ -900,14 +900,8 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactoryProvider) {
900900
*
901901
*/
902902
$state.go = function go(to, params, options) {
903-
return $state.transitionTo(to, params, defaults(options, {
904-
location: true,
905-
relative: $state.$current,
906-
inherit: true,
907-
notify: true,
908-
reload: false,
909-
trace: false
910-
}));
903+
var defautGoOpts = { relative: $state.$current, inherit: true };
904+
return $state.transitionTo(to, params, defaults(options, defautGoOpts, defaultTransOpts));
911905
};
912906

913907
/**
@@ -977,14 +971,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactoryProvider) {
977971
* {@link ui.router.state.$state#methods_go $state.go}.
978972
*/
979973
$state.transitionTo = function transitionTo(to, toParams, options) {
980-
options = defaults(options, {
981-
location: true,
982-
relative: null,
983-
inherit: false,
984-
notify: true,
985-
reload: false,
986-
trace: false
987-
});
974+
options = defaults(options, defaultTransOpts);
988975

989976
// If we're reloading, find the state object to reload from
990977
if (isObject(options.reload) && !options.reload.name) { throw new Error('Invalid reload state object'); }
@@ -1116,7 +1103,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactoryProvider) {
11161103
* @returns {boolean} Returns true if it is the state.
11171104
*/
11181105
$state.is = function is(stateOrName, params, options) {
1119-
options = extend({ relative: $state.$current }, options || {});
1106+
options = defaults(options, { relative: $state.$current });
11201107
var state = matcher.find(stateOrName, options.relative);
11211108
if (!isDefined(state)) return undefined;
11221109
if ($state.$current !== state) return false;
@@ -1175,7 +1162,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactoryProvider) {
11751162
* @returns {boolean} Returns true if it does include the state
11761163
*/
11771164
$state.includes = function includes(stateOrName, params, options) {
1178-
options = extend({ relative: $state.$current }, options || {});
1165+
options = defaults(options, { relative: $state.$current });
11791166
var glob = isString(stateOrName) && Glob.fromString(stateOrName);
11801167

11811168
if (glob) {
@@ -1218,12 +1205,13 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactoryProvider) {
12181205
* @returns {string} compiled state url
12191206
*/
12201207
$state.href = function href(stateOrName, params, options) {
1221-
options = defaults(options || {}, {
1208+
var defaultHrefOpts = {
12221209
lossy: true,
12231210
inherit: true,
12241211
absolute: false,
12251212
relative: $state.$current
1226-
});
1213+
};
1214+
options = defaults(options, defaultHrefOpts);
12271215

12281216
var state = matcher.find(stateOrName, options.relative);
12291217

src/stateDirectives.ts

+5-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='../bower_components/DefinitelyTyped/angularjs/angular.d.ts' />
2-
import {equalForKeys, forEach, copy} from "./common";
2+
import {equalForKeys, forEach, copy, defaults} from "./common";
3+
import {defaultTransOpts} from "./transition";
34

45
function parseStateRef(ref, current) {
56
var preparsed = ref.match(/^\s*({[^}]*})\s*$/), parsed;
@@ -81,8 +82,6 @@ function stateContext(el) {
8182
*/
8283
$StateRefDirective.$inject = ['$state', '$timeout'];
8384
function $StateRefDirective($state, $timeout) {
84-
var allowedOptions = ['location', 'inherit', 'reload'];
85-
8685
return {
8786
restrict: 'A',
8887
require: ['?^uiSrefActive', '?^uiSrefActiveEq'],
@@ -93,14 +92,9 @@ function $StateRefDirective($state, $timeout) {
9392
var isForm = element[0].nodeName === "FORM";
9493
var attr = isForm ? "action" : "href", nav = true;
9594

96-
var options = { relative: base, inherit: true };
97-
var optionsOverride = scope.$eval(attrs.uiSrefOpts) || {};
98-
99-
forEach(allowedOptions, function(option) {
100-
if (option in optionsOverride) {
101-
options[option] = optionsOverride[option];
102-
}
103-
});
95+
var srefOpts = scope.$eval(attrs.uiSrefOpts);
96+
var defaultSrefOpts = { relative: base, inherit: true };
97+
var options = defaults(srefOpts, defaultSrefOpts, defaultTransOpts);
10498

10599
var update = function(newVal?: any) {
106100
if (newVal) params = copy(newVal);

src/transition.ts

+16
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,22 @@ export function TransitionStep(pathElement, fn, locals, pathContext, options) {
152152
});
153153
}
154154

155+
/**
156+
* The default transition options.
157+
* Include this object when applying custom defaults:
158+
* var reloadOpts = { reload: true, notify: true }
159+
* var options = defaults(theirOpts, customDefaults, defaultOptions);
160+
*/
161+
export var defaultTransOpts = {
162+
location: true,
163+
relative: null,
164+
inherit: false,
165+
notify: true,
166+
reload: false,
167+
trace: false,
168+
custom: {}
169+
};
170+
155171
/**
156172
* @ngdoc object
157173
* @name ui.router.state.$transitionProvider

test/stateDirectivesSpec.js

+17-17
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ describe('uiStateRef', function() {
133133
$q.flush();
134134

135135
expect($state.current.name).toEqual('contacts.item.detail');
136-
expect($stateParams).toEqual({ id: "5" });
136+
expect(obj($stateParams)).toEqualData({ id: "5" });
137137
}));
138138

139139
it('should transition when given a click that contains no data (fake-click)', inject(function($state, $stateParams, $q) {
@@ -150,56 +150,56 @@ describe('uiStateRef', function() {
150150
$q.flush();
151151

152152
expect($state.current.name).toEqual('contacts.item.detail');
153-
expect($stateParams).toEqual({ id: "5" });
153+
expect(obj($stateParams)).toEqualData({ id: "5" });
154154
}));
155155

156156
it('should not transition states when ctrl-clicked', inject(function($state, $stateParams, $q) {
157157
expect($state.$current.name).toEqual('top');
158-
expect($stateParams).toEqualData({});
158+
expect(obj($stateParams)).toEqualData({});
159159

160160
triggerClick(el, { ctrlKey: true });
161161

162162
timeoutFlush();
163163
$q.flush();
164164

165165
expect($state.current.name).toEqual('top');
166-
expect($stateParams).toEqualData({ });
166+
expect(obj($stateParams)).toEqualData({ });
167167
}));
168168

169169
it('should not transition states when meta-clicked', inject(function($state, $stateParams, $q) {
170170
expect($state.$current.name).toEqual('top');
171-
expect($stateParams).toEqualData({});
171+
expect(obj($stateParams)).toEqualData({});
172172

173173
triggerClick(el, { metaKey: true });
174174
timeoutFlush();
175175
$q.flush();
176176

177177
expect($state.current.name).toEqual('top');
178-
expect($stateParams).toEqualData({});
178+
expect(obj($stateParams)).toEqualData({});
179179
}));
180180

181181
it('should not transition states when shift-clicked', inject(function($state, $stateParams, $q) {
182182
expect($state.$current.name).toEqual('top');
183-
expect($stateParams).toEqualData({});
183+
expect(obj($stateParams)).toEqualData({});
184184

185185
triggerClick(el, { shiftKey: true });
186186
timeoutFlush();
187187
$q.flush();
188188

189189
expect($state.current.name).toEqual('top');
190-
expect($stateParams).toEqualData({});
190+
expect(obj($stateParams)).toEqualData({});
191191
}));
192192

193193
it('should not transition states when middle-clicked', inject(function($state, $stateParams, $q) {
194194
expect($state.$current.name).toEqual('top');
195-
expect($stateParams).toEqualData({});
195+
expect(obj($stateParams)).toEqualData({});
196196

197197
triggerClick(el, { button: 1 });
198198
timeoutFlush();
199199
$q.flush();
200200

201201
expect($state.current.name).toEqual('top');
202-
expect($stateParams).toEqualData({});
202+
expect(obj($stateParams)).toEqualData({});
203203
}));
204204

205205
it('should not transition states when element has target specified', inject(function($state, $stateParams, $q) {
@@ -211,12 +211,12 @@ describe('uiStateRef', function() {
211211
$q.flush();
212212

213213
expect($state.current.name).toEqual('top');
214-
expect($stateParams).toEqualData({});
214+
expect(obj($stateParams)).toEqualData({});
215215
}));
216216

217217
it('should not transition states if preventDefault() is called in click handler', inject(function($state, $stateParams, $q) {
218218
expect($state.$current.name).toEqual('top');
219-
expect($stateParams).toEqualData({});
219+
expect(obj($stateParams)).toEqualData({});
220220

221221
el.bind('click', function(e) {
222222
e.preventDefault();
@@ -227,7 +227,7 @@ describe('uiStateRef', function() {
227227
$q.flush();
228228

229229
expect($state.current.name).toEqual('top');
230-
expect($stateParams).toEqualData({});
230+
expect(obj($stateParams)).toEqualData({});
231231
}));
232232

233233
it('should allow passing params to current state', inject(function($compile, $rootScope, $state) {
@@ -297,7 +297,7 @@ describe('uiStateRef', function() {
297297
$q.flush();
298298

299299
expect($state.current.name).toEqual('top');
300-
expect($stateParams).toEqualData({});
300+
expect(obj($stateParams)).toEqualData({});
301301
}));
302302
});
303303

@@ -338,7 +338,7 @@ describe('uiStateRef', function() {
338338
$q.flush();
339339

340340
expect($state.$current.name).toBe("contacts.item.detail");
341-
expect($state.params).toEqual({ id: "5" });
341+
expect(obj($state.params)).toEqualData({ id: "5" });
342342
}));
343343

344344
it('should resolve states from parent uiView', inject(function ($state, $stateParams, $q, $timeout) {
@@ -395,8 +395,8 @@ describe('uiStateRef', function() {
395395
$timeout.flush();
396396

397397
expect(transitionOptions.reload).toEqual(true);
398-
expect(transitionOptions.absolute).toEqual(true);
399-
expect(transitionOptions.notify).toBeUndefined();
398+
expect(transitionOptions.absolute).toBeUndefined();
399+
expect(transitionOptions.notify).toEqual(true);
400400
}));
401401
});
402402
});

test/tests.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
var testsContext = require.context(".", true, /.Spec/);
2-
var ignoredSpecs = [/stateDirectivesSpec/, /viewDirectiveSpec/, /viewScrollSpec/];
2+
var ignoredSpecs = [/viewDirectiveSpec/, /viewScrollSpec/];
33

44
var notIgnored = function (key) {
55
var ignored = ignoredSpecs.reduce(function(memo, regexp) { return memo || regexp.exec(key); }, false);

0 commit comments

Comments
 (0)