|
7 | 7 | import { writable } from 'svelte/store'; |
8 | 8 | import Link from '../elements/Link.svelte'; |
9 | 9 | import { focusedConnectionOrDatabase } from '../stores'; |
10 | | - import { tick } from 'svelte'; |
11 | | - import { _tval } from '../translations'; |
| 10 | + import { tick, onDestroy, afterUpdate } from 'svelte'; |
| 11 | + import { _t, _tval } from '../translations'; |
12 | 12 |
|
13 | 13 | export let list; |
14 | 14 | export let module; |
|
34 | 34 |
|
35 | 35 | export let collapsedGroupNames = writable([]); |
36 | 36 | export let onChangeFilteredList = undefined; |
| 37 | + export let initialRenderCount = null; |
| 38 | + export let renderBatchSize = 200; |
37 | 39 |
|
38 | 40 | let expandLimited = false; |
| 41 | + let renderedCount = null; |
| 42 | + let renderTimer = null; |
| 43 | + let lastLimitedList = null; |
39 | 44 |
|
40 | 45 | $: matcher = module.createMatcher && module.createMatcher(filter, passProps?.searchSettings); |
41 | 46 |
|
|
82 | 87 | $: filtered = dataLabeled.filter(x => x.isMatched).map(x => x.data); |
83 | 88 | $: childrenMatched = dataLabeled.filter(x => x.isChildMatched).map(x => x.data); |
84 | 89 | $: mainMatched = dataLabeled.filter(x => x.isMainMatched).map(x => x.data); |
| 90 | + $: filteredSet = new Set(filtered); |
| 91 | + $: childrenMatchedSet = new Set(childrenMatched); |
| 92 | + $: mainMatchedSet = new Set(mainMatched); |
85 | 93 |
|
86 | 94 | // let filtered = []; |
87 | 95 |
|
|
112 | 120 | expandLimited = true; |
113 | 121 | } |
114 | 122 |
|
115 | | - $: groups = groupFunc ? extendGroups(_.groupBy(dataLabeled, 'group'), emptyGroupNames) : null; |
116 | | -
|
117 | 123 | $: listLimited = |
118 | 124 | isExpandedBySearch && !expandLimited ? filtered.slice(0, filter.trim().length < 3 ? 1 : 3) : listTranslated; |
119 | 125 | $: isListLimited = isExpandedBySearch && listLimited.length < filtered.length; |
120 | 126 | $: listMissingItems = isListLimited ? filtered.slice(listLimited.length) : []; |
| 127 | + $: if (initialRenderCount && listLimited !== lastLimitedList) { |
| 128 | + lastLimitedList = listLimited; |
| 129 | + renderedCount = Math.min(initialRenderCount, listLimited.length); |
| 130 | + } |
| 131 | + $: listRendered = |
| 132 | + initialRenderCount && renderedCount != null ? listLimited.slice(0, renderedCount) : listLimited; |
| 133 | + $: hasMoreToRender = initialRenderCount && renderedCount != null && renderedCount < listLimited.length; |
| 134 | + $: loadingMoreObjectsMessage = _t('objectsList.loadingMoreObjects', { defaultMessage: 'Loading more objects...' }); |
| 135 | + $: dataLabeledRendered = |
| 136 | + initialRenderCount && renderedCount != null ? dataLabeled.slice(0, renderedCount) : dataLabeled; |
| 137 | + $: groups = groupFunc ? extendGroups(_.groupBy(dataLabeledRendered, 'group'), emptyGroupNames) : null; |
121 | 138 |
|
122 | 139 | $: if ( |
123 | 140 | $focusedConnectionOrDatabase && |
|
127 | 144 | ) { |
128 | 145 | tick().then(setExpandLimited); |
129 | 146 | } |
| 147 | +
|
| 148 | + afterUpdate(() => { |
| 149 | + if (hasMoreToRender && !renderTimer) { |
| 150 | + renderTimer = setTimeout(() => { |
| 151 | + renderTimer = null; |
| 152 | + renderedCount = Math.min(listLimited.length, renderedCount + renderBatchSize); |
| 153 | + }, 0); |
| 154 | + } |
| 155 | + }); |
| 156 | +
|
| 157 | + onDestroy(() => { |
| 158 | + if (renderTimer) { |
| 159 | + clearTimeout(renderTimer); |
| 160 | + } |
| 161 | + }); |
130 | 162 | </script> |
131 | 163 |
|
132 | 164 | {#if groupFunc} |
|
152 | 184 | {collapsedGroupNames} |
153 | 185 | /> |
154 | 186 | {/each} |
| 187 | + {#if hasMoreToRender} |
| 188 | + <div class="ml-2 grayed">{loadingMoreObjectsMessage}</div> |
| 189 | + {/if} |
155 | 190 | {:else} |
156 | | - {#each listLimited as data} |
| 191 | + {#each listRendered as data} |
157 | 192 | <AppObjectListItem |
158 | | - isHidden={!filtered.includes(data)} |
| 193 | + isHidden={!filteredSet.has(data)} |
159 | 194 | {module} |
160 | 195 | {subItemsComponent} |
161 | 196 | {expandOnClick} |
|
166 | 201 | {checkedObjectsStore} |
167 | 202 | {disableContextMenu} |
168 | 203 | {filter} |
169 | | - isExpandedBySearch={filter && childrenMatched.includes(data)} |
170 | | - isMainMatched={filter && mainMatched.includes(data)} |
| 204 | + isExpandedBySearch={filter && childrenMatchedSet.has(data)} |
| 205 | + isMainMatched={filter && mainMatchedSet.has(data)} |
171 | 206 | {passProps} |
172 | 207 | {getIsExpanded} |
173 | 208 | {setIsExpanded} |
|
182 | 217 | > |
183 | 218 | </div> |
184 | 219 | {/if} |
| 220 | + {#if hasMoreToRender} |
| 221 | + <div class="ml-2 grayed">{loadingMoreObjectsMessage}</div> |
| 222 | + {/if} |
185 | 223 | {/if} |
0 commit comments