From b63127828af29f50ba7c209febff54b40b7af9df Mon Sep 17 00:00:00 2001 From: Chris Wachtman Date: Wed, 28 Aug 2024 14:30:31 -0400 Subject: [PATCH 1/8] USAGOV-1899-Benefits-Redirect-Modal: Modal data, templates, and script --- .../custom/usa_twig_vars/usa_twig_vars.module | 15 +++ web/themes/custom/usagov/scripts/modal.js | 35 ++++++ ...d--block-content--field-modal-id.html.twig | 7 ++ .../paragraph--uswds-modal.html.twig | 101 ++++++++++++++++++ .../templates/region--header-top.html.twig | 9 ++ web/themes/custom/usagov/usagov.libraries.yml | 4 + 6 files changed, 171 insertions(+) create mode 100644 web/themes/custom/usagov/scripts/modal.js create mode 100644 web/themes/custom/usagov/templates/field--block-content--field-modal-id.html.twig create mode 100644 web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig diff --git a/web/modules/custom/usa_twig_vars/usa_twig_vars.module b/web/modules/custom/usa_twig_vars/usa_twig_vars.module index 4b22dd24c9..8c02f33bc5 100644 --- a/web/modules/custom/usa_twig_vars/usa_twig_vars.module +++ b/web/modules/custom/usa_twig_vars/usa_twig_vars.module @@ -325,6 +325,21 @@ function usa_twig_vars_preprocess_region(&$variables) { } } + // Get all modals from the website + $modal_blocks = \Drupal::entityTypeManager()->getStorage('block_content')->loadByProperties(['type' => 'modal']); + foreach ($modal_blocks as $modal) { + /** + * Check if the language of the modal is the same as the website. + * This prevents incorrect language modals from being displayed on the site. + * */ + $modal_lang = $modal->langcode->value; + if ($modal_lang === $site_language) { + $variables['modals'][$modal->id()] = array( + "name" => $modal->field_modal_id->value, + "id" => $modal->field_modal[0]->getValue(), + ); + } + } } } diff --git a/web/themes/custom/usagov/scripts/modal.js b/web/themes/custom/usagov/scripts/modal.js new file mode 100644 index 0000000000..d2fae510e1 --- /dev/null +++ b/web/themes/custom/usagov/scripts/modal.js @@ -0,0 +1,35 @@ + +function processModalUrlParameter() { + "use strict"; + + const urlParams = new URLSearchParams(window.location.search); + const modalName = urlParams.get('modal'); + if (modalName === null) return; + + toggleModal(modalName); + + urlParams.delete("modal"); + let newURL = window.location.pathname; + if (urlParams.size) { + newURL = newURL + '?' + urlParams.toString(); + } + history.replaceState(history.state, null, newURL); +} + +/* open or close the modal programatically */ +function toggleModal(modalName) { + "use strict"; + + let map = document.querySelector('[data-modal-name="'+ modalName +'"]'); + if (map === null) return; + let modalID = map.getAttribute('data-modal-id'); + if (modalID === null) return; + document.querySelector('[href="#paragraph--id--'+ modalID +'"]').click(); +} + +document.addEventListener('DOMContentLoaded', function() { + "use strict"; + + processModalUrlParameter(); +}); + diff --git a/web/themes/custom/usagov/templates/field--block-content--field-modal-id.html.twig b/web/themes/custom/usagov/templates/field--block-content--field-modal-id.html.twig new file mode 100644 index 0000000000..95e2648bff --- /dev/null +++ b/web/themes/custom/usagov/templates/field--block-content--field-modal-id.html.twig @@ -0,0 +1,7 @@ +{# +/** + * @file + * This should be blank! + * We added this template to prevent this field from being displayed. + */ +#} diff --git a/web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig b/web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig new file mode 100644 index 0000000000..88156eb359 --- /dev/null +++ b/web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig @@ -0,0 +1,101 @@ +{# +/** + * @file + * Default theme implementation to display a paragraph in USWDS Paragraph Components. + * + * Available variables: + * - paragraph: Full paragraph entity. + * - id: The paragraph ID. + * - bundle: The type of the paragraph, for example, "image" or "text". + * - authorid: The user ID of the paragraph author. + * - createdtime: Formatted creation date. Preprocess functions can + * reformat it by calling format_date() with the desired parameters on + * $variables['paragraph']->getCreatedTime(). + * - content: All paragraph items. Use {{ content }} to print them all, + * or print a subset such as {{ content.field_example }}. Use + * {{ content|without('field_example') }} to temporarily suppress the printing + * of a given child element. + * - attributes: HTML attributes for the containing element. + * The attributes.class element may contain one or more of the following + * classes: + * - paragraphs: The current template type (also known as a "theming hook"). + * - paragraphs--type-[type]: The current paragraphs type. For example, if the paragraph is an + * "Image" it would result in "paragraphs--type--image". Note that the machine + * name will often be in a short form of the human readable label. + * - paragraphs--view-mode--[view_mode]: The View Mode of the paragraph; for example, a + * preview would result in: "paragraphs--view-mode--preview", and + * default: "paragraphs--view-mode--default". + * - view_mode: View mode; for example, "preview" or "full". + * - logged_in: Flag for authenticated user status. Will be true when the + * current user is a logged-in member. + * - is_admin: Flag for admin user status. Will be true when the current user + * is an administrator. + * + * @see template_preprocess_paragraph() + * + * @ingroup themeable + */ +#} + +{# The template default set classes. #} +{# Sets Paragraph ID as class. #} +{% set classes = [ + 'paragraph', + 'paragraph--type--' ~ paragraph.bundle|clean_class, + view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class, + 'paragraph--id--' ~ paragraph.id.value, +] %} + +{% set id = 'paragraph--id--' ~ paragraph.id.value %} +{% set model_id = paragraph.id.value %} +{% set modal_large = content.field_large_modal['#items'].getString() ? ' usa-modal--lg' %} +{% set force_action = content.field_force_action['#items'].getString() ? ' data-force-action' %} + + + {% if content.field_display_as_button == false %} + + {% else %} + + {% endif %} + + + diff --git a/web/themes/custom/usagov/templates/region--header-top.html.twig b/web/themes/custom/usagov/templates/region--header-top.html.twig index 5552e01e3a..c78efb549e 100644 --- a/web/themes/custom/usagov/templates/region--header-top.html.twig +++ b/web/themes/custom/usagov/templates/region--header-top.html.twig @@ -31,6 +31,15 @@ {% endfor %} {% endif %} + {% for modal_id, modal_data in modals %} + {% if modal_id %} + {{ attach_library('usagov/modal') }} + {{ drupal_entity('block_content', modal_id) }} + {# This div creates an association between the modal's name used in the query string and the numerical ID used by the paragraph component' #} +
+ {% endif %} + {% endfor %} + {% endif %} diff --git a/web/themes/custom/usagov/usagov.libraries.yml b/web/themes/custom/usagov/usagov.libraries.yml index 75463d579c..cef1d21b4a 100644 --- a/web/themes/custom/usagov/usagov.libraries.yml +++ b/web/themes/custom/usagov/usagov.libraries.yml @@ -71,3 +71,7 @@ lazyLoadBgImage: dependencies: - core/drupal - core/jquery + +modal: + js: + scripts/modal.js: {} \ No newline at end of file From 4ef89d0fc6d523237bd17f1e9a755a8080b8cfed Mon Sep 17 00:00:00 2001 From: Chris Wachtman Date: Wed, 28 Aug 2024 14:55:17 -0400 Subject: [PATCH 2/8] USAGOV-1899-Benefits-Redirect-Modal: Modal config --- config/sync/block_content.type.modal.yml | 8 ++ ...rm_display.block_content.modal.default.yml | 57 +++++++++ ...ew_display.block_content.modal.default.yml | 27 ++++ ....field.block_content.modal.field_modal.yml | 118 ++++++++++++++++++ ...eld.block_content.modal.field_modal_id.yml | 19 +++ ...ield.storage.block_content.field_modal.yml | 25 ++++ ...d.storage.block_content.field_modal_id.yml | 25 ++++ ...e.content_settings.block_content.modal.yml | 11 ++ .../sync/user.role.content_administrator.yml | 7 ++ 9 files changed, 297 insertions(+) create mode 100644 config/sync/block_content.type.modal.yml create mode 100644 config/sync/core.entity_form_display.block_content.modal.default.yml create mode 100644 config/sync/core.entity_view_display.block_content.modal.default.yml create mode 100644 config/sync/field.field.block_content.modal.field_modal.yml create mode 100644 config/sync/field.field.block_content.modal.field_modal_id.yml create mode 100644 config/sync/field.storage.block_content.field_modal.yml create mode 100644 config/sync/field.storage.block_content.field_modal_id.yml create mode 100644 config/sync/language.content_settings.block_content.modal.yml diff --git a/config/sync/block_content.type.modal.yml b/config/sync/block_content.type.modal.yml new file mode 100644 index 0000000000..da23f955ea --- /dev/null +++ b/config/sync/block_content.type.modal.yml @@ -0,0 +1,8 @@ +uuid: 1299811c-9a61-493c-b6d3-dea4dc45c4f4 +langcode: en +status: true +dependencies: { } +id: modal +label: Modal +revision: 0 +description: '' diff --git a/config/sync/core.entity_form_display.block_content.modal.default.yml b/config/sync/core.entity_form_display.block_content.modal.default.yml new file mode 100644 index 0000000000..59dac68a86 --- /dev/null +++ b/config/sync/core.entity_form_display.block_content.modal.default.yml @@ -0,0 +1,57 @@ +uuid: ae5cfc79-6a21-4a6a-acc5-1515022629eb +langcode: en +status: true +dependencies: + config: + - block_content.type.modal + - field.field.block_content.modal.field_modal + - field.field.block_content.modal.field_modal_id + module: + - paragraphs +id: block_content.modal.default +targetEntityType: block_content +bundle: modal +mode: default +content: + field_modal: + type: paragraphs + weight: 2 + region: content + settings: + title: Paragraph + title_plural: Paragraphs + edit_mode: open + closed_mode: summary + autocollapse: none + closed_mode_threshold: 0 + add_mode: dropdown + form_display_mode: default + default_paragraph_type: '' + features: + collapse_edit_all: collapse_edit_all + duplicate: duplicate + third_party_settings: { } + field_modal_id: + type: string_textfield + weight: 1 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } + info: + type: string_textfield + weight: 0 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } + langcode: + type: language_select + weight: 3 + region: content + settings: + include_locked: true + third_party_settings: { } +hidden: { } diff --git a/config/sync/core.entity_view_display.block_content.modal.default.yml b/config/sync/core.entity_view_display.block_content.modal.default.yml new file mode 100644 index 0000000000..7a1d9e306e --- /dev/null +++ b/config/sync/core.entity_view_display.block_content.modal.default.yml @@ -0,0 +1,27 @@ +uuid: 94f199f4-097b-4581-bb7e-8b1149afb7ba +langcode: en +status: true +dependencies: + config: + - block_content.type.modal + - field.field.block_content.modal.field_modal + - field.field.block_content.modal.field_modal_id + module: + - entity_reference_revisions +id: block_content.modal.default +targetEntityType: block_content +bundle: modal +mode: default +content: + field_modal: + type: entity_reference_revisions_entity_view + label: hidden + settings: + view_mode: default + link: '' + third_party_settings: { } + weight: 0 + region: content +hidden: + field_modal_id: true + langcode: true diff --git a/config/sync/field.field.block_content.modal.field_modal.yml b/config/sync/field.field.block_content.modal.field_modal.yml new file mode 100644 index 0000000000..3411a4134d --- /dev/null +++ b/config/sync/field.field.block_content.modal.field_modal.yml @@ -0,0 +1,118 @@ +uuid: b2cadf02-3ac3-4772-ae71-01b302c4c1a8 +langcode: en +status: true +dependencies: + config: + - block_content.type.modal + - field.storage.block_content.field_modal + - paragraphs.paragraphs_type.uswds_modal + module: + - entity_reference_revisions +id: block_content.modal.field_modal +field_name: field_modal +entity_type: block_content +bundle: modal +label: Modal +description: '' +required: true +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:paragraph' + handler_settings: + target_bundles: + uswds_modal: uswds_modal + negate: 0 + target_bundles_drag_drop: + b_benefit_eligibility: + weight: 31 + enabled: false + b_levent_elg_criteria: + weight: 32 + enabled: false + b_levent_elg_criteria_group: + weight: 33 + enabled: false + b_levent_elg_section: + weight: 34 + enabled: false + b_levent_relevant_benefit: + weight: 35 + enabled: false + faq: + weight: 36 + enabled: false + text_field: + weight: 37 + enabled: false + uswds_2_column_breakpoints: + weight: 39 + enabled: false + uswds_2_columns: + weight: 38 + enabled: false + uswds_3_column_breakpoints: + weight: 41 + enabled: false + uswds_3_columns: + weight: 40 + enabled: false + uswds_accordion: + weight: 42 + enabled: false + uswds_accordion_section: + weight: 43 + enabled: false + uswds_alert: + weight: 44 + enabled: false + uswds_card_breakpoints: + weight: 46 + enabled: false + uswds_card_group_flag: + weight: 47 + enabled: false + uswds_card_group_regular: + weight: 48 + enabled: false + uswds_card_regular: + weight: 49 + enabled: false + uswds_cards_flag: + weight: 45 + enabled: false + uswds_column_equal_size: + weight: 52 + enabled: false + uswds_columns_2_uneven: + weight: 50 + enabled: false + uswds_columns_3_uneven: + weight: 51 + enabled: false + uswds_icon_list: + weight: 53 + enabled: false + uswds_icon_list_item: + weight: 54 + enabled: false + uswds_modal: + weight: 55 + enabled: true + uswds_process_item: + weight: 56 + enabled: false + uswds_process_list: + weight: 57 + enabled: false + uswds_step_indicator_item: + weight: 58 + enabled: false + uswds_step_indicator_list: + weight: 59 + enabled: false + uswds_summary_box: + weight: 60 + enabled: false +field_type: entity_reference_revisions diff --git a/config/sync/field.field.block_content.modal.field_modal_id.yml b/config/sync/field.field.block_content.modal.field_modal_id.yml new file mode 100644 index 0000000000..4fc4296600 --- /dev/null +++ b/config/sync/field.field.block_content.modal.field_modal_id.yml @@ -0,0 +1,19 @@ +uuid: bd450501-1486-4459-81dd-a6d1511c8295 +langcode: en +status: true +dependencies: + config: + - block_content.type.modal + - field.storage.block_content.field_modal_id +id: block_content.modal.field_modal_id +field_name: field_modal_id +entity_type: block_content +bundle: modal +label: 'Modal ID' +description: 'A name to identify this modal for displaying it programatically. Ex: www.usa.gov/?modal=example_modal_id' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: string diff --git a/config/sync/field.storage.block_content.field_modal.yml b/config/sync/field.storage.block_content.field_modal.yml new file mode 100644 index 0000000000..6e86073e22 --- /dev/null +++ b/config/sync/field.storage.block_content.field_modal.yml @@ -0,0 +1,25 @@ +uuid: 58dda84e-deff-48c5-b96a-75e7c977bdbb +langcode: en +status: true +dependencies: + module: + - block_content + - entity_reference_revisions + - field_permissions + - paragraphs +third_party_settings: + field_permissions: + permission_type: public +id: block_content.field_modal +field_name: field_modal +entity_type: block_content +type: entity_reference_revisions +settings: + target_type: paragraph +module: entity_reference_revisions +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/sync/field.storage.block_content.field_modal_id.yml b/config/sync/field.storage.block_content.field_modal_id.yml new file mode 100644 index 0000000000..5f653901c6 --- /dev/null +++ b/config/sync/field.storage.block_content.field_modal_id.yml @@ -0,0 +1,25 @@ +uuid: 29e44770-ccd1-44e8-b8cb-44a88db4af07 +langcode: en +status: true +dependencies: + module: + - block_content + - field_permissions +third_party_settings: + field_permissions: + permission_type: public +id: block_content.field_modal_id +field_name: field_modal_id +entity_type: block_content +type: string +settings: + max_length: 255 + case_sensitive: false + is_ascii: false +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/sync/language.content_settings.block_content.modal.yml b/config/sync/language.content_settings.block_content.modal.yml new file mode 100644 index 0000000000..27cc441d04 --- /dev/null +++ b/config/sync/language.content_settings.block_content.modal.yml @@ -0,0 +1,11 @@ +uuid: eaa81891-7d18-4bcd-bb8d-54d95a127785 +langcode: en +status: true +dependencies: + config: + - block_content.type.modal +id: block_content.modal +target_entity_type_id: block_content +target_bundle: modal +default_langcode: site_default +language_alterable: true diff --git a/config/sync/user.role.content_administrator.yml b/config/sync/user.role.content_administrator.yml index 3da29cdd62..2d84e1d055 100644 --- a/config/sync/user.role.content_administrator.yml +++ b/config/sync/user.role.content_administrator.yml @@ -3,6 +3,7 @@ langcode: en status: true dependencies: config: + - block_content.type.modal - block_content.type.site_banner - media.type.audio - media.type.file @@ -75,6 +76,7 @@ permissions: - 'create file media' - 'create image media' - 'create media' + - 'create modal block content' - 'create remote_video media' - 'create site_banner block content' - 'create state_directory_record content' @@ -98,6 +100,8 @@ permissions: - 'delete any file media' - 'delete any image media' - 'delete any media' + - 'delete any modal block content' + - 'delete any modal block content revisions' - 'delete any remote_video media' - 'delete any site_banner block content' - 'delete any site_banner block content revisions' @@ -147,6 +151,7 @@ permissions: - 'edit any directory_record content' - 'edit any file media' - 'edit any image media' + - 'edit any modal block content' - 'edit any remote_video media' - 'edit any site_banner block content' - 'edit any state_directory_record content' @@ -173,6 +178,7 @@ permissions: - 'edit terms in wizard' - 'revert agency_synonym revisions' - 'revert all revisions' + - 'revert any modal block content revisions' - 'revert any site_banner block content revisions' - 'revert basic_page revisions' - 'revert bears_agency revisions' @@ -204,6 +210,7 @@ permissions: - 'view agency_synonym revisions' - 'view all media revisions' - 'view all revisions' + - 'view any modal block content history' - 'view any site_banner block content history' - 'view any unpublished content' - 'view basic_page revisions' From 176ec4624e95d5d8686a85dee693b064972a8204 Mon Sep 17 00:00:00 2001 From: Chris Wachtman Date: Wed, 28 Aug 2024 19:00:23 -0400 Subject: [PATCH 3/8] USAGOV-1899-Benefits-Redirect-Modal: Lint Errors --- web/modules/custom/usa_twig_vars/usa_twig_vars.module | 4 ++-- web/themes/custom/usagov/usagov.libraries.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web/modules/custom/usa_twig_vars/usa_twig_vars.module b/web/modules/custom/usa_twig_vars/usa_twig_vars.module index 8c02f33bc5..8afb8fe8c3 100644 --- a/web/modules/custom/usa_twig_vars/usa_twig_vars.module +++ b/web/modules/custom/usa_twig_vars/usa_twig_vars.module @@ -334,10 +334,10 @@ function usa_twig_vars_preprocess_region(&$variables) { * */ $modal_lang = $modal->langcode->value; if ($modal_lang === $site_language) { - $variables['modals'][$modal->id()] = array( + $variables['modals'][$modal->id()] = [ "name" => $modal->field_modal_id->value, "id" => $modal->field_modal[0]->getValue(), - ); + ]; } } } diff --git a/web/themes/custom/usagov/usagov.libraries.yml b/web/themes/custom/usagov/usagov.libraries.yml index cef1d21b4a..561be3f3b1 100644 --- a/web/themes/custom/usagov/usagov.libraries.yml +++ b/web/themes/custom/usagov/usagov.libraries.yml @@ -74,4 +74,4 @@ lazyLoadBgImage: modal: js: - scripts/modal.js: {} \ No newline at end of file + scripts/modal.js: {} From 4891d554ecf32eef0c58561f938913f1cc061ee1 Mon Sep 17 00:00:00 2001 From: Chris Wachtman Date: Wed, 28 Aug 2024 19:02:55 -0400 Subject: [PATCH 4/8] USAGOV-1899-Benefits-Redirect-Modal: Set focus to the first focusable element upon opening modal --- web/themes/custom/usagov/scripts/modal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web/themes/custom/usagov/scripts/modal.js b/web/themes/custom/usagov/scripts/modal.js index d2fae510e1..b99622d9d9 100644 --- a/web/themes/custom/usagov/scripts/modal.js +++ b/web/themes/custom/usagov/scripts/modal.js @@ -25,6 +25,7 @@ function toggleModal(modalName) { let modalID = map.getAttribute('data-modal-id'); if (modalID === null) return; document.querySelector('[href="#paragraph--id--'+ modalID +'"]').click(); + document.querySelector('#paragraph--id--'+ modalID).querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])').focus(); } document.addEventListener('DOMContentLoaded', function() { From 89d9e94c1e98f1c0f33ab805a135af7791a8294e Mon Sep 17 00:00:00 2001 From: Chris Wachtman Date: Thu, 29 Aug 2024 12:48:55 -0400 Subject: [PATCH 5/8] USAGOV-1899-Benefits-Redirect-Modal: button styles --- .../custom/usagov/templates/paragraph--uswds-modal.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig b/web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig index 88156eb359..b5d9df4208 100644 --- a/web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig +++ b/web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig @@ -74,7 +74,7 @@
    {% if content.field_modal_yes_button_text|render %}
  • -
  • From 51b54b2398dd65e6ede9fb613fa6139df665cfc0 Mon Sep 17 00:00:00 2001 From: Chris Wachtman Date: Thu, 29 Aug 2024 13:30:17 -0400 Subject: [PATCH 6/8] USAGOV-1899-Benefits-Redirect-Modal: Hide the modal until the page loads to prevent flash of content --- web/themes/custom/usagov/scripts/modal.js | 4 ++++ .../custom/usagov/templates/paragraph--uswds-modal.html.twig | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/web/themes/custom/usagov/scripts/modal.js b/web/themes/custom/usagov/scripts/modal.js index b99622d9d9..770a80c114 100644 --- a/web/themes/custom/usagov/scripts/modal.js +++ b/web/themes/custom/usagov/scripts/modal.js @@ -31,6 +31,10 @@ function toggleModal(modalName) { document.addEventListener('DOMContentLoaded', function() { "use strict"; + document.querySelectorAll('.usa-modal').forEach((modal) => { + modal.hidden = false; + }); + processModalUrlParameter(); }); diff --git a/web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig b/web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig index b5d9df4208..9dd1f4d907 100644 --- a/web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig +++ b/web/themes/custom/usagov/templates/paragraph--uswds-modal.html.twig @@ -59,7 +59,7 @@ {% endif %} -