@shijiu/jsview-vue 2.0.1021 → 2.0.1073

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.
Files changed (33) hide show
  1. package/package.json +4 -3
  2. package/utils/JsViewEngineWidget/CheckType.js +82 -0
  3. package/utils/JsViewEngineWidget/MetroWidget/AnimationManager.ts +72 -0
  4. package/utils/JsViewEngineWidget/MetroWidget/Const.ts +24 -0
  5. package/utils/JsViewEngineWidget/MetroWidget/ListWidget.vue +295 -0
  6. package/utils/JsViewEngineWidget/MetroWidget/MetroWidget.vue +110 -1651
  7. package/utils/JsViewEngineWidget/MetroWidget/MetroWidgetSetup.js +1867 -0
  8. package/utils/JsViewEngineWidget/MetroWidget/PageUpdater.ts +111 -0
  9. package/utils/JsViewEngineWidget/MetroWidget/RenderItem.ts +153 -0
  10. package/utils/JsViewEngineWidget/MetroWidget/VisibleInfo.ts +43 -0
  11. package/utils/JsViewEngineWidget/MetroWidget/WidgetRectInfo.ts +49 -0
  12. package/utils/JsViewEngineWidget/TemplateParser/CommonMetroTemplate.ts +1424 -0
  13. package/utils/JsViewEngineWidget/TemplateParser/Fence.ts +135 -0
  14. package/utils/JsViewEngineWidget/TemplateParser/ListMetroTemplate.ts +177 -0
  15. package/utils/JsViewEngineWidget/TemplateParser/MetroTemplate.ts +334 -0
  16. package/utils/JsViewEngineWidget/TemplateParser/TemplateItemAdder.ts +147 -0
  17. package/utils/JsViewEngineWidget/TemplateParser/index.ts +4 -0
  18. package/utils/JsViewEngineWidget/{WidgetCommon.js → WidgetCommon.ts} +64 -71
  19. package/utils/JsViewEngineWidget/index.js +2 -1
  20. package/utils/JsViewPlugin/JsvAudio/AudioProxy.js +26 -1
  21. package/utils/JsViewPlugin/JsvAudio/JsvAudio.vue +120 -133
  22. package/utils/JsViewPlugin/JsvAudio/JsvAudioBrowser.vue +11 -7
  23. package/utils/JsViewPlugin/JsvPlayer/GetVersion.js +1 -1
  24. package/utils/JsViewPlugin/JsvPlayer/JsvPlayerBrowser.vue +379 -41
  25. package/utils/JsViewPlugin/JsvPlayer/version.mjs +5 -5
  26. package/utils/JsViewVueTools/JsvHashHistory.js +2 -1
  27. package/utils/JsViewVueWidget/JsvRadarChart.vue +220 -0
  28. package/utils/JsViewVueWidget/JsvSystemAudio.vue +76 -44
  29. package/utils/JsViewVueWidget/index.js +1 -0
  30. package/utils/JsViewEngineWidget/MetroWidget/Const.js +0 -11
  31. package/utils/JsViewEngineWidget/MetroWidget/PageUpdater.js +0 -136
  32. package/utils/JsViewEngineWidget/MetroWidget/ToolFunctions.js +0 -18
  33. package/utils/JsViewEngineWidget/TemplateParser.js +0 -2004
@@ -1,2004 +0,0 @@
1
- /* eslint-disable */
2
- import { RangesModel, SingleRangeModel } from "./RangeModel";
3
- import { RectArea } from "./RectUtils";
4
- import { VERTICAL, HORIZONTAL, FocusMoveType } from "./WidgetCommon";
5
- const TAG = "TemplateParser: ";
6
-
7
- function integerCheck(value, warn_func) {
8
- const result = Math.round(value);
9
- if (result !== value) {
10
- warn_func();
11
- }
12
- return result;
13
- }
14
-
15
- const measureObjectCheckMap = {
16
- left: (obj) => {
17
- if (isNaN(obj.left)) {
18
- return 0;
19
- } else {
20
- return integerCheck(obj.left, () => {
21
- console.warn(TAG, "left is not integer", obj);
22
- });
23
- }
24
- },
25
- top: (obj) => {
26
- if (isNaN(obj.top)) {
27
- return 0;
28
- } else {
29
- return integerCheck(obj.top, () => {
30
- console.warn(TAG, "top is not integer", obj);
31
- });
32
- }
33
- },
34
- width: (obj) => {
35
- if (isNaN(obj.width)) {
36
- if (isNaN(obj.block?.w)) {
37
- throw new Error(TAG + "width is not defined");
38
- } else {
39
- console.warn(TAG, "key 'block' is deprecated ");
40
- return integerCheck(obj.blocks.w, () => {
41
- console.warn(TAG, "width is not integer", obj);
42
- });
43
- }
44
- } else {
45
- return integerCheck(obj.width, () => {
46
- console.warn(TAG, "width is not integer", obj);
47
- });
48
- }
49
- },
50
- height: (obj) => {
51
- if (isNaN(obj.height)) {
52
- if (isNaN(obj.block?.h)) {
53
- throw new Error(TAG + "height is not defined");
54
- } else {
55
- console.warn(TAG, "key 'block' is deprecated ");
56
- return integerCheck(obj.blocks.h, () => {
57
- console.warn(TAG, "height is not integer", obj);
58
- });
59
- }
60
- } else {
61
- return integerCheck(obj.height, () => {
62
- console.warn(TAG, "height is not integer", obj);
63
- });
64
- }
65
- },
66
- };
67
- function measureObjectChecker(obj) {
68
- for (let key in measureObjectCheckMap) {
69
- obj[key] = measureObjectCheckMap[key](obj);
70
- }
71
- }
72
-
73
- function getTemplateItem(measure_obj, data_info) {
74
- measureObjectChecker(measure_obj);
75
-
76
- let focusZIndex = -1,
77
- normalZIndex = -1;
78
- if (
79
- typeof measure_obj["zIndex"] != "undefined" &&
80
- measure_obj["zIndex"] != null
81
- ) {
82
- if (typeof measure_obj["zIndex"] == "object") {
83
- if (typeof measure_obj["zIndex"]["focus"] == "number") {
84
- focusZIndex = measure_obj["zIndex"]["focus"];
85
- }
86
- if (typeof measure_obj["zIndex"]["normal"] == "number") {
87
- normalZIndex = measure_obj["zIndex"]["normal"];
88
- }
89
- } else if (typeof measure_obj["zIndex"] == "number") {
90
- focusZIndex = measure_obj["zIndex"];
91
- normalZIndex = measure_obj["zIndex"];
92
- }
93
- }
94
-
95
- return {
96
- id: -1,
97
- index: -1,
98
- xPos: measure_obj.left, // Set after template be layout
99
- yPos: measure_obj.top, // Set after template be layout
100
- centerXPos: 0, // Set after template be layout
101
- centerYPos: 0, // Set after template be layout
102
- width: measure_obj.width,
103
- height: measure_obj.height,
104
- focusable:
105
- typeof measure_obj.focusable === "undefined"
106
- ? true
107
- : measure_obj.focusable,
108
- data: data_info,
109
- marginRight:
110
- typeof measure_obj.marginRight !== "undefined"
111
- ? measure_obj.marginRight
112
- : 0,
113
- marginBottom:
114
- typeof measure_obj.marginBottom !== "undefined"
115
- ? measure_obj.marginBottom
116
- : 0,
117
- findNextAnchor:
118
- typeof measure_obj.findNextAnchor !== "undefined"
119
- ? measure_obj.findNextAnchor
120
- : null,
121
- doSlide:
122
- typeof measure_obj.doSlide !== "undefined" ? measure_obj.doSlide : true,
123
- pageNumber: -1,
124
- pageHeadIndex: -1,
125
- permanent:
126
- typeof measure_obj.permanent !== "undefined"
127
- ? measure_obj.permanent
128
- : false,
129
- focusZIndex,
130
- normalZIndex,
131
- };
132
- }
133
-
134
- class MetroTemplate {
135
- /**
136
- * 在MetroLayout中使用的模板管理类
137
- *
138
- * @protected
139
- * @constructor Forge.MetroTemplate
140
- * */
141
- constructor(direction, line_max, layout_type) {
142
- this.IdsMap = [];
143
- this._IdsTotal = -1;
144
- this.List = [];
145
- this.Orient = {
146
- type: direction,
147
- widthMax: line_max,
148
- };
149
- this.Layout = {
150
- type: layout_type || "relative",
151
- };
152
- }
153
-
154
- /**
155
- * Set id map to index
156
- *
157
- * @public
158
- * @func SetIdsMap
159
- * @memberof Forge.MetroTemplate
160
- * @params {int} identity
161
- * @instance
162
- * */
163
- SetIdsMap(identity, index) {
164
- this.IdsMap[identity] = index;
165
- this._IdsTotal = -1;
166
- this.List[index].id = identity;
167
- }
168
-
169
- AddItem(item) {
170
- this.List.push(item);
171
- item.index = this.List.length - 1;
172
- }
173
-
174
- /**
175
- * 非占位的Template的个数
176
- *
177
- * @private
178
- * @func GetIdsTotal
179
- * @memberof Forge.MetroTemplate
180
- * @params
181
- * @instance
182
- * @return {int} 个数
183
- * */
184
- GetIdsTotal() {
185
- if (this._IdsTotal < 0) {
186
- let total = 0;
187
- for (let i = 0; i < this.List.length; i++) {
188
- if (this.List[i].id >= 0) {
189
- total++;
190
- }
191
- }
192
- this._IdsTotal = total;
193
- }
194
-
195
- return this._IdsTotal;
196
- }
197
-
198
- GetLastId() {
199
- return this.IdsMap.length - 1;
200
- }
201
- }
202
-
203
- class Fence {
204
- /**
205
- * MetroLayout用于计算使用区域的Fence(栅栏)
206
- *
207
- * @private
208
- * @constructor _Fence
209
- * @memberof Forge.MetroLayout
210
- * @param {int} taken_start_pos 栅栏使用区域的起始位置
211
- * @param {int} width 栅栏使用区域的宽度
212
- * @param {int} fence_width 栅栏的总宽度
213
- * @param {int} offset_ahead 栅栏的横向位置
214
- * */
215
- constructor(taken_start_pos, width, fence_width, offset_ahead) {
216
- this._Gaps = [{ GapStart: 0, GapEnd: fence_width - 1 }];
217
- this._FenceTotalWidth = fence_width;
218
- this.AheadOffset = offset_ahead;
219
- if (width > 0) this._SplitGap(0, taken_start_pos, width);
220
- }
221
-
222
- /**
223
- * 查询栅栏是否能放下给定宽度的方块
224
- *
225
- * @public
226
- * @func HasGapFor
227
- * @memberof Forge.MetroLayout._Fence
228
- * @instance
229
- * @param {int} width
230
- * @return {Object} 格式为{startPos: 栅栏空隙的起始位置},null为没有能容下的空隙。
231
- * */
232
- HasGapFor(width) {
233
- for (let i = 0; i < this._Gaps.length; i++) {
234
- if (this._Gaps[i].GapEnd - this._Gaps[i].GapStart + 1 >= width) {
235
- return { startPos: this._Gaps[i].GapStart };
236
- }
237
- }
238
-
239
- return null;
240
- }
241
-
242
- /**
243
- * 标记栅栏空隙被占用
244
- *
245
- * @public
246
- * @func MarkGapUsed
247
- * @memberof Forge.MetroLayout._Fence
248
- * @instance
249
- * @param {int} start_pos 占用块的起始位置
250
- * @param {int} width 占用快的宽度
251
- * @return {int} 剩余栅栏的个数
252
- * */
253
- MarkGapUsed(start_pos, width) {
254
- if (width <= 0) return this._Gaps.length;
255
-
256
- const end_pos = start_pos + width - 1;
257
- let gap_idx = -1;
258
- for (let i = 0; i < this._Gaps.length; i++) {
259
- if (
260
- this._Gaps[i].GapStart <= start_pos &&
261
- this._Gaps[i].GapEnd >= end_pos
262
- ) {
263
- gap_idx = i;
264
- break;
265
- }
266
- }
267
-
268
- if (gap_idx === -1) {
269
- return; // 区域完全重复,无法找到新区域
270
- }
271
-
272
- this._SplitGap(gap_idx, start_pos, width);
273
-
274
- return this._Gaps.length;
275
- }
276
-
277
- _SplitGap(gap_idx, taker_start_pos, taker_width) {
278
- const edit_gap = this._Gaps.splice(gap_idx, 1)[0];
279
- const taker_end_pos = taker_start_pos + taker_width - 1;
280
-
281
- if (
282
- taker_start_pos < edit_gap.GapStart ||
283
- taker_end_pos > edit_gap.GapEnd
284
- ) {
285
- console.log("ERROR in split Fence Gap, range overflow");
286
- // Forge.ThrowError("ERROR in split Fence Gap, range overflow");
287
- }
288
-
289
- // Insert end side gap
290
- if (taker_end_pos !== edit_gap.GapEnd) {
291
- this._Gaps.splice(gap_idx, 0, {
292
- GapStart: taker_end_pos + 1,
293
- GapEnd: edit_gap.GapEnd,
294
- });
295
- }
296
-
297
- // Insert start side gap
298
- if (taker_start_pos !== edit_gap.GapStart) {
299
- this._Gaps.splice(gap_idx, 0, {
300
- GapStart: edit_gap.GapStart,
301
- GapEnd: taker_start_pos - 1,
302
- });
303
- }
304
- }
305
-
306
- /**
307
- * 标记栅栏空隙被占用
308
- *
309
- * @public
310
- * @func Fork
311
- * @memberof Forge.MetroLayout._Fence
312
- * @instance
313
- * @param {int} new_ahead_offset 新栅栏的起点位置
314
- * @return {Forge.MetroLayout._Fence} 复制出来的Fence
315
- * */
316
- Fork(new_ahead_offset) {
317
- const new_fence = new Fence(0, 0, 0, 0);
318
- new_fence._Gaps = JSON.parse(JSON.stringify(this._Gaps));
319
- new_fence._FenceTotalWidth = this._FenceTotalWidth;
320
- new_fence.AheadOffset = new_ahead_offset;
321
-
322
- return new_fence;
323
- }
324
- }
325
-
326
- class TemplateParser {
327
- constructor(direction, lineMax, pageSize, layoutType, supportHistoryPath) {
328
- this._Template = new MetroTemplate(direction, lineMax, layoutType);
329
- this._FenceStack = [new Fence(0, 0, this._Template.Orient.widthMax, 0)];
330
- this._Identity = 0;
331
- this._FenceEdge = { StartX: 0, StartY: 0 }; // 新的未占用边列表生成
332
- this._NotOccupiedEdgeList = []; // 未占用边列表
333
- this._SupportHistoryPath = supportHistoryPath;
334
- this._PageSize = pageSize;
335
- // this._VisibleRangeSearchBaseItem = null;
336
- }
337
-
338
- _IfBlockedByOtherNeighbor(direction, cross_item, target_item) {
339
- //检查是否被其他neighbor遮挡
340
- let position_key = "yPos";
341
- let size_key = "height";
342
- let sub_position_key = "xPos";
343
- switch (direction) {
344
- case "left":
345
- break;
346
- case "right":
347
- break;
348
- case "top":
349
- position_key = "xPos";
350
- sub_position_key = "yPos";
351
- size_key = "width";
352
- break;
353
- case "bottom":
354
- position_key = "xPos";
355
- sub_position_key = "yPos";
356
- size_key = "width";
357
- break;
358
- default:
359
- console.log(`_IfBlockedByOtherNeighbor unknown direction:${direction}`);
360
- break;
361
- }
362
- const cross_template_item = this.GetItem(cross_item.index);
363
- const cross_neighbor_list =
364
- cross_template_item.neighborIndexList[direction];
365
- const target_template_item = this.GetItem(target_item.index);
366
- const target_start = target_template_item[position_key];
367
- const target_end = target_start + target_template_item[size_key] - 1;
368
- let valid = true;
369
- for (let i = cross_neighbor_list.length - 1; i >= 0; i--) {
370
- const item = this.GetItem(cross_neighbor_list[i]);
371
- const item_start = item[position_key];
372
- const item_end = item_start + item[size_key] - 1;
373
- if (item_start <= target_end && item_end >= target_start) {
374
- //有重叠, 检查两个item那个离 cross item 更近
375
- if (
376
- Math.abs(
377
- item[sub_position_key] - cross_template_item[sub_position_key]
378
- ) <
379
- Math.abs(
380
- target_template_item[sub_position_key] -
381
- cross_template_item[sub_position_key]
382
- )
383
- ) {
384
- //已有的neighbor更近
385
- valid = false;
386
- break;
387
- } else {
388
- //target item更近, 删除已有的neighbor
389
- cross_neighbor_list.splice(i, 1);
390
- }
391
- }
392
- }
393
- return valid;
394
- }
395
-
396
- _CheckNeighborItemMatching(direction, cross_item, target_item) {
397
- const cross_edge_obj = cross_item.edgeObj;
398
- const target_edge_obj = target_item.edgeObj;
399
- let target_edge_name = "rightEdge";
400
- let cross_edge_name = "leftEdge";
401
- switch (direction) {
402
- case "left":
403
- target_edge_name = "rightEdge";
404
- cross_edge_name = "leftEdge";
405
- break;
406
- case "right":
407
- target_edge_name = "leftEdge";
408
- cross_edge_name = "rightEdge";
409
- break;
410
- case "top":
411
- target_edge_name = "bottomEdge";
412
- cross_edge_name = "topEdge";
413
- break;
414
- case "bottom":
415
- cross_edge_name = "bottomEdge";
416
- target_edge_name = "topEdge";
417
- break;
418
- default:
419
- console.log(
420
- `_CheckNeighborItemMatching unknown direction:${direction}`
421
- );
422
- break;
423
- }
424
- // console.log(
425
- // "cchtest exclude edge",
426
- // cross_item.index,
427
- // target_item.index,
428
- // cross_edge_name,
429
- // target_edge_name,
430
- // cross_edge_obj[cross_edge_name].range.Clone().Ranges,
431
- // target_edge_obj[target_edge_name].range.Clone().Ranges
432
- // );
433
-
434
- const target_edge_range_clone =
435
- target_edge_obj[target_edge_name].range.Clone();
436
- target_edge_obj[target_edge_name].range.ExcludeRanges(
437
- cross_edge_obj[cross_edge_name].range
438
- );
439
- cross_edge_obj[cross_edge_name].range.ExcludeRanges(
440
- target_edge_range_clone
441
- );
442
-
443
- // console.log(
444
- // "cchtest after exclude",
445
- // cross_edge_obj[cross_edge_name].range.Clone().Ranges,
446
- // target_edge_obj[target_edge_name].range.Clone().Ranges
447
- // );
448
-
449
- if (target_edge_obj[target_edge_name].range.IsEmpty()) {
450
- // 完全匹配,更新该边的状态为已被占用
451
- target_edge_obj[target_edge_name] = null;
452
- }
453
-
454
- if (cross_edge_obj[cross_edge_name].range.IsEmpty()) {
455
- // 清除该边
456
- cross_edge_obj[cross_edge_name] = null;
457
- }
458
- }
459
-
460
- _FindNearestNeighbor(cross_item) {
461
- const cross_edge_obj = cross_item.edgeObj;
462
-
463
- let nearest_left_index = -1;
464
- let nearest_right_index = -1;
465
- let nearest_top_index = -1;
466
- let nearest_bottom_index = -1;
467
- let left_distance = -1;
468
- let right_distance = -1;
469
- let top_distance = -1;
470
- let bottom_distance = -1;
471
-
472
- for (let j = 0; j < this._NotOccupiedEdgeList.length; j++) {
473
- const target_item = this._NotOccupiedEdgeList[j];
474
- const target_edge_obj = target_item.edgeObj;
475
- if (cross_item === target_item) {
476
- continue;
477
- }
478
- // 左边最近项
479
- if (
480
- cross_edge_obj.leftEdge !== null &&
481
- target_edge_obj.rightEdge !== null
482
- ) {
483
- if (
484
- cross_edge_obj.leftEdge.x >= target_edge_obj.rightEdge.x &&
485
- cross_edge_obj.leftEdge.range.IsInterAct(
486
- target_edge_obj.rightEdge.range
487
- )
488
- ) {
489
- // 在其左侧,且有交叉,才为neighbor
490
- // 计算最短距离
491
- if (left_distance === -1) {
492
- left_distance =
493
- cross_edge_obj.leftEdge.x - target_edge_obj.rightEdge.x;
494
- nearest_left_index = j;
495
- continue;
496
- } else if (
497
- left_distance >
498
- cross_edge_obj.leftEdge.x - target_edge_obj.rightEdge.x
499
- ) {
500
- left_distance =
501
- cross_edge_obj.leftEdge.x - target_edge_obj.rightEdge.x;
502
- nearest_left_index = j;
503
- continue;
504
- }
505
- }
506
- }
507
- // 右边最近项
508
- if (
509
- cross_edge_obj.rightEdge !== null &&
510
- target_edge_obj.leftEdge !== null
511
- ) {
512
- if (
513
- cross_edge_obj.rightEdge.x <= target_edge_obj.leftEdge.x &&
514
- cross_edge_obj.rightEdge.range.IsInterAct(
515
- target_edge_obj.leftEdge.range
516
- )
517
- ) {
518
- // 在其左侧,且有交叉,才为neighbor
519
- // 计算最短距离
520
- if (right_distance === -1) {
521
- right_distance =
522
- target_edge_obj.leftEdge.x - cross_edge_obj.rightEdge.x;
523
- nearest_right_index = j;
524
- continue;
525
- } else if (
526
- right_distance >
527
- target_edge_obj.leftEdge.x - cross_edge_obj.rightEdge.x
528
- ) {
529
- right_distance =
530
- target_edge_obj.leftEdge.x - cross_edge_obj.rightEdge.x;
531
- nearest_right_index = j;
532
- continue;
533
- }
534
- }
535
- }
536
-
537
- // 上边最近项
538
- if (
539
- cross_edge_obj.topEdge !== null &&
540
- target_edge_obj.bottomEdge !== null
541
- ) {
542
- if (
543
- cross_edge_obj.topEdge.y >= target_edge_obj.bottomEdge.y &&
544
- cross_edge_obj.topEdge.range.IsInterAct(
545
- target_edge_obj.bottomEdge.range
546
- )
547
- ) {
548
- // 在其左侧,且有交叉,才为neighbor
549
- // 计算最短距离
550
- if (top_distance === -1) {
551
- top_distance =
552
- cross_edge_obj.topEdge.y - target_edge_obj.bottomEdge.y;
553
- nearest_top_index = j;
554
- continue;
555
- } else if (
556
- top_distance >
557
- cross_edge_obj.topEdge.y - target_edge_obj.bottomEdge.y
558
- ) {
559
- top_distance =
560
- cross_edge_obj.topEdge.y - target_edge_obj.bottomEdge.y;
561
- nearest_top_index = j;
562
- continue;
563
- }
564
- }
565
- }
566
- // 下边的最近项
567
- if (
568
- cross_edge_obj.bottomEdge !== null &&
569
- target_edge_obj.topEdge !== null
570
- ) {
571
- if (
572
- cross_edge_obj.bottomEdge.y <= target_edge_obj.topEdge.y &&
573
- cross_edge_obj.bottomEdge.range.IsInterAct(
574
- target_edge_obj.topEdge.range
575
- )
576
- ) {
577
- // 在其左侧,且有交叉,才为neighbor
578
- // 计算最短距离
579
- if (bottom_distance === -1) {
580
- bottom_distance =
581
- target_edge_obj.topEdge.y - cross_edge_obj.bottomEdge.y;
582
- nearest_bottom_index = j;
583
- continue;
584
- } else if (
585
- bottom_distance >
586
- target_edge_obj.topEdge.y - cross_edge_obj.bottomEdge.y
587
- ) {
588
- bottom_distance =
589
- target_edge_obj.topEdge.y - cross_edge_obj.bottomEdge.y;
590
- nearest_bottom_index = j;
591
- continue;
592
- }
593
- }
594
- }
595
- }
596
-
597
- return {
598
- left: nearest_left_index,
599
- right: nearest_right_index,
600
- top: nearest_top_index,
601
- bottom: nearest_bottom_index,
602
- };
603
- }
604
-
605
- _TryUpdateItemNeighbor(tmp_neighbor, direction, cross_item, target_item) {
606
- const key_map = {
607
- target: {
608
- left: "right",
609
- right: "left",
610
- top: "bottom",
611
- bottom: "top",
612
- },
613
- cross: {
614
- left: "left",
615
- right: "right",
616
- top: "top",
617
- bottom: "bottom",
618
- },
619
- };
620
- let cross_neighbor_key = key_map.cross[direction];
621
- let target_neighbor_key = key_map.target[direction];
622
- if (!cross_neighbor_key || !target_neighbor_key) {
623
- console.error("_TryUpdateItemNeighbor: undefined direction", direction);
624
- }
625
-
626
- const target_index = target_item.index;
627
- const cross_item_index = cross_item.index;
628
- const template_list = this._Template.List;
629
- if (this._IfBlockedByOtherNeighbor(direction, cross_item, target_item)) {
630
- if (!tmp_neighbor) {
631
- this._CheckNeighborItemMatching(direction, cross_item, target_item);
632
- // 查看是否有交集,有交集,更新临近边
633
- template_list[target_index].neighborIndexList[target_neighbor_key].push(
634
- cross_item_index
635
- );
636
- template_list[cross_item_index].neighborIndexList[
637
- cross_neighbor_key
638
- ].push(target_index);
639
- template_list[target_index].tmpNeighborIndexList[target_neighbor_key] =
640
- [];
641
- template_list[cross_item_index].tmpNeighborIndexList[
642
- cross_neighbor_key
643
- ] = [];
644
- } else {
645
- template_list[target_index].tmpNeighborIndexList[
646
- target_neighbor_key
647
- ].push(cross_item_index);
648
- template_list[cross_item_index].tmpNeighborIndexList[
649
- cross_neighbor_key
650
- ].push(target_index);
651
- }
652
- }
653
- }
654
-
655
- _CalculateNeighborItem(tmp_neighbor) {
656
- const template_list = this._Template.List;
657
- // 更新邻近边,以及未占用的边
658
- for (let i = 0; i < this._NotOccupiedEdgeList.length; i++) {
659
- const cross_item = this._NotOccupiedEdgeList[i];
660
- const cross_edge_obj = cross_item.edgeObj;
661
- const cross_item_index = cross_item.index;
662
- if (
663
- cross_edge_obj.leftEdge == null &&
664
- cross_edge_obj.rightEdge == null &&
665
- cross_edge_obj.topEdge == null &&
666
- cross_edge_obj.bottomEdge == null
667
- ) {
668
- this._NotOccupiedEdgeList.splice(i, 1);
669
- i--;
670
- continue;
671
- }
672
- if (this._Template.Orient.type === VERTICAL) {
673
- // 如果下边被占用,则将其从列表中删除
674
- // if (cross_edge_obj.bottomEdge === null) {
675
- // this._NotOccupiedEdgeList.splice(i, 1);
676
- // i--;
677
- // continue;
678
- // }
679
- // 临时邻居不触发fence edge
680
- // 超过fenceedge范围,不作为对比相
681
- if (
682
- !tmp_neighbor &&
683
- cross_edge_obj.bottomEdge?.y > this._FenceEdge.StartY
684
- ) {
685
- continue;
686
- }
687
- } else {
688
- // 如果右边被占用,则将其从列表中删除
689
- // if (cross_edge_obj.rightEdge === null) {
690
- // this._NotOccupiedEdgeList.splice(i, 1);
691
- // i--;
692
- // continue;
693
- // }
694
- // 临时邻居不触发fence edge
695
- // 超过fenceedge范围,不作为对比相
696
- if (
697
- !tmp_neighbor &&
698
- cross_edge_obj.rightEdge?.x > this._FenceEdge.StartX
699
- ) {
700
- continue;
701
- }
702
- }
703
-
704
- // 查找与交叉项上下左右最近的各项目,做交叉
705
- const neighbor = this._FindNearestNeighbor(cross_item);
706
- // console.log(
707
- // "%c cchtest find nearest neighbor",
708
- // "color:red;",
709
- // cross_item.index,
710
- // {
711
- // left: this._NotOccupiedEdgeList[neighbor.left]?.index,
712
- // right: this._NotOccupiedEdgeList[neighbor.right]?.index,
713
- // top: this._NotOccupiedEdgeList[neighbor.top]?.index,
714
- // bottom: this._NotOccupiedEdgeList[neighbor.bottom]?.index,
715
- // }
716
- // );
717
-
718
- for (let key in neighbor) {
719
- //更新每个方向找到的邻居
720
- if (neighbor[key] !== -1) {
721
- const target_item = this._NotOccupiedEdgeList[neighbor[key]];
722
- this._TryUpdateItemNeighbor(
723
- tmp_neighbor,
724
- key,
725
- cross_item,
726
- target_item
727
- );
728
- }
729
- }
730
- }
731
- }
732
-
733
- /**
734
- * 计算相邻节点(包含占位符)
735
- *
736
- * @func _TryCalculateNeighborItem
737
- * @memberof Forge.MetroLayout
738
- * @param index Template 索引
739
- * @param {int} x_pos
740
- * @param {int} y_pos
741
- * @param {int} width
742
- * @param {int} height
743
- * @private
744
- */
745
- _TryCalculateNeighborItem(index, x_pos, y_pos, width, height) {
746
- const cur_not_occupied_edge = {
747
- index,
748
- edgeObj: {
749
- leftEdge: {
750
- x: x_pos,
751
- range: new RangesModel(y_pos, y_pos + height - 1),
752
- },
753
- rightEdge: {
754
- x: x_pos + width,
755
- range: new RangesModel(y_pos, y_pos + height - 1),
756
- },
757
- topEdge: {
758
- y: y_pos,
759
- range: new RangesModel(x_pos, x_pos + width - 1),
760
- },
761
- bottomEdge: {
762
- y: y_pos + height,
763
- range: new RangesModel(x_pos, x_pos + width - 1),
764
- },
765
- },
766
- };
767
- // 边界处理,重置leftEdge和topEdge;
768
- if (x_pos === 0) {
769
- cur_not_occupied_edge.edgeObj.leftEdge = null;
770
- }
771
- if (y_pos === 0) {
772
- cur_not_occupied_edge.edgeObj.topEdge = null;
773
- }
774
- let new_fance = false;
775
- // 边界处理,重置bootomEdge和rightEdge
776
- const width_max = this._Template.Orient.widthMax;
777
- let new_fence_edge_start_x = this._FenceEdge.StartX;
778
- let new_fence_edge_start_y = this._FenceEdge.StartY;
779
- if (this._Template.Orient.type === VERTICAL) {
780
- if (x_pos + width === width_max) {
781
- cur_not_occupied_edge.edgeObj.rightEdge = null;
782
- }
783
- // 判断FenceEdge,是否产生新的fence
784
- if (y_pos > this._FenceEdge.StartY) {
785
- // 产生新的Fence
786
- new_fance = true;
787
- new_fence_edge_start_y = y_pos;
788
- }
789
- } else {
790
- if (y_pos + height === width_max) {
791
- cur_not_occupied_edge.edgeObj.bottomEdge = null;
792
- }
793
- // 判断FenceEdge,是否产生新的fence
794
- if (x_pos > this._FenceEdge.StartX) {
795
- // 产生新的Fence
796
- new_fance = true;
797
- new_fence_edge_start_x = x_pos;
798
- }
799
- }
800
- this._FenceEdge.StartX = new_fence_edge_start_x;
801
- this._FenceEdge.StartY = new_fence_edge_start_y;
802
- // 添加节点
803
- this._NotOccupiedEdgeList.push(cur_not_occupied_edge);
804
- // 如果产生新fence,则对NotOccupiedEdgeList进行相邻节点计算
805
- if (new_fance) {
806
- this._CalculateNeighborItem();
807
- }
808
- }
809
-
810
- _UpdateLastFenceEdge() {
811
- const old_fence = this._FenceEdge;
812
- const new_min_fence = { StartX: -1, StartY: -1 };
813
- // 查找最后一条FenceEdge
814
- for (let i = 0; i < this._NotOccupiedEdgeList.length; i++) {
815
- const cross_item = this._NotOccupiedEdgeList[i];
816
- const cross_edge_obj = cross_item.edgeObj;
817
- if (this._Template.Orient.type === VERTICAL) {
818
- if (cross_edge_obj.bottomEdge !== null) {
819
- if (cross_edge_obj.bottomEdge.y > old_fence.StartY) {
820
- if (new_min_fence.StartY === -1) {
821
- new_min_fence.StartY = cross_edge_obj.bottomEdge.y;
822
- } else if (cross_edge_obj.bottomEdge.y < new_min_fence.StartY) {
823
- new_min_fence.StartY = cross_edge_obj.bottomEdge.y;
824
- }
825
- }
826
- }
827
- } else {
828
- if (cross_edge_obj.rightEdge !== null) {
829
- if (cross_edge_obj.rightEdge.x > old_fence.StartX) {
830
- if (new_min_fence.StartX === -1) {
831
- new_min_fence.StartX = cross_edge_obj.rightEdge.x;
832
- } else if (cross_edge_obj.rightEdge.y < new_min_fence.StartX) {
833
- new_min_fence.StartX = cross_edge_obj.rightEdge.x;
834
- }
835
- }
836
- }
837
- }
838
- }
839
-
840
- this._FenceEdge = new_min_fence;
841
- }
842
-
843
- ParseTemplateItem(item_obj, data_obj) {
844
- const template_item = getTemplateItem(item_obj, data_obj);
845
- // Layout template items
846
- const fence_stack = this._FenceStack;
847
- const item_id = template_item.id;
848
- const item_width = template_item.width;
849
- const item_height = template_item.height;
850
- // Add view to contents view layer
851
- let x_pos;
852
- let y_pos;
853
- let x_width;
854
- let y_width;
855
- let item_key_pos = 0;
856
- let item_second_pos = 0;
857
-
858
- let item_key_width = 0;
859
- let item_second_width = 0;
860
- let item_key_margin = 0;
861
- let item_second_margin = 0;
862
- if (this._Template.Layout.type === "relative") {
863
- if (this._Template.Orient.type === VERTICAL) {
864
- item_key_width = item_width;
865
- item_second_width = item_height;
866
- item_key_margin = template_item.marginRight;
867
- item_second_margin = template_item.marginBottom;
868
- } else {
869
- item_key_width = item_height;
870
- item_second_width = item_width;
871
- item_key_margin = template_item.marginBottom;
872
- item_second_margin = template_item.marginRight;
873
- }
874
- // Find capability fence in stack
875
- let top_fence = null;
876
- let gap_info = null;
877
- while (fence_stack.length > 0) {
878
- const checking_fence = fence_stack[fence_stack.length - 1];
879
- gap_info = checking_fence.HasGapFor(item_key_width + item_key_margin);
880
- if (gap_info !== null) {
881
- top_fence = checking_fence;
882
- break;
883
- }
884
- fence_stack.pop();
885
- }
886
-
887
- // Layout the item in top fence
888
- if (gap_info !== null) {
889
- item_key_pos = gap_info.startPos;
890
- item_second_pos = top_fence.AheadOffset;
891
- } else {
892
- throw new Error(
893
- `${TAG} item size ${item_width}x${item_height} is greater than widget line max ${this._Template.Orient.widthMax}`
894
- );
895
- // console.error(TAG, "ERROR: coding error, header full gap fence lost");
896
- }
897
-
898
- if (this._Template.Orient.type === VERTICAL) {
899
- x_pos = item_key_pos;
900
- y_pos = item_second_pos;
901
- x_width = item_key_width;
902
- y_width = item_second_width;
903
- } else {
904
- x_pos = item_second_pos;
905
- y_pos = item_key_pos;
906
- x_width = item_second_width;
907
- y_width = item_key_width;
908
- }
909
- } else {
910
- x_pos = template_item.xPos;
911
- y_pos = template_item.yPos;
912
- x_width = item_width;
913
- y_width = item_height;
914
- }
915
-
916
- // Update template item information
917
- template_item.neighborIndexList = {
918
- left: [],
919
- top: [],
920
- right: [],
921
- bottom: [],
922
- };
923
- template_item.tmpNeighborIndexList = {
924
- left: [],
925
- top: [],
926
- right: [],
927
- bottom: [],
928
- };
929
- // 记录历史路径
930
- template_item.pathHistory = {
931
- left: null,
932
- top: null,
933
- right: null,
934
- bottom: null,
935
- };
936
- template_item.xPos = x_pos;
937
- template_item.yPos = y_pos;
938
- template_item.centerXPos = Math.floor(x_pos + x_width / 2) - 1;
939
- template_item.centerYPos = Math.floor(y_pos + y_width / 2) - 1;
940
- //分页相关的计算
941
- let cur_page_number = 0;
942
- let cur_page_head_index = 0;
943
- if (this._Template.List.length > 0) {
944
- const last_item = this._Template.List[this._Template.List.length - 1];
945
- cur_page_number = last_item.pageNumber;
946
- cur_page_head_index = last_item.pageHeadIndex;
947
- let position_key = "xPos";
948
- let size_key = "width";
949
- if (this._Template.Orient.type === VERTICAL) {
950
- position_key = "yPos";
951
- size_key = "height";
952
- }
953
- const cur_page_start =
954
- this._Template.List[cur_page_head_index][position_key];
955
- if (
956
- template_item[position_key] + template_item[size_key] >
957
- cur_page_start + this._PageSize
958
- ) {
959
- //新的页
960
- cur_page_number++;
961
- cur_page_head_index = this._Template.List.length;
962
- }
963
- }
964
-
965
- template_item.pageNumber = cur_page_number;
966
- template_item.pageHeadIndex = cur_page_head_index;
967
- // if (
968
- // this._Template.Orient.type !== VERTICAL &&
969
- // y_pos + y_width === this._Template.Orient.widthMax
970
- // ) {
971
- // template_item.onBottomLine = true;
972
- // }
973
- this._Template.AddItem(template_item);
974
- // Update template item id
975
- if (template_item.focusable) {
976
- this._Template.SetIdsMap(
977
- this._Identity++,
978
- this._Template.List.length - 1
979
- );
980
- }
981
- // 计算相邻项
982
- this._TryCalculateNeighborItem(
983
- this._Template.List.length - 1,
984
- template_item.xPos,
985
- template_item.yPos,
986
- template_item.width + template_item.marginRight,
987
- template_item.height + template_item.marginBottom
988
- );
989
-
990
- const item_second_end_pos =
991
- item_second_pos + item_second_width + item_second_margin - 1;
992
-
993
- // Ensure header fence
994
- if (fence_stack[0].AheadOffset <= item_second_end_pos) {
995
- // Need new header fence
996
- fence_stack.splice(
997
- 0,
998
- 0,
999
- new Fence(0, 0, this._Template.Orient.widthMax, item_second_end_pos + 1)
1000
- );
1001
- }
1002
-
1003
- // Mark gap used in fence stack
1004
- let end_fence_existed = false;
1005
- let far_away_end_fence_existed = false;
1006
- let one_ahead_last_fence_idx = -1;
1007
- for (let fence_idx = fence_stack.length - 1; fence_idx >= 0; fence_idx--) {
1008
- if (fence_stack[fence_idx].AheadOffset <= item_second_end_pos) {
1009
- if (fence_stack[fence_idx].AheadOffset === item_second_end_pos)
1010
- end_fence_existed = true;
1011
- const left_gaps = fence_stack[fence_idx].MarkGapUsed(
1012
- item_key_pos,
1013
- item_key_width + item_key_margin
1014
- );
1015
- if (left_gaps === 0) {
1016
- // remove fence
1017
- fence_stack.splice(fence_idx, 1);
1018
- }
1019
- } else {
1020
- if (fence_stack[fence_idx].AheadOffset === item_second_end_pos + 1)
1021
- far_away_end_fence_existed = true;
1022
- one_ahead_last_fence_idx = fence_idx;
1023
- break;
1024
- }
1025
- }
1026
-
1027
- const fence_ahead_offset = item_second_end_pos;
1028
- // Create fences
1029
- if (!end_fence_existed) {
1030
- // Build fence edge which close to the beginning
1031
- if (one_ahead_last_fence_idx + 1 <= fence_stack.length - 1) {
1032
- const fence =
1033
- fence_stack[one_ahead_last_fence_idx + 1].Fork(fence_ahead_offset);
1034
- fence_stack.splice(one_ahead_last_fence_idx + 1, 0, fence);
1035
- }
1036
- }
1037
- if (!far_away_end_fence_existed) {
1038
- // Build fence edge which far away from the beginning
1039
- if (one_ahead_last_fence_idx > 0) {
1040
- const fence = fence_stack[one_ahead_last_fence_idx].Fork(
1041
- fence_ahead_offset + 1
1042
- );
1043
- fence_stack.splice(one_ahead_last_fence_idx + 1, 0, fence);
1044
- }
1045
- }
1046
- return template_item;
1047
- }
1048
-
1049
- GetItemById(id) {
1050
- return this._Template.List[this._Template.IdsMap[id]];
1051
- }
1052
-
1053
- GetLastId() {
1054
- return this._Template.GetLastId();
1055
- }
1056
-
1057
- GetItem(index) {
1058
- return index >= 0
1059
- ? this._Template.List[index]
1060
- : this._Template.List[this._Template.List.length + index];
1061
- }
1062
-
1063
- GetLength() {
1064
- return this._Template.List.length;
1065
- }
1066
-
1067
- IdToIndex(id) {
1068
- const index = this._Template.IdsMap[id];
1069
- if (typeof index !== "undefined") {
1070
- return index;
1071
- } else {
1072
- return -1;
1073
- }
1074
- }
1075
-
1076
- /**
1077
- * 查看Ids中是否有能够获得焦点的项
1078
- * @param ids
1079
- * @returns {boolean}
1080
- * @private
1081
- */
1082
- _CheckIdsHasFocusable(ids) {
1083
- const template_list = this._Template.List;
1084
- let found = false;
1085
- for (let i = 0; i < ids.length; i++) {
1086
- const id = ids[i];
1087
- if (template_list[id].focusable) {
1088
- found = true;
1089
- break;
1090
- }
1091
- }
1092
- return found;
1093
- }
1094
-
1095
- _IsInNeighborList(neighbor_index_list, target_idx) {
1096
- let found = false;
1097
- for (let i = neighbor_index_list.length - 1; i >= 0; i--) {
1098
- if (neighbor_index_list[i] === target_idx) {
1099
- found = true;
1100
- break;
1101
- }
1102
- }
1103
- return found;
1104
- }
1105
-
1106
- _GetValidNeighborIndex(src_item_id, last_item_id, neighbor_direction) {
1107
- const template_list = this._Template.List;
1108
- let valid_id = -1;
1109
- const item = template_list[last_item_id];
1110
- const src_item = template_list[src_item_id];
1111
- let first_ids = null;
1112
- let second_ids = null;
1113
-
1114
- if (neighbor_direction === "top") {
1115
- // 查找左侧邻居节点
1116
- second_ids = item.neighborIndexList.left;
1117
- first_ids = item.neighborIndexList.right;
1118
- } else {
1119
- // left, right
1120
- second_ids = item.neighborIndexList.right;
1121
- first_ids = item.neighborIndexList.left;
1122
- }
1123
-
1124
- if (first_ids.length > 0) {
1125
- for (let i = 0; i < first_ids.length; i++) {
1126
- const id = first_ids[i];
1127
- const check_item = template_list[id];
1128
- if (
1129
- check_item.focusable &&
1130
- ((neighbor_direction === "top" &&
1131
- check_item.yPos + check_item.height <= src_item.yPos) ||
1132
- (neighbor_direction === "bottom" &&
1133
- check_item.yPos >= src_item.yPos + src_item.height))
1134
- ) {
1135
- // 并且在src_item_id之上或之下
1136
- valid_id = id;
1137
- break;
1138
- }
1139
- }
1140
- }
1141
- if (valid_id === -1) {
1142
- if (second_ids.length > 0) {
1143
- for (let i = 0; i < second_ids.length; i++) {
1144
- const id = second_ids[i];
1145
- const check_item = template_list[id];
1146
- if (
1147
- check_item.focusable &&
1148
- ((neighbor_direction === "top" &&
1149
- check_item.yPos + check_item.height <= src_item.yPos) ||
1150
- (neighbor_direction === "bottom" &&
1151
- check_item.yPos >= src_item.yPos + src_item.height))
1152
- ) {
1153
- // 并且在src_item_id之上或之下
1154
- valid_id = id;
1155
- break;
1156
- }
1157
- }
1158
- }
1159
- }
1160
- return valid_id;
1161
- }
1162
-
1163
- _FindFocusableNeighbor(direction, item) {
1164
- if (
1165
- item.neighborIndexList[direction].length > 0 &&
1166
- !this._CheckIdsHasFocusable(item.neighborIndexList[direction])
1167
- ) {
1168
- const last_item_id =
1169
- item.neighborIndexList[direction][
1170
- item.neighborIndexList[direction].length - 1
1171
- ];
1172
- const idx = this._GetValidNeighborIndex(item.id, last_item_id, direction); // 查找其左右邻居
1173
- if (idx !== -1) {
1174
- item.neighborIndexList[direction] = []; // 清除无效项
1175
- item.neighborIndexList[direction].push(idx);
1176
- }
1177
- }
1178
- }
1179
-
1180
- CalculateNeighborWhenAddStop() {
1181
- // Update Last Fence Edge(更新最后一行的fence edge)
1182
- this._UpdateLastFenceEdge();
1183
- // Last fence edge to get neighbor
1184
- this._CalculateNeighborItem();
1185
- this._CalculateNeighborItem(true);
1186
- const template_list = this._Template.List;
1187
- // 若下一行或者上一行的邻居都为非焦点项,则查找向下向上有效项
1188
- let last_item_index = template_list.length - 1;
1189
- let last_item = template_list[last_item_index];
1190
- // 查找有效的最后项
1191
- for (let i = template_list.length - 1; i >= 0; i--) {
1192
- last_item = template_list[i];
1193
- if (last_item.focusable) {
1194
- last_item_index = i;
1195
- break;
1196
- }
1197
- }
1198
- //处理找到的neighbor均是占位符的情况
1199
- for (let j = template_list.length - 1; j >= 0; j--) {
1200
- const item = template_list[j];
1201
- if (item.focusable) {
1202
- this._FindFocusableNeighbor("bottom", item);
1203
- this._FindFocusableNeighbor("top", item);
1204
- this._FindFocusableNeighbor("left", item);
1205
- this._FindFocusableNeighbor("right", item);
1206
- }
1207
- }
1208
- }
1209
-
1210
- /**
1211
- * 获取指定id的下一个Item
1212
- *
1213
- * @public
1214
- * @func GetNextItem
1215
- * @memberof Forge.MetroLayout
1216
- * @instance
1217
- * @param {int} base_item_id Item的Id
1218
- * @param {int} vertical_offset 纵向偏移(-1为向上,1为向下)
1219
- * @param {int} horizontal_offset 横向偏移(-1为向左,1为向右)
1220
- * @param {int} focus_move_type 焦点移动设置
1221
- * @return {int} 下一个Item的Id,-1为该方向未找到Item(到达边缘)
1222
- * */
1223
- GetNextItem(
1224
- base_item_id,
1225
- vertical_offset,
1226
- horizontal_offset,
1227
- focus_move_type
1228
- ) {
1229
- if (vertical_offset === 0 && horizontal_offset === 0)
1230
- console.log("GetNextItem(): offset is 0");
1231
- // Forge.ThrowError("GetNextItem(): offset is 0");
1232
-
1233
- if (vertical_offset !== 0 && horizontal_offset !== 0) {
1234
- console.log(
1235
- "GetNextItem(): not support change vertical and horizontal at the same time"
1236
- );
1237
- // Forge.ThrowError("GetNextItem(): not support change vertical and horizontal and the same time");
1238
- }
1239
-
1240
- const item_index = this.IdToIndex(base_item_id);
1241
- const offset = vertical_offset !== 0 ? vertical_offset : horizontal_offset;
1242
- let next_template_item = this._GetNextItem(
1243
- item_index,
1244
- offset,
1245
- vertical_offset !== 0
1246
- );
1247
- const is_vertical = this._Template.Orient.type === VERTICAL;
1248
-
1249
- if (next_template_item === null) {
1250
- // 在次方向的焦点移动才会loop
1251
- if (
1252
- is_vertical &&
1253
- focus_move_type & FocusMoveType.ROW_LOOP &&
1254
- horizontal_offset != 0
1255
- ) {
1256
- next_template_item = this._GetNextLoopItem(
1257
- item_index,
1258
- horizontal_offset,
1259
- is_vertical
1260
- );
1261
- } else if (
1262
- !is_vertical &&
1263
- focus_move_type & FocusMoveType.COLUMN_LOOP &&
1264
- vertical_offset != 0
1265
- ) {
1266
- next_template_item = this._GetNextLoopItem(
1267
- item_index,
1268
- vertical_offset,
1269
- is_vertical
1270
- );
1271
- }
1272
- }
1273
-
1274
- if (next_template_item === null) {
1275
- // 临近行的焦点移动
1276
- if (
1277
- vertical_offset != 0 &&
1278
- focus_move_type & FocusMoveType.ROW_FIND_NEAR
1279
- ) {
1280
- next_template_item = this._GetNearLineItem(item_index, vertical_offset, true);
1281
- } else if (
1282
- horizontal_offset != 0 &&
1283
- focus_move_type & FocusMoveType.COLUMN_FIND_NEAR
1284
- ) {
1285
- next_template_item = this._GetNearLineItem(item_index, horizontal_offset, false);
1286
- }
1287
- }
1288
-
1289
- return next_template_item;
1290
- }
1291
-
1292
- _GetNextItem(index, offset, vertical) {
1293
- const template_list = this._Template.List;
1294
- const base_item = template_list[index];
1295
- let check_anchor = -1;
1296
- if (base_item.findNextAnchor) {
1297
- //有自定义的 anchor
1298
- // TODO 优化
1299
- if (vertical) {
1300
- if (offset > 0) {
1301
- if (base_item.findNextAnchor.bottom) {
1302
- check_anchor =
1303
- base_item.xPos +
1304
- base_item.findNextAnchor.bottom *
1305
- (base_item.width + base_item.marginRight);
1306
- }
1307
- } else {
1308
- if (base_item.findNextAnchor.top) {
1309
- check_anchor =
1310
- base_item.xPos +
1311
- base_item.findNextAnchor.top *
1312
- (base_item.width + base_item.marginRight);
1313
- }
1314
- }
1315
- } else {
1316
- if (offset > 0) {
1317
- if (base_item.findNextAnchor.right) {
1318
- check_anchor =
1319
- base_item.yPos +
1320
- base_item.findNextAnchor.right *
1321
- (base_item.height + base_item.marginBottom);
1322
- }
1323
- } else {
1324
- if (base_item.findNextAnchor.left) {
1325
- check_anchor =
1326
- base_item.yPos +
1327
- base_item.findNextAnchor.left *
1328
- (base_item.height + base_item.marginBottom);
1329
- }
1330
- }
1331
- }
1332
- }
1333
- if (check_anchor < 0) {
1334
- check_anchor = vertical ? base_item.centerXPos : base_item.centerYPos;
1335
- }
1336
- const pos_key = vertical ? "xPos" : "yPos";
1337
- const size_key = vertical ? "width" : "height";
1338
- let direction = vertical ? "top" : "left";
1339
- let path_history_direction = vertical ? "bottom" : "right";
1340
- // Normalize offset
1341
- if (offset > 0) {
1342
- path_history_direction = vertical ? "top" : "left";
1343
- direction = vertical ? "bottom" : "right";
1344
- }
1345
- const not_record_history_direction = vertical ? "bottom" : "right";
1346
- const not_record_history_orient = vertical ? HORIZONTAL : VERTICAL;
1347
- let last_item_index = template_list.length - 1;
1348
- const orient_type = this._Template.Orient.type;
1349
- // 查找有效的最后项
1350
- for (let i = template_list.length - 1; i >= 0; i--) {
1351
- const last_item = template_list[i];
1352
- if (last_item.focusable) {
1353
- last_item_index = i;
1354
- break;
1355
- }
1356
- }
1357
- let found = false;
1358
- let next_index = -1;
1359
- let path_history_index = null;
1360
- if (this._SupportHistoryPath && !base_item.findNextAnchor) {
1361
- path_history_index = template_list[index].pathHistory[direction];
1362
- }
1363
- if (path_history_index === null) {
1364
- // 无历史路径
1365
- // 获得邻近点列表
1366
- let neighbor_list = template_list[index].neighborIndexList[direction];
1367
- if (template_list[index].tmpNeighborIndexList[direction].length > 0) {
1368
- neighbor_list = neighbor_list.concat(
1369
- template_list[index].tmpNeighborIndexList[direction]
1370
- );
1371
- }
1372
- if (neighbor_list.length === 1) {
1373
- next_index = neighbor_list[0];
1374
- if (
1375
- last_item_index !== index ||
1376
- direction !== not_record_history_direction ||
1377
- orient_type !== not_record_history_orient
1378
- ) {
1379
- // horizontal last_item_index bottom 不记历史路径
1380
- template_list[index].pathHistory[direction] = next_index; // 更新历史路径
1381
- template_list[next_index].pathHistory[path_history_direction] = index; // 更新历史路径
1382
- }
1383
- found = true;
1384
- } else {
1385
- for (let i = 0; i < neighbor_list.length; i++) {
1386
- next_index = neighbor_list[i];
1387
- const checking_item = template_list[next_index];
1388
- if (
1389
- check_anchor <=
1390
- checking_item[pos_key] + checking_item[size_key] - 1 &&
1391
- check_anchor >= checking_item[pos_key]
1392
- ) {
1393
- if (
1394
- last_item_index !== index ||
1395
- direction !== not_record_history_direction ||
1396
- orient_type !== not_record_history_orient
1397
- ) {
1398
- // horizontal last_item_index bottom 不记历史路径
1399
- template_list[index].pathHistory[direction] = next_index; // 更新历史路径
1400
- template_list[next_index].pathHistory[path_history_direction] =
1401
- index; // 更新历史路径
1402
- }
1403
- found = true;
1404
- break;
1405
- }
1406
- }
1407
- // 若未找到中间位置的项目
1408
- // 若找到了项目,但是该项为非 focusable
1409
- // 则使用neighbor list中focusable项
1410
- if (!found || !template_list[next_index].focusable) {
1411
- for (let i = 0; i < neighbor_list.length; i++) {
1412
- const neighbor_index = neighbor_list[i];
1413
- const checking_item = template_list[neighbor_index];
1414
- if (checking_item.focusable) {
1415
- if (
1416
- last_item_index !== index ||
1417
- direction !== not_record_history_direction ||
1418
- orient_type !== not_record_history_orient
1419
- ) {
1420
- // horizontal last_item_index bottom 不记历史路径
1421
- template_list[index].pathHistory[direction] = next_index; // 更新历史路径
1422
- template_list[next_index].pathHistory[path_history_direction] =
1423
- index; // 更新历史路径
1424
- }
1425
- next_index = neighbor_index;
1426
- found = true;
1427
- break;
1428
- }
1429
- }
1430
- }
1431
- }
1432
- } else {
1433
- next_index = path_history_index;
1434
- if (
1435
- last_item_index !== index ||
1436
- direction !== not_record_history_direction ||
1437
- orient_type !== not_record_history_orient
1438
- ) {
1439
- // horizontal last_item_index bottom 不记历史路径
1440
- template_list[next_index].pathHistory[path_history_direction] = index; // 更新历史路径
1441
- }
1442
- found = true;
1443
- }
1444
-
1445
- if (found) {
1446
- if (!template_list[next_index].focusable) {
1447
- // 如果是占位符,则查找占位符的下一个
1448
- return this._GetNextItem(next_index, offset, vertical);
1449
- }
1450
- return template_list[next_index];
1451
- }
1452
- return null;
1453
- }
1454
-
1455
- _GetItemDistance(item1, item2) {
1456
- return (
1457
- Math.pow(item1.centerXPos - item2.centerXPos, 2) +
1458
- Math.pow(item1.centerYPos - item2.centerYPos, 2)
1459
- );
1460
- }
1461
-
1462
- _GetTotalNeighbor(index, direction) {
1463
- const item = this._Template.List[index];
1464
- return item.neighborIndexList[direction].concat(
1465
- item.tmpNeighborIndexList[direction]
1466
- );
1467
- }
1468
-
1469
- _GetNearestItem(target_item_index, item_index_list) {
1470
- let nearest_index = -1,
1471
- min_distance = Number.POSITIVE_INFINITY;
1472
- let target_item = this._Template.List[target_item_index];
1473
- for (let i of item_index_list) {
1474
- const d = this._GetItemDistance(this._Template.List[i], target_item);
1475
- if (d < min_distance) {
1476
- nearest_index = i;
1477
- min_distance = d;
1478
- }
1479
- }
1480
- return nearest_index;
1481
- }
1482
-
1483
- _GetNextLoopItem(index, offset, is_vertical) {
1484
- const template_list = this._Template.List;
1485
- const base_item = template_list[index];
1486
- let search_direction = is_vertical ? "right" : "bottom";
1487
- let start_direction = is_vertical ? "top" : "left";
1488
- if (offset > 0) {
1489
- search_direction = is_vertical ? "left" : "top";
1490
- start_direction = is_vertical ? "bottom" : "right";
1491
- }
1492
- let target_index = -1;
1493
- let focusable_target = -1;
1494
- let start_index = -1;
1495
- let neighbor_list = [];
1496
- //寻找下一列的起始item
1497
- neighbor_list = this._GetTotalNeighbor(index, search_direction);
1498
- while (start_index < 0 && neighbor_list.length > 0) {
1499
- for (let i of neighbor_list) {
1500
- if (this._GetTotalNeighbor(i, start_direction).length > 0) {
1501
- start_index = i;
1502
- break;
1503
- } else {
1504
- //TODO 是否要用递归
1505
- neighbor_list = this._GetTotalNeighbor(i, search_direction);
1506
- }
1507
- }
1508
- }
1509
- if (start_index >= 0) {
1510
- neighbor_list = this._GetTotalNeighbor(start_index, start_direction);
1511
-
1512
- //寻找最近的neighbor
1513
- let nearest_index = -1,
1514
- min_distance = Number.POSITIVE_INFINITY;
1515
- for (let i of neighbor_list) {
1516
- const d = this._GetItemDistance(template_list[i], base_item);
1517
- if (d < min_distance) {
1518
- nearest_index = i;
1519
- min_distance = d;
1520
- }
1521
- }
1522
-
1523
- neighbor_list = this._GetTotalNeighbor(nearest_index, search_direction);
1524
- while (neighbor_list.length > 0) {
1525
- target_index = this._GetNearestItem(nearest_index, neighbor_list);
1526
- if (template_list[target_index].focusable) {
1527
- focusable_target = target_index;
1528
- }
1529
- neighbor_list = this._GetTotalNeighbor(target_index, search_direction);
1530
- }
1531
- if (focusable_target >= 0) {
1532
- return template_list[focusable_target];
1533
- } else if (target_index >= 0) {
1534
- return this._GetNextLoopItem(target_index, offset, is_vertical);
1535
- }
1536
- }
1537
- return null;
1538
- }
1539
-
1540
- //获取临近行的item
1541
- _GetNearLineItem(index, offset, is_vertical) {
1542
- const template_list = this._Template.List;
1543
- let search_direction = is_vertical ? "right" : "bottom";
1544
- let start_direction = is_vertical ? "top" : "left";
1545
- if (offset > 0) {
1546
- search_direction = is_vertical ? "left" : "top";
1547
- start_direction = is_vertical ? "bottom" : "right";
1548
- }
1549
- let start_index = -1;
1550
- let neighbor_list = [];
1551
- //寻找下一列的起始item
1552
- neighbor_list = this._GetTotalNeighbor(index, search_direction);
1553
- while (start_index < 0 && neighbor_list.length > 0) {
1554
- for (let i of neighbor_list) {
1555
- const n = this._GetTotalNeighbor(i, start_direction);
1556
- if (n.length > 0) {
1557
- return template_list[this._GetNearestItem(index, n)];
1558
- } else {
1559
- //TODO 是否要用递归
1560
- neighbor_list = this._GetTotalNeighbor(i, search_direction);
1561
- }
1562
- }
1563
- }
1564
- return null;
1565
- }
1566
-
1567
- GetTemplate() {
1568
- return this._Template;
1569
- }
1570
-
1571
- GetVisibleItemList(visibleStartLine, visibleEndLine, search_base_item) {
1572
- if (visibleStartLine > visibleEndLine) {
1573
- // No visible item
1574
- return null;
1575
- }
1576
- //取整以避免starline和endline找不到骑线的item的bug
1577
- visibleStartLine = Math.round(visibleStartLine);
1578
- visibleEndLine = Math.round(visibleEndLine);
1579
- // let search_base_item = this._VisibleRangeSearchBaseItem;
1580
- // if (search_base_item ===null) {
1581
- // search_base_item = this._Template.List[this._Template.IdsMap[0]];
1582
- // }
1583
- let search_base_item_idx = this._Template.IdsMap[search_base_item];
1584
- if (typeof search_base_item_idx === "undefined") search_base_item_idx = 0;
1585
- const common_data = {
1586
- resultStartIdx: -1,
1587
- resultEndIdx: -1,
1588
- enableBackwardSearching: true,
1589
- enableForwardSearching: true,
1590
- checkingStartLinePos: visibleStartLine,
1591
- checkingEndLinePos: visibleEndLine,
1592
- };
1593
- const backward_configure = {
1594
- searchDirect: -1,
1595
- baseIdx: search_base_item_idx,
1596
- checkingStartLineRanges: new RangesModel(),
1597
- startLineRangesFulled: false,
1598
- latestOverStartLineIdx: -1,
1599
- checkingEndLineRanges: new RangesModel(),
1600
- endLineRangesFulled: false,
1601
- latestOverEndLineIdx: -1,
1602
- endSearchingIndex: 0,
1603
- firstStartLineBlockIdx: -1,
1604
- firstEndLineBlockIdx: -1,
1605
- searchToBorder: false,
1606
- common: common_data,
1607
- };
1608
- const forward_configure = {
1609
- searchDirect: 1,
1610
- baseIdx: search_base_item_idx,
1611
- checkingStartLineRanges: new RangesModel(),
1612
- startLineRangesFulled: false,
1613
- latestOverStartLineIdx: -1,
1614
- checkingEndLineRanges: new RangesModel(),
1615
- endLineRangesFulled: false,
1616
- latestOverEndLineIdx: -1,
1617
- endSearchingIndex: this._Template.List.length - 1,
1618
- firstStartLineBlockIdx: -1,
1619
- firstEndLineBlockIdx: -1,
1620
- searchToBorder: false,
1621
- common: common_data,
1622
- };
1623
-
1624
- const is_template_vertical = this._Template.Orient.type === VERTICAL;
1625
- let offset = 0;
1626
- while (
1627
- common_data.enableBackwardSearching ||
1628
- common_data.enableForwardSearching
1629
- ) {
1630
- if (common_data.enableBackwardSearching) {
1631
- this._DoSearching(backward_configure, -offset, is_template_vertical);
1632
- }
1633
-
1634
- if (common_data.enableForwardSearching) {
1635
- this._DoSearching(forward_configure, offset, is_template_vertical);
1636
- }
1637
- offset++;
1638
- }
1639
- // console.log(
1640
- // "GetVisibleItemList [" +
1641
- // JSON.stringify(common_data) +
1642
- // ", " +
1643
- // JSON.stringify(backward_configure) +
1644
- // ", " +
1645
- // JSON.stringify(forward_configure) +
1646
- // "]"
1647
- // );
1648
-
1649
- if (common_data.resultStartIdx < 0) {
1650
- // When start index not found
1651
- // Use just over start line block as start idx
1652
- if (
1653
- backward_configure.latestOverStartLineIdx >= 0 &&
1654
- backward_configure.firstStartLineBlockIdx >= 0
1655
- )
1656
- common_data.resultStartIdx = backward_configure.latestOverStartLineIdx;
1657
- else if (forward_configure.firstStartLineBlockIdx >= 0)
1658
- common_data.resultStartIdx = forward_configure.firstStartLineBlockIdx;
1659
- }
1660
-
1661
- if (common_data.resultEndIdx < 0) {
1662
- // When end index not found
1663
- // Use just over end line block as end idx
1664
- if (
1665
- forward_configure.latestOverEndLineIdx >= 0 &&
1666
- forward_configure.firstEndLineBlockIdx >= 0
1667
- )
1668
- common_data.resultEndIdx = forward_configure.latestOverEndLineIdx;
1669
- else if (backward_configure.firstEndLineBlockIdx >= 0)
1670
- common_data.resultEndIdx = backward_configure.firstEndLineBlockIdx;
1671
- }
1672
- // Recheck if whole contents inside the range
1673
- if (common_data.resultStartIdx < 0 && common_data.resultEndIdx < 0) {
1674
- // Check if whole contents inside the range
1675
- const first_item = this._Template.List[0];
1676
- const first_second_pos = is_template_vertical
1677
- ? first_item.yPos
1678
- : first_item.xPos;
1679
- const last_item = this._Template.List[this._Template.List.length - 1];
1680
- const last_second_pos = is_template_vertical
1681
- ? last_item.yPos
1682
- : last_item.xPos;
1683
- const last_second_width = is_template_vertical
1684
- ? last_item.height
1685
- : last_item.width;
1686
- if (
1687
- first_second_pos > visibleStartLine &&
1688
- last_second_pos + last_second_width < visibleEndLine
1689
- ) {
1690
- common_data.resultStartIdx = 0;
1691
- common_data.resultEndIdx = this._Template.List.length - 1;
1692
- }
1693
- }
1694
- let ret = null;
1695
- if (common_data.resultStartIdx >= 0 || common_data.resultEndIdx >= 0) {
1696
- const start_idx =
1697
- common_data.resultStartIdx >= 0 ? common_data.resultStartIdx : 0;
1698
- const end_idx =
1699
- common_data.resultEndIdx >= 0
1700
- ? common_data.resultEndIdx
1701
- : this._Template.List.length - 1;
1702
- ret = { visibleStart: start_idx, visibleEnd: end_idx };
1703
- }
1704
- return ret;
1705
- }
1706
-
1707
- _DoSearching(configures, offset, be_vertical_template) {
1708
- const check_item = this._Template.List[configures.baseIdx + offset];
1709
- const key_pos = be_vertical_template ? check_item.xPos : check_item.yPos;
1710
- const key_width = be_vertical_template
1711
- ? check_item.width + check_item.marginRight
1712
- : check_item.height + check_item.marginBottom;
1713
- const key_start = Math.round(key_pos);
1714
- const key_end = Math.round(key_pos + key_width - 1);
1715
- const second_pos = be_vertical_template ? check_item.yPos : check_item.xPos;
1716
- const second_width = be_vertical_template
1717
- ? check_item.height + check_item.marginBottom
1718
- : check_item.width + check_item.marginRight;
1719
- const second_start = Math.round(second_pos);
1720
- const second_end = Math.round(second_pos + second_width - 1);
1721
- // console.log(
1722
- // "idx=" +
1723
- // (configures.baseIdx + offset) +
1724
- // " pos=" +
1725
- // second_pos +
1726
- // " posend=" +
1727
- // (second_pos + second_width - 1) +
1728
- // " line_pos=" +
1729
- // configures.common.checkingStartLinePos
1730
- // );
1731
-
1732
- if (
1733
- configures.common.resultStartIdx < 0 &&
1734
- !configures.startLineRangesFulled
1735
- ) {
1736
- let is_range_changed = false;
1737
- if (
1738
- second_start <= configures.common.checkingStartLinePos &&
1739
- second_end >= configures.common.checkingStartLinePos
1740
- ) {
1741
- // Overlap the visbible start line
1742
- configures.latestOverStartLineIdx = configures.baseIdx + offset;
1743
- if (configures.firstStartLineBlockIdx < 0)
1744
- configures.firstStartLineBlockIdx = configures.baseIdx + offset;
1745
- configures.checkingStartLineRanges.Merge(
1746
- new SingleRangeModel(key_start, key_end)
1747
- );
1748
- is_range_changed = true;
1749
- } else if (
1750
- configures.searchDirect < 0 &&
1751
- second_end <= configures.common.checkingStartLinePos
1752
- ) {
1753
- // above the visible start line
1754
- configures.checkingStartLineRanges.Merge(
1755
- new SingleRangeModel(key_start, key_end)
1756
- );
1757
- is_range_changed = true;
1758
- }
1759
-
1760
- if (is_range_changed) {
1761
- const current_acrossed_range =
1762
- configures.checkingStartLineRanges.Ranges[0];
1763
- if (current_acrossed_range) {
1764
- if (this.DebugPrint) {
1765
- if (
1766
- current_acrossed_range.Start <= 0 &&
1767
- current_acrossed_range.End >= this._Template.Orient.widthMax - 1
1768
- ) {
1769
- if (
1770
- current_acrossed_range.End >
1771
- this._Template.Orient.widthMax - 1 ||
1772
- current_acrossed_range.Start < 0
1773
- ) {
1774
- configures.startLineRangesFulled = true;
1775
- }
1776
-
1777
- // Update result start index
1778
- if (configures.searchDirect > 0)
1779
- configures.common.resultStartIdx =
1780
- configures.firstStartLineBlockIdx;
1781
- else
1782
- configures.common.resultStartIdx =
1783
- configures.latestOverStartLineIdx;
1784
-
1785
- if (configures.common.resultStartIdx >= 0)
1786
- configures.common.enableBackwardSearching = false;
1787
- }
1788
- }
1789
- }
1790
- }
1791
- }
1792
- // console.log(
1793
- // "idx=" +
1794
- // (configures.baseIdx + offset) +
1795
- // " pos=" +
1796
- // second_pos +
1797
- // " posend=" +
1798
- // (second_pos + second_width - 1) +
1799
- // " line_pos=" +
1800
- // configures.common.checkingEndLinePos
1801
- // );
1802
- if (configures.common.resultEndIdx < 0 && !configures.endLineRangesFulled) {
1803
- let is_range_changed = false;
1804
- if (
1805
- second_start <= configures.common.checkingEndLinePos &&
1806
- second_end >= configures.common.checkingEndLinePos
1807
- ) {
1808
- // Overlap the visbible end line
1809
- configures.latestOverEndLineIdx = configures.baseIdx + offset;
1810
- if (configures.firstEndLineBlockIdx < 0)
1811
- configures.firstEndLineBlockIdx = configures.baseIdx + offset;
1812
- configures.checkingEndLineRanges.Merge(
1813
- new SingleRangeModel(key_start, key_end)
1814
- );
1815
- is_range_changed = true;
1816
- } else if (
1817
- configures.searchDirect > 0 &&
1818
- second_start >= configures.common.checkingEndLinePos
1819
- ) {
1820
- // below the visible end line
1821
- configures.checkingEndLineRanges.Merge(
1822
- new SingleRangeModel(key_start, key_end)
1823
- );
1824
- is_range_changed = true;
1825
- }
1826
-
1827
- if (is_range_changed) {
1828
- const current_acrossed_range =
1829
- configures.checkingEndLineRanges.Ranges[0];
1830
- if (current_acrossed_range) {
1831
- if (this.DebugPrint) {
1832
- if (
1833
- current_acrossed_range.Start <= 0 &&
1834
- current_acrossed_range.End >= this._Template.Orient.widthMax - 1
1835
- ) {
1836
- if (
1837
- current_acrossed_range.End >
1838
- this._Template.Orient.widthMax - 1 ||
1839
- current_acrossed_range.Start < 0
1840
- ) {
1841
- configures.endLineRangesFulled = true;
1842
- }
1843
-
1844
- // Update end index
1845
- if (configures.searchDirect < 0)
1846
- configures.common.resultEndIdx =
1847
- configures.firstEndLineBlockIdx;
1848
- else
1849
- configures.common.resultEndIdx =
1850
- configures.latestOverEndLineIdx;
1851
-
1852
- if (configures.common.resultEndIdx >= 0)
1853
- configures.common.enableForwardSearching = false;
1854
- }
1855
- }
1856
- }
1857
- }
1858
- }
1859
- if (configures.baseIdx + offset === configures.endSearchingIndex) {
1860
- if (configures.searchDirect > 0) {
1861
- configures.common.enableForwardSearching = false;
1862
- } else {
1863
- configures.common.enableBackwardSearching = false;
1864
- }
1865
- configures.searchToBorder = true;
1866
- }
1867
- }
1868
- }
1869
-
1870
- class TemplateItemAdder {
1871
- constructor(
1872
- template_parser,
1873
- data,
1874
- measure_func,
1875
- page_range,
1876
- side_effect,
1877
- id
1878
- ) {
1879
- this._TemplateParser = template_parser;
1880
- this._Data = data;
1881
- this._PageRange = page_range;
1882
- this._MeasureFunc = measure_func;
1883
- this._CurIndex = 0;
1884
- this._CurPage = 0;
1885
- this._KeyIndex = 0; //分页处的item
1886
- this._SideEffect = side_effect;
1887
- this._Key =
1888
- this._TemplateParser._Template.Orient.type === HORIZONTAL
1889
- ? "xPos"
1890
- : "yPos";
1891
- this._ID = id;
1892
- }
1893
-
1894
- tryAddItem(cur_item = null, page_num = 1) {
1895
- let added = false;
1896
- if (
1897
- this._CurIndex < this._Data.length &&
1898
- (!cur_item ||
1899
- cur_item[this._Key] >= (this._CurPage - 1) * this._PageRange)
1900
- ) {
1901
- while (this._CurIndex < this._Data.length) {
1902
- try {
1903
- let item = this._TemplateParser.ParseTemplateItem(
1904
- this._MeasureFunc(this._Data[this._CurIndex]),
1905
- this._Data[this._CurIndex]
1906
- );
1907
- this._SideEffect?.(item);
1908
- this._CurIndex++;
1909
- if (item[this._Key] >= (this._CurPage + page_num) * this._PageRange) {
1910
- this._CurPage += page_num;
1911
- break;
1912
- }
1913
- } catch (e) {
1914
- console.error(
1915
- `MetroWidget: ${this._ID} parse template item ${this._CurIndex} failed. data: `,
1916
- this._Data
1917
- );
1918
- throw e;
1919
- }
1920
- }
1921
- this._TemplateParser.CalculateNeighborWhenAddStop();
1922
- added = true;
1923
- }
1924
- // 添加完成需要计算neighbor
1925
- return added;
1926
- }
1927
-
1928
- tryAddItemByPosition(position) {
1929
- const page_num = Math.ceil(position / this._PageRange + 1);
1930
- if (page_num > this._CurPage) {
1931
- this.tryAddItem(null, page_num - this._CurPage);
1932
- }
1933
- }
1934
-
1935
- tryAddItemByIndex(index) {
1936
- let _index = Math.min(index, this._Data.length - 1);
1937
- let added = false;
1938
- while (this._CurIndex <= _index) {
1939
- added = true;
1940
- try {
1941
- let item = this._TemplateParser.ParseTemplateItem(
1942
- this._MeasureFunc(this._Data[this._CurIndex]),
1943
- this._Data[this._CurIndex]
1944
- );
1945
- this._SideEffect?.(item);
1946
- this._CurIndex++;
1947
- if (item[this._Key] >= (this._CurPage + 1) * this._PageRange) {
1948
- this._CurPage++;
1949
- }
1950
- } catch (e) {
1951
- console.error(
1952
- `MetroWidget: ${this._ID} parse template item ${this._CurIndex} failed. data:`,
1953
- this._Data
1954
- );
1955
- throw e;
1956
- }
1957
- }
1958
- if (added) {
1959
- this._TemplateParser.CalculateNeighborWhenAddStop();
1960
- }
1961
- //再添加一屏
1962
- this.tryAddItem(this._TemplateParser.GetItem(index), 2);
1963
- }
1964
-
1965
- tryAddItemById(id) {
1966
- let _id = Math.min(id, this._Data.length - 1); // id小于等于index, 因此为了避免过界取小值
1967
- const last_id = this._TemplateParser.GetLastId();
1968
- if (last_id < _id) {
1969
- let added = false;
1970
- let cur_id = last_id;
1971
- while (cur_id < _id && this._CurIndex < this._Data.length) {
1972
- added = true;
1973
- try {
1974
- const item = this._TemplateParser.ParseTemplateItem(
1975
- this._MeasureFunc(this._Data[this._CurIndex]),
1976
- this._Data[this._CurIndex]
1977
- );
1978
- cur_id = item.id;
1979
- this._SideEffect?.(item);
1980
- if (item[this._Key] >= (this._CurPage + 1) * this._PageRange) {
1981
- this._CurPage++;
1982
- }
1983
- this._CurIndex++;
1984
- } catch (e) {
1985
- console.error(
1986
- `MetroWidget: ${this._ID} parse template item ${this._CurIndex} failed. data:`,
1987
- this._Data
1988
- );
1989
- throw e;
1990
- }
1991
- }
1992
- if (added) {
1993
- this._TemplateParser.CalculateNeighborWhenAddStop();
1994
- }
1995
- }
1996
- //再添加一屏
1997
- this.tryAddItem(this._TemplateParser.GetItemById(id), 2);
1998
- }
1999
-
2000
- updateData(data) {
2001
- this._Data = data;
2002
- }
2003
- }
2004
- export { TemplateParser, TemplateItemAdder };