Skip to content

Commit f7ececc

Browse files
1 parent 2549313 commit f7ececc

File tree

12 files changed

+227
-83
lines changed

12 files changed

+227
-83
lines changed

Gruntfile.js

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,7 @@ module.exports = function(grunt) {
138138
tests: {
139139
jqlite: 'karma-jqlite.conf.js',
140140
jquery: 'karma-jquery.conf.js',
141-
'jquery-2.2': 'karma-jquery-2.2.conf.js',
142-
'jquery-2.1': 'karma-jquery-2.1.conf.js',
141+
'jquery-3.5': 'karma-jquery-3.5.conf.js',
143142
docs: 'karma-docs.conf.js',
144143
modules: 'karma-modules.conf.js'
145144
},
@@ -148,8 +147,7 @@ module.exports = function(grunt) {
148147
autotest: {
149148
jqlite: 'karma-jqlite.conf.js',
150149
jquery: 'karma-jquery.conf.js',
151-
'jquery-2.2': 'karma-jquery-2.2.conf.js',
152-
'jquery-2.1': 'karma-jquery-2.1.conf.js',
150+
'jquery-3.5': 'karma-jquery-3.5.conf.js',
153151
modules: 'karma-modules.conf.js',
154152
docs: 'karma-docs.conf.js'
155153
},
@@ -437,10 +435,9 @@ module.exports = function(grunt) {
437435
'tests:docs',
438436
'test:protractor'
439437
]);
440-
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
438+
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma', ['tests:jqlite']);
441439
grunt.registerTask('test:jquery', 'Run the jQuery (latest) unit tests with Karma', ['tests:jquery']);
442-
grunt.registerTask('test:jquery-2.2', 'Run the jQuery 2.2 unit tests with Karma', ['tests:jquery-2.2']);
443-
grunt.registerTask('test:jquery-2.1', 'Run the jQuery 2.1 unit tests with Karma', ['tests:jquery-2.1']);
440+
grunt.registerTask('test:jquery-3.5', 'Run the jQuery 3.5 unit tests with Karma', ['tests:jquery-3.5']);
444441
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', [
445442
'build',
446443
'tests:modules'
@@ -449,8 +446,7 @@ module.exports = function(grunt) {
449446
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', [
450447
'test:jqlite',
451448
'test:jquery',
452-
'test:jquery-2.2',
453-
'test:jquery-2.1',
449+
'test:jquery-3.5',
454450
'test:modules'
455451
]);
456452
grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', [

angularFiles.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ var angularFiles = {
244244
]
245245
};
246246

247-
['2.1', '2.2'].forEach(function(jQueryVersion) {
247+
['3.5'].forEach(function(jQueryVersion) {
248248
angularFiles['karmaJquery' + jQueryVersion] = []
249249
.concat(angularFiles.karmaJquery)
250250
.map(function(path) {

karma-jquery-2.2.conf.js

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
var karmaConfigFactory = require('./karma-jquery.conf-factory');
44

5-
module.exports = karmaConfigFactory('2.1');
5+
module.exports = karmaConfigFactory('3.5');

lib/grunt/utils.js

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -182,23 +182,24 @@ module.exports = {
182182
var errorFileName = file.replace(/\.js$/, '-errors.json');
183183
var versionNumber = grunt.config('NG_VERSION').full;
184184
var compilationLevel = (file === 'build/angular-message-format.js') ?
185-
'ADVANCED_OPTIMIZATIONS' : 'SIMPLE_OPTIMIZATIONS';
185+
'ADVANCED_OPTIMIZATIONS' : 'SIMPLE_OPTIMIZATIONS';
186+
var command = 'java ' +
187+
this.java32flags() + ' ' +
188+
this.memoryRequirement() + ' ' +
189+
'-cp vendor/closure-compiler/compiler.jar' + classPathSep +
190+
'vendor/ng-closure-runner/ngcompiler.jar ' +
191+
'org.angularjs.closurerunner.NgClosureRunner ' +
192+
'--compilation_level ' + compilationLevel + ' ' +
193+
'--language_in ECMASCRIPT5_STRICT ' +
194+
'--minerr_pass ' +
195+
'--minerr_errors ' + errorFileName + ' ' +
196+
'--minerr_url http://errors.angularjs.org/' + versionNumber + '/ ' +
197+
'--source_map_format=V3 ' +
198+
'--create_source_map ' + mapFile + ' ' +
199+
'--js ' + file + ' ' +
200+
'--js_output_file ' + minFile;
186201
shell.exec(
187-
'java ' +
188-
this.java32flags() + ' ' +
189-
this.memoryRequirement() + ' ' +
190-
'-cp vendor/closure-compiler/compiler.jar' + classPathSep +
191-
'vendor/ng-closure-runner/ngcompiler.jar ' +
192-
'org.angularjs.closurerunner.NgClosureRunner ' +
193-
'--compilation_level ' + compilationLevel + ' ' +
194-
'--language_in ECMASCRIPT5_STRICT ' +
195-
'--minerr_pass ' +
196-
'--minerr_errors ' + errorFileName + ' ' +
197-
'--minerr_url http://errors.angularjs.org/' + versionNumber + '/ ' +
198-
'--source_map_format=V3 ' +
199-
'--create_source_map ' + mapFile + ' ' +
200-
'--js ' + file + ' ' +
201-
'--js_output_file ' + minFile,
202+
command,
202203
function(code) {
203204
if (code !== 0) grunt.fail.warn('Error minifying ' + file);
204205

@@ -221,7 +222,7 @@ module.exports = {
221222
//returns the 32-bit mode force flags for java compiler if supported, this makes the build much faster
222223
java32flags: function() {
223224
if (process.platform === 'win32') return '';
224-
if (shell.exec('java -version -d32 2>&1', {silent: true}).code !== 0) return '';
225+
if (shell.exec('java -d32 2>&1', {silent: true}).code !== 0) return '';
225226
return ' -d32 -client';
226227
},
227228

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,8 @@
6060
"jasmine-core": "^2.8.0",
6161
"jasmine-node": "^2.0.0",
6262
"jasmine-reporters": "^2.2.0",
63-
"jquery": "3.2.1",
64-
"jquery-2.1": "npm:jquery@2.1.4",
65-
"jquery-2.2": "npm:jquery@2.2.4",
63+
"jquery": "3.5.1",
64+
"jquery-3.5": "npm:jquery@3.5.1",
6665
"karma": "^2.0.0",
6766
"karma-browserstack-launcher": "^1.2.0",
6867
"karma-chrome-launcher": "^2.1.1",

scripts/travis/build.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ case "$JOB" in
3939
;;
4040
"unit-jquery")
4141
grunt test:jquery --browsers="$BROWSERS" --reporters=spec
42-
grunt test:jquery-2.2 --browsers="$BROWSERS" --reporters=spec
43-
grunt test:jquery-2.1 --browsers="$BROWSERS" --reporters=spec
42+
grunt test:jquery-3.5 --browsers="$BROWSERS" --reporters=spec
4443
;;
4544
"docs-app")
4645
grunt tests:docs --browsers="$BROWSERS" --reporters=spec

src/Angular.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
hasOwnProperty,
9696
createMap,
9797
stringify,
98+
UNSAFE_restoreLegacyJqLiteXHTMLReplacement,
9899
99100
NODE_TYPE_ELEMENT,
100101
NODE_TYPE_ATTRIBUTE,
@@ -1965,6 +1966,25 @@ function bindJQuery() {
19651966
bindJQueryFired = true;
19661967
}
19671968

1969+
/**
1970+
* @ngdoc function
1971+
* @name angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement
1972+
* @module ng
1973+
* @kind function
1974+
*
1975+
* @description
1976+
* Restores the pre-1.8 behavior of jqLite that turns XHTML-like strings like
1977+
* `<div /><span />` to `<div></div><span></span>` instead of `<div><span></span></div>`.
1978+
* The new behavior is a security fix. Thus, if you need to call this function, please try to adjust
1979+
* your code for this change and remove your use of this function as soon as possible.
1980+
* Note that this only patches jqLite. If you use jQuery 3.5.0 or newer, please read the
1981+
* [jQuery 3.5 upgrade guide](https://jquery.com/upgrade-guide/3.5/) for more details
1982+
* about the workarounds.
1983+
*/
1984+
function UNSAFE_restoreLegacyJqLiteXHTMLReplacement() {
1985+
JQLite.legacyXHTMLReplacement = true;
1986+
}
1987+
19681988
/**
19691989
* throw error if the argument is falsy.
19701990
*/

src/AngularPublic.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
ngModelOptionsDirective,
5252
ngAttributeAliasDirectives,
5353
ngEventDirectives,
54+
UNSAFE_restoreLegacyJqLiteXHTMLReplacement,
5455
5556
$AnchorScrollProvider,
5657
$AnimateProvider,
@@ -155,6 +156,7 @@ function publishExternalAPI(angular) {
155156
'callbacks': {$$counter: 0},
156157
'getTestability': getTestability,
157158
'reloadWithDebugInfo': reloadWithDebugInfo,
159+
'UNSAFE_restoreLegacyJqLiteXHTMLReplacement': UNSAFE_restoreLegacyJqLiteXHTMLReplacement,
158160
'$$minErr': minErr,
159161
'$$csp': csp,
160162
'$$encodeUriSegment': encodeUriSegment,

src/jqLite.js

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@
9090
* - [`val()`](http://api.jquery.com/val/)
9191
* - [`wrap()`](http://api.jquery.com/wrap/)
9292
*
93+
* jqLite also provides a method restoring pre-1.8 insecure treatment of XHTML-like tags.
94+
* This legacy behavior turns input like `<div /><span />` to `<div></div><span></span>`
95+
* instead of `<div><span></span></div>` like version 1.8 & newer do. To restore it, invoke:
96+
* ```js
97+
* angular.UNSAFE_restoreLegacyJqLiteXHTMLReplacement();
98+
* ```
99+
* Note that this only patches jqLite. If you use jQuery 3.5.0 or newer, please read the
100+
* [jQuery 3.5 upgrade guide](https://jquery.com/upgrade-guide/3.5/) for more details
101+
* about the workarounds.
102+
*
93103
* ## jQuery/jqLite Extras
94104
* AngularJS also provides the following additional methods and events to both jQuery and jqLite:
95105
*
@@ -169,20 +179,36 @@ var HTML_REGEXP = /<|&#?\w+;/;
169179
var TAG_NAME_REGEXP = /<([\w:-]+)/;
170180
var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
171181

182+
// Table parts need to be wrapped with `<table>` or they're
183+
// stripped to their contents when put in a div.
184+
// XHTML parsers do not magically insert elements in the
185+
// same way that tag soup parsers do, so we cannot shorten
186+
// this by omitting <tbody> or other required elements.
172187
var wrapMap = {
173-
'option': [1, '<select multiple="multiple">', '</select>'],
174-
175-
'thead': [1, '<table>', '</table>'],
176-
'col': [2, '<table><colgroup>', '</colgroup></table>'],
177-
'tr': [2, '<table><tbody>', '</tbody></table>'],
178-
'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
179-
'_default': [0, '', '']
188+
thead: ['table'],
189+
col: ['colgroup', 'table'],
190+
tr: ['tbody', 'table'],
191+
td: ['tr', 'tbody', 'table']
180192
};
181193

182-
wrapMap.optgroup = wrapMap.option;
183194
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
184195
wrapMap.th = wrapMap.td;
185196

197+
// Support: IE <10 only
198+
// IE 9 requires an option wrapper & it needs to have the whole table structure
199+
// set up in advance; assigning `"<td></td>"` to `tr.innerHTML` doesn't work, etc.
200+
var wrapMapIE9 = {
201+
option: [1, '<select multiple="multiple">', '</select>'],
202+
_default: [0, '', '']
203+
};
204+
205+
for (var key in wrapMap) {
206+
var wrapMapValueClosing = wrapMap[key];
207+
var wrapMapValue = wrapMapValueClosing.slice().reverse();
208+
wrapMapIE9[key] = [wrapMapValue.length, '<' + wrapMapValue.join('><') + '>', '</' + wrapMapValueClosing.join('></') + '>'];
209+
}
210+
211+
wrapMapIE9.optgroup = wrapMapIE9.option;
186212

187213
function jqLiteIsTextNode(html) {
188214
return !HTML_REGEXP.test(html);
@@ -203,7 +229,7 @@ function jqLiteHasData(node) {
203229
}
204230

205231
function jqLiteBuildFragment(html, context) {
206-
var tmp, tag, wrap,
232+
var tmp, tag, wrap, finalHtml,
207233
fragment = context.createDocumentFragment(),
208234
nodes = [], i;
209235

@@ -214,13 +240,30 @@ function jqLiteBuildFragment(html, context) {
214240
// Convert html into DOM nodes
215241
tmp = fragment.appendChild(context.createElement('div'));
216242
tag = (TAG_NAME_REGEXP.exec(html) || ['', ''])[1].toLowerCase();
217-
wrap = wrapMap[tag] || wrapMap._default;
218-
tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, '<$1></$2>') + wrap[2];
243+
finalHtml = JQLite.legacyXHTMLReplacement ?
244+
html.replace(XHTML_TAG_REGEXP, '<$1></$2>') :
245+
html;
246+
247+
if (msie < 10) {
248+
wrap = wrapMapIE9[tag] || wrapMapIE9._default;
249+
tmp.innerHTML = wrap[1] + finalHtml + wrap[2];
250+
251+
// Descend through wrappers to the right content
252+
i = wrap[0];
253+
while (i--) {
254+
tmp = tmp.firstChild;
255+
}
256+
} else {
257+
wrap = wrapMap[tag] || [];
219258

220-
// Descend through wrappers to the right content
221-
i = wrap[0];
222-
while (i--) {
223-
tmp = tmp.lastChild;
259+
// Create wrappers & descend into them
260+
i = wrap.length;
261+
while (--i > -1) {
262+
tmp.appendChild(window.document.createElement(wrap[i]));
263+
tmp = tmp.firstChild;
264+
}
265+
266+
tmp.innerHTML = finalHtml;
224267
}
225268

226269
nodes = concat(nodes, tmp.childNodes);

0 commit comments

Comments
 (0)