From d435f5b39f20126d234d518c67a16083c6745bce Mon Sep 17 00:00:00 2001 From: David Blankenship <128765777+dblanken-yale@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:24:57 -0500 Subject: [PATCH] YALB-1696: Hotfix: Can't configure Page title as Site admin (#547) * fix(YALB-1696): guard against empty block_form Code was added in YALB-959 that attached javascript to specific block types: * tabs * quick_links * image_grids * media_gallery It referenced a block_form array that tells us which block type we are currently attempting to use. In some cases, though, like the heading block, this block_form array does not exist, resulting in a background error. This makes it look as if the user cannot modify the block. While block_form doesn't always exist, it seems that getting the blockInfo and looking at the args can tell you which block type we are dealing with. I'm hoping there's a more elegant way of doing this, but it does seem to be working for existing and new block elements. In some cases, the arguments dictate the type of block, and in others, it has a block_form object. We abstract this to just get it. * fix(YALB-1696): fallback js error to submit button In fixing the block_form issue, I noticed that when testing the functionality of YALB-959, there was an issue where paragraph items that weren't expanded couldn't display the error message to the user, and would error. It would not hinder the submissions of the form, so it would result in users being able to submit with one tab, for instance. This fix checks if the input that was found is visible, and if not, it appends the message to the submit button that we know is there, thus letting the form continue to submit or stop. --- .../modules/custom/ys_core/js/block-form.js | 101 +++++++++++------- .../modules/custom/ys_core/ys_core.module | 39 ++++++- 2 files changed, 98 insertions(+), 42 deletions(-) diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_core/js/block-form.js b/web/profiles/custom/yalesites_profile/modules/custom/ys_core/js/block-form.js index 3c3a43d278..24a3f253a9 100644 --- a/web/profiles/custom/yalesites_profile/modules/custom/ys_core/js/block-form.js +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_core/js/block-form.js @@ -1,59 +1,78 @@ ((Drupal) => { Drupal.behaviors.ysCoreBlockForm = { - attach: () => { // eslint-disable-line + attach: () => { + // eslint-disable-line /* - * Function to validate that all media items contain media. - * - * @param object blockType - * blockType object. - * - * @return string - * The error message or empty string. - * */ + * Function to validate that all media items contain media. + * + * @param object blockType + * blockType object. + * + * @return string + * The error message or empty string. + * */ function getErrors(blockType) { // Get all items of the specified type. const items = document.querySelectorAll(blockType.itemSelector); // Count the number of items present. const numberOfItems = items.length; - if (numberOfItems < blockType.min || (blockType.max > 0 && numberOfItems > blockType.max)) { - let messageText = ''; + if ( + numberOfItems < blockType.min || + (blockType.max > 0 && numberOfItems > blockType.max) + ) { + let messageText = ""; if (blockType.max > 0) { messageText = `Number of ${blockType.type} must be between ${blockType.min} and ${blockType.max}. `; } else { messageText = `Number of ${blockType.type} must be ${blockType.min} or more. `; } - return messageText + `Number of ${blockType.type} added: ${numberOfItems}.`; + return ( + messageText + `Number of ${blockType.type} added: ${numberOfItems}.` + ); } // An empty string signifies no errors and resets validation for the input. - return ''; + return ""; } /* - * Function to validate a block type. - * - * @param object blocktype - * Object containing block type information for validation. - * - * @return void - * */ + * Function to validate a block type. + * + * @param object blocktype + * Object containing block type information for validation. + * + * @return void + * */ function validateBlockType(blockType) { // Get the layout builder add and update forms. - const blockContentForm = document.querySelector('form[id^="block-content"]'); + const blockContentForm = document.querySelector( + 'form[id^="block-content"]' + ); // Inputs and submit selectors are different on block content and layout builder forms. - const inputSelector = blockContentForm ? blockType.inputSelector : blockType.lbInputSelector; - const submitSelector = blockContentForm ? 'edit-submit' : 'edit-actions-submit'; - const submitButton = document.querySelector(`input[data-drupal-selector=${submitSelector}]`); + const inputSelector = blockContentForm + ? blockType.inputSelector + : blockType.lbInputSelector; + const submitSelector = blockContentForm + ? "edit-submit" + : "edit-actions-submit"; + const submitButton = document.querySelector( + `input[data-drupal-selector=${submitSelector}]` + ); if (submitButton) { // On click, check for custom errors. submitButton.addEventListener("click", () => { const input = document.querySelector(inputSelector); const errorMsg = getErrors(blockType); - // If there are any errors, set custom validity on the chosen input field. - input.setCustomValidity(errorMsg); + // If there are any errors, set custom validity on the chosen input field if it's visible. + if (input.type === "hidden") { + submitButton.setCustomValidity(errorMsg); + // Otherwise set it on the submit button. + } else { + input.setCustomValidity(errorMsg); + } }); } } @@ -62,40 +81,44 @@ const blockTypes = [ { // Tabs - itemSelector: 'tr.paragraph-type--tab', + itemSelector: "tr.paragraph-type--tab", inputSelector: 'input[data-drupal-selector^="edit-field-tabs"]', - lbInputSelector: 'input[data-drupal-selector^="edit-settings-block-form-field-tabs"]', + lbInputSelector: + 'input[data-drupal-selector^="edit-settings-block-form-field-tabs"]', min: 2, max: 5, - type: 'tabs', + type: "tabs", }, { // Quick links - itemSelector: 'input.ui-autocomplete-input', + itemSelector: "input.ui-autocomplete-input", inputSelector: 'input[data-drupal-selector^="edit-field-heading"]', - lbInputSelector: 'input[data-drupal-selector^="edit-settings-block-form-field-links"]', + lbInputSelector: + 'input[data-drupal-selector^="edit-settings-block-form-field-links"]', min: 3, max: 9, - type: 'links', + type: "links", }, { // Media Grid - itemSelector: '.paragraph-type--media-grid-item', + itemSelector: ".paragraph-type--media-grid-item", inputSelector: 'input[data-drupal-selector^="edit-field-heading"]', - lbInputSelector: 'input[data-drupal-selector^="edit-settings-block-form-field-heading"]', + lbInputSelector: + 'input[data-drupal-selector^="edit-settings-block-form-field-heading"]', min: 2, max: 0, - type: 'media grid items', + type: "media grid items", }, { // Gallery - itemSelector: '.paragraph-type--gallery-item', + itemSelector: ".paragraph-type--gallery-item", inputSelector: 'input[data-drupal-selector^="edit-field-heading"]', - lbInputSelector: 'input[data-drupal-selector^="edit-settings-block-form-field-heading"]', + lbInputSelector: + 'input[data-drupal-selector^="edit-settings-block-form-field-heading"]', min: 2, max: 0, - type: 'gallery items', - } + type: "gallery items", + }, ]; // Apply the function to each block type. diff --git a/web/profiles/custom/yalesites_profile/modules/custom/ys_core/ys_core.module b/web/profiles/custom/yalesites_profile/modules/custom/ys_core/ys_core.module index 7cefad4675..13d74399dc 100644 --- a/web/profiles/custom/yalesites_profile/modules/custom/ys_core/ys_core.module +++ b/web/profiles/custom/yalesites_profile/modules/custom/ys_core/ys_core.module @@ -138,19 +138,20 @@ function ys_core_form_alter(&$form, $form_state, $form_id) { ]; if (in_array($form_id, $layout_builder_block_forms)) { - // Get the block type from the form. - $block = $form['settings']['block_form']['#block']; + $block_type_name = ys_core_get_block_type($form, $form_state); + $limited_block_types = [ 'tabs', 'quick_links', 'media_grid', 'gallery', ]; - if (in_array($block->bundle(), $limited_block_types)) { + if (in_array($block_type_name, $limited_block_types)) { $form['#attached']['library'][] = 'ys_core/block_form'; } } + } /** @@ -416,3 +417,35 @@ function ys_core_preprocess_page(&$variables) { $config = \Drupal::config('ys_core.header_settings'); \Drupal::service('renderer')->addCacheableDependency($variables, $config); } + +/** + * Retrieves the block type from a form. + * + * @param array $form + * The form array. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return string + * The block type name. + */ +function ys_core_get_block_type(&$form, &$form_state) { + $block_type_name = ""; + $inline_block_type_name = $form_state->getBuildInfo()['args'][3]; + + // If adding a new element, arg 3 should be of the form: + // inline_block:BLOCK_TYPE_NAME. + if (strpos($inline_block_type_name, ':') !== FALSE) { + $block_type_name = explode(':', $inline_block_type_name)[1]; + } + // Otherwise, attempt to get it the original way if it exists. + elseif (isset($form['settings']['block_form'])) { + $block_type_name = $form['settings']['block_form']['#block']->bundle(); + } + // If we can't find it, make it something that will fail any future checks. + else { + $block_type_name = "unknown"; + } + + return $block_type_name; +}