From 60239287ec8ae8076a25746dc957168a820aadd2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Joshua=20R=C3=BCsweg?= Date: Wed, 5 Jul 2017 22:02:41 +0200 Subject: [PATCH] Add trophy add form (WIP) See #2315 --- com.woltlab.wcf/acpMenu.xml | 7 + .../install/files/acp/templates/trophyAdd.tpl | 235 ++++++++++++++ .../WoltLabSuite/Core/Acp/Ui/Trophy/Badge.js | 182 +++++++++++ .../lib/acp/form/TrophyAddForm.class.php | 302 ++++++++++++++++++ wcfsetup/install/files/style/ui/trophy.scss | 18 ++ wcfsetup/install/lang/de.xml | 14 + wcfsetup/install/lang/en.xml | 14 + 7 files changed, 772 insertions(+) create mode 100644 wcfsetup/install/files/acp/templates/trophyAdd.tpl create mode 100644 wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Trophy/Badge.js create mode 100644 wcfsetup/install/files/lib/acp/form/TrophyAddForm.class.php diff --git a/com.woltlab.wcf/acpMenu.xml b/com.woltlab.wcf/acpMenu.xml index f8395b3ca2..a4e2365f7e 100644 --- a/com.woltlab.wcf/acpMenu.xml +++ b/com.woltlab.wcf/acpMenu.xml @@ -319,6 +319,13 @@ admin.trophy.canManageTrophy module_trophy + + wcf\acp\form\TrophyAddForm + wcf.acp.menu.link.trophy.list + admin.trophy.canManageTrophy + module_trophy + fa-plus + diff --git a/wcfsetup/install/files/acp/templates/trophyAdd.tpl b/wcfsetup/install/files/acp/templates/trophyAdd.tpl new file mode 100644 index 0000000000..f5d2604e3d --- /dev/null +++ b/wcfsetup/install/files/acp/templates/trophyAdd.tpl @@ -0,0 +1,235 @@ +{include file='header' pageTitle='wcf.acp.menu.link.trophy.'|concat:$action} + +{js application='wcf' file='WCF.ColorPicker' bundle='WCF.Combined'} +{include file='fontAwesomeJavaScript'} + + + +
+
+

{lang}wcf.acp.menu.link.trophy.{$action}{/lang}

+
+ + +
+ +{include file='formError'} + +{if $success|isset} +

{lang}wcf.global.success.{$action}{/lang}

+{/if} + +
+
+ +
+
+ + {if $errorField == 'title'} + + {if $errorType == 'empty'} + {lang}wcf.global.form.error.empty{/lang} + {elseif $errorType == 'multilingual'} + {lang}wcf.global.form.error.multilingual{/lang} + {/if} + + {/if} +
+ + {include file='multipleLanguageInputJavascript' elementIdentifier='title' forceSelection=false} + + +
+
+ + {if $errorField == 'description'} + + {if $errorType == 'empty'} + {lang}wcf.global.form.error.empty{/lang} + {elseif $errorType == 'multilingual'} + {lang}wcf.global.form.error.multilingual{/lang} + {/if} + + {/if} +
+ + {include file='multipleLanguageInputJavascript' elementIdentifier='description' forceSelection=false} + + +
+
+ + {if $errorField == 'categoryID'} + + {if $errorType == 'empty'} + {lang}wcf.global.form.error.empty{/lang} + {/if} + + {/if} +
+ + +
+
+
+ +
+
+ +
+
+
+ +
+
+ +
+
{lang}wcf.acp.trophy.type{/lang}
+
+ +
+
+ + {event name='dataFields'} +
+ + + + + + {event name='sections'} + + + + {event name='conditionSections'} + +
+ + {@SECURITY_TOKEN_INPUT_TAG} +
+
+ + + +{include file='footer'} diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Trophy/Badge.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Trophy/Badge.js new file mode 100644 index 0000000000..12f90db430 --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Trophy/Badge.js @@ -0,0 +1,182 @@ +/** + * Provides the trophy icon designer. + * + * @author Joshua Ruesweg + * @copyright 2001-2017 WoltLab GmbH + * @license GNU Lesser General Public License + * @module WoltLabSuite/Core/Acp/Ui/Trophy/Badge + */ +define(['Core', 'Dictionary', 'Language', 'Ui/Dialog', 'WoltLabSuite/Core/Ui/Color/Picker', 'WoltLabSuite/Core/Ui/Style/FontAwesome'], function (Core, Dictionary, Language, UiDialog, UiColorPicker, UiStyleFontAwesome) { + "use strict"; + + var _icon, _iconNameInput, _iconColorInput, _badgeColorInput, _dialogContent, _iconColor, _badgeColor; + + /** + * @exports WoltLabSuite/Core/Acp/Ui/Trophy/Badge + */ + return { + /** + * Initializes the badge designer. + */ + init: function () { + var iconContainer = elById('badgeContainer'); + elBySel('button', iconContainer).addEventListener(WCF_CLICK_EVENT, this._click.bind(this)); + + _iconNameInput = elBySel('input[name="iconName"]', iconContainer); + _iconColorInput = elBySel('input[name="iconColor"]', iconContainer); + _badgeColorInput = elBySel('input[name="badgeColor"]', iconContainer); + }, + + /** + * Opens the icon designer. + * + * @param {Event} event event object + * @protected + */ + _click: function (event) { + event.preventDefault(); + + UiDialog.open(this); + }, + + /** + * Sets the icon name. + * + * @param {string} iconName icon name + * @protected + */ + _setIcon: function (iconName) { + _icon.textContent = iconName; + + this._renderIcon(); + }, + + /** + * Sets the icon color, can be either a string or an object holding the + * individual r, g, b and a values. + * + * @param {(string|Object)} color color data + * @protected + */ + _setIconColor: function (color) { + if (typeof color !== "string") { + color = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + color.a + ')'; + } + + elData(_iconColor, 'color', color); + _iconColor.style.setProperty('background-color', color, ''); + + this._renderIcon(); + }, + + /** + * Sets the badge color, can be either a string or an object holding the + * individual r, g, b and a values. + * + * @param {(string|Object)} color color data + * @protected + */ + _setBadgeColor: function (color) { + if (typeof color !== "string") { + color = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + color.a + ')'; + } + + elData(_badgeColor, 'color', color); + _badgeColor.style.setProperty('background-color', color, ''); + + this._renderIcon(); + }, + + /** + * Renders the custom icon preview. + * + * @protected + */ + _renderIcon: function () { + var iconColor = _iconColor.style.getPropertyValue('background-color'); + var badgeColor = _badgeColor.style.getPropertyValue('background-color'); + + var icon = elBySel('.jsTrophyIcon', _dialogContent); + + // set icon + icon.className = icon.className.replace(/\b(fa-[a-z0-9\-]+)\b/, ''); + icon.classList.add('fa-' + _icon.textContent); + + icon.style.setProperty('color', iconColor, ''); + icon.style.setProperty('background-color', badgeColor, ''); + }, + + /** + * Saves the custom icon design. + * + * @param {Event} event event object + * @protected + */ + _save: function(event) { + event.preventDefault(); + + var iconColor = _iconColor.style.getPropertyValue('background-color'); + var badgeColor = _badgeColor.style.getPropertyValue('background-color'); + var icon = _icon.textContent; + + _iconNameInput.value = icon; + _badgeColorInput.value = badgeColor; + _iconColorInput.value = iconColor; + + var previewIcon = elBySel('.jsTrophyIcon', elById('iconContainer')); + + // set icon + previewIcon.className = previewIcon.className.replace(/\b(fa-[a-z0-9\-]+)\b/, ''); + previewIcon.classList.add('fa-' + icon); + previewIcon.style.setProperty('color', iconColor, ''); + previewIcon.style.setProperty('background-color', badgeColor, ''); + + UiDialog.close(this); + }, + + _dialogSetup: function () { + return { + id: 'trophyIconEditor', + options: { + onSetup: (function (context) { + _dialogContent = context; + + _iconColor = elBySel('#jsIconColorContainer .colorBoxValue', context); + _badgeColor = elBySel('#jsBadgeColorContainer .colorBoxValue', context); + _icon = elBySel('.jsTrophyIconName', context); + + elBySel('.jsTrophyIconName + .button', context).addEventListener(WCF_CLICK_EVENT, (function (event) { + event.preventDefault(); + + UiStyleFontAwesome.open(this._setIcon.bind(this)); + }).bind(this)); + + elBySel('.jsButtonIconColorPicker', elById('jsIconColorContainer')).addEventListener(WCF_CLICK_EVENT, function (event) { + event.preventDefault(); + + Core.triggerEvent(elBySel('.jsColorPicker', elById('jsIconColorContainer')), WCF_CLICK_EVENT); + }); + + elBySel('.jsButtonBadgeColorPicker', elById('jsBadgeColorContainer')).addEventListener(WCF_CLICK_EVENT, function (event) { + event.preventDefault(); + + Core.triggerEvent(elBySel('.jsColorPicker', elById('jsBadgeColorContainer')), WCF_CLICK_EVENT); + }); + + var colorPicker = new WCF.ColorPicker('.jsColorPicker'); + colorPicker.setCallbackSubmit(this._renderIcon.bind(this)); + + elBySel('.formSubmit > .buttonPrimary', context).addEventListener(WCF_CLICK_EVENT, this._save.bind(this)); + return; + }).bind(this), + onShow: (function () { + this._setIcon(_iconNameInput.value); + this._setIconColor(_iconColorInput.value); + this._setBadgeColor(_badgeColorInput.value); + }).bind(this), + title: Language.get('wcf.acp.trophy.badge.edit') + } + }; + } + }; +}); diff --git a/wcfsetup/install/files/lib/acp/form/TrophyAddForm.class.php b/wcfsetup/install/files/lib/acp/form/TrophyAddForm.class.php new file mode 100644 index 0000000000..621660086c --- /dev/null +++ b/wcfsetup/install/files/lib/acp/form/TrophyAddForm.class.php @@ -0,0 +1,302 @@ + + * @package WoltLabSuite\Core\Acp\Form + * @since 3.1 + */ +class TrophyAddForm extends AbstractAcpForm { + /** + * @inheritDoc + */ + public $activeMenuItem = 'wcf.acp.menu.link.trophy.add'; + + /** + * @inheritDoc + */ + public $neededPermissions = ['admin.trophy.canManageTrophy']; + + /** + * @inheritDoc + */ + public $neededModules = ['MODULE_TROPHY']; + + /** + * category id for the trophy. + * @var integer + */ + public $categoryID = 0; + + /** + * Category object. + * @var Category + */ + public $category = null; + + /** + * Trophy description. + * @var string + */ + public $description = ''; + + /** + * Trophy title. + * @var string + */ + public $title = ''; + + /** + * All available trophy types. + * @var [] + */ + public $availableTypes = [ + Trophy::TYPE_IMAGE => 'image', + Trophy::TYPE_BADGE => 'badge' + ]; + + /** + * Type of the trophy (whether this is an image or not) + * @var int + */ + public $type = Trophy::TYPE_BADGE; + + /** + * the location of the uploaded icon + * @var string + */ + public $uploadIconFile = ''; + + /** + * the icon name for CSS icons (FA-Icon) + * @var string + */ + public $iconName = 'trophy'; + + /** + * The icon color (rgba format with rgba prefix) + * @var string + */ + public $iconColor = 'rgba(255, 255, 255, 1)'; + + /** + * The badge color (rgba format with rgba prefix) + * @var string + */ + public $badgeColor = 'rgba(50, 92, 132, 1)'; + + /** + * `1` if the trophy is disabled. + * @var int + */ + public $isDisabled = 0; + /** + * `1` if the trophy has conditions to reward automatically trophies. + * @var int + */ + public $awardAutomatically = 0; + + /** + * list of grouped user group assignment condition object types + * @var ObjectType[][] + */ + public $conditions = []; + + /** + * @inheritDoc + */ + public function readData() { + $this->conditions = TrophyConditionHandler::getInstance()->getGroupedObjectTypes(); + + parent::readData(); + } + + /** + * @inheritDoc + */ + public function readParameters() { + parent::readParameters(); + + $titleI18n = new I18nValue('title'); + $titleI18n->setLanguageItem('wcf.trophy.title', 'wcf.trophy', 'com.woltlab.wcf'); + $this->registerI18nValue($titleI18n); + + $descriptionI18n = new I18nValue('description'); + $descriptionI18n->setLanguageItem('wcf.trophy.description', 'wcf.trophy', 'com.woltlab.wcf'); + $this->registerI18nValue($descriptionI18n); + } + + /** + * @inheritDoc + */ + public function readFormParameters() { + parent::readFormParameters(); + + if (isset($_POST['categoryID'])) $this->categoryID = intval($_POST['categoryID']); + if (isset($_POST['type'])) $this->type = intval($_POST['type']); + if (isset($_POST['isDisabled'])) $this->isDisabled = intval($_POST['isDisabled']); + if (isset($_POST['uploadIconFile'])) $this->uploadIconFile = StringUtil::trim($_POST['uploadIconFile']); + if (isset($_POST['iconName'])) $this->iconName = StringUtil::trim($_POST['iconName']); + if (isset($_POST['iconColor'])) $this->iconColor = $_POST['iconColor']; + if (isset($_POST['badgeColor'])) $this->badgeColor = $_POST['badgeColor']; + if (isset($_POST['awardAutomatically'])) $this->awardAutomatically = intval($_POST['awardAutomatically']); + + $this->category = TrophyCategoryCache::getInstance()->getCategoryByID($this->categoryID); + + foreach ($this->conditions as $conditions) { + /** @var ObjectType $condition */ + foreach ($conditions as $condition) { + $condition->getProcessor()->readFormParameters(); + } + } + } + + /** + * @inheritDoc + */ + public function validate() { + parent::validate(); + + if (!in_array($this->type, array_keys($this->availableTypes))) { + throw new UserInputException('type'); + } + + if (!$this->categoryID) { + throw new UserInputException('categoryID'); + } + + if (!$this->category->getObjectID()) { + throw new UserInputException('categoryID'); + } + + switch ($this->type) { + case Trophy::TYPE_IMAGE: + // @TODO + break; + + case Trophy::TYPE_BADGE: + if (empty($this->iconName)) { + throw new UserInputException('iconName'); + } + + if (empty($this->iconColor)) { + throw new UserInputException('iconColor'); + } + + if (empty($this->badgeColor)) { + throw new UserInputException('badgeColor'); + } + break; + } + + if ($this->awardAutomatically) { + $hasData = false; + foreach ($this->conditions as $conditions) { + foreach ($conditions as $condition) { + $condition->getProcessor()->validate(); + + if (!$hasData && $condition->getProcessor()->getData() !== null) { + $hasData = true; + } + } + } + + if (!$hasData) { + throw new UserInputException('conditions'); + } + } + } + + /** + * @inheritDoc + */ + public function save() { + parent::save(); + + $data = []; + if ($this->type == Trophy::TYPE_IMAGE) { + // @ TODO + } else if ($this->type == Trophy::TYPE_BADGE) { + $data['iconName'] = $this->iconName; + $data['iconColor'] = $this->iconColor; + $data['badgeColor'] = $this->badgeColor; + } + + $this->objectAction = new TrophyAction([], 'create', [ + 'data' => array_merge($this->additionalFields, $data, [ + 'title' => $this->title, + 'description' => $this->description, + 'categoryID' => $this->categoryID, + 'type' => $this->type, + 'isDisabled' => $this->isDisabled + ]) + ]); + $this->objectAction->executeAction(); + + // transform conditions array into one-dimensional array + $conditions = []; + foreach ($this->conditions as $groupedObjectTypes) { + $conditions = array_merge($conditions, $groupedObjectTypes); + } + + ConditionHandler::getInstance()->createConditions($this->objectAction->getReturnValues()['returnValues']->trophyID, $conditions); + + $this->reset(); + } + + /** + * @inheritDoc + */ + public function reset() { + parent::reset(); + + $this->isDisabled = $this->awardAutomatically = $this->categoryID = 0; + $this->type = Trophy::TYPE_BADGE; + $this->uploadIconFile = $this->iconName = ''; + $this->iconColor = 'rgba(255, 255, 255, 1)'; + $this->badgeColor = 'rgba(50, 92, 132, 1)'; + $this->iconName = 'trophy'; + + foreach ($this->conditions as $conditions) { + foreach ($conditions as $condition) { + $condition->getProcessor()->reset(); + } + } + } + + /** + * @inheritDoc + */ + public function assignVariables() { + parent::assignVariables(); + + WCF::getTPL()->assign([ + 'categoryID' => $this->categoryID, + 'type' => $this->type, + 'iconFile' => $this->uploadIconFile, + 'isDisabled' => $this->isDisabled, + 'iconName' => $this->iconName, + 'iconColor' => $this->iconColor, + 'badgeColor' => $this->badgeColor, + 'trophyCategories' => TrophyCategoryCache::getInstance()->getCategories(), + 'groupedObjectTypes' => $this->conditions, + 'awardAutomatically' => $this->awardAutomatically, + 'availableTypes' => $this->availableTypes + ]); + } +} diff --git a/wcfsetup/install/files/style/ui/trophy.scss b/wcfsetup/install/files/style/ui/trophy.scss index 6c7bb4cc0e..94c25b53f4 100644 --- a/wcfsetup/install/files/style/ui/trophy.scss +++ b/wcfsetup/install/files/style/ui/trophy.scss @@ -1,3 +1,21 @@ +#trophyIconEditor .colorBoxValue { + display: block; + height: 24px; + width: 24px; +} + +#trophyIconEditor .colorBox { + background-color: rgb(255, 255, 255); + border: 1px solid rgb(204, 204, 204); + display: inline-block; + padding: 1px; + vertical-align: middle; +} + +#badgeContainer .icon { + vertical-align: middle; +} + .trophyIcon { display: inline-block; border-radius: 50%; diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index e183d78b46..da181be353 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -851,6 +851,7 @@ + @@ -3578,7 +3579,20 @@ Die E-Mail-Adresse des neuen Benutzers lautet: {@$user->email} + + + + + + + + + + + + + {trophy->getTitle()} wirklich löschen?]]> diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 2a7829a08c..1b68213b5c 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -834,6 +834,7 @@ + @@ -3565,7 +3566,20 @@ Open the link below to access the user profile: + + + + + + + + + + + + + {$trophy->getTitle()}?]]> -- 2.20.1