js-kompo-utils 1.0.23 → 1.0.25
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/components/VlSelect.vue +111 -14
- package/package.json +1 -1
package/components/VlSelect.vue
CHANGED
|
@@ -27,9 +27,11 @@
|
|
|
27
27
|
class="vlNativeSelect"
|
|
28
28
|
:value="nativeValue"
|
|
29
29
|
@change="onNativeChange"
|
|
30
|
+
@mousedown="onNativeOpen"
|
|
31
|
+
@focus="onNativeOpen"
|
|
30
32
|
:style="nativeSelectStyle">
|
|
31
33
|
<option value="">{{ nativePlaceholder }}</option>
|
|
32
|
-
<option v-for="opt in
|
|
34
|
+
<option v-for="opt in nativeOptionsList" :key="opt.value" :value="opt.value">{{ nativeLabel(opt) }}</option>
|
|
33
35
|
</select>
|
|
34
36
|
</div>
|
|
35
37
|
<div class="vlOptions vlOptionsTeleported"
|
|
@@ -85,8 +87,11 @@ export default {
|
|
|
85
87
|
return this.panelStyle
|
|
86
88
|
},
|
|
87
89
|
useNativeMobile() {
|
|
88
|
-
if (this.$_config('
|
|
89
|
-
return this.isTouchDevice && !this.$_multiple
|
|
90
|
+
if (!this.$_config('native_on_mobile')) return false
|
|
91
|
+
return this.isTouchDevice && !this.$_multiple
|
|
92
|
+
},
|
|
93
|
+
nativeOptionsList() {
|
|
94
|
+
return this.ajaxOptions ? this.filteredOptions : this.options
|
|
90
95
|
},
|
|
91
96
|
nativeValue() {
|
|
92
97
|
return this.$_value && this.$_value.length ? this.$_value[0].value : ''
|
|
@@ -121,12 +126,21 @@ export default {
|
|
|
121
126
|
filteredOptions() {
|
|
122
127
|
if (this.isFocused) this.$nextTick(() => this.refresh())
|
|
123
128
|
},
|
|
129
|
+
optionsKey() {
|
|
130
|
+
this.$nextTick(() => {
|
|
131
|
+
this.teleportOptions()
|
|
132
|
+
if (this.isFocused) this.refresh()
|
|
133
|
+
})
|
|
134
|
+
},
|
|
124
135
|
},
|
|
125
136
|
mounted() {
|
|
126
137
|
this.teleportOptions()
|
|
127
138
|
if (typeof window !== 'undefined' && window.matchMedia) {
|
|
128
139
|
this.isTouchDevice = window.matchMedia('(pointer: coarse)').matches
|
|
129
140
|
}
|
|
141
|
+
if (this.useNativeMobile && this.ajaxOptions) {
|
|
142
|
+
this.$nextTick(() => this.onNativeOpen())
|
|
143
|
+
}
|
|
130
144
|
},
|
|
131
145
|
beforeDestroy() {
|
|
132
146
|
this.cleanupOptions()
|
|
@@ -136,14 +150,33 @@ export default {
|
|
|
136
150
|
onNativeChange(e) {
|
|
137
151
|
const v = e.target.value
|
|
138
152
|
if (v === '') return
|
|
139
|
-
const
|
|
153
|
+
const list = this.nativeOptionsList || []
|
|
154
|
+
const opt = list.find(o => String(o.value) === String(v))
|
|
140
155
|
if (opt) this.select(opt)
|
|
141
156
|
},
|
|
157
|
+
onNativeOpen() {
|
|
158
|
+
if (!this.ajaxOptions) return
|
|
159
|
+
if (this.ajaxOptionsFromField) {
|
|
160
|
+
this.$kompo.vlRequestFieldValue(this.kompoid, this.ajaxOptionsFromField, this.$_elKompoId)
|
|
161
|
+
this.performAjax(this.$_getFromStore())
|
|
162
|
+
} else {
|
|
163
|
+
this.performAjax('')
|
|
164
|
+
}
|
|
165
|
+
},
|
|
142
166
|
nativeLabel(opt) {
|
|
143
167
|
const l = opt.label
|
|
144
|
-
|
|
145
|
-
if (
|
|
146
|
-
|
|
168
|
+
let raw = ''
|
|
169
|
+
if (typeof l === 'string') raw = l
|
|
170
|
+
else if (l && typeof l === 'object') raw = l.label || l.text || l.search || ''
|
|
171
|
+
else raw = String(opt.value ?? '')
|
|
172
|
+
return this.stripHtml(raw)
|
|
173
|
+
},
|
|
174
|
+
stripHtml(str) {
|
|
175
|
+
if (!str || typeof str !== 'string') return ''
|
|
176
|
+
if (str.indexOf('<') === -1) return str
|
|
177
|
+
const tmp = document.createElement('div')
|
|
178
|
+
tmp.innerHTML = str
|
|
179
|
+
return (tmp.textContent || tmp.innerText || '').trim()
|
|
147
180
|
},
|
|
148
181
|
teleportOptions() {
|
|
149
182
|
const opts = this.$refs.selectOptions
|
|
@@ -162,22 +195,82 @@ export default {
|
|
|
162
195
|
},
|
|
163
196
|
attachListeners() {
|
|
164
197
|
if (this._listenersAttached) return
|
|
198
|
+
this._rafId = null
|
|
165
199
|
this._onScroll = (e) => {
|
|
166
200
|
const opts = this.$refs.selectOptions
|
|
167
201
|
if (opts && e.target instanceof Node && opts.contains(e.target)) return
|
|
168
|
-
this.
|
|
202
|
+
if (this._rafId) return
|
|
203
|
+
this._rafId = requestAnimationFrame(() => {
|
|
204
|
+
this._rafId = null
|
|
205
|
+
this.trackPosition()
|
|
206
|
+
})
|
|
169
207
|
}
|
|
170
208
|
this._onResize = () => this.refresh()
|
|
171
209
|
window.addEventListener('scroll', this._onScroll, true)
|
|
172
210
|
window.addEventListener('resize', this._onResize, { passive: true })
|
|
211
|
+
|
|
212
|
+
const opts = this.$refs.selectOptions
|
|
213
|
+
const anchor = this.anchorEl()
|
|
214
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
215
|
+
this._panelObserver = new ResizeObserver(() => {
|
|
216
|
+
if (this.isFocused) this.trackPosition()
|
|
217
|
+
})
|
|
218
|
+
if (opts) this._panelObserver.observe(opts)
|
|
219
|
+
this._anchorObserver = new ResizeObserver((entries) => {
|
|
220
|
+
const entry = entries[0]
|
|
221
|
+
if (!entry) return
|
|
222
|
+
const r = entry.contentRect
|
|
223
|
+
const el = entry.target
|
|
224
|
+
if (r.width === 0 || r.height === 0 || !el.isConnected) {
|
|
225
|
+
this.blur()
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
if (anchor) this._anchorObserver.observe(anchor)
|
|
229
|
+
}
|
|
230
|
+
if (typeof IntersectionObserver !== 'undefined' && anchor) {
|
|
231
|
+
this._anchorIntersection = new IntersectionObserver((entries) => {
|
|
232
|
+
const entry = entries[entries.length - 1]
|
|
233
|
+
if (entry && entry.intersectionRatio === 0) this.blur()
|
|
234
|
+
}, { threshold: 0 })
|
|
235
|
+
this._anchorIntersection.observe(anchor)
|
|
236
|
+
}
|
|
237
|
+
|
|
173
238
|
this._listenersAttached = true
|
|
174
239
|
},
|
|
175
240
|
detachListeners() {
|
|
176
241
|
if (!this._listenersAttached) return
|
|
242
|
+
if (this._rafId) {
|
|
243
|
+
cancelAnimationFrame(this._rafId)
|
|
244
|
+
this._rafId = null
|
|
245
|
+
}
|
|
177
246
|
window.removeEventListener('scroll', this._onScroll, true)
|
|
178
247
|
window.removeEventListener('resize', this._onResize)
|
|
248
|
+
if (this._panelObserver) {
|
|
249
|
+
this._panelObserver.disconnect()
|
|
250
|
+
this._panelObserver = null
|
|
251
|
+
}
|
|
252
|
+
if (this._anchorObserver) {
|
|
253
|
+
this._anchorObserver.disconnect()
|
|
254
|
+
this._anchorObserver = null
|
|
255
|
+
}
|
|
256
|
+
if (this._anchorIntersection) {
|
|
257
|
+
this._anchorIntersection.disconnect()
|
|
258
|
+
this._anchorIntersection = null
|
|
259
|
+
}
|
|
179
260
|
this._listenersAttached = false
|
|
180
261
|
},
|
|
262
|
+
trackPosition() {
|
|
263
|
+
const opts = this.$refs.selectOptions
|
|
264
|
+
const anchor = this.anchorEl()
|
|
265
|
+
if (!opts || !anchor) return
|
|
266
|
+
const rect = anchor.getBoundingClientRect()
|
|
267
|
+
const x = Math.round(rect.left)
|
|
268
|
+
const y = this.flipUp
|
|
269
|
+
? Math.round(rect.top) - opts.offsetHeight + 1
|
|
270
|
+
: Math.round(rect.bottom) - 1
|
|
271
|
+
opts.style.transform = `translate3d(${x}px, ${y}px, 0)`
|
|
272
|
+
opts.style.width = Math.round(rect.width) + 'px'
|
|
273
|
+
},
|
|
181
274
|
refresh() {
|
|
182
275
|
const opts = this.$refs.selectOptions
|
|
183
276
|
const anchor = this.anchorEl()
|
|
@@ -185,13 +278,17 @@ export default {
|
|
|
185
278
|
|
|
186
279
|
const rect = anchor.getBoundingClientRect()
|
|
187
280
|
const inOverlay = !!anchor.closest('.kompoModal, .kompoDrawer, .vl-sidebar-l')
|
|
281
|
+
const x = Math.round(rect.left)
|
|
282
|
+
const yBelow = Math.round(rect.bottom) - 1
|
|
188
283
|
const baseStyle = {
|
|
189
284
|
position: 'fixed',
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
zIndex: inOverlay ? 5001 : 1000,
|
|
193
|
-
top: rect.bottom + 'px',
|
|
285
|
+
top: '0px',
|
|
286
|
+
left: '0px',
|
|
194
287
|
bottom: 'auto',
|
|
288
|
+
width: Math.round(rect.width) + 'px',
|
|
289
|
+
zIndex: inOverlay ? 5001 : 1000,
|
|
290
|
+
transform: `translate3d(${x}px, ${yBelow}px, 0)`,
|
|
291
|
+
willChange: 'transform',
|
|
195
292
|
}
|
|
196
293
|
this.panelStyle = baseStyle
|
|
197
294
|
|
|
@@ -202,10 +299,10 @@ export default {
|
|
|
202
299
|
const shouldFlip = this.forceUp || (spaceBelow < optsHeight && spaceAbove > spaceBelow)
|
|
203
300
|
this.flipUp = shouldFlip
|
|
204
301
|
if (shouldFlip) {
|
|
302
|
+
const yAbove = Math.round(rect.top) - optsHeight + 1
|
|
205
303
|
this.panelStyle = {
|
|
206
304
|
...baseStyle,
|
|
207
|
-
|
|
208
|
-
bottom: (window.innerHeight - rect.top) + 'px',
|
|
305
|
+
transform: `translate3d(${x}px, ${yAbove}px, 0)`,
|
|
209
306
|
borderRadius: '5px 5px 0 0',
|
|
210
307
|
}
|
|
211
308
|
}
|