Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
perf($compile): add a flag to compile only EA directives
Browse files Browse the repository at this point in the history
  • Loading branch information
drpicox committed Jun 30, 2016
1 parent 3a40bd4 commit e40345e
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 8 deletions.
8 changes: 8 additions & 0 deletions docs/content/error/$compile/rstrto.ngdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@ngdoc error
@name $compile:rstrto
@fullName Invalid restrictDirectivesTo argument value
@description

This error occurs when you do not include `'E'` or `'A'` in the argument of {@link ng.$compileProvider#restrictDirectivesTo `$compileProvider.restrictDirectivesTo`}.

These values are mandatory and you must include both in the argument string.
38 changes: 38 additions & 0 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,42 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return TTL;
};

var ignoreCDirectives = false;
var ignoreMDirectives = false;
/**
* @ngdoc method
* @name $compileProvider#restrictDirectivesTo
* @description
*
* It indicates to the compiler which restrict directive values
* must follow and which restrict directive values may ignore.
*
* It allows to the compiler to make optimizations, for example,
* if you indicate that you restrict directives only to ‘EA’
* (entities and attributes), it will not parse classes or comments
* looking for directives.
*
* Possible values are ‘EA’, ‘EAC’, ‘EAM’ and ‘EACM’.
* Having at least 'EA' is mandatory.
*
* Default value is ‘EACM’
*
* Example:
*
* ```
* $compileProvider.restrictDirectivesTo('EA');
* ```
*
* @param {string} directive restrict values that compiler must follow
*/
this.restrictDirectivesTo = function(value) {
if (value.indexOf('E') === -1 || value.indexOf('A') === -1) {
throw $compileMinErr('rstrto', '"{0}" must include E and A');
}
ignoreCDirectives = value.indexOf('C') === -1;
ignoreMDirectives = value.indexOf('M') === -1;
};

this.$get = [
'$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
'$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
Expand Down Expand Up @@ -2026,6 +2062,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}

// use class as directive
if (ignoreCDirectives) break;
className = node.className;
if (isObject(className)) {
// Maybe SVGAnimatedString
Expand All @@ -2052,6 +2089,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
addTextInterpolateDirective(directives, node.nodeValue);
break;
case NODE_TYPE_COMMENT: /* Comment */
if (ignoreMDirectives) break;
collectCommentDirectives();
break;
}
Expand Down
128 changes: 120 additions & 8 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3128,17 +3128,129 @@ describe('$compile', function() {
});
});

it('should observe interpolated attrs', inject(function($rootScope, $compile) {
$compile('<div some-attr="{{value}}" observer></div>')($rootScope);
describe('$compileProvider.restrictDirectivesTo', function() {

// should be async
expect(observeSpy).not.toHaveBeenCalled();
var collected;
beforeEach(module(function($compileProvider) {
collected = false;
$compileProvider.directive('testCollect', function() {
return {
restrict: 'ECMA',
link: function(scope, element) {
collected = true;
}
};
});
}));

$rootScope.$apply(function() {
$rootScope.value = 'bound-value';
describe('EA', function() {

beforeEach(module(function($compileProvider) {
$compileProvider.restrictDirectivesTo('EA');
}));

var $compile, $rootScope;
beforeEach(inject(function(_$compile_,_$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
}));

it('should not compile class directives', function() {
var html = 'Classes collected: <span class="ng-bind: \'Yes\';">No</span>';
element = $compile('<div>' + html + '</div>')($rootScope);
$rootScope.$apply();
expect(element.text()).toBe('Classes collected: No');
});

it('should not compile comment directives', function() {
var html = '<!-- directive: test-collect -->';
element = $compile('<div>' + html + '</div>')($rootScope);
expect(collected).toBe(false);
});

it('should not prevent to compile entity directives', function() {
element = $compile('<test-collect></test-collect>')($rootScope);
expect(collected).toBe(true);
});

it('should not prevent to compile attribute directives', function() {
element = $compile('<span test-collect></span>')($rootScope);
expect(collected).toBe(true);
});

it('should not prevent to compile interpolated expressions', function() {
element = $compile('<span>{{"text "+"interpolated"}}</span>')($rootScope);
$rootScope.$apply();
expect(element.text()).toBe('text interpolated');
});

it('should interpolate expressions inside class attribute', function() {
$rootScope.interpolateMe = 'interpolated';
var html = '<div class="{{interpolateMe}}"></div>';
element = $compile(html)($rootScope);
$rootScope.$apply();
expect(element).toHaveClass('interpolated');
});
});
expect(observeSpy).toHaveBeenCalledOnceWith('bound-value');
}));

describe('EAC', function() {

beforeEach(module(function($compileProvider) {
$compileProvider.restrictDirectivesTo('EAC');
}));

var $compile, $rootScope;
beforeEach(inject(function(_$compile_,_$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
}));

it('should compile class directives', function() {
var html = 'Classes collected: <span class="ng-bind: \'Yes\';">No</span>';
element = $compile('<div>' + html + '</div>')($rootScope);
$rootScope.$apply();
expect(element.text()).toBe('Classes collected: Yes');
});
});

describe('EAM', function() {

beforeEach(module(function($compileProvider) {
$compileProvider.restrictDirectivesTo('EAM');
}));

var $compile, $rootScope;
beforeEach(inject(function(_$compile_,_$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
}));

it('should compile comment directives', function() {
var html = '<!-- directive: test-collect -->';
element = $compile('<div>' + html + '</div>')($rootScope);
expect(collected).toBe(true);
});
});

describe('without E or A', function() {

it('should throw an exception if E is not included', module(function($compileProvider) {
expect(function() {
$compileProvider.restrictDirectivesTo('A');
}).toThrowMinErr('$compile', 'rstrto');
}));

it('should throw an exception if A is not included', module(function($compileProvider) {
expect(function() {
$compileProvider.restrictDirectivesTo('E');
}).toThrowMinErr('$compile', 'rstrto');
}));

afterEach(inject(function($compile) {
// ensure that $compileProvider is instantiated
}));
});
});


it('should return a deregistration function while observing an attribute', inject(function($rootScope, $compile) {
Expand Down

0 comments on commit e40345e

Please sign in to comment.