Commit c91f2365 authored by webchick's avatar webchick
Browse files

Issue #3023797 by seanB, webchick, lauriii, ckrina, phenaproxima,...

Issue #3023797 by seanB, webchick, lauriii, ckrina, phenaproxima, andrewmacpherson, rainbreaw, Gábor Hojtsy, jhodgdon, jrockowitz, worldlinemine, benjifisher: Let users choose what to do after selecting and/or adding items in the media library
parent 9d96532b
......@@ -24,6 +24,7 @@
.media-library-views-form,
.media-library-selection,
.media-library-add-form__selected-media .details-wrapper,
.media-library-views-form__bulk_form,
.media-library-view .form--inline {
display: flex;
......@@ -81,7 +82,8 @@
/* @todo Remove or re-work in https://www.drupal.org/node/2985168 */
.media-library-widget .media-library-item__name a,
.media-library-view--widget .media-library-item__name a {
.media-library-view--widget .media-library-item__name a,
.media-library-add-form__selected-media .media-library-item__name a {
pointer-events: none;
}
......
......@@ -116,6 +116,10 @@
margin: 8px 0 0;
}
.media-library-add-form__description {
margin: 0;
}
/* Style the media add oEmbed form. */
.media-library-add-form--oembed .media-library-add-form__input-wrapper {
display: flex;
......@@ -143,6 +147,20 @@
align-self: center;
}
/* Media add form selection styles. */
.media-library-add-form__selected-media {
margin-top: 1em;
}
/* Change to padding to account for the negative margin for flex grid. */
.media-library-add-form__selected-media .details-wrapper {
padding: 0 10px 1em 10px;
}
.media-library-add-form__selected-media .media-library-item .field--name-thumbnail img {
height: 100px;
}
/* Generic media library view styles. */
.media-library-select-all {
margin: 10px 0 10px 0;
......@@ -290,16 +308,26 @@
border: 1px solid #dbdbdb;
}
/* The selected items in the add form should be shown a bit smaller. */
.media-library-add-form__selected-media .media-library-item--small {
width: 33.3%;
}
@media screen and (min-width: 45em) {
.media-library-item--grid {
width: 33%;
width: 33.3%;
}
/* Use a smaller width for the modal and widget since there is less space. */
/* Change the width for the modal and widget since there is less space. */
.media-library-widget-modal .media-library-item--grid,
.media-library-selection .media-library-item--grid {
width: 50%;
}
/* The selected items in the add form should be shown a bit smaller. */
.media-library-add-form__selected-media .media-library-item--small {
width: 25%;
}
}
@media screen and (min-width: 60em) {
......@@ -307,23 +335,33 @@
width: 25%;
}
/* Use a smaller width for the modal and widget since there is less space. */
/* Change the width for the modal and widget since there is less space. */
.media-library-widget-modal .media-library-item--grid,
.media-library-selection .media-library-item--grid {
width: 33%;
width: 33.3%;
}
/* The selected items in the add form should be shown a bit smaller. */
.media-library-add-form__selected-media .media-library-item--small {
width: 16.6%;
}
}
@media screen and (min-width: 77em) {
.media-library-item--grid {
width: 16%;
width: 16.6%;
}
/* Use a smaller width for the modal and widget since there is less space. */
/* Change the width for the modal and widget since there is less space. */
.media-library-widget-modal .media-library-item--grid,
.media-library-selection .media-library-item--grid {
width: 25%;
}
/* The selected items in the add form should be shown a bit smaller. */
.media-library-add-form__selected-media .media-library-item--small {
width: 16.6%;
}
}
.media-library-item--grid .field--name-thumbnail {
......@@ -348,7 +386,7 @@
border-radius: 3px;
}
.media-library-item--grid.checked {
.media-library-item--grid.checked:before {
border-color: #0076c0;
}
......@@ -504,7 +542,7 @@
.media-library-add-form__media {
position: relative;
display: flex;
padding: 20px 0 20px 0;
padding: 1em 0;
border-bottom: 1px solid #c0c0c0;
outline: none;
}
......@@ -607,7 +645,8 @@
/* @todo Remove or re-work in https://www.drupal.org/node/2985168 */
.media-library-widget .media-library-item__name a,
.media-library-view--widget .media-library-item__name a {
.media-library-view--widget .media-library-item__name a,
.media-library-add-form__selected-media .media-library-item__name a {
text-decoration: none;
color: black;
}
......@@ -24,12 +24,29 @@
.find('.js-click-to-select-checkbox input');
$input.prop('checked', !$input.prop('checked')).trigger('change');
});
$('.js-click-to-select-checkbox input', context)
.once('media-library-click-to-select')
// Adds checked class to the click-to-select element.
.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.
$('.js-click-to-select-trigger, .js-click-to-select-checkbox', context)
.once('media-library-click-to-select-hover')
.on('mouseover mouseout', ({ currentTarget, type }) => {
$(currentTarget)
.closest('.js-click-to-select')
.toggleClass('is-hover', type === 'mouseover');
});
},
};
......
......@@ -14,10 +14,23 @@
var $input = $(event.currentTarget).closest('.js-click-to-select').find('.js-click-to-select-checkbox input');
$input.prop('checked', !$input.prop('checked')).trigger('change');
});
$('.js-click-to-select-checkbox input', context).once('media-library-click-to-select').on('change', function (_ref) {
var currentTarget = _ref.currentTarget;
$(currentTarget).closest('.js-click-to-select').toggleClass('checked', $(currentTarget).prop('checked'));
}).on('focus blur', function (_ref2) {
var currentTarget = _ref2.currentTarget,
type = _ref2.type;
$(currentTarget).closest('.js-click-to-select').toggleClass('is-focus', type === 'focus');
});
$('.js-click-to-select-trigger, .js-click-to-select-checkbox', context).once('media-library-click-to-select-hover').on('mouseover mouseout', function (_ref3) {
var currentTarget = _ref3.currentTarget,
type = _ref3.type;
$(currentTarget).closest('.js-click-to-select').toggleClass('is-hover', type === 'mouseover');
});
}
};
......
......@@ -251,7 +251,10 @@
*/
Drupal.behaviors.MediaLibraryItemSelection = {
attach(context, settings) {
const $form = $('.js-media-library-views-form', context);
const $form = $(
'.js-media-library-views-form, .js-media-library-add-form',
context,
);
const currentSelection = Drupal.MediaLibrary.currentSelection;
if (!$form.length) {
......@@ -263,30 +266,6 @@
$form,
);
// Update the selection array and the hidden form field when a media item
// is selected.
$mediaItems.once('media-item-change').on('change', e => {
const id = e.currentTarget.value;
// Update the selection.
const position = currentSelection.indexOf(id);
if (e.currentTarget.checked) {
// Check if the ID is not already in the selection and add if needed.
if (position === -1) {
currentSelection.push(id);
}
} else if (position !== -1) {
// Remove the ID when it is in the current selection.
currentSelection.splice(position, 1);
}
// Set the selection in the hidden form element.
$form
.find('#media-library-modal-selection')
.val(currentSelection.join())
.trigger('change');
});
/**
* Disable media items.
*
......@@ -343,23 +322,49 @@
}
}
// The hidden selection form field changes when the selection is updated.
$('#media-library-modal-selection', $form)
.once('media-library-selection-change')
.on('change', e => {
updateSelectionInfo(settings.media_library.selection_remaining);
// Update the selection array and the hidden form field when a media item
// is selected.
$mediaItems.once('media-item-change').on('change', e => {
const id = e.currentTarget.value;
// Prevent users from selecting more items than allowed.
if (
currentSelection.length ===
settings.media_library.selection_remaining
) {
disableItems($mediaItems.not(':checked'));
enableItems($mediaItems.filter(':checked'));
} else {
enableItems($mediaItems);
// Update the selection.
const position = currentSelection.indexOf(id);
if (e.currentTarget.checked) {
// Check if the ID is not already in the selection and add if needed.
if (position === -1) {
currentSelection.push(id);
}
});
} else if (position !== -1) {
// Remove the ID when it is in the current selection.
currentSelection.splice(position, 1);
}
// Set the selection in the hidden form element.
$form
.find('#media-library-modal-selection')
.val(currentSelection.join())
.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.
$('.js-media-library-add-form-current-selection').val(
currentSelection.join(),
);
// Update the number of selected items in the button pane.
updateSelectionInfo(settings.media_library.selection_remaining);
// Prevent users from selecting more items than allowed.
if (
currentSelection.length === settings.media_library.selection_remaining
) {
disableItems($mediaItems.not(':checked'));
enableItems($mediaItems.filter(':checked'));
} else {
enableItems($mediaItems);
}
});
// Apply the current selection to the media library view. Changing the
// checkbox values triggers the change event for the media items. The
......
......@@ -136,7 +136,7 @@
Drupal.behaviors.MediaLibraryItemSelection = {
attach: function attach(context, settings) {
var $form = $('.js-media-library-views-form', context);
var $form = $('.js-media-library-views-form, .js-media-library-add-form', context);
var currentSelection = Drupal.MediaLibrary.currentSelection;
if (!$form.length) {
......@@ -145,21 +145,6 @@
var $mediaItems = $('.js-media-library-item input[type="checkbox"]', $form);
$mediaItems.once('media-item-change').on('change', function (e) {
var id = e.currentTarget.value;
var position = currentSelection.indexOf(id);
if (e.currentTarget.checked) {
if (position === -1) {
currentSelection.push(id);
}
} else if (position !== -1) {
currentSelection.splice(position, 1);
}
$form.find('#media-library-modal-selection').val(currentSelection.join()).trigger('change');
});
function disableItems($items) {
$items.prop('disabled', true).closest('.js-media-library-item').addClass('media-library-item--disabled');
}
......@@ -183,7 +168,22 @@
}
}
$('#media-library-modal-selection', $form).once('media-library-selection-change').on('change', function (e) {
$mediaItems.once('media-item-change').on('change', function (e) {
var id = e.currentTarget.value;
var position = currentSelection.indexOf(id);
if (e.currentTarget.checked) {
if (position === -1) {
currentSelection.push(id);
}
} else if (position !== -1) {
currentSelection.splice(position, 1);
}
$form.find('#media-library-modal-selection').val(currentSelection.join()).trigger('change');
$('.js-media-library-add-form-current-selection').val(currentSelection.join());
updateSelectionInfo(settings.media_library.selection_remaining);
if (currentSelection.length === settings.media_library.selection_remaining) {
......
......@@ -2,46 +2,6 @@
* @file media_library.view.es6.js
*/
(($, Drupal) => {
/**
* Adds hover effect to media items.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches behavior to add a class when hovering over media items.
*/
Drupal.behaviors.MediaLibraryHover = {
attach(context) {
$('.js-click-to-select-trigger, .js-click-to-select-checkbox', context)
.once('media-library-item-hover')
.on('mouseover mouseout', ({ currentTarget, type }) => {
$(currentTarget)
.closest('.js-media-library-item')
.toggleClass('is-hover', type === 'mouseover');
});
},
};
/**
* Adds focus effect to media items.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches behavior to add a focus effect to media items.
*/
Drupal.behaviors.MediaLibraryFocus = {
attach(context) {
$('.js-click-to-select-checkbox input', context)
.once('media-library-item-focus')
.on('focus blur', ({ currentTarget, type }) => {
$(currentTarget)
.closest('.js-media-library-item')
.toggleClass('is-focus', type === 'focus');
});
},
};
/**
* Adds checkbox to select all items in the library.
*
......
......@@ -6,34 +6,12 @@
**/
(function ($, Drupal) {
Drupal.behaviors.MediaLibraryHover = {
attach: function attach(context) {
$('.js-click-to-select-trigger, .js-click-to-select-checkbox', context).once('media-library-item-hover').on('mouseover mouseout', function (_ref) {
var currentTarget = _ref.currentTarget,
type = _ref.type;
$(currentTarget).closest('.js-media-library-item').toggleClass('is-hover', type === 'mouseover');
});
}
};
Drupal.behaviors.MediaLibraryFocus = {
attach: function attach(context) {
$('.js-click-to-select-checkbox input', context).once('media-library-item-focus').on('focus blur', function (_ref2) {
var currentTarget = _ref2.currentTarget,
type = _ref2.type;
$(currentTarget).closest('.js-media-library-item').toggleClass('is-focus', type === 'focus');
});
}
};
Drupal.behaviors.MediaLibrarySelectAll = {
attach: function attach(context) {
var $view = $('.js-media-library-view', context).once('media-library-select-all');
if ($view.length && $view.find('.js-media-library-item').length) {
var $checkbox = $('<input type="checkbox" class="form-checkbox" />').on('click', function (_ref3) {
var currentTarget = _ref3.currentTarget;
var $checkbox = $('<input type="checkbox" class="form-checkbox" />').on('click', function (_ref) {
var currentTarget = _ref.currentTarget;
var $checkboxes = $(currentTarget).closest('.media-library-view').find('.js-media-library-item input[type="checkbox"]');
$checkboxes.prop('checked', $(currentTarget).prop('checked')).trigger('change');
......
......@@ -3,6 +3,7 @@
namespace Drupal\media_library\Form;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\CloseDialogCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
......@@ -15,6 +16,7 @@
use Drupal\media\MediaTypeInterface;
use Drupal\media_library\Ajax\UpdateSelectionCommand;
use Drupal\media_library\MediaLibraryUiBuilder;
use Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
......@@ -48,6 +50,13 @@ abstract class AddFormBase extends FormBase {
*/
protected $mediaType;
/**
* The media view builder.
*
* @var \Drupal\Core\Entity\EntityViewBuilderInterface
*/
protected $viewBuilder;
/**
* Constructs a AddFormBase object.
*
......@@ -59,6 +68,7 @@ abstract class AddFormBase extends FormBase {
public function __construct(EntityTypeManagerInterface $entity_type_manager, MediaLibraryUiBuilder $library_ui_builder) {
$this->entityTypeManager = $entity_type_manager;
$this->libraryUiBuilder = $library_ui_builder;
$this->viewBuilder = $this->entityTypeManager->getViewBuilder('media');
}
/**
......@@ -131,8 +141,12 @@ public function buildForm(array $form, FormStateInterface $form_state) {
'#type' => 'status_messages',
];
$form['#attributes']['class'][] = 'media-library-add-form';
$added_media = $form_state->get('media');
$form['#attributes']['class'] = [
'media-library-add-form',
'js-media-library-add-form',
];
$added_media = $this->getAddedMediaItems($form_state);
if (empty($added_media)) {
$form['#attributes']['class'][] = 'media-library-add-form--without-input';
$form = $this->buildInputElement($form, $form_state);
......@@ -157,12 +171,39 @@ public function buildForm(array $form, FormStateInterface $form_state) {
],
];
$form['media']['description'] = [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => $this->formatPlural(count($added_media), 'The media item has been created but has not yet been saved. Fill in any required fields and save to add it to the media library.', 'The media items have been created but have not yet been saved. Fill in any required fields and save to add them to the media library.'),
'#attributes' => [
'class' => [
'media-library-add-form__description',
],
],
];
foreach ($added_media as $delta => $media) {
$form['media'][$delta] = $this->buildEntityFormElement($media, $form, $form_state, $delta);
}
$form['selection'] = $this->buildCurrentSelectionArea($form, $form_state);
$form['actions'] = $this->buildActions($form, $form_state);
}
// Allow the current selection to be set in a hidden field so the selection
// can be passed between different states of the form. This field is filled
// via JavaScript so the default value should be empty.
// @see Drupal.behaviors.MediaLibraryItemSelection
$form['current_selection'] = [
'#type' => 'hidden',
'#default_value' => '',
'#attributes' => [
'class' => [
'js-media-library-add-form-current-selection',
],
],
];
return $form;
}
......@@ -309,6 +350,90 @@ protected function buildEntityFormElement(MediaInterface $media, array $form, Fo
return $element;
}
/**
* Returns a render array containing the current selection.
*
* @param array $form
* The complete form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current form state.
*
* @return array
* A render array containing the current selection.
*/
protected function buildCurrentSelectionArea(array $form, FormStateInterface $form_state) {
$pre_selected_items = $this->getPreSelectedMediaItems($form_state);
if (!$pre_selected_items) {
return [];
}
$selection = [
'#type' => 'details',
'#open' => FALSE,
'#title' => $this->t('Additional selected media'),
'#attributes' => [
'class' => [
'media-library-add-form__selected-media',
],
],
];
foreach ($pre_selected_items as $media_id => $media) {
$selection[$media_id] = $this->buildSelectedItemElement($media, $form, $form_state);
}
return $selection;
}
/**
* Returns a render array for a single pre-selected media item.
*
* @param \Drupal\media\MediaInterface $media
* The media item.
* @param array $form
* The complete form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current form state.
*
* @return array
* A render array of a pre-selected media item.
*/
protected function buildSelectedItemElement(MediaInterface $media, array $form, FormStateInterface $form_state) {
return [
'#type' => 'container',
'#attributes' => [
'class' => [
'media-library-item',
'media-library-item--grid',
'media-library-item--small',
'js-media-library-item',
'js-click-to-select',
],