[TASK] Use jQuery UI for Drag&Drop in Page Module 07/35807/7
authorBenjamin Mack <benni@typo3.org>
Mon, 5 Jan 2015 23:54:46 +0000 (00:54 +0100)
committerBenjamin Mack <benni@typo3.org>
Thu, 29 Jan 2015 09:00:27 +0000 (10:00 +0100)
In the process to move away from ExtJS
and fixing some open problems, the JS
code for the drag+drop functionality in the
page module is rewritten based on jQuery UI.

In addition to having a RequireJS module,
the new JS-based DataHandler AJAX call
is used. Also, a content element is only
moved in the HTML code, if the AJAX result
is true. Scrolling works as well, which resolves
the existing problem from forge ticket #50576.

Resolves: #50576
Resolves: #64221
Releases: master
Change-Id: I19cdbf4820d16606125ec908cc7fe4d34df415da
Reviewed-on: http://review.typo3.org/35807
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Mathias Schreiber <mathias.schreiber@wmdb.de>
Tested-by: Mathias Schreiber <mathias.schreiber@wmdb.de>
Reviewed-by: Benjamin Mack <benni@typo3.org>
Tested-by: Benjamin Mack <benni@typo3.org>
typo3/sysext/backend/Classes/View/PageLayout/Extdirect/ExtdirectPageCommands.php
typo3/sysext/backend/Classes/View/PageLayoutView.php
typo3/sysext/backend/Resources/Public/JavaScript/AjaxDataHandler.js
typo3/sysext/backend/Resources/Public/JavaScript/LayoutModule/DragDrop.js [new file with mode: 0644]
typo3/sysext/cms/layout/js/typo3pageModule.js [deleted file]
typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/visual/_module_web_page.less
typo3/sysext/t3skin/Resources/Public/Css/visual/t3skin.css

index 299e1f9..27f479c 100644 (file)
@@ -21,6 +21,8 @@ use TYPO3\CMS\Core\Utility\MathUtility;
  * Commands for the Page module
  *
  * @author Jigal van Hemert <jigal.van.hemert@typo3.org>
+ * @deprecated since TYPO3 CMS 7, this file will be removed in TYPO3 CMS 8, as Drag&Drop does this
+ * logic now directly and calls DataHandler via AJAX directly.
  */
 class ExtdirectPageCommands {
 
@@ -33,8 +35,10 @@ class ExtdirectPageCommands {
         * @param string $destinationColumn Column to move the content element to
         * @param int $destinationElement Id attribute of the element it was dropped on
         * @return array
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
         */
        public function moveContentElement($sourceElement, $destinationColumn, $destinationElement) {
+               GeneralUtility::logDeprecatedFunction();
                $moveElementUid = 0;
                $afterElementUid = -1;
                $targetColumn = 0;
index ee8f047..1ba3d3c 100644 (file)
@@ -402,8 +402,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                $pageTitleParamForAltDoc = '&recTitle=' . rawurlencode(BackendUtility::getRecordTitle('pages', BackendUtility::getRecordWSOL('pages', $id), TRUE));
                /** @var $pageRenderer \TYPO3\CMS\Core\Page\PageRenderer */
                $pageRenderer = $this->getPageLayoutController()->doc->getPageRenderer();
-               $pageRenderer->loadExtJs();
-               $pageRenderer->addJsFile($GLOBALS['BACK_PATH'] . 'sysext/cms/layout/js/typo3pageModule.js');
+               $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/DragDrop');
                // Get labels for CTypes and tt_content element fields in general:
                $this->CType_labels = array();
                foreach ($GLOBALS['TCA']['tt_content']['columns']['CType']['config']['items'] as $val) {
@@ -459,7 +458,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                        $content[$key] .= '">';
                                        // Add new content at the top most position
                                        $content[$key] .= '
-                                       <div class="t3-page-ce" id="' . str_replace('.', '', uniqid('', TRUE)) . '">
+                                       <div class="t3-page-ce" data-page="' . (int)$id . '" id="' . str_replace('.', '', uniqid('', TRUE)) . '">
                                                <div class="t3-page-ce-dropzone" id="colpos-' . $key . '-' . 'page-' . $id . '-' . uniqid('', TRUE) . '">
                                                        <div class="t3-page-ce-wrapper-new-ce">
                                                                <a href="#" onclick="' . htmlspecialchars($this->newContentElementOnClick($id, $key, $lP))
@@ -509,7 +508,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                        $singleElementHTML .= '</div>';
                                                        $statusHidden = $this->isDisabled('tt_content', $row) ? ' t3-page-ce-hidden' : '';
                                                        $singleElementHTML = '<div class="t3-page-ce' . $statusHidden . '" id="element-tt_content-'
-                                                               . $row['uid'] . '">' . $singleElementHTML . '</div>';
+                                                               . $row['uid'] . '" data-table="tt_content" data-uid="' . $row['uid'] . '">' . $singleElementHTML . '</div>';
                                                        if ($this->tt_contentConfig['languageMode']) {
                                                                $singleElementHTML .= '<div class="t3-page-ce">';
                                                        }
@@ -611,7 +610,7 @@ class PageLayoutView extends \TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRe
                                                        $grid .= '<td valign="top"' .
                                                                ($colSpan > 0 ? ' colspan="' . $colSpan . '"' : '') .
                                                                ($rowSpan > 0 ? ' rowspan="' . $rowSpan . '"' : '') .
-                                                               ' class="t3-gridCell t3-page-column t3-page-column-' . $columnKey .
+                                                               ' data-colpos="' . (int)$columnConfig['colPos'] . '" class="t3-gridCell t3-page-column t3-page-column-' . $columnKey .
                                                                ((!isset($columnConfig['colPos']) || $columnConfig['colPos'] === '') ? ' t3-gridCell-unassigned' : '') .
                                                                ((isset($columnConfig['colPos']) && $columnConfig['colPos'] !== '' && !$head[$columnKey]) || !GeneralUtility::inList($this->tt_contentConfig['activeCols'], $columnConfig['colPos']) ? ' t3-gridCell-restricted' : '') .
                                                                ($colSpan > 0 ? ' t3-gridCell-width' . $colSpan : '') .
index e3e0beb..1fcacd9 100644 (file)
 define('TYPO3/CMS/Backend/AjaxDataHandler', ['jquery', 'TYPO3/CMS/Backend/FlashMessages', 'TYPO3/CMS/Backend/Modal'], function ($) {
        var AjaxDataHandler = {};
 
+       /**
+        * generic function to call from the outside the script and validate directly showing errors
+        * @param parameters
+        * @return a jQuery deferred object (promise)
+        */
+       AjaxDataHandler.process = function(parameters) {
+               return AjaxDataHandler._call(parameters).done(function(result) {
+                       if (result.hasErrors) {
+                               AjaxDataHandler.handleErrors(result);
+                       }
+               });
+       };
+
        AjaxDataHandler.initialize = function() {
 
                // HIDE/UNHIDE: click events for all action icons to hide/unhide
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/LayoutModule/DragDrop.js b/typo3/sysext/backend/Resources/Public/JavaScript/LayoutModule/DragDrop.js
new file mode 100644 (file)
index 0000000..915468e
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * this JS code does the drag+drop logic for the Layout module (Web => Page)
+ * based on jQuery UI
+ */
+define(['jquery', 'jquery-ui/draggable', 'jquery-ui/droppable'], function ($) {
+
+       var DragDrop = {
+               contentIdentifier: '.t3-page-ce',
+               dragIdentifier: '.t3-page-ce-dragitem',
+               dragHeaderIdentifier: '.t3-page-ce-header',
+               dropZoneIdentifier: '.t3-page-ce-dropzone',
+               columnIdentifier: '.t3-page-column',
+               validDropZoneClass: 't3-page-ce-dropzone-available',
+               dropPossibleHoverClass: 't3-page-ce-drop-possible'
+       };
+
+       /**
+        * initializes Drag+Drop for all content elements on the page
+        */
+       DragDrop.initialize = function() {
+               $(this.contentIdentifier).draggable({
+                       handle: this.dragHeaderIdentifier,
+                       scope: 'tt_content',
+                       cursor: 'move',
+                       distance: 20,
+                       addClasses: 'active-drag',
+                       revert: 'invalid',
+                       zIndex: 100,
+                       start: function(evt, ui) {
+                               DragDrop.onDragStart($(this));
+                       },
+                       stop: function(evt, ui) {
+                               DragDrop.onDragStop($(this));
+                       }
+               });
+
+               $(this.dropZoneIdentifier).droppable({
+                       accept: this.contentIdentifier,
+                       scope: 'tt_content',
+                       tolerance: 'pointer',
+                       over: function(evt, ui) {
+                               DragDrop.onDropHoverOver($(ui.draggable), $(this));
+                       },
+                       out: function(evt, ui) {
+                               DragDrop.onDropHoverOut($(ui.draggable), $(this));
+                       },
+                       drop: function(evt, ui) {
+                               DragDrop.onDrop($(ui.draggable), $(this));
+                       }
+               });
+       };
+
+       /**
+        * called when a draggable is selected to be moved
+        * @param $element a jQuery object for the draggable
+        * @private
+        */
+       DragDrop.onDragStart = function($element) {
+               // Add css class for the drag shadow
+               $element.children(DragDrop.dragIdentifier).addClass('dragitem-shadow');
+               // Hide create new element button
+               $element.children(DragDrop.dropZoneIdentifier).addClass('drag-start');
+               $element.closest(DragDrop.columnIdentifier).removeClass('active');
+
+               // make the dropzones visible (all except the previous one in the current list)
+               var $previousDropZone = $element.prev().children(DragDrop.dropZoneIdentifier);
+               $(DragDrop.dropZoneIdentifier).not($previousDropZone).addClass(DragDrop.validDropZoneClass);
+       };
+
+       /**
+        * called when a draggable is released
+        * @param $element a jQuery object for the draggable
+        * @private
+        */
+       DragDrop.onDragStop = function($element) {
+               // Remove css class for the drag shadow
+               $element.children(DragDrop.dragIdentifier).removeClass('dragitem-shadow');
+               // Show create new element button
+               $element.children(DragDrop.dropZoneIdentifier).removeClass('drag-start');
+               $element.closest(DragDrop.columnIdentifier).addClass('active');
+               $('.' + DragDrop.validDropZoneClass).removeClass(DragDrop.validDropZoneClass);
+       };
+
+       /**
+        * adds CSS classes when hovering over a dropzone
+        * @param $draggableElement
+        * @param $droppableElement
+        * @private
+        */
+       DragDrop.onDropHoverOver = function($draggableElement, $droppableElement) {
+               if ($droppableElement.hasClass(DragDrop.validDropZoneClass)) {
+                       $droppableElement.addClass(DragDrop.dropPossibleHoverClass);
+                       $draggableElement.addClass(DragDrop.dropPossibleHoverClass);
+               }
+       };
+
+       /**
+        * removes the CSS classes after hovering out of a dropzone again
+        * @param $draggableElement
+        * @param $droppableElement
+        * @private
+        */
+       DragDrop.onDropHoverOut = function($draggableElement, $droppableElement) {
+               $droppableElement.removeClass(DragDrop.dropPossibleHoverClass);
+               $draggableElement.removeClass(DragDrop.dropPossibleHoverClass);
+       };
+
+       /**
+        * this method does the whole logic when a draggable is dropped on to a dropzone
+        * sending out the request and afterwards move the HTML element in the right place.
+        *
+        * @param $draggableElement
+        * @param $droppableElement
+        * @private
+        */
+       DragDrop.onDrop = function($draggableElement, $droppableElement) {
+               var oldColumn = DragDrop.getColumnPositionForElement($draggableElement),
+                       newColumn = DragDrop.getColumnPositionForElement($droppableElement);
+
+               $droppableElement.removeClass(DragDrop.dropPossibleHoverClass);
+               $draggableElement.removeClass(DragDrop.dropPossibleHoverClass);
+
+               // send an AJAX requst via the AjaxDataHandler
+               var contentElementUid = parseInt($draggableElement.data('uid'));
+               if (contentElementUid > 0) {
+                       var parameters = {};
+                       // add the information about a possible column position change
+                       if (newColumn !== oldColumn) {
+                               parameters['data'] = {tt_content: {}};
+                               parameters['data']['tt_content'][contentElementUid] = {colPos: parseInt(newColumn)};
+                       }
+
+                       var targetContentElementUid = $droppableElement.closest(DragDrop.contentIdentifier).data('uid');
+                       // the item was moved to the top of the colPos, so the page ID is used here
+                       if (typeof targetContentElementUid === 'undefined') {
+                               // the actual page is needed
+                               targetContentElementUid = parseInt($droppableElement.closest(DragDrop.contentIdentifier).data('page'));
+                       } else {
+                               // the negative value of the content element after where it should be moved
+                               targetContentElementUid = 0-parseInt(targetContentElementUid);
+                       }
+
+                       parameters['cmd'] = {tt_content: {}};
+                       parameters['cmd']['tt_content'][contentElementUid] = {move: targetContentElementUid};
+                       // fire the request, and show a message if it has failed
+                       require(['TYPO3/CMS/Backend/AjaxDataHandler'], function(DataHandler) {
+                               DataHandler.process(parameters).done(function(result) {
+                                       if (!result.hasErrors) {
+                                               // insert draggable on the new position
+                                               $draggableElement.detach().css({top: 0, left: 0})
+                                                       .insertAfter($droppableElement.closest(DragDrop.contentIdentifier));
+                                       }
+                               });
+                       });
+               }
+       };
+
+       /**
+        * returns the next "upper" container colPos parameter inside the code
+        * @param $element
+        * @return int|null the colPos
+        */
+       DragDrop.getColumnPositionForElement = function($element) {
+               var $columnContainer = $element.closest(DragDrop.columnIdentifier);
+               if ($columnContainer.length && $columnContainer.data('colpos') !== 'undefined') {
+                       return $columnContainer.data('colpos');
+               } else {
+                       return null;
+               }
+       };
+
+       /**
+        * initialize function
+        */
+       return function() {
+               DragDrop.initialize();
+               return DragDrop;
+       }();
+});
\ No newline at end of file
diff --git a/typo3/sysext/cms/layout/js/typo3pageModule.js b/typo3/sysext/cms/layout/js/typo3pageModule.js
deleted file mode 100644 (file)
index ba659d2..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-Ext.ns('TYPO3', 'TYPO3.Components');
-
-TYPO3.Components.PageModule = {
-       /**
-        * Initialization
-        */
-       init: function() {
-               this.enableDragDrop();
-       },
-
-       /**
-        * This method configures the drag'n'drop behavior in the page module
-        */
-       enableDragDrop: function() {
-               var overrides = {
-                       // Called the instance the element is dragged.
-                       b4StartDrag: function () {
-                               // Cache the drag element
-                               if (!this.el) {
-                                       this.el = Ext.get(this.getEl());
-                               }
-
-                               // Add css class to define active state
-                               this.el.addClass('active-drag');
-
-                               // Add css class for the drag shadow
-                               if (this.el.child('.t3-icon-ce-dragitem')) {
-                                       this.el.child('.t3-page-ce-dragitem').addClass('dragitem-shadow');
-                               }
-
-                               // Hide create new element button
-                               if (this.el.child('.t3-icon-document-new')) {
-                                       this.el.child('.t3-icon-document-new').addClass('drag-start');
-                               }
-
-                               // Cache the original XY Coordinates of the element, we'll use this later.
-                               this.originalXY = this.el.getXY();
-
-                               // Hide create new element button
-                               this.el.findParent('td.t3-page-column', null, true).removeClass('active');
-
-                               var dropZones = Ext.select('.t3-page-ce-dropzone');
-                               var self = this;
-                               Ext.each(dropZones.elements, function(el) {
-                                       var dropZoneElement = Ext.get(el);
-                                       // Only highlight valid drop targets
-                                       if (dropZoneElement.id != self.el.prev().child('.t3-page-ce-dropzone').id &&
-                                       dropZoneElement.id != self.el.child('.t3-page-ce-dropzone').id) {
-                                               dropZoneElement.addClass('t3-page-ce-dropzone-available');
-                                       }
-                               });
-                       },
-                       // Called when element is dropped not anything other than a dropzone with the same ddgroup
-                       onInvalidDrop: function () {
-                               // Set a flag to invoke the animated repair
-                               this.invalidDrop = true;
-                       },
-                       // Called when the drag operation completes
-                       endDrag: function () {
-                               // Invoke the animation if the invalidDrop flag is set to true
-                               if (this.invalidDrop === true) {
-                                       // Remove the drop invitation
-                                       this.el.removeClass('dropOK');
-
-                                       // Create the animation configuration object
-                                       var animCfgObj = {
-                                               easing:'easeOut',
-                                               duration:0.3,
-                                               scope:this,
-                                               callback: function () {
-                                                       // Remove the position attribute
-                                                       this.el.dom.style.position = '';
-                                               }
-                                       };
-
-                                       // Apply the repair animation
-                                       this.el.moveTo(this.originalXY[0], this.originalXY[1], animCfgObj);
-                                       delete this.invalidDrop;
-                               }
-
-                               var dropZones = Ext.select('.t3-page-ce-dropzone');
-                               Ext.each(dropZones.elements, function(el) {
-                                       Ext.get(el).removeClass('t3-page-ce-dropzone-available');
-                               });
-
-                               // Remove css class to define inactive state
-                               this.el.removeClass('active-drag');
-                               // Remove dragitem-shadow after dragging
-                               if (this.el.child('.t3-page-ce-dragitem')) {
-                                       this.el.child('.t3-page-ce-dragitem').removeClass('dragitem-shadow');
-                               }
-                               // Show create new element button again
-                               if (this.el.child('.t3-icon-document-new')) {
-                                       this.el.child('.t3-icon-document-new').removeClass('drag-start');
-                               }
-                       },
-
-                       // Called upon successful drop of an element on a DDTarget with the same
-                       onDragDrop: function (evtObj, targetElId) {
-                               // Wrap the drop target element with Ext.Element
-                               var dropEl = Ext.get(targetElId);
-
-                               // Perform the node move only if not dropped on the dropzone directly above
-                               // this element
-                               if (this.el.prev().child('.t3-page-ce-dropzone').id != targetElId &&
-                                               targetElId != this.el.child('.t3-page-ce-dropzone').id) {
-
-                                       // Remove the drag invitation
-                                       this.onDragOut(evtObj, targetElId);
-
-                                       // Add height to drop zone
-                                       var oldHeight = dropEl.getHeight();
-                                       var elementNewY = dropEl.getY() + dropEl.getHeight();
-                                       dropEl.setHeight(dropEl.getHeight() + this.el.getHeight(), true);
-
-                                       // Create the animation configuration object
-                                       var animCfgObj = {
-                                               easing: 'easeOut',
-                                               duration: 0.3,
-                                               scope: this,
-                                               callback: function () {
-
-                                                       // restore dropzone height
-                                                       // animation is necessary to let it work.
-                                                       dropEl.setHeight(oldHeight, {duration: 0.1});
-
-                                                       // Move the element
-                                                       dropEl.parent().insertSibling(this.el, 'after');
-
-                                                       // Clear the styles
-                                                       this.el.dom.style.position = '';
-                                                       this.el.dom.style.top = '';
-                                                       this.el.dom.style.left = '';
-                                               }
-                                       };
-
-                                       // Animate to new position
-                                       this.el.moveTo(dropEl.getX(), elementNewY, animCfgObj);
-
-                                       // Show create new element button again
-                                       dropEl.findParent('td.t3-page-column', null, true).addClass('active');
-
-                                       // Try to save changes to the backend
-                                       // There is no feedback from the server side functions, just hope for the best
-                                       TYPO3.Components.DragAndDrop.CommandController.moveContentElement(
-                                               this.el.id,
-                                               targetElId,
-                                               dropEl.parent().id,
-                                               this
-                                       );
-
-                               } else {
-                                       // This was an invalid drop, initiate a repair
-                                       this.onInvalidDrop();
-                               }
-                       },
-                       // Only called when the drag element is dragged over the a drop target with the same ddgroup
-                       onDragEnter: function (evtObj, targetElId) {
-                               // Perform the node move only if not dropped on the dropzone directly above
-                               // this element
-                               if (targetElId != this.el.prev().child('.t3-page-ce-dropzone').id &&
-                                               targetElId != this.el.child('.t3-page-ce-dropzone').id) {
-                                       this.el.addClass('dropOK');
-                                       Ext.get(targetElId).addClass('dropReceiveOK');
-                               } else {
-                                       // Remove the invitation
-                                       this.onDragOut();
-                               }
-                       },
-                       // Only called when element is dragged out of a dropzone with the same ddgroup
-                       onDragOut: function (evtObj, targetElId) {
-                               this.el.removeClass('dropOK');
-                               if (targetElId) {
-                                       Ext.get(targetElId).removeClass('dropReceiveOK');
-                               }
-                       },
-
-                       /**
-                        * Evaluates a response from an ext direct call and shows a flash message
-                        * if it was an exceptional result
-                        *
-                        * @param {Object} response
-                        * @return {Boolean}
-                        */
-                       evaluateResponse: function (response) {
-                               if (response.success === false) {
-                                       top.TYPO3.Flashmessage.display(top.TYPO3.Severity.error, 'Exception', response.message);
-                                       return false;
-                               }
-
-                               return true;
-                       }
-               };
-
-               var contentElements = Ext.select('.t3-page-ce');
-               Ext.each(contentElements.elements, function (el) {
-                       if (Ext.DomQuery.is(el, 'div:has(.t3-page-ce-dragitem)')) {
-                               var dd = new Ext.dd.DD(el, 'ceDDgroup', {
-                                       isTarget : false
-                               });
-                               // Apply overrides to newly created instance
-                               Ext.apply(dd, overrides);
-                       }
-               });
-
-               // Find dropzones and add them to the group
-               var dropZones = Ext.select('.t3-page-ce-dropzone');
-               Ext.each(dropZones.elements, function(el) {
-                       var dropTarget = new Ext.dd.DDTarget(el, 'ceDDgroup');
-               });
-       }
-}
-
-Ext.onReady(function() {
-       TYPO3.Components.PageModule.init();
-});
\ No newline at end of file
index 4c331a2..c2939c7 100644 (file)
@@ -185,7 +185,11 @@ td.t3-gridCell-restricted div.t3-row-header div {
        visibility: visible;
 }
 
-.t3-page-ce-dropzone.t3-page-ce-dropzone-available.dropReceiveOK {
+.t3-page-ce-dropzone {
+       padding: 6px 0;
+}
+
+.t3-page-ce-dropzone.t3-page-ce-dropzone-available.t3-page-ce-drop-possible {
     background-color: #73ab61;
 }
 
@@ -193,7 +197,7 @@ td.t3-gridCell-restricted div.t3-row-header div {
        background-color: #c8d9c3;
 }
 
-.t3-page-ce-dragitem:hover {
+.t3-page-ce-dragitem .t3-page-ce-header:hover {
        cursor: move;
 }
 
index c963389..7a2c23a 100644 (file)
@@ -12385,13 +12385,16 @@ td.t3-gridCell-restricted div.t3-row-header div {
 .t3-page-ce:hover .t3-row-header .ce-icons-left {
   visibility: visible;
 }
-.t3-page-ce-dropzone.t3-page-ce-dropzone-available.dropReceiveOK {
+.t3-page-ce-dropzone {
+  padding: 6px 0;
+}
+.t3-page-ce-dropzone.t3-page-ce-dropzone-available.t3-page-ce-drop-possible {
   background-color: #73ab61;
 }
 .t3-page-ce-dropzone.t3-page-ce-dropzone-available {
   background-color: #c8d9c3;
 }
-.t3-page-ce-dragitem:hover {
+.t3-page-ce-dragitem .t3-page-ce-header:hover {
   cursor: move;
 }
 .t3-page-ce-dragitem.dragitem-shadow {