@@ -1486,6 +1486,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
14861486 } ) ;
14871487 } ;
14881488
1489+ // We need to attach the transclusion slots onto the `boundTranscludeFn`
1490+ // so that they are available inside the `controllersBoundTransclude` function
1491+ var boundSlots = boundTranscludeFn . $$slots = createMap ( ) ;
1492+ for ( var slotName in transcludeFn . $$slots ) {
1493+ boundSlots [ slotName ] = createBoundTranscludeFn ( scope , transcludeFn . $$slots [ slotName ] , previousBoundTranscludeFn ) ;
1494+ }
1495+
14891496 return boundTranscludeFn ;
14901497 }
14911498
@@ -1826,6 +1833,52 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
18261833 // on the same element more than once.
18271834 nonTlbTranscludeDirective : nonTlbTranscludeDirective
18281835 } ) ;
1836+ } else if ( isObject ( directiveValue ) ) {
1837+
1838+ // We have multiple transclusion zones - match them and collect them up into slots
1839+ $template = [ ] ;
1840+ var slots = createMap ( ) ;
1841+ var slotNames = createMap ( ) ;
1842+ var filledSlots = createMap ( ) ;
1843+
1844+ // Parse the slot names: if they start with a ? then they are optional
1845+ forEach ( directiveValue , function ( slotName , key ) {
1846+ var optional = ( slotName . charAt ( 0 ) === '?' ) ;
1847+ slotName = optional ? slotName . substring ( 1 ) : slotName ;
1848+ slotNames [ key ] = slotName ;
1849+ slots [ slotName ] = [ ] ;
1850+ // filledSlots will contain true for all slots that are either
1851+ // optional or have been filled
1852+ filledSlots [ slotName ] = optional ;
1853+ } ) ;
1854+
1855+
1856+ forEach ( $compileNode . children ( ) , function ( node ) {
1857+ var slotName = slotNames [ directiveNormalize ( nodeName_ ( node ) ) ] ;
1858+ var slot = $template ;
1859+ if ( slotName ) {
1860+ filledSlots [ slotName ] = true ;
1861+ slots [ slotName ] . push ( node ) ;
1862+ } else {
1863+ $template . push ( node ) ;
1864+ }
1865+ } ) ;
1866+
1867+ // Check for required slots that were not filled
1868+ forEach ( filledSlots , function ( filled , slotName ) {
1869+ if ( ! filled ) {
1870+ throw $compileMinErr ( 'reqslot' , 'Required transclusion slot `{0}` was not filled.' , slotName ) ;
1871+ }
1872+ } ) ;
1873+
1874+ // Compile each slot into a transclusion function and attach them to the default transclusion function
1875+ childTranscludeFn = compilationGenerator ( mightHaveMultipleTransclusionError , $template , transcludeFn ) ;
1876+ forEach ( Object . keys ( slots ) , function ( slotName ) {
1877+ slots [ slotName ] = compilationGenerator ( mightHaveMultipleTransclusionError , slots [ slotName ] , transcludeFn ) ;
1878+ } ) ;
1879+ childTranscludeFn . $$slots = slots ;
1880+ $compileNode . empty ( ) ; // clear contents
1881+
18291882 } else {
18301883 $template = jqLite ( jqLiteClone ( compileNode ) ) . contents ( ) ;
18311884 $compileNode . empty ( ) ; // clear contents
@@ -2134,11 +2187,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
21342187
21352188 // This is the function that is injected as `$transclude`.
21362189 // Note: all arguments are optional!
2137- function controllersBoundTransclude ( scope , cloneAttachFn , futureParentElement ) {
2190+ function controllersBoundTransclude ( scope , cloneAttachFn , futureParentElement , slotName ) {
21382191 var transcludeControllers ;
2139-
21402192 // No scope passed in:
21412193 if ( ! isScope ( scope ) ) {
2194+ slotName = futureParentElement ;
21422195 futureParentElement = cloneAttachFn ;
21432196 cloneAttachFn = scope ;
21442197 scope = undefined ;
@@ -2150,6 +2203,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
21502203 if ( ! futureParentElement ) {
21512204 futureParentElement = hasElementTranscludeDirective ? $element . parent ( ) : $element ;
21522205 }
2206+ if ( slotName ) {
2207+ var slotTranscludeFn = boundTranscludeFn . $$slots [ slotName ] ;
2208+ if ( ! slotTranscludeFn ) {
2209+ throw $compileMinErr ( 'noslot' ,
2210+ 'No parent directive that requires a transclusion with slot name "{0}". ' +
2211+ 'Element: {1}' ,
2212+ slotName , startingTag ( $element ) ) ;
2213+ }
2214+ return slotTranscludeFn ( scope , cloneAttachFn , transcludeControllers , futureParentElement , scopeToChild ) ;
2215+ }
21532216 return boundTranscludeFn ( scope , cloneAttachFn , transcludeControllers , futureParentElement , scopeToChild ) ;
21542217 }
21552218 }
0 commit comments