refactor($compile): rename directive.type to directive.templateNamespace

Also corrects the tests for MathML that use `directive.templateNamespace`.

BREAKING CHANGE (within 1.3.0-beta): `directive.type` was renamed to `directive.templateNamespace`

The property name `type` was too general.
This commit is contained in:
Tobias Bosch
2014-08-22 11:43:58 -07:00
parent 642af96c48
commit 75c4cbf81f
2 changed files with 113 additions and 97 deletions

View File

@@ -219,18 +219,17 @@
* * `M` - Comment: `<!-- directive: my-directive exp -->` * * `M` - Comment: `<!-- directive: my-directive exp -->`
* *
* *
* #### `type` * #### `templateNamespace`
* String representing the document type used by the markup. This is useful for templates where the root * String representing the document type used by the markup in the template.
* node is non-HTML content (such as SVG or MathML). The default value is "html". * AngularJS needs this information as those elements need to be created and cloned
* in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
* *
* * `html` - All root template nodes are HTML, and don't need to be wrapped. Root nodes may also be * * `html` - All root nodes in the template are HTML. Root nodes may also be
* top-level elements such as `<svg>` or `<math>`. * top-level elements such as `<svg>` or `<math>`.
* * `svg` - The template contains only SVG content, and must be wrapped in an `<svg>` node prior to * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
* processing. * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
* * `math` - The template contains only MathML content, and must be wrapped in an `<math>` node prior to
* processing.
* *
* If no `type` is specified, then the type is considered to be html. * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
* *
* #### `template` * #### `template`
* HTML markup that may: * HTML markup that may:
@@ -1339,7 +1338,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (jqLiteIsTextNode(directiveValue)) { if (jqLiteIsTextNode(directiveValue)) {
$template = []; $template = [];
} else { } else {
$template = jqLite(wrapTemplate(directive.type, trim(directiveValue))); $template = jqLite(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
} }
compileNode = $template[0]; compileNode = $template[0];
@@ -1786,7 +1785,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
templateUrl = (isFunction(origAsyncDirective.templateUrl)) templateUrl = (isFunction(origAsyncDirective.templateUrl))
? origAsyncDirective.templateUrl($compileNode, tAttrs) ? origAsyncDirective.templateUrl($compileNode, tAttrs)
: origAsyncDirective.templateUrl, : origAsyncDirective.templateUrl,
type = origAsyncDirective.type; templateNamespace = origAsyncDirective.templateNamespace;
$compileNode.empty(); $compileNode.empty();
@@ -1800,7 +1799,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (jqLiteIsTextNode(content)) { if (jqLiteIsTextNode(content)) {
$template = []; $template = [];
} else { } else {
$template = jqLite(wrapTemplate(type, trim(content))); $template = jqLite(wrapTemplate(templateNamespace, trim(content)));
} }
compileNode = $template[0]; compileNode = $template[0];

View File

@@ -7,8 +7,25 @@ function calcCacheSize() {
return size; return size;
} }
describe('$compile', function() { describe('$compile', function() {
function isUnknownElement(el) {
return !!el.toString().match(/Unknown/);
}
function isSVGElement(el) {
return !!el.toString().match(/SVG/);
}
function isHTMLElement(el) {
return !!el.toString().match(/HTML/);
}
function supportsMathML() {
var d = document.createElement('div');
d.innerHTML = '<math></math>';
return !isUnknownElement(d.firstChild);
}
var element, directive, $compile, $rootScope; var element, directive, $compile, $rootScope;
beforeEach(module(provideLog, function($provide, $compileProvider){ beforeEach(module(provideLog, function($provide, $compileProvider){
@@ -838,58 +855,58 @@ describe('$compile', function() {
expect(nodeName_(element)).toMatch(/optgroup/i); expect(nodeName_(element)).toMatch(/optgroup/i);
})); }));
if (window.SVGAElement) { it('should support SVG templates using directive.templateNamespace=svg', function() {
it('should support SVG templates using directive.type=svg', function() {
module(function() {
directive('svgAnchor', valueFn({
replace: true,
template: '<a xlink:href="{{linkurl}}">{{text}}</a>',
type: 'SVG',
scope: {
linkurl: '@svgAnchor',
text: '@?'
}
}));
});
inject(function($compile, $rootScope) {
element = $compile('<svg><g svg-anchor="/foo/bar" text="foo/bar!"></g></svg>')($rootScope);
var child = element.children().eq(0);
$rootScope.$digest();
expect(nodeName_(child)).toMatch(/a/i);
expect(child[0].constructor).toBe(window.SVGAElement);
expect(child[0].href.baseVal).toBe("/foo/bar");
});
});
}
// MathML is only natively supported in Firefox at the time of this test's writing,
// and even there, the browser does not export MathML element constructors globally.
// So the test is slightly limited in what it does. But as browsers begin to
// implement MathML natively, this can be tightened up to be more meaningful.
it('should support MathML templates using directive.type=math', function() {
module(function() { module(function() {
directive('pow', valueFn({ directive('svgAnchor', valueFn({
replace: true, replace: true,
transclude: true, template: '<a xlink:href="{{linkurl}}">{{text}}</a>',
template: '<msup><mn>{{pow}}</mn></msup>', templateNamespace: 'SVG',
type: 'MATH',
scope: { scope: {
pow: '@pow', linkurl: '@svgAnchor',
}, text: '@?'
link: function(scope, elm, attr, ctrl, transclude) {
transclude(function(node) {
elm.prepend(node[0]);
});
} }
})); }));
}); });
inject(function($compile, $rootScope) { inject(function($compile, $rootScope) {
element = $compile('<math><mn pow="2"><mn>8</mn></mn></math>')($rootScope); element = $compile('<svg><g svg-anchor="/foo/bar" text="foo/bar!"></g></svg>')($rootScope);
$rootScope.$digest();
var child = element.children().eq(0); var child = element.children().eq(0);
expect(nodeName_(child)).toMatch(/msup/i); $rootScope.$digest();
expect(nodeName_(child)).toMatch(/a/i);
expect(isSVGElement(child[0])).toBe(true);
expect(child[0].href.baseVal).toBe("/foo/bar");
}); });
}); });
if (supportsMathML()) {
// MathML is only natively supported in Firefox at the time of this test's writing,
// and even there, the browser does not export MathML element constructors globally.
it('should support MathML templates using directive.templateNamespace=math', function() {
module(function() {
directive('pow', valueFn({
replace: true,
transclude: true,
template: '<msup><mn>{{pow}}</mn></msup>',
templateNamespace: 'MATH',
scope: {
pow: '@pow',
},
link: function(scope, elm, attr, ctrl, transclude) {
transclude(function(node) {
elm.prepend(node[0]);
});
}
}));
});
inject(function($compile, $rootScope) {
element = $compile('<math><mn pow="2"><mn>8</mn></mn></math>')($rootScope);
$rootScope.$digest();
var child = element.children().eq(0);
expect(nodeName_(child)).toMatch(/msup/i);
expect(isUnknownElement(child[0])).toBe(false);
expect(isHTMLElement(child[0])).toBe(false);
});
});
}
}); });
@@ -1735,60 +1752,60 @@ describe('$compile', function() {
expect(nodeName_(element)).toMatch(/optgroup/i); expect(nodeName_(element)).toMatch(/optgroup/i);
})); }));
if (window.SVGAElement) { it('should support SVG templates using directive.templateNamespace=svg', function() {
it('should support SVG templates using directive.type=svg', function() {
module(function() {
directive('svgAnchor', valueFn({
replace: true,
templateUrl: 'template.html',
type: 'SVG',
scope: {
linkurl: '@svgAnchor',
text: '@?'
}
}));
});
inject(function($compile, $rootScope, $templateCache) {
$templateCache.put('template.html', '<a xlink:href="{{linkurl}}">{{text}}</a>');
element = $compile('<svg><g svg-anchor="/foo/bar" text="foo/bar!"></g></svg>')($rootScope);
$rootScope.$digest();
var child = element.children().eq(0);
expect(nodeName_(child)).toMatch(/a/i);
expect(child[0].constructor).toBe(window.SVGAElement);
expect(child[0].href.baseVal).toBe("/foo/bar");
});
});
}
// MathML is only natively supported in Firefox at the time of this test's writing,
// and even there, the browser does not export MathML element constructors globally.
// So the test is slightly limited in what it does. But as browsers begin to
// implement MathML natively, this can be tightened up to be more meaningful.
it('should support MathML templates using directive.type=math', function() {
module(function() { module(function() {
directive('pow', valueFn({ directive('svgAnchor', valueFn({
replace: true, replace: true,
transclude: true,
templateUrl: 'template.html', templateUrl: 'template.html',
type: 'MATH', templateNamespace: 'SVG',
scope: { scope: {
pow: '@pow', linkurl: '@svgAnchor',
}, text: '@?'
link: function(scope, elm, attr, ctrl, transclude) {
transclude(function(node) {
elm.prepend(node[0]);
});
} }
})); }));
}); });
inject(function($compile, $rootScope, $templateCache) { inject(function($compile, $rootScope, $templateCache) {
$templateCache.put('template.html', '<msup><mn>{{pow}}</mn></msup>'); $templateCache.put('template.html', '<a xlink:href="{{linkurl}}">{{text}}</a>');
element = $compile('<math><mn pow="2"><mn>8</mn></mn></math>')($rootScope); element = $compile('<svg><g svg-anchor="/foo/bar" text="foo/bar!"></g></svg>')($rootScope);
$rootScope.$digest(); $rootScope.$digest();
var child = element.children().eq(0); var child = element.children().eq(0);
expect(nodeName_(child)).toMatch(/msup/i); expect(nodeName_(child)).toMatch(/a/i);
expect(isSVGElement(child[0])).toBe(true);
expect(child[0].href.baseVal).toBe("/foo/bar");
}); });
}); });
if (supportsMathML()) {
// MathML is only natively supported in Firefox at the time of this test's writing,
// and even there, the browser does not export MathML element constructors globally.
it('should support MathML templates using directive.templateNamespace=math', function() {
module(function() {
directive('pow', valueFn({
replace: true,
transclude: true,
templateUrl: 'template.html',
templateNamespace: 'math',
scope: {
pow: '@pow',
},
link: function(scope, elm, attr, ctrl, transclude) {
transclude(function(node) {
elm.prepend(node[0]);
});
}
}));
});
inject(function($compile, $rootScope, $templateCache) {
$templateCache.put('template.html', '<msup><mn>{{pow}}</mn></msup>');
element = $compile('<math><mn pow="2"><mn>8</mn></mn></math>')($rootScope);
$rootScope.$digest();
var child = element.children().eq(0);
expect(nodeName_(child)).toMatch(/msup/i);
expect(isUnknownElement(child[0])).toBe(false);
expect(isHTMLElement(child[0])).toBe(false);
});
});
}
}); });