Skip to content

Commit 5d1f51a

Browse files
committed
HTML5-mode compatibility + tests, fixes #276
- Refactoring directive test event handling
1 parent 4bdc937 commit 5d1f51a

File tree

3 files changed

+74
-117
lines changed

3 files changed

+74
-117
lines changed

src/state.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
$StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider'];
2-
function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
1+
$StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider', '$locationProvider'];
2+
function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $locationProvider) {
33

44
var root, states = {}, $state;
55

@@ -275,7 +275,8 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory) {
275275
options = extend({ lossy: true }, options || {});
276276
var state = findState(stateOrName);
277277
var nav = (state && options.lossy) ? state.navigable : state;
278-
return (nav && nav.url) ? nav.url.format(normalize(state.params, params || {})) : null;
278+
var url = (nav && nav.url) ? nav.url.format(normalize(state.params, params || {})) : null;
279+
return !$locationProvider.html5Mode() && url ? "#" + url : url;
279280
};
280281

281282
function resolveState(state, params, paramsAreFiltered, inherited, dst) {

test/stateDirectivesSpec.js

Lines changed: 48 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,41 @@ describe('uiStateRef', function() {
1313
}));
1414

1515
describe('links', function() {
16-
var el, scope;
16+
var el, scope, document;
17+
18+
beforeEach(inject(function($document) {
19+
document = $document[0];
20+
}));
21+
22+
function triggerClick(el, options) {
23+
options = angular.extend({
24+
metaKey: false,
25+
ctrlKey: false,
26+
shiftKey: false,
27+
altKey: false,
28+
button: 0
29+
}, options || {});
30+
31+
var e = document.createEvent("MouseEvents");
32+
e.initMouseEvent(
33+
"click", // typeArg of type DOMString, Specifies the event type.
34+
true, // canBubbleArg of type boolean, Specifies whether or not the event can bubble.
35+
true, // cancelableArg of type boolean, Specifies whether or not the event's default action can be prevented.
36+
undefined, // viewArg of type views::AbstractView, Specifies the Event's AbstractView.
37+
0, // detailArg of type long, Specifies the Event's mouse click count.
38+
0, // screenXArg of type long, Specifies the Event's screen x coordinate
39+
0, // screenYArg of type long, Specifies the Event's screen y coordinate
40+
0, // clientXArg of type long, Specifies the Event's client x coordinate
41+
0, // clientYArg of type long, Specifies the Event's client y coordinate
42+
options.ctrlKey, // ctrlKeyArg of type boolean, Specifies whether or not control key was depressed during the Event.
43+
options.altKey, // altKeyArg of type boolean, Specifies whether or not alt key was depressed during the Event.
44+
options.shiftKey, // shiftKeyArg of type boolean, Specifies whether or not shift key was depressed during the Event.
45+
options.metaKey, // metaKeyArg of type boolean, Specifies whether or not meta key was depressed during the Event.
46+
options.button, // buttonArg of type unsigned short, Specifies the Event's mouse button.
47+
null // relatedTargetArg of type EventTarget
48+
);
49+
el[0].dispatchEvent(e);
50+
}
1751

1852
beforeEach(inject(function($rootScope, $compile) {
1953
el = angular.element('<a ui-sref="contacts.item.detail({ id: contact.id })">Details</a>');
@@ -27,66 +61,29 @@ describe('uiStateRef', function() {
2761

2862

2963
it('should generate the correct href', function() {
30-
expect(el.attr('href')).toBe('/contacts/5');
64+
expect(el.attr('href')).toBe('#/contacts/5');
3165
});
3266

3367
it('should update the href when parameters change', function() {
34-
expect(el.attr('href')).toBe('/contacts/5');
68+
expect(el.attr('href')).toBe('#/contacts/5');
3569
scope.contact.id = 6;
3670
scope.$apply();
37-
expect(el.attr('href')).toBe('/contacts/6');
71+
expect(el.attr('href')).toBe('#/contacts/6');
3872
});
3973

4074
it('should transition states when left-clicked', inject(function($state, $stateParams, $document, $q) {
4175
expect($state.$current.name).toEqual('');
4276

43-
var e = $document[0].createEvent("MouseEvents");
44-
e.initMouseEvent(
45-
"click", // typeArg of type DOMString, Specifies the event type.
46-
true, // canBubbleArg of type boolean, Specifies whether or not the event can bubble.
47-
true, // cancelableArg of type boolean, Specifies whether or not the event's default action can be prevented.
48-
undefined, // viewArg of type views::AbstractView, Specifies the Event's AbstractView.
49-
0, // detailArg of type long, Specifies the Event's mouse click count.
50-
0, // screenXArg of type long, Specifies the Event's screen x coordinate
51-
0, // screenYArg of type long, Specifies the Event's screen y coordinate
52-
0, // clientXArg of type long, Specifies the Event's client x coordinate
53-
0, // clientYArg of type long, Specifies the Event's client y coordinate
54-
false, // ctrlKeyArg of type boolean, Specifies whether or not control key was depressed during the Event.
55-
false, // altKeyArg of type boolean, Specifies whether or not alt key was depressed during the Event.
56-
false, // shiftKeyArg of type boolean, Specifies whether or not shift key was depressed during the Event.
57-
false, // metaKeyArg of type boolean, Specifies whether or not meta key was depressed during the Event.
58-
0, // buttonArg of type unsigned short, Specifies the Event's mouse button.
59-
null // relatedTargetArg of type EventTarget
60-
);
61-
el[0].dispatchEvent(e);
62-
77+
triggerClick(el);
6378
$q.flush();
79+
6480
expect($state.current.name).toEqual('contacts.item.detail');
6581
expect($stateParams).toEqual({ id: "5" });
6682
}));
6783

6884
it('should not transition states when ctrl-clicked', inject(function($state, $stateParams, $document, $q) {
6985
expect($state.$current.name).toEqual('');
70-
71-
var e = $document[0].createEvent("MouseEvents");
72-
e.initMouseEvent(
73-
"click", // typeArg of type DOMString, Specifies the event type.
74-
true, // canBubbleArg of type boolean, Specifies whether or not the event can bubble.
75-
true, // cancelableArg of type boolean, Specifies whether or not the event's default action can be prevented.
76-
undefined, // viewArg of type views::AbstractView, Specifies the Event's AbstractView.
77-
0, // detailArg of type long, Specifies the Event's mouse click count.
78-
0, // screenXArg of type long, Specifies the Event's screen x coordinate
79-
0, // screenYArg of type long, Specifies the Event's screen y coordinate
80-
0, // clientXArg of type long, Specifies the Event's client x coordinate
81-
0, // clientYArg of type long, Specifies the Event's client y coordinate
82-
true, // ctrlKeyArg of type boolean, Specifies whether or not control key was depressed during the Event.
83-
false, // altKeyArg of type boolean, Specifies whether or not alt key was depressed during the Event.
84-
false, // shiftKeyArg of type boolean, Specifies whether or not shift key was depressed during the Event.
85-
false, // metaKeyArg of type boolean, Specifies whether or not meta key was depressed during the Event.
86-
0, // buttonArg of type unsigned short, Specifies the Event's mouse button.
87-
null // relatedTargetArg of type EventTarget
88-
);
89-
el[0].dispatchEvent(e);
86+
triggerClick(el, { ctrlKey: true });
9087

9188
$q.flush();
9289
expect($state.current.name).toEqual('');
@@ -96,83 +93,29 @@ describe('uiStateRef', function() {
9693
it('should not transition states when meta-clicked', inject(function($state, $stateParams, $document, $q) {
9794
expect($state.$current.name).toEqual('');
9895

99-
var e = $document[0].createEvent("MouseEvents");
100-
e.initMouseEvent(
101-
"click", // typeArg of type DOMString, Specifies the event type.
102-
true, // canBubbleArg of type boolean, Specifies whether or not the event can bubble.
103-
true, // cancelableArg of type boolean, Specifies whether or not the event's default action can be prevented.
104-
undefined, // viewArg of type views::AbstractView, Specifies the Event's AbstractView.
105-
0, // detailArg of type long, Specifies the Event's mouse click count.
106-
0, // screenXArg of type long, Specifies the Event's screen x coordinate
107-
0, // screenYArg of type long, Specifies the Event's screen y coordinate
108-
0, // clientXArg of type long, Specifies the Event's client x coordinate
109-
0, // clientYArg of type long, Specifies the Event's client y coordinate
110-
false, // ctrlKeyArg of type boolean, Specifies whether or not control key was depressed during the Event.
111-
false, // altKeyArg of type boolean, Specifies whether or not alt key was depressed during the Event.
112-
false, // shiftKeyArg of type boolean, Specifies whether or not shift key was depressed during the Event.
113-
true, // metaKeyArg of type boolean, Specifies whether or not meta key was depressed during the Event.
114-
0, // buttonArg of type unsigned short, Specifies the Event's mouse button.
115-
null // relatedTargetArg of type EventTarget
116-
);
117-
el[0].dispatchEvent(e);
118-
96+
triggerClick(el, { metaKey: true });
11997
$q.flush();
98+
12099
expect($state.current.name).toEqual('');
121100
expect($stateParams).toEqual({ id: "5" });
122101
}));
123102

124103
it('should not transition states when shift-clicked', inject(function($state, $stateParams, $document, $q) {
125104
expect($state.$current.name).toEqual('');
126105

127-
var e = $document[0].createEvent("MouseEvents");
128-
e.initMouseEvent(
129-
"click", // typeArg of type DOMString, Specifies the event type.
130-
true, // canBubbleArg of type boolean, Specifies whether or not the event can bubble.
131-
true, // cancelableArg of type boolean, Specifies whether or not the event's default action can be prevented.
132-
undefined, // viewArg of type views::AbstractView, Specifies the Event's AbstractView.
133-
0, // detailArg of type long, Specifies the Event's mouse click count.
134-
0, // screenXArg of type long, Specifies the Event's screen x coordinate
135-
0, // screenYArg of type long, Specifies the Event's screen y coordinate
136-
0, // clientXArg of type long, Specifies the Event's client x coordinate
137-
0, // clientYArg of type long, Specifies the Event's client y coordinate
138-
false, // ctrlKeyArg of type boolean, Specifies whether or not control key was depressed during the Event.
139-
false, // altKeyArg of type boolean, Specifies whether or not alt key was depressed during the Event.
140-
true, // shiftKeyArg of type boolean, Specifies whether or not shift key was depressed during the Event.
141-
false, // metaKeyArg of type boolean, Specifies whether or not meta key was depressed during the Event.
142-
0, // buttonArg of type unsigned short, Specifies the Event's mouse button.
143-
null // relatedTargetArg of type EventTarget
144-
);
145-
el[0].dispatchEvent(e);
146-
106+
triggerClick(el, { shiftKey: true });
147107
$q.flush();
108+
148109
expect($state.current.name).toEqual('');
149110
expect($stateParams).toEqual({ id: "5" });
150111
}));
151112

152113
it('should not transition states when middle-clicked', inject(function($state, $stateParams, $document, $q) {
153114
expect($state.$current.name).toEqual('');
154115

155-
var e = $document[0].createEvent("MouseEvents");
156-
e.initMouseEvent(
157-
"click", // typeArg of type DOMString, Specifies the event type.
158-
true, // canBubbleArg of type boolean, Specifies whether or not the event can bubble.
159-
true, // cancelableArg of type boolean, Specifies whether or not the event's default action can be prevented.
160-
undefined, // viewArg of type views::AbstractView, Specifies the Event's AbstractView.
161-
0, // detailArg of type long, Specifies the Event's mouse click count.
162-
0, // screenXArg of type long, Specifies the Event's screen x coordinate
163-
0, // screenYArg of type long, Specifies the Event's screen y coordinate
164-
0, // clientXArg of type long, Specifies the Event's client x coordinate
165-
0, // clientYArg of type long, Specifies the Event's client y coordinate
166-
false, // ctrlKeyArg of type boolean, Specifies whether or not control key was depressed during the Event.
167-
false, // altKeyArg of type boolean, Specifies whether or not alt key was depressed during the Event.
168-
false, // shiftKeyArg of type boolean, Specifies whether or not shift key was depressed during the Event.
169-
false, // metaKeyArg of type boolean, Specifies whether or not meta key was depressed during the Event.
170-
1, // buttonArg of type unsigned short, Specifies the Event's mouse button.
171-
null // relatedTargetArg of type EventTarget
172-
);
173-
el[0].dispatchEvent(e);
174-
116+
triggerClick(el, { button: 1 });
175117
$q.flush();
118+
176119
expect($state.current.name).toEqual('');
177120
expect($stateParams).toEqual({ id: "5" });
178121
}));
@@ -192,7 +135,7 @@ describe('uiStateRef', function() {
192135
}));
193136

194137
it('should generate the correct action', function() {
195-
expect(el.attr('action')).toBe('/contacts/5');
138+
expect(el.attr('action')).toBe('#/contacts/5');
196139
});
197140
});
198141
});

test/stateSpec.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
describe('state', function () {
2-
3-
beforeEach(module('ui.state'));
2+
3+
var locationProvider;
4+
5+
beforeEach(module('ui.state', function($locationProvider) {
6+
locationProvider = $locationProvider;
7+
$locationProvider.html5Mode(false);
8+
}));
49

510
var log, logEvents, logEnterExit;
611
function eventLogger(event, to, toParams, from, fromParams) {
@@ -267,18 +272,18 @@ describe('state', function () {
267272
}));
268273

269274
it('generates a parent state URL when lossy is true', inject(function ($state) {
270-
expect($state.href("about.sidebar", null, { lossy: true })).toEqual("/about");
275+
expect($state.href("about.sidebar", null, { lossy: true })).toEqual("#/about");
271276
}));
272277

273278
it('generates a URL without parameters', inject(function ($state) {
274-
expect($state.href("home")).toEqual("/");
275-
expect($state.href("about", {})).toEqual("/about");
276-
expect($state.href("about", { foo: "bar" })).toEqual("/about");
279+
expect($state.href("home")).toEqual("#/");
280+
expect($state.href("about", {})).toEqual("#/about");
281+
expect($state.href("about", { foo: "bar" })).toEqual("#/about");
277282
}));
278283

279284
it('generates a URL with parameters', inject(function ($state) {
280-
expect($state.href("about.person", { person: "bob" })).toEqual("/about/bob");
281-
expect($state.href("about.person.item", { person: "bob", id: null })).toEqual("/about/bob/");
285+
expect($state.href("about.person", { person: "bob" })).toEqual("#/about/bob");
286+
expect($state.href("about.person.item", { person: "bob", id: null })).toEqual("#/about/bob/");
282287
}));
283288
});
284289

@@ -307,4 +312,12 @@ describe('state', function () {
307312
}));
308313
});
309314

310-
});
315+
describe('html5Mode compatibility', function() {
316+
317+
it('should generate non-hashbang URLs in HTML5 mode', inject(function ($state) {
318+
expect($state.href("about.person", { person: "bob" })).toEqual("#/about/bob");
319+
locationProvider.html5Mode(true);
320+
expect($state.href("about.person", { person: "bob" })).toEqual("/about/bob");
321+
}));
322+
});
323+
});

0 commit comments

Comments
 (0)