Skip to content

Commit c1d9f87

Browse files
committed
refactor(*): use toBeUndefined function instead of tobe(undefined) function
use toBeUndefined for code consistency fixes angular#14184
1 parent 32feb2b commit c1d9f87

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2144
-225
lines changed

CHANGELOG.md

+37
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,43 @@ describe('$q.when', function() {
15191519
});
15201520
```
15211521

1522+
- **form:** Due to [94533e57](https://github.com/angular/angular.js/commit/94533e570673e6b2eb92073955541fa289aabe02),
1523+
the `name` attribute of `form` elements can now only contain characters that can be evaluated as part
1524+
of an Angular expression. This is because Angular uses the value of `name` as an assignable expression
1525+
to set the form on the `$scope`. For example, `name="myForm"` assigns the form to `$scope.myForm` and
1526+
`name="myObj.myForm"` assigns it to `$scope.myObj.myForm`.
1527+
1528+
Previously, it was possible to also use names such `name="my:name"`, because Angular used a special setter
1529+
function for the form name. Now the general, more robust `$parse` setter is used.
1530+
1531+
The easiest way to migrate your code is therefore to remove all special characters from the `name` attribute.
1532+
1533+
If you need to keep the special characters, you can use the following directive, which will replace
1534+
the `name` with a value that can be evaluated as an expression in the compile function, and then
1535+
re-set the original name in the postLink function. This ensures that (1), the form is published on
1536+
the scope, and (2), the form has the original name, which might be important if you are doing server-side
1537+
form submission.
1538+
1539+
```js
1540+
angular.module('myApp').directive('form', function() {
1541+
return {
1542+
restrict: 'E',
1543+
priority: 1000,
1544+
compile: function(element, attrs) {
1545+
var unsupportedCharacter = ':'; // change accordingly
1546+
var originalName = attrs.name;
1547+
if (attrs.name && attrs.name.indexOf(unsupportedCharacter) > 0) {
1548+
attrs.$set('name', 'this["' + originalName + '"]');
1549+
}
1550+
1551+
return postLinkFunction(scope, element) {
1552+
// Don't trigger $observers
1553+
element.setAttribute('name', originalName);
1554+
}
1555+
}
1556+
};
1557+
});
1558+
```
15221559

15231560
<a name="1.4.3"></a>
15241561
# 1.4.3 foam-acceleration (2015-07-15)

docs/app/src/errors.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ angular.module('errors', ['ngSanitize'])
1313
};
1414

1515
return function (text, target) {
16-
var targetHtml = target ? ' target="' + target + '"' : '';
17-
1816
if (!text) return text;
1917

18+
var targetHtml = target ? ' target="' + target + '"' : '';
19+
2020
return $sanitize(text.replace(LINKY_URL_REGEXP, function (url) {
2121
if (STACK_TRACE_REGEXP.test(url)) {
2222
return url;
@@ -34,6 +34,10 @@ angular.module('errors', ['ngSanitize'])
3434

3535

3636
.directive('errorDisplay', ['$location', 'errorLinkFilter', function ($location, errorLinkFilter) {
37+
var encodeAngleBrackets = function (text) {
38+
return text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
39+
};
40+
3741
var interpolate = function (formatString) {
3842
var formatArgs = arguments;
3943
return formatString.replace(/\{\d+\}/g, function (match) {
@@ -51,12 +55,15 @@ angular.module('errors', ['ngSanitize'])
5155
link: function (scope, element, attrs) {
5256
var search = $location.search(),
5357
formatArgs = [attrs.errorDisplay],
58+
formattedText,
5459
i;
5560

5661
for (i = 0; angular.isDefined(search['p'+i]); i++) {
5762
formatArgs.push(search['p'+i]);
5863
}
59-
element.html(errorLinkFilter(interpolate.apply(null, formatArgs), '_blank'));
64+
65+
formattedText = encodeAngleBrackets(interpolate.apply(null, formatArgs));
66+
element.html(errorLinkFilter(formattedText, '_blank'));
6067
}
6168
};
6269
}]);

docs/app/test/.jshintrc

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"extends": "../../../.jshintrc-base",
3+
"browser": true,
4+
"globals": {
5+
// AngularJS
6+
"angular": false,
7+
8+
// ngMocks
9+
"module": false,
10+
"inject": true,
11+
12+
// Jasmine
13+
"jasmine": false,
14+
"describe": false,
15+
"ddescribe": false,
16+
"xdescribe": false,
17+
"it": false,
18+
"iit": false,
19+
"xit": false,
20+
"beforeEach": false,
21+
"afterEach": false,
22+
"spyOn": false,
23+
"expect": false
24+
}
25+
}

docs/app/test/errorsSpec.js

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
'use strict';
2+
3+
describe('errors', function() {
4+
// Mock `ngSanitize` module
5+
angular.
6+
module('ngSanitize', []).
7+
value('$sanitize', jasmine.createSpy('$sanitize').andCallFake(angular.identity));
8+
9+
beforeEach(module('errors'));
10+
11+
12+
describe('errorDisplay', function() {
13+
var $sanitize;
14+
var errorLinkFilter;
15+
16+
beforeEach(inject(function(_$sanitize_, _errorLinkFilter_) {
17+
$sanitize = _$sanitize_;
18+
errorLinkFilter = _errorLinkFilter_;
19+
}));
20+
21+
22+
it('should return empty input unchanged', function() {
23+
var inputs = [undefined, null, false, 0, ''];
24+
var remaining = inputs.length;
25+
26+
inputs.forEach(function(falsyValue) {
27+
expect(errorLinkFilter(falsyValue)).toBe(falsyValue);
28+
remaining--;
29+
});
30+
31+
expect(remaining).toBe(0);
32+
});
33+
34+
35+
it('should recognize URLs and convert them to `<a>`', function() {
36+
var urls = [
37+
['ftp://foo/bar?baz#qux'],
38+
['http://foo/bar?baz#qux'],
39+
['https://foo/bar?baz#qux'],
40+
41+
42+
];
43+
var remaining = urls.length;
44+
45+
urls.forEach(function(values) {
46+
var actualUrl = values[0];
47+
var expectedUrl = values[1] || actualUrl;
48+
var expectedText = values[2] || expectedUrl;
49+
var anchor = '<a href="' + expectedUrl + '">' + expectedText + '</a>';
50+
51+
var input = 'start ' + actualUrl + ' end';
52+
var output = 'start ' + anchor + ' end';
53+
54+
expect(errorLinkFilter(input)).toBe(output);
55+
remaining--;
56+
});
57+
58+
expect(remaining).toBe(0);
59+
});
60+
61+
62+
it('should not recognize stack-traces as URLs', function() {
63+
var urls = [
64+
'ftp://foo/bar?baz#qux:4:2',
65+
'http://foo/bar?baz#qux:4:2',
66+
'https://foo/bar?baz#qux:4:2',
67+
'mailto:[email protected]:4:2',
68+
69+
];
70+
var remaining = urls.length;
71+
72+
urls.forEach(function(url) {
73+
var input = 'start ' + url + ' end';
74+
75+
expect(errorLinkFilter(input)).toBe(input);
76+
remaining--;
77+
});
78+
79+
expect(remaining).toBe(0);
80+
});
81+
82+
83+
it('should should set `[target]` if specified', function() {
84+
var url = 'https://foo/bar?baz#qux';
85+
var target = '_blank';
86+
var outputWithoutTarget = '<a href="' + url + '">' + url + '</a>';
87+
var outputWithTarget = '<a target="' + target + '" href="' + url + '">' + url + '</a>';
88+
89+
expect(errorLinkFilter(url)).toBe(outputWithoutTarget);
90+
expect(errorLinkFilter(url, target)).toBe(outputWithTarget);
91+
});
92+
93+
94+
it('should truncate the contents of the generated `<a>` to 60 characters', function() {
95+
var looongUrl = 'https://foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo';
96+
var truncatedUrl = 'https://foooooooooooooooooooooooooooooooooooooooooooooooo...';
97+
var output = '<a href="' + looongUrl + '">' + truncatedUrl + '</a>';
98+
99+
expect(looongUrl.length).toBeGreaterThan(60);
100+
expect(truncatedUrl.length).toBe(60);
101+
expect(errorLinkFilter(looongUrl)).toBe(output);
102+
});
103+
104+
105+
it('should pass the final string through `$sanitize`', function() {
106+
$sanitize.reset();
107+
108+
var input = 'start https://foo/bar?baz#qux end';
109+
var output = errorLinkFilter(input);
110+
111+
expect($sanitize.callCount).toBe(1);
112+
expect($sanitize).toHaveBeenCalledWith(output);
113+
});
114+
});
115+
116+
117+
describe('errorDisplay', function() {
118+
var $compile;
119+
var $location;
120+
var $rootScope;
121+
var errorLinkFilter;
122+
123+
beforeEach(module(function($provide) {
124+
$provide.decorator('errorLinkFilter', function() {
125+
errorLinkFilter = jasmine.createSpy('errorLinkFilter');
126+
errorLinkFilter.andCallFake(angular.identity);
127+
128+
return errorLinkFilter;
129+
});
130+
}));
131+
beforeEach(inject(function(_$compile_, _$location_, _$rootScope_) {
132+
$compile = _$compile_;
133+
$location = _$location_;
134+
$rootScope = _$rootScope_;
135+
}));
136+
137+
138+
it('should set the element\s HTML', function() {
139+
var elem = $compile('<span error-display="bar">foo</span>')($rootScope);
140+
expect(elem.html()).toBe('bar');
141+
});
142+
143+
144+
it('should interpolate the contents against `$location.search()`', function() {
145+
spyOn($location, 'search').andReturn({p0: 'foo', p1: 'bar'});
146+
147+
var elem = $compile('<span error-display="foo = {0}, bar = {1}"></span>')($rootScope);
148+
expect(elem.html()).toBe('foo = foo, bar = bar');
149+
});
150+
151+
152+
it('should pass the interpolated text through `errorLinkFilter`', function() {
153+
$location.search = jasmine.createSpy('search').andReturn({p0: 'foo'});
154+
155+
var elem = $compile('<span error-display="foo = {0}"></span>')($rootScope);
156+
expect(errorLinkFilter.callCount).toBe(1);
157+
expect(errorLinkFilter).toHaveBeenCalledWith('foo = foo', '_blank');
158+
});
159+
160+
161+
it('should encode `<` and `>`', function() {
162+
var elem = $compile('<span error-display="&lt;xyz&gt;"></span>')($rootScope);
163+
expect(elem.text()).toBe('<xyz>');
164+
});
165+
});
166+
});

0 commit comments

Comments
 (0)