Initial Drupal 11 with DDEV setup
This commit is contained in:
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @file media_library.click_to_select.js
|
||||
*/
|
||||
|
||||
(($, Drupal) => {
|
||||
/**
|
||||
* Allows users to select an element which checks a hidden checkbox.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches behavior for selecting media library item.
|
||||
*/
|
||||
Drupal.behaviors.ClickToSelect = {
|
||||
attach(context) {
|
||||
$(
|
||||
once(
|
||||
'media-library-click-to-select',
|
||||
'.js-click-to-select-trigger',
|
||||
context,
|
||||
),
|
||||
).on('click', (event) => {
|
||||
// Links inside the trigger should not be click-able.
|
||||
event.preventDefault();
|
||||
// Click the hidden checkbox when the trigger is clicked.
|
||||
const $input = $(event.currentTarget)
|
||||
.closest('.js-click-to-select')
|
||||
.find('.js-click-to-select-checkbox input');
|
||||
$input.prop('checked', !$input.prop('checked')).trigger('change');
|
||||
});
|
||||
|
||||
$(
|
||||
once(
|
||||
'media-library-click-to-select',
|
||||
'.js-click-to-select-checkbox input',
|
||||
context,
|
||||
),
|
||||
)
|
||||
.on('change', ({ currentTarget }) => {
|
||||
$(currentTarget)
|
||||
.closest('.js-click-to-select')
|
||||
.toggleClass('checked', $(currentTarget).prop('checked'));
|
||||
})
|
||||
// Adds is-focus class to the click-to-select element.
|
||||
.on('focus blur', ({ currentTarget, type }) => {
|
||||
$(currentTarget)
|
||||
.closest('.js-click-to-select')
|
||||
.toggleClass('is-focus', type === 'focus');
|
||||
});
|
||||
|
||||
// Adds hover class to the click-to-select element.
|
||||
$(
|
||||
once(
|
||||
'media-library-click-to-select-hover',
|
||||
'.js-click-to-select-trigger, .js-click-to-select-checkbox',
|
||||
context,
|
||||
),
|
||||
).on('mouseover mouseout', ({ currentTarget, type }) => {
|
||||
$(currentTarget)
|
||||
.closest('.js-click-to-select')
|
||||
.toggleClass('is-hover', type === 'mouseover');
|
||||
});
|
||||
},
|
||||
};
|
||||
})(jQuery, Drupal);
|
||||
429
web/core/modules/media_library/js/media_library.ui.js
Normal file
429
web/core/modules/media_library/js/media_library.ui.js
Normal file
@ -0,0 +1,429 @@
|
||||
/**
|
||||
* @file media_library.ui.js
|
||||
*/
|
||||
(($, Drupal, window, { tabbable }) => {
|
||||
/**
|
||||
* Wrapper object for the current state of the media library.
|
||||
*/
|
||||
Drupal.MediaLibrary = {
|
||||
/**
|
||||
* When a user interacts with the media library we want the selection to
|
||||
* persist as long as the media library modal is opened. We temporarily
|
||||
* store the selected items while the user filters the media library view or
|
||||
* navigates to different tabs.
|
||||
*/
|
||||
currentSelection: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* Command to update the current media library selection.
|
||||
*
|
||||
* @param {Drupal.Ajax} [ajax]
|
||||
* The Drupal Ajax object.
|
||||
* @param {object} response
|
||||
* Object holding the server response.
|
||||
* @param {number} [status]
|
||||
* The HTTP status code.
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.updateMediaLibrarySelection = function (
|
||||
ajax,
|
||||
response,
|
||||
status,
|
||||
) {
|
||||
Object.values(response.mediaIds).forEach((value) => {
|
||||
Drupal.MediaLibrary.currentSelection.push(value);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Load media library content through AJAX.
|
||||
*
|
||||
* Standard AJAX links (using the 'use-ajax' class) replace the entire library
|
||||
* dialog. When navigating to a media type through the vertical tabs, we only
|
||||
* want to load the changed library content. This is not only more efficient,
|
||||
* but also provides a more accessible user experience for screen readers.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches behavior to vertical tabs in the media library.
|
||||
*
|
||||
* @todo Remove when the AJAX system adds support for replacing a specific
|
||||
* selector via a link.
|
||||
* https://www.drupal.org/project/drupal/issues/3026636
|
||||
*/
|
||||
Drupal.behaviors.MediaLibraryTabs = {
|
||||
attach(context) {
|
||||
const $menu = $('.js-media-library-menu');
|
||||
$(once('media-library-menu-item', $menu.find('a')))
|
||||
.on('keypress', (e) => {
|
||||
// The AJAX link has the button role, so we need to make sure the link
|
||||
// is also triggered when pressing the space bar.
|
||||
if (e.which === 32) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$(e.currentTarget).trigger('click');
|
||||
}
|
||||
})
|
||||
.on('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// Replace the library content.
|
||||
const ajaxObject = Drupal.ajax({
|
||||
wrapper: 'media-library-content',
|
||||
url: e.currentTarget.href,
|
||||
dialogType: 'ajax',
|
||||
progress: {
|
||||
type: 'fullscreen',
|
||||
message: Drupal.t('Processing...'),
|
||||
},
|
||||
});
|
||||
|
||||
// Override the AJAX success callback to shift focus to the media
|
||||
// library content.
|
||||
ajaxObject.success = function (response, status) {
|
||||
return Promise.resolve(
|
||||
Drupal.Ajax.prototype.success.call(ajaxObject, response, status),
|
||||
).then(() => {
|
||||
// Set focus to the first tabbable element in the media library
|
||||
// content.
|
||||
const mediaLibraryContent = document.getElementById(
|
||||
'media-library-content',
|
||||
);
|
||||
if (mediaLibraryContent) {
|
||||
const tabbableContent = tabbable(mediaLibraryContent);
|
||||
if (tabbableContent.length) {
|
||||
tabbableContent[0].focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
ajaxObject.execute();
|
||||
|
||||
// Set the selected tab.
|
||||
$menu.find('.active-tab').remove();
|
||||
$menu.find('a').removeClass('active');
|
||||
$(e.currentTarget)
|
||||
.addClass('active')
|
||||
.html(
|
||||
Drupal.t(
|
||||
'<span class="visually-hidden">Show </span>@title<span class="visually-hidden"> media</span><span class="active-tab visually-hidden"> (selected)</span>',
|
||||
{ '@title': $(e.currentTarget).data('title') },
|
||||
),
|
||||
);
|
||||
|
||||
// Announce the updated content.
|
||||
Drupal.announce(
|
||||
Drupal.t('Showing @title media.', {
|
||||
'@title': $(e.currentTarget).data('title'),
|
||||
}),
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Load media library displays through AJAX.
|
||||
*
|
||||
* Standard AJAX links (using the 'use-ajax' class) replace the entire library
|
||||
* dialog. When navigating to a media library views display, we only want to
|
||||
* load the changed views display content. This is not only more efficient,
|
||||
* but also provides a more accessible user experience for screen readers.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches behavior to vertical tabs in the media library.
|
||||
*
|
||||
* @todo Remove when the AJAX system adds support for replacing a specific
|
||||
* selector via a link.
|
||||
* https://www.drupal.org/project/drupal/issues/3026636
|
||||
*/
|
||||
Drupal.behaviors.MediaLibraryViewsDisplay = {
|
||||
attach(context) {
|
||||
const $view = $(context).hasClass('.js-media-library-view')
|
||||
? $(context)
|
||||
: $('.js-media-library-view', context);
|
||||
|
||||
// Add a class to the view to allow it to be replaced via AJAX.
|
||||
// @todo Remove the custom ID when the AJAX system allows replacing
|
||||
// elements by selector.
|
||||
// https://www.drupal.org/project/drupal/issues/2821793
|
||||
$view
|
||||
.closest('.views-element-container')
|
||||
.attr('id', 'media-library-view');
|
||||
|
||||
// We would ideally use a generic JavaScript specific class to detect the
|
||||
// display links. Since we have no good way of altering display links yet,
|
||||
// this is the best we can do for now.
|
||||
// @todo Add media library specific classes and data attributes to the
|
||||
// media library display links when we can alter display links.
|
||||
// https://www.drupal.org/project/drupal/issues/3036694
|
||||
$(
|
||||
once(
|
||||
'media-library-views-display-link',
|
||||
'.views-display-link-widget, .views-display-link-widget_table',
|
||||
context,
|
||||
),
|
||||
).on('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const $link = $(e.currentTarget);
|
||||
|
||||
// Add a loading and display announcement for screen reader users.
|
||||
let loadingAnnouncement = '';
|
||||
let displayAnnouncement = '';
|
||||
let focusSelector = '';
|
||||
if ($link.hasClass('views-display-link-widget')) {
|
||||
loadingAnnouncement = Drupal.t('Loading grid view.');
|
||||
displayAnnouncement = Drupal.t('Changed to grid view.');
|
||||
focusSelector = '.views-display-link-widget';
|
||||
} else if ($link.hasClass('views-display-link-widget_table')) {
|
||||
loadingAnnouncement = Drupal.t('Loading table view.');
|
||||
displayAnnouncement = Drupal.t('Changed to table view.');
|
||||
focusSelector = '.views-display-link-widget_table';
|
||||
}
|
||||
|
||||
// Replace the library view.
|
||||
const ajaxObject = Drupal.ajax({
|
||||
wrapper: 'media-library-view',
|
||||
url: e.currentTarget.href,
|
||||
dialogType: 'ajax',
|
||||
progress: {
|
||||
type: 'fullscreen',
|
||||
message: loadingAnnouncement || Drupal.t('Processing...'),
|
||||
},
|
||||
});
|
||||
|
||||
// Override the AJAX success callback to announce the updated content
|
||||
// to screen readers.
|
||||
if (displayAnnouncement || focusSelector) {
|
||||
const success = ajaxObject.success;
|
||||
ajaxObject.success = function (response, status) {
|
||||
success.bind(this)(response, status);
|
||||
// The AJAX link replaces the whole view, including the clicked
|
||||
// link. Move the focus back to the clicked link when the view is
|
||||
// replaced.
|
||||
if (focusSelector) {
|
||||
$(focusSelector).focus();
|
||||
}
|
||||
// Announce the new view is loaded to screen readers.
|
||||
if (displayAnnouncement) {
|
||||
Drupal.announce(displayAnnouncement);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ajaxObject.execute();
|
||||
|
||||
// Announce the new view is being loaded to screen readers.
|
||||
// @todo Replace custom announcement when
|
||||
// https://www.drupal.org/project/drupal/issues/2973140 is in.
|
||||
if (loadingAnnouncement) {
|
||||
Drupal.announce(loadingAnnouncement);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the media library selection when loaded or media items are selected.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches behavior to select media items.
|
||||
*/
|
||||
Drupal.behaviors.MediaLibraryItemSelection = {
|
||||
attach(context, settings) {
|
||||
const $form = $(
|
||||
'.js-media-library-views-form, .js-media-library-add-form',
|
||||
context,
|
||||
);
|
||||
const currentSelection = Drupal.MediaLibrary.currentSelection;
|
||||
|
||||
if (!$form.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $mediaItems = $(
|
||||
'.js-media-library-item input[type="checkbox"]',
|
||||
$form,
|
||||
);
|
||||
|
||||
/**
|
||||
* Disable media items.
|
||||
*
|
||||
* @param {jQuery} $items
|
||||
* A jQuery object representing the media items that should be disabled.
|
||||
*/
|
||||
function disableItems($items) {
|
||||
$items
|
||||
.prop('disabled', true)
|
||||
.closest('.js-media-library-item')
|
||||
.addClass('media-library-item--disabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable media items.
|
||||
*
|
||||
* @param {jQuery} $items
|
||||
* A jQuery object representing the media items that should be enabled.
|
||||
*/
|
||||
function enableItems($items) {
|
||||
$items
|
||||
.prop('disabled', false)
|
||||
.closest('.js-media-library-item')
|
||||
.removeClass('media-library-item--disabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the number of selected items in the button pane.
|
||||
*
|
||||
* @param {number} remaining
|
||||
* The number of remaining slots.
|
||||
*/
|
||||
function updateSelectionCount(remaining) {
|
||||
// When the remaining number of items is a negative number, we allow an
|
||||
// unlimited number of items. In that case we don't want to show the
|
||||
// number of remaining slots.
|
||||
const selectItemsText =
|
||||
remaining < 0
|
||||
? Drupal.formatPlural(
|
||||
currentSelection.length,
|
||||
'1 item selected',
|
||||
'@count items selected',
|
||||
)
|
||||
: Drupal.formatPlural(
|
||||
remaining,
|
||||
'@selected of @count item selected',
|
||||
'@selected of @count items selected',
|
||||
{
|
||||
'@selected': currentSelection.length,
|
||||
},
|
||||
);
|
||||
// The selected count div could have been created outside of the
|
||||
// context, so we unfortunately can't use context here.
|
||||
$('.js-media-library-selected-count').html(selectItemsText);
|
||||
}
|
||||
|
||||
function checkEnabled() {
|
||||
updateSelectionCount(settings.media_library.selection_remaining);
|
||||
if (
|
||||
currentSelection.length === settings.media_library.selection_remaining
|
||||
) {
|
||||
disableItems($mediaItems.not(':checked'));
|
||||
enableItems($mediaItems.filter(':checked'));
|
||||
} else {
|
||||
enableItems($mediaItems);
|
||||
}
|
||||
}
|
||||
// Update the selection array and the hidden form field when a media item
|
||||
// is selected.
|
||||
$(once('media-item-change', $mediaItems)).on('change', (e) => {
|
||||
const id = e.currentTarget.value;
|
||||
|
||||
// Update the selection.
|
||||
if (e.currentTarget.checked) {
|
||||
// Check if the ID is not already in the selection and add if needed.
|
||||
if (!currentSelection.includes(id)) {
|
||||
currentSelection.push(id);
|
||||
}
|
||||
} else if (currentSelection.includes(id)) {
|
||||
// Remove the ID when it is in the current selection.
|
||||
currentSelection.splice(currentSelection.indexOf(id), 1);
|
||||
}
|
||||
|
||||
const mediaLibraryModalSelection = document.querySelector(
|
||||
'#media-library-modal-selection',
|
||||
);
|
||||
|
||||
if (mediaLibraryModalSelection) {
|
||||
// Set the selection in the hidden form element.
|
||||
mediaLibraryModalSelection.value = currentSelection.join();
|
||||
$(mediaLibraryModalSelection).trigger('change');
|
||||
}
|
||||
|
||||
// Set the selection in the media library add form. Since the form is
|
||||
// not necessarily loaded within the same context, we can't use the
|
||||
// context here.
|
||||
document
|
||||
.querySelectorAll('.js-media-library-add-form-current-selection')
|
||||
.forEach((item) => {
|
||||
item.value = currentSelection.join();
|
||||
});
|
||||
});
|
||||
checkEnabled();
|
||||
// The hidden selection form field changes when the selection is updated.
|
||||
$(
|
||||
once(
|
||||
'media-library-selection-change',
|
||||
$form.find('#media-library-modal-selection'),
|
||||
),
|
||||
).on('change', (e) => {
|
||||
checkEnabled();
|
||||
});
|
||||
|
||||
// Apply the current selection to the media library view. Changing the
|
||||
// checkbox values triggers the change event for the media items. The
|
||||
// change event handles updating the hidden selection field for the form.
|
||||
currentSelection.forEach((value) => {
|
||||
$form
|
||||
.find(`input[type="checkbox"][value="${value}"]`)
|
||||
.prop('checked', true)
|
||||
.trigger('change');
|
||||
});
|
||||
|
||||
// Add the selection count to the button pane when a media library dialog
|
||||
// is created.
|
||||
if (!once('media-library-selection-info', 'html').length) {
|
||||
return;
|
||||
}
|
||||
window.addEventListener('dialog:aftercreate', () => {
|
||||
// Since the dialog HTML is not part of the context, we can't use
|
||||
// context here.
|
||||
const $buttonPane = $(
|
||||
'.media-library-widget-modal .ui-dialog-buttonpane',
|
||||
);
|
||||
if (!$buttonPane.length) {
|
||||
return;
|
||||
}
|
||||
$buttonPane.append(Drupal.theme('mediaLibrarySelectionCount'));
|
||||
updateSelectionCount(settings.media_library.selection_remaining);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the current selection.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches behavior to clear the selection when the library modal closes.
|
||||
*/
|
||||
Drupal.behaviors.MediaLibraryModalClearSelection = {
|
||||
attach() {
|
||||
if (!once('media-library-clear-selection', 'html').length) {
|
||||
return;
|
||||
}
|
||||
window.addEventListener('dialog:afterclose', () => {
|
||||
// This empty the array while keeping the existing array reference,
|
||||
// to keep event listeners working.
|
||||
Drupal.MediaLibrary.currentSelection.length = 0;
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Theme function for the selection count.
|
||||
*
|
||||
* @return {string}
|
||||
* The corresponding HTML.
|
||||
*/
|
||||
Drupal.theme.mediaLibrarySelectionCount = function () {
|
||||
return `<div class="media-library-selected-count js-media-library-selected-count" role="status" aria-live="polite" aria-atomic="true"></div>`;
|
||||
};
|
||||
})(jQuery, Drupal, window, window.tabbable);
|
||||
49
web/core/modules/media_library/js/media_library.view.js
Normal file
49
web/core/modules/media_library/js/media_library.view.js
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @file media_library.view.js
|
||||
*/
|
||||
(($, Drupal) => {
|
||||
/**
|
||||
* Adds checkbox to select all items in the library.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches behavior to select all media items.
|
||||
*/
|
||||
Drupal.behaviors.MediaLibrarySelectAll = {
|
||||
attach(context) {
|
||||
const $view = $(
|
||||
once(
|
||||
'media-library-select-all',
|
||||
'.js-media-library-view[data-view-display-id="page"]',
|
||||
context,
|
||||
),
|
||||
);
|
||||
if ($view.length && $view.find('.js-media-library-item').length) {
|
||||
const $checkbox = $(Drupal.theme('checkbox')).on(
|
||||
'click',
|
||||
({ currentTarget }) => {
|
||||
// Toggle all checkboxes.
|
||||
const $checkboxes = $(currentTarget)
|
||||
.closest('.js-media-library-view')
|
||||
.find('.js-media-library-item input[type="checkbox"]');
|
||||
$checkboxes
|
||||
.prop('checked', $(currentTarget).prop('checked'))
|
||||
.trigger('change');
|
||||
// Announce the selection.
|
||||
const announcement = $(currentTarget).prop('checked')
|
||||
? Drupal.t('All @count items selected', {
|
||||
'@count': $checkboxes.length,
|
||||
})
|
||||
: Drupal.t('Zero items selected');
|
||||
Drupal.announce(announcement);
|
||||
},
|
||||
);
|
||||
const $label = $('<label class="media-library-select-all"></label>');
|
||||
$label[0].textContent = Drupal.t('Select all media');
|
||||
$label.prepend($checkbox);
|
||||
$view.find('.js-media-library-item').first().before($label);
|
||||
}
|
||||
},
|
||||
};
|
||||
})(jQuery, Drupal);
|
||||
106
web/core/modules/media_library/js/media_library.widget.js
Normal file
106
web/core/modules/media_library/js/media_library.widget.js
Normal file
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @file media_library.widget.js
|
||||
*/
|
||||
(($, Drupal, Sortable) => {
|
||||
/**
|
||||
* Allows users to re-order their selection with drag+drop.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches behavior to re-order selected media items.
|
||||
*/
|
||||
Drupal.behaviors.MediaLibraryWidgetSortable = {
|
||||
attach(context) {
|
||||
// Allow media items to be re-sorted with drag+drop in the widget.
|
||||
const selection = context.querySelectorAll('.js-media-library-selection');
|
||||
selection.forEach((widget) => {
|
||||
Sortable.create(widget, {
|
||||
draggable: '.js-media-library-item',
|
||||
handle: '.js-media-library-item-preview',
|
||||
onEnd: () => {
|
||||
$(widget)
|
||||
.children()
|
||||
.each((index, child) => {
|
||||
$(child).find('.js-media-library-item-weight')[0].value = index;
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Allows selection order to be set without drag+drop for accessibility.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches behavior to toggle the weight field for media items.
|
||||
*/
|
||||
Drupal.behaviors.MediaLibraryWidgetToggleWeight = {
|
||||
attach(context) {
|
||||
const strings = {
|
||||
show: Drupal.t('Show media item weights'),
|
||||
hide: Drupal.t('Hide media item weights'),
|
||||
};
|
||||
const mediaLibraryToggle = once(
|
||||
'media-library-toggle',
|
||||
'.js-media-library-widget-toggle-weight',
|
||||
context,
|
||||
);
|
||||
$(mediaLibraryToggle).on('click', (e) => {
|
||||
e.preventDefault();
|
||||
const $target = $(e.currentTarget);
|
||||
e.currentTarget.textContent = $target.hasClass('active')
|
||||
? strings.show
|
||||
: strings.hide;
|
||||
$target
|
||||
.toggleClass('active')
|
||||
.closest('.js-media-library-widget')
|
||||
.find('.js-media-library-item-weight')
|
||||
.parent()
|
||||
.toggle();
|
||||
});
|
||||
mediaLibraryToggle.forEach((item) => {
|
||||
item.textContent = strings.show;
|
||||
});
|
||||
|
||||
$(once('media-library-toggle', '.js-media-library-item-weight', context))
|
||||
.parent()
|
||||
.hide();
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable the open button when the user is not allowed to add more items.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches behavior to disable the media library open button.
|
||||
*/
|
||||
Drupal.behaviors.MediaLibraryWidgetDisableButton = {
|
||||
attach(context) {
|
||||
// When the user returns from the modal to the widget, we want to shift
|
||||
// the focus back to the open button. If the user is not allowed to add
|
||||
// more items, the button needs to be disabled. Since we can't shift the
|
||||
// focus to disabled elements, the focus is set back to the open button
|
||||
// via JavaScript by adding the 'data-disabled-focus' attribute.
|
||||
once(
|
||||
'media-library-disable',
|
||||
'.js-media-library-open-button[data-disabled-focus="true"]',
|
||||
context,
|
||||
).forEach((button) => {
|
||||
$(button).focus();
|
||||
|
||||
// There is a small delay between the focus set by the browser and the
|
||||
// focus of screen readers. We need to give screen readers time to shift
|
||||
// the focus as well before the button is disabled.
|
||||
setTimeout(() => {
|
||||
$(button).attr('disabled', 'disabled');
|
||||
}, 50);
|
||||
});
|
||||
},
|
||||
};
|
||||
})(jQuery, Drupal, Sortable);
|
||||
Reference in New Issue
Block a user