1- export function sortIndexFactory ( model ) {
1+ import { bend , copy } from '../node/node.service' ;
2+ import { preOrderDFS } from '../node/node.service' ;
3+
4+ export { sortIndexFactory , merge } ;
5+
6+ function sortIndexFactory ( model ) {
27 const templateIndex = model . columnList ( ) . columns . map ( c => c . key ) ;
38
49 return ( columns , scores ) => {
510 const { length } = columns ;
611 scores = Object . assign ( {
7- list : column => column . class === 'data' ? 0.1 : 0.3 ,
12+ list : column => ( column . class === 'data' || column . class === 'cohort' ) ? 0.1 : 0.3 ,
813 index : ( ) => 0.2 ,
9- view : column => length + ( column . class !== 'data' ? 0.1 : 0.3 ) ,
14+ view : column => length + ( ( column . class !== 'data' && column . class !== 'cohort' ) ? 0.1 : 0.3 ) ,
1015 template : ( ) => length + 0.4
1116 } , scores ) ;
1217
@@ -66,13 +71,12 @@ function compareFactory(scoreFor, templateIndex, viewIndex) {
6671}
6772
6873function findFactory ( index ) {
69- const map =
70- index . reduce ( ( memo , key , i ) => {
71- memo . set ( key , i ) ;
72- return memo ;
73- } , new Map ( ) ) ;
74+ const map = index . reduce ( ( memo , key , i ) => {
75+ memo . set ( key , i ) ;
76+ return memo ;
77+ } , new Map ( ) ) ;
7478
75- return key => map . has ( key ) ? map . get ( key ) : - 1 ;
79+ return key => ( map . has ( key ) ? map . get ( key ) : - 1 ) ;
7680}
7781
7882function equals ( xs , ys ) {
@@ -86,5 +90,143 @@ function equals(xs, ys) {
8690 return false ;
8791 }
8892 }
93+
8994 return true ;
90- }
95+ }
96+
97+ function merge ( newTree , oldTree , buildIndex ) {
98+ const current = running ( newTree , buildIndex ) ;
99+ const screen = former ( oldTree , current ) ;
100+ const insertNear = insertFactory ( current , screen ) ;
101+ const insertCohort = insertCohortFactory ( current , screen ) ;
102+
103+ const root = current . line [ 0 ] ;
104+ if ( ! screen . set . has ( root . key . model . key ) ) {
105+ screen . line . unshift ( copy ( root ) ) ;
106+ screen . line . forEach ( n => n . level ++ ) ;
107+ }
108+
109+ for ( let i = 1 , length = current . line . length ; i < length ; i ++ ) {
110+ const node = current . line [ i ] ;
111+ const { model } = node . key ;
112+ if ( screen . set . has ( model . key ) ) {
113+ continue ;
114+ }
115+
116+ const prevNode = current . line [ i - 1 ] ;
117+ if ( model . type === 'cohort' ) {
118+ insertCohort ( prevNode , node ) ;
119+ } else {
120+ insertNear ( prevNode , node , i ) ;
121+ }
122+ }
123+
124+ return bend ( screen . line ) ;
125+ }
126+
127+ function running ( tree , buildIndex ) {
128+ const result = {
129+ line : [ ] ,
130+ map : new Map ( )
131+ } ;
132+
133+ preOrderDFS ( [ tree ] , node => {
134+ result . line . push ( node ) ;
135+ result . map . set ( node . key . model . key , node . key ) ;
136+
137+ // As we use pre order direction we can manipulate with children without affecting on algorithm.
138+ // Below we sort columns in appropriate order.
139+ const columns = node . children . map ( child => child . key . model ) ;
140+ const index = buildIndex ( columns ) ;
141+
142+ let cursor = 0 ;
143+ const indexMap = index . reduce ( ( memo , key ) => {
144+ memo [ key ] = cursor ++ ;
145+ return memo ;
146+ } , { } ) ;
147+
148+ node . children . sort ( ( x , y ) => indexMap [ x . key . model . key ] - indexMap [ y . key . model . key ] ) ;
149+ } ) ;
150+
151+ return result ;
152+ }
153+
154+ function former ( tree , current ) {
155+ const result = {
156+ line : [ ] ,
157+ set : new Set ( )
158+ } ;
159+
160+ preOrderDFS ( [ tree ] , node => {
161+ // Filter out nodes if they were deleted from newTree.
162+ const { key } = node . key . model ;
163+ const view = current . map . get ( key ) ;
164+ if ( view ) {
165+ const newNode = copy ( node ) ;
166+ newNode . key = view ;
167+ result . line . push ( newNode ) ;
168+ result . set . add ( key ) ;
169+ }
170+ } ) ;
171+
172+ return result ;
173+ }
174+
175+ function insertFactory ( current , screen ) {
176+ const { line } = screen ;
177+ return ( prevNode , node , i ) => {
178+ let pos = line . findIndex ( n => n . key . model . key === prevNode . key . model . key ) ;
179+
180+ const target = copy ( node ) ;
181+ target . level = node . level ;
182+
183+ if ( everyNextIsNew ( current , screen , i ) ) {
184+ line . push ( target ) ;
185+ } else {
186+ line . splice ( pos + 1 , 0 , target ) ;
187+ }
188+ } ;
189+ }
190+
191+ function insertCohortFactory ( current , screen ) {
192+ const insertNear = insertFactory ( current , screen ) ;
193+ const { line } = screen ;
194+ return ( prevNode , node ) => {
195+ const set = new Set ( node . children . map ( n => n . key . model . key ) ) ;
196+ const index = line . findIndex ( n => set . has ( n . key . model . key ) ) ;
197+
198+ if ( index < 0 ) {
199+ insertNear ( prevNode , node ) ;
200+ return ;
201+ }
202+
203+ const target = copy ( node ) ;
204+ const { level } = line [ index ] ;
205+ target . level = level ;
206+ line . splice ( index , 0 , target ) ;
207+
208+ for ( let i = index + 1 , end = line . length ; i < end ; i ++ ) {
209+ const child = line [ i ] ;
210+ if ( child . level !== level ) {
211+ break ;
212+ }
213+
214+ if ( set . has ( child . key . model . key ) ) {
215+ child . level = level + 1 ;
216+ }
217+ }
218+ } ;
219+ }
220+
221+ function everyNextIsNew ( current , screen , index ) {
222+ const { line } = current ;
223+
224+ let n ;
225+ while ( ( n = line [ ++ index ] ) ) {
226+ if ( screen . set . has ( n . key . model . key ) ) {
227+ return false ;
228+ }
229+ }
230+
231+ return true ;
232+ }
0 commit comments