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

PR 7565 fixed #7610

Merged
merged 14 commits into from May 29, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
59 changes: 39 additions & 20 deletions src/ng/compile.js
Expand Up @@ -847,7 +847,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
compileNodes($compileNodes, transcludeFn, $compileNodes,
maxPriority, ignoreDirective, previousCompileContext);
safeAddClass($compileNodes, 'ng-scope');
return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn){
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.
Expand All @@ -869,7 +869,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}

if (cloneConnectFn) cloneConnectFn($linkNode, scope);
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
return $linkNode;
};
}
Expand Down Expand Up @@ -924,7 +924,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
!childNodes.length)
? null
: compileNodes(childNodes,
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
nodeLinkFn ? (
(nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
&& nodeLinkFn.transclude) : transcludeFn);

linkFns.push(nodeLinkFn, childLinkFn);
linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
Expand All @@ -935,8 +937,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// return a linking function if we have found anything, null otherwise
return linkFnFound ? compositeLinkFn : null;

function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
var nodeLinkFn, childLinkFn, node, $node, childScope, i, ii, n, childBoundTranscludeFn;

// copy nodeList so that linking doesn't break due to live list updates.
var nodeListLength = nodeList.length,
Expand All @@ -958,23 +960,32 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
} else {
childScope = scope;
}
childTranscludeFn = nodeLinkFn.transclude;
if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
nodeLinkFn(childLinkFn, childScope, node, $rootElement,
createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
);

if ( nodeLinkFn.transcludeOnThisElement ) {
childBoundTranscludeFn = createBoundTranscludeFn(scope, nodeLinkFn.transclude, parentBoundTranscludeFn);

} else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
childBoundTranscludeFn = parentBoundTranscludeFn;

} else if (!parentBoundTranscludeFn && transcludeFn) {
childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);

} else {
nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
childBoundTranscludeFn = null;
}

nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);

} else if (childLinkFn) {
childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
}
}
}
}

function createBoundTranscludeFn(scope, transcludeFn) {
return function boundTranscludeFn(transcludedScope, cloneFn, controllers) {
function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {

var boundTranscludeFn = function(transcludedScope, cloneFn, controllers) {
var scopeCreated = false;

if (!transcludedScope) {
Expand All @@ -983,12 +994,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
scopeCreated = true;
}

var clone = transcludeFn(transcludedScope, cloneFn, controllers);
var clone = transcludeFn(transcludedScope, cloneFn, controllers, previousBoundTranscludeFn);
if (scopeCreated) {
clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy));
clone.on('$destroy', function() { transcludedScope.$destroy(); });
}
return clone;
};

return boundTranscludeFn;
}

/**
Expand Down Expand Up @@ -1166,6 +1179,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
templateDirective = previousCompileContext.templateDirective,
nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
hasTranscludeDirective = false,
hasTemplate = false,
hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
$compileNode = templateAttrs.$$element = jqLite(compileNode),
directive,
Expand Down Expand Up @@ -1256,6 +1270,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}

if (directive.template) {
hasTemplate = true;
assertNoDuplicate('template', templateDirective, directive, $compileNode);
templateDirective = directive;

Expand Down Expand Up @@ -1305,6 +1320,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}

if (directive.templateUrl) {
hasTemplate = true;
assertNoDuplicate('template', templateDirective, directive, $compileNode);
templateDirective = directive;

Expand All @@ -1313,7 +1329,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}

nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
templateAttrs, jqCollection, childTranscludeFn, preLinkFns, postLinkFns, {
templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
controllerDirectives: controllerDirectives,
newIsolateScopeDirective: newIsolateScopeDirective,
templateDirective: templateDirective,
Expand Down Expand Up @@ -1341,7 +1357,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}

nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
nodeLinkFn.templateOnThisElement = hasTemplate;
nodeLinkFn.transclude = childTranscludeFn;

previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;

// might be normal or delayed nodeLinkFn depending on if templateUrl is present
Expand Down Expand Up @@ -1760,8 +1779,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// Copy in CSS classes from original node
safeAddClass(jqLite(linkNode), oldClasses);
}
if (afterTemplateNodeLinkFn.transclude) {
childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
} else {
childBoundTranscludeFn = boundTranscludeFn;
}
Expand Down
4 changes: 2 additions & 2 deletions src/ng/directive/ngIf.js
Expand Up @@ -89,8 +89,8 @@ var ngIfDirective = ['$animate', function($animate) {

if (toBoolean(value)) {
if (!childScope) {
childScope = $scope.$new();
$transclude(childScope, function (clone) {
$transclude(function (clone, newScope) {
childScope = newScope;
clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
// Note: We only need the first/last node of the cloned nodes.
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
Expand Down
46 changes: 21 additions & 25 deletions src/ng/directive/ngRepeat.js
Expand Up @@ -264,7 +264,6 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
// lastBlockMap on the next iteration.
nextBlockMap = {},
arrayLength,
childScope,
key, value, // key/value of iteration
trackById,
trackByIdFn,
Expand All @@ -273,6 +272,17 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
nextBlockOrder = [],
elementsToRemove;

var updateScope = function(scope, index) {
scope[valueIdentifier] = value;
if (keyIdentifier) scope[keyIdentifier] = key;
scope.$index = index;
scope.$first = (index === 0);
scope.$last = (index === (arrayLength - 1));
scope.$middle = !(scope.$first || scope.$last);
// jshint bitwise: false
scope.$odd = !(scope.$even = (index&1) === 0);
// jshint bitwise: true
};

if (isArrayLike(collection)) {
collectionKeys = collection;
Expand All @@ -281,9 +291,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
trackByIdFn = trackByIdExpFn || trackByIdObjFn;
// if object, extract keys, sort them and use to determine order of iteration over obj props
collectionKeys = [];
for (key in collection) {
if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
collectionKeys.push(key);
for (var itemKey in collection) {
if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) != '$') {
collectionKeys.push(itemKey);
}
}
collectionKeys.sort();
Expand Down Expand Up @@ -319,10 +329,10 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
}

// remove existing items
for (key in lastBlockMap) {
for (var blockKey in lastBlockMap) {
// lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
if (lastBlockMap.hasOwnProperty(key)) {
block = lastBlockMap[key];
if (lastBlockMap.hasOwnProperty(blockKey)) {
block = lastBlockMap[blockKey];
elementsToRemove = getBlockElements(block.clone);
$animate.leave(elementsToRemove);
forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
Expand All @@ -340,8 +350,6 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
if (block.scope) {
// if we have already seen this object, then we need to reuse the
// associated scope/element
childScope = block.scope;

nextNode = previousNode;
do {
nextNode = nextNode.nextSibling;
Expand All @@ -352,32 +360,20 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
$animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
}
previousNode = getBlockEnd(block);
updateScope(block.scope, index);
} else {
// new item which we don't know about
childScope = $scope.$new();
}

childScope[valueIdentifier] = value;
if (keyIdentifier) childScope[keyIdentifier] = key;
childScope.$index = index;
childScope.$first = (index === 0);
childScope.$last = (index === (arrayLength - 1));
childScope.$middle = !(childScope.$first || childScope.$last);
// jshint bitwise: false
childScope.$odd = !(childScope.$even = (index&1) === 0);
// jshint bitwise: true

if (!block.scope) {
$transclude(childScope, function(clone) {
$transclude(function(clone, scope) {
block.scope = scope;
clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
$animate.enter(clone, null, jqLite(previousNode));
previousNode = clone;
block.scope = childScope;
// Note: We only need the first/last node of the cloned nodes.
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
// by a directive with templateUrl when it's template arrives.
block.clone = clone;
nextBlockMap[block.id] = block;
updateScope(block.scope, index);
});
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/ngTouch/directive/ngClick.js
Expand Up @@ -95,8 +95,8 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
//
// Why not just put click handlers on the element?
// We do that too, just to be sure. If the tap event caused the DOM to change,
// it is possible another element is now in that position. To take account for these possibly distinct elements,
// the handlers are global and care only about coordinates.
// it is possible another element is now in that position. To take account for these possibly
// distinct elements, the handlers are global and care only about coordinates.

// Checks if the coordinates are close enough to be within the region.
function hit(x1, y1, x2, y2) {
Expand Down