@@ -12,77 +12,96 @@ import { animationsLog as traceLog } from "../trace";
12
12
13
13
import { createSelector , SelectorCore } from "tns-core-modules/ui/styling/css-selector" ;
14
14
15
- export class NativeScriptAnimationDriver implements AnimationDriver {
16
- matchesElement ( _element : any , _selector : string ) : boolean {
17
- // this method is never called since NG 4.2.5
18
- throw new Error ( "Method not implemented." ) ;
19
- }
15
+ interface ViewMatchResult {
16
+ found : boolean ;
17
+ }
20
18
21
- containsElement ( elm1 : NgView , elm2 : NgView ) : boolean {
22
- traceLog (
23
- `NativeScriptAnimationDriver.containsElement ` +
24
- `element1: ${ elm1 } , element2: ${ elm2 } `
25
- ) ;
19
+ interface ViewMatchParams {
20
+ originalView : NgView ;
21
+ }
26
22
27
- let found = false ;
28
- eachDescendant ( elm1 , child => {
29
- if ( child === elm2 ) {
30
- found = true ;
31
- }
23
+ interface QueryParams {
24
+ selector : Selector ;
25
+ multi : boolean ;
26
+ }
27
+
28
+ interface QueryResult {
29
+ matches : NgView [ ] ;
30
+ }
32
31
33
- return ! found ;
34
- } ) ;
32
+ class Selector {
33
+ private nsSelectors : SelectorCore [ ] ;
34
+ private classSelectors : string [ ] ;
35
35
36
- return found ;
36
+ constructor ( rawSelector : string ) {
37
+ this . parse ( rawSelector ) ;
37
38
}
38
39
39
- query ( element : NgView , selector : string , multi : boolean ) : NgView [ ] {
40
- traceLog (
41
- `NativeScriptAnimationDriver.query ` +
42
- `element: ${ element } , selector: ${ selector } ` +
43
- `multi: ${ multi } `
44
- ) ;
40
+ match ( element : NgView ) : boolean {
41
+ return this . nsSelectorMatch ( element ) || this . classSelectorsMatch ( element ) ;
42
+ }
45
43
46
- const selectors = selector . split ( "," ) . map ( s => s . trim ( ) ) ;
44
+ private parse ( rawSelector : string ) {
45
+ const selectors = rawSelector . split ( "," ) . map ( s => s . trim ( ) ) ;
47
46
48
- const nsSelectors : SelectorCore [ ] = selectors . map ( createSelector ) ;
49
- const classSelectors = selectors
47
+ this . nsSelectors = selectors . map ( createSelector ) ;
48
+ this . classSelectors = selectors
50
49
. filter ( s => s . startsWith ( "." ) )
51
50
. map ( s => s . substring ( 1 ) ) ;
51
+ }
52
52
53
- return this . visitDescendants ( element , nsSelectors , classSelectors , multi ) ;
53
+ private nsSelectorMatch ( element : NgView ) {
54
+ return this . nsSelectors . some ( s => s . match ( element ) ) ;
54
55
}
55
56
56
- private visitDescendants (
57
- element : NgView ,
58
- nsSelectors : SelectorCore [ ] ,
59
- classSelectors : string [ ] ,
60
- multi : boolean ) : NgView [ ] {
57
+ private classSelectorsMatch ( element : NgView ) {
58
+ return this . classSelectors . some ( s => this . hasClass ( element , s ) ) ;
59
+ }
61
60
62
- let results = [ ] ;
63
- eachDescendant ( element , child => {
64
- if ( child instanceof InvisibleNode ) {
65
- return true ;
66
- }
61
+ // we're using that instead of match for classes
62
+ // that are dynamically added by the animation engine
63
+ // such as .ng-trigger, that's added for every :enter view
64
+ private hasClass ( element : NgView , cls : string ) {
65
+ return element && element [ "$$classes" ] && element [ "$$classes" ] [ cls ] ;
66
+ }
67
+ }
67
68
68
- if ( nsSelectors . some ( s => s . match ( child ) ) ||
69
- classSelectors . some ( s => this . hasClass ( child , s ) ) ) {
69
+ export class NativeScriptAnimationDriver implements AnimationDriver {
70
+ matchesElement ( element : NgView , rawSelector : string ) : boolean {
71
+ traceLog (
72
+ `NativeScriptAnimationDriver.matchesElement ` +
73
+ `element: ${ element } , selector: ${ rawSelector } `
74
+ ) ;
70
75
71
- results . push ( child ) ;
72
- return multi ;
73
- }
76
+ const selector = this . makeSelector ( rawSelector ) ;
77
+ return selector . match ( element ) ;
78
+ }
74
79
75
- return true ;
76
- } ) ;
77
80
78
- return results ;
81
+ containsElement ( elm1 : NgView , elm2 : NgView ) : boolean {
82
+ traceLog (
83
+ `NativeScriptAnimationDriver.containsElement ` +
84
+ `element1: ${ elm1 } , element2: ${ elm2 } `
85
+ ) ;
86
+
87
+ const params : ViewMatchParams = { originalView : elm2 } ;
88
+ const result : ViewMatchResult = this . visitDescendants ( elm1 , viewMatches , params ) ;
89
+
90
+ return result . found ;
79
91
}
80
92
81
- // we're using that instead of match for classes
82
- // that are dynamically added by the animation engine
83
- // such as .ng-trigger, that's added for every :enter view
84
- private hasClass ( element : any , cls : string ) {
85
- return element [ "$$classes" ] [ cls ] ;
93
+ query ( element : NgView , rawSelector : string , multi : boolean ) : NgView [ ] {
94
+ traceLog (
95
+ `NativeScriptAnimationDriver.query ` +
96
+ `element: ${ element } , selector: ${ rawSelector } ` +
97
+ `multi: ${ multi } `
98
+ ) ;
99
+
100
+ const selector = this . makeSelector ( rawSelector ) ;
101
+ const params : QueryParams = { selector, multi } ;
102
+ const result : QueryResult = this . visitDescendants ( element , queryDescendants , params ) ;
103
+
104
+ return result . matches || [ ] ;
86
105
}
87
106
88
107
computeStyle ( element : NgView , prop : string ) : string {
@@ -112,4 +131,60 @@ export class NativeScriptAnimationDriver implements AnimationDriver {
112
131
return new NativeScriptAnimationPlayer (
113
132
element , keyframes , duration , delay , easing ) ;
114
133
}
134
+
135
+ private makeSelector ( rawSelector : string ) : Selector {
136
+ return new Selector ( rawSelector ) ;
137
+ }
138
+
139
+ private visitDescendants (
140
+ element : NgView ,
141
+ cb : ( child : NgView , result : any , params : any ) => boolean ,
142
+ cbParams : any ) : any {
143
+
144
+ const result = { } ;
145
+ // fill the result obj with the result from the callback function
146
+ eachDescendant ( element , ( child : NgView ) => cb ( child , result , cbParams ) ) ;
147
+
148
+ return result ;
149
+ }
150
+ }
151
+
152
+ function viewMatches (
153
+ element : NgView ,
154
+ result : ViewMatchResult ,
155
+ params : ViewMatchParams
156
+ ) : boolean {
157
+
158
+ if ( element === params . originalView ) {
159
+ result . found = true ;
160
+ }
161
+
162
+ return ! result . found ;
163
+ }
164
+
165
+ function queryDescendants (
166
+ element : NgView ,
167
+ result : QueryResult ,
168
+ params : QueryParams
169
+ ) : boolean {
170
+
171
+ if ( ! result . matches ) {
172
+ result . matches = [ ] ;
173
+ }
174
+
175
+ const { selector, multi } = params ;
176
+
177
+ // skip comment and text nodes
178
+ // because they are not actual Views
179
+ // and cannot be animated
180
+ if ( element instanceof InvisibleNode ) {
181
+ return true ;
182
+ }
183
+
184
+ if ( selector . match ( element ) ) {
185
+ result . matches . push ( element ) ;
186
+ return multi ;
187
+ }
188
+
189
+ return true ;
115
190
}
0 commit comments