Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Rewrite LiveSearch as an ES Module #5370

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions app/assets/javascripts/esm/all-esm.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import Homepage from './homepage.mjs';
import PreviewPane from './preview-pane.mjs';
import CopyToClipboard from './copy-to-clipboard.mjs';

import LiveSearch from './live-search.mjs';

// Modules from 3rd party vendors
import morphdom from 'morphdom';

Expand All @@ -20,6 +22,11 @@ createAll(ErrorSummary);
createAll(SkipLink);
createAll(Tabs);

const $livesearch = document.querySelector('[data-notify-module="live-search"]');
if ($livesearch) {
new LiveSearch($livesearch);
}

const $collapsibleCheckboxes = document.querySelector('[data-notify-module="collapsible-checkboxes"]');
if ($collapsibleCheckboxes) {
new CollapsibleCheckboxes($collapsibleCheckboxes);
Expand Down
113 changes: 113 additions & 0 deletions app/assets/javascripts/esm/live-search.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { isSupported } from 'govuk-frontend';

class LiveSearch {
constructor($module) {
if (!isSupported()) {
return this;
}

this.$module = $module;

this.$searchBox = this.$module.querySelector('input');
this.$searchLabel = this.$module.querySelector('label');
this.$liveRegion = this.$module.querySelector('.live-search__status');
this.$targets = document.querySelectorAll(this.$module.dataset.targets);
this.state = 'loaded';


this.$searchBox.addEventListener("input", () => {
this.filter(this.$searchBox, this.$searchLabel, this.$liveRegion, this.$targets);
});

this.filter(this.$searchBox, this.$searchLabel, this.$liveRegion, this.$targets);

}

filter ($searchBox, $searchLabel, $liveRegion, $targets) {

let query = this.normalize(this.$searchBox.value);
let results = 0;

$targets.forEach(($node) => {

let content = $node.querySelector('.live-search-relevant') ? $node.querySelector('.live-search-relevant').textContent : $node.textContent;
let isMatch = this.normalize(content).includes(this.normalize(query));
// if there is a child node with checked state
if ($node.querySelectorAll(':checked').length > 0) {
if ($node.hasAttribute('hidden')) {
$node.removeAttribute('hidden');
}
results++;
return;
}

if (query == '') {
if ($node.hasAttribute('hidden')) {
$node.removeAttribute('hidden');
}
// specific to template list as we have items hidden by default in css
// (items with ancestors) that we need to show if they match the search query
// but also hide them back when there is no search query
if ($node.classList.contains('visible-as-matches-search-query')) {
$node.classList.remove('visible-as-matches-search-query');
}
results++;
return;
}

if (isMatch) {
$node.removeAttribute('hidden');
// specific to template list as we have items hidden by default in css
// (items with ancestors) that we need to show if they match the search query
// we do that by applying a new class with display block property
if ($node.classList.contains('template-list-item-hidden-by-default')) {
$node.classList.add('visible-as-matches-search-query');
}
} else {
$node.setAttribute('hidden', '');
// specific to template list as we have items hidden by default in css
// (items with ancestors) that we now need to hide again when they don't
// match the search criteria
if ($node.classList.contains('visible-as-matches-search-query')) {
$node.classList.remove('visible-as-matches-search-query');
}
};

if (isMatch) {
results++;
}

});

if (this.state === 'loaded') {
if (query !== '') {
$searchBox.setAttribute('aria-label', $searchLabel.textContent.trim() + ', ' + this.resultsSummary(results));
}
this.state = 'active';
} else {
$searchBox.removeAttribute('aria-label');
$liveRegion.textContent = this.resultsSummary(results);
}

// make sticky JS recalculate its cache of the element's position
// because live search can change the height document
if ('stickAtBottomWhenScrolling' in window.GOVUK) {
window.GOVUK.stickAtBottomWhenScrolling.recalculate();
}

}

normalize (string) {
return string.toLowerCase().replace(/ /g,'');
}

resultsSummary (num) {
if (num === 0) {
return "no results";
} else {
return num + (num === 1 ? " result" : " results");
}
};
}

export default LiveSearch;
88 changes: 0 additions & 88 deletions app/assets/javascripts/liveSearch.js

This file was deleted.

4 changes: 3 additions & 1 deletion app/assets/stylesheets/components/message.scss
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ a {

&-hidden-by-default {
display: none;
&.visible-as-matches-search-query {
display: block;
}
}

&-without-ancestors {
Expand Down Expand Up @@ -178,7 +181,6 @@ a {
padding-left: 0;
width: auto;
}

}

&-folder,
Expand Down
13 changes: 13 additions & 0 deletions app/assets/stylesheets/govuk-frontend/extensions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,16 @@ $govuk-grid-widths: map.merge($govuk-grid-widths, $notify-grid-widths);
width: 66.66% !important;
}
/* stylelint-enable declaration-no-important */

// we use hidden attribute to hide items that don't match live-search results
// normally the broser would hide the element, but as this one has display property
// set, we need to set additional override styles
// used on /organisations/<id>/settings/email-branding/add
// used on /organisations/<id>/settings/letter-branding/add
// aused on /organisations/<id>/settings/add-nhs-local-organisation for NHS services
// used on /services/<id>/service-settings/link-service-to-organisation
// used on /services/>id>/service-settings/(set-email/letter)-branding
.govuk-checkboxes__item[hidden],
.govuk-radios__item[hidden] {
display: none;
}
1 change: 0 additions & 1 deletion rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ export default [
paths.src + 'javascripts/radioSelect.js',
paths.src + 'javascripts/updateContent.js',
paths.src + 'javascripts/listEntry.js',
paths.src + 'javascripts/liveSearch.js',
paths.src + 'javascripts/preventDuplicateFormSubmissions.js',
paths.src + 'javascripts/fullscreenTable.js',
paths.src + 'javascripts/radios-with-images.js',
Expand Down
Loading