From 08bff25830cad61489bdfe796a1be6944beb1ad1 Mon Sep 17 00:00:00 2001 From: Mladen Todorovic Date: Mon, 31 Oct 2016 11:44:59 +0100 Subject: [PATCH 1/4] Added support of auto select functionality --- .../js/dropzonejs_eb_widget.common.js | 30 +++++++ .../Widget/DropzoneJsEbWidget.php | 86 ++++++++++++++++++- .../Widget/MediaEntityDropzoneJsEbWidget.php | 9 +- 3 files changed, 116 insertions(+), 9 deletions(-) diff --git a/modules/eb_widget/js/dropzonejs_eb_widget.common.js b/modules/eb_widget/js/dropzonejs_eb_widget.common.js index 39c12b0..39d537d 100644 --- a/modules/eb_widget/js/dropzonejs_eb_widget.common.js +++ b/modules/eb_widget/js/dropzonejs_eb_widget.common.js @@ -29,7 +29,37 @@ if (item.instance.getRejectedFiles().length == 0) { $submit.removeAttr("disabled"); } + + // If there are no files in DropZone -> disable Button. + if (item.instance.getAcceptedFiles().length === 0) { + $submit.prop("disabled", true); + } }); + + if (drupalSettings.dropzonejs.auto_select) { + item.instance.on("queuecomplete", function () { + var dzInstance = item.instance; + var filesInQueue = dzInstance.getQueuedFiles(); + var i, rejectedFiles; + + if (filesInQueue.length === 0) { + // Remove filed files. + rejectedFiles = dzInstance.getRejectedFiles(); + for (i = 0; i < rejectedFiles.length; i++) { + dzInstance.removeFile(rejectedFiles[i]); + } + + // Ensure that there are some files that should be submitted. + if (dzInstance.getAcceptedFiles().length > 0 && dzInstance.getUploadingFiles().length === 0) { + jQuery(dzInstance.element) + .parent() + .siblings('[name="auto_select_handler"]') + .trigger('auto_select_enity_browser_widget'); + } + } + }); + } + } }); } diff --git a/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php b/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php index 3c622c7..0d80ac0 100644 --- a/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php +++ b/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php @@ -4,6 +4,8 @@ use Drupal\Component\Utility\Bytes; use Drupal\Component\Utility\NestedArray; +use Drupal\Core\Ajax\AjaxResponse; +use Drupal\Core\Ajax\InvokeCommand; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Session\AccountProxyInterface; @@ -20,7 +22,8 @@ * @EntityBrowserWidget( * id = "dropzonejs", * label = @Translation("DropzoneJS"), - * description = @Translation("Adds DropzoneJS upload integration.") + * description = @Translation("Adds DropzoneJS upload integration."), + * autoSelect = TRUE * ) */ class DropzoneJsEbWidget extends WidgetBase { @@ -138,6 +141,27 @@ public function getForm(array &$original_form, FormStateInterface $form_state, a $form['#attached']['library'][] = 'dropzonejs_eb_widget/common'; $original_form['#attributes']['class'][] = 'dropzonejs-disable-submit'; + // Add hidden element used to make execution of auto-select of form. + if ($this->configuration['auto_select']) { + $form['auto_select_handler'] = [ + '#type' => 'hidden', + '#name' => 'auto_select_handler', + '#id' => 'auto_select_handler', + '#attributes' => ['id' => 'auto_select_handler'], + '#submit' => ['::submitForm'], + '#executes_submit_callback' => TRUE, + '#ajax' => [ + 'callback' => [get_class($this), 'handleAjaxCommand'], + 'event' => 'auto_select_enity_browser_widget', + 'progress' => [ + 'type' => 'fullscreen', + ], + ], + ]; + + $form['#attached']['drupalSettings']['dropzonejs']['auto_select'] = $this->configuration['auto_select']; + } + return $form; } @@ -245,9 +269,21 @@ public function submit(array &$element, array &$form, FormStateInterface $form_s $files[] = $file; } - if (!empty(array_filter($files))) { - $this->selectEntities($files, $form_state); - $this->clearFormValues($element, $form_state); + $this->selectEntities($files, $form_state); + $this->clearFormValues($element, $form_state); + } + + /** + * {@inheritdoc} + */ + protected function selectEntities(array $entities, FormStateInterface $form_state) { + if (!empty(array_filter($entities))) { + if ($this->configuration['auto_select']) { + $form_state->set('added_entities', $entities); + } + else { + parent::selectEntities($entities, $form_state); + } } } @@ -367,4 +403,46 @@ public function __sleep() { return array_diff(parent::__sleep(), ['files']); } + /** + * Handling of automated submit of uploaded files. + * + * @param array $form + * Form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * Form state. + * + * @return \Drupal\Core\Ajax\AjaxResponse + * Returns ajax commands that will be executed in front-end. + */ + public static function handleAjaxCommand(array $form, FormStateInterface $form_state) { + $ajax = new AjaxResponse(); + + if (($triggering_element = $form_state->getTriggeringElement()) && $triggering_element['#name'] === 'auto_select_handler') { + $entity_ids = []; + + $added_entities = $form_state->get('added_entities'); + /** @var \Drupal\Core\Entity\EntityInterface $entity */ + foreach ($added_entities as $entity) { + $entity_ids[] = $entity->getEntityTypeId() . ':' . $entity->id(); + } + $form_state->unsetValue('added_entities'); + + // Add command to clear list of uploaded files. It's important to set + // empty string value, in other case it will act as getter. + $ajax->addCommand( + new InvokeCommand('[data-drupal-selector="edit-upload-uploaded-files"]', 'val', ['']) + ); + + // Add Invoke command to select uploaded entities. + $ajax->addCommand( + new InvokeCommand('.entities-list', 'trigger', [ + 'load-entities', + [$entity_ids], + ]) + ); + } + + return $ajax; + } + } diff --git a/modules/eb_widget/src/Plugin/EntityBrowser/Widget/MediaEntityDropzoneJsEbWidget.php b/modules/eb_widget/src/Plugin/EntityBrowser/Widget/MediaEntityDropzoneJsEbWidget.php index 58428e6..297159d 100644 --- a/modules/eb_widget/src/Plugin/EntityBrowser/Widget/MediaEntityDropzoneJsEbWidget.php +++ b/modules/eb_widget/src/Plugin/EntityBrowser/Widget/MediaEntityDropzoneJsEbWidget.php @@ -24,7 +24,8 @@ * @EntityBrowserWidget( * id = "dropzonejs_media_entity", * label = @Translation("Media Entity DropzoneJS"), - * description = @Translation("Adds DropzoneJS upload integration that saves Media entities.") + * description = @Translation("Adds DropzoneJS upload integration that saves Media entities."), + * autoSelect = TRUE * ) */ class MediaEntityDropzoneJsEbWidget extends DropzoneJsEbWidget { @@ -190,10 +191,8 @@ public function submit(array &$element, array &$form, FormStateInterface $form_s $media_entity->save(); } - if (!empty(array_filter($media_entities))) { - $this->selectEntities($media_entities, $form_state); - $this->clearFormValues($element, $form_state); - } + $this->selectEntities($media_entities, $form_state); + $this->clearFormValues($element, $form_state); } } From b5114717b419e49c396429dd67111052b8a4dd54 Mon Sep 17 00:00:00 2001 From: Mladen Todorovic Date: Sun, 6 Nov 2016 21:24:15 +0100 Subject: [PATCH 2/4] Adjusted code to correspond to entity browser changes --- modules/eb_widget/js/dropzonejs_eb_widget.common.js | 2 +- .../Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/eb_widget/js/dropzonejs_eb_widget.common.js b/modules/eb_widget/js/dropzonejs_eb_widget.common.js index 39d537d..45a3014 100644 --- a/modules/eb_widget/js/dropzonejs_eb_widget.common.js +++ b/modules/eb_widget/js/dropzonejs_eb_widget.common.js @@ -36,7 +36,7 @@ } }); - if (drupalSettings.dropzonejs.auto_select) { + if (drupalSettings.entity_browser_widget.auto_select) { item.instance.on("queuecomplete", function () { var dzInstance = item.instance; var filesInQueue = dzInstance.getQueuedFiles(); diff --git a/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php b/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php index 0d80ac0..e5aa198 100644 --- a/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php +++ b/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php @@ -142,7 +142,7 @@ public function getForm(array &$original_form, FormStateInterface $form_state, a $original_form['#attributes']['class'][] = 'dropzonejs-disable-submit'; // Add hidden element used to make execution of auto-select of form. - if ($this->configuration['auto_select']) { + if ($config['settings']['auto_select']) { $form['auto_select_handler'] = [ '#type' => 'hidden', '#name' => 'auto_select_handler', @@ -158,8 +158,6 @@ public function getForm(array &$original_form, FormStateInterface $form_state, a ], ], ]; - - $form['#attached']['drupalSettings']['dropzonejs']['auto_select'] = $this->configuration['auto_select']; } return $form; @@ -278,7 +276,9 @@ public function submit(array &$element, array &$form, FormStateInterface $form_s */ protected function selectEntities(array $entities, FormStateInterface $form_state) { if (!empty(array_filter($entities))) { - if ($this->configuration['auto_select']) { + $config = $this->getConfiguration(); + + if ($config['settings']['auto_select']) { $form_state->set('added_entities', $entities); } else { @@ -436,7 +436,7 @@ public static function handleAjaxCommand(array $form, FormStateInterface $form_s // Add Invoke command to select uploaded entities. $ajax->addCommand( new InvokeCommand('.entities-list', 'trigger', [ - 'load-entities', + 'add-entities', [$entity_ids], ]) ); From d19089c1bbb4b9057b819686217f22c3406369f4 Mon Sep 17 00:00:00 2001 From: Mladen Todorovic Date: Tue, 8 Nov 2016 12:11:31 +0100 Subject: [PATCH 3/4] Adjusted schema and new widget for auto_select functionality --- .../config/schema/dropzonejs_eb_widget.schema.yml | 9 +++++++++ .../EntityBrowser/Widget/InlineEntityFormMediaWidget.php | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/eb_widget/config/schema/dropzonejs_eb_widget.schema.yml b/modules/eb_widget/config/schema/dropzonejs_eb_widget.schema.yml index 72213db..3eb28cc 100644 --- a/modules/eb_widget/config/schema/dropzonejs_eb_widget.schema.yml +++ b/modules/eb_widget/config/schema/dropzonejs_eb_widget.schema.yml @@ -5,6 +5,9 @@ entity_browser.browser.widget.dropzonejs: submit_text: type: string label: 'Submit button text' + auto_select: + type: boolean + label: 'Automatically submit selection' upload_location: type: string label: 'Upload location' @@ -28,6 +31,9 @@ entity_browser.browser.widget.dropzonejs_media_entity: submit_text: type: string label: 'Submit button text' + auto_select: + type: boolean + label: 'Automatically submit selection' upload_location: type: string label: 'Upload location' @@ -51,6 +57,9 @@ entity_browser.browser.widget.dropzonejs_media_entity_inline_entity_form: submit_text: type: string label: 'Submit button text' + auto_select: + type: boolean + label: 'Automatically submit selection' upload_location: type: string label: 'Upload location' diff --git a/modules/eb_widget/src/Plugin/EntityBrowser/Widget/InlineEntityFormMediaWidget.php b/modules/eb_widget/src/Plugin/EntityBrowser/Widget/InlineEntityFormMediaWidget.php index 631d314..7272dbc 100644 --- a/modules/eb_widget/src/Plugin/EntityBrowser/Widget/InlineEntityFormMediaWidget.php +++ b/modules/eb_widget/src/Plugin/EntityBrowser/Widget/InlineEntityFormMediaWidget.php @@ -16,7 +16,8 @@ * @EntityBrowserWidget( * id = "dropzonejs_media_entity_inline_entity_form", * label = @Translation("Media Entity DropzoneJS with edit"), - * description = @Translation("Adds DropzoneJS upload integration that saves Media entities and allows to edit them.") + * description = @Translation("Adds DropzoneJS upload integration that saves Media entities and allows to edit them."), + * autoSelect = FALSE * ) */ class InlineEntityFormMediaWidget extends MediaEntityDropzoneJsEbWidget { From 16598329f9dd51eeb3b33fe1a9a83e88f06c14a2 Mon Sep 17 00:00:00 2001 From: Mladen Todorovic Date: Fri, 11 Nov 2016 15:31:50 +0100 Subject: [PATCH 4/4] Added functionality to submit only accepted files and keep rejected in list --- js/dropzone.integration.js | 13 ++++++++++++ .../js/dropzonejs_eb_widget.common.js | 20 +++++++++++-------- .../Widget/DropzoneJsEbWidget.php | 16 +++++++-------- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/js/dropzone.integration.js b/js/dropzone.integration.js index e81800f..ee5b0c1 100644 --- a/js/dropzone.integration.js +++ b/js/dropzone.integration.js @@ -14,6 +14,8 @@ Drupal.behaviors.dropzonejsIntegraion = { attach: function (context) { Dropzone.autoDiscover = false; + + // TODO: init functionality should support multiple drop zones on page var selector = $(".dropzone-enable"); selector.addClass("dropzone"); var input = selector.siblings('input'); @@ -24,9 +26,20 @@ addRemoveLinks: false }; var instanceConfig = drupalSettings.dropzonejs.instances[selector.attr('id')]; + + // if DropzoneJS instance is already registered on Element. There is no + // need to register it again. + if (selector.once('register-dropzonejs').length !== selector.length) { + return; + } + + // If instance exists for configuration, but it's detached from element + // then destroy detached instance and create new instance. if (instanceConfig.instance !== undefined) { instanceConfig.instance.destroy(); } + + // Initialize DropzoneJS instance for element. var dropzoneInstance = new Dropzone("#" + selector.attr("id"), $.extend({}, instanceConfig, config)); // Other modules might need instances. diff --git a/modules/eb_widget/js/dropzonejs_eb_widget.common.js b/modules/eb_widget/js/dropzonejs_eb_widget.common.js index 45a3014..943d831 100644 --- a/modules/eb_widget/js/dropzonejs_eb_widget.common.js +++ b/modules/eb_widget/js/dropzonejs_eb_widget.common.js @@ -37,24 +37,28 @@ }); if (drupalSettings.entity_browser_widget.auto_select) { - item.instance.on("queuecomplete", function () { + item.instance.on('queuecomplete', function () { var dzInstance = item.instance; var filesInQueue = dzInstance.getQueuedFiles(); - var i, rejectedFiles; + var acceptedFiles; + var i; if (filesInQueue.length === 0) { - // Remove filed files. - rejectedFiles = dzInstance.getRejectedFiles(); - for (i = 0; i < rejectedFiles.length; i++) { - dzInstance.removeFile(rejectedFiles[i]); - } + acceptedFiles = dzInstance.getAcceptedFiles(); // Ensure that there are some files that should be submitted. - if (dzInstance.getAcceptedFiles().length > 0 && dzInstance.getUploadingFiles().length === 0) { + if (acceptedFiles.length > 0 && dzInstance.getUploadingFiles().length === 0) { + // First submit accepted files and clear them from list of + // dropped files afterwards. jQuery(dzInstance.element) .parent() .siblings('[name="auto_select_handler"]') .trigger('auto_select_enity_browser_widget'); + + // Remove accepted files -> because they are submitted. + for (i = 0; i < acceptedFiles.length; i++) { + dzInstance.removeFile(acceptedFiles[i]); + } } } }); diff --git a/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php b/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php index e5aa198..ec9b84f 100644 --- a/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php +++ b/modules/eb_widget/src/Plugin/EntityBrowser/Widget/DropzoneJsEbWidget.php @@ -278,13 +278,12 @@ protected function selectEntities(array $entities, FormStateInterface $form_stat if (!empty(array_filter($entities))) { $config = $this->getConfiguration(); - if ($config['settings']['auto_select']) { - $form_state->set('added_entities', $entities); - } - else { + if (!$config['settings']['auto_select']) { parent::selectEntities($entities, $form_state); } } + + $form_state->set(['dropzonejs', 'added_entities'], $entities); } /** @@ -420,12 +419,13 @@ public static function handleAjaxCommand(array $form, FormStateInterface $form_s if (($triggering_element = $form_state->getTriggeringElement()) && $triggering_element['#name'] === 'auto_select_handler') { $entity_ids = []; - $added_entities = $form_state->get('added_entities'); + $added_entities = $form_state->get(['dropzonejs', 'added_entities']); /** @var \Drupal\Core\Entity\EntityInterface $entity */ - foreach ($added_entities as $entity) { - $entity_ids[] = $entity->getEntityTypeId() . ':' . $entity->id(); + if (!empty($added_entities)) { + foreach ($added_entities as $entity) { + $entity_ids[] = $entity->getEntityTypeId() . ':' . $entity->id(); + } } - $form_state->unsetValue('added_entities'); // Add command to clear list of uploaded files. It's important to set // empty string value, in other case it will act as getter.