1import { Controller } from '@hotwired/stimulus' 2import debounce from 'debounce' 3import { pushHistory } from 'src/turbo_history' 4 5// Connects to data-controller="form" 6export default class extends Controller { 7 static targets = ['dropdown', 'loading', 'results'] 8 9 connect() { 10 this.submit = debounce(this.submit.bind(this), 250) 11 this.boundPaginate = this.paginate.bind(this) 12 this.boundKeepFieldValues = this.keepFieldValues.bind(this) 13 // Pagy's links load the next page as a turbo_stream, which leaves the URL 14 // alone. The nav can sit outside the form, so listen on the document. 15 document.addEventListener('click', this.boundPaginate) 16 // Back and Forward between search URLs are Turbo restores (see 17 // src/turbo_history), from the snapshot Turbo takes when the page is left. 18 document.addEventListener('turbo:before-cache', this.boundKeepFieldValues) 19 } 20 21 disconnect() { 22 document.removeEventListener('click', this.boundPaginate) 23 document.removeEventListener('turbo:before-cache', this.boundKeepFieldValues) 24 } 25 26 // A snapshot is a clone of the DOM, and a clone carries each field's value 27 // attribute, not what was typed or ticked since. Write the live state into 28 // the attributes so a restored snapshot shows the search it has results for. 29 keepFieldValues() { 30 for (const field of this.element.elements) { 31 if (field.type === 'checkbox' || field.type === 'radio') { 32 field.toggleAttribute('checked', field.checked) 33 } else if (field instanceof HTMLInputElement && field.type !== 'password' && field.type !== 'file') { 34 field.setAttribute('value', field.value) 35 } 36 } 37 } 38 39 submit() { 40 const params = new URLSearchParams(new FormData(this.element)) 41 const frame = this.element.dataset.turboFrame && document.getElementById(this.element.dataset.turboFrame) 42 43 if (frame) { 44 frame.src = `${this.element.action}?${params}` 45 } else { 46 if (this.hasLoadingTarget) { 47 this.loadingTarget.classList.remove('hidden') 48 this.resultsTarget.classList.add('hidden') 49 } 50 this.element.requestSubmit() 51 } 52 53 pushHistory(`${window.location.origin}${window.location.pathname}?${params}`) 54 } 55 56 // Record a page link's URL in history so a reload, a shared link or Back 57 // lands on that page. Turbo still fetches the stream itself. 58 paginate(event) { 59 if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return 60 61 const link = event.target.closest('nav a[data-turbo-stream][href]') 62 if (!link) return 63 64 const url = new URL(link.href, window.location.href) 65 if (url.pathname !== new URL(this.element.action, window.location.href).pathname) return 66 if (url.href === window.location.href) return 67 68 pushHistory(url.href) 69 } 70 71 resetDropdown() { 72 this.dropdownTarget.value = this.dropdownTarget.dataset.defaultId 73 } 74}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.