mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
style($compile): clean up the code and normalize fn names
This commit is contained in:
parent
9cba23a588
commit
fff31d8d61
2 changed files with 190 additions and 161 deletions
|
|
@ -1,5 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
|
||||
*
|
||||
* DOM-related variables:
|
||||
*
|
||||
* - "node" - DOM Node
|
||||
* - "element" - DOM Element or Node
|
||||
* - "$node" or "$element" - jqLite-wrapped node or element
|
||||
*
|
||||
*
|
||||
* Compiler related stuff:
|
||||
*
|
||||
* - "linkFn" - linking fn of a single directive
|
||||
* - "nodeLinkFn" - function that aggregates all linking fns for a particular node
|
||||
* - "childLinkFn" - function that aggregates all linking fns for child nodes of a particular node
|
||||
* - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.module.ng.$compile
|
||||
|
|
@ -290,30 +308,31 @@ function $CompileProvider($provide) {
|
|||
|
||||
//================================
|
||||
|
||||
function compile(templateElement, transcludeFn, maxPriority) {
|
||||
if (!(templateElement instanceof jqLite)) {
|
||||
function compile($compileNode, transcludeFn, maxPriority) {
|
||||
if (!($compileNode instanceof jqLite)) {
|
||||
// jquery always rewraps, where as we need to preserve the original selector so that we can modify it.
|
||||
templateElement = jqLite(templateElement);
|
||||
$compileNode = jqLite($compileNode);
|
||||
}
|
||||
// We can not compile top level text elements since text nodes can be merged and we will
|
||||
// not be able to attach scope data to them, so we will wrap them in <span>
|
||||
forEach(templateElement, function(node, index){
|
||||
forEach($compileNode, function(node, index){
|
||||
if (node.nodeType == 3 /* text node */) {
|
||||
templateElement[index] = jqLite(node).wrap('<span>').parent()[0];
|
||||
$compileNode[index] = jqLite(node).wrap('<span>').parent()[0];
|
||||
}
|
||||
});
|
||||
var linkingFn = compileNodes(templateElement, transcludeFn, templateElement, maxPriority);
|
||||
var compositeLinkFn = compileNodes($compileNode, transcludeFn, $compileNode, maxPriority);
|
||||
return function(scope, cloneConnectFn){
|
||||
assertArg(scope, 'scope');
|
||||
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
|
||||
// and sometimes changes the structure of the DOM.
|
||||
var element = cloneConnectFn
|
||||
? JQLitePrototype.clone.call(templateElement) // IMPORTANT!!!
|
||||
: templateElement;
|
||||
safeAddClass(element.data('$scope', scope), 'ng-scope');
|
||||
if (cloneConnectFn) cloneConnectFn(element, scope);
|
||||
if (linkingFn) linkingFn(scope, element, element);
|
||||
return element;
|
||||
var $linkNode = cloneConnectFn
|
||||
? JQLitePrototype.clone.call($compileNode) // IMPORTANT!!!
|
||||
: $compileNode;
|
||||
$linkNode.data('$scope', scope);
|
||||
safeAddClass($linkNode, 'ng-scope');
|
||||
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
|
||||
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
|
||||
return $linkNode;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -321,9 +340,9 @@ function $CompileProvider($provide) {
|
|||
throw Error("Unsupported '" + mode + "' for '" + localName + "'.");
|
||||
}
|
||||
|
||||
function safeAddClass(element, className) {
|
||||
function safeAddClass($element, className) {
|
||||
try {
|
||||
element.addClass(className);
|
||||
$element.addClass(className);
|
||||
} catch(e) {
|
||||
// ignore, since it means that we are trying to set class on
|
||||
// SVG element, where class name is read-only.
|
||||
|
|
@ -339,15 +358,15 @@ function $CompileProvider($provide) {
|
|||
* @param {NodeList} nodeList an array of nodes to compile
|
||||
* @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
|
||||
* scope argument is auto-generated to the new child of the transcluded parent scope.
|
||||
* @param {DOMElement=} rootElement If the nodeList is the root of the compilation tree then the
|
||||
* @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then the
|
||||
* rootElement must be set the jqLite collection of the compile root. This is
|
||||
* needed so that the jqLite collection items can be replaced with widgets.
|
||||
* @param {number=} max directive priority
|
||||
* @returns {?function} A composite linking function of all of the matched directives or null.
|
||||
*/
|
||||
function compileNodes(nodeList, transcludeFn, rootElement, maxPriority) {
|
||||
var linkingFns = [],
|
||||
directiveLinkingFn, childLinkingFn, directives, attrs, linkingFnFound;
|
||||
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority) {
|
||||
var linkFns = [],
|
||||
nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
|
||||
|
||||
for(var i = 0; i < nodeList.length; i++) {
|
||||
attrs = new Attributes();
|
||||
|
|
@ -355,41 +374,41 @@ function $CompileProvider($provide) {
|
|||
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
|
||||
directives = collectDirectives(nodeList[i], [], attrs, maxPriority);
|
||||
|
||||
directiveLinkingFn = (directives.length)
|
||||
? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, rootElement)
|
||||
nodeLinkFn = (directives.length)
|
||||
? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
|
||||
: null;
|
||||
|
||||
childLinkingFn = (directiveLinkingFn && directiveLinkingFn.terminal)
|
||||
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal)
|
||||
? null
|
||||
: compileNodes(nodeList[i].childNodes,
|
||||
directiveLinkingFn ? directiveLinkingFn.transclude : transcludeFn);
|
||||
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
|
||||
|
||||
linkingFns.push(directiveLinkingFn);
|
||||
linkingFns.push(childLinkingFn);
|
||||
linkingFnFound = (linkingFnFound || directiveLinkingFn || childLinkingFn);
|
||||
linkFns.push(nodeLinkFn);
|
||||
linkFns.push(childLinkFn);
|
||||
linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
|
||||
}
|
||||
|
||||
// return a linking function if we have found anything, null otherwise
|
||||
return linkingFnFound ? linkingFn : null;
|
||||
return linkFnFound ? compositeLinkFn : null;
|
||||
|
||||
/* nodesetLinkingFn */ function linkingFn(scope, nodeList, rootElement, boundTranscludeFn) {
|
||||
var childLinkingFn, directiveLinkingFn, node, childScope, childTransclusionFn;
|
||||
function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
|
||||
var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn;
|
||||
|
||||
for(var i=0, n=0, ii=linkingFns.length; i<ii; n++) {
|
||||
for(var i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
|
||||
node = nodeList[n];
|
||||
directiveLinkingFn = /* directiveLinkingFn */ linkingFns[i++];
|
||||
childLinkingFn = /* nodesetLinkingFn */ linkingFns[i++];
|
||||
nodeLinkFn = linkFns[i++];
|
||||
childLinkFn = linkFns[i++];
|
||||
|
||||
if (directiveLinkingFn) {
|
||||
if (directiveLinkingFn.scope) {
|
||||
childScope = scope.$new(isObject(directiveLinkingFn.scope));
|
||||
if (nodeLinkFn) {
|
||||
if (nodeLinkFn.scope) {
|
||||
childScope = scope.$new(isObject(nodeLinkFn.scope));
|
||||
jqLite(node).data('$scope', childScope);
|
||||
} else {
|
||||
childScope = scope;
|
||||
}
|
||||
childTransclusionFn = directiveLinkingFn.transclude;
|
||||
if (childTransclusionFn || (!boundTranscludeFn && transcludeFn)) {
|
||||
directiveLinkingFn(childLinkingFn, childScope, node, rootElement,
|
||||
childTranscludeFn = nodeLinkFn.transclude;
|
||||
if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
|
||||
nodeLinkFn(childLinkFn, childScope, node, $rootElement,
|
||||
(function(transcludeFn) {
|
||||
return function(cloneFn) {
|
||||
var transcludeScope = scope.$new();
|
||||
|
|
@ -397,13 +416,13 @@ function $CompileProvider($provide) {
|
|||
return transcludeFn(transcludeScope, cloneFn).
|
||||
bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
|
||||
};
|
||||
})(childTransclusionFn || transcludeFn)
|
||||
})(childTranscludeFn || transcludeFn)
|
||||
);
|
||||
} else {
|
||||
directiveLinkingFn(childLinkingFn, childScope, node, undefined, boundTranscludeFn);
|
||||
nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
|
||||
}
|
||||
} else if (childLinkingFn) {
|
||||
childLinkingFn(scope, node.childNodes, undefined, boundTranscludeFn);
|
||||
} else if (childLinkFn) {
|
||||
childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -493,48 +512,47 @@ function $CompileProvider($provide) {
|
|||
*
|
||||
* @param {Array} directives Array of collected directives to execute their compile function.
|
||||
* this needs to be pre-sorted by priority order.
|
||||
* @param {Node} templateNode The raw DOM node to apply the compile functions to
|
||||
* @param {Node} compileNode The raw DOM node to apply the compile functions to
|
||||
* @param {Object} templateAttrs The shared attribute function
|
||||
* @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
|
||||
* scope argument is auto-generated to the new child of the transcluded parent scope.
|
||||
* @param {DOMElement} rootElement If we are working on the root of the compile tree then this
|
||||
* @param {DOMElement} $rootElement If we are working on the root of the compile tree then this
|
||||
* argument has the root jqLite array so that we can replace widgets on it.
|
||||
* @returns linkingFn
|
||||
* @returns linkFn
|
||||
*/
|
||||
function applyDirectivesToNode(directives, templateNode, templateAttrs, transcludeFn, rootElement) {
|
||||
function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, $rootElement) {
|
||||
var terminalPriority = -Number.MAX_VALUE,
|
||||
preLinkingFns = [],
|
||||
postLinkingFns = [],
|
||||
preLinkFns = [],
|
||||
postLinkFns = [],
|
||||
newScopeDirective = null,
|
||||
newIsolatedScopeDirective = null,
|
||||
templateDirective = null,
|
||||
delayedLinkingFn = null,
|
||||
element = templateAttrs.$$element = jqLite(templateNode),
|
||||
$compileNode = templateAttrs.$$element = jqLite(compileNode),
|
||||
directive,
|
||||
directiveName,
|
||||
template,
|
||||
$template,
|
||||
transcludeDirective,
|
||||
childTranscludeFn = transcludeFn,
|
||||
controllerDirectives,
|
||||
linkingFn,
|
||||
linkFn,
|
||||
directiveValue;
|
||||
|
||||
// executes all directives on the current element
|
||||
for(var i = 0, ii = directives.length; i < ii; i++) {
|
||||
directive = directives[i];
|
||||
template = undefined;
|
||||
$template = undefined;
|
||||
|
||||
if (terminalPriority > directive.priority) {
|
||||
break; // prevent further processing of directives
|
||||
}
|
||||
|
||||
if (directiveValue = directive.scope) {
|
||||
assertNoDuplicate('isolated scope', newIsolatedScopeDirective, directive, element);
|
||||
assertNoDuplicate('isolated scope', newIsolatedScopeDirective, directive, $compileNode);
|
||||
if (isObject(directiveValue)) {
|
||||
safeAddClass(element, 'ng-isolate-scope');
|
||||
safeAddClass($compileNode, 'ng-isolate-scope');
|
||||
newIsolatedScopeDirective = directive;
|
||||
}
|
||||
safeAddClass(element, 'ng-scope');
|
||||
safeAddClass($compileNode, 'ng-scope');
|
||||
newScopeDirective = newScopeDirective || directive;
|
||||
}
|
||||
|
||||
|
|
@ -543,34 +561,35 @@ function $CompileProvider($provide) {
|
|||
if (directiveValue = directive.controller) {
|
||||
controllerDirectives = controllerDirectives || {};
|
||||
assertNoDuplicate("'" + directiveName + "' controller",
|
||||
controllerDirectives[directiveName], directive, element);
|
||||
controllerDirectives[directiveName], directive, $compileNode);
|
||||
controllerDirectives[directiveName] = directive;
|
||||
}
|
||||
|
||||
if (directiveValue = directive.transclude) {
|
||||
assertNoDuplicate('transclusion', transcludeDirective, directive, element);
|
||||
assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode);
|
||||
transcludeDirective = directive;
|
||||
terminalPriority = directive.priority;
|
||||
if (directiveValue == 'element') {
|
||||
template = jqLite(templateNode);
|
||||
templateNode = (element = templateAttrs.$$element = jqLite(
|
||||
'<!-- ' + directiveName + ': ' + templateAttrs[directiveName] + ' -->'))[0];
|
||||
replaceWith(rootElement, jqLite(template[0]), templateNode);
|
||||
childTranscludeFn = compile(template, transcludeFn, terminalPriority);
|
||||
$template = jqLite(compileNode);
|
||||
$compileNode = templateAttrs.$$element =
|
||||
jqLite('<!-- ' + directiveName + ': ' + templateAttrs[directiveName] + ' -->');
|
||||
compileNode = $compileNode[0];
|
||||
replaceWith($rootElement, jqLite($template[0]), compileNode);
|
||||
childTranscludeFn = compile($template, transcludeFn, terminalPriority);
|
||||
} else {
|
||||
template = jqLite(JQLiteClone(templateNode));
|
||||
element.html(''); // clear contents
|
||||
childTranscludeFn = compile(template.contents(), transcludeFn);
|
||||
$template = jqLite(JQLiteClone(compileNode)).contents();
|
||||
$compileNode.html(''); // clear contents
|
||||
childTranscludeFn = compile($template, transcludeFn);
|
||||
}
|
||||
}
|
||||
|
||||
if (directiveValue = directive.template) {
|
||||
assertNoDuplicate('template', templateDirective, directive, element);
|
||||
assertNoDuplicate('template', templateDirective, directive, $compileNode);
|
||||
templateDirective = directive;
|
||||
|
||||
templateNode = jqLite(directiveValue)[0];
|
||||
compileNode = jqLite(directiveValue)[0];
|
||||
if (directive.replace) {
|
||||
replaceWith(rootElement, element, templateNode);
|
||||
replaceWith($rootElement, $compileNode, compileNode);
|
||||
|
||||
var newTemplateAttrs = {$attr: {}};
|
||||
|
||||
|
|
@ -581,7 +600,7 @@ function $CompileProvider($provide) {
|
|||
// - append the second group with new directives to the first group
|
||||
directives = directives.concat(
|
||||
collectDirectives(
|
||||
templateNode,
|
||||
compileNode,
|
||||
directives.splice(i + 1, directives.length - (i + 1)),
|
||||
newTemplateAttrs
|
||||
)
|
||||
|
|
@ -590,59 +609,58 @@ function $CompileProvider($provide) {
|
|||
|
||||
ii = directives.length;
|
||||
} else {
|
||||
element.html(directiveValue);
|
||||
$compileNode.html(directiveValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (directive.templateUrl) {
|
||||
assertNoDuplicate('template', templateDirective, directive, element);
|
||||
assertNoDuplicate('template', templateDirective, directive, $compileNode);
|
||||
templateDirective = directive;
|
||||
delayedLinkingFn = compileTemplateUrl(directives.splice(i, directives.length - i),
|
||||
/* directiveLinkingFn */ compositeLinkFn, element, templateAttrs, rootElement,
|
||||
directive.replace, childTranscludeFn);
|
||||
nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i),
|
||||
nodeLinkFn, $compileNode, templateAttrs, $rootElement, directive.replace,
|
||||
childTranscludeFn);
|
||||
ii = directives.length;
|
||||
} else if (directive.compile) {
|
||||
try {
|
||||
linkingFn = directive.compile(element, templateAttrs, childTranscludeFn);
|
||||
if (isFunction(linkingFn)) {
|
||||
addLinkingFns(null, linkingFn);
|
||||
} else if (linkingFn) {
|
||||
addLinkingFns(linkingFn.pre, linkingFn.post);
|
||||
linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
|
||||
if (isFunction(linkFn)) {
|
||||
addLinkFns(null, linkFn);
|
||||
} else if (linkFn) {
|
||||
addLinkFns(linkFn.pre, linkFn.post);
|
||||
}
|
||||
} catch (e) {
|
||||
$exceptionHandler(e, startingTag(element));
|
||||
$exceptionHandler(e, startingTag($compileNode));
|
||||
}
|
||||
}
|
||||
|
||||
if (directive.terminal) {
|
||||
compositeLinkFn.terminal = true;
|
||||
nodeLinkFn.terminal = true;
|
||||
terminalPriority = Math.max(terminalPriority, directive.priority);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
linkingFn = delayedLinkingFn || compositeLinkFn;
|
||||
linkingFn.scope = newScopeDirective && newScopeDirective.scope;
|
||||
linkingFn.transclude = transcludeDirective && childTranscludeFn;
|
||||
nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope;
|
||||
nodeLinkFn.transclude = transcludeDirective && childTranscludeFn;
|
||||
|
||||
// if we have templateUrl, then we have to delay linking
|
||||
return linkingFn;
|
||||
// might be normal or delayed nodeLinkFn depending on if templateUrl is present
|
||||
return nodeLinkFn;
|
||||
|
||||
////////////////////
|
||||
|
||||
function addLinkingFns(pre, post) {
|
||||
function addLinkFns(pre, post) {
|
||||
if (pre) {
|
||||
pre.require = directive.require;
|
||||
preLinkingFns.push(pre);
|
||||
preLinkFns.push(pre);
|
||||
}
|
||||
if (post) {
|
||||
post.require = directive.require;
|
||||
postLinkingFns.push(post);
|
||||
postLinkFns.push(post);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getControllers(require, element) {
|
||||
function getControllers(require, $element) {
|
||||
var value, retrievalMethod = 'data', optional = false;
|
||||
if (isString(require)) {
|
||||
while((value = require.charAt(0)) == '^' || value == '?') {
|
||||
|
|
@ -652,7 +670,7 @@ function $CompileProvider($provide) {
|
|||
}
|
||||
optional = optional || value == '?';
|
||||
}
|
||||
value = element[retrievalMethod]('$' + require + 'Controller');
|
||||
value = $element[retrievalMethod]('$' + require + 'Controller');
|
||||
if (!value && !optional) {
|
||||
throw Error("No controller: " + require);
|
||||
}
|
||||
|
|
@ -660,24 +678,22 @@ function $CompileProvider($provide) {
|
|||
} else if (isArray(require)) {
|
||||
value = [];
|
||||
forEach(require, function(require) {
|
||||
value.push(getControllers(require, element));
|
||||
value.push(getControllers(require, $element));
|
||||
});
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/* directiveLinkingFn */
|
||||
function compositeLinkFn(/* nodesetLinkingFn */ childLinkingFn,
|
||||
scope, linkNode, rootElement, boundTranscludeFn) {
|
||||
var attrs, element, i, ii, linkingFn, controller;
|
||||
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
|
||||
var attrs, $element, i, ii, linkFn, controller;
|
||||
|
||||
if (templateNode === linkNode) {
|
||||
if (compileNode === linkNode) {
|
||||
attrs = templateAttrs;
|
||||
} else {
|
||||
attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
|
||||
}
|
||||
element = attrs.$$element;
|
||||
$element = attrs.$$element;
|
||||
|
||||
if (newScopeDirective && isObject(newScopeDirective.scope)) {
|
||||
forEach(newScopeDirective.scope, function(mode, name) {
|
||||
|
|
@ -690,7 +706,7 @@ function $CompileProvider($provide) {
|
|||
forEach(controllerDirectives, function(directive) {
|
||||
var locals = {
|
||||
$scope: scope,
|
||||
$element: element,
|
||||
$element: $element,
|
||||
$attrs: attrs,
|
||||
$transclude: boundTranscludeFn
|
||||
};
|
||||
|
|
@ -706,34 +722,34 @@ function $CompileProvider($provide) {
|
|||
controller = attrs[directive.name];
|
||||
}
|
||||
|
||||
element.data(
|
||||
$element.data(
|
||||
'$' + directive.name + 'Controller',
|
||||
$controller(controller, locals));
|
||||
});
|
||||
}
|
||||
|
||||
// PRELINKING
|
||||
for(i = 0, ii = preLinkingFns.length; i < ii; i++) {
|
||||
for(i = 0, ii = preLinkFns.length; i < ii; i++) {
|
||||
try {
|
||||
linkingFn = preLinkingFns[i];
|
||||
linkingFn(scope, element, attrs,
|
||||
linkingFn.require && getControllers(linkingFn.require, element));
|
||||
linkFn = preLinkFns[i];
|
||||
linkFn(scope, $element, attrs,
|
||||
linkFn.require && getControllers(linkFn.require, $element));
|
||||
} catch (e) {
|
||||
$exceptionHandler(e, startingTag(element));
|
||||
$exceptionHandler(e, startingTag($element));
|
||||
}
|
||||
}
|
||||
|
||||
// RECURSION
|
||||
childLinkingFn && childLinkingFn(scope, linkNode.childNodes, undefined, boundTranscludeFn);
|
||||
childLinkFn && childLinkFn(scope, linkNode.childNodes, undefined, boundTranscludeFn);
|
||||
|
||||
// POSTLINKING
|
||||
for(i = 0, ii = postLinkingFns.length; i < ii; i++) {
|
||||
for(i = 0, ii = postLinkFns.length; i < ii; i++) {
|
||||
try {
|
||||
linkingFn = postLinkingFns[i];
|
||||
linkingFn(scope, element, attrs,
|
||||
linkingFn.require && getControllers(linkingFn.require, element));
|
||||
linkFn = postLinkFns[i];
|
||||
linkFn(scope, $element, attrs,
|
||||
linkFn.require && getControllers(linkFn.require, $element));
|
||||
} catch (e) {
|
||||
$exceptionHandler(e, startingTag(element));
|
||||
$exceptionHandler(e, startingTag($element));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -758,7 +774,7 @@ function $CompileProvider($provide) {
|
|||
var match = false;
|
||||
if (hasDirectives.hasOwnProperty(name)) {
|
||||
for(var directive, directives = $injector.get(name + Suffix),
|
||||
i=0, ii = directives.length; i<ii; i++) {
|
||||
i = 0, ii = directives.length; i<ii; i++) {
|
||||
try {
|
||||
directive = directives[i];
|
||||
if ( (maxPriority === undefined || maxPriority > directive.priority) &&
|
||||
|
|
@ -784,7 +800,7 @@ function $CompileProvider($provide) {
|
|||
function mergeTemplateAttributes(dst, src) {
|
||||
var srcAttr = src.$attr,
|
||||
dstAttr = dst.$attr,
|
||||
element = dst.$$element;
|
||||
$element = dst.$$element;
|
||||
// reapply the old attributes to the new element
|
||||
forEach(dst, function(value, key) {
|
||||
if (key.charAt(0) != '$') {
|
||||
|
|
@ -797,9 +813,9 @@ function $CompileProvider($provide) {
|
|||
// copy the new attributes on the old attrs object
|
||||
forEach(src, function(value, key) {
|
||||
if (key == 'class') {
|
||||
safeAddClass(element, value);
|
||||
safeAddClass($element, value);
|
||||
} else if (key == 'style') {
|
||||
element.attr('style', element.attr('style') + ';' + value);
|
||||
$element.attr('style', $element.attr('style') + ';' + value);
|
||||
} else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
|
||||
dst[key] = value;
|
||||
dstAttr[key] = srcAttr[key];
|
||||
|
|
@ -808,71 +824,70 @@ function $CompileProvider($provide) {
|
|||
}
|
||||
|
||||
|
||||
function compileTemplateUrl(directives, /* directiveLinkingFn */ beforeWidgetLinkFn,
|
||||
tElement, tAttrs, rootElement, replace, transcludeFn) {
|
||||
function compileTemplateUrl(directives, beforeTemplateNodeLinkFn, $compileNode, tAttrs,
|
||||
$rootElement, replace, childTranscludeFn) {
|
||||
var linkQueue = [],
|
||||
afterWidgetLinkFn,
|
||||
afterWidgetChildrenLinkFn,
|
||||
originalWidgetNode = tElement[0],
|
||||
asyncWidgetDirective = directives.shift(),
|
||||
afterTemplateNodeLinkFn,
|
||||
afterTemplateChildLinkFn,
|
||||
origCompileNode = $compileNode[0],
|
||||
origAsyncDirective = directives.shift(),
|
||||
// The fact that we have to copy and patch the directive seems wrong!
|
||||
syncWidgetDirective = extend({}, asyncWidgetDirective, {
|
||||
derivedSyncDirective = extend({}, origAsyncDirective, {
|
||||
controller: null, templateUrl: null, transclude: null
|
||||
}),
|
||||
html = tElement.html();
|
||||
});
|
||||
|
||||
tElement.html('');
|
||||
$compileNode.html('');
|
||||
|
||||
$http.get(asyncWidgetDirective.templateUrl, {cache: $templateCache}).
|
||||
$http.get(origAsyncDirective.templateUrl, {cache: $templateCache}).
|
||||
success(function(content) {
|
||||
if (replace && !content.match(HAS_ROOT_ELEMENT)) {
|
||||
throw Error('Template must have exactly one root element: ' + content);
|
||||
}
|
||||
|
||||
var templateNode, tempTemplateAttrs;
|
||||
var compileNode, tempTemplateAttrs;
|
||||
|
||||
if (replace) {
|
||||
tempTemplateAttrs = {$attr: {}};
|
||||
templateNode = jqLite(content)[0];
|
||||
replaceWith(rootElement, tElement, templateNode);
|
||||
collectDirectives(tElement[0], directives, tempTemplateAttrs);
|
||||
compileNode = jqLite(content)[0];
|
||||
replaceWith($rootElement, $compileNode, compileNode);
|
||||
collectDirectives(compileNode, directives, tempTemplateAttrs);
|
||||
mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
|
||||
} else {
|
||||
templateNode = tElement[0];
|
||||
tElement.html(content);
|
||||
compileNode = origCompileNode;
|
||||
$compileNode.html(content);
|
||||
}
|
||||
|
||||
directives.unshift(syncWidgetDirective);
|
||||
afterWidgetLinkFn = /* directiveLinkingFn */ applyDirectivesToNode(directives, tElement, tAttrs, transcludeFn);
|
||||
afterWidgetChildrenLinkFn = /* nodesetLinkingFn */ compileNodes(tElement.contents(), transcludeFn);
|
||||
directives.unshift(derivedSyncDirective);
|
||||
afterTemplateNodeLinkFn = applyDirectivesToNode(directives, $compileNode, tAttrs, childTranscludeFn);
|
||||
afterTemplateChildLinkFn = compileNodes($compileNode.contents(), childTranscludeFn);
|
||||
|
||||
|
||||
while(linkQueue.length) {
|
||||
var controller = linkQueue.pop(),
|
||||
linkRootElement = linkQueue.pop(),
|
||||
cLinkNode = linkQueue.pop(),
|
||||
origLinkNode = linkQueue.pop(),
|
||||
scope = linkQueue.pop(),
|
||||
node = templateNode,
|
||||
cLinkNodeJq = jqLite(cLinkNode);
|
||||
linkNode = compileNode,
|
||||
$origLinkNode = jqLite(origLinkNode);
|
||||
|
||||
if (cLinkNode !== originalWidgetNode) {
|
||||
if (origLinkNode !== origCompileNode) {
|
||||
// it was cloned therefore we have to clone as well.
|
||||
node = JQLiteClone(templateNode);
|
||||
replaceWith(linkRootElement, jqLite(cLinkNode), node);
|
||||
linkNode = JQLiteClone(compileNode);
|
||||
replaceWith(linkRootElement, $origLinkNode, linkNode);
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
if (cLinkNodeJq.data('$scope')) {
|
||||
if ($origLinkNode.data('$scope')) {
|
||||
// if the original element before replacement had a new scope, the replacement should
|
||||
// get it as well
|
||||
jqLite(node).data('$scope', scope);
|
||||
jqLite(linkNode).data('$scope', scope);
|
||||
}
|
||||
dealoc(cLinkNodeJq);
|
||||
dealoc($origLinkNode);
|
||||
}
|
||||
|
||||
afterWidgetLinkFn(function() {
|
||||
beforeWidgetLinkFn(afterWidgetChildrenLinkFn, scope, node, rootElement, controller);
|
||||
}, scope, node, rootElement, controller);
|
||||
afterTemplateNodeLinkFn(function() {
|
||||
beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, controller);
|
||||
}, scope, linkNode, $rootElement, controller);
|
||||
}
|
||||
linkQueue = null;
|
||||
}).
|
||||
|
|
@ -880,16 +895,15 @@ function $CompileProvider($provide) {
|
|||
throw Error('Failed to load template: ' + config.url);
|
||||
});
|
||||
|
||||
return /* directiveLinkingFn */ function(ignoreChildLinkingFn, scope, node, rootElement,
|
||||
controller) {
|
||||
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) {
|
||||
if (linkQueue) {
|
||||
linkQueue.push(scope);
|
||||
linkQueue.push(node);
|
||||
linkQueue.push(rootElement);
|
||||
linkQueue.push(controller);
|
||||
} else {
|
||||
afterWidgetLinkFn(function() {
|
||||
beforeWidgetLinkFn(afterWidgetChildrenLinkFn, scope, node, rootElement, controller);
|
||||
afterTemplateNodeLinkFn(function() {
|
||||
beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, controller);
|
||||
}, scope, node, rootElement, controller);
|
||||
}
|
||||
};
|
||||
|
|
@ -963,28 +977,28 @@ function $CompileProvider($provide) {
|
|||
* This is a special jqLite.replaceWith, which can replace items which
|
||||
* have no parents, provided that the containing jqLite collection is provided.
|
||||
*
|
||||
* @param {JqLite=} rootElement The root of the compile tree. Used so that we can replace nodes
|
||||
* @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
|
||||
* in the root of the tree.
|
||||
* @param {JqLite} element The jqLite element which we are going to replace. We keep the shell,
|
||||
* @param {JqLite} $element The jqLite element which we are going to replace. We keep the shell,
|
||||
* but replace its DOM node reference.
|
||||
* @param {Node} newNode The new DOM node.
|
||||
*/
|
||||
function replaceWith(rootElement, element, newNode) {
|
||||
var oldNode = element[0],
|
||||
function replaceWith($rootElement, $element, newNode) {
|
||||
var oldNode = $element[0],
|
||||
parent = oldNode.parentNode,
|
||||
i, ii;
|
||||
|
||||
if (rootElement) {
|
||||
for(i = 0, ii = rootElement.length; i<ii; i++) {
|
||||
if (rootElement[i] == oldNode) {
|
||||
rootElement[i] = newNode;
|
||||
if ($rootElement) {
|
||||
for(i = 0, ii = $rootElement.length; i < ii; i++) {
|
||||
if ($rootElement[i] == oldNode) {
|
||||
$rootElement[i] = newNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parent) {
|
||||
parent.replaceChild(newNode, oldNode);
|
||||
}
|
||||
element[0] = newNode;
|
||||
$element[0] = newNode;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1088,6 +1088,21 @@ describe('$compile', function() {
|
|||
}));
|
||||
|
||||
|
||||
it('should allow creation of new scopes for replace directives with templates in a repeater',
|
||||
inject(function($rootScope, $compile, log, $httpBackend) {
|
||||
$httpBackend.expect('GET', 'trscope.html').
|
||||
respond('<p><a log>{{name}}; scopeId: {{$id}} |</a></p>');
|
||||
element = $compile('<div><span ng-repeat="i in [1,2,3]" trscope></span></div>')($rootScope);
|
||||
$httpBackend.flush();
|
||||
expect(log).toEqual('LOG; log-003-002; 003; LOG; log-005-004; 005; LOG; log-007-006; 007');
|
||||
$rootScope.name = 'Jozo';
|
||||
$rootScope.$apply();
|
||||
expect(element.text()).toBe('Jozo; scopeId: 003 |Jozo; scopeId: 005 |Jozo; scopeId: 007 |');
|
||||
expect(element.find('p').scope().$id).toBe('003');
|
||||
expect(element.find('a').scope().$id).toBe('003');
|
||||
}));
|
||||
|
||||
|
||||
it('should allow creation of new isolated scopes for directives with templates', inject(
|
||||
function($rootScope, $compile, log, $httpBackend) {
|
||||
$httpBackend.expect('GET', 'tiscope.html').respond('<a log></a>');
|
||||
|
|
|
|||
Loading…
Reference in a new issue