commit d2d9b562007fbcad78879e40ef73cfeb6adfdee2 Author: Paul Pound Date: Thu Aug 27 13:31:54 2026 -0300 initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..c29b4b1 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# Preserve Advanced Search + +Keeps the advanced search `a[]` query parameters attached to the facet slider +URLs that Facets builds server-side, so clicking a slider doesn't drop the +user's advanced search criteria. + +Replaces the equivalent code that previously lived in individual themes +(`THEME.libraries.yml` + `THEME_preprocess_page()`). + +## Install + +Copy this directory to `web/modules/custom/preserve_advanced_search` on each +site, then: + + drush en preserve_advanced_search + drush cr + +## Scope + +`hook_library_info_alter()` appends this module's library to the dependencies of +`facets_range_nouislider/facets_range_nouislider`. It therefore loads only on +pages that actually render a noUiSlider facet — not site-wide, and with no route +list to maintain per site. + +Library info is cached, so run `drush cr` after deploying or the alter won't +take effect. + +If a site configures its facets with the **Facets core** slider widget +(`facets_range_widget`) instead of `facets_range_nouislider`, add that +extension's library to the alter as well. Both submodules write to +`drupalSettings.facets.sliders`, so the JavaScript itself needs no change — only +the attachment point does. + +## Notes + +- Load order is guaranteed by the dependency: our script is loaded ahead of + `slider.js`, so `Drupal.behaviors.preserveAdvancedSearchParams` is registered + first and runs first. `facets_range_nouislider`'s `slider.js` is additionally + marked `defer: true` while ours is not, and non-deferred scripts always + execute before deferred ones — so the ordering holds twice over. +- `rebuildUrl()` is idempotent (it strips all `a[]` params before re-adding the + current ones), so re-running on AJAX rebuilds is safe. +- The JS handles both `sliderSettings.url` and `sliderSettings.urls`. Range + widgets collapse the parent's `urls` map into a single `url` + (`RangeNoUiSliderWidget::build()`); single-handle widgets keep `urls`. Both + branches are live — don't remove either. diff --git a/js/preserve-advanced-search.js b/js/preserve-advanced-search.js new file mode 100644 index 0000000..b4145a3 --- /dev/null +++ b/js/preserve-advanced-search.js @@ -0,0 +1,59 @@ +(function (Drupal, drupalSettings) { + 'use strict'; + + Drupal.behaviors.preserveAdvancedSearchParams = { + attach: function (context, settings) { + + // Capture the a[] advanced search params from the current URL + const rawSearch = window.location.search; + const aParams = rawSearch + .substring(1) + .split('&') + .filter(part => part.startsWith('a%5B') || part.startsWith('a[')) + .join('&'); + + if (!aParams) return; + + const sliders = settings.facets && settings.facets.sliders; + if (!sliders) return; + + // Replace any a[] params in a URL with the current page's a[] params. + // The current URL is always the source of truth — the server-built + // slider URL may contain stale or partial a[] params. + function rebuildUrl(url) { + if (!url) return url; + const parts = url.split('?'); + const basePath = parts[0]; + const query = parts[1] || ''; + + // Keep everything that is NOT an a[] param (i.e. the f[] facet params) + const keptParams = query + .split('&') + .filter(p => p.length > 0) + .filter(p => !p.startsWith('a%5B') && !p.startsWith('a[')) + .join('&'); + + const finalQuery = [keptParams, aParams].filter(Boolean).join('&'); + return basePath + '?' + finalQuery; + } + + // Range sliders expose a single `url`; single-handle sliders expose a + // `urls` map keyed by value. Handle both — which one is present depends + // on the widget the facet is configured with. + Object.keys(sliders).forEach(function (key) { + const sliderSettings = sliders[key]; + + if (sliderSettings.url) { + sliderSettings.url = rebuildUrl(sliderSettings.url); + } + + if (sliderSettings.urls) { + Object.keys(sliderSettings.urls).forEach(function (urlKey) { + sliderSettings.urls[urlKey] = rebuildUrl(sliderSettings.urls[urlKey]); + }); + } + }); + } + }; + +})(Drupal, drupalSettings); diff --git a/preserve_advanced_search.info.yml b/preserve_advanced_search.info.yml new file mode 100644 index 0000000..2df8904 --- /dev/null +++ b/preserve_advanced_search.info.yml @@ -0,0 +1,5 @@ +name: 'Preserve Advanced Search' +type: module +description: 'Keeps advanced search a[] query parameters attached to facet slider URLs built by the server.' +package: 'Custom' +core_version_requirement: ^10 || ^11 diff --git a/preserve_advanced_search.libraries.yml b/preserve_advanced_search.libraries.yml new file mode 100644 index 0000000..3e34dc5 --- /dev/null +++ b/preserve_advanced_search.libraries.yml @@ -0,0 +1,7 @@ +preserve-advanced-search: + version: VERSION + js: + js/preserve-advanced-search.js: {} + dependencies: + - core/drupal + - core/drupalSettings diff --git a/preserve_advanced_search.module b/preserve_advanced_search.module new file mode 100644 index 0000000..2f81d37 --- /dev/null +++ b/preserve_advanced_search.module @@ -0,0 +1,26 @@ +