commit
d2d9b56200
5 changed files with 143 additions and 0 deletions
@ -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. |
||||
@ -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); |
||||
@ -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 |
||||
@ -0,0 +1,7 @@
|
||||
preserve-advanced-search: |
||||
version: VERSION |
||||
js: |
||||
js/preserve-advanced-search.js: {} |
||||
dependencies: |
||||
- core/drupal |
||||
- core/drupalSettings |
||||
@ -0,0 +1,26 @@
|
||||
<?php |
||||
|
||||
/** |
||||
* @file |
||||
* Preserves advanced search a[] parameters on facet slider URLs. |
||||
*/ |
||||
|
||||
/** |
||||
* Implements hook_library_info_alter(). |
||||
* |
||||
* Attaches the fix-up library as a dependency of the slider widget library |
||||
* rather than to every page. This scopes it to the pages that actually render |
||||
* a slider, and guarantees our script loads first so the behavior is |
||||
* registered — and therefore runs — before the slider reads |
||||
* drupalSettings.facets.sliders. |
||||
*/ |
||||
function preserve_advanced_search_library_info_alter(array &$libraries, $extension) |
||||
{ |
||||
if ($extension !== 'facets_range_nouislider') { |
||||
return; |
||||
} |
||||
|
||||
if (isset($libraries['facets_range_nouislider'])) { |
||||
$libraries['facets_range_nouislider']['dependencies'][] = 'preserve_advanced_search/preserve-advanced-search'; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue