diff --git a/Resources/Public/JavaScript/paste-reference-drag-drop.js b/Resources/Public/JavaScript/paste-reference-drag-drop.js index a0b71145..5d779efc 100644 --- a/Resources/Public/JavaScript/paste-reference-drag-drop.js +++ b/Resources/Public/JavaScript/paste-reference-drag-drop.js @@ -126,10 +126,9 @@ DragDrop.default = { $(DragDrop.default.dropZoneIdentifier).not(DragDrop.default.ownDropZone).each(function () { $(this).addClass(DragDrop.default.validDropZoneClass); - if (($(this).not(disabledDropZones).length - || siblingsDropZones.length - ) && - $(this).parent().find('.icon-actions-add').length + if ( + ($(this).not(disabledDropZones).length || siblingsDropZones.length) + && $(this).parent().find('.icon-actions-add').length ) { $(this).addClass(DragDrop.default.validDropZoneClass); } else { @@ -173,6 +172,7 @@ DragDrop.default = { */ onDrop: function ($draggableElement, $droppableElement, evt, reference) { const newColumn = DragDrop.default.getColumnPositionForElement($droppableElement) ?? 0; + const containerParent = DragDrop.default.getContainerParentForElement($droppableElement) ?? 0; $droppableElement.removeClass(DragDrop.default.dropPossibleHoverClass); const $pasteAction = typeof $draggableElement === 'number' || typeof $draggableElement === 'undefined'; @@ -261,6 +261,9 @@ DragDrop.default = { if (evt === 'copyFromAnotherPage') { parameters['CB'] = {setCopyMode: 1}; } + if (containerParent) { + parameters['cmd']['tt_content'][contentElementUid]['copy']['update']['tx_container_parent'] = containerParent; + } // fire the request, and show a message if it has failed // This is adding a copy from another page "to this [selected] place". AjaxDataHandler.process(parameters).then(function (result) { @@ -290,6 +293,9 @@ DragDrop.default = { } } }; + if (containerParent) { + parameters['cmd']['tt_content'][contentElementUid]['move']['update']['tx_container_parent'] = containerParent; + } // fire the request, and show a message if it has failed AjaxDataHandler.process(parameters).then(function (result) { if (!result.hasErrors) { @@ -323,6 +329,20 @@ DragDrop.default = { } else { return false; } + }, + + /** + * returns the next "upper" container parent parameter inside the code + * @param $element + * @return int|boolean the containerParent + */ + getContainerParentForElement: function ($element) { + const $gridContainer = $element.closest('[data-tx-container-parent]'); + if ($gridContainer.length && $gridContainer.data('txContainerParent') !== 'undefined') { + return $gridContainer.data('txContainerParent'); + } else { + return false; + } } } diff --git a/Resources/Public/JavaScript/paste-reference.js b/Resources/Public/JavaScript/paste-reference.js index 4d199dc1..a53aaf9f 100644 --- a/Resources/Public/JavaScript/paste-reference.js +++ b/Resources/Public/JavaScript/paste-reference.js @@ -17,21 +17,31 @@ import Paste from "@typo3/backend/layout-module/paste.js"; import DragDrop from "@ehaerer/paste-reference/paste-reference-drag-drop.js"; import { MessageUtility } from "@typo3/backend/utility/message-utility.js"; -class OnReady { - openedPopupWindow = []; +/** + * Module: @ehaerer/paste-reference/paste-reference.js + */ + +'use strict'; + +/** + * @exports @ehaerer/paste-reference/paste-reference.js + */ +class PasteReference { + + static instanceCount = 0; + + // openedPopupWindow = []; + + constructor() { + PasteReference.instanceCount++; + this.activatePasteIcons(); + this.initModalEventListener(); + } /** - * generates the paste into / paste after modal + * gets Clipboard data by Ajax and adds them + * to the "top" variable */ - copyFromAnotherPage(element) { - const url = top.browserUrl + '&mode=db&bparams=' + element.parent().attr('id') + '|||tt_content|'; - const configurationIframe = { - type: Modal.types.iframe, - content: url, - size: Modal.sizes.large - }; - Modal.advanced(configurationIframe); - }; getClipboardData() { (new AjaxRequest(top.TYPO3.settings.Clipboard.moduleUrl)) .withQueryArguments({ action: 'getClipboardData' }) @@ -45,187 +55,223 @@ class OnReady { let table = identifier ? identifier.split('|')[0] : ''; let uid = identifier ? identifier.split('|')[1] : 0; let title = record ? record.title.replace(/<[^>]*>?/gm, '') : ''; - let clipboardData = { - copyMode: resolvedBody.data.copyMode, - data: record, - itemOnClipboardUid: uid * 1, - itemOnClipboardTitleHtml: record ? record.title : '', - itemOnClipboardTitle: title, - itemOnClipboardTable: table, - }; - top.itemOnClipboardUid = clipboardData.itemOnClipboardUid; - top.itemOnClipboardTitle = clipboardData.itemOnClipboardTitle; - top.itemOnClipboardTitleHtml = clipboardData.itemOnClipboardTitleHtml; - top.itemOnClipboardTable = clipboardData.itemOnClipboardTable; - return clipboardData; + + top.itemOnClipboardUid = uid * 1; + top.itemOnClipboardTitle = title; + top.itemOnClipboardTitleHtml = record ? record.title : ''; + top.itemOnClipboardTable = table; } - else return { - copyMode: '', - data: {}, - itemOnClipboardUid: 0, - itemOnClipboardTitleHtml: '', - itemOnClipboardTitle: '', - itemOnClipboardTable: '', - }; }); - }; - initClickEventListener($element) { - // Add modal, functionality of the modal itself is not done here, - // but rather in paste-reference-drag-drop and triggered by - // the custom EventListener 'message' (see downwards) - if ($element.find('button.t3js-paste-new').length) { - $element.find('button.t3js-paste-new').on('click', function (evt) { - evt.preventDefault(); - onReady.copyFromAnotherPage($element); - }); - } } -} -const onReady = new OnReady; -/** - * generates the paste into / paste after modal - */ -Paste.activatePasteModal = function (element) { - const $element = $(element); - const url = $element.data('url') || null; - const elementTitle = top.itemOnClipboardTitle != undefined ? top.itemOnClipboardTitle : "["+TYPO3.lang['tx_paste_reference_js.modal.labels.no_title']+"]"; - const title = (TYPO3.lang['paste.modal.title.paste'] || 'Paste record') + ': "' + elementTitle + '"'; - const severity = (typeof top.TYPO3.Severity[$element.data('severity')] !== 'undefined') ? top.TYPO3.Severity[$element.data('severity')] : top.TYPO3.Severity.info; - let buttons = []; - let content = ''; - - if ($element.hasClass('t3js-paste-copy')) { - content = TYPO3.lang['tx_paste_reference_js.modal.pastecopy'] || 'How do you want to paste that clipboard content here?'; - buttons = [ - { - text: TYPO3.lang['paste.modal.button.cancel'] || 'Cancel', - active: true, - btnClass: 'btn-default', - trigger: (evt, modal) => modal.hideModal(), - }, - { - text: TYPO3.lang['tx_paste_reference_js.modal.button.pastecopy'] || 'Paste as copy', - btnClass: 'text-white btn-' + top.TYPO3.Severity.getCssClass(severity), - trigger: function (evt, modal) { - modal.hideModal(); - DragDrop.default.onDrop(top.itemOnClipboardUid, $element, evt); - } - }, - { - text: TYPO3.lang['tx_paste_reference_js.modal.button.pastereference'] || 'Paste as reference', - btnClass: 'text-white btn-' + top.TYPO3.Severity.getCssClass(severity), - trigger: function (evt, modal) { - modal.hideModal(); - DragDrop.default.onDrop(top.itemOnClipboardUid, $element, evt, 'reference'); + /** + * activates the icons for "paste into" / "paste after" and to + * fetch a copy from another page outside of the context menus + */ + activatePasteIcons() { + const thisClass = this; + this.getClipboardData(); + + $('.t3js-page-new-ce').each(function () { + const addButton = this; + if (top.itemOnClipboardUid) { + // sorting of the buttons is important, else the modal + // for the first one is not working correctly, + // therefore the buttons are added by promises + $.when($(this).find('button.t3js-paste')) + .then(() => { + thisClass.alterDefaultPasteButton(this); + // avoid that button is added twice in container elements + // console.log(this, this.querySelectorAll('.t3js-paste-new').length); + if (this.querySelectorAll('.t3js-paste-new').length < 1) { + // add additional button + thisClass.addPasteReferenceButton(addButton, $(this).find('button.t3js-paste-default')); + } + }) + .catch((error) => {console.error(error)}); + + } else { + thisClass.addPasteReferenceButton(addButton); + } + }); + } + + /** + * generates the "paste into" / "paste after" modal + */ + activatePasteModal(element) { + const $element = $(element); + const url = $element.data('url') || null; + const elementTitle = top.itemOnClipboardTitle != undefined ? top.itemOnClipboardTitle : "["+TYPO3.lang['tx_paste_reference_js.modal.labels.no_title']+"]"; + const title = (TYPO3.lang['paste.modal.title.paste'] || 'Paste record') + ': "' + elementTitle + '"'; + const severity = (typeof top.TYPO3.Severity[$element.data('severity')] !== 'undefined') ? top.TYPO3.Severity[$element.data('severity')] : top.TYPO3.Severity.info; + let buttons = []; + let content = ''; + + if ($element.hasClass('t3js-paste-copy')) { + content = TYPO3.lang['tx_paste_reference_js.modal.pastecopy'] || 'How do you want to paste that clipboard content here?'; + buttons = [ + { + text: TYPO3.lang['paste.modal.button.cancel'] || 'Cancel', + active: true, + btnClass: 'btn-default', + trigger: (evt, modal) => modal.hideModal(), + }, + { + text: TYPO3.lang['tx_paste_reference_js.modal.button.pastecopy'] || 'Paste as copy', + btnClass: 'text-white btn-' + top.TYPO3.Severity.getCssClass(severity), + trigger: function (evt, modal) { + modal.hideModal(); + DragDrop.default.onDrop(top.itemOnClipboardUid, $element, evt); + } + }, + { + text: TYPO3.lang['tx_paste_reference_js.modal.button.pastereference'] || 'Paste as reference', + btnClass: 'text-white btn-' + top.TYPO3.Severity.getCssClass(severity), + trigger: function (evt, modal) { + modal.hideModal(); + DragDrop.default.onDrop(top.itemOnClipboardUid, $element, evt, 'reference'); + } } + ]; + if (top.pasteReferenceAllowed * 1 !== 1) { + buttons.pop(); } - ]; - if (top.pasteReferenceAllowed * 1 !== 1) { - buttons.pop(); - } - } else { - content = TYPO3.lang['paste.modal.paste'] || 'Do you want to move the record to this position?'; - buttons = [ - { - text: TYPO3.lang['paste.modal.button.cancel'] || 'Cancel', - active: true, - btnClass: 'btn-default', - trigger: (evt, modal) => modal.hideModal(), - }, - { - text: TYPO3.lang['paste.modal.button.paste'] || 'Move', - btnClass: 'btn-' + top.TYPO3.Severity.getCssClass(severity), - trigger: function (evt, modal) { - modal.hideModal(); - DragDrop.default.onDrop(top.itemOnClipboardUid, $element, null); + } else { + content = TYPO3.lang['paste.modal.paste'] || 'Do you want to move the record to this position?'; + buttons = [ + { + text: TYPO3.lang['paste.modal.button.cancel'] || 'Cancel', + active: true, + btnClass: 'btn-default', + trigger: (evt, modal) => modal.hideModal(), + }, + { + text: TYPO3.lang['paste.modal.button.paste'] || 'Move', + btnClass: 'btn-' + top.TYPO3.Severity.getCssClass(severity), + trigger: function (evt, modal) { + modal.hideModal(); + DragDrop.default.onDrop(top.itemOnClipboardUid, $element, null); + } } + ]; + } + if (url !== null) { + const separator = (url.indexOf('?') > -1) ? '&' : '?'; + const params = $.param({data: $element.data()}); + if (document.querySelectorAll('.typo3-backend-modal').length < 1) { + Modal.loadUrl(title, severity, buttons, url + separator + params); } - ]; + } else { + if (document.querySelectorAll('.typo3-backend-modal').length < 1) { + Modal.show(title, content, severity, buttons); + } + } } - if (url !== null) { - const separator = (url.indexOf('?') > -1) ? '&' : '?'; - const params = $.param({data: $element.data()}); - Modal.loadUrl(title, severity, buttons, url + separator + params); - } else { - Modal.show(title, content, severity, buttons); + + /** + * gives back the data from the popup window with record-selection to the copy action + * + * $('.typo3-TCEforms') is not relevant here as it exists on + * detail pages for single records only. + */ + initModalEventListener() { + if (!$('.typo3-TCEforms').length) { + window.addEventListener('message', function (evt) { + + if (!MessageUtility.verifyOrigin(evt.origin)) { + throw 'Denied message sent by ' + evt.origin; + } + if (typeof evt.data.fieldName === 'undefined') { + // throw 'fieldName not defined in message'; + console.log('fieldName not defined in message'); + } + if (typeof evt.data.value === 'undefined') { + throw 'value not defined in message'; + } + const result = evt.data.value; + const tableUid = result.replace('tt_content_', '') * 1; + const elementId = evt.data.fieldName; + DragDrop.default.onDrop(tableUid, $('#' + elementId).find('.t3js-paste-new'), 'copyFromAnotherPage'); + }); + } } -}; -/** - * activates the paste into / paste after and fetch copy from another page icons outside of the context menus - */ -Paste.activatePasteIcons = function () { - onReady.getClipboardData(); + /** + * is changing the common paste button to show + * the modal window with extended options + */ + alterDefaultPasteButton(button) { + const thisClass = this; + // replace class and in consequence the corresponding EventListener + $(button).find('button.t3js-paste').addClass('t3js-paste-default').removeClass('t3js-paste'); - $('.t3js-page-new-ce').each(function () { + // add custom click-EventListener on default paste button + $(button).on('click', '.t3js-paste-default', (evt) => { + evt.preventDefault(); + thisClass.activatePasteModal($(evt.currentTarget)); + }); + } - if (!$(this).find('.icon-actions-plus').length) { - return true; - } + addPasteReferenceButton(addButton, $pasteButton = null) { + const thisClass = this; + const $pasteReferenceButton = $(top.copyFromAnotherPageLinkTemplate); - if (top.itemOnClipboardUid) { - - // sorting of the buttons is important, else the modal for the first one is not working correctly - // therefore the buttons are added by promises - $.when($(this).find('button.t3js-paste')) - .then(() => { - - // disable default click-EventListener - $(document).off('click', '.t3js-paste'); - - // add custom click-EventListener - $(document).on('click', '.t3js-paste', (evt) => { - evt.preventDefault(); - Paste.activatePasteModal($(evt.currentTarget)); - }); - - $.when($(this).find('button.t3js-paste').after(top.copyFromAnotherPageLinkTemplate)) - .then( - onReady.initClickEventListener($(this)) - ) - .catch( - (error) => {console.error(error)} - ); - }) + if ($pasteButton) { + // promise to add custom button and eventHandler + // if 'button.t3js-paste' is found + $.when($pasteButton.after($pasteReferenceButton)) + .then( + thisClass.initClickEventListener($pasteReferenceButton) + ) .catch((error) => {console.error(error)}); - } else { - $(this).append(top.copyFromAnotherPageLinkTemplate); - onReady.initClickEventListener($(this)); + $(addButton).append($pasteReferenceButton); + thisClass.initClickEventListener($pasteReferenceButton); } - }); -}; + } + /** + * adds eventListener for copyFromAnotherPage + */ + initClickEventListener($element) { + const thisClass = this; + // Add modal, functionality of the modal itself is not done here, + // but rather in paste-reference-drag-drop and triggered by + // the custom EventListener 'message' (see downwards) + if ($element.length) { + $element.on('click', function (evt) { + evt.preventDefault(); + thisClass.copyFromAnotherPage($element); + }); + } + } -/** - * gives back the data from the popup window with record-selection to the copy action - * - * $('.typo3-TCEforms') is not relevant here as it exists on - * detail pages for single records only. - */ -if (!$('.typo3-TCEforms').length) { - window.addEventListener('message', function (evt) { + /** + * generates the paste into / paste after modal + */ + copyFromAnotherPage($element) { + const url = top.browserUrl + '&mode=db&bparams=' + $element.parent().attr('id') + '|||tt_content|'; + const configurationIframe = { + type: Modal.types.iframe, + content: url, + size: Modal.sizes.large + }; + Modal.advanced(configurationIframe); + } +} - if (!MessageUtility.verifyOrigin(evt.origin)) { - throw 'Denied message sent by ' + evt.origin; - } +// Deactivate default functions +Paste.activatePasteModal = function (element) {} +Paste.activatePasteIcons = function () {} - if (typeof evt.data.fieldName === 'undefined') { - throw 'fieldName not defined in message'; - } +export default PasteReference; - if (typeof evt.data.value === 'undefined') { - throw 'value not defined in message'; +if (PasteReference.instanceCount === 0 && top.pasteReferenceAllowed) { + const pollTime = 100; + window.setTimeout(function() { + if (PasteReference.instanceCount === 0) { + const pasteReference = new PasteReference({}); } - - const result = evt.data.value; - const tableUid = result.replace('tt_content_', '') * 1; - const elementId = evt.data.fieldName; - DragDrop.default.onDrop(tableUid, $('#' + elementId).find('.t3js-paste-new'), 'copyFromAnotherPage'); - }); + }, pollTime); } - -Paste.activatePasteIcons(); - -export default OnReady;