w-web-perm 1.1.2 → 1.1.4
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/dist/css/{chunk-vendors.b16f7333.css → chunk-vendors.2bcfce08.css} +1 -1
- package/dist/index.tmp +1 -1
- package/dist/js/app-legacy.8e615442.js +1 -0
- package/dist/js/app.8e615442.js +1 -0
- package/dist/js/{chunk-vendors.22ee28bb.js → chunk-vendors-legacy.fc37f076.js} +3 -3
- package/dist/js/{chunk-vendors-legacy.22ee28bb.js → chunk-vendors.fc37f076.js} +3 -3
- package/dist/w-web-perm.umd.js +2 -2
- package/dist/w-web-perm.umd.js.map +1 -1
- package/docs/WWebPerm.html +1 -1
- package/docs/global.html +1 -1
- package/docs/index.html +1 -1
- package/docs/server_WWebPerm.mjs.html +1 -1
- package/docs/server_procCore.mjs.html +1 -1
- package/docs/src_fetchJson.mjs.html +1 -1
- package/package.json +12 -12
- package/server/procLang.mjs +8 -0
- package/src/components/Layout.vue +566 -181
- package/src/components/LayoutContent.vue +1 -0
- package/tableTags-web-perm.json +1 -1
- package/dist/js/app-legacy.72f6cac9.js +0 -1
- package/dist/js/app.72f6cac9.js +0 -1
|
@@ -1,181 +1,566 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div style="height:100svh; background:#f5f5f5;">
|
|
3
|
-
|
|
4
|
-
<!-- menu top,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<div style="height:100svh; background:#f5f5f5;">
|
|
3
|
+
|
|
4
|
+
<!-- menu top, 內容驅動之RWD(同 w-web-sso ADR-067): 系統名稱/說明/語系選單全部攤開所需之自然寬未超過標題列寬時為寬版(與原版面相同),
|
|
5
|
+
超過則右側收合為漢堡按鈕(WPopup內含當前登入者資訊/語系切換); 名稱與說明各自以剩餘寬為上限, 超出顯示省略符號並以WTooltip提供全文.
|
|
6
|
+
overflow:hidden為保險, 正常情況下任何寬度皆不溢出(原overflow-y:hidden會使水平方向自動出現捲軸, 語系選單被擠出畫面) -->
|
|
7
|
+
<div
|
|
8
|
+
ref="rfHeader"
|
|
9
|
+
data-fmid="app-topbar"
|
|
10
|
+
:style="`height:${heightToolbar}px; box-sizing:border-box; overflow:hidden; padding:0px 10px; background:#fff; border-bottom:1px solid #ccc; display:flex; align-items:center;`"
|
|
11
|
+
v-domresize
|
|
12
|
+
@domresize="resizeHeader"
|
|
13
|
+
>
|
|
14
|
+
|
|
15
|
+
<!-- 識別區, flex:1與min-width:0使寬度隨版寬伸縮, 不再以nowrap撐開整列 -->
|
|
16
|
+
<div style="padding-left:5px; display:flex; align-items:center; flex:1 1 auto; min-width:0;">
|
|
17
|
+
|
|
18
|
+
<div style="padding-right:10px; display:flex; align-items:center; flex:0 0 auto;" v-if="webLogo">
|
|
19
|
+
<img style="width:36px; _min-width:36px; height:36px;" :src="webLogo" />
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div style="flex:1 1 auto; min-width:0;">
|
|
23
|
+
|
|
24
|
+
<!-- 系統名稱, 超出剩餘寬時省略; 僅於確實被截斷時啟用tooltip, 顯示中則維持啟用直到移出, 避免截斷狀態於顯示中翻轉致提示無法關閉(editable為false時mouseleave不處理) -->
|
|
25
|
+
<WTooltip
|
|
26
|
+
:displayType="'line'"
|
|
27
|
+
:isolated="true"
|
|
28
|
+
:placement="'bottom-start'"
|
|
29
|
+
:maxWidth="tooltipMaxWidth"
|
|
30
|
+
:editable="webNameTruncated || tipNameShown"
|
|
31
|
+
@show="tipNameShown=true"
|
|
32
|
+
@hide="tipNameShown=false"
|
|
33
|
+
>
|
|
34
|
+
<template v-slot:trigger>
|
|
35
|
+
<div
|
|
36
|
+
ref="rfWebName"
|
|
37
|
+
style="font-size:1.2rem; color:#000; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;"
|
|
38
|
+
>{{webName}}</div>
|
|
39
|
+
</template>
|
|
40
|
+
<template v-slot:content>
|
|
41
|
+
<div style="white-space:normal; word-break:break-word;">{{webName}}</div>
|
|
42
|
+
</template>
|
|
43
|
+
</WTooltip>
|
|
44
|
+
|
|
45
|
+
<!-- 系統說明, 同上 -->
|
|
46
|
+
<WTooltip
|
|
47
|
+
:displayType="'line'"
|
|
48
|
+
:isolated="true"
|
|
49
|
+
:placement="'bottom-start'"
|
|
50
|
+
:maxWidth="tooltipMaxWidth"
|
|
51
|
+
:editable="webDescTruncated || tipDescShown"
|
|
52
|
+
@show="tipDescShown=true"
|
|
53
|
+
@hide="tipDescShown=false"
|
|
54
|
+
>
|
|
55
|
+
<template v-slot:trigger>
|
|
56
|
+
<div
|
|
57
|
+
ref="rfWebDesc"
|
|
58
|
+
style="font-size:0.8rem; color:#666; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;"
|
|
59
|
+
>{{webDesc}}</div>
|
|
60
|
+
</template>
|
|
61
|
+
<template v-slot:content>
|
|
62
|
+
<div style="white-space:normal; word-break:break-word;">{{webDesc}}</div>
|
|
63
|
+
</template>
|
|
64
|
+
</WTooltip>
|
|
65
|
+
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div
|
|
71
|
+
style="padding-right:10px; white-space:nowrap; flex:0 0 auto;"
|
|
72
|
+
v-if="showLangSelect && !isNarrow"
|
|
73
|
+
>
|
|
74
|
+
<WTextSelect
|
|
75
|
+
style="width:100px;"
|
|
76
|
+
:items="keysLang"
|
|
77
|
+
:value="lang"
|
|
78
|
+
@input="toggleLang"
|
|
79
|
+
>
|
|
80
|
+
<template v-slot:select="props">
|
|
81
|
+
{{getLangText(props.item)}}
|
|
82
|
+
</template>
|
|
83
|
+
<template v-slot:item="props">
|
|
84
|
+
{{getLangText(props.item)}}
|
|
85
|
+
</template>
|
|
86
|
+
</WTextSelect>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<!-- 窄版: 右側收合為漢堡按鈕, 彈窗內依序為當前登入者資訊/語系切換(本系統無登出功能);
|
|
90
|
+
用v-show而非v-if: 非isolated之WPopup於開啟中被銷毀時不會自行隱藏(不釋放popper與開啟層級清單), 故切回寬版時改以menuOpen=false正常關閉;
|
|
91
|
+
v-show之元素其靜態style不可含display: Vue 2.7.16之updateStyle每次重繪皆重設靜態style全部屬性, 會蓋掉v-show之display:none, 故flex置於內層 -->
|
|
92
|
+
<div
|
|
93
|
+
style="padding-left:10px; padding-right:5px; flex:0 0 auto;"
|
|
94
|
+
v-show="isNarrow && hasMenuItems"
|
|
95
|
+
@keydown.esc="closeMenu"
|
|
96
|
+
>
|
|
97
|
+
<div style="display:flex; align-items:center;">
|
|
98
|
+
|
|
99
|
+
<WPopup
|
|
100
|
+
:placement="'bottom-end'"
|
|
101
|
+
:value="menuOpen"
|
|
102
|
+
@input="setMenuOpen"
|
|
103
|
+
>
|
|
104
|
+
<template v-slot:trigger>
|
|
105
|
+
<!-- 開關一律由toggleMenu經menuOpen控制(再次點擊即關閉, 開啟中以active維持底色); 攔下click不讓WPopup觸發區自行開啟:
|
|
106
|
+
使用者真實點擊時各監聽器之間會先執行microtask, 按鈕之toggleMenu關閉後觸發區仍收到同一click而重新開啟. 外部點擊關閉走window之mouseup, 不受影響 -->
|
|
107
|
+
<div @click.stop>
|
|
108
|
+
<WButtonCircle
|
|
109
|
+
ref="rfMenuBtn"
|
|
110
|
+
:paddingStyle="{v:6,h:6}"
|
|
111
|
+
:icon="mdiMenu"
|
|
112
|
+
:backgroundColor="'#fff'"
|
|
113
|
+
:backgroundColorHover="'#f2f2f2'"
|
|
114
|
+
:iconColor="'#444'"
|
|
115
|
+
:iconColorHover="'#222'"
|
|
116
|
+
:iconColorFocus="'#222'"
|
|
117
|
+
:iconColorActive="'#222'"
|
|
118
|
+
:shadow="false"
|
|
119
|
+
:active="menuOpen"
|
|
120
|
+
:aria-label="$t('menuUser')"
|
|
121
|
+
:aria-expanded="menuOpen?'true':'false'"
|
|
122
|
+
@click="toggleMenu"
|
|
123
|
+
></WButtonCircle>
|
|
124
|
+
</div>
|
|
125
|
+
</template>
|
|
126
|
+
<template v-slot:content>
|
|
127
|
+
<div
|
|
128
|
+
:style="`min-width:220px; max-width:${menuMaxWidth}px; padding:4px 0px; font-size:0.85rem; color:#222;`"
|
|
129
|
+
@keydown.esc="closeMenu"
|
|
130
|
+
>
|
|
131
|
+
|
|
132
|
+
<!-- 當前登入者資訊: 姓名為主, Email為輔 -->
|
|
133
|
+
<div
|
|
134
|
+
style="padding:8px 12px; display:flex; align-items:center;"
|
|
135
|
+
v-if="userName || userEmail"
|
|
136
|
+
>
|
|
137
|
+
<div style="flex:0 0 36px; display:flex; justify-content:center;">
|
|
138
|
+
<WIcon
|
|
139
|
+
:icon="mdiAccountCircleOutline"
|
|
140
|
+
:color="'grey darken-1'"
|
|
141
|
+
:colorHover="'grey darken-1'"
|
|
142
|
+
:size="36"
|
|
143
|
+
></WIcon>
|
|
144
|
+
</div>
|
|
145
|
+
<div style="padding-left:10px; min-width:0;">
|
|
146
|
+
<div style="font-size:0.9rem; color:#222; word-break:break-word;">
|
|
147
|
+
{{userName || userEmail}}
|
|
148
|
+
</div>
|
|
149
|
+
<div
|
|
150
|
+
style="font-size:0.75rem; color:#666; word-break:break-all;"
|
|
151
|
+
v-if="userName && userEmail"
|
|
152
|
+
>
|
|
153
|
+
{{userEmail}}
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<!-- 語系切換, 下拉選單同寬版 -->
|
|
159
|
+
<div
|
|
160
|
+
:style="`${(userName || userEmail)?'border-top:1px solid #ddd;':''} padding:8px 12px; display:flex; align-items:center;`"
|
|
161
|
+
v-if="showLangSelect"
|
|
162
|
+
>
|
|
163
|
+
<div style="flex:0 0 36px; display:flex; justify-content:center;">
|
|
164
|
+
<WIcon
|
|
165
|
+
:icon="mdiTranslate"
|
|
166
|
+
:color="'grey darken-1'"
|
|
167
|
+
:colorHover="'grey darken-1'"
|
|
168
|
+
:size="20"
|
|
169
|
+
></WIcon>
|
|
170
|
+
</div>
|
|
171
|
+
<div style="padding-left:10px; flex:1 1 auto; white-space:nowrap;">
|
|
172
|
+
{{$t('language')}}
|
|
173
|
+
</div>
|
|
174
|
+
<div style="padding-left:10px; flex:0 0 auto;">
|
|
175
|
+
<WTextSelect
|
|
176
|
+
style="width:100px;"
|
|
177
|
+
:items="keysLang"
|
|
178
|
+
:value="lang"
|
|
179
|
+
@input="toggleLang"
|
|
180
|
+
>
|
|
181
|
+
<template v-slot:select="props">
|
|
182
|
+
{{getLangText(props.item)}}
|
|
183
|
+
</template>
|
|
184
|
+
<template v-slot:item="props">
|
|
185
|
+
{{getLangText(props.item)}}
|
|
186
|
+
</template>
|
|
187
|
+
</WTextSelect>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
</div>
|
|
192
|
+
</template>
|
|
193
|
+
</WPopup>
|
|
194
|
+
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<div :style="`height:calc( 100% - ${heightToolbar}px );`">
|
|
201
|
+
<LayoutContent
|
|
202
|
+
></LayoutContent>
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
</div>
|
|
207
|
+
</template>
|
|
208
|
+
|
|
209
|
+
<script>
|
|
210
|
+
import { mdiMenu, mdiAccountCircleOutline, mdiTranslate } from '@mdi/js/mdi.js'
|
|
211
|
+
import get from 'lodash-es/get.js'
|
|
212
|
+
// import cloneDeep from 'lodash-es/cloneDeep.js'
|
|
213
|
+
import isestr from 'wsemi/src/isestr.mjs'
|
|
214
|
+
import WIcon from 'w-component-vue/src/components/WIcon.vue'
|
|
215
|
+
import WPopup from 'w-component-vue/src/components/WPopup.vue'
|
|
216
|
+
import WTooltip from 'w-component-vue/src/components/WTooltip.vue'
|
|
217
|
+
import WTextSelect from 'w-component-vue/src/components/WTextSelect.vue'
|
|
218
|
+
import WButtonCircle from 'w-component-vue/src/components/WButtonCircle.vue'
|
|
219
|
+
import LayoutContent from './LayoutContent.vue'
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
//寬窄版判斷用之固定寬(px), 須與template之寬版結構一致
|
|
223
|
+
const hdPadH = 20 //標題列左右padding各10
|
|
224
|
+
const hdLeftPad = 5 //識別區padding-left
|
|
225
|
+
const hdLogoW = 36 + 10 //logo寬+其padding-right
|
|
226
|
+
const hdLangW = 100 + 10 //語系選單寬+其容器padding-right
|
|
227
|
+
const hdGap = 10 //寬版時名稱說明與右側群組間至少保留之間距
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
//量測文字自然寬(px), 以canvas量測, 不受DOM截斷(省略符號)影響
|
|
231
|
+
let ctxMeasure = null
|
|
232
|
+
function measureTextWidth(text, font) {
|
|
233
|
+
if (!isestr(text)) {
|
|
234
|
+
return 0
|
|
235
|
+
}
|
|
236
|
+
if (ctxMeasure === null) {
|
|
237
|
+
ctxMeasure = document.createElement('canvas').getContext('2d')
|
|
238
|
+
}
|
|
239
|
+
ctxMeasure.font = font
|
|
240
|
+
return ctxMeasure.measureText(text).width
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
//取元素實際字型字串, 供canvas量測
|
|
245
|
+
function getElFont(el) {
|
|
246
|
+
if (!el) {
|
|
247
|
+
return ''
|
|
248
|
+
}
|
|
249
|
+
let cs = window.getComputedStyle(el)
|
|
250
|
+
return `${cs.fontStyle} ${cs.fontWeight} ${cs.fontSize} ${cs.fontFamily}`
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
export default {
|
|
255
|
+
components: {
|
|
256
|
+
WIcon,
|
|
257
|
+
WPopup,
|
|
258
|
+
WTooltip,
|
|
259
|
+
WTextSelect,
|
|
260
|
+
WButtonCircle,
|
|
261
|
+
LayoutContent,
|
|
262
|
+
},
|
|
263
|
+
props: {
|
|
264
|
+
},
|
|
265
|
+
data: function() {
|
|
266
|
+
return {
|
|
267
|
+
mdiMenu,
|
|
268
|
+
mdiAccountCircleOutline,
|
|
269
|
+
mdiTranslate,
|
|
270
|
+
|
|
271
|
+
firstSetting: true,
|
|
272
|
+
|
|
273
|
+
showLangSelect: false,
|
|
274
|
+
|
|
275
|
+
keysLang: [
|
|
276
|
+
'eng',
|
|
277
|
+
'cht',
|
|
278
|
+
],
|
|
279
|
+
kpLangSelect: {
|
|
280
|
+
'eng': 'English',
|
|
281
|
+
'cht': '中文',
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
hdW: 0, //標題列寬(clientWidth), 0代表尚未量測
|
|
285
|
+
fontName: '', //系統名稱實際字型, 供canvas量測自然寬
|
|
286
|
+
fontDesc: '', //系統說明實際字型
|
|
287
|
+
fontsTick: 0, //字型載入完成後遞增, 觸發文字自然寬重算
|
|
288
|
+
|
|
289
|
+
menuOpen: false, //窄版漢堡選單是否開啟
|
|
290
|
+
|
|
291
|
+
webNameTruncated: false, //系統名稱是否被截斷(顯示省略符號)
|
|
292
|
+
webDescTruncated: false, //系統說明是否被截斷
|
|
293
|
+
tipNameShown: false, //系統名稱tooltip是否顯示中
|
|
294
|
+
tipDescShown: false, //系統說明tooltip是否顯示中
|
|
295
|
+
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
mounted: function() {
|
|
299
|
+
// console.log('mounted')
|
|
300
|
+
|
|
301
|
+
let vo = this
|
|
302
|
+
|
|
303
|
+
//字型與標題列寬, 於mounted同步設定, 寬窄版於首次繪製前即確定(資料變更之重繪在microtask內完成)
|
|
304
|
+
vo.readFonts()
|
|
305
|
+
let elHeader = vo.$refs.rfHeader
|
|
306
|
+
if (elHeader) {
|
|
307
|
+
vo.hdW = elHeader.clientWidth
|
|
308
|
+
}
|
|
309
|
+
if (document.fonts && document.fonts.ready) {
|
|
310
|
+
document.fonts.ready.then(() => {
|
|
311
|
+
vo.readFonts()
|
|
312
|
+
vo.fontsTick++
|
|
313
|
+
})
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
//firstSetting
|
|
317
|
+
if (vo.firstSetting) {
|
|
318
|
+
// console.log('webInfor', vo.webInfor)
|
|
319
|
+
let showLanguage = get(vo, 'webInfor.showLanguage', '')
|
|
320
|
+
// console.log('showLanguage', showLanguage)
|
|
321
|
+
vo.showLangSelect = showLanguage === 'y'
|
|
322
|
+
let language = get(vo, 'webInfor.language', '')
|
|
323
|
+
// console.log('language', language)
|
|
324
|
+
vo.$ui.setLang(language, 'layout mounted')
|
|
325
|
+
vo.firstSetting = false
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
},
|
|
329
|
+
computed: {
|
|
330
|
+
|
|
331
|
+
// viewState: function() {
|
|
332
|
+
// let vo = this
|
|
333
|
+
// return get(vo, '$store.state.viewState', '')
|
|
334
|
+
// },
|
|
335
|
+
|
|
336
|
+
heightToolbar: function() {
|
|
337
|
+
let vo = this
|
|
338
|
+
return get(vo, `$store.state.heightToolbar`, 0)
|
|
339
|
+
},
|
|
340
|
+
|
|
341
|
+
webInfor: function() {
|
|
342
|
+
let wi = get(this, `$store.state.webInfor`)
|
|
343
|
+
return wi
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
webName: {
|
|
347
|
+
get() {
|
|
348
|
+
let vo = this
|
|
349
|
+
let c = vo.$t('webName', '')
|
|
350
|
+
// console.log('get webName1', c)
|
|
351
|
+
if (!isestr(c)) {
|
|
352
|
+
c = vo.$t('waitingData', '')
|
|
353
|
+
}
|
|
354
|
+
// console.log('get webName2', c)
|
|
355
|
+
document.title = c //更換網頁title
|
|
356
|
+
return c
|
|
357
|
+
},
|
|
358
|
+
// set(value) {
|
|
359
|
+
// return value
|
|
360
|
+
// },
|
|
361
|
+
},
|
|
362
|
+
|
|
363
|
+
webDesc: function() {
|
|
364
|
+
let vo = this
|
|
365
|
+
return vo.$t('webDescription')
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
webLogo: function() {
|
|
369
|
+
let vo = this
|
|
370
|
+
return get(vo, 'webInfor.webLogo', '')
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
lang: function() {
|
|
374
|
+
let vo = this
|
|
375
|
+
return get(vo, '$store.state.lang', '')
|
|
376
|
+
},
|
|
377
|
+
|
|
378
|
+
userName: function() {
|
|
379
|
+
let vo = this
|
|
380
|
+
return get(vo, '$store.state.userSelf.name', '')
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
userEmail: function() {
|
|
384
|
+
let vo = this
|
|
385
|
+
return get(vo, '$store.state.userSelf.email', '')
|
|
386
|
+
},
|
|
387
|
+
|
|
388
|
+
hasMenuItems: function() {
|
|
389
|
+
//漢堡選單有內容才顯示按鈕
|
|
390
|
+
let vo = this
|
|
391
|
+
return vo.showLangSelect || isestr(vo.userName) || isestr(vo.userEmail)
|
|
392
|
+
},
|
|
393
|
+
|
|
394
|
+
natLeftWidth: function() {
|
|
395
|
+
//識別區自然寬: padding + logo + 名稱與說明之較寬者
|
|
396
|
+
let vo = this
|
|
397
|
+
let wName = vo.getTextWidth(vo.webName, vo.fontName)
|
|
398
|
+
let wDesc = vo.getTextWidth(vo.webDesc, vo.fontDesc)
|
|
399
|
+
return hdLeftPad + (vo.webLogo ? hdLogoW : 0) + Math.max(wName, wDesc)
|
|
400
|
+
},
|
|
401
|
+
|
|
402
|
+
natRightWidth: function() {
|
|
403
|
+
//寬版右側群組自然寬: 語系選單
|
|
404
|
+
let vo = this
|
|
405
|
+
return vo.showLangSelect ? hdLangW : 0
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
isNarrow: function() {
|
|
409
|
+
//全部攤開所需寬度超過標題列寬即為窄版, 未量測前(hdW為0)視為寬版
|
|
410
|
+
let vo = this
|
|
411
|
+
if (vo.hdW <= 0) {
|
|
412
|
+
return false
|
|
413
|
+
}
|
|
414
|
+
return hdPadH + vo.natLeftWidth + vo.natRightWidth + hdGap > vo.hdW
|
|
415
|
+
},
|
|
416
|
+
|
|
417
|
+
tooltipMaxWidth: function() {
|
|
418
|
+
//名稱與說明tooltip最大寬(不含其左右padding共20), 不超出版寬
|
|
419
|
+
let vo = this
|
|
420
|
+
return Math.max(100, Math.min(400, vo.hdW - 40))
|
|
421
|
+
},
|
|
422
|
+
|
|
423
|
+
menuMaxWidth: function() {
|
|
424
|
+
//漢堡選單最大寬, 不超出版寬
|
|
425
|
+
let vo = this
|
|
426
|
+
return Math.max(220, Math.min(320, vo.hdW - 20))
|
|
427
|
+
},
|
|
428
|
+
|
|
429
|
+
layoutSig: function() {
|
|
430
|
+
//影響名稱與說明是否被截斷之因子, 變更時重新偵測截斷狀態
|
|
431
|
+
let vo = this
|
|
432
|
+
return `${vo.hdW}|${vo.isNarrow}|${vo.hasMenuItems}|${!!vo.webLogo}|${vo.webName}|${vo.webDesc}|${vo.fontsTick}`
|
|
433
|
+
},
|
|
434
|
+
|
|
435
|
+
},
|
|
436
|
+
watch: {
|
|
437
|
+
|
|
438
|
+
isNarrow: function(v) {
|
|
439
|
+
//切回寬版時關閉漢堡選單(漢堡按鈕隨之隱藏)
|
|
440
|
+
let vo = this
|
|
441
|
+
if (!v) {
|
|
442
|
+
vo.menuOpen = false
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
|
|
446
|
+
layoutSig: function() {
|
|
447
|
+
let vo = this
|
|
448
|
+
vo.$nextTick(() => {
|
|
449
|
+
vo.checkTruncated()
|
|
450
|
+
})
|
|
451
|
+
},
|
|
452
|
+
|
|
453
|
+
},
|
|
454
|
+
methods: {
|
|
455
|
+
|
|
456
|
+
readFonts: function() {
|
|
457
|
+
let vo = this
|
|
458
|
+
vo.fontName = getElFont(vo.$refs.rfWebName)
|
|
459
|
+
vo.fontDesc = getElFont(vo.$refs.rfWebDesc)
|
|
460
|
+
},
|
|
461
|
+
|
|
462
|
+
getTextWidth: function(text, font) {
|
|
463
|
+
//以指定字型量測文字自然寬; fontsTick僅作為相依觸發重算
|
|
464
|
+
let vo = this
|
|
465
|
+
if (vo.fontsTick < 0 || !isestr(font)) {
|
|
466
|
+
return 0
|
|
467
|
+
}
|
|
468
|
+
return measureTextWidth(text, font)
|
|
469
|
+
},
|
|
470
|
+
|
|
471
|
+
resizeHeader: function(msg) {
|
|
472
|
+
// console.log('methods resizeHeader', msg)
|
|
473
|
+
|
|
474
|
+
let vo = this
|
|
475
|
+
|
|
476
|
+
//hdW, 直接讀元素當下寬度, 不用msg.snew(視窗resize事件所帶者為前次輪詢之舊值)
|
|
477
|
+
let el = vo.$refs.rfHeader
|
|
478
|
+
if (el) {
|
|
479
|
+
vo.hdW = el.clientWidth
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
checkTruncated: function() {
|
|
485
|
+
//偵測名稱與說明是否被截斷: scrollWidth為整數, 溢出不足1px時可能偵測不到, 故再以自然寬比對元素實寬
|
|
486
|
+
let vo = this
|
|
487
|
+
let isTruncated = (el, text, font) => {
|
|
488
|
+
if (!el) {
|
|
489
|
+
return false
|
|
490
|
+
}
|
|
491
|
+
if (el.scrollWidth > el.clientWidth) {
|
|
492
|
+
return true
|
|
493
|
+
}
|
|
494
|
+
return vo.getTextWidth(text, font) > el.getBoundingClientRect().width + 0.05
|
|
495
|
+
}
|
|
496
|
+
vo.webNameTruncated = isTruncated(vo.$refs.rfWebName, vo.webName, vo.fontName)
|
|
497
|
+
vo.webDescTruncated = isTruncated(vo.$refs.rfWebDesc, vo.webDesc, vo.fontDesc)
|
|
498
|
+
},
|
|
499
|
+
|
|
500
|
+
toggleMenu: function() {
|
|
501
|
+
// console.log('methods toggleMenu')
|
|
502
|
+
|
|
503
|
+
let vo = this
|
|
504
|
+
|
|
505
|
+
vo.menuOpen = !vo.menuOpen
|
|
506
|
+
|
|
507
|
+
},
|
|
508
|
+
|
|
509
|
+
setMenuOpen: function(b) {
|
|
510
|
+
// console.log('methods setMenuOpen', b)
|
|
511
|
+
|
|
512
|
+
let vo = this
|
|
513
|
+
|
|
514
|
+
vo.menuOpen = b
|
|
515
|
+
|
|
516
|
+
},
|
|
517
|
+
|
|
518
|
+
closeMenu: function() {
|
|
519
|
+
// console.log('methods closeMenu')
|
|
520
|
+
|
|
521
|
+
let vo = this
|
|
522
|
+
|
|
523
|
+
//check
|
|
524
|
+
if (!vo.menuOpen) {
|
|
525
|
+
return
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
vo.menuOpen = false
|
|
529
|
+
|
|
530
|
+
//焦點回到漢堡按鈕(焦點原位於選單內時, 選單內容銷毀後焦點會遺失); WButtonCircle內有兩個tabindex=0之元素,
|
|
531
|
+
//外層為其tooltip觸發區, 內層為按鈕本體(具Enter處理), 故取最後一個
|
|
532
|
+
let el = get(vo, '$refs.rfMenuBtn.$el', null)
|
|
533
|
+
let els = el ? el.querySelectorAll('[tabindex="0"]') : []
|
|
534
|
+
let elFocus = els.length > 0 ? els[els.length - 1] : null
|
|
535
|
+
if (elFocus) {
|
|
536
|
+
elFocus.focus()
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
},
|
|
540
|
+
|
|
541
|
+
getLangText: function(lang) {
|
|
542
|
+
// console.log('methods getLangText', lang)
|
|
543
|
+
|
|
544
|
+
let vo = this
|
|
545
|
+
|
|
546
|
+
let t = get(vo, `kpLangSelect.${lang}`, '')
|
|
547
|
+
|
|
548
|
+
return t
|
|
549
|
+
},
|
|
550
|
+
|
|
551
|
+
toggleLang: function(lang) {
|
|
552
|
+
// console.log('methods toggleLang', lang)
|
|
553
|
+
|
|
554
|
+
let vo = this
|
|
555
|
+
|
|
556
|
+
//setLang
|
|
557
|
+
vo.$ui.setLang(lang, 'toggle')
|
|
558
|
+
|
|
559
|
+
},
|
|
560
|
+
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
</script>
|
|
564
|
+
|
|
565
|
+
<style scoped>
|
|
566
|
+
</style>
|