Compare commits

..

5 Commits

Author SHA1 Message Date
George Kalpakas 223cf2b5bb docs(CHANGELOG): add release notes for 1.7.2 2018-06-12 16:34:38 +03:00
George Kalpakas c387e0d79d chore(doc-gen): error on unmatched links
Closes #16597
2018-06-12 14:45:22 +03:00
George Kalpakas cbf74d5d64 docs(*): fix dangling or ambiguous links 2018-06-12 14:45:06 +03:00
George Kalpakas a812327acd revert: refactor($compile): remove preAssignBindingsEnabled leftovers
This reverts commit 8e104ee508.

This internal clean-up turned out to break popular UI libraries (e.g.
`ngMaterial`, `ui-bootstrap`) and cause pain to developers.

Fixes #16594

Closes #16595
2018-06-11 17:09:48 +03:00
George Kalpakas 35fce310e9 docs(CHANGELOG): fix links to issues/PRs 2018-06-08 17:10:08 +03:00
12 changed files with 937 additions and 131 deletions
+46 -26
View File
@@ -1,3 +1,23 @@
<a name="1.7.2"></a>
# 1.7.2 extreme-compatiplication (2018-06-12)
In the previous release, we removed a private, undocumented API that was no longer used by
AngularJS. It turned out that several popular UI libraries (such as
[AngularJS Material](https://material.angularjs.org/),
[UI Bootstrap](https://angular-ui.github.io/bootstrap/),
[ngDialog](http://likeastore.github.io/ngDialog/) and probably others) relied on that API.
In order to avoid unnecessary pain for developers, this release reverts the removal of the private
API and restores compatibility of the aforementioned libraries with the latest AngularJS.
## Reverts
- **$compile:** remove `preAssignBindingsEnabled` leftovers
([2da495](https://github.com/angular/angular.js/commit/2da49504065e9e2b71a7a5622e45118d8abbe87e),
[#16580](https://github.com/angular/angular.js/pull/16580),
[a81232](https://github.com/angular/angular.js/commit/a812327acda8bc890a4c4e809f0debb761c29625),
[#16595](https://github.com/angular/angular.js/pull/16595))
<a name="1.7.1"></a>
# 1.7.1 momentum-defiance (2018-06-08)
@@ -5,53 +25,53 @@
## Bug Fixes
- **$compile:** support transcluding multi-element directives
([789db8](https://github.com/angular/angular.js/commit/789db83a8ae0e2db5db13289b2c29e56093d967a),
[#15554](https://github.com/angular/angular.js.git/issues/15554),
[#15555](https://github.com/angular/angular.js.git/issues/15555))
[#15554](https://github.com/angular/angular.js/issues/15554),
[#15555](https://github.com/angular/angular.js/issues/15555))
- **ngModel:** do not throw if view value changes on destroyed scope
([2b6c98](https://github.com/angular/angular.js/commit/2b6c9867369fd3ef1ddb687af1153478ab62ee1b),
[#16583](https://github.com/angular/angular.js.git/issues/16583),
[#16585](https://github.com/angular/angular.js.git/issues/16585))
[#16583](https://github.com/angular/angular.js/issues/16583),
[#16585](https://github.com/angular/angular.js/issues/16585))
## New Features
- **$compile:** add one-way collection bindings
([f9d1ca](https://github.com/angular/angular.js/commit/f9d1ca20c38f065f15769fbe23aee5314cb58bd4),
[#14039](https://github.com/angular/angular.js.git/issues/14039),
[#16553](https://github.com/angular/angular.js.git/issues/16553),
[#15874](https://github.com/angular/angular.js.git/issues/15874))
[#14039](https://github.com/angular/angular.js/issues/14039),
[#16553](https://github.com/angular/angular.js/issues/16553),
[#15874](https://github.com/angular/angular.js/issues/15874))
- **ngRef:** add directive to publish controller, or element into scope
([bf841d](https://github.com/angular/angular.js/commit/bf841d35120bf3c4655fde46af4105c85a0f1cdc),
[#16511](https://github.com/angular/angular.js.git/issues/16511))
[#16511](https://github.com/angular/angular.js/issues/16511))
- **errorHandlingConfig:** add option to exclude error params from url
([3d6c45](https://github.com/angular/angular.js/commit/3d6c45d76e30b1b3c4eb9672cf4a93e5251c06b3),
[#14744](https://github.com/angular/angular.js.git/issues/14744),
[#15707](https://github.com/angular/angular.js.git/issues/15707),
[#16283](https://github.com/angular/angular.js.git/issues/16283),
[#16299](https://github.com/angular/angular.js.git/issues/16299),
[#16591](https://github.com/angular/angular.js.git/issues/16591))
[#14744](https://github.com/angular/angular.js/issues/14744),
[#15707](https://github.com/angular/angular.js/issues/15707),
[#16283](https://github.com/angular/angular.js/issues/16283),
[#16299](https://github.com/angular/angular.js/issues/16299),
[#16591](https://github.com/angular/angular.js/issues/16591))
- **ngAria:** add support for ignoring a specific element
([7d9d38](https://github.com/angular/angular.js/commit/7d9d387195292cb5e04984602b752d31853cfea6),
[#14602](https://github.com/angular/angular.js.git/issues/14602),
[#14672](https://github.com/angular/angular.js.git/issues/14672),
[#14833](https://github.com/angular/angular.js.git/issues/14833))
[#14602](https://github.com/angular/angular.js/issues/14602),
[#14672](https://github.com/angular/angular.js/issues/14672),
[#14833](https://github.com/angular/angular.js/issues/14833))
- **ngCookies:** support samesite option
([10a229](https://github.com/angular/angular.js/commit/10a229ce1befdeaf6295d1635dc11391c252a91a),
[#16543](https://github.com/angular/angular.js.git/issues/16543),
[#16544](https://github.com/angular/angular.js.git/issues/16544))
[#16543](https://github.com/angular/angular.js/issues/16543),
[#16544](https://github.com/angular/angular.js/issues/16544))
- **ngMessages:** add support for default message
([a8c263](https://github.com/angular/angular.js/commit/a8c263c1947cc85ee60b4732f7e4bcdc7ba463e8),
[#12008](https://github.com/angular/angular.js.git/issues/12008),
[#12213](https://github.com/angular/angular.js.git/issues/12213),
[#16587](https://github.com/angular/angular.js.git/issues/16587))
[#12008](https://github.com/angular/angular.js/issues/12008),
[#12213](https://github.com/angular/angular.js/issues/12213),
[#16587](https://github.com/angular/angular.js/issues/16587))
- **ngMock, ngMockE2E:** add option to match latest definition for `$httpBackend` request
([773f39](https://github.com/angular/angular.js/commit/773f39c9345479f5f8b6321236ce6ad96f77aa92),
[#16251](https://github.com/angular/angular.js.git/issues/16251),
[#11637](https://github.com/angular/angular.js.git/issues/11637),
[#16560](https://github.com/angular/angular.js.git/issues/16560))
[#16251](https://github.com/angular/angular.js/issues/16251),
[#11637](https://github.com/angular/angular.js/issues/11637),
[#16560](https://github.com/angular/angular.js/issues/16560))
- **$route:** add support for the `reloadOnUrl` configuration option
([f4f571](https://github.com/angular/angular.js/commit/f4f571efdf86d6acbcd5c6b1de66b4b33a259125),
[#7925](https://github.com/angular/angular.js.git/issues/7925),
[#15002](https://github.com/angular/angular.js.git/issues/15002))
[#7925](https://github.com/angular/angular.js/issues/7925),
[#15002](https://github.com/angular/angular.js/issues/15002))
<a name="1.7.0"></a>
+1
View File
@@ -148,6 +148,7 @@ module.exports = new Package('angularjs', [
.config(function(checkAnchorLinksProcessor) {
checkAnchorLinksProcessor.base = '/';
checkAnchorLinksProcessor.errorOnUnmatchedLinks = true;
// We are only interested in docs that have an area (i.e. they are pages)
checkAnchorLinksProcessor.checkDoc = function(doc) { return doc.area; };
})
+16 -8
View File
@@ -30,13 +30,21 @@ Any version branch not shown in the following table (e.g. 1.5.x) is no longer be
Any version branch not shown in the following table (e.g. 1.6.x) is no longer being developed.
<table class="dev-status table table-bordered">
<thead>
<tr><th>Version</th><th>Status</th><th>Comments</th></tr>
</thead>
<tbody>
<tr class="security"><td><span>1.2.x</span></td><td>Long Term Support</td><td>Last version to provide IE 8 support</td></tr>
<tr class="stable"><td><span>1.7.x</span></td><td>Long Term Support</td><td>See [Long Term Support](#long-term-support) section below.</td></tr>
</tbody>
<thead>
<tr><th>Version</th><th>Status</th><th>Comments</th></tr>
</thead>
<tbody>
<tr class="security">
<td><span>1.2.x</span></td>
<td>Long Term Support</td>
<td>Last version to provide IE 8 support</td>
</tr>
<tr class="stable">
<td><span>1.7.x</span></td>
<td>Long Term Support</td>
<td>See {@link version-support-status#long-term-support Long Term Support} section below.</td>
</tr>
</tbody>
</table>
### Long Term Support
@@ -51,4 +59,4 @@ At this time we will focus exclusively on providing fixes to bugs that satisfy a
### Blog Post
You can read more about these plans in our [blog post announcement](https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c).
You can read more about these plans in our [blog post announcement](https://blog.angular.io/stable-angularjs-and-long-term-support-7e077635ee9c).
+2 -2
View File
@@ -32,8 +32,8 @@
"commitplease": "^2.7.10",
"cross-spawn": "^4.0.0",
"cz-conventional-changelog": "1.1.4",
"dgeni": "^0.4.0",
"dgeni-packages": "^0.16.4",
"dgeni": "^0.4.9",
"dgeni-packages": "^0.26.2",
"eslint-plugin-promise": "^3.6.0",
"event-stream": "~3.1.0",
"glob": "^6.0.1",
+26 -4
View File
@@ -70,8 +70,12 @@ var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var $injectorMinErr = minErr('$injector');
function stringifyFn(fn) {
return Function.prototype.toString.call(fn);
}
function extractArgs(fn) {
var fnText = Function.prototype.toString.call(fn).replace(STRIP_COMMENTS, ''),
var fnText = stringifyFn(fn).replace(STRIP_COMMENTS, ''),
args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
return args;
}
@@ -910,6 +914,19 @@ function createInjector(modulesToLoad, strictDi) {
return args;
}
function isClass(func) {
// Support: IE 9-11 only
// IE 9-11 do not support classes and IE9 leaks with the code below.
if (msie || typeof func !== 'function') {
return false;
}
var result = func.$$ngIsClass;
if (!isBoolean(result)) {
result = func.$$ngIsClass = /^class\b/.test(stringifyFn(func));
}
return result;
}
function invoke(fn, self, locals, serviceName) {
if (typeof locals === 'string') {
serviceName = locals;
@@ -921,9 +938,14 @@ function createInjector(modulesToLoad, strictDi) {
fn = fn[fn.length - 1];
}
// http://jsperf.com/angularjs-invoke-apply-vs-switch
// #5388
return fn.apply(self, args);
if (!isClass(fn)) {
// http://jsperf.com/angularjs-invoke-apply-vs-switch
// #5388
return fn.apply(self, args);
} else {
args.unshift(null);
return new (Function.prototype.bind.apply(fn, args))();
}
}
+73 -57
View File
@@ -2790,6 +2790,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
};
}
if (controllerDirectives) {
elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective);
}
if (newIsolateScopeDirective) {
// Initialize isolate scope bindings for new isolate scope directive.
compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
@@ -2805,69 +2809,53 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
if (controllerDirectives) {
elementControllers = createMap();
for (var name in controllerDirectives) {
var directive = controllerDirectives[name];
var locals = {
$scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
$element: $element,
$attrs: attrs,
$transclude: transcludeFn
};
// Initialize bindToController bindings
for (var name in elementControllers) {
var controllerDirective = controllerDirectives[name];
var controller = elementControllers[name];
var bindings = controllerDirective.$$bindings.bindToController;
var controllerConstructor = directive.controller;
if (controllerConstructor === '@') {
controllerConstructor = attrs[name];
}
var instance = $controller(controllerConstructor, locals, directive.controllerAs);
$element.data('$' + name + 'Controller', instance);
// Initialize bindToController bindings
var bindings = directive.$$bindings.bindToController;
var bindingInfo = initializeDirectiveBindings(controllerScope, attrs, instance, bindings, directive);
elementControllers[name] = { instance: instance, bindingInfo: bindingInfo };
controller.instance = controller();
$element.data('$' + controllerDirective.name + 'Controller', controller.instance);
controller.bindingInfo =
initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
}
// Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
forEach(controllerDirectives, function(controllerDirective, name) {
var require = controllerDirective.require;
if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
}
});
// Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
forEach(controllerDirectives, function(controllerDirective, name) {
var require = controllerDirective.require;
if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
}
});
// Handle the init and destroy lifecycle hooks on all controllers that have them
forEach(elementControllers, function(controller) {
var controllerInstance = controller.instance;
if (isFunction(controllerInstance.$onChanges)) {
try {
controllerInstance.$onChanges(controller.bindingInfo.initialChanges);
} catch (e) {
$exceptionHandler(e);
}
// Handle the init and destroy lifecycle hooks on all controllers that have them
forEach(elementControllers, function(controller) {
var controllerInstance = controller.instance;
if (isFunction(controllerInstance.$onChanges)) {
try {
controllerInstance.$onChanges(controller.bindingInfo.initialChanges);
} catch (e) {
$exceptionHandler(e);
}
if (isFunction(controllerInstance.$onInit)) {
try {
controllerInstance.$onInit();
} catch (e) {
$exceptionHandler(e);
}
}
if (isFunction(controllerInstance.$onInit)) {
try {
controllerInstance.$onInit();
} catch (e) {
$exceptionHandler(e);
}
if (isFunction(controllerInstance.$doCheck)) {
controllerScope.$watch(function() { controllerInstance.$doCheck(); });
controllerInstance.$doCheck();
}
if (isFunction(controllerInstance.$onDestroy)) {
controllerScope.$on('$destroy', function callOnDestroyHook() {
controllerInstance.$onDestroy();
});
}
});
}
}
if (isFunction(controllerInstance.$doCheck)) {
controllerScope.$watch(function() { controllerInstance.$doCheck(); });
controllerInstance.$doCheck();
}
if (isFunction(controllerInstance.$onDestroy)) {
controllerScope.$on('$destroy', function callOnDestroyHook() {
controllerInstance.$onDestroy();
});
}
});
// PRELINKING
for (i = 0, ii = preLinkFns.length; i < ii; i++) {
@@ -2995,6 +2983,34 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return value || null;
}
function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective) {
var elementControllers = createMap();
for (var controllerKey in controllerDirectives) {
var directive = controllerDirectives[controllerKey];
var locals = {
$scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
$element: $element,
$attrs: attrs,
$transclude: transcludeFn
};
var controller = directive.controller;
if (controller === '@') {
controller = attrs[directive.name];
}
var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
// For directives with element transclusion the element is a comment.
// In this case .data will not attach any data.
// Instead, we save the controllers for the element in a local hash and attach to .data
// later, once we have the actual element.
elementControllers[directive.name] = controllerInstance;
$element.data('$' + directive.name + 'Controller', controllerInstance.instance);
}
return elementControllers;
}
// Depending upon the context in which a directive finds itself it might need to have a new isolated
// or child scope created. For instance:
// * if the directive has been pulled into a template because another directive with a higher priority
+41 -1
View File
@@ -81,11 +81,16 @@ function $ControllerProvider() {
* It's just a simple call to {@link auto.$injector $injector}, but extracted into
* a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
*/
return function $controller(expression, locals, ident) {
return function $controller(expression, locals, later, ident) {
// PRIVATE API:
// param `later` --- indicates that the controller's constructor is invoked at a later time.
// If true, $controller will allocate the object with the correct
// prototype chain, but will not invoke the controller until a returned
// callback is invoked.
// param `ident` --- An optional label which overrides the label parsed from the controller
// expression, if any.
var instance, match, constructor, identifier;
later = later === true;
if (ident && isString(ident)) {
identifier = ident;
}
@@ -111,6 +116,41 @@ function $ControllerProvider() {
assertArgFn(expression, constructor, true);
}
if (later) {
// Instantiate controller later:
// This machinery is used to create an instance of the object before calling the
// controller's constructor itself.
//
// This allows properties to be added to the controller before the constructor is
// invoked. Primarily, this is used for isolate scope bindings in $compile.
//
// This feature is not intended for use by applications, and is thus not documented
// publicly.
// Object creation: http://jsperf.com/create-constructor/2
var controllerPrototype = (isArray(expression) ?
expression[expression.length - 1] : expression).prototype;
instance = Object.create(controllerPrototype || null);
if (identifier) {
addIdentifier(locals, identifier, instance, constructor || expression.name);
}
return extend(function $controllerInit() {
var result = $injector.invoke(expression, instance, locals, constructor);
if (result !== instance && (isObject(result) || isFunction(result))) {
instance = result;
if (identifier) {
// If result changed, re-assign controllerAs value to scope.
addIdentifier(locals, identifier, instance, constructor || expression.name);
}
}
return instance;
}, {
instance: instance,
identifier: identifier
});
}
instance = $injector.instantiate(expression, locals, constructor);
if (identifier) {
+3 -3
View File
@@ -281,9 +281,9 @@
*
* Sometimes you need to animate between different expression states, whose values
* don't necessary need to be known or referenced in CSS styles.
* Unless possible with another ["animation aware" directive](#directive-support), that specific
* use case can always be covered with {@link ngAnimate.directive:ngAnimateSwap} as can be seen in
* {@link ngAnimate.directive:ngAnimateSwap#examples this example}.
* Unless possible with another {@link ngAnimate#directive-support "animation aware" directive},
* that specific use case can always be covered with {@link ngAnimate.directive:ngAnimateSwap} as
* can be seen in {@link ngAnimate.directive:ngAnimateSwap#examples this example}.
*
* Note that {@link ngAnimate.directive:ngAnimateSwap} is a *structural directive*, which means it
* creates a new instance of the element (including any other/child directives it may have) and
+1 -1
View File
@@ -704,7 +704,7 @@ angular.module('ngMessages', [], function initAngularHelpers() {
*
* @description
* `ngMessageDefault` is a directive with the purpose to show and hide a default message for
* {@link ngMessages}, when none of provided messages matches.
* {@link directive:ngMessages}, when none of provided messages matches.
*
* More information about using `ngMessageDefault` can be found in the
* {@link module:ngMessages `ngMessages` module documentation}.
+8 -5
View File
@@ -2345,11 +2345,14 @@ angular.mock.$RootElementProvider = function() {
*/
function createControllerDecorator() {
angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
return function(expression, locals, bindings, ident) {
if (angular.isString(bindings)) ident = bindings;
var instance = $delegate(expression, locals, ident);
angular.extend(instance, bindings);
return instance;
return function(expression, locals, later, ident) {
if (later && typeof later === 'object') {
var instantiate = $delegate(expression, locals, true, ident);
var instance = instantiate();
angular.extend(instance, later);
return instance;
}
return $delegate(expression, locals, later, ident);
};
}];
+19
View File
@@ -482,6 +482,25 @@ describe('injector', function() {
expect(instance).toEqual(new Clazz('a-value'));
expect(instance.aVal()).toEqual('a-value');
});
they('should detect ES6 classes regardless of whitespace/comments ($prop)', [
'class Test {}',
'class Test{}',
'class //<--ES6 stuff\nTest {}',
'class//<--ES6 stuff\nTest {}',
'class {}',
'class{}',
'class //<--ES6 stuff\n {}',
'class//<--ES6 stuff\n {}',
'class/* Test */{}',
'class /* Test */ {}'
], function(classDefinition) {
// eslint-disable-next-line no-eval
var Clazz = eval('(' + classDefinition + ')');
var instance = injector.invoke(Clazz);
expect(instance).toEqual(jasmine.any(Clazz));
});
}
});
+701 -24
View File
File diff suppressed because it is too large Load Diff