Skip to content

Commit 9530491

Browse files
Merge pull request #129 from angular/master
Update upstream
2 parents e050598 + 3a2aea7 commit 9530491

17 files changed

+963
-157
lines changed

scripts/travis/build.sh

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ export SAUCE_ACCESS_KEY
1111
BROWSER_STACK_ACCESS_KEY=$(echo "$BROWSER_STACK_ACCESS_KEY" | rev)
1212
SAUCE_ACCESS_KEY=$(echo "$SAUCE_ACCESS_KEY" | rev)
1313

14+
# TODO: restore "SL_EDGE-1" once Sauce Labs adds Edge 17 and "SL_EDGE-1" refers
15+
# to version 16. Edge 15 disconnects from Karma frequently causing extreme build instability.
1416
BROWSERS="SL_Chrome,SL_Chrome-1,\
1517
SL_Firefox,SL_Firefox-1,\
1618
SL_Safari,SL_Safari-1,\
1719
SL_iOS_10,SL_iOS_11,\
1820
SL_IE_9,SL_IE_10,SL_IE_11,\
19-
SL_EDGE,SL_EDGE-1"
21+
SL_EDGE"
2022

2123
case "$JOB" in
2224
"ci-checks")

src/.eslintrc.json

+2
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"toJsonReplacer": false,
8080
"toJson": false,
8181
"fromJson": false,
82+
"addDateMinutes": false,
8283
"convertTimezoneToLocal": false,
8384
"timezoneToOffset": false,
8485
"startingTag": false,
@@ -161,6 +162,7 @@
161162
"urlResolve": false,
162163
"urlIsSameOrigin": false,
163164
"urlIsSameOriginAsBaseUrl": false,
165+
"urlIsAllowedOriginFactory": false,
164166

165167
/* ng/controller.js */
166168
"identifierForController": false,

src/Angular.js

+17-16
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
fromJson,
7676
convertTimezoneToLocal,
7777
timezoneToOffset,
78+
addDateMinutes,
7879
startingTag,
7980
tryDecodeURIComponent,
8081
parseKeyValue,
@@ -1369,7 +1370,7 @@ function convertTimezoneToLocal(date, timezone, reverse) {
13691370
*/
13701371
function startingTag(element) {
13711372
element = jqLite(element).clone().empty();
1372-
var elemHtml = jqLite('<div>').append(element).html();
1373+
var elemHtml = jqLite('<div></div>').append(element).html();
13731374
try {
13741375
return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
13751376
elemHtml.
@@ -1924,25 +1925,25 @@ function bindJQuery() {
19241925
injector: JQLitePrototype.injector,
19251926
inheritedData: JQLitePrototype.inheritedData
19261927
});
1927-
1928-
// All nodes removed from the DOM via various jQuery APIs like .remove()
1929-
// are passed through jQuery.cleanData. Monkey-patch this method to fire
1930-
// the $destroy event on all removed nodes.
1931-
originalCleanData = jQuery.cleanData;
1932-
jQuery.cleanData = function(elems) {
1933-
var events;
1934-
for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1935-
events = jQuery._data(elem, 'events');
1936-
if (events && events.$destroy) {
1937-
jQuery(elem).triggerHandler('$destroy');
1938-
}
1939-
}
1940-
originalCleanData(elems);
1941-
};
19421928
} else {
19431929
jqLite = JQLite;
19441930
}
19451931

1932+
// All nodes removed from the DOM via various jqLite/jQuery APIs like .remove()
1933+
// are passed through jqLite/jQuery.cleanData. Monkey-patch this method to fire
1934+
// the $destroy event on all removed nodes.
1935+
originalCleanData = jqLite.cleanData;
1936+
jqLite.cleanData = function(elems) {
1937+
var events;
1938+
for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1939+
events = jqLite._data(elem).events;
1940+
if (events && events.$destroy) {
1941+
jqLite(elem).triggerHandler('$destroy');
1942+
}
1943+
}
1944+
originalCleanData(elems);
1945+
};
1946+
19461947
angular.element = jqLite;
19471948

19481949
// Prevent double-proxying.

src/jqLite.js

+30-10
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@
5454
*
5555
* - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument
5656
* - [`after()`](http://api.jquery.com/after/)
57-
* - [`append()`](http://api.jquery.com/append/)
57+
* - [`append()`](http://api.jquery.com/append/) - Contrary to jQuery, this doesn't clone elements
58+
* so will not work correctly when invoked on a jqLite object containing more than one DOM node
5859
* - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
5960
* - [`bind()`](http://api.jquery.com/bind/) (_deprecated_, use [`on()`](http://api.jquery.com/on/)) - Does not support namespaces, selectors or eventData
6061
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
@@ -310,6 +311,28 @@ function jqLiteDealoc(element, onlyDescendants) {
310311
}
311312
}
312313

314+
function isEmptyObject(obj) {
315+
var name;
316+
317+
for (name in obj) {
318+
return false;
319+
}
320+
return true;
321+
}
322+
323+
function removeIfEmptyData(element) {
324+
var expandoId = element.ng339;
325+
var expandoStore = expandoId && jqCache[expandoId];
326+
327+
var events = expandoStore && expandoStore.events;
328+
var data = expandoStore && expandoStore.data;
329+
330+
if ((!data || isEmptyObject(data)) && (!events || isEmptyObject(events))) {
331+
delete jqCache[expandoId];
332+
element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
333+
}
334+
}
335+
313336
function jqLiteOff(element, type, fn, unsupported) {
314337
if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
315338

@@ -346,6 +369,8 @@ function jqLiteOff(element, type, fn, unsupported) {
346369
}
347370
});
348371
}
372+
373+
removeIfEmptyData(element);
349374
}
350375

351376
function jqLiteRemoveData(element, name) {
@@ -355,17 +380,11 @@ function jqLiteRemoveData(element, name) {
355380
if (expandoStore) {
356381
if (name) {
357382
delete expandoStore.data[name];
358-
return;
383+
} else {
384+
expandoStore.data = {};
359385
}
360386

361-
if (expandoStore.handle) {
362-
if (expandoStore.events.$destroy) {
363-
expandoStore.handle({}, '$destroy');
364-
}
365-
jqLiteOff(element);
366-
}
367-
delete jqCache[expandoId];
368-
element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
387+
removeIfEmptyData(element);
369388
}
370389
}
371390

@@ -615,6 +634,7 @@ forEach({
615634
cleanData: function jqLiteCleanData(nodes) {
616635
for (var i = 0, ii = nodes.length; i < ii; i++) {
617636
jqLiteRemoveData(nodes[i]);
637+
jqLiteOff(nodes[i]);
618638
}
619639
}
620640
}, function(fn, name) {

src/ng/compile.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1941,7 +1941,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
19411941
// for call to the link function.
19421942
// Note: This will already clone the nodes...
19431943
$linkNode = jqLite(
1944-
wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
1944+
wrapTemplate(namespace, jqLite('<div></div>').append($compileNodes).html())
19451945
);
19461946
} else if (cloneConnectFn) {
19471947
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart

src/ng/directive/input.js

+25-8
Original file line numberDiff line numberDiff line change
@@ -1468,20 +1468,17 @@ function createDateInputType(type, regexp, parseDate, format) {
14681468
return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
14691469
badInputChecker(scope, element, attr, ctrl, type);
14701470
baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
1471-
var timezone = ctrl && ctrl.$options.getOption('timezone');
14721471
var previousDate;
1472+
var previousTimezone;
14731473

14741474
ctrl.$parsers.push(function(value) {
14751475
if (ctrl.$isEmpty(value)) return null;
1476+
14761477
if (regexp.test(value)) {
14771478
// Note: We cannot read ctrl.$modelValue, as there might be a different
14781479
// parser/formatter in the processing chain so that the model
14791480
// contains some different data format!
1480-
var parsedDate = parseDate(value, previousDate);
1481-
if (timezone) {
1482-
parsedDate = convertTimezoneToLocal(parsedDate, timezone);
1483-
}
1484-
return parsedDate;
1481+
return parseDateAndConvertTimeZoneToLocal(value, previousDate);
14851482
}
14861483
ctrl.$$parserName = type;
14871484
return undefined;
@@ -1493,12 +1490,15 @@ function createDateInputType(type, regexp, parseDate, format) {
14931490
}
14941491
if (isValidDate(value)) {
14951492
previousDate = value;
1496-
if (previousDate && timezone) {
1493+
var timezone = ctrl.$options.getOption('timezone');
1494+
if (timezone) {
1495+
previousTimezone = timezone;
14971496
previousDate = convertTimezoneToLocal(previousDate, timezone, true);
14981497
}
14991498
return $filter('date')(value, format, timezone);
15001499
} else {
15011500
previousDate = null;
1501+
previousTimezone = null;
15021502
return '';
15031503
}
15041504
});
@@ -1531,7 +1531,24 @@ function createDateInputType(type, regexp, parseDate, format) {
15311531
}
15321532

15331533
function parseObservedDateValue(val) {
1534-
return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
1534+
return isDefined(val) && !isDate(val) ? parseDateAndConvertTimeZoneToLocal(val) || undefined : val;
1535+
}
1536+
1537+
function parseDateAndConvertTimeZoneToLocal(value, previousDate) {
1538+
var timezone = ctrl.$options.getOption('timezone');
1539+
1540+
if (previousTimezone && previousTimezone !== timezone) {
1541+
// If the timezone has changed, adjust the previousDate to the default timezone
1542+
// so that the new date is converted with the correct timezone offset
1543+
previousDate = addDateMinutes(previousDate, timezoneToOffset(previousTimezone));
1544+
}
1545+
1546+
var parsedDate = parseDate(value, previousDate);
1547+
1548+
if (!isNaN(parsedDate) && timezone) {
1549+
parsedDate = convertTimezoneToLocal(parsedDate, timezone);
1550+
}
1551+
return parsedDate;
15351552
}
15361553
};
15371554
}

src/ng/directive/ngModelOptions.js

+2
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,8 @@ defaultModelOptions = new ModelOptions({
462462
* continental US time zone abbreviations, but for general use, use a time zone offset, for
463463
* example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
464464
* If not specified, the timezone of the browser will be used.
465+
* Note that changing the timezone will have no effect on the current date, and is only applied after
466+
* the next input / model change.
465467
*
466468
*/
467469
var ngModelOptionsDirective = function() {

0 commit comments

Comments
 (0)