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

VOTE-587 state selector paragraph refinements #473

Merged
merged 1 commit into from
Dec 18, 2023
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,15 @@ langcode: en
status: true
dependencies:
config:
- field.field.paragraph.registration_tool.field_dropdown_label
- field.field.paragraph.registration_tool.field_form_heading
- field.field.paragraph.registration_tool.field_heading
- field.field.paragraph.registration_tool.field_submit_button_label
- field.field.paragraph.registration_tool.field_placeholder
- paragraphs.paragraphs_type.registration_tool
id: paragraph.registration_tool.default
targetEntityType: paragraph
bundle: registration_tool
mode: default
content:
field_dropdown_label:
type: string_textfield
weight: 2
region: content
settings:
size: 60
placeholder: ''
third_party_settings: { }
field_form_heading:
type: string_textfield
weight: 1
Expand All @@ -37,16 +28,16 @@ content:
size: 60
placeholder: ''
third_party_settings: { }
field_submit_button_label:
field_placeholder:
type: string_textfield
weight: 3
weight: 2
region: content
settings:
size: 60
placeholder: ''
third_party_settings: { }
translation:
weight: 4
weight: 3
region: content
settings: { }
third_party_settings: { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,15 @@ langcode: en
status: true
dependencies:
config:
- field.field.paragraph.registration_tool.field_dropdown_label
- field.field.paragraph.registration_tool.field_form_heading
- field.field.paragraph.registration_tool.field_heading
- field.field.paragraph.registration_tool.field_submit_button_label
- field.field.paragraph.registration_tool.field_placeholder
- paragraphs.paragraphs_type.registration_tool
id: paragraph.registration_tool.default
targetEntityType: paragraph
bundle: registration_tool
mode: default
content:
field_dropdown_label:
type: string
label: hidden
settings:
link_to_entity: false
third_party_settings: { }
weight: 2
region: content
field_form_heading:
type: string
label: hidden
Expand All @@ -37,12 +28,12 @@ content:
third_party_settings: { }
weight: 0
region: content
field_submit_button_label:
field_placeholder:
type: string
label: hidden
settings:
link_to_entity: false
third_party_settings: { }
weight: 3
weight: 2
region: content
hidden: { }
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ id: paragraph.registration_tool.field_form_heading
field_name: field_form_heading
entity_type: paragraph
bundle: registration_tool
label: 'Form heading'
label: 'Field Label'
description: ''
required: true
translatable: true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
uuid: 5e35facf-9d13-428e-b66e-94ae072633a5
uuid: bf81dc6a-e290-4bda-9c22-4790a0b0055a
langcode: en
status: true
dependencies:
config:
- field.storage.paragraph.field_dropdown_label
- field.storage.paragraph.field_placeholder
- paragraphs.paragraphs_type.registration_tool
id: paragraph.registration_tool.field_dropdown_label
field_name: field_dropdown_label
id: paragraph.registration_tool.field_placeholder
field_name: field_placeholder
entity_type: paragraph
bundle: registration_tool
label: 'Dropdown label'
label: Placeholder
description: ''
required: true
translatable: true
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
uuid: 95c1bafc-87b1-453b-a65b-845186b30004
uuid: e6b21b32-160e-4cd9-b228-6bf2352a4d85
langcode: en
status: true
dependencies:
module:
- paragraphs
id: paragraph.field_dropdown_label
field_name: field_dropdown_label
id: paragraph.field_placeholder
field_name: field_placeholder
entity_type: paragraph
type: string
settings:
Expand Down
21 changes: 0 additions & 21 deletions config/sync/field.storage.paragraph.field_submit_button_label.yml

This file was deleted.

175 changes: 175 additions & 0 deletions web/themes/custom/votegov/src/js/registration-tool.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
Dropdown functionality for state selector component.
*/

(() => {
const stateComboBox = document.getElementById("state-combo-box");
const stateInput = document.getElementById("state-input");
const stateDropdownBtn = document.getElementById("state-dropdown-btn");
const stateResultsContainer = document.getElementById("state-results-container");
const stateFilteredOptions = stateComboBox ? stateResultsContainer.getElementsByTagName('a') : null;

// Store dynamic filtered results.
let stateListResults = [];

// Show state dropdown.
function stateListShow() {
stateResultsContainer.removeAttribute('hidden');
}

// Hide state dropdown.
function stateListHide() {
stateResultsContainer.setAttribute('hidden', '');
}

// Toggle state dropdown.
function stateListToggle() {
if (!stateResultsContainer.getAttribute('data-empty')) {
stateResultsContainer.toggleAttribute('hidden');
}
}

// Toggle state dropdown if empty.
function stateListToggleEmpty(empty) {
if (empty) {
stateListHide();
stateResultsContainer.setAttribute('data-empty', true);
} else {
stateListShow();
stateResultsContainer.removeAttribute('data-empty');
}
}

// Filter dropdown results based on user input.
function stateListFilter() {
let filter, txtValue, wordTxtValues, keyValue;
filter = stateInput.value.toUpperCase();
txtValue = "";
wordTxtValues = [];
keyValue = "";
stateListResults = [];

for (let i = 0; i < stateFilteredOptions.length; i++) {
let li = stateFilteredOptions[i].parentNode;
txtValue = li.textContent.trim() || li.innerText.trim();
wordTxtValues = txtValue.split(' ');
keyValue = li.firstElementChild.getAttribute('key');

// Match user input with the start of the state name or state abbrev.
if (wordTxtValues.some((elem) => elem.length > 2 && elem.toUpperCase().startsWith(filter))
|| (filter.length === 2 && keyValue.toUpperCase() === filter)) {
li.removeAttribute('hidden');
stateListResults.push(stateFilteredOptions[i]);
} else {
li.setAttribute('hidden', '');
}
}

toggleDataFiltered(filter);
stateListToggleEmpty(!stateListResults.length);
}

// Focus on previous option in dropdown.
function stateListPrevious(option) {
stateListResults.find((element, index) => {
if (element === option) {
if (index === 0) {
stateInput.focus();
}
else {
stateListResults[index - 1].focus();
}
}
});
}

// Focus on next option in dropdown.
function stateListNext(option) {
stateListResults.find((element, index) => {
if (element === option) {
if (index === stateListResults.length - 1) {
stateListResults[0].focus();
}
else {
stateListResults[index + 1].focus();
}
}
});
}

// Toggle data attribute on results container.
function toggleDataFiltered(filter) {
if (filter === '') {
stateResultsContainer.removeAttribute('data-filtered');
}
else {
stateResultsContainer.setAttribute('data-filtered', 'true');
}
}

// Redirect user if value is an exact match to a option.
function quickLinkToState(value) {
stateListResults.find((element) => {
let resultTxt = element.textContent || element.innerText;
if (resultTxt.toUpperCase() === value) {
window.location.href = element.href;
}
});
}

// Initialize event listeners if combobox loaded.
if (stateComboBox) {
// Attach events for combobox component.
stateComboBox.addEventListener('focusout', (e) => {
if (!e.currentTarget.contains(e.relatedTarget)) {
stateListHide();
}
});
stateComboBox.addEventListener('submit', (e) => {
e.preventDefault();
let value = stateInput.value.toUpperCase();
quickLinkToState(value);
})

// Attach events for state input field.
stateInput.addEventListener('focus', stateListShow);
stateInput.addEventListener('keydown', (e) => {
if (e.key === "ArrowDown") {
stateListResults[0].focus();
}
});
stateInput.addEventListener('keyup', (e) => {
if (e.key !== "ArrowDown") {
stateListFilter();
}
});

// Attach events for state links in dropdown.
for (let i = 0; i < stateFilteredOptions.length; i++) {
stateListResults.push(stateFilteredOptions[i]);
stateFilteredOptions[i].addEventListener('keydown', (e) => {
// stateFilteredOptions = stateResultsContainer.getElementsByTagName('a');
if (e.key === "ArrowDown") {
e.preventDefault();
let option = stateFilteredOptions[i];
stateListNext(option);
}
});

stateFilteredOptions[i].addEventListener('keyup', (e) => {
if (e.key === "ArrowUp") {
e.preventDefault();
let option = stateFilteredOptions[i];
stateListPrevious(option);
}
});
}

// Attach events for dropdown toggle button.
stateDropdownBtn.addEventListener('click', (e) => {
e.preventDefault();
stateListToggle();
});
}

})();
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{#
/**
* @file
* Default theme implementation to display a registration tool paragraph.
*
* @ingroup themeable
*/
#}

{{ attach_library('votegov/registration_tool') }}

{% block paragraph %}
<section class="register align-bottom" role="region" aria-label="{{ content.field_heading | field_value }}">
<header>
<h1 class="main-heading" data-test="main-header">{{ content.field_heading | field_value }}</h1>
</header>

<form id="state-combo-box">
<label for="state-input">{{ content.field_form_heading | field_value }}</label>
<div class="input-buttons-group">
<input type="text" class="state-input" id="state-input" autocomplete="off"
placeholder="{{ content.field_placeholder | field_value }}">
<div class="input-control-container">
<button id="state-dropdown-btn" tabindex="-1" class="dropdown-btn" type="button"
aria-hidden="true"></button>
</div>
</div>
<nav id="state-results-container" hidden>
<ul id="results-list">
{% set results = drupal_view_result('state_territory', 'block') %}
{% for result in results %}
{% set nodeID = result._entity.id() %}
{% set node_path = path('entity.node.canonical', {'node': nodeID}) %}
<li>
<a href="{{ node_path }}">{{ result.node_field_data_title }}</a>
</li>
{% endfor %}
</ul>
</nav>
</form>

</section>
{% endblock %}
Loading