Skip to content

Commit f6ccad9

Browse files
committed
Fix mobile signature placement and coordinate serialization
Signed-off-by: Phillip <phillipxh@gmail.com>
1 parent 87e6c83 commit f6ccad9

4 files changed

Lines changed: 115 additions & 26 deletions

File tree

src/components/PdfEditor/PdfEditor.vue

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ type PdfElementsInstance = {
127127
selectedDocIndex?: number
128128
autoFitZoom?: boolean
129129
}
130+
type PdfElementsRuntimeInstance = PdfElementsInstance & {
131+
handleMouseMove?: (event: { type: string, touches: Array<{ clientX: number, clientY: number }> }) => void
132+
finishAdding?: () => void
133+
previewElement?: Record<string, unknown> | null
134+
previewVisible?: boolean
135+
}
130136
131137
defineOptions({
132138
name: 'PdfEditor',
@@ -155,6 +161,7 @@ const pdfElements = ref<PdfElementsInstance | null>(null)
155161
const pendingAddedObjectCount = ref<number | null>(null)
156162
157163
let pendingAddCheckTimer: ReturnType<typeof setTimeout> | null = null
164+
let pendingAddCheckRetries = 0
158165
159166
const ignoreClickOutsideSelectors = computed(() => ['.action-item__popper', '.action-item'])
160167
@@ -271,6 +278,7 @@ function clearPendingAddCheck() {
271278
clearTimeout(pendingAddCheckTimer)
272279
pendingAddCheckTimer = null
273280
}
281+
pendingAddCheckRetries = 0
274282
pendingAddedObjectCount.value = null
275283
}
276284
@@ -283,11 +291,29 @@ function checkSignerAdded() {
283291
pendingAddCheckTimer = null
284292
const isAddingMode = pdfElements.value?.isAddingMode === true
285293
const objectsAfter = getTotalObjectsCount()
286-
pendingAddedObjectCount.value = null
287294
288-
if (!isAddingMode && objectsAfter > objectsBefore) {
295+
if (objectsAfter > objectsBefore) {
296+
clearPendingAddCheck()
289297
emit('pdf-editor:signer-added')
298+
return
299+
}
300+
301+
// Fallback: once add mode ends, unblock the UI even if the object count
302+
// comparison was not conclusive due timing/reactivity.
303+
if (!isAddingMode) {
304+
clearPendingAddCheck()
305+
emit('pdf-editor:signer-added')
306+
return
290307
}
308+
309+
// Poll while the external component still processes placement.
310+
if (pendingAddCheckRetries < 300) {
311+
pendingAddCheckRetries++
312+
pendingAddCheckTimer = setTimeout(checkSignerAdded, 100)
313+
return
314+
}
315+
316+
clearPendingAddCheck()
291317
}
292318
293319
function scheduleSignerAddedCheck() {
@@ -300,6 +326,38 @@ function scheduleSignerAddedCheck() {
300326
pendingAddCheckTimer = setTimeout(checkSignerAdded, 0)
301327
}
302328
329+
function handleDocumentTouchEnd(event: Event) {
330+
if (pendingAddedObjectCount.value === null) {
331+
return
332+
}
333+
334+
const instance = pdfElements.value as PdfElementsRuntimeInstance | null
335+
const touchEvent = event as TouchEvent
336+
const touchPoint = touchEvent.changedTouches?.[0]
337+
if (!instance || !touchPoint) {
338+
scheduleSignerAddedCheck()
339+
return
340+
}
341+
342+
// Work around mobile tap placement timing in pdf-elements: touchend has no
343+
// touches[0], so preview may never become visible on first tap.
344+
if (instance.isAddingMode && instance.previewElement && !instance.previewVisible && instance.handleMouseMove) {
345+
instance.handleMouseMove({
346+
type: 'touchmove',
347+
touches: [{ clientX: touchPoint.clientX, clientY: touchPoint.clientY }],
348+
})
349+
requestAnimationFrame(() => {
350+
if (instance.isAddingMode) {
351+
instance.finishAdding?.()
352+
}
353+
scheduleSignerAddedCheck()
354+
})
355+
return
356+
}
357+
358+
scheduleSignerAddedCheck()
359+
}
360+
303361
function startAddingSigner(signer: SignerSummaryRecord | SignerDetailRecord | null | undefined, size: { width?: number, height?: number }) {
304362
if (!pdfElements.value || !size?.width || !size?.height) {
305363
return false
@@ -319,6 +377,11 @@ function startAddingSigner(signer: SignerSummaryRecord | SignerDetailRecord | nu
319377
signer: signerPayload,
320378
})
321379
pendingAddedObjectCount.value = getTotalObjectsCount()
380+
pendingAddCheckRetries = 0
381+
if (pendingAddCheckTimer !== null) {
382+
clearTimeout(pendingAddCheckTimer)
383+
}
384+
pendingAddCheckTimer = setTimeout(checkSignerAdded, 100)
322385
323386
return true
324387
}
@@ -383,15 +446,11 @@ async function waitForPageRender(docIndex: number, pageIndex: number) {
383446
384447
onMounted(() => {
385448
ensurePdfWorker()
386-
document.addEventListener('mouseup', scheduleSignerAddedCheck)
387-
document.addEventListener('touchend', scheduleSignerAddedCheck)
388-
document.addEventListener('keyup', scheduleSignerAddedCheck)
449+
document.addEventListener('touchend', handleDocumentTouchEnd)
389450
})
390451
391452
onBeforeUnmount(() => {
392-
document.removeEventListener('mouseup', scheduleSignerAddedCheck)
393-
document.removeEventListener('touchend', scheduleSignerAddedCheck)
394-
document.removeEventListener('keyup', scheduleSignerAddedCheck)
453+
document.removeEventListener('touchend', handleDocumentTouchEnd)
395454
clearPendingAddCheck()
396455
})
397456

src/components/Request/VisibleElements.vue

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,22 @@
5151
</template>
5252
</Signer>
5353
</ul>
54-
<NcButton v-if="canSave"
55-
:variant="variantOfSaveButton"
56-
:wide="true"
57-
:class="{ disabled: signerSelected }"
58-
@click="save()">
59-
{{ t('libresign', 'Save') }}
60-
</NcButton>
61-
62-
<NcButton v-if="canSign"
63-
:variant="variantOfSignButton"
64-
:wide="true"
65-
@click="goToSign">
66-
{{ t('libresign', 'Sign') }}
67-
</NcButton>
54+
<div class="sign-details__actions">
55+
<NcButton v-if="canSave"
56+
:variant="variantOfSaveButton"
57+
:wide="true"
58+
:class="{ disabled: signerSelected }"
59+
@click="save()">
60+
{{ t('libresign', 'Save') }}
61+
</NcButton>
62+
63+
<NcButton v-if="canSign"
64+
:variant="variantOfSignButton"
65+
:wide="true"
66+
@click="goToSign">
67+
{{ t('libresign', 'Sign') }}
68+
</NcButton>
69+
</div>
6870
</div>
6971
<PdfEditor v-if="!filesStore.loading && pdfFiles.length > 0"
7072
ref="pdfEditor"
@@ -947,6 +949,12 @@ defineExpose({
947949
margin: 3px 3px 1em 3px;
948950
}
949951
}
952+
&__actions {
953+
position: sticky;
954+
bottom: 0;
955+
background-color: var(--color-main-background);
956+
padding-top: 4px;
957+
}
950958
.disabled {
951959
pointer-events: none;
952960
visibility: hidden;

src/store/files.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -867,10 +867,11 @@ const _filesStore = defineStore('files', () => {
867867
}
868868
const coordinates = element.coordinates && typeof element.coordinates === 'object'
869869
? {
870-
x: element.coordinates.x,
871-
y: element.coordinates.y,
872-
w: element.coordinates.w,
873-
h: element.coordinates.h,
870+
page: element.coordinates.page,
871+
top: element.coordinates.top,
872+
left: element.coordinates.left,
873+
width: element.coordinates.width,
874+
height: element.coordinates.height,
874875
}
875876
: undefined
876877
return {

vite.config.mjs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,26 @@
66
import { createAppConfig } from '@nextcloud/vite-config'
77
import { resolve } from 'node:path'
88

9+
const patchPdfElementsTouchmovePassive = {
10+
name: 'patch-pdf-elements-touchmove-passive',
11+
enforce: 'pre',
12+
transform(code, id) {
13+
if (!id.includes('/@libresign/pdf-elements/')) {
14+
return null
15+
}
16+
if (!id.endsWith('/dist/index.mjs') && !id.endsWith('/src/components/DraggableElement.vue')) {
17+
return null
18+
}
19+
20+
const replaced = code.replace(
21+
/window\.addEventListener\((['"])touchmove\1,\s*this\.boundHandleMove\)/g,
22+
'window.addEventListener($1touchmove$1, this.boundHandleMove, { passive: false })',
23+
)
24+
25+
return replaced === code ? null : { code: replaced, map: null }
26+
},
27+
}
28+
929
export default createAppConfig({
1030
main: resolve('src/main.ts'),
1131
init: resolve('src/init.ts'),
@@ -25,6 +45,7 @@ export default createAppConfig({
2545
},
2646
},
2747
plugins: [
48+
patchPdfElementsTouchmovePassive,
2849
{
2950
name: 'vue-devtools',
3051
config(_, { mode }) {

0 commit comments

Comments
 (0)