mercury_editor-2.0.x-dev/source/js/autosave.js

source/js/autosave.js
((Drupal, drupalSettings, $) => {
  let ajaxing = false;
  function setAjaxing(value) {
    document.body.classList.toggle('me-ajaxing', value);
    ajaxing = value;
  }
  $(document).on('ajaxStart', () => setAjaxing(true));
  $(document).on('ajaxComplete', () => setAjaxing(false));

  let interacting = false;
  window.addEventListener('message', (event) => {
    if (event.data.type === 'layoutParagraphsEvent') {
      if (event.data.eventName === 'lpb-component:drag') {
        interacting = true;
      }
      if (event.data.eventName === 'lpb-component:drop') {
        interacting = false;
      }
    }
  });

  /**
   * Serializes a form.
   * @param {HTMLElement} form The form element.
   * @return {string} The serialized form data.
   */
  function serializeForm(form) {
    // JavaScript editors like CKEditor and CodeMirror save changes to text areas
    // when behaviors are detached. So we need to detach behaviors first, then
    // serialize the form.
    Drupal.detachBehaviors(form, drupalSettings, 'serialize');
    // Drupal.attachBehaviors(form, drupalSettings);
    let formData = Object.fromEntries(new FormData(form).entries());
    formData = Object.fromEntries(
      Object.entries(formData).filter(
        ([, value]) => value !== '' && value !== null && value !== undefined,
      ),
    );
    formData = Object.keys(formData)
      .sort()
      .reduce((obj, key) => {
        obj[key] = formData[key];
        return obj;
      }, {});
    // Remove non-essential keys to avoid false positives.
    ['form_build_id', 'form_id', 'form_token', 'tabs'].forEach((key) => {
      delete formData[key];
    });
    return JSON.stringify(formData);
  }

  /**
   * Debounced function to submit form when it changes.
   * @param {Element} form The form.
   * @return {boolean} True if the form has changed.
   */
  function checkFormForChanges(form) {
    if (
      interacting ||
      ajaxing ||
      !drupalSettings.ajaxPreviewPageState ||
      !form.serializedData ||
      form.hasAttribute('data-me-saving') ||
      form.querySelector('input[type="file"][disabled]')
    ) {
      return false;
    }
    const serializedData = serializeForm(form);
    // No changes detected.
    if (form.serializedData === serializedData) {
      return false;
    }
    form.serializedData = serializedData;
    return true;
  }

  // Only one form is autosaved at a time, so we need to keep track of it.
  let autosaveForm = null;

  /**
   * @todo Pause the interval after period of inactivity.
   * @todo Evaluate for performance.
   */
  let autosaveInterval = null;

  /**
   * Start polling for changes in the autosave form.
   * @todo Use a more efficient way to check for changes.
   */
  function startPolling() {
    if (autosaveInterval) {
      return;
    }
    autosaveInterval = setInterval(() => {
      if (!ajaxing && autosaveForm) {
        if (checkFormForChanges(autosaveForm) === true) {
          const saveButton = autosaveForm.querySelector('.me-autosave-btn');
          if (saveButton) {
            saveButton.dispatchEvent(new Event('mousedown'));
          }
        }
      }
    }, 500);
  }

  /**
   * Stop polling for changes in the autosave form.
   */
  function stopPolling() {
    if (autosaveInterval) {
      clearInterval(autosaveInterval);
      autosaveInterval = null;
    }
  }

  /**
   * Set the autosave form to the last autosave button's parent form in the DOM.
   */
  function setAutosaveForm() {
    const autosaveBtns = document.querySelectorAll('form .me-autosave-btn');
    if (autosaveBtns.length > 0) {
      autosaveForm = autosaveBtns[autosaveBtns.length - 1].closest('form');
      if (!autosaveForm.serializedData) {
        autosaveForm.serializedData = serializeForm(autosaveForm);
      }
      autosaveForm.classList.add('me-autosave');
      startPolling();
    } else {
      autosaveForm = null;
      stopPolling();
    }
  }
  /**
   * Debounced function to check validity of inputs on keyup.
   * @todo Re-evaluate necessity, approach, and UX impact.
   */
  // let checkValidityTimeout = null;
  // document.addEventListener('keyup', (event) => {
  //   if (!event.target.validity) return;
  //   clearTimeout(checkValidityTimeout);
  //   checkValidityTimeout = setTimeout(
  //     () => {
  //       if (!event.target.validity.valid) {
  //         event.target.reportValidity();
  //       }
  //     },
  //     event.target.type === 'date' || event.target.type === 'time' ? 1000 : 500,
  //   );
  // });
  /**
   * Re-evaluate the autosave form when a dialog is closed.
   */
  document.addEventListener('dialog:afterclose', () => {
    setTimeout(setAutosaveForm, 100);
  });
  /**
   * Attaches the autosave behavior to forms with the .me-autosave-form class.
   */
  Drupal.behaviors.mercuryEditorAutosave = {
    attach() {
      if (document.querySelectorAll('.me-autosave-form')) {
        setAutosaveForm();
      }
    },
  };
})(Drupal, drupalSettings, jQuery, once, Drupal.debounce);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc