Jake Vanderwerf
2025-10-18 b0194e10a87e16797a568d8a30d53ebecd27d8a4
assets/js/concise/FormController.js
@@ -3,11 +3,20 @@
 * Works with DataStore for CRUD operations and standalone for front-end forms
 */
class FormController {
   constructor(store = null) {
      this.store = store; // Optional - for CRUD operations
      if (!store) {
         this.store = new window.jvbStore({name:'forms', TTL: 604800});
      }
   constructor() {
      this.store = new window.jvbStore({
         name:'forms',
         storeName: 'forms',
         keyPath: 'formId',
         indexes: [
            { name: 'status', keyPath: 'status' },
            { name: 'operationId', keyPath: 'operationId' },
            { name: 'timestamp', keyPath: 'timestamp' },
            { name: 'formType', keyPath: 'type' }
         ],
         TTL: 604800000, //7 days
      });
      this.debouncer = window.debouncer;
      this.ignore = [];
@@ -52,21 +61,38 @@
      // Check for pending operations on page load
      await this.checkPendingOperations();
      this.store.subscribe(this.handleStoreEvent.bind(this));
      // Set up global form handlers for standalone forms
      this.initListeners();
   }
   handleStoreEvent(event, data) {
      switch(event) {
         case 'item-saved':
            if (data.item.status === 'autosave') {
               this.showFormStatus(data.item.formId, 'autosave');
            }
            break;
         case 'data-loaded':
            break;
      }
   }
   /**
    * Check for pending operations from previous session
    */
   async checkPendingOperations() {
      if (!this.store) return;
      try {
         let pending = this.store.getAllForms();
      const pendingForms = await this.store.query('status', 'pending');
      } catch (error) {
         console.error('Failed to load pending forms:', error);
      }
      if (pendingForms.length === 0) return;
      // Group by form type or page
      const grouped = this.groupPendingForms(pendingForms);
      // Show consolidated notification
      this.showPendingNotification(grouped);
   }
   /**
@@ -121,7 +147,7 @@
    * Discard pending form data
    */
   async discardPendingForm(formId) {
      this.store.clearForm(formId);
      this.store.delete(formId);
      if (window.jvbA11y) {
         window.jvbA11y.announce('Previous changes discarded');
@@ -485,16 +511,18 @@
   /**
    * Initialize image upload fields
    */
   initImageUploadFields() {
      window.jvbUploads.scanFields();
   initImageUploadFields(form) {
      window.jvbUploads.scanFields(form);
   }
   /* ========== Event Handlers ========== */
   handleSubmit(event) {
      //TODO: submit data, if successful, delete from store
      if (this.subscribers.size > 0 ){
         const form = event.target;
         if (!form.dataset.formId) return;
         this.store.delete(form.dataset.formId);
         event.preventDefault();
@@ -629,7 +657,6 @@
    * Get appropriate delay based on field type and context
    */
   getDelayForField(field) {
      console.log('Get Delay for Field', field);
      // Text fields get longer delay for typing
      if (field.type === 'text' || field.type === 'textarea') {
         return this.autoSaveDefaults.typingDelay;
@@ -665,7 +692,14 @@
   async autosave(formConfig) {
      const formData = this.collectFormData(formConfig.element);
      this.cacheFormData(formConfig, formData);
      await this.store.save({
         formId: formConfig.id,
         data: formData,
         status: 'draft',
         timestamp: Date.now()
      });
      this.showFormStatus(formConfig.id, 'saved');
      // Get only changed fields
      const changes = this.getChangedFields(formConfig.data, formData);
@@ -691,20 +725,6 @@
      });
   }
   cacheFormData(formConfig, formData) {
      try {
         this.store.storeForm(formConfig.id, {
            formId: formConfig.id,
            formData: formData,
            timestamp: Date.now(),
            status: 'pending',
            operationId: null
         });
      } catch (error) {
         console.error('Failed to cache form data:', error);
      }
   }
   /**
    * Check if form has unsaved changes
    */
@@ -971,7 +991,6 @@
   cleanupForm(formId) {
      const formConfig = this.forms.get(formId);
      if (!formConfig) return;
      console.log('Cleaning up form', formConfig);
      // Check for unsaved changes
      if (this.hasUnsavedChanges(formId)) {