Skip to content

Commit

Permalink
[FEATURE] Add duplicate button
Browse files Browse the repository at this point in the history
This patch provides a new "duplicate" button inside of the topbar of the
edit record form next to the close button. This button creates and opens
a new copy of the current element which is positioned right below the
existing one.
If there are unsaved changes in the currently open record, a modal
appears with options to cancel, dismiss the changes and clone or save
the changes and clone the changed record.

Resolves: #77685
Releases: master
Change-Id: I9e2a0f02fc9c4452f0a7d868ea17aeacb9375d95
Reviewed-on: https://review.typo3.org/53101
Reviewed-by: Wolfgang Klinger <wolfgang@wazum.com>
Tested-by: Wolfgang Klinger <wolfgang@wazum.com>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Mathias Schreiber <mathias.schreiber@typo3.com>
Tested-by: Mathias Schreiber <mathias.schreiber@typo3.com>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
  • Loading branch information
whmyr authored and NeoBlack committed Feb 13, 2018
1 parent 85aa890 commit 6af66f1
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 8 deletions.
95 changes: 90 additions & 5 deletions typo3/sysext/backend/Classes/Controller/EditDocumentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ public function preInit()
$this->columnsOnly = GeneralUtility::_GP('columnsOnly');
$this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
$this->closeDoc = (int)GeneralUtility::_GP('closeDoc');
$this->doSave = GeneralUtility::_GP('doSave');
$this->doSave = (bool)GeneralUtility::_GP('doSave');
$this->returnEditConf = GeneralUtility::_GP('returnEditConf');
$this->workspace = GeneralUtility::_GP('workspace');
$this->uc = GeneralUtility::_GP('uc');
Expand Down Expand Up @@ -509,6 +509,7 @@ public function doProcessData()
|| isset($_POST['_saveandclosedok'])
|| isset($_POST['_savedokview'])
|| isset($_POST['_savedoknew'])
|| isset($_POST['_duplicatedoc'])
|| isset($_POST['_translation_savedok'])
|| isset($_POST['_translation_savedokclear']);
return $out;
Expand Down Expand Up @@ -559,9 +560,11 @@ public function processData()
}

// Perform the saving operation with DataHandler:
$tce->process_uploads($_FILES);
$tce->process_datamap();
$tce->process_cmdmap();
if ($this->doSave === true) {
$tce->process_uploads($_FILES);
$tce->process_datamap();
$tce->process_cmdmap();
}
// If pages are being edited, we set an instruction about updating the page tree after this operation.
if ($tce->pagetreeNeedsRefresh
&& (isset($this->data['pages']) || $beUser->workspace != 0 && !empty($this->data))
Expand Down Expand Up @@ -666,6 +669,75 @@ public function processData()
// Re-compile the store* values since editconf changed...
$this->compileStoreDat();
}
// If a document should be duplicated.
if (isset($_POST['_duplicatedoc']) && is_array($this->editconf)) {
$this->closeDocument(self::DOCUMENT_CLOSE_MODE_NO_REDIRECT);
// Finding the current table:
reset($this->editconf);
$nTable = key($this->editconf);
// Finding the first id, getting the records pid+uid
reset($this->editconf[$nTable]);
$nUid = key($this->editconf[$nTable]);
if (!MathUtility::canBeInterpretedAsInteger($nUid)) {
$nUid = $tce->substNEWwithIDs[$nUid];
}

$recordFields = 'pid,uid';
if (!empty($GLOBALS['TCA'][$nTable]['ctrl']['versioningWS'])) {
$recordFields .= ',t3ver_oid';
}
$nRec = BackendUtility::getRecord($nTable, $nUid, $recordFields);

// Setting a blank editconf array for a new record:
$this->editconf = [];

if ($nRec['pid'] != -1) {
$relatedPageId = -$nRec['uid'];
} else {
$relatedPageId = -$nRec['t3ver_oid'];
}

/** @var $duplicateTce \TYPO3\CMS\Core\DataHandling\DataHandler */
$duplicateTce = GeneralUtility::makeInstance(DataHandler::class);

$duplicateCmd = [
$nTable => [
$nUid => [
'copy' => $relatedPageId
]
]
];

$duplicateTce->start([], $duplicateCmd);
$duplicateTce->process_cmdmap();

$duplicateMappingArray = $duplicateTce->copyMappingArray;
$duplicateUid = $duplicateMappingArray[$nTable][$nUid];

if ($nTable === 'pages') {
BackendUtility::setUpdateSignal('updatePageTree');
}

$this->editconf[$nTable][$duplicateUid] = 'edit';
// Finally, set the editconf array in the "getvars" so they will be passed along in URLs as needed.
$this->R_URL_getvars['edit'] = $this->editconf;
// Re-compile the store* values since editconf changed...
$this->compileStoreDat();

// Inform the user of the duplication
/** @var $flashMessage \TYPO3\CMS\Core\Messaging\FlashMessage */
$flashMessage = GeneralUtility::makeInstance(
FlashMessage::class,
$this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.recordDuplicated'),
'',
FlashMessage::OK
);
/** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
$flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
/** @var $defaultFlashMessageQueue FlashMessageQueue */
$defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
$defaultFlashMessageQueue->enqueue($flashMessage);
}
// If a preview is requested
if (isset($_POST['_savedokview'])) {
// Get the first table and id of the data array from DataHandler
Expand Down Expand Up @@ -1255,6 +1327,19 @@ protected function getButtons()
Icon::SIZE_SMALL
));
$buttonBar->addButton($closeButton);
// DUPLICATE button:
if ($this->firstEl['cmd'] !== 'new' && MathUtility::canBeInterpretedAsInteger($this->firstEl['uid'])) {
$duplicateButton = $buttonBar->makeLinkButton()
->setHref('#')
->setClasses('t3js-editform-duplicate')
->setShowLabelText(true)
->setTitle($lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.duplicateDoc'))
->setIcon($this->moduleTemplate->getIconFactory()->getIcon(
'actions-document-duplicates-select',
Icon::SIZE_SMALL
));
$buttonBar->addButton($duplicateButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
}
// DELETE + UNDO buttons:
if (!$this->errorC
&& !$GLOBALS['TCA'][$this->firstEl['table']]['ctrl']['readOnly']
Expand Down Expand Up @@ -1291,7 +1376,7 @@ protected function getButtons()
'uid' => $this->firstEl['uid'],
'table' => $this->firstEl['table']
]);
$buttonBar->addButton($deleteButton, ButtonBar::BUTTON_POSITION_LEFT, 3);
$buttonBar->addButton($deleteButton, ButtonBar::BUTTON_POSITION_LEFT, 4);
}
// Undo:
if ($this->getNewIconMode($this->firstEl['table'], 'showHistory')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,26 +149,32 @@ define(['jquery', 'TYPO3/CMS/Backend/Modal', 'TYPO3/CMS/Backend/Severity'], func
var url = TYPO3.settings.ajaxUrls['contextmenu_clipboard'];
url += '&CB[el][' + table + '%7C' + uid + ']=1' + '&CB[setCopyMode]=1';
$.ajax(url).always(function() {
top.TYPO3.Backend.ContentContainer.refresh(true);
ContextMenuActions.triggerRefresh(top.TYPO3.Backend.ContentContainer.get().location.href);
});
};

ContextMenuActions.clipboardRelease = function(table, uid) {
var url = TYPO3.settings.ajaxUrls['contextmenu_clipboard'];
url += '&CB[el][' + table + '%7C' + uid + ']=0';
$.ajax(url).always(function() {
top.TYPO3.Backend.ContentContainer.refresh(true);
ContextMenuActions.triggerRefresh(top.TYPO3.Backend.ContentContainer.get().location.href);
});
};

ContextMenuActions.cut = function(table, uid) {
var url = TYPO3.settings.ajaxUrls['contextmenu_clipboard'];
url += '&CB[el][' + table + '%7C' + uid + ']=1' + '&CB[setCopyMode]=0';
$.ajax(url).always(function() {
top.TYPO3.Backend.ContentContainer.refresh(true);
ContextMenuActions.triggerRefresh(top.TYPO3.Backend.ContentContainer.get().location.href);
});
};

ContextMenuActions.triggerRefresh = function (iframeUrl) {
if (iframeUrl.indexOf("record%2Fedit") === -1) {
top.TYPO3.Backend.ContentContainer.refresh(true);
}
};

/**
* Clear cache for given page uid
*
Expand Down
44 changes: 44 additions & 0 deletions typo3/sysext/backend/Resources/Public/JavaScript/FormEngine.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,50 @@ define(['jquery',
FormEngine.preventExitIfNotSaved(
FormEngine.preventExitIfNotSavedCallback
);
}).on('click', '.t3js-editform-duplicate', function(e) {
e.preventDefault();
var $elem = $('<input />').attr('type', 'hidden').attr('name', '_duplicatedoc').attr('value', '1');
if ($('form[name="' + FormEngine.formName + '"] .has-change').length > 0) {
var title = TYPO3.lang['label.confirm.duplicate_record_changed.title'] || 'Duplicate changed record?';
var content = TYPO3.lang['label.confirm.duplicate_record_changed.content'] || 'Do you want to save your changes and duplicate the record?';
var $modal = Modal.confirm(title, content, Severity.warning, [
{
text: TYPO3.lang['buttons.confirm.duplicate_record_changed.cancel'] || 'Cancel',
active: true,
btnClass: 'btn-default',
name: 'cancel'
},
{
text: TYPO3.lang['buttons.confirm.duplicate_record_changed.dismiss_and_duplicate'] || 'Dismiss changes and duplicate',
active: true,
btnClass: 'btn-default',
name: 'dismissDuplicate'
},
{
text: TYPO3.lang['buttons.confirm.duplicate_record_changed.save_and_duplicate'] || 'Save changes and duplicate',
btnClass: 'btn-success',
name: 'saveDuplicate'
}
]);
$modal.on('button.clicked', function (e) {
if (e.target.name === 'cancel') {
Modal.dismiss();
} else if (e.target.name === 'dismissDuplicate') {
$('form[name=' + FormEngine.formName + ']').append($elem);
$('input[name=doSave]').val(0);
Modal.dismiss();
document.editform.submit();
} else if (e.target.name == 'saveDuplicate') {
$('form[name=' + FormEngine.formName + ']').append($elem);
$('input[name=doSave]').val(1);
Modal.dismiss();
document.editform.submit();
}
});
} else {
$('form[name=' + FormEngine.formName + ']').append($elem);
document.editform.submit();
}
}).on('click', '.t3js-editform-delete-record', function(e) {
e.preventDefault();
var title = TYPO3.lang['label.confirm.delete_record.title'] || 'Delete this record?';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.. include:: ../../Includes.txt

==================================================================================
Feature: #77685 - Create a save and open copy button when saving a content element
==================================================================================

See :issue:`77685`

Description
===========

This patch adds a "clone content element" icon next to the save icon in the edit record form for already persisted reccords. If there are not persisted changes when pressing the button a modal appears, providing the following 3 options: abort, clone the content element without saving the current changes, save the changes and clones the record afterwards. The copy of the record will by put right below the record itself.
After saving, the edit record form opens for the copied element.


Impact
======

Editors are able to make a duplicate of a record with just a single click. They don't have to copy & paste.

.. index:: Backend
15 changes: 15 additions & 0 deletions typo3/sysext/lang/Resources/Private/Language/locallang_alt_doc.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,27 @@
<trans-unit id="noDocuments_listmodule">
<source>the Web&gt;List module</source>
</trans-unit>
<trans-unit id="buttons.confirm.duplicate_record_changed.cancel">
<source>Cancel</source>
</trans-unit>
<trans-unit id="button.confirm.duplicate_record_changed.dismiss_and_duplicate">
<source>Dismiss changes and duplicate</source>
</trans-unit>
<trans-unit id="buttons.confirm.duplicate_record_changed.save_and_duplicate">
<source>Save changes and duplicate</source>
</trans-unit>
<trans-unit id="buttons.confirm.close_without_save.yes">
<source>Yes, discard my changes</source>
</trans-unit>
<trans-unit id="buttons.confirm.close_without_save.no">
<source>No, I will continue editing</source>
</trans-unit>
<trans-unit id="label.confirm.duplicate_record_changed.title">
<source>Duplicate changed record?</source>
</trans-unit>
<trans-unit id="label.confirm.duplicate_record_changed.content">
<source>Do you want to save your changes and duplicate the record?</source>
</trans-unit>
<trans-unit id="label.confirm.close_without_save.title">
<source>Do you want to quit without saving?</source>
</trans-unit>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,12 @@ Do you want to refresh it now?</source>
<trans-unit id="rm.saveNewDoc">
<source>Save and create a new one</source>
</trans-unit>
<trans-unit id="rm.duplicateDoc">
<source>Duplicate</source>
</trans-unit>
<trans-unit id="labels.recordDuplicated">
<source>The record has been duplicated.</source>
</trans-unit>
<trans-unit id="rm.closeDoc">
<source>Close</source>
</trans-unit>
Expand Down

0 comments on commit 6af66f1

Please sign in to comment.