@shijiu/jsview-vue 2.2.426-test.0 → 2.3.151-test.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/bin/browser/BrowserAudio.vue.mjs +4 -1
- package/bin/jsview-vue-common.mjs +1 -1
- package/bin/jsview-vue.mjs +9771 -7511
- package/bin/types/utils/JsViewEngineWidget/JsvFocus/JsvFocusHub.d.ts +21 -1
- package/bin/types/utils/JsViewEngineWidget/JsvFocus/JsvFocusManager.d.ts +11 -2
- package/bin/types/utils/JsViewEngineWidget/MetroWidget/DebugFrame.vue.d.ts +8 -0
- package/bin/types/utils/JsViewEngineWidget/MetroWidget/DebugTools.d.ts +5 -0
- package/bin/types/utils/JsViewEngineWidget/MetroWidget/ListWidget.vue.d.ts +24 -6
- package/bin/types/utils/JsViewEngineWidget/MetroWidget/MetroWidget.vue.d.ts +24 -6
- package/bin/types/utils/JsViewEngineWidget/MetroWidget/MetroWidgetSetup.d.ts +9 -2
- package/bin/types/utils/JsViewEngineWidget/MetroWidget/RenderItem.d.ts +8 -1
- package/bin/types/utils/JsViewEngineWidget/TemplateParser/CommonMetroTemplate.d.ts +2 -1
- package/bin/types/utils/JsViewEngineWidget/WidgetCommon.d.ts +10 -7
- package/bin/types/utils/JsViewPlugin/JsvAudio/version.d.mts +1 -0
- package/bin/types/utils/JsViewPlugin/JsvAudio/version.d.ts +1 -0
- package/bin/types/utils/JsViewPlugin/JsvLatex/BrowserJsvLatex.vue.d.ts +1 -1
- package/bin/types/utils/JsViewPlugin/JsvLatex/JsvLatex.vue.d.ts +1 -1
- package/bin/types/utils/JsViewPlugin/JsvPlayer/AckEventDefine.d.ts +10 -0
- package/bin/types/utils/JsViewPlugin/JsvPlayer/BrowserJsvPlayer.vue.d.ts +1 -2
- package/bin/types/utils/JsViewPlugin/JsvPlayer/JsvMedia.d.ts +2 -2
- package/bin/types/utils/JsViewVueTools/ForgeHandles.d.ts +1 -0
- package/bin/types/utils/JsViewVueTools/JsvRuntimeBridge.d.ts +43 -1
- package/bin/types/utils/JsViewVueTools/JsvTextureStore/CanvasTexture/Path.d.ts +21 -0
- package/bin/types/utils/JsViewVueTools/JsvTextureStore/CapturedTexture/CapturedTexture.d.ts +3 -3
- package/bin/types/utils/JsViewVueTools/JsvTextureStore/DominantColor/GetDominantColor.d.ts +7 -0
- package/bin/types/utils/JsViewVueTools/JsvTextureStore/JsvTextureStore.d.ts +15 -2
- package/bin/types/utils/JsViewVueTools/JsvTextureStore/Store.d.ts +2 -0
- package/bin/types/utils/JsViewVueTools/JsvTextureStore/Texture.d.ts +4 -0
- package/bin/types/utils/JsViewVueTools/index.d.ts +0 -1
- package/bin/types/utils/JsViewVueWidget/Jsv3dDiv.vue.d.ts +120 -0
- package/bin/types/utils/JsViewVueWidget/Jsv3dStage.vue.d.ts +144 -0
- package/bin/types/utils/JsViewVueWidget/JsvApic/JsvApic/index.d.ts +50 -2
- package/bin/types/utils/JsViewVueWidget/JsvApic/JsvApic2/index.d.ts +23 -2
- package/bin/types/utils/JsViewVueWidget/JsvDashPath.vue.d.ts +11 -0
- package/bin/types/utils/JsViewVueWidget/JsvDriftScope/JsvDriftScope.vue.d.ts +4 -4
- package/bin/types/utils/JsViewVueWidget/JsvFilterView.vue.d.ts +3 -3
- package/bin/types/utils/JsViewVueWidget/JsvFlexCell/JsvFullScrAdjust.vue.d.ts +78 -0
- package/bin/types/utils/JsViewVueWidget/JsvFlexCell/index.d.ts +1 -0
- package/bin/types/utils/JsViewVueWidget/JsvFragShaderView/JsvFragShaderView.vue.d.ts +2 -1
- package/bin/types/utils/JsViewVueWidget/JsvFreeMoveActor/FreeMoveActor.vue.d.ts +3 -3
- package/bin/types/utils/JsViewVueWidget/JsvFreeMoveActor/JsvEnvBlocker.vue.d.ts +3 -3
- package/bin/types/utils/JsViewVueWidget/JsvFreeMoveActor/SetState.d.ts +1 -0
- package/bin/types/utils/JsViewVueWidget/JsvInput/Cursor.vue.d.ts +1 -1
- package/bin/types/utils/JsViewVueWidget/JsvMindMap/JsvMindMap.vue.d.ts +3 -3
- package/bin/types/utils/JsViewVueWidget/JsvNinePatch.vue.d.ts +4 -4
- package/bin/types/utils/JsViewVueWidget/JsvPosterDiv.vue.d.ts +3 -0
- package/bin/types/utils/JsViewVueWidget/JsvPosterImage.vue.d.ts +3 -0
- package/bin/types/utils/JsViewVueWidget/JsvRipple/JsvRipple.vue.d.ts +3 -3
- package/bin/types/utils/JsViewVueWidget/JsvSmoothSlideContainer.vue.d.ts +72 -0
- package/bin/types/utils/JsViewVueWidget/JsvSoundPool.d.ts +26 -0
- package/bin/types/utils/JsViewVueWidget/JsvSpray/JsvSpray.vue.d.ts +10 -37
- package/bin/types/utils/JsViewVueWidget/JsvSpriteAnim/JsvSpriteAnim.vue.d.ts +1 -1
- package/bin/types/utils/JsViewVueWidget/JsvSwiper/JsvSmoothSwiper.vue.d.ts +112 -0
- package/bin/types/utils/JsViewVueWidget/JsvSwiper/JsvSwiper.vue.d.ts +1 -1
- package/bin/types/utils/JsViewVueWidget/JsvSwiper/JsvSwiper2.vue.d.ts +142 -0
- package/bin/types/utils/JsViewVueWidget/JsvSwiper/index.d.ts +3 -1
- package/bin/types/utils/JsViewVueWidget/JsvSwiper3D/JsvSwiper.vue.d.ts +3 -3
- package/bin/types/utils/JsViewVueWidget/JsvTextureAnim/JsvTextureAnim.vue.d.ts +4 -3
- package/bin/types/utils/JsViewVueWidget/JsvVisibleSensor/JsvVisibleSensor.vue.d.ts +3 -3
- package/bin/types/utils/JsViewVueWidget/JsvVisibleSensor/index.d.ts +3 -3
- package/bin/types/utils/JsViewVueWidget/index.d.ts +4 -1
- package/package.json +1 -1
- package/utils/JsViewEngineWidget/CheckType.js +3 -3
- package/utils/JsViewEngineWidget/JsvFocus/JsvFocusBlock.vue +25 -6
- package/utils/JsViewEngineWidget/JsvFocus/JsvFocusHub.ts +27 -1
- package/utils/JsViewEngineWidget/JsvFocus/JsvFocusManager.ts +22 -3
- package/utils/JsViewEngineWidget/MetroWidget/DebugFrame.vue +22 -0
- package/utils/JsViewEngineWidget/MetroWidget/DebugTools.ts +37 -0
- package/utils/JsViewEngineWidget/MetroWidget/ListWidget.vue +42 -7
- package/utils/JsViewEngineWidget/MetroWidget/MetroWidget.vue +97 -13
- package/utils/JsViewEngineWidget/MetroWidget/MetroWidgetSetup.js +876 -412
- package/utils/JsViewEngineWidget/MetroWidget/RenderItem.ts +43 -2
- package/utils/JsViewEngineWidget/MetroWidget/TaskManager.ts +38 -26
- package/utils/JsViewEngineWidget/TemplateParser/CommonMetroTemplate.ts +144 -73
- package/utils/JsViewEngineWidget/WidgetCommon.ts +12 -0
- package/utils/JsViewPlugin/JsvAudio/BrowserAudio/BrowserAudio.vue +4 -0
- package/utils/JsViewPlugin/JsvAudio/BrowserAudio/JsvSystemAudio.vue +13 -13
- package/utils/JsViewPlugin/JsvAudio/version.js +1 -1
- package/utils/JsViewPlugin/JsvAudio/version.mjs +1 -1
- package/utils/JsViewPlugin/JsvPlayer/AckEventDefine.ts +82 -0
- package/utils/JsViewPlugin/JsvPlayer/BrowserJsvPlayer.vue +50 -32
- package/utils/JsViewVueTools/FeatureActive.ts +2 -1
- package/utils/JsViewVueTools/ForgeHandles.ts +5 -2
- package/utils/JsViewVueTools/JsvRuntimeBridge.js +109 -4
- package/utils/JsViewVueTools/JsvTextTools.ts +3 -1
- package/utils/JsViewVueTools/JsvTextureStore/CanvasTexture/Path.ts +38 -2
- package/utils/JsViewVueTools/JsvTextureStore/CapturedTexture/CapturedTexture.ts +15 -12
- package/utils/JsViewVueTools/JsvTextureStore/DominantColor/GetDominantColor.ts +36 -0
- package/utils/JsViewVueTools/JsvTextureStore/JsvTextureStore.ts +24 -3
- package/utils/JsViewVueTools/JsvTextureStore/Store.ts +33 -21
- package/utils/JsViewVueTools/JsvTextureStore/Texture.ts +56 -41
- package/utils/JsViewVueTools/index.js +0 -1
- package/utils/JsViewVueWidget/Jsv3dDiv.vue +85 -0
- package/utils/JsViewVueWidget/Jsv3dStage.vue +50 -0
- package/utils/JsViewVueWidget/JsvApic/JsvApic/index.js +1 -8
- package/utils/JsViewVueWidget/JsvApic/JsvApic2/index.js +1 -8
- package/utils/JsViewVueWidget/JsvDashPath.vue +150 -0
- package/utils/JsViewVueWidget/JsvFlexCell/JsvFlexDiv.vue +1 -1
- package/utils/JsViewVueWidget/JsvFlexCell/JsvFullScrAdjust.vue +153 -0
- package/utils/JsViewVueWidget/JsvFlexCell/JsvScreenFlex.vue +2 -2
- package/utils/JsViewVueWidget/JsvFlexCell/index.js +1 -0
- package/utils/JsViewVueWidget/JsvFragShaderView/JsvFragShaderView.vue +26 -22
- package/utils/JsViewVueWidget/JsvFreeMoveActor/SetAction.ts +1 -1
- package/utils/JsViewVueWidget/JsvFreeMoveActor/SetState.ts +8 -0
- package/utils/JsViewVueWidget/JsvInput/EditViewOperator.ts +1 -1
- package/utils/JsViewVueWidget/JsvInput/JsvInput.vue +1 -0
- package/utils/JsViewVueWidget/JsvMaskClipDiv.vue +0 -9
- package/utils/JsViewVueWidget/JsvNativeSharedDiv.vue +57 -71
- package/utils/JsViewVueWidget/JsvPosterDiv.vue +15 -8
- package/utils/JsViewVueWidget/JsvPosterImage.vue +11 -1
- package/utils/JsViewVueWidget/JsvPreload/JsvPreload.vue +2 -2
- package/utils/JsViewVueWidget/JsvQrcode/JsvQrcode.vue +1 -1
- package/utils/JsViewVueWidget/JsvSmoothSlideContainer.vue +108 -0
- package/utils/JsViewVueWidget/JsvSoundPool.js +75 -12
- package/utils/JsViewVueWidget/JsvSpray/JsvSpray.vue +99 -61
- package/utils/JsViewVueWidget/JsvSwiper/JsvSmoothSwiper.vue +543 -0
- package/utils/JsViewVueWidget/JsvSwiper/JsvSwiper.vue +3 -3
- package/utils/JsViewVueWidget/JsvSwiper/JsvSwiper2.vue +644 -0
- package/utils/JsViewVueWidget/JsvSwiper/index.js +3 -1
- package/utils/JsViewVueWidget/JsvTextureAnim/JsvTextureAnim.vue +56 -50
- package/utils/JsViewVueWidget/index.js +4 -1
- package/bin/browser/BrowserApic.vue.mjs +0 -114
- package/bin/browser/BrowserApic2.vue.mjs +0 -108
- package/bin/browser/BrowserApicLib.mjs +0 -431
- package/bin/types/utils/JsViewVueTools/JsvDemoTester.d.ts +0 -2
- package/utils/JsViewVueTools/JsvDemoTester.js +0 -81
|
@@ -18,8 +18,8 @@ declare const _default: {
|
|
|
18
18
|
$el: any;
|
|
19
19
|
$options: import("vue").ComponentOptionsBase<Readonly<import("vue").ExtractPropTypes<{}>>, {
|
|
20
20
|
$props: {
|
|
21
|
-
readonly left?: number | undefined;
|
|
22
21
|
readonly top?: number | undefined;
|
|
22
|
+
readonly left?: number | undefined;
|
|
23
23
|
readonly enable?: boolean | undefined;
|
|
24
24
|
readonly width?: number | undefined;
|
|
25
25
|
readonly height?: number | undefined;
|
|
@@ -50,8 +50,8 @@ declare const _default: {
|
|
|
50
50
|
$watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (args_0: R, args_1: R) => any : (...args: any) => any, options?: import("vue").WatchOptions<boolean> | undefined): import("vue").WatchStopHandle;
|
|
51
51
|
} & Readonly<import("vue").ExtractPropTypes<{}>> & import("vue").ShallowUnwrapRef<{
|
|
52
52
|
$props: {
|
|
53
|
-
readonly left?: number | undefined;
|
|
54
53
|
readonly top?: number | undefined;
|
|
54
|
+
readonly left?: number | undefined;
|
|
55
55
|
readonly enable?: boolean | undefined;
|
|
56
56
|
readonly width?: number | undefined;
|
|
57
57
|
readonly height?: number | undefined;
|
|
@@ -66,8 +66,8 @@ declare const _default: {
|
|
|
66
66
|
__isSuspense?: undefined;
|
|
67
67
|
} & import("vue").ComponentOptionsBase<Readonly<import("vue").ExtractPropTypes<{}>>, {
|
|
68
68
|
$props: {
|
|
69
|
-
readonly left?: number | undefined;
|
|
70
69
|
readonly top?: number | undefined;
|
|
70
|
+
readonly left?: number | undefined;
|
|
71
71
|
readonly enable?: boolean | undefined;
|
|
72
72
|
readonly width?: number | undefined;
|
|
73
73
|
readonly height?: number | undefined;
|
|
@@ -8,7 +8,6 @@ export { default as JsvApic } from "./JsvApic/JsvApic";
|
|
|
8
8
|
export { default as JsvApic2 } from "./JsvApic/JsvApic2";
|
|
9
9
|
export { default as JsvQrcode } from "./JsvQrcode/JsvQrcode.vue";
|
|
10
10
|
export { default as JsvSpray } from "./JsvSpray/JsvSpray.vue";
|
|
11
|
-
export { default as JsvSwiper } from "./JsvSwiper";
|
|
12
11
|
export { default as JsvSwiper3D } from "./JsvSwiper3D";
|
|
13
12
|
export { default as JsvVisibleSensor } from "./JsvVisibleSensor";
|
|
14
13
|
export { default as JsvFilterView } from "./JsvFilterView.vue";
|
|
@@ -32,12 +31,16 @@ export { JsvMindMap } from "./JsvMindMap";
|
|
|
32
31
|
export { default as JsvFragShaderView } from "./JsvFragShaderView";
|
|
33
32
|
export { default as JsvTouchModeSwitcher } from "./JsvTouchModeSwitcher.vue";
|
|
34
33
|
export { default as JsvDragBox } from "./JsvDragBox/JsvDragBox.vue";
|
|
34
|
+
export { default as Jsv3dDiv } from "./Jsv3dDiv.vue";
|
|
35
|
+
export { default as Jsv3dStage } from "./Jsv3dStage.vue";
|
|
36
|
+
export { default as JsvDashPath } from "./JsvDashPath.vue";
|
|
35
37
|
import JsvNativeSharedDiv from "./JsvNativeSharedDiv.vue";
|
|
36
38
|
export { JsvNativeSharedDiv as JsvTransparentDiv, JsvNativeSharedDiv };
|
|
37
39
|
export { default as JsvActorMove, JsvActorMoveControl } from "./JsvActorMove";
|
|
38
40
|
export { LoopType, ApicEndState } from "./JsvApic/JsvCommonLoopToolBase.js";
|
|
39
41
|
export { default as JsvInput, InputType } from "./JsvInput";
|
|
40
42
|
export { default as JsvPreload, buildPreloadInfo, buildDownloadInfo } from "./JsvPreload";
|
|
43
|
+
export { JsvSwiper, JsvSwiper2, JsvSmoothSwiper } from "./JsvSwiper";
|
|
41
44
|
export { default as JsvTextureAnim, TexAlignAnchor, DECORATE_NINEPATCH_ALPHA_MIX, DECORATE_BORDER_RADIUS } from "./JsvTextureAnim";
|
|
42
45
|
export { default as JsvGrid, PageType, LineType, FocusMoveType } from "./JsvGrid.vue";
|
|
43
46
|
export { default as JsvRipple, JsvRippleShape } from "./JsvRipple";
|
package/package.json
CHANGED
|
@@ -44,10 +44,10 @@ function checkType(value, type) {
|
|
|
44
44
|
let valid;
|
|
45
45
|
const expectedType = getTypeName(t);
|
|
46
46
|
if (isSimpleType(expectedType)) {
|
|
47
|
-
const
|
|
48
|
-
valid =
|
|
47
|
+
const valueType = typeof v;
|
|
48
|
+
valid = valueType === expectedType.toLowerCase();
|
|
49
49
|
// for primitive wrapper objects
|
|
50
|
-
if (!valid &&
|
|
50
|
+
if (!valid && valueType === 'object') {
|
|
51
51
|
valid = v instanceof t;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -221,16 +221,29 @@ onUnmounted(() => {
|
|
|
221
221
|
});
|
|
222
222
|
|
|
223
223
|
onActivated(() => {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
if (fDivRef.value == null) {
|
|
225
|
+
console.log("FocusBlock onActivated but not mounted name=" + props.name);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
227
228
|
|
|
228
|
-
if (
|
|
229
|
-
|
|
229
|
+
if (focusNodeRef == null) {
|
|
230
|
+
focusNodeRef = toRaw(fDivRef.value)?.FocusNodeRef;
|
|
231
|
+
_mountToFocusSystem();
|
|
232
|
+
|
|
233
|
+
if (!!props.autoFocus || props.autoFocus === "") {
|
|
234
|
+
requestFocus(props.autoFocus !== "exact");
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
// 首次mounted后会调用onActivated, 考虑避免重复添加
|
|
230
238
|
}
|
|
231
239
|
});
|
|
232
240
|
|
|
233
241
|
onDeactivated(() => {
|
|
242
|
+
if (fDivRef.value == null) {
|
|
243
|
+
console.log("FocusBlock onDeactivated but not mounted name=" + props.name);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
234
247
|
focusNodeRef?.onUnMount(true);
|
|
235
248
|
if (focusNodeRef?.jsvVueComponent) {
|
|
236
249
|
focusNodeRef.jsvVueComponent = undefined;
|
|
@@ -242,7 +255,13 @@ defineExpose(exportObject);
|
|
|
242
255
|
</script>
|
|
243
256
|
|
|
244
257
|
<template>
|
|
245
|
-
<fdiv
|
|
258
|
+
<fdiv
|
|
259
|
+
ref="fDivRef"
|
|
260
|
+
:fname="name"
|
|
261
|
+
:new-namespace="namespace"
|
|
262
|
+
:style="style"
|
|
263
|
+
:data-jsv-focusable="focusable ?? !namespace"
|
|
264
|
+
>
|
|
246
265
|
<slot></slot>
|
|
247
266
|
</fdiv>
|
|
248
267
|
</template>
|
|
@@ -43,7 +43,8 @@ class JsvFocusHubApi {
|
|
|
43
43
|
* getCurrentFocus
|
|
44
44
|
*
|
|
45
45
|
* 获取当前焦点的的 focusName 信息,用于后续的进行的 setFocus 操作
|
|
46
|
-
* (
|
|
46
|
+
* (注意1: 获取的NameSpace不带NameSpace)
|
|
47
|
+
* (注意2: 如果当前状态所设焦点还没Mounted时,也会返回null)
|
|
47
48
|
*
|
|
48
49
|
* @return {string} 当前焦点的focusName
|
|
49
50
|
*/
|
|
@@ -117,6 +118,31 @@ class JsvFocusHubApi {
|
|
|
117
118
|
public getCurrentFocusStack(): Array<Object> {
|
|
118
119
|
return this._FocusHub.getCurrentFocusStack();
|
|
119
120
|
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* addFocusChangeListener
|
|
124
|
+
*
|
|
125
|
+
* 添加焦点变化监听器, 主要用来追踪焦点name的变化,例如路由切换的场景
|
|
126
|
+
*
|
|
127
|
+
* @param {Function} listener 焦点变化监听器, 参数为 {focusName: string}
|
|
128
|
+
* @param {boolean} onRequest 监听时机,true: 在focus请求时即回调,无论节点是否存在;
|
|
129
|
+
* false: 在节点真实存在后,确认进行focus时才回调(在正准备Focus()调用前)
|
|
130
|
+
*/
|
|
131
|
+
addFocusChangeListener(listener: Function, onRequest: boolean = false) {
|
|
132
|
+
this._FocusHub.addFocusChangeListener(listener, onRequest);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* removeFocusChangeListener
|
|
137
|
+
*
|
|
138
|
+
* 删除焦点变化监听器
|
|
139
|
+
*
|
|
140
|
+
* @param {Function} listener 由addFocusChangeListener添加的变化监听器
|
|
141
|
+
* @param {boolean} onRequest 和addFocusChangeListener时设置的参数要完全对应
|
|
142
|
+
*/
|
|
143
|
+
removeFocusChangeListener(listener: Function, onRequest: boolean = false) {
|
|
144
|
+
this._FocusHub.delFocusChangeListener(listener, onRequest);
|
|
145
|
+
}
|
|
120
146
|
}
|
|
121
147
|
|
|
122
148
|
const ROOT_HUB_PROVIDE_NAME = "__jsvFocusRootHub__";
|
|
@@ -25,8 +25,11 @@ export class JsvFocusManager {
|
|
|
25
25
|
// #aliasMap = {}
|
|
26
26
|
private $_appMount: any = undefined;
|
|
27
27
|
private $_topFDiv: any = undefined;
|
|
28
|
+
private $_autoSearchFocus: boolean = false;
|
|
28
29
|
|
|
29
|
-
constructor() {
|
|
30
|
+
constructor(config: any) {
|
|
31
|
+
this.$_autoSearchFocus = config.autoSearchFocus;
|
|
32
|
+
}
|
|
30
33
|
|
|
31
34
|
install(app: any, ...options: any) {
|
|
32
35
|
console.log("JsvFocusManager install");
|
|
@@ -98,6 +101,7 @@ export class JsvFocusManager {
|
|
|
98
101
|
$_hookMount(app: any, rootNodeId: any) {
|
|
99
102
|
rootNodeId = rootNodeId.replace("#", "");
|
|
100
103
|
this.$_topFDiv = (document as any).jsvInitFDivRoot(rootNodeId);
|
|
104
|
+
this.$_topFDiv.enableAutoSearchFocus(this.$_autoSearchFocus);
|
|
101
105
|
this.$_appMount = app.mount.bind(app);
|
|
102
106
|
|
|
103
107
|
return this.$_doAppMount.bind(this);
|
|
@@ -115,8 +119,23 @@ export class JsvFocusManager {
|
|
|
115
119
|
}
|
|
116
120
|
}
|
|
117
121
|
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
/**
|
|
123
|
+
* 创建 JsView 焦点管理器
|
|
124
|
+
*
|
|
125
|
+
* @param {Object} config: 对象设置,子参数有{
|
|
126
|
+
* autoSearchFocus{boolean}: 是否开启自动寻焦,默认为false(兼容旧代码)
|
|
127
|
+
* }
|
|
128
|
+
* @return JsvFocusManager
|
|
129
|
+
*/
|
|
130
|
+
function jsvCreateFocusManager(config: Object | null = null) {
|
|
131
|
+
let defualt_config = {
|
|
132
|
+
autoSearchFocus: false
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return new JsvFocusManager({
|
|
136
|
+
...defualt_config,
|
|
137
|
+
...config
|
|
138
|
+
});
|
|
120
139
|
}
|
|
121
140
|
|
|
122
141
|
export { jsvCreateFocusManager, useFocusHub };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import JsvNinePatch from "../../JsViewVueWidget/JsvNinePatch.vue";
|
|
3
|
+
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
width: Number,
|
|
6
|
+
height: Number,
|
|
7
|
+
sourceId: String,
|
|
8
|
+
})
|
|
9
|
+
</script>
|
|
10
|
+
<template>
|
|
11
|
+
<JsvNinePatch
|
|
12
|
+
:style="{
|
|
13
|
+
width: width,
|
|
14
|
+
height: height,
|
|
15
|
+
}"
|
|
16
|
+
:imageUrl="`jsvtexturestore://${sourceId}`"
|
|
17
|
+
:imageWidth="20"
|
|
18
|
+
:centerWidth="1"
|
|
19
|
+
:imageDspWidth="20"
|
|
20
|
+
:borderOutset="2"
|
|
21
|
+
/>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { JsvTextureStoreApi } from "../../JsViewVueTools"
|
|
2
|
+
|
|
3
|
+
export const randomColor = () => {
|
|
4
|
+
let randomColor = Math.round(Math.random() * 2 ** 24).toString(16);
|
|
5
|
+
return (
|
|
6
|
+
"#" + new Array(6 - randomColor.length).fill("0").join("") + randomColor + "99"
|
|
7
|
+
);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const RandomColorPool = [
|
|
11
|
+
"#FF0000",
|
|
12
|
+
"#00FF00",
|
|
13
|
+
"#0000FF",
|
|
14
|
+
"#FFFF00",
|
|
15
|
+
"#00FFFF",
|
|
16
|
+
"#FF00FF",
|
|
17
|
+
]
|
|
18
|
+
export function createCanvasText(width: number) {
|
|
19
|
+
|
|
20
|
+
let canvasRef = JsvTextureStoreApi.canvasTexture(
|
|
21
|
+
width,
|
|
22
|
+
width
|
|
23
|
+
); // 创建画布
|
|
24
|
+
|
|
25
|
+
let customPath = canvasRef.rectPath(0, 0, width, width);
|
|
26
|
+
if (customPath) {
|
|
27
|
+
customPath.stroke(5, RandomColorPool[Math.floor(Math.random() * RandomColorPool.length)]); // 以给定线宽绘制圆环
|
|
28
|
+
}
|
|
29
|
+
let sourceId = canvasRef.commit(); // texture和div的textureStore绑定
|
|
30
|
+
const releaseHandler = () => {
|
|
31
|
+
JsvTextureStoreApi.deleteTexture(sourceId); // 释放texture资源
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
sourceId,
|
|
35
|
+
releaseHandler,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @file 只显示单列/行的MetroWidget
|
|
3
3
|
-->
|
|
4
4
|
<script setup>
|
|
5
|
-
import { ref, shallowRef, computed, reactive, onMounted } from "vue";
|
|
5
|
+
import { ref, shallowRef, computed, reactive, onMounted, onBeforeUnmount } from "vue";
|
|
6
6
|
import { setup } from "./MetroWidgetSetup";
|
|
7
7
|
import {
|
|
8
8
|
VERTICAL,
|
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
RENDER_ITEM_BREAK_KEY,
|
|
13
13
|
} from "../WidgetCommon";
|
|
14
14
|
import { ForgeConst } from "../../JsViewVueTools/ForgeConstDefine.ts";
|
|
15
|
+
import DebugFrame from "./DebugFrame.vue";
|
|
16
|
+
import { createCanvasText } from "./DebugTools.ts";
|
|
15
17
|
|
|
16
18
|
const props = defineProps({
|
|
17
19
|
padding: {
|
|
@@ -147,6 +149,14 @@ const props = defineProps({
|
|
|
147
149
|
type: Number,
|
|
148
150
|
default: 0,
|
|
149
151
|
},
|
|
152
|
+
enableLongPress: {
|
|
153
|
+
type: Boolean,
|
|
154
|
+
default: false,
|
|
155
|
+
},
|
|
156
|
+
enableDebug: {
|
|
157
|
+
type: Boolean,
|
|
158
|
+
default: false,
|
|
159
|
+
},
|
|
150
160
|
});
|
|
151
161
|
|
|
152
162
|
const renderBreakKey = props.enableItemRenderBreak ? RENDER_ITEM_BREAK_KEY : "";
|
|
@@ -181,13 +191,14 @@ const {
|
|
|
181
191
|
focusBlockOnFocus,
|
|
182
192
|
focusBlockOnBlur,
|
|
183
193
|
focusBlockOnKeyDown,
|
|
194
|
+
focusBlockOnKeyUp,
|
|
184
195
|
focusBlockOnCustomEvent,
|
|
185
196
|
_onFocusableItemEdge,
|
|
186
197
|
exportObject,
|
|
187
198
|
onTouchDown,
|
|
188
199
|
onTouchRelease,
|
|
189
200
|
currentFocusIndex,
|
|
190
|
-
onDispatchKeyDown
|
|
201
|
+
onDispatchKeyDown,
|
|
191
202
|
} = setup(
|
|
192
203
|
props,
|
|
193
204
|
itemRender,
|
|
@@ -203,6 +214,15 @@ const {
|
|
|
203
214
|
"list"
|
|
204
215
|
);
|
|
205
216
|
|
|
217
|
+
let debugFrameSourceId = "";
|
|
218
|
+
let debugFrameSourceReleaseHandler = null;
|
|
219
|
+
if (props.enableDebug) {
|
|
220
|
+
const sourceInfo = createCanvasText(20);
|
|
221
|
+
debugFrameSourceId = sourceInfo.sourceId;
|
|
222
|
+
debugFrameSourceReleaseHandler = sourceInfo.releaseHandler;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
206
226
|
onMounted(() => {
|
|
207
227
|
if (onTouchRelease) {
|
|
208
228
|
touchDiv.value.jsvSetTapListener(
|
|
@@ -216,6 +236,14 @@ onMounted(() => {
|
|
|
216
236
|
}
|
|
217
237
|
});
|
|
218
238
|
|
|
239
|
+
onBeforeUnmount(() => {
|
|
240
|
+
if (props.enableDebug) {
|
|
241
|
+
debugFrameSourceReleaseHandler?.();
|
|
242
|
+
debugFrameSourceReleaseHandler = null;
|
|
243
|
+
debugFrameSourceId = "";
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
219
247
|
defineExpose(exportObject);
|
|
220
248
|
</script>
|
|
221
249
|
|
|
@@ -262,8 +290,9 @@ defineExpose(exportObject);
|
|
|
262
290
|
onFocus: focusBlockOnFocus,
|
|
263
291
|
onBlur: focusBlockOnBlur,
|
|
264
292
|
onKeyDown: focusBlockOnKeyDown,
|
|
293
|
+
onKeyUp: focusBlockOnKeyUp,
|
|
265
294
|
onCustomEvent: focusBlockOnCustomEvent,
|
|
266
|
-
onDispatchKeyDown
|
|
295
|
+
onDispatchKeyDown,
|
|
267
296
|
}"
|
|
268
297
|
>
|
|
269
298
|
<div
|
|
@@ -286,6 +315,12 @@ defineExpose(exportObject);
|
|
|
286
315
|
}"
|
|
287
316
|
@click="item.onTap.value"
|
|
288
317
|
>
|
|
318
|
+
<DebugFrame
|
|
319
|
+
v-if="enableDebug"
|
|
320
|
+
:width="item.templateInfo.width"
|
|
321
|
+
:height="item.templateInfo.height"
|
|
322
|
+
:sourceId="debugFrameSourceId"
|
|
323
|
+
></DebugFrame>
|
|
289
324
|
<div
|
|
290
325
|
v-if="
|
|
291
326
|
!enableItemRenderBreak || item.mounted.value || itemRender
|
|
@@ -305,10 +340,10 @@ defineExpose(exportObject);
|
|
|
305
340
|
</div>
|
|
306
341
|
<div
|
|
307
342
|
v-if="
|
|
308
|
-
enableItemRenderBreak
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
343
|
+
enableItemRenderBreak &&
|
|
344
|
+
placeHolderSetting &&
|
|
345
|
+
!item.mounted.value &&
|
|
346
|
+
item.itemConfig.showSkeleton
|
|
312
347
|
"
|
|
313
348
|
:style="{
|
|
314
349
|
width: item.renderStyle.width - normalizedPlaceHolder.gap,
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* name {string} 用于设置焦点的名称
|
|
24
24
|
* padding {object} 控件内边距, 默认为{left: 0, right: 0, top: 0, bottom: 0}
|
|
25
25
|
* direction {enum} (必选)控件方向 HORIZONTAL/VERTICAL
|
|
26
|
-
* focusMoveType {int} 焦点移动的模式, 可通过 |
|
|
26
|
+
* focusMoveType {int} 焦点移动的模式, 可通过 | 运算进行组合. 这些常量在FocusMoveType对象中, 需要import { FocusMoveType } from 'jsview'
|
|
27
27
|
NO_ADJUST: 无特殊处理
|
|
28
28
|
COLUMN_LOOP: 到达列首/尾后跳转到上/下一列, 只在水平滚动时生效
|
|
29
29
|
ROW_LOOP: 到达行首/尾后跳转到上/下一行, 只在竖直滚动时生效
|
|
@@ -58,6 +58,9 @@
|
|
|
58
58
|
focusBackgroundColor: 获焦时的颜色
|
|
59
59
|
borderRadius: 占位符圆角设置
|
|
60
60
|
gap: 占位符之间的gap
|
|
61
|
+
logoUrl: 占位符logo的url
|
|
62
|
+
logoWidth: 占位符logo的宽度
|
|
63
|
+
logoHeight: 占位符logo的高度
|
|
61
64
|
}
|
|
62
65
|
* sendFocusRectEvent {boolean} item获焦时在焦点树上冒泡一个事件, MetroWidget接收到事件时会触发滚动操作, 一般用于嵌套
|
|
63
66
|
时的滚动
|
|
@@ -84,7 +87,9 @@
|
|
|
84
87
|
uid {string}: item的uid, 可以通过uid来设置焦点
|
|
85
88
|
permanent {boolean}: 出去与是否保留
|
|
86
89
|
enableTap {boolean}: 是否接受触控tap
|
|
87
|
-
showSkeleton {boolean}: 打断描画时,
|
|
90
|
+
showSkeleton {boolean}: 打断描画时, 是否显示骨架图, 默认为true
|
|
91
|
+
enableLongPress {boolean}: item是否支持长按, 默认值为props.enableLongPress
|
|
92
|
+
placeHolderLayout{{left: number, top: number, width: number, height: number}}: 占位符的布局信息
|
|
88
93
|
}
|
|
89
94
|
*
|
|
90
95
|
* onFocus {function} 控件获取焦点的回调
|
|
@@ -100,11 +105,14 @@
|
|
|
100
105
|
totalSize: 所有item的总长
|
|
101
106
|
* onFocusRectChange {() => void} 焦点区域变化的回调
|
|
102
107
|
* onAllItemResizeDone {() => void} 所有item resize完成的回调
|
|
108
|
+
* onFocusChange {(id: number) => void} 焦点变化的回调
|
|
103
109
|
* loadAll {boolean} 加载不显示的view,触控场景使用
|
|
104
110
|
* flingPageWidth {}
|
|
105
111
|
* flingPageEdge {}
|
|
106
112
|
* disableClip {boolean} 取消显示范围的clipView
|
|
107
113
|
* touchFlag {int} 触控的开关, 0:关闭, 1:打开. 打开后支持drag, fling; item的tap则由measuresObject的enableTap控制
|
|
114
|
+
* enableLongPress {boolean} 支持长按, 长按模式下, onkeyup时触发onclick, 长按触发后, onclik不触发
|
|
115
|
+
* enableDebug {boolean} 显示debug用的item框
|
|
108
116
|
|
|
109
117
|
* methods:
|
|
110
118
|
getFocusBlockRef 获取此MetroWidget的 jsv-focus-block句柄,可以使用requestFocus完成获焦
|
|
@@ -215,7 +223,10 @@
|
|
|
215
223
|
setSensorSensitivity
|
|
216
224
|
@description 触控模式下, 设置运动回调敏感度, 每移动多少像素进行回调,适当放大(推荐10以上)可以极大减小对js回调过多引起的性能降低
|
|
217
225
|
@params {number} sensitivity 敏感度, 等于0时关闭触控的移动监听
|
|
218
|
-
|
|
226
|
+
getItemLayoutInfo
|
|
227
|
+
@description 获取 item 的布局位置信息, index对应的item不存在时, 返回null
|
|
228
|
+
@params {number} index item 的 index
|
|
229
|
+
@return {object} {left: number, top: number, width: number, height: number} | null
|
|
219
230
|
slots:
|
|
220
231
|
renderItem: 该slot用于描画每个单元格
|
|
221
232
|
background: 该slot描画在item后, 一般用于描画需要跟随MetroWidget滚动的内容
|
|
@@ -246,7 +257,13 @@
|
|
|
246
257
|
}
|
|
247
258
|
* onItemEdge: 若单元格内另有可接管按键的控件(如MetroWidget),该控件到达边缘需要通知MetroWidget时的回调
|
|
248
259
|
* onAction: 单元格内控件需要通过onAction.register方法向MetroWidget注册 item 的回调,回调函数有
|
|
249
|
-
onFocus
|
|
260
|
+
onFocus: widget获焦状态下, item获焦的回调
|
|
261
|
+
onBlur: widget获焦状态下, item失焦的回调
|
|
262
|
+
onGaze: item获焦的回调, 无论widget是否为获焦状态
|
|
263
|
+
onIgnore: itemh失焦的回调, 无论widget是否为获焦状态
|
|
264
|
+
onClick: item点击的回调
|
|
265
|
+
onWidgetEdge: 到达边缘的回调
|
|
266
|
+
onLongPress: item长按的回调
|
|
250
267
|
*
|
|
251
268
|
* Q: 如何进行布局,定制每个格的尺寸?
|
|
252
269
|
* A: 首先选定一个布局的方式,一列列地横向布局(HROIZONTAL)还是一行行地纵向(VERTICAL)布局,设置给属性direction
|
|
@@ -275,7 +292,14 @@
|
|
|
275
292
|
-->
|
|
276
293
|
|
|
277
294
|
<script setup>
|
|
278
|
-
import {
|
|
295
|
+
import {
|
|
296
|
+
ref,
|
|
297
|
+
shallowRef,
|
|
298
|
+
computed,
|
|
299
|
+
reactive,
|
|
300
|
+
onMounted,
|
|
301
|
+
onBeforeUnmount,
|
|
302
|
+
} from "vue";
|
|
279
303
|
import { setup } from "./MetroWidgetSetup";
|
|
280
304
|
import SlotComponent from "./SlotComponent.vue";
|
|
281
305
|
import {
|
|
@@ -286,6 +310,8 @@ import {
|
|
|
286
310
|
RENDER_ITEM_BREAK_KEY,
|
|
287
311
|
} from "../WidgetCommon";
|
|
288
312
|
import { ForgeConst } from "../../JsViewVueTools/ForgeConstDefine.ts";
|
|
313
|
+
import DebugFrame from "./DebugFrame.vue";
|
|
314
|
+
import { createCanvasText } from "./DebugTools.ts";
|
|
289
315
|
|
|
290
316
|
const props = defineProps({
|
|
291
317
|
padding: {
|
|
@@ -421,6 +447,14 @@ const props = defineProps({
|
|
|
421
447
|
type: Number,
|
|
422
448
|
default: 0,
|
|
423
449
|
},
|
|
450
|
+
enableLongPress: {
|
|
451
|
+
type: Boolean,
|
|
452
|
+
default: false,
|
|
453
|
+
},
|
|
454
|
+
enableDebug: {
|
|
455
|
+
type: Boolean,
|
|
456
|
+
default: false,
|
|
457
|
+
},
|
|
424
458
|
});
|
|
425
459
|
|
|
426
460
|
const renderBreakKey = props.enableItemRenderBreak ? RENDER_ITEM_BREAK_KEY : "";
|
|
@@ -440,8 +474,21 @@ const touchDivSize = reactive({
|
|
|
440
474
|
});
|
|
441
475
|
|
|
442
476
|
const normalizedPlaceHolder = computed(() => {
|
|
477
|
+
let logoInfo = null;
|
|
478
|
+
if (
|
|
479
|
+
typeof props.placeHolderSetting.logoUrl == "string" &&
|
|
480
|
+
typeof props.placeHolderSetting.logoWidth == "number" &&
|
|
481
|
+
typeof props.placeHolderSetting.logoHeight == "number"
|
|
482
|
+
) {
|
|
483
|
+
logoInfo = {
|
|
484
|
+
url: props.placeHolderSetting.logoUrl,
|
|
485
|
+
width: props.placeHolderSetting.logoWidth,
|
|
486
|
+
height: props.placeHolderSetting.logoHeight,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
443
489
|
return {
|
|
444
490
|
gap: props.placeHolderSetting.gap ?? 0,
|
|
491
|
+
logoInfo: logoInfo,
|
|
445
492
|
borderRadius: props.placeHolderSetting.borderRadius ?? 0,
|
|
446
493
|
backgroundColor: props.placeHolderSetting.backgroundColor,
|
|
447
494
|
focusBackgroundColor:
|
|
@@ -455,6 +502,7 @@ const {
|
|
|
455
502
|
focusBlockOnFocus,
|
|
456
503
|
focusBlockOnBlur,
|
|
457
504
|
focusBlockOnKeyDown,
|
|
505
|
+
focusBlockOnKeyUp,
|
|
458
506
|
focusBlockOnCustomEvent,
|
|
459
507
|
_onFocusableItemEdge,
|
|
460
508
|
exportObject,
|
|
@@ -462,7 +510,7 @@ const {
|
|
|
462
510
|
onTouchRelease,
|
|
463
511
|
currentFocusIndex,
|
|
464
512
|
modeForExport,
|
|
465
|
-
onDispatchKeyDown
|
|
513
|
+
onDispatchKeyDown,
|
|
466
514
|
} = setup(
|
|
467
515
|
props,
|
|
468
516
|
itemRender,
|
|
@@ -478,6 +526,14 @@ const {
|
|
|
478
526
|
"common"
|
|
479
527
|
);
|
|
480
528
|
|
|
529
|
+
let debugFrameSourceId = "";
|
|
530
|
+
let debugFrameSourceReleaseHandler = null;
|
|
531
|
+
if (props.enableDebug) {
|
|
532
|
+
const sourceInfo = createCanvasText(20);
|
|
533
|
+
debugFrameSourceId = sourceInfo.sourceId;
|
|
534
|
+
debugFrameSourceReleaseHandler = sourceInfo.releaseHandler;
|
|
535
|
+
}
|
|
536
|
+
|
|
481
537
|
onMounted(() => {
|
|
482
538
|
if (onTouchRelease) {
|
|
483
539
|
touchDiv.value.jsvSetTapListener(
|
|
@@ -491,6 +547,14 @@ onMounted(() => {
|
|
|
491
547
|
}
|
|
492
548
|
});
|
|
493
549
|
|
|
550
|
+
onBeforeUnmount(() => {
|
|
551
|
+
if (props.enableDebug) {
|
|
552
|
+
debugFrameSourceReleaseHandler?.();
|
|
553
|
+
debugFrameSourceReleaseHandler = null;
|
|
554
|
+
debugFrameSourceId = "";
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
|
|
494
558
|
defineExpose(exportObject);
|
|
495
559
|
</script>
|
|
496
560
|
|
|
@@ -537,6 +601,7 @@ defineExpose(exportObject);
|
|
|
537
601
|
onFocus: focusBlockOnFocus,
|
|
538
602
|
onBlur: focusBlockOnBlur,
|
|
539
603
|
onKeyDown: focusBlockOnKeyDown,
|
|
604
|
+
onKeyUp: focusBlockOnKeyUp,
|
|
540
605
|
onCustomEvent: focusBlockOnCustomEvent,
|
|
541
606
|
onDispatchKeyDown,
|
|
542
607
|
}"
|
|
@@ -561,6 +626,12 @@ defineExpose(exportObject);
|
|
|
561
626
|
}"
|
|
562
627
|
@click="item.onTap.value"
|
|
563
628
|
>
|
|
629
|
+
<DebugFrame
|
|
630
|
+
v-if="enableDebug"
|
|
631
|
+
:width="item.templateInfo.width"
|
|
632
|
+
:height="item.templateInfo.height"
|
|
633
|
+
:sourceId="debugFrameSourceId"
|
|
634
|
+
></DebugFrame>
|
|
564
635
|
<div
|
|
565
636
|
v-if="
|
|
566
637
|
!enableItemRenderBreak || item.mounted.value || itemRender
|
|
@@ -582,21 +653,34 @@ defineExpose(exportObject);
|
|
|
582
653
|
</div>
|
|
583
654
|
<div
|
|
584
655
|
v-if="
|
|
585
|
-
enableItemRenderBreak
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
656
|
+
enableItemRenderBreak &&
|
|
657
|
+
placeHolderSetting &&
|
|
658
|
+
!item.mounted.value &&
|
|
659
|
+
item.itemConfig.showSkeleton
|
|
589
660
|
"
|
|
590
661
|
:style="{
|
|
591
|
-
|
|
592
|
-
|
|
662
|
+
left: item.placeHolderLayout.left,
|
|
663
|
+
top: item.placeHolderLayout.top,
|
|
664
|
+
width: item.placeHolderLayout.width,
|
|
665
|
+
height: item.placeHolderLayout.height,
|
|
593
666
|
backgroundColor:
|
|
594
667
|
currentFocusIndex == item.index && modeForExport == 2
|
|
595
668
|
? normalizedPlaceHolder.focusBackgroundColor
|
|
596
669
|
: normalizedPlaceHolder.backgroundColor,
|
|
597
670
|
borderRadius: normalizedPlaceHolder.borderRadius,
|
|
598
671
|
}"
|
|
599
|
-
|
|
672
|
+
>
|
|
673
|
+
<img
|
|
674
|
+
v-if="normalizedPlaceHolder.logoInfo"
|
|
675
|
+
:src="`url(${normalizedPlaceHolder.logoInfo.url})`"
|
|
676
|
+
:style="{
|
|
677
|
+
left: (item.placeHolderLayout.width - normalizedPlaceHolder.logoInfo.width) / 2,
|
|
678
|
+
top: (item.placeHolderLayout.height - normalizedPlaceHolder.logoInfo.height) / 2,
|
|
679
|
+
width: normalizedPlaceHolder.logoInfo.width,
|
|
680
|
+
height: normalizedPlaceHolder.logoInfo.height,
|
|
681
|
+
}"
|
|
682
|
+
/>
|
|
683
|
+
</div>
|
|
600
684
|
</div>
|
|
601
685
|
</jsv-focus-block>
|
|
602
686
|
</div>
|