1- export default function Adapter ( $rootScope , $parse , $attr , viewport , buffer , adjustBuffer , element ) {
2- const viewportScope = viewport . scope ( ) || $rootScope ;
3- let disabled = false ;
4- let self = this ;
5-
6- createValueInjector ( 'adapter' ) ( self ) ;
7- let topVisibleInjector = createValueInjector ( 'topVisible' ) ;
8- let topVisibleElementInjector = createValueInjector ( 'topVisibleElement' ) ;
9- let topVisibleScopeInjector = createValueInjector ( 'topVisibleScope' ) ;
10- let isLoadingInjector = createValueInjector ( 'isLoading' ) ;
11-
12- // Adapter API definition
13-
14- Object . defineProperty ( this , 'disabled' , {
15- get : ( ) => disabled ,
16- set : ( value ) => ( ! ( disabled = value ) ) ? adjustBuffer ( ) : null
17- } ) ;
18-
19- this . isLoading = false ;
20- this . isBOF = ( ) => buffer . bof ;
21- this . isEOF = ( ) => buffer . eof ;
22- this . isEmpty = ( ) => ! buffer . length ;
23-
24- this . applyUpdates = ( arg1 , arg2 ) => {
1+ function findCtrl ( scope , ctrl ) {
2+ if ( ! scope ) {
3+ return ;
4+ }
5+ if ( scope . hasOwnProperty ( ctrl ) && Object . getPrototypeOf ( scope [ ctrl ] ) . constructor . hasOwnProperty ( '$inject' ) ) {
6+ return scope [ ctrl ] ;
7+ }
8+ return findCtrl ( scope . $parent , ctrl ) ;
9+ }
10+
11+ function assignAttr ( attr , scope , element ) {
12+ if ( ! attr || ! ( attr = attr . replace ( / ^ \s + | \s + $ / gm, '' ) ) ) {
13+ return ;
14+ }
15+
16+ let onSyntax = attr . match ( / ^ ( .+ ) ( \s + o n \s + ) ( .+ ) ? / ) ;
17+ let asSyntax = attr . match ( / ^ ( [ ^ . ] + ) \. ( .+ ) ? / ) ;
18+
19+ if ( onSyntax && onSyntax . length === 4 ) { // controller on (backward compatibility), deprecated since v1.6.1
20+ window . console . warn ( 'Angular ui-scroll adapter assignment warning. "Controller On" syntax has been deprecated since ui-scroll v1.6.1.' ) ;
21+ let ctrl = onSyntax [ 3 ] ;
22+ let tail = onSyntax [ 1 ] ;
23+ let candidate = element ;
24+ while ( candidate . length ) {
25+ let candidateScope = candidate . scope ( ) ; // doesn't work when debugInfoEnabled flag = true
26+ let candidateName = ( candidate . attr ( 'ng-controller' ) || '' ) . match ( / ( \w (?: \w | \d ) * ) (?: \s + a s \s + ( \w (?: \w | \d ) * ) ) ? / ) ;
27+ if ( candidateName && candidateName [ 1 ] === ctrl ) {
28+ return {
29+ target : candidateScope ,
30+ source : tail
31+ } ;
32+ }
33+ candidate = candidate . parent ( ) ;
34+ }
35+ throw new Error ( 'Angular ui-scroll adapter assignment error. Failed to locate target controller "' + ctrl + '" to inject "' + tail + '"' ) ;
36+ }
37+ else if ( asSyntax && asSyntax . length === 3 ) { // controller as
38+ let ctrl = asSyntax [ 1 ] ;
39+ let tail = asSyntax [ 2 ] ;
40+ let foundCtrl = findCtrl ( scope , ctrl ) ;
41+ if ( foundCtrl ) {
42+ return {
43+ target : foundCtrl ,
44+ source : tail
45+ } ;
46+ }
47+ }
48+
49+ return {
50+ target : scope ,
51+ source : attr
52+ } ;
53+ }
54+
55+ class Adapter {
56+
57+ constructor ( viewport , buffer , adjustBuffer , reload , $attr , $parse , element ) {
58+ this . viewport = viewport ;
59+ this . buffer = buffer ;
60+ this . adjustBuffer = adjustBuffer ;
61+ this . reload = reload ;
62+
63+ this . publicContext = { } ;
64+ this . assignAdapter ( $attr , $parse , element ) ;
65+ this . generatePublicContext ( $attr , $parse , element ) ;
66+
67+ this . isLoading = false ;
68+ this . disabled = false ;
69+ }
70+
71+ assignAdapter ( $attr , $parse , element ) {
72+ let data = assignAttr ( $attr . adapter , this . viewport . getScope ( ) , element ) ;
73+
74+ if ( data ) {
75+ try {
76+ $parse ( data . source ) . assign ( data . target , { } ) ;
77+ let adapterOnScope = $parse ( data . source ) ( data . target ) ;
78+
79+ angular . extend ( adapterOnScope , this . publicContext ) ;
80+ this . publicContext = adapterOnScope ;
81+ }
82+ catch ( error ) {
83+ error . message = `Angular ui-scroll Adapter assignment exception.\n` +
84+ `Can't parse "${ $attr . adapter } " expression.\n` +
85+ error . message ;
86+ throw error ;
87+ }
88+ }
89+ }
90+
91+ generatePublicContext ( $attr , $parse , element ) {
92+ // these methods will be accessible out of ui-scroll via user defined adapter
93+ const publicMethods = [ 'reload' , 'applyUpdates' , 'append' , 'prepend' , 'isBOF' , 'isEOF' , 'isEmpty' ] ;
94+ for ( let i = publicMethods . length - 1 ; i >= 0 ; i -- ) {
95+ this . publicContext [ publicMethods [ i ] ] = this [ publicMethods [ i ] ] . bind ( this ) ;
96+ }
97+
98+ // these read-only props will be accessible out of ui-scroll via user defined adapter
99+ const publicProps = [ 'isLoading' , 'topVisible' , 'topVisibleElement' , 'topVisibleScope' ] ;
100+ for ( let i = publicProps . length - 1 ; i >= 0 ; i -- ) {
101+ let property , assignProp ;
102+ let data = assignAttr ( $attr [ publicProps [ i ] ] , this . viewport . getScope ( ) , element ) ;
103+ if ( data ) {
104+ assignProp = $parse ( data . source ) . assign ;
105+ }
106+ Object . defineProperty ( this , publicProps [ i ] , {
107+ get : ( ) => property ,
108+ set : ( value ) => {
109+ property = value ;
110+ if ( assignProp ) {
111+ assignProp ( data . target , value ) ;
112+ }
113+ this . publicContext [ publicProps [ i ] ] = value ;
114+ }
115+ } ) ;
116+ }
117+
118+ // non-read-only public property
119+ Object . defineProperty ( this . publicContext , 'disabled' , {
120+ get : ( ) => this . disabled ,
121+ set : ( value ) => ( ! ( this . disabled = value ) ) ? this . adjustBuffer ( ) : null
122+ } ) ;
123+ }
124+
125+ loading ( value ) {
126+ this [ 'isLoading' ] = value ;
127+ }
128+
129+ isBOF ( ) {
130+ return this . buffer . bof ;
131+ }
132+
133+ isEOF ( ) {
134+ return this . buffer . eof ;
135+ }
136+
137+ isEmpty ( ) {
138+ return ! this . buffer . length ;
139+ }
140+
141+ applyUpdates ( arg1 , arg2 ) {
25142 if ( angular . isFunction ( arg1 ) ) {
26143 // arg1 is the updater function, arg2 is ignored
27- buffer . slice ( 0 ) . forEach ( ( wrapper ) => {
144+ this . buffer . slice ( 0 ) . forEach ( ( wrapper ) => {
28145 // we need to do it on the buffer clone, because buffer content
29146 // may change as we iterate through
30- applyUpdate ( wrapper , arg1 ( wrapper . item , wrapper . scope , wrapper . element ) ) ;
147+ this . applyUpdate ( wrapper , arg1 ( wrapper . item , wrapper . scope , wrapper . element ) ) ;
31148 } ) ;
32149 } else {
33150 // arg1 is item index, arg2 is the newItems array
34151 if ( arg1 % 1 !== 0 ) { // checking if it is an integer
35152 throw new Error ( 'applyUpdates - ' + arg1 + ' is not a valid index' ) ;
36153 }
37154
38- const index = arg1 - buffer . first ;
39- if ( ( index >= 0 && index < buffer . length ) ) {
40- applyUpdate ( buffer [ index ] , arg2 ) ;
155+ const index = arg1 - this . buffer . first ;
156+ if ( ( index >= 0 && index < this . buffer . length ) ) {
157+ this . applyUpdate ( this . buffer [ index ] , arg2 ) ;
41158 }
42159 }
43160
44- adjustBuffer ( ) ;
45- } ;
46-
47- this . append = ( newItems ) => {
48- buffer . append ( newItems ) ;
49- adjustBuffer ( ) ;
50- } ;
161+ this . adjustBuffer ( ) ;
162+ }
51163
52- this . prepend = ( newItems ) => {
53- buffer . prepend ( newItems ) ;
54- adjustBuffer ( ) ;
55- } ;
164+ append ( newItems ) {
165+ this . buffer . append ( newItems ) ;
166+ this . adjustBuffer ( ) ;
167+ }
56168
57- this . loading = ( value ) => {
58- isLoadingInjector ( value ) ;
59- } ;
169+ prepend ( newItems ) {
170+ this . buffer . prepend ( newItems ) ;
171+ this . adjustBuffer ( ) ;
172+ }
60173
61- this . calculateProperties = ( ) => {
174+ calculateProperties ( ) {
62175 let item , itemHeight , itemTop , isNewRow , rowTop = null ;
63176 let topHeight = 0 ;
64- for ( let i = 0 ; i < buffer . length ; i ++ ) {
65- item = buffer [ i ] ;
177+ for ( let i = 0 ; i < this . buffer . length ; i ++ ) {
178+ item = this . buffer [ i ] ;
66179 itemTop = item . element . offset ( ) . top ;
67180 isNewRow = rowTop !== itemTop ;
68181 rowTop = itemTop ;
69182 if ( isNewRow ) {
70183 itemHeight = item . element . outerHeight ( true ) ;
71184 }
72- if ( isNewRow && ( viewport . topDataPos ( ) + topHeight + itemHeight <= viewport . topVisiblePos ( ) ) ) {
185+ if ( isNewRow && ( this . viewport . topDataPos ( ) + topHeight + itemHeight <= this . viewport . topVisiblePos ( ) ) ) {
73186 topHeight += itemHeight ;
74187 } else {
75188 if ( isNewRow ) {
76- topVisibleInjector ( item . item ) ;
77- topVisibleElementInjector ( item . element ) ;
78- topVisibleScopeInjector ( item . scope ) ;
189+ this [ 'topVisible' ] = item . item ;
190+ this [ 'topVisibleElement' ] = item . element ;
191+ this [ 'topVisibleScope' ] = item . scope ;
79192 }
80193 break ;
81194 }
82195 }
83- } ;
84-
85- // private function definitions
86-
87- function createValueInjector ( attribute ) {
88- let expression = $attr [ attribute ] ;
89- let scope = viewportScope ;
90- let assign ;
91- if ( expression ) {
92- // it is ok to have relaxed validation for the first part of the 'on' expression.
93- // additional validation will be done by the $parse service below
94- let match = expression . match ( / ^ ( \S + ) (?: \s + o n \s + ( \w (?: \w | \d ) * ) ) ? / ) ;
95- if ( ! match )
96- throw new Error ( 'Expected injection expression in form of \'target\' or \'target on controller\' but got \'' + expression + '\'' ) ;
97- let target = match [ 1 ] ;
98- let onControllerName = match [ 2 ] ;
99-
100- let parseController = ( controllerName , on ) => {
101- let candidate = element ;
102- while ( candidate . length ) {
103- let candidateScope = candidate . scope ( ) ;
104- // ng-controller's "Controller As" parsing
105- let candidateName = ( candidate . attr ( 'ng-controller' ) || '' ) . match ( / ( \w (?: \w | \d ) * ) (?: \s + a s \s + ( \w (?: \w | \d ) * ) ) ? / ) ;
106- if ( candidateName && candidateName [ on ? 1 : 2 ] === controllerName ) {
107- scope = candidateScope ;
108- return true ;
109- }
110- // directive's/component's "Controller As" parsing
111- if ( ! on && candidateScope && candidateScope . hasOwnProperty ( controllerName ) && Object . getPrototypeOf ( candidateScope [ controllerName ] ) . constructor . hasOwnProperty ( '$inject' ) ) {
112- scope = candidateScope ;
113- return true ;
114- }
115- candidate = candidate . parent ( ) ;
116- }
117- } ;
118-
119- if ( onControllerName ) { // 'on' syntax DOM parsing (adapter="adapter on ctrl")
120- scope = null ;
121- parseController ( onControllerName , true ) ;
122- if ( ! scope ) {
123- throw new Error ( 'Failed to locate target controller \'' + onControllerName + '\' to inject \'' + target + '\'' ) ;
124- }
125- }
126- else { // try to parse DOM with 'Controller As' syntax (adapter="ctrl.adapter")
127- let controllerAsName ;
128- let dotIndex = target . indexOf ( '.' ) ;
129- if ( dotIndex > 0 ) {
130- controllerAsName = target . substr ( 0 , dotIndex ) ;
131- parseController ( controllerAsName , false ) ;
132- }
133- }
134-
135- assign = $parse ( target ) . assign ;
136- }
137- return ( value ) => {
138- if ( self !== value ) // just to avoid injecting adapter reference in the adapter itself. Kludgy, I know.
139- self [ attribute ] = value ;
140- if ( assign )
141- assign ( scope , value ) ;
142- } ;
143196 }
144197
145- function applyUpdate ( wrapper , newItems ) {
198+ applyUpdate ( wrapper , newItems ) {
146199 if ( ! angular . isArray ( newItems ) ) {
147200 return ;
148201 }
149202
150203 let keepIt ;
151- let pos = ( buffer . indexOf ( wrapper ) ) + 1 ;
204+ let pos = ( this . buffer . indexOf ( wrapper ) ) + 1 ;
152205
153206 newItems . reverse ( ) . forEach ( ( newItem ) => {
154207 if ( newItem === wrapper . item ) {
155208 keepIt = true ;
156209 pos -- ;
157210 } else {
158- buffer . insert ( pos , newItem ) ;
211+ this . buffer . insert ( pos , newItem ) ;
159212 }
160213 } ) ;
161214
@@ -164,4 +217,6 @@ export default function Adapter($rootScope, $parse, $attr, viewport, buffer, adj
164217 }
165218 }
166219
167- }
220+ }
221+
222+ export default Adapter ;
0 commit comments