From 290d9d2cb3b84efa4f096e58b9af06619486f1c2 Mon Sep 17 00:00:00 2001 From: Benni Mack <benni@typo3.org> Date: Thu, 12 Aug 2021 15:29:22 +0200 Subject: [PATCH] [TASK] Reduce inline JavaScript in Page Module Paste logic When having a content element on the clipboard (normal mode) the page module dynamically shows paste icons everywhere. This change centralizes the generation of the Paste icons into JavaScript, so the inline javascript usage of "top.*" functionality to park code somewhere has been removed, and the actual items are generated in JavaScript. In addition, as this code is only affecting the page module when a tt_content element is on the clipboard, the Paste.js JS module is only loaded when appropriate, thus reducing the actual loading time for "regular" visits on the Page Module. The icon in the paste button is now loaded via a native web component, and only necessary logic is used in the Paste JS module. The outer rendering for the Page Module has been simplified, moving this functionality all into PageLayoutController, reducing cross-dependencies between the PageLayout* classes. Resolves: #94840 Releases: master Change-Id: I380df9a56bfff74684616732166f25c68bbc6dec Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/70488 Tested-by: core-ci <typo3@b13.com> Tested-by: Jochen <rothjochen@gmail.com> Tested-by: Oliver Bartsch <bo@cedev.de> Tested-by: Benni Mack <benni@typo3.org> Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl> Reviewed-by: Jochen <rothjochen@gmail.com> Reviewed-by: Oliver Bartsch <bo@cedev.de> Reviewed-by: Benni Mack <benni@typo3.org> --- .../Public/TypeScript/LayoutModule/Paste.ts | 83 ++++++++----- .../Controller/PageLayoutController.php | 33 ++++- .../View/Drawing/BackendLayoutRenderer.php | 115 +----------------- .../Classes/View/PageLayoutContext.php | 12 -- .../backend/Classes/View/PageLayoutView.php | 78 ------------ .../Public/JavaScript/LayoutModule/Paste.js | 2 +- 6 files changed, 85 insertions(+), 238 deletions(-) diff --git a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/LayoutModule/Paste.ts b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/LayoutModule/Paste.ts index eb9d7d0f45d1..b2cdaeee5ff6 100644 --- a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/LayoutModule/Paste.ts +++ b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/LayoutModule/Paste.ts @@ -13,14 +13,17 @@ /** * Module: TYPO3/CMS/Backend/LayoutModule/Paste - * this JS code does the paste logic for the Layout module (Web => Page) - * based on jQuery UI + * Dynamically adds "Paste" Icons in the Page Layout module (Web => Page) + * and triggers a modal window. which then calls the AjaxDataHandler + * to execute the action to paste the current clipboard contents. */ import $ from 'jquery'; import ResponseInterface from '../AjaxDataHandler/ResponseInterface'; import DataHandler = require('../AjaxDataHandler'); import Modal = require('../Modal'); import Severity = require('../Severity'); +import 'TYPO3/CMS/Backend/Element/IconElement'; +import {SeverityEnum} from '../Enum/Severity'; interface Button { text: string; @@ -30,7 +33,12 @@ interface Button { } class Paste { + public itemOnClipboardUid: number = 0; + public itemOnClipboardTitle: string = ''; + public copyMode: string = ''; private elementIdentifier: string = '.t3js-page-ce'; + private pasteAfterLinkTemplate: string = ''; + private pasteIntoLinkTemplate: string = ''; /** * @param {JQuery} $element @@ -51,33 +59,57 @@ class Paste { constructor() { $((): void => { if ($('.t3js-page-columns').length) { + this.generateButtonTemplates(); this.activatePasteIcons(); + this.initializeEvents(); } }); } + private initializeEvents(): void + { + $(document).on('click', '.t3js-paste', (evt: Event): void => { + evt.preventDefault(); + this.activatePasteModal($(evt.currentTarget)); + }); + } + + private generateButtonTemplates(): void + { + if (!this.itemOnClipboardUid) { + return; + } + this.pasteAfterLinkTemplate = '<button' + + ' type="button"' + + ' class="t3js-paste t3js-paste' + (this.copyMode ? '-' + this.copyMode : '') + ' t3js-paste-after btn btn-default btn-sm"' + + ' title="' + TYPO3.lang?.pasteAfterRecord + '">' + + '<typo3-backend-icon identifier="actions-document-paste-into" size="small"></typo3-backend-icon>' + + '</button>'; + this.pasteIntoLinkTemplate = '<button' + + ' type="button"' + + ' class="t3js-paste t3js-paste' + (this.copyMode ? '-' + this.copyMode : '') + ' t3js-paste-into btn btn-default btn-sm"' + + ' title="' + TYPO3.lang?.pasteIntoColumn + '">' + + '<typo3-backend-icon identifier="actions-document-paste-into" size="small"></typo3-backend-icon>' + + '</button>'; + } + /** * activates the paste into / paste after icons outside of the context menus */ private activatePasteIcons(): void { - const me = this; - $('.t3-page-ce-wrapper-new-ce').each((index: number, el: HTMLElement): void => { if (!$(el).find('.t3js-toggle-new-content-element-wizard').length) { return; } $('.t3js-page-lang-column .t3-page-ce > .t3-page-ce').removeClass('t3js-page-ce'); - if (top.pasteAfterLinkTemplate && top.pasteIntoLinkTemplate) { + if (this.pasteAfterLinkTemplate && this.pasteIntoLinkTemplate) { const parent = $(el).parent(); + // append the buttons if (parent.data('page')) { - $(el).append(top.pasteIntoLinkTemplate); + $(el).append(this.pasteIntoLinkTemplate); } else { - $(el).append(top.pasteAfterLinkTemplate); + $(el).append(this.pasteAfterLinkTemplate); } - $(el).find('.t3js-paste').on('click', (evt: Event): void => { - evt.preventDefault(); - me.activatePasteModal($(evt.currentTarget)); - }); } }); } @@ -85,15 +117,9 @@ class Paste { /** * generates the paste into / paste after modal */ - private activatePasteModal(element: JQuery): void { - const me = this; - const $element = $(element); - const url = $element.data('url') || null; - const title = (TYPO3.lang['paste.modal.title.paste'] || 'Paste record') + ': "' + $element.data('title') + '"'; + private activatePasteModal($element: JQuery): void { + const title = (TYPO3.lang['paste.modal.title.paste'] || 'Paste record') + ': "' + this.itemOnClipboardTitle + '"'; const content = TYPO3.lang['paste.modal.paste'] || 'Do you want to paste the record to this position?'; - const severity = (typeof top.TYPO3.Severity[$element.data('severity')] !== 'undefined') ? - top.TYPO3.Severity[$element.data('severity')] : - top.TYPO3.Severity.info; let buttons: Array<Button> = []; buttons = [ @@ -107,20 +133,15 @@ class Paste { }, { text: TYPO3.lang['paste.modal.button.paste'] || 'Paste', - btnClass: 'btn-' + Severity.getCssClass(severity), + btnClass: 'btn-' + Severity.getCssClass(SeverityEnum.warning), trigger: (): void => { Modal.currentModal.trigger('modal-dismiss'); - me.execute($element); + this.execute($element); }, }, ]; - if (url !== null) { - const separator = url.contains('?') ? '&' : '?'; - const params = $.param({data: $element.data()}); - Modal.loadUrl(title, severity, buttons, url + separator + params); - } else { - Modal.show(title, content, severity, buttons); - } + + Modal.show(title, content, SeverityEnum.warning, buttons); } /** @@ -150,11 +171,9 @@ class Paste { }; DataHandler.process(parameters).then((result: ResponseInterface): void => { - if (result.hasErrors) { - return; + if (!result.hasErrors) { + window.location.reload(); } - - window.location.reload(); }); } } diff --git a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php index 9a70dbbe5b62..f47e158a9b74 100644 --- a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php +++ b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php @@ -19,6 +19,7 @@ namespace TYPO3\CMS\Backend\Controller; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Backend\Clipboard\Clipboard; use TYPO3\CMS\Backend\Domain\Model\Element\ImmediateActionElement; use TYPO3\CMS\Backend\Module\ModuleLoader; use TYPO3\CMS\Backend\Routing\PreviewUriBuilder; @@ -28,6 +29,7 @@ use TYPO3\CMS\Backend\Template\ModuleTemplate; use TYPO3\CMS\Backend\Template\ModuleTemplateFactory; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Backend\View\BackendLayoutView; +use TYPO3\CMS\Backend\View\Drawing\BackendLayoutRenderer; use TYPO3\CMS\Backend\View\PageLayoutContext; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Database\ConnectionPool; @@ -599,6 +601,7 @@ class PageLayoutController $content .= '</form>'; // Setting up the buttons for the docheader $this->makeButtons($request); + $this->initializeClipboard($request); // Create LanguageMenu $this->makeLanguageMenu(); @@ -618,6 +621,30 @@ class PageLayoutController $this->moduleTemplate->setContent($content); } + /** + * Initializes the clipboard for generating paste links dynamically via JavaScript after each "+ Content" symbol + */ + protected function initializeClipboard(ServerRequestInterface $request): void + { + $clipboard = GeneralUtility::makeInstance(Clipboard::class); + $clipboard->initializeClipboard($request); + $clipboard->lockToNormal(); + $clipboard->cleanCurrent(); + $clipboard->endClipboard(); + $elFromTable = $clipboard->elFromTable('tt_content'); + if (!empty($elFromTable) && $this->isContentEditable($this->current_sys_language)) { + $pasteItem = (int)substr((string)key($elFromTable), 11); + $pasteRecord = BackendUtility::getRecordWSOL('tt_content', $pasteItem); + $pasteTitle = BackendUtility::getRecordTitle('tt_content', $pasteRecord, false, true); + $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/Paste', ' + function(Paste) { + Paste.itemOnClipboardUid = ' . $pasteItem . '; + Paste.itemOnClipboardTitle = ' . GeneralUtility::quoteJSvalue($pasteTitle) . '; + Paste.copyMode = ' . GeneralUtility::quoteJSvalue($clipboard->clipData['normal']['mode']) . '; + }'); + } + } + /** * Rendering content * @@ -630,7 +657,6 @@ class PageLayoutController $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Localization'); $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/DragDrop'); $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal'); - $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LayoutModule/Paste'); $this->pageRenderer->loadRequireJsModule(ImmediateActionElement::MODULE_NAME); $this->pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_layout.xlf'); @@ -654,8 +680,6 @@ class PageLayoutController $numberOfHiddenElements = $this->getNumberOfHiddenElements($configuration->getLanguageColumns()); - $pageLayoutDrawer = $this->context->getBackendLayoutRenderer(); - $pageActionsCallback = null; if ($this->context->isPageEditable()) { $languageOverlayId = 0; @@ -672,7 +696,7 @@ class PageLayoutController }'; } $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/PageActions', $pageActionsCallback); - $tableOutput = $pageLayoutDrawer->drawContent(); + $tableOutput = GeneralUtility::makeInstance(BackendLayoutRenderer::class, $this->context)->drawContent(); } if ($this->getBackendUser()->check('tables_select', 'tt_content') && $numberOfHiddenElements > 0) { @@ -979,6 +1003,7 @@ class PageLayoutController return !$this->pageinfo['editlock'] && $this->getBackendUser()->doesUserHaveAccess($this->pageinfo, Permission::CONTENT_EDIT) + && $this->getBackendUser()->check('tables_modify', 'tt_content') && $this->getBackendUser()->checkLanguageAccess($languageId); } diff --git a/typo3/sysext/backend/Classes/View/Drawing/BackendLayoutRenderer.php b/typo3/sysext/backend/Classes/View/Drawing/BackendLayoutRenderer.php index f713260e1d1f..16acadcb12e3 100644 --- a/typo3/sysext/backend/Classes/View/Drawing/BackendLayoutRenderer.php +++ b/typo3/sysext/backend/Classes/View/Drawing/BackendLayoutRenderer.php @@ -17,8 +17,6 @@ declare(strict_types=1); namespace TYPO3\CMS\Backend\View\Drawing; -use Psr\Log\LoggerAwareTrait; -use TYPO3\CMS\Backend\Clipboard\Clipboard; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Backend\View\BackendLayout\ContentFetcher; use TYPO3\CMS\Backend\View\BackendLayout\Grid\Grid; @@ -29,13 +27,9 @@ use TYPO3\CMS\Backend\View\BackendLayout\Grid\LanguageColumn; use TYPO3\CMS\Backend\View\BackendLayout\RecordRememberer; use TYPO3\CMS\Backend\View\PageLayoutContext; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; -use TYPO3\CMS\Core\Imaging\Icon; -use TYPO3\CMS\Core\Imaging\IconFactory; use TYPO3\CMS\Core\Localization\LanguageService; use TYPO3\CMS\Core\Messaging\FlashMessage; use TYPO3\CMS\Core\Messaging\FlashMessageService; -use TYPO3\CMS\Core\Page\PageRenderer; -use TYPO3\CMS\Core\Type\Bitmask\Permission; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Mvc\Request; use TYPO3\CMS\Fluid\View\TemplateView; @@ -47,46 +41,18 @@ use TYPO3\CMS\Fluid\View\TemplateView; * which renders the Resources/Private/PageLayout/PageLayout template * with necessary assigned template variables. * - * - Initializes the clipboard used in the page layout - * - Inserts an encoded paste icon as JS which is made visible when clipboard elements are registered - * * @internal this is experimental and subject to change in TYPO3 v10 / v11 */ class BackendLayoutRenderer { - use LoggerAwareTrait; - - /** - * @var IconFactory - */ - protected $iconFactory; - - /** - * @var PageLayoutContext - */ - protected $context; - - /** - * @var ContentFetcher - */ - protected $contentFetcher; - - /** - * @var Clipboard - */ - protected $clipboard; - - /** - * @var TemplateView - */ - protected $view; + protected PageLayoutContext $context; + protected ContentFetcher $contentFetcher; + protected TemplateView $view; public function __construct(PageLayoutContext $context) { $this->context = $context; $this->contentFetcher = GeneralUtility::makeInstance(ContentFetcher::class, $context); - $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class); - $this->initializeClipboard(); $this->view = GeneralUtility::makeInstance(TemplateView::class); $this->view->getRenderingContext()->setRequest(GeneralUtility::makeInstance(Request::class)); $this->view->getRenderingContext()->getTemplatePaths()->fillDefaultsByPackageName('backend'); @@ -125,7 +91,7 @@ class BackendLayoutRenderer /** * @return LanguageColumn[] */ - public function getLanguageColumnsForPageLayoutContext(PageLayoutContext $context): iterable + protected function getLanguageColumnsForPageLayoutContext(PageLayoutContext $context): iterable { $languageColumns = []; foreach ($context->getLanguagesToShow() as $siteLanguage) { @@ -279,79 +245,6 @@ class BackendLayoutRenderer return $rendered; } - /** - * Initializes the clipboard for generating paste links - * - * @see \TYPO3\CMS\Backend\Controller\ContextMenuController::clipboardAction() - * @see \TYPO3\CMS\Filelist\Controller\FileListController::indexAction() - */ - protected function initializeClipboard(): void - { - $this->clipboard = GeneralUtility::makeInstance(Clipboard::class); - $this->clipboard->initializeClipboard(); - $this->clipboard->lockToNormal(); - $this->clipboard->cleanCurrent(); - $this->clipboard->endClipboard(); - - $elFromTable = $this->clipboard->elFromTable('tt_content'); - if (!empty($elFromTable) && $this->isContentEditable()) { - $pasteItem = (int)substr((string)key($elFromTable), 11); - $pasteRecord = BackendUtility::getRecord('tt_content', (int)$pasteItem); - $pasteTitle = (string)($pasteRecord['header'] ?: $pasteItem); - $copyMode = $this->clipboard->clipData['normal']['mode'] ? '-' . $this->clipboard->clipData['normal']['mode'] : ''; - $addExtOnReadyCode = ' - top.pasteIntoLinkTemplate = ' - . $this->drawPasteIcon($pasteItem, $pasteTitle, $copyMode, 't3js-paste-into', 'pasteIntoColumn') - . '; - top.pasteAfterLinkTemplate = ' - . $this->drawPasteIcon($pasteItem, $pasteTitle, $copyMode, 't3js-paste-after', 'pasteAfterRecord') - . ';'; - } else { - $addExtOnReadyCode = ' - top.pasteIntoLinkTemplate = \'\'; - top.pasteAfterLinkTemplate = \'\';'; - } - GeneralUtility::makeInstance(PageRenderer::class)->addJsInlineCode('pasteLinkTemplates', $addExtOnReadyCode); - } - - /** - * Draw a paste icon either for pasting into a column or for pasting after a record - * - * @param int $pasteItem ID of the item in the clipboard - * @param string $pasteTitle Title for the JS modal - * @param string $copyMode copy or cut - * @param string $cssClass CSS class to determine if pasting is done into column or after record - * @param string $title title attribute of the generated link - * - * @return string Generated HTML code with link and icon - */ - private function drawPasteIcon(int $pasteItem, string $pasteTitle, string $copyMode, string $cssClass, string $title): string - { - $pasteIcon = json_encode( - ' <button type="button"' - . ' data-bs-content="' . htmlspecialchars((string)$pasteItem) . '"' - . ' data-title="' . htmlspecialchars($pasteTitle) . '"' - . ' data-severity="warning"' - . ' class="t3js-paste t3js-paste' . htmlspecialchars($copyMode) . ' ' . htmlspecialchars($cssClass) . ' btn btn-default btn-sm"' - . ' title="' . htmlspecialchars($this->getLanguageService()->getLL($title)) . '">' - . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() - . '</button>' - ); - return $pasteIcon; - } - - protected function isContentEditable(): bool - { - if ($this->getBackendUser()->isAdmin()) { - return true; - } - - $pageRecord = $this->context->getPageRecord(); - return !$pageRecord['editlock'] - && $this->getBackendUser()->check('tables_modify', 'tt_content') - && $this->getBackendUser()->doesUserHaveAccess($pageRecord, Permission::CONTENT_EDIT); - } - protected function getBackendUser(): BackendUserAuthentication { return $GLOBALS['BE_USER']; diff --git a/typo3/sysext/backend/Classes/View/PageLayoutContext.php b/typo3/sysext/backend/Classes/View/PageLayoutContext.php index b3a57c396653..fc7928a781e7 100644 --- a/typo3/sysext/backend/Classes/View/PageLayoutContext.php +++ b/typo3/sysext/backend/Classes/View/PageLayoutContext.php @@ -21,7 +21,6 @@ use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Backend\View\BackendLayout\BackendLayout; use TYPO3\CMS\Backend\View\BackendLayout\ContentFetcher; -use TYPO3\CMS\Backend\View\Drawing\BackendLayoutRenderer; use TYPO3\CMS\Backend\View\Drawing\DrawingConfiguration; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Database\ConnectionPool; @@ -56,11 +55,6 @@ class PageLayoutContext */ protected $contentFetcher; - /** - * @var BackendLayoutRenderer - */ - protected $backendLayoutRenderer; - /** * @var array */ @@ -125,7 +119,6 @@ class PageLayoutContext $this->backendLayout = $backendLayout; $this->drawingConfiguration = GeneralUtility::makeInstance(DrawingConfiguration::class); $this->contentFetcher = GeneralUtility::makeInstance(ContentFetcher::class, $this); - $this->backendLayoutRenderer = GeneralUtility::makeInstance(BackendLayoutRenderer::class, $this); $this->siteLanguages = $this->site->getAvailableLanguages($this->getBackendUser(), true, $this->pageId); $this->siteLanguage = $this->site->getDefaultLanguage(); } @@ -168,11 +161,6 @@ class PageLayoutContext return $this->drawingConfiguration; } - public function getBackendLayoutRenderer(): BackendLayoutRenderer - { - return $this->backendLayoutRenderer; - } - public function getBackendUser(): BackendUserAuthentication { return $GLOBALS['BE_USER']; diff --git a/typo3/sysext/backend/Classes/View/PageLayoutView.php b/typo3/sysext/backend/Classes/View/PageLayoutView.php index 93b773ec4ee1..0052a03261d8 100644 --- a/typo3/sysext/backend/Classes/View/PageLayoutView.php +++ b/typo3/sysext/backend/Classes/View/PageLayoutView.php @@ -20,7 +20,6 @@ use Doctrine\DBAL\Statement; use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; -use TYPO3\CMS\Backend\Clipboard\Clipboard; use TYPO3\CMS\Backend\Controller\Page\LocalizationController; use TYPO3\CMS\Backend\Routing\PreviewUriBuilder; use TYPO3\CMS\Backend\Routing\UriBuilder; @@ -146,11 +145,6 @@ class PageLayoutView implements LoggerAwareInterface */ protected $siteLanguages = []; - /** - * @var Clipboard - */ - protected $clipboard; - /** * Current ids page record * @@ -243,7 +237,6 @@ class PageLayoutView implements LoggerAwareInterface { $this->resolveSiteLanguages($this->id); $this->pageRecord = BackendUtility::getRecordWSOL('pages', $this->id); - $this->initializeClipboard(); $this->pageinfo = BackendUtility::readPageAccess($this->id, '') ?: []; $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class); $pageActionsCallback = null; @@ -651,26 +644,6 @@ class PageLayoutView implements LoggerAwareInterface $out .= $grid . '</table></div>'; } } - $elFromTable = $this->clipboard->elFromTable('tt_content'); - if (!empty($elFromTable) && $this->isContentEditable()) { - $pasteItem = (int)substr((string)key($elFromTable), 11); - $pasteRecord = BackendUtility::getRecord('tt_content', $pasteItem); - $pasteTitle = $pasteRecord['header'] ?: (string)$pasteItem; - $copyMode = $this->clipboard->clipData['normal']['mode'] ? '-' . $this->clipboard->clipData['normal']['mode'] : ''; - $inlineJavaScript = ' - top.pasteIntoLinkTemplate = ' - . $this->tt_content_drawPasteIcon($pasteItem, $pasteTitle, $copyMode, 't3js-paste-into', 'pasteIntoColumn') - . '; - top.pasteAfterLinkTemplate = ' - . $this->tt_content_drawPasteIcon($pasteItem, $pasteTitle, $copyMode, 't3js-paste-after', 'pasteAfterRecord') - . ';'; - } else { - $inlineJavaScript = ' - top.pasteIntoLinkTemplate = \'\'; - top.pasteAfterLinkTemplate = \'\';'; - } - $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class); - $pageRenderer->addJsInlineCode('pasteLinkTemplates', $inlineJavaScript); // If language mode, then make another presentation: // Notice that THIS presentation will override the value of $out! // But it needs the code above to execute since $languageColumn is filled with content we need! @@ -951,32 +924,6 @@ class PageLayoutView implements LoggerAwareInterface </div>'; } - /** - * Draw a paste icon either for pasting into a column or for pasting after a record - * - * @param int $pasteItem ID of the item in the clipboard - * @param string $pasteTitle Title for the JS modal - * @param string $copyMode copy or cut - * @param string $cssClass CSS class to determine if pasting is done into column or after record - * @param string $title title attribute of the generated link - * - * @return string Generated HTML code with link and icon - */ - protected function tt_content_drawPasteIcon($pasteItem, $pasteTitle, $copyMode, $cssClass, $title) - { - $pasteIcon = json_encode( - ' <button type="button"' - . ' data-bs-content="' . htmlspecialchars((string)$pasteItem) . '"' - . ' data-title="' . htmlspecialchars($pasteTitle) . '"' - . ' data-severity="warning"' - . ' class="t3js-paste t3js-paste' . htmlspecialchars($copyMode) . ' ' . htmlspecialchars($cssClass) . ' btn btn-default btn-sm"' - . ' title="' . htmlspecialchars($this->getLanguageService()->getLL($title)) . '">' - . $this->iconFactory->getIcon('actions-document-paste-into', Icon::SIZE_SMALL)->render() - . '</button>' - ); - return $pasteIcon; - } - /** * Draw the footer for a single tt_content element * @@ -1645,31 +1592,6 @@ class PageLayoutView implements LoggerAwareInterface * ********************************/ - /** - * Initializes the clipboard for generating paste links - * - * - * @see \TYPO3\CMS\Backend\Controller\ContextMenuController::clipboardAction() - * @see \TYPO3\CMS\Filelist\Controller\FileListController::indexAction() - */ - protected function initializeClipboard() - { - // Start clipboard - $this->clipboard = GeneralUtility::makeInstance(Clipboard::class); - - // Initialize - reads the clipboard content from the user session - $this->clipboard->initializeClipboard(); - - // This locks the clipboard to the Normal for this request. - $this->clipboard->lockToNormal(); - - // Clean up pad - $this->clipboard->cleanCurrent(); - - // Save the clipboard content - $this->clipboard->endClipboard(); - } - /** * Generates the data for previous and next elements which is needed for movements. * diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/LayoutModule/Paste.js b/typo3/sysext/backend/Resources/Public/JavaScript/LayoutModule/Paste.js index b1c54869d8cd..2b2af4d0b17f 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/LayoutModule/Paste.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/LayoutModule/Paste.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","jquery","../AjaxDataHandler","../Modal","../Severity"],(function(t,e,a,s,n,l){"use strict";a=__importDefault(a);class o{constructor(){this.elementIdentifier=".t3js-page-ce",a.default(()=>{a.default(".t3js-page-columns").length&&this.activatePasteIcons()})}static determineColumn(t){const e=t.closest("[data-colpos]");return e.length&&"undefined"!==e.data("colpos")?e.data("colpos"):0}activatePasteIcons(){const t=this;a.default(".t3-page-ce-wrapper-new-ce").each((e,s)=>{if(a.default(s).find(".t3js-toggle-new-content-element-wizard").length&&(a.default(".t3js-page-lang-column .t3-page-ce > .t3-page-ce").removeClass("t3js-page-ce"),top.pasteAfterLinkTemplate&&top.pasteIntoLinkTemplate)){a.default(s).parent().data("page")?a.default(s).append(top.pasteIntoLinkTemplate):a.default(s).append(top.pasteAfterLinkTemplate),a.default(s).find(".t3js-paste").on("click",e=>{e.preventDefault(),t.activatePasteModal(a.default(e.currentTarget))})}})}activatePasteModal(t){const e=this,s=a.default(t),o=s.data("url")||null,d=(TYPO3.lang["paste.modal.title.paste"]||"Paste record")+': "'+s.data("title")+'"',i=TYPO3.lang["paste.modal.paste"]||"Do you want to paste the record to this position?",r=void 0!==top.TYPO3.Severity[s.data("severity")]?top.TYPO3.Severity[s.data("severity")]:top.TYPO3.Severity.info;let p=[];if(p=[{text:TYPO3.lang["paste.modal.button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",trigger:()=>{n.currentModal.trigger("modal-dismiss")}},{text:TYPO3.lang["paste.modal.button.paste"]||"Paste",btnClass:"btn-"+l.getCssClass(r),trigger:()=>{n.currentModal.trigger("modal-dismiss"),e.execute(s)}}],null!==o){const t=o.contains("?")?"&":"?",e=a.default.param({data:s.data()});n.loadUrl(d,r,p,o+t+e)}else n.show(d,i,r,p)}execute(t){const e=o.determineColumn(t),a=t.closest(this.elementIdentifier),n=a.data("uid");let l;l=void 0===n?parseInt(a.data("page"),10):0-parseInt(n,10);const d={CB:{paste:"tt_content|"+l,update:{colPos:e,sys_language_uid:parseInt(t.closest("[data-language-uid]").data("language-uid"),10)}}};s.process(d).then(t=>{t.hasErrors||window.location.reload()})}}return new o})); \ No newline at end of file +var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","jquery","../AjaxDataHandler","../Modal","../Severity","../Enum/Severity","TYPO3/CMS/Backend/Element/IconElement"],(function(t,e,a,n,s,i,o){"use strict";a=__importDefault(a);class l{constructor(){this.itemOnClipboardUid=0,this.itemOnClipboardTitle="",this.copyMode="",this.elementIdentifier=".t3js-page-ce",this.pasteAfterLinkTemplate="",this.pasteIntoLinkTemplate="",a.default(()=>{a.default(".t3js-page-columns").length&&(this.generateButtonTemplates(),this.activatePasteIcons(),this.initializeEvents())})}static determineColumn(t){const e=t.closest("[data-colpos]");return e.length&&"undefined"!==e.data("colpos")?e.data("colpos"):0}initializeEvents(){a.default(document).on("click",".t3js-paste",t=>{t.preventDefault(),this.activatePasteModal(a.default(t.currentTarget))})}generateButtonTemplates(){var t,e;this.itemOnClipboardUid&&(this.pasteAfterLinkTemplate='<button type="button" class="t3js-paste t3js-paste'+(this.copyMode?"-"+this.copyMode:"")+' t3js-paste-after btn btn-default btn-sm" title="'+(null===(t=TYPO3.lang)||void 0===t?void 0:t.pasteAfterRecord)+'"><typo3-backend-icon identifier="actions-document-paste-into" size="small"></typo3-backend-icon></button>',this.pasteIntoLinkTemplate='<button type="button" class="t3js-paste t3js-paste'+(this.copyMode?"-"+this.copyMode:"")+' t3js-paste-into btn btn-default btn-sm" title="'+(null===(e=TYPO3.lang)||void 0===e?void 0:e.pasteIntoColumn)+'"><typo3-backend-icon identifier="actions-document-paste-into" size="small"></typo3-backend-icon></button>')}activatePasteIcons(){a.default(".t3-page-ce-wrapper-new-ce").each((t,e)=>{if(a.default(e).find(".t3js-toggle-new-content-element-wizard").length&&(a.default(".t3js-page-lang-column .t3-page-ce > .t3-page-ce").removeClass("t3js-page-ce"),this.pasteAfterLinkTemplate&&this.pasteIntoLinkTemplate)){a.default(e).parent().data("page")?a.default(e).append(this.pasteIntoLinkTemplate):a.default(e).append(this.pasteAfterLinkTemplate)}})}activatePasteModal(t){const e=(TYPO3.lang["paste.modal.title.paste"]||"Paste record")+': "'+this.itemOnClipboardTitle+'"',a=TYPO3.lang["paste.modal.paste"]||"Do you want to paste the record to this position?";let n=[];n=[{text:TYPO3.lang["paste.modal.button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",trigger:()=>{s.currentModal.trigger("modal-dismiss")}},{text:TYPO3.lang["paste.modal.button.paste"]||"Paste",btnClass:"btn-"+i.getCssClass(o.SeverityEnum.warning),trigger:()=>{s.currentModal.trigger("modal-dismiss"),this.execute(t)}}],s.show(e,a,o.SeverityEnum.warning,n)}execute(t){const e=l.determineColumn(t),a=t.closest(this.elementIdentifier),s=a.data("uid");let i;i=void 0===s?parseInt(a.data("page"),10):0-parseInt(s,10);const o={CB:{paste:"tt_content|"+i,update:{colPos:e,sys_language_uid:parseInt(t.closest("[data-language-uid]").data("language-uid"),10)}}};n.process(o).then(t=>{t.hasErrors||window.location.reload()})}}return new l})); \ No newline at end of file -- GitLab