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