@@ -117,11 +117,10 @@ const authStore = useAuthStore();
117117const formStore = useFormStore ();
118118const notificationStore = useNotificationStore ();
119119
120- // Local crash-recovery autosave
120+ // Local crash-recovery autosave (storage layer)
121121const localAutosave = useLocalAutosave ();
122122const showLocalRecoveryDialog = ref (false );
123- const autosaveReady = ref (false );
124- const initialRenderComplete = ref (false ); // Prevent autosave firing during Form.io internal events
123+ const autosaveReady = ref (false ); // becomes true after first Form.io render
125124
126125const { config } = storeToRefs (appStore);
127126const { authenticated , keycloak , tokenParsed , user } = storeToRefs (authStore);
@@ -219,7 +218,7 @@ onBeforeUnmount(() => {
219218 window .removeEventListener (' beforeunload' , beforeWindowUnload);
220219 clearTimeout (downloadTimeout .value );
221220
222- // Cleanup local autosave
221+ // Cleanup local autosave debounce
223222 localAutosave .cleanup ();
224223});
225224
@@ -233,6 +232,13 @@ function getCurrentAuthHeader() {
233232 return ` Bearer ${ keycloak .value .token } ` ;
234233}
235234
235+ /**
236+ * Central autosave initialization:
237+ * - Only for authenticated, non-preview, non-readonly forms
238+ * - Only when form.enableAutoSave is true
239+ * - Builds a per-user, per-form(+submission) storage key
240+ * - Decides whether to show the recovery dialog
241+ */
236242function initializeLocalAutosave () {
237243 // Only enable for authenticated users on non-readonly, non-preview forms
238244 if (
@@ -256,7 +262,7 @@ function initializeLocalAutosave() {
256262 userId: authStore .currentUser .idpUserId ,
257263 });
258264
259- // Check if we should show recovery dialog
265+ // Decide if we should show the recovery dialog
260266 const shouldRecover = localAutosave .shouldShowRecoveryDialog (
261267 submissionRecord .value
262268 );
@@ -296,13 +302,6 @@ function handleLocalDiscard() {
296302}
297303
298304async function getFormData () {
299- // We are loading an existing submission:
300- // - stop autosave
301- // - clear any stale local autosave data
302- // - reset render flags so Form.io can re-init safely
303- localAutosave .clear ();
304- autosaveReady .value = false ;
305- initialRenderComplete .value = false ;
306305 function iterate (obj , stack , fields , propNeeded ) {
307306 // Get property path from nested object
308307 for (let property in obj) {
@@ -514,6 +513,13 @@ function isProcessingMultiUpload(e) {
514513 block .value = e;
515514}
516515
516+ /**
517+ * Form change handler:
518+ * - Validates drafts on change
519+ * - Ignores Form.io's internal "fromSubmission" changes
520+ * - Marks real user input
521+ * - Triggers autosave only when ready and allowed
522+ */
517523function formChange (e ) {
518524 // If this is a draft, validate on change
519525 if (submissionRecord .value .draft ) {
@@ -528,12 +534,11 @@ function formChange(e) {
528534 // user typing
529535 formDataEntered .value = true ;
530536
531- // AUTOSAVE – only when:
532- // autosave is ready
533- // form has enableAutoSave turned on
534- // not read-only or preview
535- // Form.io has valid _data
536-
537+ // AUTOSAVE – only when:
538+ // autosave flag ready (Form.io render happened)
539+ // form has enableAutoSave turned on
540+ // not read-only or preview
541+ // Form.io has valid _data
537542 if (
538543 autosaveReady .value &&
539544 form .value ? .enableAutoSave &&
@@ -628,11 +633,8 @@ async function sendSubmission(isDraft, sub) {
628633}
629634
630635function onFormRender () {
631- // Mark initial render complete + allow autosave AFTER Form.io finish render
632- if (! initialRenderComplete .value ) {
633- initialRenderComplete .value = true ;
634- autosaveReady .value = true ;
635- }
636+ // Mark autosave as ready AFTER Form.io finishes first render
637+ autosaveReady .value = true ;
636638
637639 if (isLoading .value ) isLoading .value = false ;
638640}
@@ -653,7 +655,6 @@ function onSubmitButton(event) {
653655 }
654656 // this is our first event in the submission chain.
655657 // most important thing here is ensuring that the formio form does not have an action, or else it POSTs to that action.
656- // console.info('onSubmitButton()') ; // eslint-disable-line no-console
657658 currentForm .value = event .instance .parent .root ;
658659 currentForm .value .form .action = undefined ;
659660
@@ -888,8 +889,8 @@ function beforeWindowUnload(e) {
888889
889890 // If autosave is enabled on this form, it can *reduce* warnings
890891 if (form .value ? .enableAutoSave ) {
891- // If a debounced save is still pending, assume it will complete soon
892- // Skip warning if save is pending OR data already exists in localStorage
892+ // If a debounced save is still pending, assume it will complete soon,
893+ // or if there is an autosave snapshot available, do not warn.
893894 if (
894895 (localAutosave ._isPending && localAutosave ._isPending ()) ||
895896 localAutosave .exists ()
0 commit comments