mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-09-04 09:13:24 +00:00
FIX - make phone input and overlays CEF safe
This commit is contained in:
@@ -12,6 +12,10 @@ import { useMarketplaceStore } from '@/stores/marketplace'
|
||||
import { useDarkChatStore } from '@/stores/darkchat'
|
||||
import { usePhoneStore } from '@/stores/phone'
|
||||
import type { PhoneAppDefinition } from '@/types/apps'
|
||||
import {
|
||||
reorderDirectionFromKeyboard,
|
||||
type ReorderDirection,
|
||||
} from '@/utils/keyboard'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -33,6 +37,7 @@ const emit = defineEmits<{
|
||||
dragstart: [event: PointerEvent]
|
||||
edit: []
|
||||
remove: []
|
||||
reorder: [direction: ReorderDirection]
|
||||
}>()
|
||||
|
||||
const phone = usePhoneStore()
|
||||
@@ -65,6 +70,8 @@ const suppressClick = ref(false)
|
||||
let holdTimer: number | undefined
|
||||
let calendarTimer: number | undefined
|
||||
let pointerStart = { x: 0, y: 0 }
|
||||
let pointerTarget: HTMLElement | null = null
|
||||
let pointerId: number | null = null
|
||||
|
||||
watch(
|
||||
() => props.app.iconImage,
|
||||
@@ -135,6 +142,9 @@ function clearHold(): void {
|
||||
|
||||
function onPointerDown(event: PointerEvent): void {
|
||||
if (props.compact || event.button !== 0) return
|
||||
pointerTarget = event.currentTarget as HTMLElement
|
||||
pointerId = event.pointerId
|
||||
pointerTarget.setPointerCapture(pointerId)
|
||||
pointerStart = { x: event.clientX, y: event.clientY }
|
||||
clearHold()
|
||||
if (props.editMode) {
|
||||
@@ -173,35 +183,48 @@ function beginPointerDrag(event: PointerEvent): void {
|
||||
.closest<HTMLElement>('.springboard-page')
|
||||
?.getBoundingClientRect().width ?? 0
|
||||
isDragging.value = true
|
||||
window.addEventListener('pointermove', onPointerMove)
|
||||
window.addEventListener('pointerup', onPointerUp)
|
||||
window.addEventListener('pointercancel', cancelPointerDrag)
|
||||
emit('dragstart', event)
|
||||
}
|
||||
|
||||
function onPointerUp(event: PointerEvent): void {
|
||||
clearHold()
|
||||
if (!isDragging.value) return
|
||||
suppressClick.value = true
|
||||
emit('dragend', event)
|
||||
isDragging.value = false
|
||||
dragOffset.value = { x: 0, y: 0 }
|
||||
removeDragListeners()
|
||||
if (isDragging.value) {
|
||||
suppressClick.value = true
|
||||
emit('dragend', event)
|
||||
isDragging.value = false
|
||||
dragOffset.value = { x: 0, y: 0 }
|
||||
}
|
||||
releasePointerCapture()
|
||||
}
|
||||
|
||||
function cancelPointerDrag(): void {
|
||||
clearHold()
|
||||
if (!isDragging.value) return
|
||||
const wasDragging = isDragging.value
|
||||
isDragging.value = false
|
||||
dragOffset.value = { x: 0, y: 0 }
|
||||
removeDragListeners()
|
||||
emit('dragcancel')
|
||||
releasePointerCapture()
|
||||
if (wasDragging) emit('dragcancel')
|
||||
}
|
||||
|
||||
function removeDragListeners(): void {
|
||||
window.removeEventListener('pointermove', onPointerMove)
|
||||
window.removeEventListener('pointerup', onPointerUp)
|
||||
window.removeEventListener('pointercancel', cancelPointerDrag)
|
||||
function releasePointerCapture(): void {
|
||||
if (
|
||||
pointerTarget &&
|
||||
pointerId !== null &&
|
||||
pointerTarget.hasPointerCapture(pointerId)
|
||||
) {
|
||||
pointerTarget.releasePointerCapture(pointerId)
|
||||
}
|
||||
pointerTarget = null
|
||||
pointerId = null
|
||||
}
|
||||
|
||||
function onKeydown(event: KeyboardEvent): void {
|
||||
if (!props.editMode) return
|
||||
const direction = reorderDirectionFromKeyboard(event)
|
||||
if (!direction) return
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
emit('reorder', direction)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@@ -214,7 +237,7 @@ onMounted(() => {
|
||||
onBeforeUnmount(() => {
|
||||
clearHold()
|
||||
if (calendarTimer !== undefined) window.clearInterval(calendarTimer)
|
||||
removeDragListeners()
|
||||
releasePointerCapture()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -234,10 +257,15 @@ onBeforeUnmount(() => {
|
||||
type="button"
|
||||
:aria-label="getPhoneAppLabel(app, phone.t)"
|
||||
:aria-disabled="!app.route"
|
||||
:aria-keyshortcuts="
|
||||
editMode ? 'ArrowLeft ArrowRight ArrowUp ArrowDown' : undefined
|
||||
"
|
||||
@click="launch"
|
||||
@contextmenu.prevent
|
||||
@keydown="onKeydown"
|
||||
@pointercancel="cancelPointerDrag"
|
||||
@pointerdown="onPointerDown"
|
||||
@lostpointercapture="cancelPointerDrag"
|
||||
@pointerleave="isDragging || clearHold()"
|
||||
@pointermove="onPointerMove"
|
||||
@pointerup="onPointerUp"
|
||||
|
||||
@@ -35,7 +35,10 @@ function closeFromOutside(event: PointerEvent): void {
|
||||
}
|
||||
|
||||
function closeFromEscape(event: KeyboardEvent): void {
|
||||
if (event.key === 'Escape') opened.value = false
|
||||
if (event.key !== 'Escape' || !opened.value) return
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
opened.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -31,6 +31,10 @@ import { useCallsStore } from '@/stores/calls'
|
||||
import { useMessagesStore } from '@/stores/messages'
|
||||
import { usePhoneStore } from '@/stores/phone'
|
||||
import type { WidgetInstance } from '@/types/widgets'
|
||||
import {
|
||||
reorderDirectionFromKeyboard,
|
||||
type ReorderDirection,
|
||||
} from '@/utils/keyboard'
|
||||
import type { WeatherConditionId } from '@/types/weather'
|
||||
import { WIDGET_SPANS } from '@/utils/widgetLayout'
|
||||
|
||||
@@ -50,6 +54,7 @@ const emit = defineEmits<{
|
||||
dragstart: [event: PointerEvent]
|
||||
menu: []
|
||||
remove: []
|
||||
reorder: [direction: ReorderDirection]
|
||||
}>()
|
||||
|
||||
const phone = usePhoneStore()
|
||||
@@ -68,6 +73,8 @@ let holdTimer: number | undefined
|
||||
let pointerStart = { x: 0, y: 0 }
|
||||
let dragStartPage = 0
|
||||
let dragPageWidth = 0
|
||||
let pointerTarget: HTMLElement | null = null
|
||||
let pointerId: number | null = null
|
||||
|
||||
const weatherIcons: Record<WeatherConditionId, Component> = {
|
||||
sunny: Sun,
|
||||
@@ -173,6 +180,9 @@ function onPointerDown(event: PointerEvent): void {
|
||||
) {
|
||||
return
|
||||
}
|
||||
pointerTarget = event.currentTarget as HTMLElement
|
||||
pointerId = event.pointerId
|
||||
pointerTarget.setPointerCapture(pointerId)
|
||||
pointerStart = { x: event.clientX, y: event.clientY }
|
||||
clearHold()
|
||||
if (props.editMode) {
|
||||
@@ -210,35 +220,48 @@ function beginDrag(event: PointerEvent): void {
|
||||
.closest<HTMLElement>('.springboard-page')
|
||||
?.getBoundingClientRect().width ?? 0
|
||||
isDragging.value = true
|
||||
window.addEventListener('pointermove', onPointerMove)
|
||||
window.addEventListener('pointerup', onPointerUp)
|
||||
window.addEventListener('pointercancel', cancelDrag)
|
||||
emit('dragstart', event)
|
||||
}
|
||||
|
||||
function onPointerUp(event: PointerEvent): void {
|
||||
clearHold()
|
||||
if (!isDragging.value) return
|
||||
suppressClick.value = true
|
||||
emit('dragend', event)
|
||||
isDragging.value = false
|
||||
dragOffset.value = { x: 0, y: 0 }
|
||||
removeDragListeners()
|
||||
if (isDragging.value) {
|
||||
suppressClick.value = true
|
||||
emit('dragend', event)
|
||||
isDragging.value = false
|
||||
dragOffset.value = { x: 0, y: 0 }
|
||||
}
|
||||
releasePointerCapture()
|
||||
}
|
||||
|
||||
function cancelDrag(): void {
|
||||
clearHold()
|
||||
if (!isDragging.value) return
|
||||
const wasDragging = isDragging.value
|
||||
isDragging.value = false
|
||||
dragOffset.value = { x: 0, y: 0 }
|
||||
removeDragListeners()
|
||||
emit('dragcancel')
|
||||
releasePointerCapture()
|
||||
if (wasDragging) emit('dragcancel')
|
||||
}
|
||||
|
||||
function removeDragListeners(): void {
|
||||
window.removeEventListener('pointermove', onPointerMove)
|
||||
window.removeEventListener('pointerup', onPointerUp)
|
||||
window.removeEventListener('pointercancel', cancelDrag)
|
||||
function releasePointerCapture(): void {
|
||||
if (
|
||||
pointerTarget &&
|
||||
pointerId !== null &&
|
||||
pointerTarget.hasPointerCapture(pointerId)
|
||||
) {
|
||||
pointerTarget.releasePointerCapture(pointerId)
|
||||
}
|
||||
pointerTarget = null
|
||||
pointerId = null
|
||||
}
|
||||
|
||||
function onKeydown(event: KeyboardEvent): void {
|
||||
if (!props.editMode) return
|
||||
const direction = reorderDirectionFromKeyboard(event)
|
||||
if (!direction) return
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
emit('reorder', direction)
|
||||
}
|
||||
|
||||
function openWidget(): void {
|
||||
@@ -276,7 +299,7 @@ async function messageContact(phoneNumber: string): Promise<void> {
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearHold()
|
||||
removeDragListeners()
|
||||
releasePointerCapture()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -300,9 +323,14 @@ onBeforeUnmount(() => {
|
||||
:class="`home-widget--${instance.kind}`"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
:aria-keyshortcuts="
|
||||
editMode ? 'ArrowLeft ArrowRight ArrowUp ArrowDown' : undefined
|
||||
"
|
||||
@click="openWidget"
|
||||
@contextmenu.prevent
|
||||
@keydown="onKeydown"
|
||||
@keydown.enter="openWidget"
|
||||
@lostpointercapture="cancelDrag"
|
||||
@pointercancel="cancelDrag"
|
||||
@pointerdown="onPointerDown"
|
||||
@pointerleave="isDragging || clearHold()"
|
||||
|
||||
@@ -3,6 +3,7 @@ import { computed } from 'vue'
|
||||
|
||||
import SpringboardWidget from '@/components/SpringboardWidget.vue'
|
||||
import { useWidgetsStore } from '@/stores/widgets'
|
||||
import type { ReorderDirection } from '@/utils/keyboard'
|
||||
import { WIDGET_HOME_ROWS, WIDGET_PAGE_ROWS } from '@/utils/widgetLayout'
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -17,6 +18,7 @@ const emit = defineEmits<{
|
||||
dragstart: [id: string, event: PointerEvent]
|
||||
menu: [id: string]
|
||||
remove: [id: string]
|
||||
reorder: [id: string, direction: ReorderDirection]
|
||||
}>()
|
||||
const widgets = useWidgetsStore()
|
||||
const rows = computed(() =>
|
||||
@@ -51,6 +53,7 @@ const instances = computed(() =>
|
||||
@dragstart="emit('dragstart', instance.id, $event)"
|
||||
@menu="emit('menu', instance.id)"
|
||||
@remove="emit('remove', instance.id)"
|
||||
@reorder="emit('reorder', instance.id, $event)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -41,6 +41,9 @@ function select(value: string): void {
|
||||
|
||||
function handleKeydown(event: KeyboardEvent): void {
|
||||
if (event.key === 'Escape') {
|
||||
if (!isOpen.value) return
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
isOpen.value = false
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user