{include file='header' pageTitle='wcf.acp.template.group.'|concat:$action}
+{if $action === 'edit'}
+ <script data-relocate="true">
+ require(['Language', 'WoltLabSuite/Core/Acp/Ui/Template/Group/Copy'], function (Language, AcpUiTemplateGroupCopy) {
+ Language.addObject({
+ 'wcf.acp.template.group.copy': '{lang}wcf.acp.template.group.copy{/lang}',
+ 'wcf.acp.template.group.name.error.notUnique': '{lang}wcf.acp.template.group.name.error.notUnique{/lang}',
+ 'wcf.acp.template.group.folderName': '{lang}wcf.acp.template.group.folderName{/lang}',
+ 'wcf.acp.template.group.folderName.error.invalid': '{lang}wcf.acp.template.group.folderName.error.invalid{/lang}',
+ 'wcf.acp.template.group.folderName.error.notUnique': '{lang}wcf.acp.template.group.folderName.error.notUnique{/lang}',
+ 'wcf.global.name': '{lang}wcf.global.name{/lang}'
+ });
+
+ AcpUiTemplateGroupCopy.init({$templateGroupID});
+ });
+ </script>
+{/if}
+
<header class="contentHeader">
<div class="contentHeaderTitle">
<h1 class="contentTitle">{lang}wcf.acp.template.group.{$action}{/lang}</h1>
<nav class="contentHeaderNavigation">
<ul>
+ {if $action === 'edit'}<li><a href="#" class="jsButtonCopy button"><span class="icon icon16 fa-files-o"></span> <span>{lang}wcf.acp.template.group.copy{/lang}</span></a></li>{/if}
<li><a href="{link controller='TemplateGroupList'}{/link}" class="button"><span class="icon icon16 fa-list"></span> <span>{lang}wcf.acp.menu.link.template.group.list{/lang}</span></a></li>
{event name='contentHeaderNavigation'}
{if $errorField == 'parentTemplateGroupID'}
<small class="innerError">
{if $errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
+ {lang}wcf.global.form.error.empty{/lang}
{else}
- {lang}wcf.acp.template.group.parentTemplateGroupID.error.{@$errorType}{/lang}
+ {lang}wcf.acp.template.group.parentTemplateGroupID.error.{@$errorType}{/lang}
{/if}
</small>
{/if}
{foreach from=$objects item=templateGroup}
<tr class="jsTemplateGroupRow">
<td class="columnIcon">
- {if !$templateGroup->isImmutable()}
- <a href="{link controller='TemplateGroupEdit' id=$templateGroup->templateGroupID}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip"><span class="icon icon16 fa-pencil"></span></a>
- <span class="icon icon16 fa-times jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{@$templateGroup->templateGroupID}" data-confirm-message-html="{lang __encode=true}wcf.acp.template.group.delete.sure{/lang}"></span>
- {else}
+ {if $templateGroup->isImmutable()}
<span class="icon icon16 fa-pencil disabled" title="{lang}wcf.global.button.edit{/lang}"></span>
+ {else}
+ <a href="{link controller='TemplateGroupEdit' id=$templateGroup->templateGroupID}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip"><span class="icon icon16 fa-pencil"></span></a>
+ {/if}
+
+ <a href="{link controller='TemplateList' templateGroupID=$templateGroup->templateGroupID}{/link}" title="{lang}wcf.acp.template.list{/lang}" class="jsTooltip"><span class="icon icon16 fa-list"></span></a>
+
+ {if $templateGroup->isImmutable()}
<span class="icon icon16 fa-times disabled" title="{lang}wcf.global.button.delete{/lang}"></span>
+ {else}
+ <span class="icon icon16 fa-times jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{@$templateGroup->templateGroupID}" data-confirm-message-html="{lang __encode=true}wcf.acp.template.group.delete.sure{/lang}"></span>
{/if}
{event name='rowButtons'}
--- /dev/null
+/**
+ * Provides a dialog to copy an existing template group.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2017 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Acp/Ui/Template/Group/Copy
+ */
+define(['Ajax', 'EventKey', 'Language', 'Ui/Dialog', 'Ui/Notification'], function(Ajax, EventKey, Language, UiDialog, UiNotification) {
+ "use strict";
+
+ var _name = null;
+ var _folderName = null;
+ var _templateGroupId = 0;
+
+ /**
+ * @exports WoltLabSuite/Core/Acp/Ui/Template/Group/Copy
+ */
+ return {
+ /**
+ * Initializes the dialog handler.
+ *
+ * @param {int} templateGroupId
+ */
+ init: function (templateGroupId) {
+ _templateGroupId = templateGroupId;
+
+ elBySel('.jsButtonCopy').addEventListener(WCF_CLICK_EVENT, this._click.bind(this));
+ },
+
+ /**
+ * Handles clicks on the 'Copy Template Group' button.
+ *
+ * @param {Event} event
+ * @protected
+ */
+ _click: function (event) {
+ event.preventDefault();
+
+ UiDialog.open(this);
+ },
+
+ /**
+ * Submits the values for the new template group.
+ *
+ * @param {Event} event
+ * @protected
+ */
+ _submit: function (event) {
+ event.preventDefault();
+
+ var valid = true;
+ [_name, _folderName].forEach(function (input) {
+ if (input.value.trim() === '') {
+ elInnerError(input, Language.get('wcf.global.form.error.empty'));
+ valid = false;
+ }
+ else {
+ elInnerError(input, false);
+ }
+ });
+
+ if (valid) {
+ Ajax.api(this, {
+ parameters: {
+ templateGroupName: _name.value,
+ templateGroupFolderName: _folderName.value
+ }
+ });
+ }
+ },
+
+ _ajaxSuccess: function (data) {
+ UiDialog.close(this);
+
+ UiNotification.show(undefined, function () {
+ //noinspection JSUnresolvedVariable
+ window.location = data.returnValues.redirectURL;
+ });
+ },
+
+ _dialogSetup: function () {
+ return {
+ id: 'templateGroupCopy',
+ options: {
+ onSetup: (function (content) {
+ ['Name', 'FolderName'].forEach((function(type) {
+ var input = elById('copyTemplateGroup' + type);
+ input.value = elById('templateGroup' + type).value;
+
+ if (type === 'Name') _name = input;
+ else _folderName = input;
+
+ input.addEventListener('keydown', (function (event) {
+ if (EventKey.Enter(event)) {
+ this._submit(event);
+ }
+ }).bind(this));
+ }).bind(this));
+
+ elBySel('.formSubmit > button[data-type="submit"]', content).addEventListener(WCF_CLICK_EVENT, this._submit.bind(this));
+ }).bind(this),
+ title: Language.get('wcf.acp.template.group.copy')
+ },
+ source: '<dl>' +
+ '<dt><label for="copyTemplateGroupName">' + Language.get('wcf.global.name') + '</label></dt>' +
+ '<dd><input type="text" id="copyTemplateGroupName" class="long"></dd>' +
+ '</dl>' +
+ '<dl>' +
+ '<dt><label for="copyTemplateGroupFolderName">' + Language.get('wcf.acp.template.group.folderName') + '</label></dt>' +
+ '<dd><input type="text" id="copyTemplateGroupFolderName" class="long"></dd>' +
+ '</dl>' +
+ '<div class="formSubmit">' +
+ '<button class="buttonPrimary" data-type="submit">' + Language.get('wcf.global.button.submit') + '</button>' +
+ '</div>'
+ }
+ },
+
+ _ajaxSetup: function () {
+ return {
+ data: {
+ actionName: 'copy',
+ className: 'wcf\\data\\template\\group\\TemplateGroupAction',
+ objectIDs: [_templateGroupId]
+ },
+ /** @var {{returnValues:{fieldName: string, errorType: string}}} data */
+ failure: function (data) {
+ if (data && data.returnValues && data.returnValues.fieldName && data.returnValues.errorType) {
+ if (data.returnValues.fieldName === 'templateGroupName') {
+ elInnerError(_name, Language.get('wcf.acp.template.group.name.error.' + data.returnValues.errorType));
+ }
+ else {
+ elInnerError(_folderName, Language.get('wcf.acp.template.group.folderName.error.' + data.returnValues.errorType));
+ }
+
+ return false;
+ }
+ }
+ }
+ }
+ };
+});
*
* @exports WoltLabSuite/Core/Ui/Confirmation
*/
- var UiConfirmation = {
+ return {
/**
* Shows the confirmation dialog.
*
_confirmButton.focus();
}
};
-
- return UiConfirmation;
});
<?php
namespace wcf\data\template\group;
use wcf\data\AbstractDatabaseObjectAction;
+use wcf\data\template\Template;
+use wcf\data\template\TemplateAction;
+use wcf\data\template\TemplateList;
+use wcf\system\exception\UserInputException;
+use wcf\system\request\LinkHandler;
+use wcf\system\WCF;
/**
* Executes template group-related actions.
/**
* @inheritDoc
*/
- protected $requireACP = ['create', 'delete', 'update'];
+ protected $requireACP = ['copy', 'create', 'delete', 'update'];
+
+ /**
+ * @var TemplateGroupEditor
+ */
+ public $templateGroupEditor;
+
+ /**
+ * Validates the parameters to copy an existing template group.
+ *
+ * @throws UserInputException
+ */
+ public function validateCopy() {
+ WCF::getSession()->checkPermissions(['admin.template.canManageTemplate']);
+
+ $this->readString('templateGroupName');
+ $this->readString('templateGroupFolderName');
+
+ $this->templateGroupEditor = $this->getSingleObject();
+
+ // validate name
+ $sql = "SELECT COUNT(*)
+ FROM wcf".WCF_N."_template_group
+ WHERE templateGroupName = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute([$this->parameters['templateGroupName']]);
+
+ if ($statement->fetchSingleColumn()) {
+ throw new UserInputException('templateGroupName', 'notUnique');
+ }
+
+ // validate folder name
+ if (!preg_match('/^[a-z0-9_\- ]+\/$/i', $this->parameters['templateGroupFolderName'])) {
+ throw new UserInputException('templateGroupFolderName', 'invalid');
+ }
+
+ $sql = "SELECT COUNT(*)
+ FROM wcf".WCF_N."_template_group
+ WHERE templateGroupFolderName = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute([$this->parameters['templateGroupFolderName']]);
+
+ if ($statement->fetchSingleColumn()) {
+ throw new UserInputException('templateGroupFolderName', 'notUnique');
+ }
+ }
+
+ /**
+ * Copies an existing template group.
+ *
+ * @return string[]
+ */
+ public function copy() {
+ // create a new template group
+ $returnValues = (new TemplateGroupAction([], 'create', [
+ 'data' => [
+ 'parentTemplateGroupID' => ($this->templateGroupEditor->parentTemplateGroupID ?: null),
+ 'templateGroupName' => $this->parameters['templateGroupName'],
+ 'templateGroupFolderName' => $this->parameters['templateGroupFolderName']
+ ]
+ ]))->executeAction();
+ /** @var TemplateGroup $templateGroup */
+ $templateGroup = $returnValues['returnValues'];
+
+ // copy over the templates
+ $templateList = new TemplateList();
+ $templateList->getConditionBuilder()->add("template.templateGroupID = ?", [$this->templateGroupEditor->templateGroupID]);
+ $templateList->readObjects();
+
+ /** @var Template $template */
+ foreach ($templateList as $template) {
+ (new TemplateAction([], 'create', [
+ 'data' => [
+ 'application' => $template->application,
+ 'templateName' => $template->templateName,
+ 'packageID' => $template->packageID,
+ 'templateGroupID' => $templateGroup->templateGroupID
+ ],
+ 'source' => $template->getSource()
+ ]))->executeAction();
+ }
+
+ return [
+ 'redirectURL' => LinkHandler::getInstance()->getLink(
+ 'TemplateGroupEdit', [
+ 'isACP' => true,
+ 'id' => $templateGroup->templateGroupID
+ ]
+ )
+ ];
+ }
}
<item name="wcf.acp.template.lastModificationTime"><![CDATA[Letzte Änderung]]></item>
<item name="wcf.acp.template.group.list"><![CDATA[Templategruppen]]></item>
<item name="wcf.acp.template.group.add"><![CDATA[Templategruppe hinzufügen]]></item>
+ <item name="wcf.acp.template.group.copy"><![CDATA[Templategruppe kopieren]]></item>
<item name="wcf.acp.template.group.edit"><![CDATA[Templategruppe bearbeiten]]></item>
<item name="wcf.acp.template.group.templates"><![CDATA[Templates]]></item>
<item name="wcf.acp.template.error.noGroups"><![CDATA[Bevor {if LANGUAGE_USE_INFORMAL_VARIANT}du{else}Sie{/if} ein eigenes Template erstellen {if LANGUAGE_USE_INFORMAL_VARIANT}kannst{else}können{/if}, {if LANGUAGE_USE_INFORMAL_VARIANT}musst du{else}müssen Sie{/if} eine <a href="{link controller='TemplateGroupAdd'}{/link}">Templategruppe hinzufügen</a>.]]></item>
<item name="wcf.acp.template.lastModificationTime"><![CDATA[Last Modification]]></item>
<item name="wcf.acp.template.group.list"><![CDATA[Template Groups]]></item>
<item name="wcf.acp.template.group.add"><![CDATA[Add Template Group]]></item>
+ <item name="wcf.acp.template.group.copy"><![CDATA[Copy Template Group]]></item>
<item name="wcf.acp.template.group.edit"><![CDATA[Edit Template Group]]></item>
<item name="wcf.acp.template.group.templates"><![CDATA[Templates]]></item>
<item name="wcf.acp.template.error.noGroups"><![CDATA[You must create a <a href="{link controller='TemplateGroupAdd'}{/link}">template group</a> first.]]></item>