@@ -377,6 +377,10 @@ Lexer.prototype = {
377
377
} ;
378
378
379
379
380
+ function isConstant ( exp ) {
381
+ return exp . constant ;
382
+ }
383
+
380
384
/**
381
385
* @constructor
382
386
*/
@@ -494,23 +498,25 @@ Parser.prototype = {
494
498
return extend ( function ( self , locals ) {
495
499
return fn ( self , locals , right ) ;
496
500
} , {
497
- constant :right . constant
501
+ constant :right . constant ,
502
+ inputs : [ right ]
498
503
} ) ;
499
504
} ,
500
505
501
506
ternaryFn : function ( left , middle , right ) {
502
507
return extend ( function ( self , locals ) {
503
508
return left ( self , locals ) ? middle ( self , locals ) : right ( self , locals ) ;
504
509
} , {
505
- constant : left . constant && middle . constant && right . constant
510
+ constant :left . constant && middle . constant && right . constant
506
511
} ) ;
507
512
} ,
508
513
509
- binaryFn : function ( left , fn , right ) {
514
+ binaryFn : function ( left , fn , right , isBranching ) {
510
515
return extend ( function ( self , locals ) {
511
516
return fn ( self , locals , left , right ) ;
512
517
} , {
513
- constant :left . constant && right . constant
518
+ constant : left . constant && right . constant ,
519
+ inputs : ! isBranching && [ left , right ]
514
520
} ) ;
515
521
} ,
516
522
@@ -558,7 +564,9 @@ Parser.prototype = {
558
564
}
559
565
}
560
566
561
- return function $parseFilter ( self , locals ) {
567
+ var inputs = [ inputFn ] . concat ( argsFn || [ ] ) ;
568
+
569
+ return extend ( function $parseFilter ( self , locals ) {
562
570
var input = inputFn ( self , locals ) ;
563
571
if ( args ) {
564
572
args [ 0 ] = input ;
@@ -572,7 +580,10 @@ Parser.prototype = {
572
580
}
573
581
574
582
return fn ( input ) ;
575
- } ;
583
+ } , {
584
+ constant : ! fn . externalInput && inputs . every ( isConstant ) ,
585
+ inputs : ! fn . externalInput && inputs
586
+ } ) ;
576
587
} ,
577
588
578
589
expression : function ( ) {
@@ -589,9 +600,11 @@ Parser.prototype = {
589
600
this . text . substring ( 0 , token . index ) + '] can not be assigned to' , token ) ;
590
601
}
591
602
right = this . ternary ( ) ;
592
- return function $parseAssignment ( scope , locals ) {
603
+ return extend ( function $parseAssignment ( scope , locals ) {
593
604
return left . assign ( scope , right ( scope , locals ) , locals ) ;
594
- } ;
605
+ } , {
606
+ inputs : [ left , right ]
607
+ } ) ;
595
608
}
596
609
return left ;
597
610
} ,
@@ -616,7 +629,7 @@ Parser.prototype = {
616
629
var left = this . logicalAND ( ) ;
617
630
var token ;
618
631
while ( ( token = this . expect ( '||' ) ) ) {
619
- left = this . binaryFn ( left , token . fn , this . logicalAND ( ) ) ;
632
+ left = this . binaryFn ( left , token . fn , this . logicalAND ( ) , true ) ;
620
633
}
621
634
return left ;
622
635
} ,
@@ -625,7 +638,7 @@ Parser.prototype = {
625
638
var left = this . equality ( ) ;
626
639
var token ;
627
640
if ( ( token = this . expect ( '&&' ) ) ) {
628
- left = this . binaryFn ( left , token . fn , this . logicalAND ( ) ) ;
641
+ left = this . binaryFn ( left , token . fn , this . logicalAND ( ) , true ) ;
629
642
}
630
643
return left ;
631
644
} ,
@@ -760,7 +773,6 @@ Parser.prototype = {
760
773
// This is used with json array declaration
761
774
arrayDeclaration : function ( ) {
762
775
var elementFns = [ ] ;
763
- var allConstant = true ;
764
776
if ( this . peekToken ( ) . text !== ']' ) {
765
777
do {
766
778
if ( this . peek ( ']' ) ) {
@@ -769,9 +781,6 @@ Parser.prototype = {
769
781
}
770
782
var elementFn = this . expression ( ) ;
771
783
elementFns . push ( elementFn ) ;
772
- if ( ! elementFn . constant ) {
773
- allConstant = false ;
774
- }
775
784
} while ( this . expect ( ',' ) ) ;
776
785
}
777
786
this . consume ( ']' ) ;
@@ -784,13 +793,13 @@ Parser.prototype = {
784
793
return array ;
785
794
} , {
786
795
literal : true ,
787
- constant : allConstant
796
+ constant : elementFns . every ( isConstant ) ,
797
+ inputs : elementFns
788
798
} ) ;
789
799
} ,
790
800
791
801
object : function ( ) {
792
802
var keys = [ ] , values = [ ] ;
793
- var allConstant = true ;
794
803
if ( this . peekToken ( ) . text !== '}' ) {
795
804
do {
796
805
if ( this . peek ( '}' ) ) {
@@ -802,9 +811,6 @@ Parser.prototype = {
802
811
this . consume ( ':' ) ;
803
812
var value = this . expression ( ) ;
804
813
values . push ( value ) ;
805
- if ( ! value . constant ) {
806
- allConstant = false ;
807
- }
808
814
} while ( this . expect ( ',' ) ) ;
809
815
}
810
816
this . consume ( '}' ) ;
@@ -817,7 +823,8 @@ Parser.prototype = {
817
823
return object ;
818
824
} , {
819
825
literal : true ,
820
- constant : allConstant
826
+ constant : values . every ( isConstant ) ,
827
+ inputs : values
821
828
} ) ;
822
829
}
823
830
} ;
@@ -1045,6 +1052,9 @@ function $ParseProvider() {
1045
1052
parsedExpression . $$watchDelegate = parsedExpression . literal ?
1046
1053
oneTimeLiteralWatchDelegate : oneTimeWatchDelegate ;
1047
1054
}
1055
+ else if ( parsedExpression . inputs ) {
1056
+ parsedExpression . $$watchDelegate = inputsWatchDelegate ;
1057
+ }
1048
1058
1049
1059
cache [ cacheKey ] = parsedExpression ;
1050
1060
}
@@ -1058,6 +1068,81 @@ function $ParseProvider() {
1058
1068
}
1059
1069
} ;
1060
1070
1071
+ function collectExpressionInputs ( inputs , list ) {
1072
+ for ( var i = 0 , ii = inputs . length ; i < ii ; i ++ ) {
1073
+ var input = inputs [ i ] ;
1074
+ if ( ! input . constant ) {
1075
+ if ( input . inputs ) {
1076
+ collectExpressionInputs ( input . inputs , list ) ;
1077
+ }
1078
+ else if ( - 1 === list . indexOf ( input ) ) {
1079
+ list . push ( input ) ;
1080
+ }
1081
+ }
1082
+ }
1083
+
1084
+ return list ;
1085
+ }
1086
+
1087
+ function simpleEquals ( o1 , o2 ) {
1088
+ if ( o1 == null || o2 == null ) return o1 === o2 ; // null/undefined
1089
+
1090
+ if ( typeof o1 === "object" ) {
1091
+ //The same object is not supported because it may have been mutated
1092
+ if ( o1 === o2 ) return false ;
1093
+
1094
+ if ( typeof o2 !== "object" ) return false ;
1095
+
1096
+ //Convert to primitive if possible
1097
+ o1 = o1 . valueOf ( ) ;
1098
+ o2 = o2 . valueOf ( ) ;
1099
+
1100
+ //If the type became a non-object then we can use the primitive check below
1101
+ if ( typeof o1 === "object" ) return false ;
1102
+ }
1103
+
1104
+ //Primitive or NaN
1105
+ return o1 === o2 || ( o1 !== o1 && o2 !== o2 ) ;
1106
+ }
1107
+
1108
+ function inputsWatchDelegate ( scope , listener , objectEquality , parsedExpression ) {
1109
+ var inputExpressions = parsedExpression . $$inputs ||
1110
+ ( parsedExpression . $$inputs = collectExpressionInputs ( parsedExpression . inputs , [ ] ) ) ;
1111
+
1112
+ var inputs = [ simpleEquals /*=something that will never equal an evaluated input*/ ] ;
1113
+ var lastResult ;
1114
+
1115
+ if ( 1 === inputExpressions . length ) {
1116
+ inputs = inputs [ 0 ] ;
1117
+ inputExpressions = inputExpressions [ 0 ] ;
1118
+ return scope . $watch ( function expressionInputWatch ( scope ) {
1119
+ var newVal = inputExpressions ( scope ) ;
1120
+ if ( ! simpleEquals ( newVal , inputs ) ) {
1121
+ lastResult = parsedExpression ( scope ) ;
1122
+ inputs = newVal ;
1123
+ }
1124
+ return lastResult ;
1125
+ } , listener , objectEquality ) ;
1126
+ }
1127
+
1128
+ return scope . $watch ( function expressionInputsWatch ( scope ) {
1129
+ var changed = false ;
1130
+
1131
+ for ( var i = 0 , ii = inputExpressions . length ; i < ii ; i ++ ) {
1132
+ var valI = inputExpressions [ i ] ( scope ) ;
1133
+ if ( changed || ( changed = ! simpleEquals ( valI , inputs [ i ] ) ) ) {
1134
+ inputs [ i ] = valI ;
1135
+ }
1136
+ }
1137
+
1138
+ if ( changed ) {
1139
+ lastResult = parsedExpression ( scope ) ;
1140
+ }
1141
+
1142
+ return lastResult ;
1143
+ } , listener , objectEquality ) ;
1144
+ }
1145
+
1061
1146
function oneTimeWatchDelegate ( scope , listener , objectEquality , parsedExpression ) {
1062
1147
var unwatch , lastValue ;
1063
1148
return unwatch = scope . $watch ( function oneTimeWatch ( scope ) {
@@ -1123,7 +1208,17 @@ function $ParseProvider() {
1123
1208
// initial value is defined (for bind-once)
1124
1209
return isDefined ( value ) ? result : value ;
1125
1210
} ;
1126
- fn . $$watchDelegate = parsedExpression . $$watchDelegate ;
1211
+
1212
+ //Propogate $$watchDelegates other then inputsWatchDelegate
1213
+ if ( parsedExpression . $$watchDelegate && parsedExpression . $$watchDelegate !== inputsWatchDelegate ) {
1214
+ fn . $$watchDelegate = parsedExpression . $$watchDelegate ;
1215
+ }
1216
+ //Treat the interceptorFn similar to filters - it is assumed to be a pure function unless flagged
1217
+ else if ( ! interceptorFn . externalInput ) {
1218
+ fn . $$watchDelegate = inputsWatchDelegate ;
1219
+ fn . inputs = [ parsedExpression ] ;
1220
+ }
1221
+
1127
1222
return fn ;
1128
1223
}
1129
1224
} ] ;
0 commit comments