From 938ee28b840bbfbd9110cc0d199b58055efbb69e Mon Sep 17 00:00:00 2001 From: Paul Pound Date: Thu, 15 Oct 2026 10:09:14 -0300 Subject: [PATCH] first commit --- README.md | 24 +++++++++++ composer.json | 18 ++++++++ mirador_search_highlight.info.yml | 9 ++++ mirador_search_highlight.module | 71 +++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 README.md create mode 100644 composer.json create mode 100644 mirador_search_highlight.info.yml create mode 100644 mirador_search_highlight.module diff --git a/README.md b/README.md new file mode 100644 index 0000000..23015b6 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# Mirador search highlight + +When someone clicks an item from the Solr search results, Mirador opens with +the search term already run against the item's IIIF content search service, +so matches are highlighted with no extra JavaScript. + +## How it works + +1. `hook_views_pre_render()` appends `?search_api_fulltext=` to the + "Link this field to its item" links in the `solr_search_content` view. +2. `hook_preprocess_mirador()` reads that parameter and sets + `windows[0].defaultSearchQuery` on the viewer's Mirador config. + +The manifest must advertise a search service (`search_endpoint` in the +`iiif_manifest` view) for Mirador to run the search. + +## Configuration + +Edit the constants at the top of `mirador_search_highlight.module` to change +the query parameter or the views whose links carry the term. + +Only fields using Search API's "Link this field to its item" option get the +term. Fields linked another way (for example an image formatter linking to +content) are left alone. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..66c2adc --- /dev/null +++ b/composer.json @@ -0,0 +1,18 @@ +{ + "name": "roblib/mirador_search_highlight", + "description": "Carries the Solr search term from search results to the item page and runs it as a IIIF content search in Mirador on load.", + "type": "drupal-custom-module", + "license": "GPL-2.0-or-later", + "keywords": [ + "drupal", + "islandora", + "mirador", + "search_api" + ], + "require": { + "php": ">=8.1", + "drupal/core": "^10 || ^11", + "drupal/islandora_mirador": "*", + "drupal/search_api": "*" + } +} diff --git a/mirador_search_highlight.info.yml b/mirador_search_highlight.info.yml new file mode 100644 index 0000000..c6a1aa5 --- /dev/null +++ b/mirador_search_highlight.info.yml @@ -0,0 +1,9 @@ +name: 'Mirador search highlight' +type: module +description: 'Carries the Solr search term from search results to the item page and runs it as a IIIF content search in Mirador on load.' +package: Islandora +core_version_requirement: ^10 || ^11 +dependencies: + - islandora_mirador:islandora_mirador + - search_api:search_api + - drupal:views diff --git a/mirador_search_highlight.module b/mirador_search_highlight.module new file mode 100644 index 0000000..929887a --- /dev/null +++ b/mirador_search_highlight.module @@ -0,0 +1,71 @@ +id(), MIRADOR_SEARCH_HIGHLIGHT_VIEWS, TRUE)) { + return; + } + if (!method_exists($view->query, 'getOriginalKeys')) { + return; + } + // Parse modes may turn the keys into an array; only the raw string is + // useful as a Mirador search query. + $keys = $view->query->getOriginalKeys(); + if (!is_string($keys) || trim($keys) === '') { + return; + } + + foreach ($view->field as $handler) { + if (!empty($handler->options['link_to_item'])) { + // Search API items are merged with $options['alter'] when rendered as + // links, and an explicit 'query' replaces the item URL's query. + // UrlHelper::buildQuery() encodes the value before Views token + // replacement, so user input is never treated as Twig. + $handler->options['alter']['query'] = [MIRADOR_SEARCH_HIGHLIGHT_PARAM => trim($keys)]; + } + } +} + +/** + * Implements hook_preprocess_HOOK() for mirador. + * + * Runs after template_preprocess_mirador(), so mirador_view_id is already the + * unique ID used as the drupalSettings viewer key. + */ +function mirador_search_highlight_preprocess_mirador(&$variables) { + // Vary the cached viewer by the search term, otherwise the first term + // searched would be cached and shown to everyone viewing this item. + $variables['#cache']['contexts'][] = 'url.query_args:' . MIRADOR_SEARCH_HIGHLIGHT_PARAM; + + $term = \Drupal::request()->query->get(MIRADOR_SEARCH_HIGHLIGHT_PARAM, ''); + $term = is_string($term) ? trim($term) : ''; + if ($term === '') { + return; + } + $selector = '#' . $variables['mirador_view_id']; + $variables['#attached']['drupalSettings']['mirador']['viewers'][$selector]['windows'][0]['defaultSearchQuery'] = mb_substr($term, 0, 256); +}