PageSourceSearch

https://thinkproductive.co.uk/wp-content/themes/torii/assets/js/components/sort-dropdown.js?ver=1.1.0

js thinkproductive.co.uk collected 2026-10-03 22:41:19 UTC 3,026 bytes, 107 lines download raw bytes

1(function () {
2	'use strict';
3
4	document.querySelectorAll('.sort-dropdown').forEach(function (el) {
5		var trigger = el.querySelector('.sort-dropdown__trigger');
6		var list = el.querySelector('.sort-dropdown__list');
7		var input = el.querySelector('input[data-filter-select]');
8
9		if (!trigger || !list || !input) {
10			return;
11		}
12
13		trigger.addEventListener('click', function () {
14			var isOpen = !list.hidden;
15			list.hidden = isOpen;
16			trigger.setAttribute('aria-expanded', String(!isOpen));
17		});
18
19		el.addEventListener('focusout', function (e) {
20			if (!el.contains(e.relatedTarget)) {
21				list.hidden = true;
22				trigger.setAttribute('aria-expanded', 'false');
23			}
24		});
25
26		document.addEventListener('keydown', function (e) {
27			if (e.key === 'Escape' && !list.hidden) {
28				list.hidden = true;
29				trigger.setAttribute('aria-expanded', 'false');
30				trigger.focus();
31			}
32		});
33
34		function getOptions() {
35			return Array.prototype.slice.call(list.querySelectorAll('.sort-dropdown__option'));
36		}
37
38		// Arrow Up/Down on the closed trigger opens the list and moves focus into it.
39		trigger.addEventListener('keydown', function (e) {
40			if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') {
41				return;
42			}
43			e.preventDefault();
44			list.hidden = false;
45			trigger.setAttribute('aria-expanded', 'true');
46			var options = getOptions();
47			var selected = list.querySelector('[aria-selected="true"]');
48			var target = selected || (e.key === 'ArrowUp' ? options[options.length - 1] : options[0]);
49			if (target) {
50				target.focus();
51			}
52		});
53
54		// Enter/Space selects the focused option; arrows, Home and End move between options.
55		list.addEventListener('keydown', function (e) {
56			var option = e.target.closest('.sort-dropdown__option');
57			if (!option) {
58				return;
59			}
60			var options = getOptions();
61			var index = options.indexOf(option);
62			var next = null;
63
64			if (e.key === 'Enter' || e.key === ' ') {
65				e.preventDefault();
66				option.click();
67				trigger.focus();
68				return;
69			}
70			if (e.key === 'ArrowDown') {
71				next = options[Math.min(index + 1, options.length - 1)];
72			} else if (e.key === 'ArrowUp') {
73				next = options[Math.max(index - 1, 0)];
74			} else if (e.key === 'Home') {
75				next = options[0];
76			} else if (e.key === 'End') {
77				next = options[options.length - 1];
78			}
79			if (next) {
80				e.preventDefault();
81				next.focus();
82			}
83		});
84
85		list.addEventListener('click', function (e) {
86			var option = e.target.closest('.sort-dropdown__option');
87			if (!option) {
88				return;
89			}
90
91			list.hidden = true;
92			trigger.setAttribute('aria-expanded', 'false');
93
94			list.querySelectorAll('.sort-dropdown__option').forEach(function (otherOption) {
95				otherOption.setAttribute('aria-selected', String(otherOption === option));
96			});
97
98			trigger.firstChild.textContent = option.textContent.trim() + ' ';
99
100			var value = option.dataset.value;
101			if (value && value !== input.value) {
102				input.value = value;
103				input.dispatchEvent(new Event('change', { bubbles: true }));
104			}
105		});
106	});
107})();

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.