mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-06-19 17:53:27 +08:00
feat($compile): change directive's restrict setting to default to EA (element/attribute)
Previously we defaulted just to A because of IE8 which had a hard time with applying css styles to HTMLUnknownElements. This is no longer the case with IE9, so we should make restrict default to EA. Doing so will make it easier to create components and avoid matching errors when creating new directives BREAKING CHANGE: directives now match elements by default unless specific restriction rules are set via `restrict` property. This means that if a directive 'myFoo' previously didn't specify matching restrictrion, it will now match both the attribute and element form. Before: <div my-foo></div> <---- my-foo attribute matched the directive <my-foo></my-foo> <---- no match After: <div my-foo></div> <---- my-foo attribute matched the directive <my-foo></my-foo> <---- my-foo element matched the directive It is not expected that this will be a problem in practice because of widespread use of prefixes that make "<my-foo>" like elements unlikely. Closes #8321
This commit is contained in:
@@ -213,7 +213,7 @@
|
|||||||
* String of subset of `EACM` which restricts the directive to a specific directive
|
* String of subset of `EACM` which restricts the directive to a specific directive
|
||||||
* declaration style. If omitted, the default (attributes only) is used.
|
* declaration style. If omitted, the default (attributes only) is used.
|
||||||
*
|
*
|
||||||
* * `E` - Element name: `<my-directive></my-directive>`
|
* * `E` - Element name (default): `<my-directive></my-directive>`
|
||||||
* * `A` - Attribute (default): `<div my-directive="exp"></div>`
|
* * `A` - Attribute (default): `<div my-directive="exp"></div>`
|
||||||
* * `C` - Class: `<div class="my-directive: exp;"></div>`
|
* * `C` - Class: `<div class="my-directive: exp;"></div>`
|
||||||
* * `M` - Comment: `<!-- directive: my-directive exp -->`
|
* * `M` - Comment: `<!-- directive: my-directive exp -->`
|
||||||
@@ -581,7 +581,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|||||||
directive.index = index;
|
directive.index = index;
|
||||||
directive.name = directive.name || name;
|
directive.name = directive.name || name;
|
||||||
directive.require = directive.require || (directive.controller && directive.name);
|
directive.require = directive.require || (directive.controller && directive.name);
|
||||||
directive.restrict = directive.restrict || 'A';
|
directive.restrict = directive.restrict || 'EA';
|
||||||
directives.push(directive);
|
directives.push(directive);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
$exceptionHandler(e);
|
$exceptionHandler(e);
|
||||||
|
|||||||
@@ -351,6 +351,7 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
|
|||||||
var normalized = directiveNormalize('ng-' + attrName);
|
var normalized = directiveNormalize('ng-' + attrName);
|
||||||
ngAttributeAliasDirectives[normalized] = function() {
|
ngAttributeAliasDirectives[normalized] = function() {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
priority: 100,
|
priority: 100,
|
||||||
link: function(scope, element, attr) {
|
link: function(scope, element, attr) {
|
||||||
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
|
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
|
||||||
|
|||||||
@@ -2150,6 +2150,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|||||||
*/
|
*/
|
||||||
var ngModelDirective = function() {
|
var ngModelDirective = function() {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
require: ['ngModel', '^?form', '^?ngModelOptions'],
|
require: ['ngModel', '^?form', '^?ngModelOptions'],
|
||||||
controller: NgModelController,
|
controller: NgModelController,
|
||||||
link: {
|
link: {
|
||||||
@@ -2251,6 +2252,7 @@ var ngModelDirective = function() {
|
|||||||
* </example>
|
* </example>
|
||||||
*/
|
*/
|
||||||
var ngChangeDirective = valueFn({
|
var ngChangeDirective = valueFn({
|
||||||
|
restrict: 'A',
|
||||||
require: 'ngModel',
|
require: 'ngModel',
|
||||||
link: function(scope, element, attr, ctrl) {
|
link: function(scope, element, attr, ctrl) {
|
||||||
ctrl.$viewChangeListeners.push(function() {
|
ctrl.$viewChangeListeners.push(function() {
|
||||||
@@ -2262,6 +2264,7 @@ var ngChangeDirective = valueFn({
|
|||||||
|
|
||||||
var requiredDirective = function() {
|
var requiredDirective = function() {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
require: '?ngModel',
|
require: '?ngModel',
|
||||||
link: function(scope, elm, attr, ctrl) {
|
link: function(scope, elm, attr, ctrl) {
|
||||||
if (!ctrl) return;
|
if (!ctrl) return;
|
||||||
@@ -2281,6 +2284,7 @@ var requiredDirective = function() {
|
|||||||
|
|
||||||
var patternDirective = function() {
|
var patternDirective = function() {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
require: '?ngModel',
|
require: '?ngModel',
|
||||||
link: function(scope, elm, attr, ctrl) {
|
link: function(scope, elm, attr, ctrl) {
|
||||||
if (!ctrl) return;
|
if (!ctrl) return;
|
||||||
@@ -2311,6 +2315,7 @@ var patternDirective = function() {
|
|||||||
|
|
||||||
var maxlengthDirective = function() {
|
var maxlengthDirective = function() {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
require: '?ngModel',
|
require: '?ngModel',
|
||||||
link: function(scope, elm, attr, ctrl) {
|
link: function(scope, elm, attr, ctrl) {
|
||||||
if (!ctrl) return;
|
if (!ctrl) return;
|
||||||
@@ -2329,6 +2334,7 @@ var maxlengthDirective = function() {
|
|||||||
|
|
||||||
var minlengthDirective = function() {
|
var minlengthDirective = function() {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
require: '?ngModel',
|
require: '?ngModel',
|
||||||
link: function(scope, elm, attr, ctrl) {
|
link: function(scope, elm, attr, ctrl) {
|
||||||
if (!ctrl) return;
|
if (!ctrl) return;
|
||||||
@@ -2430,6 +2436,7 @@ var minlengthDirective = function() {
|
|||||||
*/
|
*/
|
||||||
var ngListDirective = function() {
|
var ngListDirective = function() {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
require: 'ngModel',
|
require: 'ngModel',
|
||||||
link: function(scope, element, attr, ctrl) {
|
link: function(scope, element, attr, ctrl) {
|
||||||
// We want to control whitespace trimming so we use this convoluted approach
|
// We want to control whitespace trimming so we use this convoluted approach
|
||||||
@@ -2526,6 +2533,7 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
|
|||||||
*/
|
*/
|
||||||
var ngValueDirective = function() {
|
var ngValueDirective = function() {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
priority: 100,
|
priority: 100,
|
||||||
compile: function(tpl, tplAttr) {
|
compile: function(tpl, tplAttr) {
|
||||||
if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
|
if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
|
||||||
@@ -2688,6 +2696,7 @@ var ngValueDirective = function() {
|
|||||||
*/
|
*/
|
||||||
var ngModelOptionsDirective = function() {
|
var ngModelOptionsDirective = function() {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
controller: ['$scope', '$attrs', function($scope, $attrs) {
|
controller: ['$scope', '$attrs', function($scope, $attrs) {
|
||||||
var that = this;
|
var that = this;
|
||||||
this.$options = $scope.$eval($attrs.ngModelOptions);
|
this.$options = $scope.$eval($attrs.ngModelOptions);
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
|
|||||||
*/
|
*/
|
||||||
var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
|
var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
compile: function (tElement, tAttrs) {
|
compile: function (tElement, tAttrs) {
|
||||||
tElement.addClass('ng-binding');
|
tElement.addClass('ng-binding');
|
||||||
|
|
||||||
|
|||||||
@@ -221,6 +221,7 @@
|
|||||||
*/
|
*/
|
||||||
var ngControllerDirective = [function() {
|
var ngControllerDirective = [function() {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
scope: true,
|
scope: true,
|
||||||
controller: '@',
|
controller: '@',
|
||||||
priority: 500
|
priority: 500
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ forEach(
|
|||||||
var directiveName = directiveNormalize('ng-' + name);
|
var directiveName = directiveNormalize('ng-' + name);
|
||||||
ngEventDirectives[directiveName] = ['$parse', function($parse) {
|
ngEventDirectives[directiveName] = ['$parse', function($parse) {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
compile: function($element, attr) {
|
compile: function($element, attr) {
|
||||||
var fn = $parse(attr[directiveName]);
|
var fn = $parse(attr[directiveName]);
|
||||||
return function ngEventHandler(scope, element) {
|
return function ngEventHandler(scope, element) {
|
||||||
|
|||||||
@@ -212,6 +212,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
|||||||
var NG_REMOVED = '$$NG_REMOVED';
|
var NG_REMOVED = '$$NG_REMOVED';
|
||||||
var ngRepeatMinErr = minErr('ngRepeat');
|
var ngRepeatMinErr = minErr('ngRepeat');
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
multiElement: true,
|
multiElement: true,
|
||||||
transclude: 'element',
|
transclude: 'element',
|
||||||
priority: 1000,
|
priority: 1000,
|
||||||
|
|||||||
@@ -157,6 +157,7 @@
|
|||||||
*/
|
*/
|
||||||
var ngShowDirective = ['$animate', function($animate) {
|
var ngShowDirective = ['$animate', function($animate) {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
multiElement: true,
|
multiElement: true,
|
||||||
link: function(scope, element, attr) {
|
link: function(scope, element, attr) {
|
||||||
scope.$watch(attr.ngShow, function ngShowWatchAction(value){
|
scope.$watch(attr.ngShow, function ngShowWatchAction(value){
|
||||||
@@ -311,6 +312,7 @@ var ngShowDirective = ['$animate', function($animate) {
|
|||||||
*/
|
*/
|
||||||
var ngHideDirective = ['$animate', function($animate) {
|
var ngHideDirective = ['$animate', function($animate) {
|
||||||
return {
|
return {
|
||||||
|
restrict: 'A',
|
||||||
multiElement: true,
|
multiElement: true,
|
||||||
link: function(scope, element, attr) {
|
link: function(scope, element, attr) {
|
||||||
scope.$watch(attr.ngHide, function ngHideWatchAction(value){
|
scope.$watch(attr.ngHide, function ngHideWatchAction(value){
|
||||||
|
|||||||
@@ -135,7 +135,11 @@ var ngOptionsMinErr = minErr('ngOptions');
|
|||||||
</example>
|
</example>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var ngOptionsDirective = valueFn({ terminal: true });
|
var ngOptionsDirective = valueFn({
|
||||||
|
restrict: 'A',
|
||||||
|
terminal: true
|
||||||
|
});
|
||||||
|
|
||||||
// jshint maxlen: false
|
// jshint maxlen: false
|
||||||
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||||
//000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
|
//000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
|
||||||
|
|||||||
@@ -255,14 +255,6 @@ describe('$compile', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should allow directives in comments', inject(
|
|
||||||
function($compile, $rootScope, log) {
|
|
||||||
element = $compile('<div>0<!-- directive: log angular -->1</div>')($rootScope);
|
|
||||||
expect(log).toEqual('angular');
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
|
|
||||||
it('should receive scope, element, and attributes', function() {
|
it('should receive scope, element, and attributes', function() {
|
||||||
var injector;
|
var injector;
|
||||||
module(function() {
|
module(function() {
|
||||||
@@ -437,20 +429,21 @@ describe('$compile', function() {
|
|||||||
|
|
||||||
describe('restrict', function() {
|
describe('restrict', function() {
|
||||||
|
|
||||||
it('should allow restriction of attributes', function() {
|
it('should allow restriction of availability', function () {
|
||||||
module(function() {
|
module(function () {
|
||||||
forEach({div:'E', attr:'A', clazz:'C', all:'EAC'}, function(restrict, name) {
|
forEach({div: 'E', attr: 'A', clazz: 'C', comment: 'M', all: 'EACM'},
|
||||||
directive(name, function(log) {
|
function (restrict, name) {
|
||||||
|
directive(name, function (log) {
|
||||||
return {
|
return {
|
||||||
restrict: restrict,
|
restrict: restrict,
|
||||||
compile: valueFn(function(scope, element, attr) {
|
compile: valueFn(function (scope, element, attr) {
|
||||||
log(name);
|
log(name);
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
inject(function($rootScope, $compile, log) {
|
inject(function ($rootScope, $compile, log) {
|
||||||
dealoc($compile('<span div class="div"></span>')($rootScope));
|
dealoc($compile('<span div class="div"></span>')($rootScope));
|
||||||
expect(log).toEqual('');
|
expect(log).toEqual('');
|
||||||
log.reset();
|
log.reset();
|
||||||
@@ -459,7 +452,7 @@ describe('$compile', function() {
|
|||||||
expect(log).toEqual('div');
|
expect(log).toEqual('div');
|
||||||
log.reset();
|
log.reset();
|
||||||
|
|
||||||
dealoc($compile('<attr class=""attr"></attr>')($rootScope));
|
dealoc($compile('<attr class="attr"></attr>')($rootScope));
|
||||||
expect(log).toEqual('');
|
expect(log).toEqual('');
|
||||||
log.reset();
|
log.reset();
|
||||||
|
|
||||||
@@ -475,8 +468,38 @@ describe('$compile', function() {
|
|||||||
expect(log).toEqual('clazz');
|
expect(log).toEqual('clazz');
|
||||||
log.reset();
|
log.reset();
|
||||||
|
|
||||||
dealoc($compile('<all class="all" all></all>')($rootScope));
|
dealoc($compile('<!-- directive: comment -->')($rootScope));
|
||||||
expect(log).toEqual('all; all; all');
|
expect(log).toEqual('comment');
|
||||||
|
log.reset();
|
||||||
|
|
||||||
|
dealoc($compile('<all class="all" all><!-- directive: all --></all>')($rootScope));
|
||||||
|
expect(log).toEqual('all; all; all; all');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should use EA rule as the default', function () {
|
||||||
|
module(function () {
|
||||||
|
directive('defaultDir', function (log) {
|
||||||
|
return {
|
||||||
|
compile: function () {
|
||||||
|
log('defaultDir');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
inject(function ($rootScope, $compile, log) {
|
||||||
|
dealoc($compile('<span default-dir ></span>')($rootScope));
|
||||||
|
expect(log).toEqual('defaultDir');
|
||||||
|
log.reset();
|
||||||
|
|
||||||
|
dealoc($compile('<default-dir></default-dir>')($rootScope));
|
||||||
|
expect(log).toEqual('defaultDir');
|
||||||
|
log.reset();
|
||||||
|
|
||||||
|
dealoc($compile('<span class="default-dir"></span>')($rootScope));
|
||||||
|
expect(log).toEqual('');
|
||||||
|
log.reset();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user