@@ -13,6 +13,9 @@ import contain from 'licia/contain'
13
13
import dateFormat from 'licia/dateFormat'
14
14
import toNum from 'licia/toNum'
15
15
import omit from 'licia/omit'
16
+ import ResizeSensor from 'licia/ResizeSensor'
17
+ import debounce from 'licia/debounce'
18
+ import LunaVirtualList from 'luna-virtual-list'
16
19
import { exportCjs } from '../share/util'
17
20
18
21
/** IOptions */
@@ -57,8 +60,6 @@ interface IInnerEntry extends IBaseEntry {
57
60
container : HTMLElement
58
61
}
59
62
60
- const MIN_APPEND_INTERVAL = 100
61
-
62
63
/**
63
64
* Android logcat viewer.
64
65
*
@@ -75,23 +76,31 @@ const MIN_APPEND_INTERVAL = 100
75
76
* })
76
77
*/
77
78
export default class Logcat extends Component < IOptions > {
78
- private isAtBottom = true
79
79
private render : types . AnyFn
80
80
private entries : Array < IInnerEntry > = [ ]
81
81
private displayEntries : Array < IInnerEntry > = [ ]
82
- private appendTimer : NodeJS . Timeout | null = null
83
82
private removeThreshold = 1
84
- private frag : DocumentFragment = document . createDocumentFragment ( )
83
+ private virtualList : LunaVirtualList
84
+ private resizeSensor : ResizeSensor
85
85
constructor ( container : HTMLElement , options : IOptions = { } ) {
86
86
super ( container , { compName : 'logcat' } , options )
87
87
88
88
this . initOptions ( options , {
89
- maxNum : 5000 ,
89
+ maxNum : 10000 ,
90
90
view : 'standard' ,
91
91
entries : [ ] ,
92
92
wrapLongLines : false ,
93
93
} )
94
94
95
+ this . resizeSensor = new ResizeSensor ( container )
96
+
97
+ this . initTpl ( )
98
+ this . virtualList = new LunaVirtualList (
99
+ this . find ( '.virtual-list' ) . get ( 0 ) as HTMLElement ,
100
+ { autoScroll : true }
101
+ )
102
+ this . addSubComponent ( this . virtualList )
103
+
95
104
const maxNum = this . options . maxNum
96
105
if ( maxNum !== 0 && maxNum > 500 ) {
97
106
this . removeThreshold = Math . round ( maxNum / 10 )
@@ -111,7 +120,7 @@ export default class Logcat extends Component<IOptions> {
111
120
this . bindEvent ( )
112
121
}
113
122
destroy ( ) {
114
- this . $container . off ( 'scroll' , this . onScroll )
123
+ this . resizeSensor . destroy ( )
115
124
super . destroy ( )
116
125
}
117
126
/** Append entry. */
@@ -140,7 +149,7 @@ export default class Logcat extends Component<IOptions> {
140
149
if ( entry ) {
141
150
if ( displayEntries [ 0 ] === entry ) {
142
151
displayEntries . shift ( )
143
- $ ( entry . container ) . remove ( )
152
+ this . virtualList . remove ( entry . container )
144
153
}
145
154
}
146
155
}
@@ -151,30 +160,17 @@ export default class Logcat extends Component<IOptions> {
151
160
152
161
if ( this . filterEntry ( e ) ) {
153
162
this . displayEntries . push ( e )
154
- this . frag . appendChild ( container )
155
- if ( ! this . appendTimer ) {
156
- this . appendTimer = setTimeout ( this . _append , MIN_APPEND_INTERVAL )
157
- }
163
+ this . virtualList . append ( container )
158
164
}
159
165
}
160
166
/** Clear all entries. */
161
167
clear ( ) {
162
- if ( this . appendTimer ) {
163
- clearTimeout ( this . appendTimer )
164
- this . appendTimer = null
165
- this . frag = document . createDocumentFragment ( )
166
- }
167
168
this . entries = [ ]
168
- this . $container . html ( '' )
169
+ this . virtualList . clear ( )
169
170
}
170
171
/** Scroll to end. */
171
172
scrollToEnd ( ) {
172
- const { container } = this
173
- const { scrollHeight, scrollTop, offsetHeight } = container
174
- if ( scrollTop <= scrollHeight - offsetHeight ) {
175
- container . scrollTop = 10000000
176
- this . isAtBottom = true
177
- }
173
+ this . virtualList . scrollToEnd ( )
178
174
}
179
175
/** Check if there is any selection. */
180
176
hasSelection ( ) {
@@ -197,14 +193,6 @@ export default class Logcat extends Component<IOptions> {
197
193
const selection = window . getSelection ( )
198
194
return selection ? selection . toString ( ) : ''
199
195
}
200
- private _append = ( ) => {
201
- const isAtBottom = this . isAtBottom
202
- this . container . appendChild ( this . frag )
203
- this . appendTimer = null
204
- if ( isAtBottom ) {
205
- this . scrollToEnd ( )
206
- }
207
- }
208
196
private filterEntry ( entry : IBaseEntry ) {
209
197
const { filter } = this . options
210
198
@@ -232,9 +220,16 @@ export default class Logcat extends Component<IOptions> {
232
220
233
221
return true
234
222
}
223
+ private initTpl ( ) {
224
+ this . $container . html ( this . c ( '<div class="virtual-list"></div>' ) )
225
+ }
235
226
private bindEvent ( ) {
236
227
const { c } = this
237
228
229
+ this . resizeSensor . addListener (
230
+ debounce ( ( ) => this . virtualList . update ( ) , 100 )
231
+ )
232
+
238
233
this . on ( 'changeOption' , ( name , val ) => {
239
234
const { entries } = this
240
235
@@ -277,8 +272,6 @@ export default class Logcat extends Component<IOptions> {
277
272
const self = this
278
273
279
274
this . $container
280
- . on ( 'scroll' , this . onScroll )
281
- . on ( 'click' , ( ) => ( this . isAtBottom = false ) )
282
275
. on ( 'contextmenu' , c ( '.entry' ) , function ( this : HTMLDivElement , e ) {
283
276
e . stopPropagation ( )
284
277
const idx = $ ( this ) . data ( 'idx' )
@@ -295,18 +288,6 @@ export default class Logcat extends Component<IOptions> {
295
288
self . emit ( 'contextmenu' , e . origEvent )
296
289
} )
297
290
}
298
- private onScroll = ( ) => {
299
- const { scrollHeight, clientHeight, scrollTop } = this
300
- . container as HTMLElement
301
-
302
- let isAtBottom = false
303
- if ( scrollHeight === clientHeight ) {
304
- isAtBottom = true
305
- } else if ( Math . abs ( scrollHeight - clientHeight - scrollTop ) < 1 ) {
306
- isAtBottom = true
307
- }
308
- this . isAtBottom = isAtBottom
309
- }
310
291
private formatStandard ( entry : IInnerEntry ) {
311
292
const { c } = this
312
293
@@ -339,7 +320,6 @@ export default class Logcat extends Component<IOptions> {
339
320
private _render ( ) {
340
321
const { container } = this
341
322
this . $container . html ( '' )
342
- this . isAtBottom = true
343
323
344
324
const frag = document . createDocumentFragment ( )
345
325
each ( this . displayEntries , ( entry ) => {
0 commit comments