@@ -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,26 @@ 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 ,
511
+ inputs : [ left , middle , right ]
506
512
} ) ;
507
513
} ,
508
514
509
515
binaryFn : function ( left , fn , right ) {
510
516
return extend ( function ( self , locals ) {
511
517
return fn ( self , locals , left , right ) ;
512
518
} , {
513
- constant :left . constant && right . constant
519
+ constant :left . constant && right . constant ,
520
+ inputs : [ left , right ]
514
521
} ) ;
515
522
} ,
516
523
@@ -558,7 +565,9 @@ Parser.prototype = {
558
565
}
559
566
}
560
567
561
- return function $parseFilter ( self , locals ) {
568
+ var inputs = ! fn . externalInput && [ inputFn ] . concat ( argsFn || [ ] ) ;
569
+
570
+ return extend ( function $parseFilter ( self , locals ) {
562
571
var input = inputFn ( self , locals ) ;
563
572
if ( args ) {
564
573
args [ 0 ] = input ;
@@ -572,7 +581,10 @@ Parser.prototype = {
572
581
}
573
582
574
583
return fn ( input ) ;
575
- } ;
584
+ } , {
585
+ constant : inputs && inputs . every ( isConstant ) ,
586
+ inputs : inputs
587
+ } ) ;
576
588
} ,
577
589
578
590
expression : function ( ) {
@@ -589,9 +601,11 @@ Parser.prototype = {
589
601
this . text . substring ( 0 , token . index ) + '] can not be assigned to' , token ) ;
590
602
}
591
603
right = this . ternary ( ) ;
592
- return function $parseAssignment ( scope , locals ) {
604
+ return extend ( function $parseAssignment ( scope , locals ) {
593
605
return left . assign ( scope , right ( scope , locals ) , locals ) ;
594
- } ;
606
+ } , {
607
+ inputs : [ left , right ]
608
+ } ) ;
595
609
}
596
610
return left ;
597
611
} ,
@@ -760,7 +774,6 @@ Parser.prototype = {
760
774
// This is used with json array declaration
761
775
arrayDeclaration : function ( ) {
762
776
var elementFns = [ ] ;
763
- var allConstant = true ;
764
777
if ( this . peekToken ( ) . text !== ']' ) {
765
778
do {
766
779
if ( this . peek ( ']' ) ) {
@@ -769,9 +782,6 @@ Parser.prototype = {
769
782
}
770
783
var elementFn = this . expression ( ) ;
771
784
elementFns . push ( elementFn ) ;
772
- if ( ! elementFn . constant ) {
773
- allConstant = false ;
774
- }
775
785
} while ( this . expect ( ',' ) ) ;
776
786
}
777
787
this . consume ( ']' ) ;
@@ -784,13 +794,13 @@ Parser.prototype = {
784
794
return array ;
785
795
} , {
786
796
literal : true ,
787
- constant : allConstant
797
+ constant : elementFns . every ( isConstant ) ,
798
+ inputs : elementFns
788
799
} ) ;
789
800
} ,
790
801
791
802
object : function ( ) {
792
803
var keys = [ ] , values = [ ] ;
793
- var allConstant = true ;
794
804
if ( this . peekToken ( ) . text !== '}' ) {
795
805
do {
796
806
if ( this . peek ( '}' ) ) {
@@ -802,9 +812,6 @@ Parser.prototype = {
802
812
this . consume ( ':' ) ;
803
813
var value = this . expression ( ) ;
804
814
values . push ( value ) ;
805
- if ( ! value . constant ) {
806
- allConstant = false ;
807
- }
808
815
} while ( this . expect ( ',' ) ) ;
809
816
}
810
817
this . consume ( '}' ) ;
@@ -817,7 +824,8 @@ Parser.prototype = {
817
824
return object ;
818
825
} , {
819
826
literal : true ,
820
- constant : allConstant
827
+ constant : values . every ( isConstant ) ,
828
+ inputs : values
821
829
} ) ;
822
830
}
823
831
} ;
@@ -1045,6 +1053,9 @@ function $ParseProvider() {
1045
1053
parsedExpression . $$watchDelegate = parsedExpression . literal ?
1046
1054
oneTimeLiteralWatchDelegate : oneTimeWatchDelegate ;
1047
1055
}
1056
+ else if ( parsedExpression . inputs ) {
1057
+ parsedExpression . $$watchDelegate = inputsWatchDelegate ;
1058
+ }
1048
1059
1049
1060
cache [ cacheKey ] = parsedExpression ;
1050
1061
}
@@ -1058,6 +1069,87 @@ function $ParseProvider() {
1058
1069
}
1059
1070
} ;
1060
1071
1072
+ function collectExpressionInputs ( inputs , list ) {
1073
+ for ( var i = 0 , ii = inputs . length ; i < ii ; i ++ ) {
1074
+ var input = inputs [ i ] ;
1075
+ if ( ! input . constant ) {
1076
+ if ( input . inputs ) {
1077
+ collectExpressionInputs ( input . inputs , list ) ;
1078
+ }
1079
+ else if ( - 1 === list . indexOf ( input ) ) {
1080
+ list . push ( input ) ;
1081
+ }
1082
+ }
1083
+ }
1084
+
1085
+ return list ;
1086
+ }
1087
+
1088
+ function simpleEquals ( o1 , o2 ) {
1089
+ if ( o1 == null || o2 == null ) return o1 === o2 ; // null/undefined
1090
+
1091
+ if ( typeof o1 === "object" ) {
1092
+ //The same object is not supported because it may have been mutated
1093
+ if ( o1 === o2 ) return false ;
1094
+
1095
+ if ( typeof o2 !== "object" ) return false ;
1096
+
1097
+ //Dates
1098
+ if ( isDate ( o1 ) && isDate ( o2 ) ) {
1099
+ o1 = o1 . getTime ( ) ;
1100
+ o2 = o2 . getTime ( ) ;
1101
+
1102
+ //Fallthru to the primitive equality check
1103
+ }
1104
+
1105
+ //Otherwise objects are not supported - recursing over arrays/object would be too expensive
1106
+ else {
1107
+ return false ;
1108
+ }
1109
+ }
1110
+
1111
+ //Primitive or NaN
1112
+ return o1 === o2 || ( o1 !== o1 && o2 !== o2 ) ;
1113
+ }
1114
+
1115
+ function inputsWatchDelegate ( scope , listener , objectEquality , parsedExpression ) {
1116
+ var inputExpressions = parsedExpression . $$inputs ||
1117
+ ( parsedExpression . $$inputs = collectExpressionInputs ( parsedExpression . inputs , [ ] ) ) ;
1118
+
1119
+ var inputs = [ simpleEquals /*=something that will never equal an evaluated input*/ ] ;
1120
+ var lastResult ;
1121
+
1122
+ if ( 1 === inputExpressions . length ) {
1123
+ inputs = inputs [ 0 ] ;
1124
+ inputExpressions = inputExpressions [ 0 ] ;
1125
+ return scope . $watch ( function expressionInputWatch ( scope ) {
1126
+ var newVal = inputExpressions ( scope ) ;
1127
+ if ( ! simpleEquals ( newVal , inputs ) ) {
1128
+ lastResult = parsedExpression ( scope ) ;
1129
+ inputs = newVal ;
1130
+ }
1131
+ return lastResult ;
1132
+ } , listener , objectEquality ) ;
1133
+ }
1134
+
1135
+ return scope . $watch ( function expressionInputsWatch ( scope ) {
1136
+ var changed = false ;
1137
+
1138
+ for ( var i = 0 , ii = inputExpressions . length ; i < ii ; i ++ ) {
1139
+ var valI = inputExpressions [ i ] ( scope ) ;
1140
+ if ( changed || ( changed = ! simpleEquals ( valI , inputs [ i ] ) ) ) {
1141
+ inputs [ i ] = valI ;
1142
+ }
1143
+ }
1144
+
1145
+ if ( changed ) {
1146
+ lastResult = parsedExpression ( scope ) ;
1147
+ }
1148
+
1149
+ return lastResult ;
1150
+ } , listener , objectEquality ) ;
1151
+ }
1152
+
1061
1153
function oneTimeWatchDelegate ( scope , listener , objectEquality , parsedExpression ) {
1062
1154
var unwatch , lastValue ;
1063
1155
return unwatch = scope . $watch ( function oneTimeWatch ( scope ) {
@@ -1123,7 +1215,14 @@ function $ParseProvider() {
1123
1215
// initial value is defined (for bind-once)
1124
1216
return isDefined ( value ) ? result : value ;
1125
1217
} ;
1126
- fn . $$watchDelegate = parsedExpression . $$watchDelegate ;
1218
+
1219
+ if ( parsedExpression . $$watchDelegate ) {
1220
+ //Only transfer the inputsWatchDelegate for interceptors not marked as having externalInput
1221
+ if ( ! ( parsedExpression . $$watchDelegate === inputsWatchDelegate && interceptorFn . externalInput ) ) {
1222
+ fn . inputs = parsedExpression . inputs ;
1223
+ fn . $$watchDelegate = parsedExpression . $$watchDelegate ;
1224
+ }
1225
+ }
1127
1226
return fn ;
1128
1227
}
1129
1228
} ] ;
0 commit comments