From 81db3c0a283a7cac5d4eddf7d58575e67f7381e6 Mon Sep 17 00:00:00 2001 From: David Bruchmann Date: Thu, 10 Apr 2025 19:28:03 +0700 Subject: [PATCH 1/7] [FEATURE][WIP] add support for EXT:container --- .../JavaScript/paste-reference-drag-drop.js | 21 +++++++++++++++++++ .../Public/JavaScript/paste-reference.js | 13 ++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Resources/Public/JavaScript/paste-reference-drag-drop.js b/Resources/Public/JavaScript/paste-reference-drag-drop.js index a0b71145..5e8096b5 100644 --- a/Resources/Public/JavaScript/paste-reference-drag-drop.js +++ b/Resources/Public/JavaScript/paste-reference-drag-drop.js @@ -173,6 +173,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 +262,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 +294,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 +330,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..71b285bb 100644 --- a/Resources/Public/JavaScript/paste-reference.js +++ b/Resources/Public/JavaScript/paste-reference.js @@ -160,7 +160,9 @@ Paste.activatePasteIcons = function () { $('.t3js-page-new-ce').each(function () { - if (!$(this).find('.icon-actions-plus').length) { + // '.icon-actions-plus belogs to default template + // '.icon-actions-add' belongs to EXT:contaier + if (!$(this).find('.icon-actions-plus').length && !$(this).find('.icon-actions-add').length) { return true; } @@ -171,22 +173,21 @@ Paste.activatePasteIcons = function () { $.when($(this).find('button.t3js-paste')) .then(() => { - // disable default click-EventListener + // disable default click-EventListener on default paste button $(document).off('click', '.t3js-paste'); - // add custom click-EventListener + // add custom click-EventListener on default paste button $(document).on('click', '.t3js-paste', (evt) => { evt.preventDefault(); Paste.activatePasteModal($(evt.currentTarget)); }); + // promise to add custom button and eventHandler if 'button.t3js-paste' is found $.when($(this).find('button.t3js-paste').after(top.copyFromAnotherPageLinkTemplate)) .then( onReady.initClickEventListener($(this)) ) - .catch( - (error) => {console.error(error)} - ); + .catch((error) => {console.error(error)}); }) .catch((error) => {console.error(error)}); From d2cea864cf97b5506ab0b29254ff5f00907f3e7a Mon Sep 17 00:00:00 2001 From: David Bruchmann Date: Mon, 21 Apr 2025 08:08:03 +0700 Subject: [PATCH 2/7] [BUGFIX] fix raceCondition by replacing CSS-class for EventHandler / promise for button --- Resources/Public/JavaScript/paste-reference.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/Public/JavaScript/paste-reference.js b/Resources/Public/JavaScript/paste-reference.js index 71b285bb..efefb689 100644 --- a/Resources/Public/JavaScript/paste-reference.js +++ b/Resources/Public/JavaScript/paste-reference.js @@ -160,9 +160,9 @@ Paste.activatePasteIcons = function () { $('.t3js-page-new-ce').each(function () { - // '.icon-actions-plus belogs to default template + // '.icon-actions-plus belongs to default template // '.icon-actions-add' belongs to EXT:contaier - if (!$(this).find('.icon-actions-plus').length && !$(this).find('.icon-actions-add').length) { + if (!$(this).find('.icon-actions-plus, .icon-actions-add').length) { return true; } @@ -173,17 +173,17 @@ Paste.activatePasteIcons = function () { $.when($(this).find('button.t3js-paste')) .then(() => { - // disable default click-EventListener on default paste button - $(document).off('click', '.t3js-paste'); + // replace class and in consequence the corresponding EventListener + $(this).find('button.t3js-paste').addClass('t3js-paste-default').removeClass('t3js-paste'); // add custom click-EventListener on default paste button - $(document).on('click', '.t3js-paste', (evt) => { + $(this).on('click', '.t3js-paste-default', (evt) => { evt.preventDefault(); Paste.activatePasteModal($(evt.currentTarget)); }); // promise to add custom button and eventHandler if 'button.t3js-paste' is found - $.when($(this).find('button.t3js-paste').after(top.copyFromAnotherPageLinkTemplate)) + $.when($(this).find('button.t3js-paste-default').after(top.copyFromAnotherPageLinkTemplate)) .then( onReady.initClickEventListener($(this)) ) From b350f25df7145828a4ce225bdc622f950e057f1d Mon Sep 17 00:00:00 2001 From: David Bruchmann Date: Mon, 21 Apr 2025 08:23:32 +0700 Subject: [PATCH 3/7] [TASK] adjust JS-code style --- .../Public/JavaScript/paste-reference-drag-drop.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Resources/Public/JavaScript/paste-reference-drag-drop.js b/Resources/Public/JavaScript/paste-reference-drag-drop.js index 5e8096b5..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 { @@ -262,7 +261,7 @@ DragDrop.default = { if (evt === 'copyFromAnotherPage') { parameters['CB'] = {setCopyMode: 1}; } - if (containerParent){ + if (containerParent) { parameters['cmd']['tt_content'][contentElementUid]['copy']['update']['tx_container_parent'] = containerParent; } // fire the request, and show a message if it has failed @@ -294,7 +293,7 @@ DragDrop.default = { } } }; - if (containerParent){ + if (containerParent) { parameters['cmd']['tt_content'][contentElementUid]['move']['update']['tx_container_parent'] = containerParent; } // fire the request, and show a message if it has failed From f5c07ba7c0534d16ad7ee68503c87aad96504fa9 Mon Sep 17 00:00:00 2001 From: David Bruchmann Date: Mon, 8 Sep 2025 12:26:17 +0700 Subject: [PATCH 4/7] [Task] refactor paste-reference.js, fix #79 --- .../Public/JavaScript/paste-reference.js | 371 ++++++++++-------- 1 file changed, 199 insertions(+), 172 deletions(-) diff --git a/Resources/Public/JavaScript/paste-reference.js b/Resources/Public/JavaScript/paste-reference.js index efefb689..7154c11b 100644 --- a/Resources/Public/JavaScript/paste-reference.js +++ b/Resources/Public/JavaScript/paste-reference.js @@ -17,21 +17,26 @@ 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 { +// import ContextMenuActions from "@typo3/backend/context-menu-actions.js"; +import Viewport from "@typo3/backend/viewport.js"; +import { default as CoreContextMenuActions } from "@typo3/backend/context-menu-actions.js"; +// import { default as ContextMenuActions } from "@ehaerer/paste-reference/context-menu-actions.js"; + +import { default as Topbar } from "@typo3/backend/viewport/topbar.js"; + +class PasteReference { + openedPopupWindow = []; + constructor() { + this.initModalEventListener(); + this.activatePasteIcons(); + } + /** - * 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,188 +50,210 @@ 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 () { + // '.icon-actions-plus belongs to default template + // '.icon-actions-add' belongs to EXT:contaier + if (!$(this).find('.icon-actions-plus, .icon-actions-add').length) { + return true; } - ]; - 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); - } + + 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); + thisClass.addPasteReferenceButton(addButton, $(this).find('button.t3js-paste-default')); + }) + .catch((error) => {console.error(error)}); + + } else { + thisClass.addPasteReferenceButton(addButton); } - ]; - } - 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); + }); } -}; -/** - * activates the paste into / paste after and fetch copy from another page icons outside of the context menus - */ -Paste.activatePasteIcons = function () { - onReady.getClipboardData(); - - $('.t3js-page-new-ce').each(function () { + /** + * 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 = ''; - // '.icon-actions-plus belongs to default template - // '.icon-actions-add' belongs to EXT:contaier - if (!$(this).find('.icon-actions-plus, .icon-actions-add').length) { - return true; + 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(); + } + } 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()}); + Modal.loadUrl(title, severity, buttons, url + separator + params); + } else { + Modal.show(title, content, severity, buttons); } + } - 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(() => { - - // replace class and in consequence the corresponding EventListener - $(this).find('button.t3js-paste').addClass('t3js-paste-default').removeClass('t3js-paste'); - - // add custom click-EventListener on default paste button - $(this).on('click', '.t3js-paste-default', (evt) => { - evt.preventDefault(); - Paste.activatePasteModal($(evt.currentTarget)); - }); - - // promise to add custom button and eventHandler if 'button.t3js-paste' is found - $.when($(this).find('button.t3js-paste-default').after(top.copyFromAnotherPageLinkTemplate)) - .then( - onReady.initClickEventListener($(this)) - ) - .catch((error) => {console.error(error)}); - }) - .catch((error) => {console.error(error)}); + /** + * 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) { - } else { - $(this).append(top.copyFromAnotherPageLinkTemplate); - onReady.initClickEventListener($(this)); + if (!MessageUtility.verifyOrigin(evt.origin)) { + throw 'Denied message sent by ' + evt.origin; + } + if (typeof evt.data.fieldName === 'undefined') { + throw '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'); + }); } - }); -}; + } + /** + * 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'); -/** - * 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) { + // add custom click-EventListener on default paste button + $(button).on('click', '.t3js-paste-default', (evt) => { + evt.preventDefault(); + thisClass.activatePasteModal($(evt.currentTarget)); + }); + } - if (!MessageUtility.verifyOrigin(evt.origin)) { - throw 'Denied message sent by ' + evt.origin; - } + addPasteReferenceButton(addButton, $pasteButton = null) { + const thisClass = this; + const $pasteReferenceButton = $(top.copyFromAnotherPageLinkTemplate); - if (typeof evt.data.fieldName === 'undefined') { - throw 'fieldName not defined in message'; + 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 { + addButton.append($pasteReferenceButton); + thisClass.initClickEventListener($pasteReferenceButton); } + } - if (typeof evt.data.value === 'undefined') { - throw 'value not defined in message'; + /** + * 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); + }); } + } - 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'); - }); + /** + * 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); + } } -Paste.activatePasteIcons(); +// Deactivate default functions +Paste.activatePasteModal = function (element) {} +Paste.activatePasteIcons = function () {} -export default OnReady; +export default PasteReference; From 46224fa254965cd265d03275792af85d5d8fb743 Mon Sep 17 00:00:00 2001 From: David Bruchmann Date: Mon, 8 Sep 2025 12:40:41 +0700 Subject: [PATCH 5/7] [Task] remove useless imports in paste-reference.js --- Resources/Public/JavaScript/paste-reference.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Resources/Public/JavaScript/paste-reference.js b/Resources/Public/JavaScript/paste-reference.js index 7154c11b..c2ec2745 100644 --- a/Resources/Public/JavaScript/paste-reference.js +++ b/Resources/Public/JavaScript/paste-reference.js @@ -17,13 +17,6 @@ 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"; -// import ContextMenuActions from "@typo3/backend/context-menu-actions.js"; -import Viewport from "@typo3/backend/viewport.js"; -import { default as CoreContextMenuActions } from "@typo3/backend/context-menu-actions.js"; -// import { default as ContextMenuActions } from "@ehaerer/paste-reference/context-menu-actions.js"; - -import { default as Topbar } from "@typo3/backend/viewport/topbar.js"; - class PasteReference { openedPopupWindow = []; From 5835a71919aac2d4d18fb22f9f094406aae17a45 Mon Sep 17 00:00:00 2001 From: David Bruchmann Date: Mon, 8 Sep 2025 13:25:47 +0700 Subject: [PATCH 6/7] [Task][v3] only log in the console if 'fieldName not defined in message' instead of throwing, see #74 --- Resources/Public/JavaScript/paste-reference.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/Public/JavaScript/paste-reference.js b/Resources/Public/JavaScript/paste-reference.js index c2ec2745..0dda3284 100644 --- a/Resources/Public/JavaScript/paste-reference.js +++ b/Resources/Public/JavaScript/paste-reference.js @@ -168,7 +168,8 @@ class PasteReference { throw 'Denied message sent by ' + evt.origin; } if (typeof evt.data.fieldName === 'undefined') { - throw 'fieldName not defined in message'; + // 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'; From 950c24644997b19471bd54d7d9d079faa34c5097 Mon Sep 17 00:00:00 2001 From: David Bruchmann Date: Thu, 11 Sep 2025 16:36:57 +0700 Subject: [PATCH 7/7] [Bugfix] instantiate JS-class if it's not done automatically, [Bugfix] fix paste-icon on pages without content. --- .../Public/JavaScript/paste-reference.js | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/Resources/Public/JavaScript/paste-reference.js b/Resources/Public/JavaScript/paste-reference.js index 0dda3284..a53aaf9f 100644 --- a/Resources/Public/JavaScript/paste-reference.js +++ b/Resources/Public/JavaScript/paste-reference.js @@ -17,13 +17,25 @@ 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"; +/** + * Module: @ehaerer/paste-reference/paste-reference.js + */ + +'use strict'; + +/** + * @exports @ehaerer/paste-reference/paste-reference.js + */ class PasteReference { - openedPopupWindow = []; + static instanceCount = 0; + + // openedPopupWindow = []; constructor() { - this.initModalEventListener(); + PasteReference.instanceCount++; this.activatePasteIcons(); + this.initModalEventListener(); } /** @@ -61,12 +73,6 @@ class PasteReference { this.getClipboardData(); $('.t3js-page-new-ce').each(function () { - // '.icon-actions-plus belongs to default template - // '.icon-actions-add' belongs to EXT:contaier - if (!$(this).find('.icon-actions-plus, .icon-actions-add').length) { - return true; - } - const addButton = this; if (top.itemOnClipboardUid) { // sorting of the buttons is important, else the modal @@ -75,7 +81,12 @@ class PasteReference { $.when($(this).find('button.t3js-paste')) .then(() => { thisClass.alterDefaultPasteButton(this); - thisClass.addPasteReferenceButton(addButton, $(this).find('button.t3js-paste-default')); + // 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)}); @@ -148,9 +159,13 @@ class PasteReference { if (url !== null) { const separator = (url.indexOf('?') > -1) ? '&' : '?'; const params = $.param({data: $element.data()}); - Modal.loadUrl(title, severity, buttons, url + separator + params); + if (document.querySelectorAll('.typo3-backend-modal').length < 1) { + Modal.loadUrl(title, severity, buttons, url + separator + params); + } } else { - Modal.show(title, content, severity, buttons); + if (document.querySelectorAll('.typo3-backend-modal').length < 1) { + Modal.show(title, content, severity, buttons); + } } } @@ -211,7 +226,7 @@ class PasteReference { ) .catch((error) => {console.error(error)}); } else { - addButton.append($pasteReferenceButton); + $(addButton).append($pasteReferenceButton); thisClass.initClickEventListener($pasteReferenceButton); } } @@ -251,3 +266,12 @@ Paste.activatePasteModal = function (element) {} Paste.activatePasteIcons = function () {} export default PasteReference; + +if (PasteReference.instanceCount === 0 && top.pasteReferenceAllowed) { + const pollTime = 100; + window.setTimeout(function() { + if (PasteReference.instanceCount === 0) { + const pasteReference = new PasteReference({}); + } + }, pollTime); +}