@quicktvui/web-renderer 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +24 -0
- package/src/adapters/es3-video-player.js +828 -0
- package/src/components/Modal.js +119 -0
- package/src/components/QtAnimationView.js +678 -0
- package/src/components/QtBaseComponent.js +165 -0
- package/src/components/QtFastListView.js +1920 -0
- package/src/components/QtFlexView.js +799 -0
- package/src/components/QtImage.js +203 -0
- package/src/components/QtItemFrame.js +239 -0
- package/src/components/QtItemStoreView.js +93 -0
- package/src/components/QtItemView.js +125 -0
- package/src/components/QtListView.js +331 -0
- package/src/components/QtLoadingView.js +55 -0
- package/src/components/QtPageRootView.js +19 -0
- package/src/components/QtPlayMark.js +168 -0
- package/src/components/QtProgressBar.js +199 -0
- package/src/components/QtQRCode.js +78 -0
- package/src/components/QtReplaceChild.js +149 -0
- package/src/components/QtRippleView.js +166 -0
- package/src/components/QtSeekBar.js +409 -0
- package/src/components/QtText.js +679 -0
- package/src/components/QtTransitionImage.js +170 -0
- package/src/components/QtView.js +706 -0
- package/src/components/QtWebView.js +613 -0
- package/src/components/TabsView.js +420 -0
- package/src/components/ViewPager.js +206 -0
- package/src/components/index.js +24 -0
- package/src/components/plugins/TextV2Component.js +70 -0
- package/src/components/plugins/index.js +7 -0
- package/src/core/SceneBuilder.js +58 -0
- package/src/core/TVFocusManager.js +2014 -0
- package/src/core/asyncLocalStorage.js +175 -0
- package/src/core/autoProxy.js +165 -0
- package/src/core/componentRegistry.js +84 -0
- package/src/core/constants.js +6 -0
- package/src/core/index.js +8 -0
- package/src/core/moduleUtils.js +36 -0
- package/src/core/patches.js +958 -0
- package/src/core/templateBinding.js +666 -0
- package/src/index.js +246 -0
- package/src/modules/AndroidDevelopModule.js +101 -0
- package/src/modules/AndroidDeviceModule.js +341 -0
- package/src/modules/AndroidNetworkModule.js +178 -0
- package/src/modules/AndroidSharedPreferencesModule.js +100 -0
- package/src/modules/ESDeviceInfoModule.js +450 -0
- package/src/modules/ESGroupDataModule.js +195 -0
- package/src/modules/ESIJKAudioPlayerModule.js +477 -0
- package/src/modules/ESLocalStorageModule.js +100 -0
- package/src/modules/ESLogModule.js +65 -0
- package/src/modules/ESModule.js +106 -0
- package/src/modules/ESNetworkSpeedModule.js +117 -0
- package/src/modules/ESToastModule.js +172 -0
- package/src/modules/EsNativeModule.js +117 -0
- package/src/modules/FastListModule.js +101 -0
- package/src/modules/FocusModule.js +145 -0
- package/src/modules/RuntimeDeviceModule.js +176 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
// TabsView component - Native tabs container for qt-tabs
|
|
2
|
+
import { QtBaseComponent } from './QtBaseComponent'
|
|
3
|
+
import { registerComponent } from '../core/componentRegistry'
|
|
4
|
+
|
|
5
|
+
export class TabsView extends QtBaseComponent {
|
|
6
|
+
constructor(context, id, pId) {
|
|
7
|
+
super(context, id, pId)
|
|
8
|
+
this.tagName = 'TabsView'
|
|
9
|
+
this.dom = document.createElement('div')
|
|
10
|
+
this.dom.setAttribute('data-component-name', 'TabsView')
|
|
11
|
+
registerComponent(id, this)
|
|
12
|
+
|
|
13
|
+
// Tabs state
|
|
14
|
+
this._tabData = null
|
|
15
|
+
this._currentPageIndex = 0
|
|
16
|
+
this._pages = new Map()
|
|
17
|
+
this._tabItems = []
|
|
18
|
+
|
|
19
|
+
// 子组件引用,通过 name 属性存储
|
|
20
|
+
// 'tabList' -> qt-nav-bar
|
|
21
|
+
// 'content' -> recycler-view-pager
|
|
22
|
+
this._childrenByName = new Map()
|
|
23
|
+
|
|
24
|
+
// Container for children (nav-bar and view-pager)
|
|
25
|
+
this._childrenContainer = this.dom
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
defaultStyle() {
|
|
29
|
+
return {
|
|
30
|
+
boxSizing: 'border-box',
|
|
31
|
+
display: 'flex',
|
|
32
|
+
flexDirection: 'column',
|
|
33
|
+
width: '100%',
|
|
34
|
+
height: '100%',
|
|
35
|
+
position: 'relative',
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Handle child components - 通过 name 属性存储引用
|
|
40
|
+
insertChild(view, index) {
|
|
41
|
+
if (view && view.dom) {
|
|
42
|
+
// 获取子组件的 name 属性
|
|
43
|
+
const childName = view.props?.name || view.dom.getAttribute('name')
|
|
44
|
+
|
|
45
|
+
if (childName) {
|
|
46
|
+
console.log('[TabsView] insertChild with name:', childName, view.tagName)
|
|
47
|
+
this._childrenByName.set(childName, view)
|
|
48
|
+
|
|
49
|
+
// 监听 tabList (qt-nav-bar) 的事件
|
|
50
|
+
if (childName === 'tabList') {
|
|
51
|
+
this._setupTabListListeners(view)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this._childrenContainer.appendChild(view.dom)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 设置 tabList 事件监听
|
|
60
|
+
_setupTabListListeners(tabList) {
|
|
61
|
+
if (!tabList) return
|
|
62
|
+
|
|
63
|
+
// 保存原生 dispatchEvent,注入事件转发
|
|
64
|
+
const originalDispatchEvent = tabList.dispatchEvent.bind(tabList)
|
|
65
|
+
tabList.dispatchEvent = (eventName, params) => {
|
|
66
|
+
// 调用原始 dispatchEvent
|
|
67
|
+
originalDispatchEvent(eventName, params)
|
|
68
|
+
|
|
69
|
+
// 转发事件到 TabsView 处理
|
|
70
|
+
console.log('[TabsView] intercepted event from tabList:', eventName, params)
|
|
71
|
+
|
|
72
|
+
// 处理 onItemFocused 事件 (hasFocus === true 时切换页面)
|
|
73
|
+
if (eventName === 'onItemFocused' && params && params.hasFocus === true) {
|
|
74
|
+
const pageIndex = params.position
|
|
75
|
+
if (pageIndex !== undefined && pageIndex !== this._currentPageIndex) {
|
|
76
|
+
console.log('[TabsView] tab focus changed to:', pageIndex)
|
|
77
|
+
this._currentPageIndex = pageIndex
|
|
78
|
+
this._dispatchPageChanged(pageIndex)
|
|
79
|
+
this._dispatchLoadPageData(pageIndex, false)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 处理 onItemClick 事件
|
|
84
|
+
if (eventName === 'onItemClick') {
|
|
85
|
+
const pageIndex = params?.position
|
|
86
|
+
if (pageIndex !== undefined && pageIndex !== this._currentPageIndex) {
|
|
87
|
+
console.log('[TabsView] tab clicked, switching to:', pageIndex)
|
|
88
|
+
this._currentPageIndex = pageIndex
|
|
89
|
+
this._dispatchPageChanged(pageIndex)
|
|
90
|
+
this._dispatchLoadPageData(pageIndex, false)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log('[TabsView] tabList listeners setup complete')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Remove child
|
|
99
|
+
removeChild(view) {
|
|
100
|
+
if (view && view.dom) {
|
|
101
|
+
const childName = view.props?.name || view.dom.getAttribute('name')
|
|
102
|
+
if (childName) {
|
|
103
|
+
this._childrenByName.delete(childName)
|
|
104
|
+
}
|
|
105
|
+
if (view.dom.parentNode === this._childrenContainer) {
|
|
106
|
+
this._childrenContainer.removeChild(view.dom)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 通过 name 获取子组件
|
|
112
|
+
getChildByName(name) {
|
|
113
|
+
return this._childrenByName.get(name)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
updateProperty(key, value) {
|
|
117
|
+
switch (key) {
|
|
118
|
+
case 'offscreenPageLimit':
|
|
119
|
+
this._offscreenPageLimit = value
|
|
120
|
+
break
|
|
121
|
+
case 'dataStrategy':
|
|
122
|
+
this._dataStrategy = value
|
|
123
|
+
break
|
|
124
|
+
case 'hideOnSingleTab':
|
|
125
|
+
this._hideOnSingleTab = value
|
|
126
|
+
this._applyHideOnSingleTab()
|
|
127
|
+
break
|
|
128
|
+
case 'pageSwitchDelay':
|
|
129
|
+
this._pageSwitchDelay = value
|
|
130
|
+
break
|
|
131
|
+
case 'suspension':
|
|
132
|
+
this._suspension = value
|
|
133
|
+
break
|
|
134
|
+
case 'useSuspensionBg':
|
|
135
|
+
this._useSuspensionBg = value
|
|
136
|
+
break
|
|
137
|
+
default:
|
|
138
|
+
super.updateProperty(key, value)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 应用 hideOnSingleTab 逻辑
|
|
143
|
+
_applyHideOnSingleTab() {
|
|
144
|
+
const tabList = this.getChildByName('tabList')
|
|
145
|
+
if (!tabList || !tabList.dom) return
|
|
146
|
+
|
|
147
|
+
const shouldHide = this._hideOnSingleTab === true && this._tabItems.length === 1
|
|
148
|
+
tabList.dom.style.display = shouldHide ? 'none' : ''
|
|
149
|
+
console.log('[TabsView] _applyHideOnSingleTab:', shouldHide, 'tabCount:', this._tabItems.length)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Set tabs data - 设置 tab 导航栏数据
|
|
153
|
+
setTabsData(...args) {
|
|
154
|
+
args = Array.isArray(args[0]) && args.length === 1 ? args[0] : args
|
|
155
|
+
const config = args[0] || {}
|
|
156
|
+
const data = args[1] || []
|
|
157
|
+
this._tabData = { ...config, data }
|
|
158
|
+
this._tabItems = Array.isArray(data) ? data : []
|
|
159
|
+
this._currentPageIndex = config.defaultIndex ?? 0
|
|
160
|
+
this._focusIndex = config.focusIndex ?? this._currentPageIndex
|
|
161
|
+
|
|
162
|
+
console.log(
|
|
163
|
+
'[TabsView] setTabsData:',
|
|
164
|
+
config,
|
|
165
|
+
data,
|
|
166
|
+
'tabList:',
|
|
167
|
+
this._childrenByName.get('tabList')
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
// 通过 name 获取 tabList (qt-nav-bar) 并设置数据
|
|
171
|
+
const tabList = this.getChildByName('tabList')
|
|
172
|
+
if (tabList && tabList.setListData) {
|
|
173
|
+
console.log('[TabsView] calling tabList.setListData with:', data)
|
|
174
|
+
tabList.setListData(data)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 应用 hideOnSingleTab 逻辑
|
|
178
|
+
this._applyHideOnSingleTab()
|
|
179
|
+
|
|
180
|
+
// 延迟分发事件,确保事件监听器已经注册
|
|
181
|
+
// 使用 requestAnimationFrame 或 setTimeout 来等待事件监听器注册完成
|
|
182
|
+
requestAnimationFrame(() => {
|
|
183
|
+
console.log('[TabsView] Dispatching events after setTabsData, events:', this.events)
|
|
184
|
+
const content = this.getChildByName('content')
|
|
185
|
+
if (content && typeof content.setCurrentPage === 'function') {
|
|
186
|
+
content.setCurrentPage(this._currentPageIndex)
|
|
187
|
+
}
|
|
188
|
+
// Dispatch page changed event
|
|
189
|
+
this._dispatchPageChanged(this._currentPageIndex)
|
|
190
|
+
this._dispatchLoadPageData(this._currentPageIndex, false)
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Set page data - 设置页面内容数据
|
|
195
|
+
setPageData(...args) {
|
|
196
|
+
args = Array.isArray(args[0]) && args.length === 1 ? args[0] : args
|
|
197
|
+
const pageIndex = args[0]
|
|
198
|
+
const meta = args[1] || {}
|
|
199
|
+
const data = args[2] || []
|
|
200
|
+
const pageData = { ...meta, data }
|
|
201
|
+
this._pages.set(pageIndex, pageData)
|
|
202
|
+
|
|
203
|
+
console.log(
|
|
204
|
+
'[TabsView] setPageData:',
|
|
205
|
+
pageIndex,
|
|
206
|
+
meta,
|
|
207
|
+
data,
|
|
208
|
+
'content:',
|
|
209
|
+
this._childrenByName.get('content')
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
// 通过 name 获取 content (recycler-view-pager) 并设置数据
|
|
213
|
+
const content = this.getChildByName('content')
|
|
214
|
+
if (content && content.setListData) {
|
|
215
|
+
console.log('[TabsView] calling content.setListData with:', pageIndex, meta, data)
|
|
216
|
+
content.setListData(pageIndex, meta, data)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Add page data
|
|
221
|
+
addPageData(...args) {
|
|
222
|
+
args = Array.isArray(args[0]) && args.length === 1 ? args[0] : args
|
|
223
|
+
const pageIndex = args[0]
|
|
224
|
+
const meta = args[1] || {}
|
|
225
|
+
const data = args[2] || []
|
|
226
|
+
const deleteCount = meta.deleteCount ?? 0
|
|
227
|
+
|
|
228
|
+
const existing = this._pages.get(pageIndex) || { data: [] }
|
|
229
|
+
const existingList = Array.isArray(existing.data) ? existing.data : []
|
|
230
|
+
if (deleteCount > 0) {
|
|
231
|
+
existingList.splice(0, deleteCount)
|
|
232
|
+
}
|
|
233
|
+
if (Array.isArray(data)) {
|
|
234
|
+
existing.data = existingList.concat(data)
|
|
235
|
+
} else {
|
|
236
|
+
existing.data = existingList
|
|
237
|
+
}
|
|
238
|
+
this._pages.set(pageIndex, existing)
|
|
239
|
+
|
|
240
|
+
// 通过 name 获取 content 并添加数据
|
|
241
|
+
const content = this.getChildByName('content')
|
|
242
|
+
if (content && content.addListData) {
|
|
243
|
+
content.addListData(pageIndex, meta, data)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Update page data
|
|
248
|
+
updatePageData(...args) {
|
|
249
|
+
args = Array.isArray(args[0]) && args.length === 1 ? args[0] : args
|
|
250
|
+
const pageIndex = args[0]
|
|
251
|
+
const data = args[1] || []
|
|
252
|
+
const meta = args[2] || {}
|
|
253
|
+
this.setPageData(pageIndex, meta, data)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Update page content (placeholder - actual rendering handled by child components)
|
|
257
|
+
_updatePageContent(pageIndex, data) {
|
|
258
|
+
console.log('[TabsView] updatePageContent:', pageIndex, data)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Set current page
|
|
262
|
+
setCurrentPage(pageIndex) {
|
|
263
|
+
if (Array.isArray(pageIndex)) {
|
|
264
|
+
pageIndex = pageIndex[0]
|
|
265
|
+
}
|
|
266
|
+
if (pageIndex < 0 || pageIndex >= this._tabItems.length) return
|
|
267
|
+
|
|
268
|
+
const previousIndex = this._currentPageIndex
|
|
269
|
+
this._currentPageIndex = pageIndex
|
|
270
|
+
|
|
271
|
+
const content = this.getChildByName('content')
|
|
272
|
+
if (content && typeof content.setCurrentPage === 'function') {
|
|
273
|
+
content.setCurrentPage(pageIndex)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Dispatch page changed event
|
|
277
|
+
this._dispatchPageChanged(pageIndex)
|
|
278
|
+
this._dispatchLoadPageData(pageIndex, false)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Get current page
|
|
282
|
+
getCurrentPage() {
|
|
283
|
+
return Promise.resolve(this._currentPageIndex)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Request tab focus
|
|
287
|
+
requestTabFocus(tabIndex) {
|
|
288
|
+
this._focusIndex = tabIndex
|
|
289
|
+
this.setCurrentPage(tabIndex)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Focus back to top
|
|
293
|
+
focusBackToTop() {
|
|
294
|
+
console.log('[TabsView] focusBackToTop')
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Request node focus
|
|
298
|
+
requestNodeFocus(id) {
|
|
299
|
+
console.log('[TabsView] requestNodeFocus:', id)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Reload all pages
|
|
303
|
+
reloadAll(updateCurrent = true) {
|
|
304
|
+
this._dispatchLoadPageData(this._currentPageIndex, false)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Reload specific page
|
|
308
|
+
reloadPage(pageIndex) {
|
|
309
|
+
this._dispatchLoadPageData(pageIndex, false)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Invoke content function
|
|
313
|
+
invokeContentFunction(pageIndex, functionName, params) {
|
|
314
|
+
console.log('[TabsView] invokeContentFunction:', pageIndex, functionName, params)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Invoke content function direct
|
|
318
|
+
invokeContentFunctionDirect(functionName, params) {
|
|
319
|
+
console.log('[TabsView] invokeContentFunctionDirect:', functionName, params)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Content scroll to focus
|
|
323
|
+
contentScrollToFocus(position) {
|
|
324
|
+
console.log('[TabsView] contentScrollToFocus:', position)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Update child node
|
|
328
|
+
updateChildNode(page, position, childIndex, data) {
|
|
329
|
+
console.log('[TabsView] updateChildNode:', page, position, childIndex)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Update root node
|
|
333
|
+
updateRootNode(page, position, data) {
|
|
334
|
+
console.log('[TabsView] updateRootNode:', page, position)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Update item matched
|
|
338
|
+
updateItemMatched(key, id, newData) {
|
|
339
|
+
console.log('[TabsView] updateItemMatched:', key, id)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Block root focus
|
|
343
|
+
blockRootFocus() {
|
|
344
|
+
console.log('[TabsView] blockRootFocus')
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Unblock root focus
|
|
348
|
+
unBlockRootFocus() {
|
|
349
|
+
console.log('[TabsView] unBlockRootFocus')
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Translation left
|
|
353
|
+
translationLeft() {
|
|
354
|
+
if (this._currentPageIndex > 0) {
|
|
355
|
+
this.setCurrentPage(this._currentPageIndex - 1)
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Translation right
|
|
360
|
+
translationRight() {
|
|
361
|
+
if (this._currentPageIndex < this._tabItems.length - 1) {
|
|
362
|
+
this.setCurrentPage(this._currentPageIndex + 1)
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Destroy
|
|
367
|
+
destroy() {
|
|
368
|
+
this._pages.clear()
|
|
369
|
+
this._tabItems = []
|
|
370
|
+
this._childrenByName.clear()
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Cancel all
|
|
374
|
+
cancelAll() {
|
|
375
|
+
// Cancel pending operations
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Get root node view state
|
|
379
|
+
getRootNodeViewState(page, position, callback) {
|
|
380
|
+
if (callback) {
|
|
381
|
+
callback({ viewState: {} })
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Get child node view state
|
|
386
|
+
getChildNodeViewState(page, position, childIndex, name, callback) {
|
|
387
|
+
if (callback) {
|
|
388
|
+
callback({ viewState: {} })
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Dispatch UI function on child node
|
|
393
|
+
dispatchUIFunctionOnChildNode(page, position, childIndex, listViewName, functionParams) {
|
|
394
|
+
console.log('[TabsView] dispatchUIFunctionOnChildNode')
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Dispatch page changed event
|
|
398
|
+
_dispatchPageChanged(pageIndex) {
|
|
399
|
+
const params = {
|
|
400
|
+
pageIndex,
|
|
401
|
+
data: this._tabItems[pageIndex] || null,
|
|
402
|
+
}
|
|
403
|
+
console.log('[TabsView] _dispatchPageChanged, pageIndex:', pageIndex, 'events:', this.events)
|
|
404
|
+
// es3-vue 将 @page-changed 转换为 pagechanged 存储在 events 中
|
|
405
|
+
this.dispatchEvent('onPagechanged', params)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Dispatch load page event
|
|
409
|
+
_dispatchLoadPageData(pageIndex, useDiff) {
|
|
410
|
+
const params = {
|
|
411
|
+
pageIndex,
|
|
412
|
+
itemCount: 0,
|
|
413
|
+
data: this._tabItems[pageIndex] || null,
|
|
414
|
+
useDiff: !!useDiff,
|
|
415
|
+
}
|
|
416
|
+
console.log('[TabsView] _dispatchLoadPageData, pageIndex:', pageIndex, 'events:', this.events)
|
|
417
|
+
// es3-vue 将 @load-page 转换为 loadpagedata 存储在 events 中
|
|
418
|
+
this.dispatchEvent('onLoadpagedata', params)
|
|
419
|
+
}
|
|
420
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// ViewPager component - Native page container for qt-tabs content
|
|
2
|
+
import { QtBaseComponent } from './QtBaseComponent'
|
|
3
|
+
import { registerComponent } from '../core/componentRegistry'
|
|
4
|
+
|
|
5
|
+
export class ViewPager extends QtBaseComponent {
|
|
6
|
+
constructor(context, id, pId) {
|
|
7
|
+
super(context, id, pId)
|
|
8
|
+
this.tagName = 'RecyclerViewPager'
|
|
9
|
+
this.dom = document.createElement('div')
|
|
10
|
+
this.dom.setAttribute('data-component-name', 'RecyclerViewPager')
|
|
11
|
+
registerComponent(id, this)
|
|
12
|
+
|
|
13
|
+
this._pages = new Map()
|
|
14
|
+
this._currentIndex = 0
|
|
15
|
+
this._direction = 'horizontal'
|
|
16
|
+
this._contentView = null
|
|
17
|
+
|
|
18
|
+
// Container for children
|
|
19
|
+
this._childrenContainer = this.dom
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
defaultStyle() {
|
|
23
|
+
return {
|
|
24
|
+
boxSizing: 'border-box',
|
|
25
|
+
display: 'block',
|
|
26
|
+
width: '100%',
|
|
27
|
+
flex: '1',
|
|
28
|
+
overflow: 'hidden',
|
|
29
|
+
position: 'relative',
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Handle child components - just append them to the container
|
|
34
|
+
insertChild(view, index) {
|
|
35
|
+
if (view && view.dom) {
|
|
36
|
+
if (!this._contentView) {
|
|
37
|
+
this._contentView = view
|
|
38
|
+
this._applyCurrentPageData()
|
|
39
|
+
}
|
|
40
|
+
this._childrenContainer.appendChild(view.dom)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Remove child
|
|
45
|
+
removeChild(view) {
|
|
46
|
+
if (view && view.dom && view.dom.parentNode === this._childrenContainer) {
|
|
47
|
+
this._childrenContainer.removeChild(view.dom)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
updateProperty(key, value) {
|
|
52
|
+
switch (key) {
|
|
53
|
+
case 'direction':
|
|
54
|
+
this._direction = value || 'horizontal'
|
|
55
|
+
break
|
|
56
|
+
case 'loadingItemType':
|
|
57
|
+
this._loadingItemType = value
|
|
58
|
+
break
|
|
59
|
+
case 'enableTransform':
|
|
60
|
+
this._enableTransform = value
|
|
61
|
+
break
|
|
62
|
+
case 'slidingEnable':
|
|
63
|
+
this._slidingEnable = value
|
|
64
|
+
break
|
|
65
|
+
case 'slidingMode':
|
|
66
|
+
this._slidingMode = value
|
|
67
|
+
break
|
|
68
|
+
case 'initTranslation':
|
|
69
|
+
this._initTranslation = value
|
|
70
|
+
break
|
|
71
|
+
case 'duration':
|
|
72
|
+
this._duration = value
|
|
73
|
+
break
|
|
74
|
+
default:
|
|
75
|
+
super.updateProperty(key, value)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Set current page
|
|
80
|
+
setCurrentPage(index) {
|
|
81
|
+
if (Array.isArray(index) && index.length === 1) {
|
|
82
|
+
index = index[0]
|
|
83
|
+
}
|
|
84
|
+
if (index < 0) return
|
|
85
|
+
|
|
86
|
+
const previousIndex = this._currentIndex
|
|
87
|
+
this._currentIndex = index
|
|
88
|
+
this._applyCurrentPageData()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_applyCurrentPageData() {
|
|
92
|
+
if (!this._contentView) return
|
|
93
|
+
const pageData = this._pages.get(this._currentIndex)
|
|
94
|
+
const listData = pageData && Array.isArray(pageData.data) ? pageData.data : []
|
|
95
|
+
|
|
96
|
+
// Check if content has a template-based list attribute (e.g., list="${tvSection0List}")
|
|
97
|
+
// If so, we need to bind the data through template mechanism
|
|
98
|
+
const listAttr = this._contentView.dom?.getAttribute?.('list')
|
|
99
|
+
if (listAttr && listAttr.includes('${')) {
|
|
100
|
+
// Use bindTemplateDataToNode to resolve template and set list data
|
|
101
|
+
// The listData should be wrapped in an object with the variable name as key
|
|
102
|
+
// Extract variable name from template string like "${tvSection0List}"
|
|
103
|
+
const varMatch = listAttr.match(/^\$\{([^}]+)\}$/)
|
|
104
|
+
if (varMatch) {
|
|
105
|
+
const varName = varMatch[1]
|
|
106
|
+
const scopeData = { [varName]: listData }
|
|
107
|
+
// Import and use bindTemplateDataToNode
|
|
108
|
+
import('../core/templateBinding.js').then(({ bindTemplateDataToNode }) => {
|
|
109
|
+
bindTemplateDataToNode(this._contentView.dom, scopeData, {
|
|
110
|
+
onListData: (element, value) => {
|
|
111
|
+
element._qtListData = value
|
|
112
|
+
if (this._contentView && typeof this._contentView.setListData === 'function') {
|
|
113
|
+
this._contentView.setListData(value)
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Direct setListData call for non-template case
|
|
123
|
+
if (typeof this._contentView.setListData === 'function') {
|
|
124
|
+
this._contentView.setListData(listData)
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
if (typeof this._contentView.updateProperty === 'function') {
|
|
128
|
+
this._contentView.updateProperty('listData', listData)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
setListData(...args) {
|
|
133
|
+
args = Array.isArray(args[0]) && args.length === 1 ? args[0] : args
|
|
134
|
+
const pageIndex = args[0]
|
|
135
|
+
const meta = args[1] || {}
|
|
136
|
+
const data = args[2] || []
|
|
137
|
+
this._pages.set(pageIndex, { ...meta, data })
|
|
138
|
+
if (pageIndex === this._currentIndex) {
|
|
139
|
+
this._applyCurrentPageData()
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
addListData(...args) {
|
|
144
|
+
args = Array.isArray(args[0]) && args.length === 1 ? args[0] : args
|
|
145
|
+
const pageIndex = args[0]
|
|
146
|
+
const meta = args[1] || {}
|
|
147
|
+
const data = args[2] || []
|
|
148
|
+
const deleteCount = meta.deleteCount ?? 0
|
|
149
|
+
|
|
150
|
+
const existing = this._pages.get(pageIndex) || { data: [] }
|
|
151
|
+
const existingList = Array.isArray(existing.data) ? existing.data : []
|
|
152
|
+
if (deleteCount > 0) {
|
|
153
|
+
existingList.splice(0, deleteCount)
|
|
154
|
+
}
|
|
155
|
+
if (Array.isArray(data)) {
|
|
156
|
+
existing.data = existingList.concat(data)
|
|
157
|
+
} else {
|
|
158
|
+
existing.data = existingList
|
|
159
|
+
}
|
|
160
|
+
this._pages.set(pageIndex, existing)
|
|
161
|
+
if (pageIndex === this._currentIndex) {
|
|
162
|
+
this._applyCurrentPageData()
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Set page data
|
|
167
|
+
setPageData(pageIndex, data) {
|
|
168
|
+
this.setListData(pageIndex, {}, data?.data ?? data)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Add page data
|
|
172
|
+
addPageData(pageIndex, data, deleteCount = 0) {
|
|
173
|
+
this.addListData(pageIndex, { deleteCount }, data?.data ?? data)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Update page data
|
|
177
|
+
updatePageData(pageIndex, data) {
|
|
178
|
+
this.setPageData(pageIndex, data)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Insert page data
|
|
182
|
+
insertPageData(pageIndex, sectionIndex, data) {
|
|
183
|
+
console.log('[ViewPager] insertPageData:', pageIndex, sectionIndex)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Update child node
|
|
187
|
+
updateChildNode(page, position, childIndex, data) {
|
|
188
|
+
console.log('[ViewPager] updateChildNode:', page, position, childIndex)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Update root node
|
|
192
|
+
updateRootNode(page, position, data) {
|
|
193
|
+
console.log('[ViewPager] updateRootNode:', page, position)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Delete item range
|
|
197
|
+
deleteItemRange(sectionIndex, count) {
|
|
198
|
+
console.log('[ViewPager] deleteItemRange:', sectionIndex, count)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Destroy
|
|
202
|
+
destroy() {
|
|
203
|
+
this._pages.clear()
|
|
204
|
+
this._contentView = null
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Component exports
|
|
2
|
+
export { QtView, createNamedComponent } from './QtView'
|
|
3
|
+
export { QtBaseComponent } from './QtBaseComponent'
|
|
4
|
+
export { QtPageRootView } from './QtPageRootView'
|
|
5
|
+
export { QtText } from './QtText'
|
|
6
|
+
export { QtImage } from './QtImage'
|
|
7
|
+
export { QtFastListView } from './QtFastListView'
|
|
8
|
+
export { QtLoadingView } from './QtLoadingView'
|
|
9
|
+
export { QtAnimationView } from './QtAnimationView'
|
|
10
|
+
export { QtWebView } from './QtWebView'
|
|
11
|
+
export { QtQRCode } from './QtQRCode'
|
|
12
|
+
export { QtProgressBar } from './QtProgressBar'
|
|
13
|
+
export { QtSeekBar } from './QtSeekBar'
|
|
14
|
+
export { QtItemFrame } from './QtItemFrame'
|
|
15
|
+
export { QtItemStoreView } from './QtItemStoreView'
|
|
16
|
+
export { QtRippleView } from './QtRippleView'
|
|
17
|
+
export { QtFlexView } from './QtFlexView'
|
|
18
|
+
export { QtItemView } from './QtItemView'
|
|
19
|
+
export { TabsView } from './TabsView'
|
|
20
|
+
export { ViewPager } from './ViewPager'
|
|
21
|
+
export { Modal } from './Modal'
|
|
22
|
+
export { QtListView, QtListViewItem } from './QtListView'
|
|
23
|
+
export { QtPlayMark } from './QtPlayMark'
|
|
24
|
+
export { QtReplaceChild } from './QtReplaceChild'
|