{"version":3,"file":"form_controller-C8o5-k8o.js","sources":["../../../frontend/common/controllers/form_controller.js"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\n/**\n * Controller extends native form and adds some perks:\n * - Syncs input and checkboxes state that have same name\n * - `button[data-form-target=\"submit\"]` - disables button when form state isn't changed\n * - `form[data-form-lock-on-change-value]` - locks window if form changed but not saved\n * - `form[data-form-update-url-value]` - Adds form state to page query once submitted\n */\nexport default class extends Controller {\n static targets = ['submit']\n\n static values = {\n lockOnChange: Boolean,\n updateUrl: Boolean,\n preventSubmitOnEnter: Boolean\n }\n\n initialState = ''\n\n isDirty = false\n\n get shouldLockWindow() {\n return this.lockOnChangeValue\n }\n\n get shouldUpdateUrl() {\n return this.updateUrlValue\n }\n\n connect() {\n this.initialState = this.currentState\n this.updateElements()\n\n this.element.addEventListener('input', this.handleFormChange)\n this.element.addEventListener('change', this.handleFormChange)\n this.element.addEventListener('submit', this.handleFormSubmit)\n\n if (this.shouldUpdateUrl) {\n window.addEventListener('popstate', this.onPopStateListener)\n }\n\n window.addEventListener('turbo:before-fetch-response', event => {\n const { response } = event.detail.fetchResponse\n if (response.redirected) {\n event.preventDefault()\n window.location.href = response.url\n // Turn on Turbo Visit once migrated from Videos\n // Turbo.visit(response.url)\n }\n })\n\n if (this.preventSubmitOnEnterValue) {\n this.element.addEventListener('keydown', this.onKeyDownListener)\n }\n }\n\n disconnect() {\n this.element.removeEventListener('input', this.handleFormChange)\n this.element.removeEventListener('change', this.handleFormChange)\n this.element.removeEventListener('submit', this.handleFormSubmit)\n this.element.removeEventListener('keydown', this.onKeyDownListener)\n this.unlockWindow()\n }\n\n onKeyDownListener = event => {\n if (event.key === 'Enter') {\n event.preventDefault()\n }\n }\n\n onPopStateListener = event => {\n if (event.state.turbo_frame_history) {\n window.Turbo.visit(document.location.href, { action: 'replace' })\n } else {\n window.location.replace(document.location.href)\n }\n }\n\n handleFormChange = () => {\n const isDirty = this.initialState !== this.currentState\n const hasChanged = isDirty !== this.isDirty\n\n if (!hasChanged) return\n\n this.isDirty = isDirty\n\n if (isDirty && this.shouldLockWindow) this.lockWindow()\n else this.unlockWindow()\n\n this.updateElements()\n }\n\n handleFormSubmit = () => {\n this.unlockWindow()\n this.isDirty = false\n this.initialState = this.currentState\n\n if (this.shouldUpdateUrl) {\n window.history.pushState(\n { turbo_frame_history: true },\n document.title,\n `${document.location.pathname}?${this.currentState}`\n )\n }\n }\n\n /**\n * Sync form elements with the same `name` inside the form\n */\n syncElements(originElement) {\n if (!originElement?.name) return\n\n const isCheckbox = originElement.type === 'checkbox' || originElement.type === 'radio'\n\n Array.from(\n this.element.querySelectorAll(\n `[name=\"${originElement.name}\"]${isCheckbox ? `[value=\"${originElement.value}\"]` : ''}`\n )\n )\n .filter(element => element !== originElement)\n .forEach(element => {\n // eslint-disable-next-line no-param-reassign\n if (isCheckbox) {\n element.checked = originElement.checked\n return\n }\n\n // eslint-disable-next-line no-param-reassign\n element.value = originElement.value\n })\n }\n\n updateElements() {\n const buttons = [...this.submitTargets]\n\n buttons.forEach(el => {\n if (el.classList.contains('u-button')) {\n // eslint-disable-next-line no-param-reassign\n el.dataset.pending = !this.isDirty\n } else {\n // eslint-disable-next-line no-param-reassign\n el.disabled = !this.isDirty\n }\n })\n }\n\n unlockWindow() {\n window.onbeforeunload = undefined\n }\n\n lockWindow() {\n window.onbeforeunload = () => ''\n }\n\n get currentState() {\n const state = new FormData(this.element)\n state.delete('utf8')\n state.delete('authenticity_token')\n state.delete('format')\n return new URLSearchParams(state).toString()\n }\n}\n"],"names":["FormController","Controller","__publicField","event","isDirty","response","originElement","isCheckbox","element","el","state"],"mappings":"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"}