@@ -152,6 +152,7 @@ function $CompileProvider($provide) {
152
152
var hasDirectives = { } ,
153
153
Suffix = 'Directive' ,
154
154
COMMENT_DIRECTIVE_REGEXP = / ^ \s * d i r e c t i v e \: \s * ( [ \d \w \- _ ] + ) \s + ( .* ) $ / ,
155
+ COMMENT_END_DIRECTIVE_REGEXP = / ^ \s * (?: d i r e c t i v e \: ) ? \s * ( [ \d \w \- _ ] + ) \s * $ / ,
155
156
CLASS_DIRECTIVE_REGEXP = / ( ( [ \d \w \- _ ] + ) (?: \: ( [ ^ ; ] + ) ) ? ; ? ) / ,
156
157
aHrefSanitizationWhitelist = / ^ \s * ( h t t p s ? | f t p | m a i l t o | f i l e ) : / ,
157
158
imgSrcSanitizationWhitelist = / ^ \s * ( h t t p s ? | f t p | f i l e ) : | d a t a : i m a g e \/ / ;
@@ -601,20 +602,21 @@ function $CompileProvider($provide) {
601
602
var nodeType = node . nodeType ,
602
603
attrsMap = attrs . $attr ,
603
604
match ,
604
- className ;
605
+ className ,
606
+ name , nName ,
607
+ startName , endName , index ;
605
608
606
609
switch ( nodeType ) {
607
610
case 1 : /* Element */
608
611
// use the node name: <directive>
609
- addDirective ( directives ,
610
- directiveNormalize ( nodeName_ ( node ) . toLowerCase ( ) ) , 'E' , maxPriority , ignoreDirective ) ;
612
+ name = nodeName_ ( node ) . toLowerCase ( ) ;
613
+ nName = directiveNormalize ( name ) ;
614
+ handleStartEndName ( name , nName ) ;
615
+ addDirective ( directives , nName , 'E' , maxPriority , ignoreDirective , startName , endName ) ;
611
616
612
617
// iterate over the attributes
613
- for ( var attr , name , nName , ngAttrName , value , nAttrs = node . attributes ,
618
+ for ( var attr , ngAttrName , value , nAttrs = node . attributes ,
614
619
j = 0 , jj = nAttrs && nAttrs . length ; j < jj ; j ++ ) {
615
- var attrStartName ;
616
- var attrEndName ;
617
- var index ;
618
620
619
621
attr = nAttrs [ j ] ;
620
622
if ( ! msie || msie >= 8 || attr . specified ) {
@@ -624,12 +626,8 @@ function $CompileProvider($provide) {
624
626
if ( NG_ATTR_BINDING . test ( ngAttrName ) ) {
625
627
name = ngAttrName . substr ( 6 ) . toLowerCase ( ) ;
626
628
}
627
- if ( ( index = ngAttrName . lastIndexOf ( 'Start' ) ) != - 1 && index == ngAttrName . length - 5 ) {
628
- attrStartName = name ;
629
- attrEndName = name . substr ( 0 , name . length - 5 ) + 'end' ;
630
- name = name . substr ( 0 , name . length - 6 ) ;
631
- }
632
629
nName = directiveNormalize ( name . toLowerCase ( ) ) ;
630
+ handleStartEndName ( name , nName ) ;
633
631
attrsMap [ nName ] = name ;
634
632
attrs [ nName ] = value = trim ( ( msie && name == 'href' )
635
633
? decodeURIComponent ( node . getAttribute ( name , 2 ) )
@@ -638,16 +636,18 @@ function $CompileProvider($provide) {
638
636
attrs [ nName ] = true ; // presence means true
639
637
}
640
638
addAttrInterpolateDirective ( node , directives , value , nName ) ;
641
- addDirective ( directives , nName , 'A' , maxPriority , ignoreDirective , attrStartName , attrEndName ) ;
639
+ addDirective ( directives , nName , 'A' , maxPriority , ignoreDirective , startName , endName ) ;
642
640
}
643
641
}
644
642
645
643
// use class as directive
646
644
className = node . className ;
647
645
if ( isString ( className ) && className !== '' ) {
648
646
while ( match = CLASS_DIRECTIVE_REGEXP . exec ( className ) ) {
649
- nName = directiveNormalize ( match [ 2 ] ) ;
650
- if ( addDirective ( directives , nName , 'C' , maxPriority , ignoreDirective ) ) {
647
+ name = match [ 2 ] ;
648
+ nName = directiveNormalize ( name ) ;
649
+ handleStartEndName ( name , nName ) ;
650
+ if ( addDirective ( directives , nName , 'C' , maxPriority , ignoreDirective , startName , endName ) ) {
651
651
attrs [ nName ] = trim ( match [ 3 ] ) ;
652
652
}
653
653
className = className . substr ( match . index + match [ 0 ] . length ) ;
@@ -661,8 +661,10 @@ function $CompileProvider($provide) {
661
661
try {
662
662
match = COMMENT_DIRECTIVE_REGEXP . exec ( node . nodeValue ) ;
663
663
if ( match ) {
664
- nName = directiveNormalize ( match [ 1 ] ) ;
665
- if ( addDirective ( directives , nName , 'M' , maxPriority , ignoreDirective ) ) {
664
+ name = match [ 1 ] ;
665
+ nName = directiveNormalize ( name ) ;
666
+ handleStartEndName ( name , nName ) ;
667
+ if ( addDirective ( directives , nName , 'M' , maxPriority , ignoreDirective , startName , endName ) ) {
666
668
attrs [ nName ] = trim ( match [ 2 ] ) ;
667
669
}
668
670
}
@@ -675,48 +677,115 @@ function $CompileProvider($provide) {
675
677
676
678
directives . sort ( byPriority ) ;
677
679
return directives ;
680
+
681
+ // takes care of populating (or emptying) startName and endName
682
+ // Also changes `name` and `nName` in the external scope if necessary
683
+ function handleStartEndName ( _name , _nName ) {
684
+ var index ;
685
+ if ( ( index = _nName . lastIndexOf ( 'Start' ) ) != - 1 && index == _nName . length - 5 ) {
686
+ startName = _name ;
687
+ endName = _name . substr ( 0 , _name . length - 5 ) + 'end' ;
688
+ name = _name . substr ( 0 , _name . length - 6 ) ;
689
+ nName = directiveNormalize ( name ) ;
690
+ } else {
691
+ startName = endName = undefined ;
692
+ }
693
+ return name ;
694
+ }
678
695
}
679
696
680
697
/**
681
698
* Given a node with an directive-start it collects all of the siblings until it find directive-end.
682
699
* @param node
683
- * @param attrStart
684
- * @param attrEnd
700
+ * @param nameStart
701
+ * @param nameEnd
702
+ * @param location
685
703
* @returns {* }
686
704
*/
687
- function groupScan ( node , attrStart , attrEnd ) {
688
- var nodes = [ ] ;
689
- var depth = 0 ;
690
- if ( attrStart && node . hasAttribute && node . hasAttribute ( attrStart ) ) {
691
- var startNode = node ;
692
- do {
693
- if ( ! node ) {
694
- throw $compileMinErr ( 'utrat' , "Unterminated attribute, found '{0}' but no matching '{1}' found." , attrStart , attrEnd ) ;
695
- }
696
- if ( node . nodeType == 1 /** Element **/ ) {
697
- if ( node . hasAttribute ( attrStart ) ) depth ++ ;
698
- if ( node . hasAttribute ( attrEnd ) ) depth -- ;
699
- }
700
- nodes . push ( node ) ;
701
- node = node . nextSibling ;
702
- } while ( depth > 0 ) ;
703
- } else {
704
- nodes . push ( node ) ;
705
+ function groupScan ( node , nameStart , nameEnd , location ) {
706
+ var nodes = [ ] ,
707
+ depth = 0 ,
708
+ $node , name ;
709
+ if ( nameStart ) {
710
+ switch ( location ) {
711
+ case 'E' : /* Element */
712
+ do {
713
+ if ( ! node ) {
714
+ throw $compileMinErr ( 'utrel' , "Unterminated element, found '{0}' but no matching '{1}' found." , nameStart , nameEnd ) ;
715
+ }
716
+ if ( node . nodeType == 1 /** Element **/ ) {
717
+ name = nodeName_ ( node ) . toLowerCase ( )
718
+ if ( name == nameStart ) depth ++ ;
719
+ if ( name == nameEnd ) depth -- ;
720
+ }
721
+ nodes . push ( node ) ;
722
+ node = node . nextSibling ;
723
+ } while ( depth > 0 ) ;
724
+ break ;
725
+
726
+ case 'A' : /* Attribute */
727
+ if ( node . hasAttribute && node . hasAttribute ( nameStart ) ) {
728
+ do {
729
+ if ( ! node ) {
730
+ throw $compileMinErr ( 'utrat' , "Unterminated attribute, found '{0}' but no matching '{1}' found." , nameStart , nameEnd ) ;
731
+ }
732
+ if ( node . nodeType == 1 /** Element **/ ) {
733
+ if ( node . hasAttribute ( nameStart ) ) depth ++ ;
734
+ if ( node . hasAttribute ( nameEnd ) ) depth -- ;
735
+ }
736
+ nodes . push ( node ) ;
737
+ node = node . nextSibling ;
738
+ } while ( depth > 0 ) ;
739
+ }
740
+ break ;
741
+
742
+ case 'C' : /* Class */
743
+ do {
744
+ if ( ! node ) {
745
+ throw $compileMinErr ( 'utrcl' , "Unterminated class, found '{0}' but no matching '{1}' found." , nameStart , nameEnd ) ;
746
+ }
747
+ if ( node . nodeType == 1 /** Element **/ ) {
748
+ $node = jqLite ( node ) ;
749
+ if ( $node . hasClass ( nameStart ) || $node . hasClass ( nameStart + ":" ) ) depth ++ ;
750
+ if ( $node . hasClass ( nameEnd ) ) depth -- ;
751
+ }
752
+ nodes . push ( node ) ;
753
+ node = node . nextSibling ;
754
+ } while ( depth > 0 ) ;
755
+ break ;
756
+
757
+ case 'M' : /* Comment */
758
+ do {
759
+ if ( ! node ) {
760
+ throw $compileMinErr ( 'utrcm' , "Unterminated comment, found '{0}' but no matching '{1}' found." , nameStart , nameEnd ) ;
761
+ }
762
+ if ( node . nodeType == 8 /** Comment **/ ) {
763
+ name = COMMENT_DIRECTIVE_REGEXP . exec ( node . nodeValue ) ;
764
+ if ( name && name [ 1 ] == nameStart ) depth ++ ;
765
+ name = COMMENT_END_DIRECTIVE_REGEXP . exec ( node . nodeValue ) ;
766
+ if ( name && name [ 1 ] == nameEnd ) depth -- ;
767
+ }
768
+ nodes . push ( node ) ;
769
+ node = node . nextSibling ;
770
+ } while ( depth > 0 ) ;
771
+ break ;
772
+ }
705
773
}
706
- return jqLite ( nodes ) ;
774
+ return jqLite ( nodes . length ? nodes : node ) ;
707
775
}
708
776
709
777
/**
710
778
* Wrapper for linking function which converts normal linking function into a grouped
711
779
* linking function.
712
780
* @param linkFn
713
- * @param attrStart
714
- * @param attrEnd
781
+ * @param nameStart
782
+ * @param nameEnd
783
+ * @param location
715
784
* @returns {Function }
716
785
*/
717
- function groupElementsLinkFnWrapper ( linkFn , attrStart , attrEnd ) {
786
+ function groupElementsLinkFnWrapper ( linkFn , nameStart , nameEnd , location ) {
718
787
return function ( scope , element , attrs , controllers ) {
719
- element = groupScan ( element [ 0 ] , attrStart , attrEnd ) ;
788
+ element = groupScan ( element [ 0 ] , nameStart , nameEnd , location ) ;
720
789
return linkFn ( scope , element , attrs , controllers ) ;
721
790
}
722
791
}
@@ -757,12 +826,12 @@ function $CompileProvider($provide) {
757
826
// executes all directives on the current element
758
827
for ( var i = 0 , ii = directives . length ; i < ii ; i ++ ) {
759
828
directive = directives [ i ] ;
760
- var attrStart = directive . $$start ;
761
- var attrEnd = directive . $$end ;
829
+ var nameStart = directive . $$start ;
830
+ var nameEnd = directive . $$end ;
762
831
763
832
// collect multiblock sections
764
- if ( attrStart ) {
765
- $compileNode = groupScan ( compileNode , attrStart , attrEnd )
833
+ if ( nameStart ) {
834
+ $compileNode = groupScan ( compileNode , nameStart , nameEnd , directive . $$location )
766
835
}
767
836
$template = undefined ;
768
837
@@ -794,7 +863,7 @@ function $CompileProvider($provide) {
794
863
transcludeDirective = directive ;
795
864
terminalPriority = directive . priority ;
796
865
if ( directiveValue == 'element' ) {
797
- $template = groupScan ( compileNode , attrStart , attrEnd )
866
+ $template = groupScan ( compileNode , nameStart , nameEnd , directive . $$location )
798
867
$compileNode = templateAttrs . $$element =
799
868
jqLite ( document . createComment ( ' ' + directiveName + ': ' + templateAttrs [ directiveName ] + ' ' ) ) ;
800
869
compileNode = $compileNode [ 0 ] ;
@@ -868,9 +937,9 @@ function $CompileProvider($provide) {
868
937
try {
869
938
linkFn = directive . compile ( $compileNode , templateAttrs , childTranscludeFn ) ;
870
939
if ( isFunction ( linkFn ) ) {
871
- addLinkFns ( null , linkFn , attrStart , attrEnd ) ;
940
+ addLinkFns ( null , linkFn , nameStart , nameEnd , directive . $$location ) ;
872
941
} else if ( linkFn ) {
873
- addLinkFns ( linkFn . pre , linkFn . post , attrStart , attrEnd ) ;
942
+ addLinkFns ( linkFn . pre , linkFn . post , nameStart , nameEnd , directive . $$location ) ;
874
943
}
875
944
} catch ( e ) {
876
945
$exceptionHandler ( e , startingTag ( $compileNode ) ) ;
@@ -892,14 +961,14 @@ function $CompileProvider($provide) {
892
961
893
962
////////////////////
894
963
895
- function addLinkFns ( pre , post , attrStart , attrEnd ) {
964
+ function addLinkFns ( pre , post , nameStart , nameEnd , location ) {
896
965
if ( pre ) {
897
- if ( attrStart ) pre = groupElementsLinkFnWrapper ( pre , attrStart , attrEnd ) ;
966
+ if ( nameStart ) pre = groupElementsLinkFnWrapper ( pre , nameStart , nameEnd , location ) ;
898
967
pre . require = directive . require ;
899
968
preLinkFns . push ( pre ) ;
900
969
}
901
970
if ( post ) {
902
- if ( attrStart ) post = groupElementsLinkFnWrapper ( post , attrStart , attrEnd ) ;
971
+ if ( nameStart ) post = groupElementsLinkFnWrapper ( post , nameStart , nameEnd , location ) ;
903
972
post . require = directive . require ;
904
973
postLinkFns . push ( post ) ;
905
974
}
@@ -1087,7 +1156,7 @@ function $CompileProvider($provide) {
1087
1156
* * `M`: comment
1088
1157
* @returns true if directive was added.
1089
1158
*/
1090
- function addDirective ( tDirectives , name , location , maxPriority , ignoreDirective , startAttrName , endAttrName ) {
1159
+ function addDirective ( tDirectives , name , location , maxPriority , ignoreDirective , startName , endName ) {
1091
1160
if ( name === ignoreDirective ) return null ;
1092
1161
var match = null ;
1093
1162
if ( hasDirectives . hasOwnProperty ( name ) ) {
@@ -1097,8 +1166,8 @@ function $CompileProvider($provide) {
1097
1166
directive = directives [ i ] ;
1098
1167
if ( ( maxPriority === undefined || maxPriority > directive . priority ) &&
1099
1168
directive . restrict . indexOf ( location ) != - 1 ) {
1100
- if ( startAttrName ) {
1101
- directive = inherit ( directive , { $$start : startAttrName , $$end : endAttrName } ) ;
1169
+ if ( startName ) {
1170
+ directive = inherit ( directive , { $$start : startName , $$end : endName , $$location : location } ) ;
1102
1171
}
1103
1172
tDirectives . push ( directive ) ;
1104
1173
match = directive ;
0 commit comments