From ca009252ac5be9c86f8089243a8473f22e04e612 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 12 Sep 2026 13:56:38 +0300 Subject: [PATCH] rename template --- app/javascript/application.js | 68 ++++++++++++------- app/javascript/elements/form_prompt.js | 33 +++++++++ app/javascript/elements/native_event.js | 25 +++++-- app/javascript/elements/native_modal.js | 1 + app/javascript/template_builder/builder.vue | 36 ++++++++++ app/javascript/template_builder/i18n.js | 7 ++ app/views/templates/_title.html.erb | 15 +++- app/views/templates_preferences/show.html.erb | 8 ++- 8 files changed, 159 insertions(+), 34 deletions(-) create mode 100644 app/javascript/elements/form_prompt.js diff --git a/app/javascript/application.js b/app/javascript/application.js index 903220a14..0ecf3be28 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -13,6 +13,7 @@ import NativeAction from './elements/native_action' import NativeSearch from './elements/native_search' import NativeModal from './elements/native_modal' import NativeEvent from './elements/native_event' +import FormPrompt from './elements/form_prompt' import InfiniteScroll from './elements/infinite_scroll' import ModalButton from './elements/modal_button' import FileDropzone from './elements/file_dropzone' @@ -128,6 +129,7 @@ safeRegisterElement('native-action', NativeAction) safeRegisterElement('native-search', NativeSearch) safeRegisterElement('native-modal', NativeModal) safeRegisterElement('native-event', NativeEvent) +safeRegisterElement('form-prompt', FormPrompt) safeRegisterElement('infinite-scroll', InfiniteScroll) safeRegisterElement('modal-button', ModalButton) safeRegisterElement('file-dropzone', FileDropzone) @@ -186,6 +188,7 @@ safeRegisterElement('date-placeholder', DatePlaceholder) safeRegisterElement('template-builder', class extends HTMLElement { connectedCallback () { document.addEventListener('turbo:submit-end', this.onSubmit) + document.addEventListener('template-builder:update', this.onSheetSubmit) document.addEventListener('turbo:before-cache', this.onBeforeCache) this.appElem = document.createElement('div') @@ -238,36 +241,48 @@ safeRegisterElement('template-builder', class extends HTMLElement { this.appendChild(this.appElem) } - onSubmit = (e) => { - if (e.detail.success) { - if (e.detail?.formSubmission?.formElement?.id === 'submitters_form') { - e.detail.fetchResponse.response.json().then((data) => { - this.component.template.submitters = data.submitters - }) - } + onSubmit = async (e) => { + const form = e.detail.formSubmission?.formElement - if (e.detail?.formSubmission?.formElement?.action?.endsWith('/prefillable_fields')) { - e.detail.fetchResponse.response.text().then((data) => { - const doc = new DOMParser().parseFromString(data, 'text/html') - const fragment = doc.querySelector('turbo-stream template').content + if (!e.detail.success || !form) return - const prefillableUuidsIndex = {} + const data = {} - fragment.querySelectorAll('[name="field_uuid"]').forEach((field) => { - prefillableUuidsIndex[field.value] = true - }) + new FormData(form).forEach((value, key) => { data[key] = value }) - this.component.template.fields.forEach((field) => { - if (prefillableUuidsIndex[field.uuid]) { - field.prefillable = true - field.readonly = true - } else if (field.prefillable) { - delete field.prefillable - delete field.readonly - } - }) - }) - } + this.applySubmission(form.id, form.action, await e.detail.fetchResponse.responseText, data) + } + + onSheetSubmit = (e) => { + this.applySubmission(e.detail.form, e.detail.action, e.detail.body, {}) + } + + applySubmission (formId, action, body, data) { + if (formId === 'submitters_form') { + this.component.template.submitters = JSON.parse(body).submitters + } else if (action.endsWith('/prefillable_fields')) { + const doc = new DOMParser().parseFromString(body, 'text/html') + const fragment = doc.querySelector('turbo-stream template').content + + const prefillableUuidsIndex = {} + + fragment.querySelectorAll('[name="field_uuid"]').forEach((field) => { + prefillableUuidsIndex[field.value] = true + }) + + this.component.template.fields.forEach((field) => { + if (prefillableUuidsIndex[field.uuid]) { + field.prefillable = true + field.readonly = true + } else if (field.prefillable) { + delete field.prefillable + delete field.readonly + } + }) + } else if (data['template[name]']) { + this.component.template.name = data['template[name]'] + + document.title = data['template[name]'] } } @@ -278,6 +293,7 @@ safeRegisterElement('template-builder', class extends HTMLElement { disconnectedCallback () { document.removeEventListener('turbo:submit-end', this.onSubmit) + document.removeEventListener('template-builder:update', this.onSheetSubmit) document.removeEventListener('turbo:before-cache', this.onBeforeCache) this.app?.unmount() diff --git a/app/javascript/elements/form_prompt.js b/app/javascript/elements/form_prompt.js new file mode 100644 index 000000000..b04219779 --- /dev/null +++ b/app/javascript/elements/form_prompt.js @@ -0,0 +1,33 @@ +export default class extends HTMLElement { + connectedCallback () { + this.addEventListener('click', this.prompt) + document.addEventListener('turbo:submit-end', this.onSubmitEnd) + } + + disconnectedCallback () { + this.removeEventListener('click', this.prompt) + document.removeEventListener('turbo:submit-end', this.onSubmitEnd) + } + + get form () { + return this.querySelector('form') + } + + prompt = () => { + const label = this.form.querySelector('label') + const input = this.form.querySelector(`#${CSS.escape(label.htmlFor)}`) + const value = window.prompt(label.textContent.trim(), input.value)?.trim() + + if (!value || value === input.value) return + + input.value = value + + this.form.requestSubmit() + } + + onSubmitEnd = (e) => { + if (e.detail.success && e.detail.formSubmission?.formElement === this.form && this.dataset.refresh !== 'false') { + window.Turbo.visit(window.location.href, { action: 'replace' }) + } + } +} diff --git a/app/javascript/elements/native_event.js b/app/javascript/elements/native_event.js index 34995670b..7c0c59669 100644 --- a/app/javascript/elements/native_event.js +++ b/app/javascript/elements/native_event.js @@ -1,16 +1,27 @@ export default class extends HTMLElement { connectedCallback () { - this.addEventListener('click', this.dispatch) + if (this.dataset.on === 'submit') { + document.addEventListener('turbo:submit-end', this.onSubmitEnd) + } else { + this.addEventListener('click', this.dispatch) + } } disconnectedCallback () { + document.removeEventListener('turbo:submit-end', this.onSubmitEnd) this.removeEventListener('click', this.dispatch) } - dispatch = async () => { - const bridge = window.webkit?.messageHandlers?.modal + onSubmitEnd = async (e) => { + const form = e.detail.formSubmission?.formElement - if (!bridge || this.dataset.loading) return + if (!e.detail.success || !form || !this.contains(form)) return + + this.post(JSON.stringify({ form: form.id, action: form.action, body: await e.detail.fetchResponse.responseText })) + } + + dispatch = async () => { + if (this.dataset.loading) return let detail = this.dataset.detail || 'null' @@ -30,6 +41,10 @@ export default class extends HTMLElement { } } - bridge.postMessage({ action: 'dispatch', name: this.dataset.name, detail }) + this.post(detail) + } + + post (detail) { + window.webkit?.messageHandlers?.modal?.postMessage({ action: 'dispatch', name: this.dataset.name, detail, dismiss: this.dataset.dismiss || 'true' }) } } diff --git a/app/javascript/elements/native_modal.js b/app/javascript/elements/native_modal.js index 968dab9eb..5f5658a11 100644 --- a/app/javascript/elements/native_modal.js +++ b/app/javascript/elements/native_modal.js @@ -13,6 +13,7 @@ export default class extends HTMLElement { if (e.detail.formSubmission?.formElement?.method === 'get') return if (this.dataset.closeAfterSubmit === 'false') return if (e.detail.formSubmission?.formElement?.dataset?.closeOnSubmit === 'false') return + if (e.detail.formSubmission?.formElement?.closest('native-event[data-on="submit"]')) return window.webkit?.messageHandlers?.modal?.postMessage({ action: 'submitted' }) } diff --git a/app/javascript/template_builder/builder.vue b/app/javascript/template_builder/builder.vue index 910679b99..f091289b6 100644 --- a/app/javascript/template_builder/builder.vue +++ b/app/javascript/template_builder/builder.vue @@ -103,6 +103,42 @@ name="buttons" />