[TASK] Migrate LayoutModule/DragDrop.js to TypeScript 81/56281/8
authorAndreas Wolf <dev@a-w.io>
Sat, 17 Mar 2018 10:01:47 +0000 (11:01 +0100)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Fri, 6 Jul 2018 15:24:06 +0000 (17:24 +0200)
Change-Id: If29efc14acf4155ac820dfbd966fd7cdc8003fe2
Resolves: #84168
Releases: master
Reviewed-on: https://review.typo3.org/56281
Reviewed-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: Andreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Build/types/TYPO3/index.d.ts
typo3/sysext/backend/Resources/Private/TypeScript/AjaxDataHandler.ts
typo3/sysext/backend/Resources/Private/TypeScript/LayoutModule/DragDrop.ts [new file with mode: 0644]
typo3/sysext/backend/Resources/Public/JavaScript/AjaxDataHandler.js
typo3/sysext/backend/Resources/Public/JavaScript/LayoutModule/DragDrop.js

index 186f208..81b9faa 100644 (file)
@@ -95,3 +95,4 @@ interface JQuery {
   // To be able to use jquery/autocomplete-slider we have to override the definition of jquerui
   autocomplete(options?: { [key: string]: any }): any;
 }
   // To be able to use jquery/autocomplete-slider we have to override the definition of jquerui
   autocomplete(options?: { [key: string]: any }): any;
 }
+
diff --git a/typo3/sysext/backend/Resources/Private/TypeScript/LayoutModule/DragDrop.ts b/typo3/sysext/backend/Resources/Private/TypeScript/LayoutModule/DragDrop.ts
new file mode 100644 (file)
index 0000000..7e83c4b
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * 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!
+ */
+
+/**
+ * Module: TYPO3/CMS/Backend/LayoutModule/DragDrop
+ * this JS code does the drag+drop logic for the Layout module (Web => Page)
+ * based on jQuery UI
+ */
+import * as $ from 'jquery';
+import 'jquery-ui/droppable';
+import DataHandler from 'TYPO3/CMS/Backend/AjaxDataHandler';
+import ResponseInterface from 'TYPO3/CMS/Backend/AjaxDataHandler/ResponseInterface';
+
+
+interface Parameters {
+  cmd?: { tt_content: { [key: string]: any } };
+  data?: { tt_content: { [key: string]: any } };
+  CB?: { paste: string, update: { colPos: number | boolean, sys_language_uid: number }};
+}
+
+interface DroppableEventUIParam {
+    draggable: JQuery;
+    helper: JQuery;
+    position: { top: number; left: number; };
+    offset: { top: number; left: number; };
+}
+
+class DragDrop {
+
+  private static readonly contentIdentifier: string = '.t3js-page-ce';
+  private static readonly dragIdentifier: string = '.t3-page-ce-dragitem';
+  private static readonly dragHeaderIdentifier: string = '.t3js-page-ce-draghandle';
+  private static readonly dropZoneIdentifier: string = '.t3js-page-ce-dropzone-available';
+  private static readonly columnIdentifier: string = '.t3js-page-column';
+  private static readonly validDropZoneClass: string = 'active';
+  private static readonly dropPossibleHoverClass: string = 't3-page-ce-dropzone-possible';
+  private static readonly addContentIdentifier: string = '.t3js-page-new-ce';
+  private static originalStyles: string = '';
+
+  /**
+   * initializes Drag+Drop for all content elements on the page
+   */
+  public static initialize(): void {
+    $(DragDrop.contentIdentifier).draggable({
+      handle: DragDrop.dragHeaderIdentifier,
+      scope: 'tt_content',
+      cursor: 'move',
+      distance: 20,
+      // removed because of incompatible types:
+      // addClasses: 'active-drag',
+      revert: 'invalid',
+      zIndex: 100,
+      start: (evt: JQueryEventObject, ui: DroppableEventUIParam): void => {
+        DragDrop.onDragStart($(evt.target));
+      },
+      stop: (evt: JQueryEventObject, ui: DroppableEventUIParam): void => {
+        DragDrop.onDragStop($(evt.target));
+      }
+    });
+
+    $(DragDrop.dropZoneIdentifier).droppable({
+      accept: this.contentIdentifier,
+      scope: 'tt_content',
+      tolerance: 'pointer',
+      over: (evt: JQueryEventObject, ui: DroppableEventUIParam): void => {
+        DragDrop.onDropHoverOver($(ui.draggable), $(evt.target));
+      },
+      out: (evt: JQueryEventObject, ui: DroppableEventUIParam): void => {
+        DragDrop.onDropHoverOut($(ui.draggable), $(evt.target));
+      },
+      drop: (evt: JQueryEventObject, ui: DroppableEventUIParam): void => {
+        DragDrop.onDrop($(ui.draggable), $(evt.target), evt);
+      }
+    });
+  }
+
+  /**
+   * called when a draggable is selected to be moved
+   * @param $element a jQuery object for the draggable
+   * @private
+   */
+  public static onDragStart($element: JQuery): void {
+    // Add css class for the drag shadow
+    DragDrop.originalStyles = $element.get(0).style.cssText;
+    $element.children(DragDrop.dragIdentifier).addClass('dragitem-shadow');
+    $element.append('<div class="ui-draggable-copy-message">' + TYPO3.lang['dragdrop.copy.message'] + '</div>');
+    // Hide create new element button
+    $element.children(DragDrop.dropZoneIdentifier).addClass('drag-start');
+    $element.closest(DragDrop.columnIdentifier).removeClass('active');
+
+    // TODO decide what to do with this
+    // $element.parents(DragDrop.columnHolderIdentifier).find(DragDrop.addContentIdentifier).hide();
+    $element.find(DragDrop.dropZoneIdentifier).hide();
+
+    $(DragDrop.dropZoneIdentifier).each((index: number, element: HTMLElement): void => {
+      const $me = $(element);
+      if ($me.parent().find('.t3js-toggle-new-content-element-wizard').length) {
+        $me.addClass(DragDrop.validDropZoneClass);
+      } else {
+        $me.closest(DragDrop.contentIdentifier)
+          .find('> ' + DragDrop.addContentIdentifier + ', > > ' + DragDrop.addContentIdentifier).show();
+      }
+    });
+  }
+
+  /**
+   * called when a draggable is released
+   * @param $element a jQuery object for the draggable
+   * @private
+   */
+  public static onDragStop($element: JQuery): void {
+    // 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');
+    // TODO decide what to do with this
+    // $element.parents(DragDrop.columnHolderIdentifier).find(DragDrop.addContentIdentifier).show();
+    $element.find(DragDrop.dropZoneIdentifier).show();
+    $element.find('.ui-draggable-copy-message').remove();
+
+    // Reset inline style
+    $element.get(0).style.cssText = DragDrop.originalStyles;
+
+    $(DragDrop.dropZoneIdentifier + '.' + DragDrop.validDropZoneClass).removeClass(DragDrop.validDropZoneClass);
+  }
+
+  /**
+   * adds CSS classes when hovering over a dropzone
+   * @param $draggableElement
+   * @param $droppableElement
+   * @private
+   */
+  public static onDropHoverOver($draggableElement: JQuery, $droppableElement: JQuery): void {
+    if ($droppableElement.hasClass(DragDrop.validDropZoneClass)) {
+      $droppableElement.addClass(DragDrop.dropPossibleHoverClass);
+    }
+  }
+
+  /**
+   * removes the CSS classes after hovering out of a dropzone again
+   * @param $draggableElement
+   * @param $droppableElement
+   * @private
+   */
+  public static onDropHoverOut($draggableElement: JQuery, $droppableElement: JQuery): void {
+    $droppableElement.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
+   * @param {Event} evt the event
+   * @private
+   */
+  public static onDrop($draggableElement: number | JQuery, $droppableElement: JQuery, evt: JQueryEventObject): void {
+    const newColumn = DragDrop.getColumnPositionForElement($droppableElement);
+
+    $droppableElement.removeClass(DragDrop.dropPossibleHoverClass);
+    const $pasteAction = typeof $draggableElement === 'number';
+
+    // send an AJAX requst via the AjaxDataHandler
+    const contentElementUid: number = $pasteAction === true ?
+      <number>$draggableElement :
+      parseInt((<JQuery>$draggableElement).data('uid'), 10);
+
+    if (typeof(contentElementUid) === 'number' && contentElementUid > 0) {
+      let parameters: Parameters = {};
+      // add the information about a possible column position change
+      const targetFound = $droppableElement.closest(DragDrop.contentIdentifier).data('uid');
+      // the item was moved to the top of the colPos, so the page ID is used here
+      let targetPid = 0;
+
+      if (typeof targetFound === 'undefined') {
+        // the actual page is needed
+        targetPid = $('[data-page]').first().data('page');
+      } else {
+        // the negative value of the content element after where it should be moved
+        targetPid = 0 - parseInt(targetFound, 10);
+      }
+
+      const language = parseInt($droppableElement.closest('[data-language-uid]').data('language-uid'), 10);
+      let colPos: number | boolean = 0;
+      if (targetPid !== 0) {
+        colPos = newColumn;
+      }
+      parameters.cmd = {tt_content: {}};
+      parameters.data = {tt_content: {}};
+
+      const copyAction = (evt && (<JQueryInputEventObject>evt.originalEvent).ctrlKey || $droppableElement.hasClass('t3js-paste-copy'));
+      if (copyAction) {
+        parameters.cmd.tt_content[contentElementUid] = {
+          copy: {
+            action: 'paste',
+            target: targetPid,
+            update: {
+              colPos: colPos,
+              sys_language_uid: language
+            }
+          }
+        };
+        // TODO Make sure we actually have a JQuery object here, not only cast it
+        DragDrop.ajaxAction($droppableElement, <JQuery>$draggableElement, parameters, copyAction, $pasteAction);
+      } else {
+        parameters.data.tt_content[contentElementUid] = {
+          colPos: colPos,
+          sys_language_uid: language
+        };
+        if ($pasteAction) {
+          parameters = {
+            CB: {
+              paste: 'tt_content|' + targetPid,
+              update: {
+                colPos: colPos,
+                sys_language_uid: language
+              }
+            }
+          };
+        } else {
+          parameters.cmd.tt_content[contentElementUid] = {move: targetPid};
+        }
+        // fire the request, and show a message if it has failed
+        DragDrop.ajaxAction($droppableElement, <JQuery>$draggableElement, parameters, copyAction, $pasteAction);
+      }
+    }
+  }
+
+  /**
+   * this method does the actual AJAX request for both, the move and the copy action.
+   *
+   * @param $droppableElement
+   * @param $draggableElement
+   * @param parameters
+   * @param $copyAction
+   * @param $pasteAction
+   * @private
+   */
+  public static ajaxAction($droppableElement: JQuery, $draggableElement: JQuery, parameters: Parameters,
+                           $copyAction: boolean, $pasteAction: boolean): void {
+    DataHandler.process(parameters).done(function(result: ResponseInterface): void {
+      if (result.hasErrors) {
+        return;
+      }
+
+      // insert draggable on the new position
+      if (!$pasteAction) {
+        if (!$droppableElement.parent().hasClass(DragDrop.contentIdentifier.substring(1))) {
+          $draggableElement.detach().css({top: 0, left: 0})
+            .insertAfter($droppableElement.closest(DragDrop.dropZoneIdentifier));
+        } else {
+          $draggableElement.detach().css({top: 0, left: 0})
+            .insertAfter($droppableElement.closest(DragDrop.contentIdentifier));
+        }
+      }
+      self.location.reload(true);
+    });
+  }
+
+  /**
+   * returns the next "upper" container colPos parameter inside the code
+   * @param $element
+   * @return int|null the colPos
+   */
+  public static getColumnPositionForElement($element: JQuery): number | boolean {
+    const $columnContainer = $element.closest('[data-colpos]');
+    if ($columnContainer.length && $columnContainer.data('colpos') !== 'undefined') {
+      return $columnContainer.data('colpos');
+    } else {
+      return false;
+    }
+  }
+}
+
+export default DragDrop;
+
+$(DragDrop.initialize);
index 0c2b510..10d40a8 100644 (file)
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
  *
  * The TYPO3 project - inspiring people to share!
  */
-define(["require","exports","./Enum/Severity","jquery","./Icons","./Modal","./Notification","./Viewport"],function(e,t,n,a,i,o,r,s){"use strict";var l,d;return(d=l||(l={})).hide=".t3js-record-hide",d.delete=".t3js-record-delete",d.icon=".t3js-icon",new(function(){function e(){var e=this;a(function(){e.initialize()})}return e.refreshPageTree=function(){s.NavigationContainer&&s.NavigationContainer.PageTree&&s.NavigationContainer.PageTree.refreshTree()},e.prototype.process=function(e){var t=this;return this._call(e).done(function(e){e.hasErrors&&t.handleErrors(e)})},e.prototype.initialize=function(){var e=this;a(document).on("click",l.hide,function(t){t.preventDefault();var n=a(t.currentTarget),i=n.find(l.icon),o=n.closest("tr[data-uid]"),r=n.data("params");e._showSpinnerIcon(i),e._call(r).done(function(t){t.hasErrors?e.handleErrors(t):e.toggleRow(o)})}),a(document).on("click",l.delete,function(t){t.preventDefault();var i=a(t.currentTarget);o.confirm(i.data("title"),i.data("message"),n.SeverityEnum.warning,[{text:i.data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:i.data("button-ok-text")||TYPO3.lang["button.delete"]||"Delete",btnClass:"btn-warning",name:"delete"}]).on("button.clicked",function(t){"cancel"===t.target.getAttribute("name")?o.dismiss():"delete"===t.target.getAttribute("name")&&(o.dismiss(),e.deleteRecord(i))})})},e.prototype.toggleRow=function(t){var n,o,r,s=t.find(l.hide),d=s.closest("table[data-table]").data("table"),c=s.data("params");"hidden"===s.data("state")?(o="visible",n=c.replace("=0","=1"),r="actions-edit-hide"):(o="hidden",n=c.replace("=1","=0"),r="actions-edit-unhide"),s.data("state",o).data("params",n),s.tooltip("hide").one("hidden.bs.tooltip",function(){var e=s.data("toggleTitle");s.data("toggleTitle",s.attr("data-original-title")).attr("data-original-title",e).tooltip("show")});var f=s.find(l.icon);i.getIcon(r,i.sizes.small).done(function(e){f.replaceWith(e)});var u=t.find(".col-icon "+l.icon);"hidden"===o?i.getIcon("miscellaneous-placeholder",i.sizes.small,"overlay-hidden").done(function(e){u.append(a(e).find(".icon-overlay"))}):u.find(".icon-overlay").remove(),t.fadeTo("fast",.4,function(){t.fadeTo("fast",1)}),"pages"===d&&e.refreshPageTree()},e.prototype.deleteRecord=function(t){var n=this,a=t.data("params"),o=t.find(l.icon);this._showSpinnerIcon(o),this._call(a).done(function(a){if(i.getIcon("actions-edit-delete",i.sizes.small).done(function(e){(o=t.find(l.icon)).replaceWith(e)}),a.hasErrors)n.handleErrors(a);else{var r=t.closest("table[data-table]"),s=t.closest(".panel"),d=s.find(".panel-heading"),c=r.data("table"),f=t.closest("tr[data-uid]"),u=f.data("uid"),p=r.find("[data-l10nparent="+u+"]").closest("tr[data-uid]");if((f=f.add(p)).fadeTo("slow",.4,function(){f.slideUp("slow",function(){f.remove(),0===r.find("tbody tr").length&&s.slideUp("slow")})}),"0"===t.data("l10parent")||""===t.data("l10parent")){var h=Number(d.find(".t3js-table-total-items").html());d.find(".t3js-table-total-items").text(h-1)}"pages"===c&&e.refreshPageTree()}})},e.prototype.handleErrors=function(e){a.each(e.messages,function(e,t){r.error(t.title,t.message)})},e.prototype._call=function(e){return a.getJSON(TYPO3.settings.ajaxUrls.record_process,e)},e.prototype._showSpinnerIcon=function(e){i.getIcon("spinner-circle-dark",i.sizes.small).done(function(t){e.replaceWith(t)})},e}())});
\ No newline at end of file
+define(["require","exports","./Enum/Severity","jquery","./Icons","./Modal","./Notification","./Viewport"],function(e,t,a,n,i,o,r,l){"use strict";var d,s;Object.defineProperty(t,"__esModule",{value:!0}),(s=d||(d={})).hide=".t3js-record-hide",s.delete=".t3js-record-delete",s.icon=".t3js-icon";var c=function(){function e(){var e=this;n(function(){e.initialize()})}return e.refreshPageTree=function(){l.NavigationContainer&&l.NavigationContainer.PageTree&&l.NavigationContainer.PageTree.refreshTree()},e.prototype.process=function(e){var t=this;return this._call(e).done(function(e){e.hasErrors&&t.handleErrors(e)})},e.prototype.initialize=function(){var e=this;n(document).on("click",d.hide,function(t){t.preventDefault();var a=n(t.currentTarget),i=a.find(d.icon),o=a.closest("tr[data-uid]"),r=a.data("params");e._showSpinnerIcon(i),e._call(r).done(function(t){t.hasErrors?e.handleErrors(t):e.toggleRow(o)})}),n(document).on("click",d.delete,function(t){t.preventDefault();var i=n(t.currentTarget);o.confirm(i.data("title"),i.data("message"),a.SeverityEnum.warning,[{text:i.data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:i.data("button-ok-text")||TYPO3.lang["button.delete"]||"Delete",btnClass:"btn-warning",name:"delete"}]).on("button.clicked",function(t){"cancel"===t.target.getAttribute("name")?o.dismiss():"delete"===t.target.getAttribute("name")&&(o.dismiss(),e.deleteRecord(i))})})},e.prototype.toggleRow=function(t){var a,o,r,l=t.find(d.hide),s=l.closest("table[data-table]").data("table"),c=l.data("params");"hidden"===l.data("state")?(o="visible",a=c.replace("=0","=1"),r="actions-edit-hide"):(o="hidden",a=c.replace("=1","=0"),r="actions-edit-unhide"),l.data("state",o).data("params",a),l.tooltip("hide").one("hidden.bs.tooltip",function(){var e=l.data("toggleTitle");l.data("toggleTitle",l.attr("data-original-title")).attr("data-original-title",e).tooltip("show")});var f=l.find(d.icon);i.getIcon(r,i.sizes.small).done(function(e){f.replaceWith(e)});var u=t.find(".col-icon "+d.icon);"hidden"===o?i.getIcon("miscellaneous-placeholder",i.sizes.small,"overlay-hidden").done(function(e){u.append(n(e).find(".icon-overlay"))}):u.find(".icon-overlay").remove(),t.fadeTo("fast",.4,function(){t.fadeTo("fast",1)}),"pages"===s&&e.refreshPageTree()},e.prototype.deleteRecord=function(t){var a=this,n=t.data("params"),o=t.find(d.icon);this._showSpinnerIcon(o),this._call(n).done(function(n){if(i.getIcon("actions-edit-delete",i.sizes.small).done(function(e){(o=t.find(d.icon)).replaceWith(e)}),n.hasErrors)a.handleErrors(n);else{var r=t.closest("table[data-table]"),l=t.closest(".panel"),s=l.find(".panel-heading"),c=r.data("table"),f=t.closest("tr[data-uid]"),u=f.data("uid"),p=r.find("[data-l10nparent="+u+"]").closest("tr[data-uid]");if((f=f.add(p)).fadeTo("slow",.4,function(){f.slideUp("slow",function(){f.remove(),0===r.find("tbody tr").length&&l.slideUp("slow")})}),"0"===t.data("l10parent")||""===t.data("l10parent")){var h=Number(s.find(".t3js-table-total-items").html());s.find(".t3js-table-total-items").text(h-1)}"pages"===c&&e.refreshPageTree()}})},e.prototype.handleErrors=function(e){n.each(e.messages,function(e,t){r.error(t.title,t.message)})},e.prototype._call=function(e){return n.getJSON(TYPO3.settings.ajaxUrls.record_process,e)},e.prototype._showSpinnerIcon=function(e){i.getIcon("spinner-circle-dark",i.sizes.small).done(function(t){e.replaceWith(t)})},e}();t.default=new c});
\ No newline at end of file
index a055956..95c97e2 100644 (file)
  *
  * The TYPO3 project - inspiring people to share!
  */
  *
  * The TYPO3 project - inspiring people to share!
  */
-
-/**
- * Module: TYPO3/CMS/Backend/LayoutModule/DragDrop
- * this JS code does the drag+drop logic for the Layout module (Web => Page)
- * based on jQuery UI
- */
-define(['jquery', 'jquery-ui/droppable'], function($) {
-  'use strict';
-
-  /**
-   *
-   * @type {{contentIdentifier: string, dragIdentifier: string, dragHeaderIdentifier: string, dropZoneIdentifier: string, columnIdentifier: string, validDropZoneClass: string, dropPossibleHoverClass: string, addContentIdentifier: string, originalStyles: string}}
-   * @exports TYPO3/CMS/Backend/LayoutModule/DragDrop
-   */
-  var DragDrop = {
-    contentIdentifier: '.t3js-page-ce',
-    dragIdentifier: '.t3-page-ce-dragitem',
-    dragHeaderIdentifier: '.t3js-page-ce-draghandle',
-    dropZoneIdentifier: '.t3js-page-ce-dropzone-available',
-    columnIdentifier: '.t3js-page-column',
-    validDropZoneClass: 'active',
-    dropPossibleHoverClass: 't3-page-ce-dropzone-possible',
-    addContentIdentifier: '.t3js-page-new-ce',
-    clone: true,
-    originalStyles: ''
-  };
-
-  /**
-   * initializes Drag+Drop for all content elements on the page
-   */
-  DragDrop.initialize = function() {
-    $(DragDrop.contentIdentifier).draggable({
-      handle: DragDrop.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));
-      }
-    });
-
-    $(DragDrop.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), evt);
-      }
-    });
-  };
-
-  /**
-   * 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
-    DragDrop.originalStyles = $element.get(0).style.cssText;
-    $element.children(DragDrop.dragIdentifier).addClass('dragitem-shadow');
-    $element.append('<div class="ui-draggable-copy-message">' + TYPO3.lang['dragdrop.copy.message'] + '</div>');
-    // Hide create new element button
-    $element.children(DragDrop.dropZoneIdentifier).addClass('drag-start');
-    $element.closest(DragDrop.columnIdentifier).removeClass('active');
-
-    $element.parents(DragDrop.columnHolderIdentifier).find(DragDrop.addContentIdentifier).hide();
-    $element.find(DragDrop.dropZoneIdentifier).hide();
-
-    $(DragDrop.dropZoneIdentifier).each(function() {
-      var $me = $(this);
-      if ($me.parent().find('.t3js-toggle-new-content-element-wizard').length) {
-        $me.addClass(DragDrop.validDropZoneClass);
-      } else {
-        $me.closest(DragDrop.contentIdentifier).find('> ' + DragDrop.addContentIdentifier + ', > > ' + DragDrop.addContentIdentifier).show();
-      }
-    });
-  };
-
-  /**
-   * 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');
-    $element.parents(DragDrop.columnHolderIdentifier).find(DragDrop.addContentIdentifier).show();
-    $element.find(DragDrop.dropZoneIdentifier).show();
-    $element.find('.ui-draggable-copy-message').remove();
-
-    // Reset inline style
-    $element.get(0).style.cssText = DragDrop.originalStyles;
-
-    $(DragDrop.dropZoneIdentifier + '.' + 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);
-    }
-  };
-
-  /**
-   * 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);
-  };
-
-  /**
-   * 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
-   * @param {Event} evt the event
-   * @private
-   */
-  DragDrop.onDrop = function($draggableElement, $droppableElement, evt) {
-    var newColumn = DragDrop.getColumnPositionForElement($droppableElement);
-
-    $droppableElement.removeClass(DragDrop.dropPossibleHoverClass);
-    var $pasteAction = typeof $draggableElement === 'number';
-
-    // send an AJAX requst via the AjaxDataHandler
-    var contentElementUid = $pasteAction ? $draggableElement : parseInt($draggableElement.data('uid'));
-    if (contentElementUid > 0) {
-      var parameters = {};
-      // add the information about a possible column position change
-      var targetFound = $droppableElement.closest(DragDrop.contentIdentifier).data('uid');
-      // the item was moved to the top of the colPos, so the page ID is used here
-      var targetPid = 0;
-      if (typeof targetFound === 'undefined') {
-        // the actual page is needed
-        targetPid = $('[data-page]').first().data('page');
-      } else {
-        // the negative value of the content element after where it should be moved
-        targetPid = 0 - parseInt(targetFound);
-      }
-      var language = parseInt($droppableElement.closest('[data-language-uid]').data('language-uid'));
-      var colPos = 0;
-      if (targetPid !== 0) {
-        colPos = newColumn;
-      }
-      parameters['cmd'] = {tt_content: {}};
-      parameters['data'] = {tt_content: {}};
-      var copyAction = (evt && evt.originalEvent.ctrlKey || $droppableElement.hasClass('t3js-paste-copy'));
-      if (copyAction) {
-        parameters['cmd']['tt_content'][contentElementUid] = {
-          copy: {
-            action: 'paste',
-            target: targetPid,
-            update: {
-              colPos: colPos,
-              sys_language_uid: language
-            }
-          }
-        };
-        DragDrop.ajaxAction($droppableElement, $draggableElement, parameters, copyAction, $pasteAction);
-      } else {
-        parameters['data']['tt_content'][contentElementUid] = {
-          colPos: colPos,
-          sys_language_uid: language
-        };
-        if ($pasteAction) {
-          parameters = {
-            CB: {
-              paste: 'tt_content|' + targetPid,
-              update: {
-                colPos: colPos,
-                sys_language_uid: language
-              }
-            }
-          };
-        } else {
-          parameters['cmd']['tt_content'][contentElementUid] = {move: targetPid};
-        }
-        // fire the request, and show a message if it has failed
-        DragDrop.ajaxAction($droppableElement, $draggableElement, parameters, copyAction, $pasteAction);
-      }
-    }
-  };
-
-  /**
-   * this method does the actual AJAX request for both, the move and the copy action.
-   *
-   * @param $droppableElement
-   * @param $draggableElement
-   * @param parameters
-   * @param $copyAction
-   * @param $pasteAction
-   * @private
-   */
-  DragDrop.ajaxAction = function($droppableElement, $draggableElement, parameters, $copyAction, $pasteAction) {
-    require(['TYPO3/CMS/Backend/AjaxDataHandler'], function(DataHandler) {
-      DataHandler.process(parameters).done(function(result) {
-        if (!result.hasErrors) {
-          // insert draggable on the new position
-          if (!$pasteAction) {
-            if (!$droppableElement.parent().hasClass(DragDrop.contentIdentifier.substring(1))) {
-              $draggableElement.detach().css({top: 0, left: 0})
-                .insertAfter($droppableElement.closest(DragDrop.dropZoneIdentifier));
-            } else {
-              $draggableElement.detach().css({top: 0, left: 0})
-                .insertAfter($droppableElement.closest(DragDrop.contentIdentifier));
-            }
-          }
-          self.location.reload(true);
-        }
-      });
-    });
-  };
-
-  /**
-   * 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('[data-colpos]');
-    if ($columnContainer.length && $columnContainer.data('colpos') !== 'undefined') {
-      return $columnContainer.data('colpos');
-    } else {
-      return false;
-    }
-  };
-
-  $(DragDrop.initialize);
-  return DragDrop;
-});
+define(["require","exports","jquery","TYPO3/CMS/Backend/AjaxDataHandler","jquery-ui/droppable"],function(e,t,n,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var o=function(){function e(){}return e.initialize=function(){n(e.contentIdentifier).draggable({handle:e.dragHeaderIdentifier,scope:"tt_content",cursor:"move",distance:20,revert:"invalid",zIndex:100,start:function(t,a){e.onDragStart(n(t.target))},stop:function(t,a){e.onDragStop(n(t.target))}}),n(e.dropZoneIdentifier).droppable({accept:this.contentIdentifier,scope:"tt_content",tolerance:"pointer",over:function(t,a){e.onDropHoverOver(n(a.draggable),n(t.target))},out:function(t,a){e.onDropHoverOut(n(a.draggable),n(t.target))},drop:function(t,a){e.onDrop(n(a.draggable),n(t.target),t)}})},e.onDragStart=function(t){e.originalStyles=t.get(0).style.cssText,t.children(e.dragIdentifier).addClass("dragitem-shadow"),t.append('<div class="ui-draggable-copy-message">'+TYPO3.lang["dragdrop.copy.message"]+"</div>"),t.children(e.dropZoneIdentifier).addClass("drag-start"),t.closest(e.columnIdentifier).removeClass("active"),t.find(e.dropZoneIdentifier).hide(),n(e.dropZoneIdentifier).each(function(t,a){var o=n(a);o.parent().find(".t3js-toggle-new-content-element-wizard").length?o.addClass(e.validDropZoneClass):o.closest(e.contentIdentifier).find("> "+e.addContentIdentifier+", > > "+e.addContentIdentifier).show()})},e.onDragStop=function(t){t.children(e.dragIdentifier).removeClass("dragitem-shadow"),t.children(e.dropZoneIdentifier).removeClass("drag-start"),t.closest(e.columnIdentifier).addClass("active"),t.find(e.dropZoneIdentifier).show(),t.find(".ui-draggable-copy-message").remove(),t.get(0).style.cssText=e.originalStyles,n(e.dropZoneIdentifier+"."+e.validDropZoneClass).removeClass(e.validDropZoneClass)},e.onDropHoverOver=function(t,n){n.hasClass(e.validDropZoneClass)&&n.addClass(e.dropPossibleHoverClass)},e.onDropHoverOut=function(t,n){n.removeClass(e.dropPossibleHoverClass)},e.onDrop=function(t,a,o){var r=e.getColumnPositionForElement(a);a.removeClass(e.dropPossibleHoverClass);var i="number"==typeof t,s=!0===i?t:parseInt(t.data("uid"),10);if("number"==typeof s&&s>0){var d={},l=a.closest(e.contentIdentifier).data("uid"),c=0;c=void 0===l?n("[data-page]").first().data("page"):0-parseInt(l,10);var p=parseInt(a.closest("[data-language-uid]").data("language-uid"),10),g=0;0!==c&&(g=r),d.cmd={tt_content:{}},d.data={tt_content:{}};var f=o&&o.originalEvent.ctrlKey||a.hasClass("t3js-paste-copy");f?(d.cmd.tt_content[s]={copy:{action:"paste",target:c,update:{colPos:g,sys_language_uid:p}}},e.ajaxAction(a,t,d,f,i)):(d.data.tt_content[s]={colPos:g,sys_language_uid:p},i?d={CB:{paste:"tt_content|"+c,update:{colPos:g,sys_language_uid:p}}}:d.cmd.tt_content[s]={move:c},e.ajaxAction(a,t,d,f,i))}},e.ajaxAction=function(t,n,o,r,i){a.default.process(o).done(function(a){a.hasErrors||(i||(t.parent().hasClass(e.contentIdentifier.substring(1))?n.detach().css({top:0,left:0}).insertAfter(t.closest(e.contentIdentifier)):n.detach().css({top:0,left:0}).insertAfter(t.closest(e.dropZoneIdentifier))),self.location.reload(!0))})},e.getColumnPositionForElement=function(e){var t=e.closest("[data-colpos]");return!(!t.length||"undefined"===t.data("colpos"))&&t.data("colpos")},e.contentIdentifier=".t3js-page-ce",e.dragIdentifier=".t3-page-ce-dragitem",e.dragHeaderIdentifier=".t3js-page-ce-draghandle",e.dropZoneIdentifier=".t3js-page-ce-dropzone-available",e.columnIdentifier=".t3js-page-column",e.validDropZoneClass="active",e.dropPossibleHoverClass="t3-page-ce-dropzone-possible",e.addContentIdentifier=".t3js-page-new-ce",e.originalStyles="",e}();t.default=o,n(o.initialize)});
\ No newline at end of file