{"version":3,"file":"index.mjs","sources":[""],"sourcesContent":["import { bubble } from \"@web3r/flowerkit/evt\";\r\nimport { wait } from \"@web3r/flowerkit/fn\";\r\nimport type { TGetFromServerArgs } from \"@web3r/flowerkit/net\";\r\nimport { getFromServer } from \"@web3r/flowerkit/net\";\r\nimport { getObjFromFormData } from \"@web3r/flowerkit/obj\";\r\nimport { getDocument } from \"ssr-window\";\r\nimport { constants } from \"../../../constants\";\r\nimport { getCheckedBoxes } from \"../../../utils/getCheckedBoxes\";\r\nimport { _getFormExtendedCfg } from \"../utils/_getFormExtendedCfg\";\r\nimport type { IFormExtendedCfg } from \"../utils/_getFormExtendedCfg\";\r\n\r\ntype TRequestMethod = NonNullable<TGetFromServerArgs<unknown>[\"method\"]>;\r\ntype TRequestContentType = NonNullable<TGetFromServerArgs<unknown>[\"contentType\"]>;\r\n\r\nconst getRequestMethod = (method: unknown): TRequestMethod => {\r\n  switch (method) {\r\n    case \"POST\":\r\n    case \"GET\":\r\n    case \"PUT\":\r\n    case \"DELETE\":\r\n    case \"HEAD\":\r\n    case \"CONNECT\":\r\n    case \"OPTIONS\":\r\n    case \"TRACE\":\r\n      return method;\r\n    case \"PATCH\":\r\n      return \"POST\";\r\n    default:\r\n      return \"POST\";\r\n  }\r\n};\r\n\r\nconst getRequestContentType = (contentType: unknown): TRequestContentType => {\r\n  switch (contentType) {\r\n    case \"auto\":\r\n    case \"application/json\":\r\n    case \"multipart/form-data\":\r\n    case \"application/x-www-form-urlencoded\":\r\n      return contentType;\r\n    default:\r\n      return \"auto\";\r\n  }\r\n};\r\n\r\n/**\r\n * Singleton. Плагин для отправки форм.\r\n * Автоматически отправляет валидную форму с атрибутом `data-js-form` в зависимости от ее параметров.\r\n * @module FormSend\r\n */\r\nexport class FormSend {\r\n\r\n  static #instance: FormSend | null = null;\r\n\r\n  constructor() {\r\n    if (FormSend.#instance) {\r\n      return FormSend.#instance;\r\n    }\r\n    this.#bindEvents();\r\n    FormSend.#instance = this;\r\n  }\r\n\r\n  /**\r\n   * Получает данные формы\r\n   * @param form{HTMLFormElement} форма\r\n   * @param isGetAll{Boolean=} получение всех input, включая disabled\r\n   * @param excludedParams{Array=} исключаемые из данных названия имён\r\n   * @param isTrim{Boolean=} удаление пустых значений\r\n   * @returns {FormData}\r\n   */\r\n  static getFormData(form: IFormExtendedCfg[\"form\"], isGetAll = false, excludedParams: string[] = [], isTrim = false) {\r\n    const cfg = _getFormExtendedCfg(form);\r\n    const fd = new FormData(form);\r\n    if (cfg.isSerializeDisabledInputs || isGetAll) {\r\n      const disabledInputs = form.querySelectorAll<HTMLInputElement>(\"[disabled]\");\r\n      disabledInputs.forEach(({ name, value, type }) => {\r\n        const set = (name: string, value: string) => fd.set(name, value);\r\n        if (type === \"radio\") {\r\n          const radios = getCheckedBoxes(getDocument().querySelectorAll(`[name=${name}]`), `[type=\"radio\"]`);\r\n          if (radios.length) {\r\n            set(name, (radios[0] as HTMLInputElement).value);\r\n          }\r\n        } else {\r\n          set(name, value);\r\n        }\r\n      });\r\n    }\r\n    if (cfg.isRemoveEmptyFiles) {\r\n      const filesInput = form.querySelectorAll<HTMLInputElement>(`[type='file'][name]`);\r\n      filesInput.forEach(({ name, value }) => {\r\n        if (!value) {\r\n          fd.delete(name);\r\n        }\r\n      });\r\n    }\r\n    [ ...fd.entries() ].forEach(([ name, value ]) => {\r\n      if ((isTrim && typeof value === \"string\" && !value.trim().length) || excludedParams.includes(name as string)) {\r\n        fd.delete(name as string);\r\n      }\r\n    });\r\n    return fd;\r\n  }\r\n\r\n  /**\r\n   * Стандартный обработчик успешной отправки формы\r\n   */\r\n  static async onSend(resp: unknown, cfg: IFormExtendedCfg) {\r\n    const { delay, form } = cfg || {\r\n      delay: 0,\r\n      form: null,\r\n    };\r\n    if (form) {\r\n      await wait(delay)\r\n        .finally(() => {\r\n          console.debug(\"[FormSend] Form sent successfully: \", form, resp);\r\n          bubble(form as HTMLFormElement, constants.formBubbles.formSuccess, {\r\n            resp,\r\n            cfg,\r\n          });\r\n          FormSend.#setLoadingState(form as IFormExtendedCfg[\"form\"], false);\r\n        });\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Стандартный обработчик неудачной отправки формы\r\n   */\r\n  static async onFail(resp: unknown, cfg: IFormExtendedCfg) {\r\n    const { form, delay } = cfg || {\r\n      delay: 0,\r\n      form: null,\r\n    };\r\n    if (form) {\r\n      await wait(delay)\r\n        .finally(() => {\r\n          console.debug(\"[FormSend] Form error on sending: \", form, resp);\r\n          bubble(form as HTMLFormElement, constants.formBubbles.formError, { resp, cfg });\r\n          FormSend.#setLoadingState(form as IFormExtendedCfg[\"form\"], false);\r\n        });\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Управление состоянием блокировки формы во время отправки данных\r\n   * @private\r\n   * @param form{HTMLFormElement} форма\r\n   * @param isLoading{Boolean=} состояние блокировки\r\n   * @param timeOut{Number=} задержка перехода в состояние\r\n   */\r\n  static #setLoadingState(form: IFormExtendedCfg[\"form\"], isLoading = true, timeOut = 0) {\r\n    const cfg = _getFormExtendedCfg(form);\r\n    const { successTimeOut, handler } = cfg;\r\n    timeOut = timeOut || (successTimeOut as number);\r\n    const fn = () => {\r\n      form.classList.toggle(constants.stateClasses.loading, isLoading);\r\n      if (handler && (handler.matches(\"button\") || handler.matches(\"[type=\\\"submit\\\"]\"))) {\r\n        (handler as HTMLButtonElement).disabled = isLoading;\r\n      }\r\n    };\r\n    (typeof timeOut === \"number\" && timeOut > 0) ? wait(timeOut).then(() => fn()) : fn();\r\n  }\r\n\r\n  /**\r\n   * Отправка данных формы на сервер\r\n   * @param form{HTMLFormElement} форма\r\n   * @param data{FormData|Object=} данные формы\r\n   * @returns {Promise}\r\n   */\r\n  static async getSendResult(form: IFormExtendedCfg[\"form\"], data?: FormData) {\r\n\r\n    const {\r\n      url, isShowLoader, contentType, method, getFromServerOptions,\r\n    } = _getFormExtendedCfg(form);\r\n    const body = data || FormSend.getFormData(form);\r\n    const requestContentType = getRequestContentType(contentType);\r\n    const requestMethod = getRequestMethod(method);\r\n    const requestData = requestContentType === \"application/json\" ? getObjFromFormData(body) : body;\r\n\r\n    if (isShowLoader) {\r\n      FormSend.#setLoadingState(form);\r\n    }\r\n\r\n    console.debug(\"[FormSend] Form sending:\", form, \"with data:\", [ ...body.entries() ], \"type:\", contentType, \"and method:\", method);\r\n    bubble(form, constants.formBubbles.formSending);\r\n\r\n    return await getFromServer({\r\n      data: requestData,\r\n      url: typeof url === \"string\" ? url : \"./\",\r\n      method: requestMethod,\r\n      contentType: requestContentType,\r\n      timeout: 30000,\r\n      ...(getFromServerOptions || {}),\r\n    });\r\n  }\r\n\r\n  #bindEvents() {\r\n    getDocument().addEventListener(constants.formBubbles.formValid, (e: Event) => this.#handleFormValid(e));\r\n  }\r\n\r\n  async #handleFormValid(e: Event) {\r\n    const { target } = e;\r\n    const cfg = _getFormExtendedCfg(target as IFormExtendedCfg[\"form\"]);\r\n    const { isIgnoreAutoSend, isUseFetch, isConfirmBeforeSubmit } = cfg;\r\n    const send = async (fd?: FormData) => {\r\n      if (isUseFetch) {\r\n        return FormSend.getSendResult(target as IFormExtendedCfg[\"form\"], fd)\r\n          .then((resp: unknown) => {\r\n            FormSend.onSend(resp, cfg);\r\n            return resp;\r\n          }, (resp: unknown) => {\r\n            FormSend.onFail(resp, cfg);\r\n            return resp;\r\n          });\r\n      } else {\r\n        (target as HTMLFormElement).submit();\r\n        return Promise.resolve();\r\n      }\r\n    };\r\n    if (!isIgnoreAutoSend) {\r\n      if (isConfirmBeforeSubmit) {\r\n        const fd = FormSend.getFormData(target as IFormExtendedCfg[\"form\"]);\r\n        bubble(target as HTMLFormElement, constants.formBubbles.formNeedsConfirm, {\r\n          getSendResult: async () => send(fd),\r\n          cfg,\r\n          fd,\r\n        });\r\n      } else {\r\n        await send();\r\n      }\r\n    }\r\n  }\r\n\r\n}\r\n"],"names":["getRequestMethod","method","getRequestContentType","contentType","FormSend","static","constructor","instance","this","bindEvents","getFormData","form","isGetAll","excludedParams","isTrim","cfg","_getFormExtendedCfg","fd","FormData","isSerializeDisabledInputs","disabledInputs","querySelectorAll","forEach","name","value","type","set","radios","getCheckedBoxes","getDocument","length","isRemoveEmptyFiles","filesInput","delete","entries","trim","includes","onSend","resp","delay","wait","finally","console","debug","bubble","constants","formBubbles","formSuccess","setLoadingState","onFail","formError","isLoading","timeOut","successTimeOut","handler","fn","classList","toggle","stateClasses","loading","matches","disabled","then","getSendResult","data","url","isShowLoader","getFromServerOptions","body","requestContentType","requestMethod","requestData","getObjFromFormData","formSending","getFromServer","timeout","addEventListener","formValid","e","handleFormValid","target","isIgnoreAutoSend","isUseFetch","isConfirmBeforeSubmit","send","async","submit","Promise","resolve","formNeedsConfirm"],"mappings":"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"}