* Notifications for comments in moderation.
* Continuous numeration of edit history version in template.
* `\wcf\data\user\UserProfile::getGuestUserProfile()` added.
+* Make labels sortable in ACP.
#### CMS
</dl>
{include file='multipleLanguageInputJavascript' elementIdentifier='label' forceSelection=false}
+ <dl>
+ <dt><label for="showOrder">{lang}wcf.acp.label.showOrder{/lang}</label></dt>
+ <dd>
+ <input type="number" min="0" id="showOrder" name="showOrder" class="tiny" value="{if $showOrder}{@$showOrder}{/if}" />
+ <small>{lang}wcf.acp.label.showOrder.description{/lang}</small>
+ </dd>
+ </dl>
+
<dl{if $errorField == 'cssClassName'} class="formError"{/if}>
<dt><label for="cssClassName">{lang}wcf.acp.label.cssClassName{/lang}</label></dt>
<dd>
{/if}
new WCF.Table.EmptyTableHandler($('#labelTableContainer'), 'jsLabelRow', options);
+
+ {if $labelGroup && !$labelSearch && !$cssClassName && $items > 1}
+ new WCF.Sortable.List('labelTableContainer', 'wcf\\data\\label\\LabelAction', {@$startIndex}, {
+ items: 'tr',
+ toleranceElement: null
+ }, true);
+ {/if}
});
//]]>
</script>
<h1 class="contentTitle">{lang}wcf.acp.label.list{/lang}</h1>
</header>
+{if $items || $labelSearch || $labelGroup || $cssClassName}
+ <p class="info">{lang}wcf.acp.label.sortAfterGroupFiltering{/lang}</p>
+
+ <form action="{link controller='LabelList'}{/link}" method="post">
+ <section class="section">
+ <h2 class="sectionTitle">{lang}wcf.acp.label.filter{/lang}</h2>
+
+ <div class="row rowColGap">
+ <dl class="col-xs-12 col-md-4">
+ <dt><label for="label">{lang}wcf.acp.label.label{/lang}</label></dt>
+ <dd>
+ <input type="text" id="label" name="label" value="{$labelSearch}" class="long" />
+ </dd>
+ </dl>
+
+ <dl class="col-xs-12 col-md-4">
+ <dt><label for="groupID">{lang}wcf.acp.label.group{/lang}</label></dt>
+ <dd>
+ <select id="groupID" name="groupID">
+ <option value="0">{lang}wcf.global.noSelection{/lang}</option>
+ {foreach from=$labelGroupList item=group}
+ <option value="{@$group->groupID}"{if $group->groupID == $groupID} selected="selected"{/if}>{$group}{if $group->groupDescription} / {$group->groupDescription}{/if}</option>
+ {/foreach}
+ </select>
+ </dd>
+ </dl>
+
+ <dl class="col-xs-12 col-md-4">
+ <dt><label for="cssClassName">{lang}wcf.acp.label.cssClassName{/lang}</label></dt>
+ <dd>
+ <input type="text" id="cssClassName" name="cssClassName" value="{$cssClassName}" class="long" />
+ </dd>
+ </dl>
+ </div>
+ </section>
+
+ <div class="formSubmit">
+ <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
+ {@SID_INPUT_TAG}
+ {@SECURITY_TOKEN_INPUT_TAG}
+ </div>
+ </form>
+{/if}
+
<div class="contentNavigation">
- {pages print=true assign=pagesLinks controller="LabelList" link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}
+ {assign var='linkParameters' value=''}
+ {if $labelSearch}
+ {append var='linkParameters' value='&label='}
+ {append var='linkParameters' value=$labelSearch|rawurlencode}
+ {/if}
+ {if $cssClassName}
+ {append var='linkParameters' value='&cssClassName='}
+ {append var='linkParameters' value=$cssClassName|rawurlencode}
+ {/if}
+ {pages print=true assign=pagesLinks controller="LabelList" object=$labelGroup link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder$linkParameters"}
<nav>
<ul>
</div>
{if $objects|count}
- <div id="labelTableContainer" class="section tabularBox">
+ <div id="labelTableContainer" class="section tabularBox{if $labelGroup && !$labelSearch && !$cssClassName && $items > 1} sortableListContainer{/if}">
<table class="table">
<thead>
<tr>
- <th class="columnID columnLabelID{if $sortField == 'labelID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link controller='LabelList'}pageNo={@$pageNo}&sortField=labelID&sortOrder={if $sortField == 'labelID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
- <th class="columnTitle columnLabel{if $sortField == 'label'} active {@$sortOrder}{/if}"><a href="{link controller='LabelList'}pageNo={@$pageNo}&sortField=label&sortOrder={if $sortField == 'label' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.label.label{/lang}</a></th>
- <th class="columnText columnGroup{if $sortField == 'groupName'} active {@$sortOrder}{/if}"><a href="{link controller='LabelList'}pageNo={@$pageNo}&sortField=groupName&sortOrder={if $sortField == 'groupName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.label.group{/lang}</a></th>
+ <th class="columnID columnLabelID{if $sortField == 'labelID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link controller='LabelList' object=$labelGroup}pageNo={@$pageNo}&sortField=labelID&sortOrder={if $sortField == 'labelID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$linkParameters}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
+ <th class="columnTitle columnLabel{if $sortField == 'label'} active {@$sortOrder}{/if}"><a href="{link controller='LabelList' object=$labelGroup}pageNo={@$pageNo}&sortField=label&sortOrder={if $sortField == 'label' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$linkParameters}{/link}">{lang}wcf.acp.label.label{/lang}</a></th>
+ <th class="columnText columnGroup{if $sortField == 'groupName'} active {@$sortOrder}{/if}"><a href="{link controller='LabelList' object=$labelGroup}pageNo={@$pageNo}&sortField=groupName&sortOrder={if $sortField == 'groupName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$linkParameters}{/link}">{lang}wcf.acp.label.group{/lang}</a></th>
+ {if $labelGroup && !$labelSearch && !$cssClassName && $items > 1}
+ <th class="columnDigits columnShowOrder{if $sortField == 'showOrder'} active {@$sortOrder}{/if}"><a href="{link controller='LabelList' object=$labelGroup}pageNo={@$pageNo}&sortField=showOrder&sortOrder={if $sortField == 'groupName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{@$linkParameters}{/link}">{lang}wcf.acp.label.showOrder{/lang}</a></th>
+ {/if}
{event name='columnHeads'}
</tr>
</thead>
- <tbody>
+ <tbody{if $labelGroup && !$labelSearch && !$cssClassName && $items > 1} class="sortableList" data-object-id="{@$labelGroup->groupID}"{/if}>
{foreach from=$objects item=label}
- <tr class="jsLabelRow">
+ <tr class="jsLabelRow{if $labelGroup && !$labelSearch && !$cssClassName && $items > 1} sortableNode" data-object-id="{@$label->labelID}{/if}">
<td class="columnIcon">
<a href="{link controller='LabelEdit' object=$label}{/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="{@$label->labelID}" data-confirm-message="{lang}wcf.acp.label.delete.sure{/lang}"></span>
<td class="columnID">{@$label->labelID}</td>
<td class="columnTitle columnLabel"><a href="{link controller='LabelEdit' object=$label}{/link}" title="{$label}" class="badge label{if $label->getClassNames()} {$label->getClassNames()}{/if}">{$label}</a></td>
<td class="columnText columnGroup">{lang}{$label->groupName}{/lang}{if $label->groupDescription} / {$label->groupDescription}{/if}</td>
+ {if $labelGroup && !$labelSearch && !$cssClassName && $items > 1}
+ <td class="columnDigits columnShowOrder">{#$label->showOrder}</td>
+ {/if}
{event name='columns'}
</tr>
</table>
</div>
+ {if $labelGroup && !$labelSearch && !$cssClassName && $items > 1}
+ <div class="formSubmit">
+ <button data-type="submit">{lang}wcf.global.button.saveSorting{/lang}</button>
+ </div>
+ {/if}
+
<div class="contentNavigation">
{@$pagesLinks}
toleranceElement: '> span'
}, options || { });
+ var sortableList = $('#' + this._containerID + ' .sortableList');
+ if (sortableList.is('tbody') && this._options.helper === 'clone') {
+ this._options.helper = this._tableRowHelper.bind(this);
+ }
+
if (isSimpleSorting) {
- $('#' + this._containerID + ' .sortableList').sortable(this._options);
+ sortableList.sortable(this._options);
}
else {
- $('#' + this._containerID + ' > .sortableList').nestedSortable(this._options);
+ sortableList.nestedSortable(this._options);
}
if (this._className) {
}
},
+ /**
+ * Fixes the width of the cells of the dragged table row.
+ *
+ * @param {Event} event
+ * @param {jQuery} ui
+ * @return {jQuery}
+ */
+ _tableRowHelper: function(event, ui) {
+ ui.children('td').each(function(index, element) {
+ element = $(element);
+
+ element.width(element.width());
+ });
+
+ return ui;
+ },
+
/**
* Saves object structure.
*/
* Shows the label add form.
*
* @author Alexander Ebert
- * @copyright 2001-2015 WoltLab GmbH
+ * @copyright 2001-2016 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
* @subpackage acp.form
*/
class LabelAddForm extends AbstractForm {
/**
- * @see \wcf\page\AbstractPage::$activeMenuItem
+ * @inheritDoc
*/
public $activeMenuItem = 'wcf.acp.menu.link.label.add';
/**
- * @see \wcf\page\AbstractPage::$neededPermissions
+ * @inheritDoc
*/
- public $neededPermissions = array('admin.content.label.canManageLabel');
+ public $neededPermissions = ['admin.content.label.canManageLabel'];
/**
* label group id
/**
* list of pre-defined css class names
- * @var array<string>
+ * @var string[]
*/
- public $availableCssClassNames = array(
+ public $availableCssClassNames = [
'yellow',
'orange',
'brown',
'none', /* not a real value */
'custom' /* not a real value */
- );
+ ];
/**
- * @see \wcf\page\IPage::readParameters()
+ * show order
+ * @var integer
+ */
+ public $showOrder = 0;
+
+ /**
+ * @inheritDoc
*/
public function readParameters() {
parent::readParameters();
}
/**
- * @see \wcf\form\IForm::readFormParameters()
+ * @inheritDoc
*/
public function readFormParameters() {
parent::readFormParameters();
if (isset($_POST['cssClassName'])) $this->cssClassName = StringUtil::trim($_POST['cssClassName']);
if (isset($_POST['customCssClassName'])) $this->customCssClassName = StringUtil::trim($_POST['customCssClassName']);
if (isset($_POST['groupID'])) $this->groupID = intval($_POST['groupID']);
+ if (isset($_POST['showOrder'])) $this->showOrder = intval($_POST['showOrder']);
}
/**
- * @see \wcf\form\IForm::validate()
+ * @inheritDoc
*/
public function validate() {
parent::validate();
throw new UserInputException('cssClassName', 'notValid');
}
}
+
+ if ($this->showOrder < 0) $this->showOrder = 0;
}
/**
- * @see \wcf\form\IForm::save()
+ * @inheritDoc
*/
public function save() {
parent::save();
// save label
- $this->objectAction = new LabelAction(array(), 'create', array('data' => array_merge($this->additionalFields, array(
+ $this->objectAction = new LabelAction([], 'create', ['data' => array_merge($this->additionalFields, [
'label' => $this->label,
'cssClassName' => ($this->cssClassName == 'custom' ? $this->customCssClassName : $this->cssClassName),
- 'groupID' => $this->groupID
- ))));
+ 'groupID' => $this->groupID,
+ 'showOrder' => $this->showOrder
+ ])]);
$this->objectAction->executeAction();
if (!I18nHandler::getInstance()->isPlainValue('label')) {
// update group name
$labelEditor = new LabelEditor($returnValues['returnValues']);
- $labelEditor->update(array(
+ $labelEditor->update([
'label' => 'wcf.acp.label.label'.$labelID
- ));
+ ]);
}
$objectTypes = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.label.objectType');
// reset values
$this->label = $this->cssClassName = $this->customCssClassName = '';
- $this->groupID = 0;
+ $this->groupID = $this->showOrder = 0;
I18nHandler::getInstance()->reset();
// show success
- WCF::getTPL()->assign(array(
- 'success' => true
- ));
+ WCF::getTPL()->assign('success', true);
}
/**
- * @see \wcf\page\IPage::readData()
+ * @inheritDoc
*/
public function readData() {
$this->labelGroupList = new LabelGroupList();
}
/**
- * @see \wcf\page\IPage::assignVariables()
+ * @inheritDoc
*/
public function assignVariables() {
parent::assignVariables();
I18nHandler::getInstance()->assignVariables();
- WCF::getTPL()->assign(array(
+ WCF::getTPL()->assign([
'action' => 'add',
'availableCssClassNames' => $this->availableCssClassNames,
'cssClassName' => $this->cssClassName,
'customCssClassName' => $this->customCssClassName,
'groupID' => $this->groupID,
'label' => $this->label,
- 'labelGroupList' => $this->labelGroupList
- ));
+ 'labelGroupList' => $this->labelGroupList,
+ 'showOrder' => $this->showOrder
+ ]);
}
}
* Shows the label edit form.
*
* @author Alexander Ebert
- * @copyright 2001-2015 WoltLab GmbH
+ * @copyright 2001-2016 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
* @subpackage acp.form
$this->objectAction = new LabelAction(array($this->labelID), 'update', array('data' => array_merge($this->additionalFields, array(
'label' => $this->label,
'cssClassName' => ($this->cssClassName == 'custom' ? $this->customCssClassName : $this->cssClassName),
- 'groupID' => $this->groupID
+ 'groupID' => $this->groupID,
+ 'showOrder' => $this->showOrder
))));
$this->objectAction->executeAction();
}
$this->groupID = $this->labelObj->groupID;
+ $this->showOrder = $this->labelObj->showOrder;
}
}
<?php
namespace wcf\acp\page;
+use wcf\data\label\group\LabelGroup;
+use wcf\data\label\group\LabelGroupList;
+use wcf\data\label\LabelList;
+use wcf\data\language\item\LanguageItemList;
use wcf\page\SortablePage;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\language\LanguageFactory;
+use wcf\system\request\LinkHandler;
+use wcf\system\WCF;
+use wcf\util\HeaderUtil;
+use wcf\util\StringUtil;
/**
* Lists available labels
*
* @author Alexander Ebert
- * @copyright 2001-2015 WoltLab GmbH
+ * @copyright 2001-2016 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
* @subpackage acp.page
*/
class LabelListPage extends SortablePage {
/**
- * @see \wcf\page\AbstractPage::$activeMenuItem
+ * @inheritDoc
*/
public $activeMenuItem = 'wcf.acp.menu.link.label.list';
/**
- * @see \wcf\page\SortablePage::$defaultSortField
+ * @inheritDoc
*/
public $defaultSortField = 'label';
/**
- * @see \wcf\page\SortablePage::$validSortFields
+ * @inheritDoc
*/
- public $validSortFields = array('labelID', 'label', 'groupName');
+ public $validSortFields = ['labelID', 'label', 'groupName', 'showOrder'];
/**
- * @see \wcf\page\AbstractPage::$neededPermissions
+ * @inheritDoc
*/
- public $neededPermissions = array('admin.content.label.canManageLabel');
+ public $neededPermissions = ['admin.content.label.canManageLabel'];
/**
- * @see \wcf\page\MultipleLinkPage::$objectListClassName
+ * @inheritDoc
*/
- public $objectListClassName = 'wcf\data\label\LabelList';
+ public $objectListClassName = LabelList::class;
/**
- * @see \wcf\page\MultipleLinkPage::initObjectList()
+ * filter for css class name
+ * @var string
+ */
+ public $cssClassName = '';
+
+ /**
+ * if of the label group to which the displayed labels belong
+ * @var integer
+ */
+ public $groupID = 0;
+
+ /**
+ * filter for label name
+ * @var string
+ */
+ public $label = '';
+
+ /**
+ * label group to which the displayed labels belong
+ * @var LabelGroup
+ */
+ public $labelGroup = null;
+
+ /**
+ * list with available label groups
+ * @var LabelGroupList
+ */
+ public $labelGroupList = null;
+
+ /**
+ * @inheritDoc
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign([
+ 'cssClassName' => $this->cssClassName,
+ 'groupID' => $this->groupID,
+ 'labelSearch' => $this->label,
+ 'labelGroup' => $this->labelGroup,
+ 'labelGroupList' => $this->labelGroupList
+ ]);
+ }
+
+ /**
+ * @inheritDoc
*/
protected function initObjectList() {
parent::initObjectList();
$this->objectList->sqlSelects = "label_group.groupName, label_group.groupDescription";
$this->objectList->sqlJoins = "LEFT JOIN wcf".WCF_N."_label_group label_group ON (label_group.groupID = label.groupID)";
+ if ($this->labelGroup) {
+ $this->objectList->getConditionBuilder()->add('label.groupID = ?', [$this->labelGroup->groupID]);
+ }
+ if ($this->cssClassName) {
+ $this->objectList->getConditionBuilder()->add('label.cssClassName LIKE ?', ['%'.addcslashes($this->cssClassName, '_%').'%']);
+ }
+
+ if ($this->label) {
+ $languageItemList = new LanguageItemList();
+ $languageItemList->getConditionBuilder()->add('languageCategoryID = ?', [LanguageFactory::getInstance()->getCategory('wcf.acp.label')->languageCategoryID]);
+ $languageItemList->getConditionBuilder()->add('languageID = ?', [WCF::getLanguage()->languageID]);
+ $languageItemList->getConditionBuilder()->add('languageItem LIKE ?', ['wcf.acp.label.label%']);
+ $languageItemList->getConditionBuilder()->add('languageItemValue LIKE ?', ['%'.addcslashes($this->label, '_%').'%']);
+ $languageItemList->readObjects();
+
+ $labelIDs = [];
+ foreach ($languageItemList as $languageItem) {
+ $labelIDs[] = str_replace('wcf.acp.label.label', '', $languageItem->languageItem);
+ }
+
+ if (!empty($labelIDs)) {
+ $this->objectList->getConditionBuilder()->add('(label LIKE ? OR labelID IN (?))', ['%'.addcslashes($this->label, '_%').'%', $labelIDs]);
+ }
+ else {
+ $this->objectList->getConditionBuilder()->add('label LIKE ?', ['%'.addcslashes($this->label, '_%').'%',]);
+ }
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function readData() {
+ parent::readData();
+
+ $this->labelGroupList = new LabelGroupList();
+ $this->labelGroupList->readObjects();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function readParameters() {
+ parent::readParameters();
+
+ if (!empty($_POST)) {
+ $parameters = [];
+ if (!empty($_POST['groupID'])) $parameters['id'] = intval($_POST['groupID']);
+ if (!empty($_POST['label'])) $parameters['label'] = StringUtil::trim($_POST['label']);
+ if (!empty($_POST['cssClassName'])) $parameters['cssClassName'] = StringUtil::trim($_POST['cssClassName']);
+
+ if (!empty($parameters)) {
+ HeaderUtil::redirect(LinkHandler::getInstance()->getLink('LabelList', $parameters));
+ exit;
+ }
+ }
+
+ if (isset($_REQUEST['id'])) $this->groupID = intval($_REQUEST['id']);
+ if (isset($_REQUEST['label'])) $this->label = StringUtil::trim($_REQUEST['label']);
+ if (isset($_REQUEST['cssClassName'])) $this->cssClassName = StringUtil::trim($_REQUEST['cssClassName']);
+
+ if ($this->groupID) {
+ $this->labelGroup = new LabelGroup($this->groupID);
+ if (!$this->labelGroup->groupID) {
+ throw new IllegalLinkException();
+ }
+
+ $this->defaultSortField = 'showOrder';
+ }
}
}
* @property-read integer $groupID
* @property-read string $label
* @property-read string $cssClassName
+ * @property-read integer $showOrder
*/
class Label extends DatabaseObject implements IRouteController {
/**
<?php
namespace wcf\data\label;
+use wcf\data\ISortableAction;
use wcf\data\language\item\LanguageItemAction;
use wcf\data\AbstractDatabaseObjectAction;
use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\exception\UserInputException;
+use wcf\system\label\LabelHandler;
use wcf\system\WCF;
/**
* Executes label-related actions.
*
* @author Alexander Ebert
- * @copyright 2001-2015 WoltLab GmbH
+ * @copyright 2001-2016 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
* @subpackage data.label
* @category Community Framework
*/
-class LabelAction extends AbstractDatabaseObjectAction {
+class LabelAction extends AbstractDatabaseObjectAction implements ISortableAction {
/**
- * @see \wcf\data\AbstractDatabaseObjectAction::$className
+ * @inheritDoc
*/
- protected $className = 'wcf\data\label\LabelEditor';
+ protected $className = LabelEditor::class;
/**
- * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsCreate
+ * @inheritDoc
*/
- protected $permissionsCreate = array('admin.content.label.canManageLabel');
+ protected $permissionsCreate = ['admin.content.label.canManageLabel'];
/**
- * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsDelete
+ * @inheritDoc
*/
- protected $permissionsDelete = array('admin.content.label.canManageLabel');
+ protected $permissionsDelete = ['admin.content.label.canManageLabel'];
/**
- * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate
+ * @inheritDoc
*/
- protected $permissionsUpdate = array('admin.content.label.canManageLabel');
+ protected $permissionsUpdate = ['admin.content.label.canManageLabel'];
/**
- * @see \wcf\data\AbstractDatabaseObjectAction::$requireACP
+ * @inheritDoc
*/
- protected $requireACP = array('create', 'delete', 'update');
+ protected $requireACP = ['create', 'delete', 'update', 'updatePosition'];
/**
- * @see \wcf\data\AbstractDatabaseObjectAction::delete()
+ * @inheritDoc
+ */
+ public function create() {
+ $showOrder = 0;
+ if (isset($this->parameters['data']['showOrder'])) {
+ $showOrder = $this->parameters['data']['showOrder'];
+ unset($this->parameters['data']['showOrder']);
+ }
+
+ $label = parent::create();
+
+ (new LabelEditor($label))->setShowOrder($label->groupID, $showOrder);
+
+ return $label;
+ }
+
+ /**
+ * @see \wcf\data\AbstractDatabaseObjectAction::update()
+ */
+ public function update() {
+ parent::update();
+
+ // update showOrder if required
+ if (count($this->objects) === 1 && isset($this->parameters['data']['groupID']) && isset($this->parameters['data']['showOrder'])) {
+ if ($this->objects[0]->groupID != $this->parameters['data']['groupID'] || $this->objects[0]->showOrder != $this->parameters['data']['showOrder']) {
+ $this->objects[0]->setShowOrder($this->parameters['data']['groupID'], $this->parameters['data']['showOrder']);
+ }
+ }
+ }
+
+ /**
+ * @inheritDoc
*/
public function delete() {
parent::delete();
if (!empty($this->objects)) {
// identify i18n labels
- $languageVariables = array();
+ $languageVariables = [];
foreach ($this->objects as $object) {
if (preg_match('~wcf.acp.label.label\d+~', $object->label)) {
$languageVariables[] = $object->label;
// remove language variables
if (!empty($languageVariables)) {
$conditions = new PreparedStatementConditionBuilder();
- $conditions->add("languageItem IN (?)", array($languageVariables));
+ $conditions->add("languageItem IN (?)", [$languageVariables]);
$sql = "SELECT languageItemID
FROM wcf".WCF_N."_language_item
".$conditions;
$statement = WCF::getDB()->prepareStatement($sql);
$statement->execute($conditions->getParameters());
- $languageItemIDs = array();
+ $languageItemIDs = [];
while ($row = $statement->fetchArray()) {
$languageItemIDs[] = $row['languageItemID'];
}
}
}
}
+
+ /**
+ * @inheritDoc
+ */
+ public function validateUpdatePosition() {
+ WCF::getSession()->checkPermissions(['admin.content.label.canManageLabel']);
+
+ if (!isset($this->parameters['data']) || !isset($this->parameters['data']['structure']) || !is_array($this->parameters['data']['structure'])) {
+ throw new UserInputException('structure');
+ }
+
+ if (count($this->parameters['data']['structure']) !== 1) {
+ throw new UserInputException('structure');
+ }
+
+ $labelGroupID = key($this->parameters['data']['structure']);
+ $labelGroup = LabelHandler::getInstance()->getLabelGroup($labelGroupID);
+ if ($labelGroup === null) {
+ throw new UserInputException('structure');
+ }
+
+ $labelIDs = $this->parameters['data']['structure'][$labelGroupID];
+
+ if (!empty(array_diff($labelIDs, $labelGroup->getLabelIDs()))) {
+ throw new UserInputException('structure');
+ }
+
+ $this->readInteger('offset', true, 'data');
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function updatePosition() {
+ $sql = "UPDATE wcf".WCF_N."_label
+ SET showOrder = ?
+ WHERE labelID = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+
+ $showOrder = $this->parameters['data']['offset'];
+
+ WCF::getDB()->beginTransaction();
+ foreach ($this->parameters['data']['structure'] as $labelIDs) {
+ foreach ($labelIDs as $labelID) {
+ $statement->execute(array(
+ $showOrder++,
+ $labelID
+ ));
+ }
+ }
+ WCF::getDB()->commitTransaction();
+ }
}
use wcf\data\DatabaseObjectEditor;
use wcf\data\IEditableCachedObject;
use wcf\system\cache\builder\LabelCacheBuilder;
+use wcf\system\WCF;
/**
* Provides functions to edit labels.
*
* @author Alexander Ebert
- * @copyright 2001-2015 WoltLab GmbH
+ * @copyright 2001-2016 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
* @subpackage data.label
*/
class LabelEditor extends DatabaseObjectEditor implements IEditableCachedObject {
/**
- * @see \wcf\data\DatabaseObjectEditor::$baseClass
+ * @inheritDoc
*/
- protected static $baseClass = 'wcf\data\label\Label';
+ protected static $baseClass = Label::class;
/**
- * @see \wcf\data\IEditableCachedObject::resetCache()
+ * @inheritDoc
*/
public static function resetCache() {
LabelCacheBuilder::getInstance()->reset();
}
+
+ /**
+ * Adds the label to a specific position in the label group.
+ *
+ * @param integer $groupID
+ * @param integer $showOrder
+ */
+ public function setShowOrder($groupID, $showOrder = 0) {
+ // shift back labels in old label group with higher showOrder
+ if ($this->showOrder) {
+ $sql = "UPDATE wcf".WCF_N."_label
+ SET showOrder = showOrder - 1
+ WHERE groupID = ?
+ AND showOrder >= ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute([$this->groupID, $this->showOrder]);
+ }
+
+ // shift labels in new label group with higher showOrder
+ if ($showOrder) {
+ $sql = "UPDATE wcf".WCF_N."_label
+ SET showOrder = showOrder + 1
+ WHERE groupID = ?
+ AND showOrder >= ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute([$groupID, $showOrder]);
+ }
+
+ // get maximum existing show order
+ $sql = "SELECT MAX(showOrder)
+ FROM wcf".WCF_N."_label
+ WHERE groupID = ?";
+ $statement = WCF::getDB()->prepareStatement($sql);
+ $statement->execute([$groupID]);
+ $maxShowOrder = $statement->fetchColumn() ?: 0;
+
+ if (!$showOrder || $showOrder > $maxShowOrder) {
+ $showOrder = $maxShowOrder + 1;
+ }
+
+ $this->update(['showOrder' => $showOrder]);
+ }
}
* Represents a list of labels.
*
* @author Alexander Ebert
- * @copyright 2001-2015 WoltLab GmbH
+ * @copyright 2001-2016 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
* @subpackage data.label
*/
class LabelList extends DatabaseObjectList {
/**
- * @see \wcf\data\DatabaseObjectList::$className
+ * @inheritDoc
*/
- public $className = 'wcf\data\label\Label';
+ public $className = Label::class;
+
+ /**
+ * @inheritDoc
+ */
+ public $sqlOrderBy = 'label.showOrder ASC, label.labelID ASC';
}
* Caches labels and groups.
*
* @author Alexander Ebert
- * @copyright 2001-2015 WoltLab GmbH
+ * @copyright 2001-2016 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package com.woltlab.wcf
* @subpackage system.cache.builder
*/
class LabelCacheBuilder extends AbstractCacheBuilder {
/**
- * @see \wcf\system\cache\builder\AbstractCacheBuilder::rebuild()
+ * @inheritDoc
*/
protected function rebuild(array $parameters) {
- $data = array(
- 'options' => array(),
- 'groups' => array()
- );
+ $data = [
+ 'options' => [],
+ 'groups' => []
+ ];
// get label groups
$groupList = new LabelGroupList();
if (count($groupList)) {
// get labels
$labelList = new LabelList();
- $labelList->sqlOrderBy = 'label';
$labelList->readObjects();
foreach ($labelList as $label) {
$data['groups'][$label->groupID]->addLabel($label);
-.sortableList {
+.sortableList:not(.tabularList) {
list-style: decimal outside;
margin-left: 20px;
}
--- /dev/null
+tr.sortableNode {
+ cursor: move;
+}
<item name="wcf.acp.label.defaultValue"><![CDATA[Label]]></item>
<item name="wcf.acp.label.delete.sure"><![CDATA[Wollen Sie das Label „{$label}“ wirklich löschen?]]></item>
<item name="wcf.acp.label.edit"><![CDATA[Label bearbeiten]]></item>
+ <item name="wcf.acp.label.edit"><![CDATA[Label bearbeiten]]></item>
<item name="wcf.acp.label.error.noGroups"><![CDATA[Bevor Sie ein Label hinzufügen können, müssen Sie eine <a href="{link controller='LabelGroupAdd'}{/link}">Labelgruppe hinzufügen</a>.]]></item>
<item name="wcf.acp.label.group"><![CDATA[Labelgruppe]]></item>
<item name="wcf.acp.label.group.add"><![CDATA[Labelgruppe hinzufügen]]></item>
<item name="wcf.acp.label.list"><![CDATA[Labels]]></item>
<item name="wcf.acp.label.group.groupName.description"><![CDATA[Der Titel ist für alle Benutzer sichtbar, die Zugriff auf diese Labelgruppe haben.]]></item>
<item name="wcf.acp.label.group.groupDescription.description"><![CDATA[Die optionale Beschreibung wird nur in der Administrationsoberfläche angezeigt.]]></item>
+ <item name="wcf.acp.label.showOrder"><![CDATA[Reihenfolge]]></item>
+ <item name="wcf.acp.label.showOrder.description"><![CDATA[Reihenfolge des Labels innerhalb seiner Labelgruppe. Wenn Sie das Feld leer lassen, wird das Label an letzter Position einsortiert.]]></item>
+ <item name="wcf.acp.label.sortAfterGroupFiltering"><![CDATA[Wenn Sie die Label-Liste nur nach einer bestimmten Labelgruppe filtern, können Sie die Labels innerhalb dieser Gruppe durch Ziehen und Loslassen sortieren.]]></item>
+ <item name="wcf.acp.label.filter"><![CDATA[Filter]]></item>
</category>
<category name="wcf.acp.language">
<item name="wcf.acp.label.list"><![CDATA[Labels]]></item>
<item name="wcf.acp.label.group.groupName.description"><![CDATA[The title is visible for every user who can interact with the label group.]]></item>
<item name="wcf.acp.label.group.groupDescription.description"><![CDATA[This optional description is visible in the Administration Control Panel only and is intended to help telling groups with the same title apart.]]></item>
+ <item name="wcf.acp.label.showOrder"><![CDATA[Display Order]]></item>
+ <item name="wcf.acp.label.showOrder.description"><![CDATA[Display order of the label in its label group. If you leave this field empty, the label will be placed at the last position.]]></item>
+ <item name="wcf.acp.label.sortAfterGroupFiltering"><![CDATA[If you only filter the label list by a certain label group, you can sort the labels in this group using drag and drop.]]></item>
+ <item name="wcf.acp.label.filter"><![CDATA[Filter]]></item>
</category>
<category name="wcf.acp.language">
labelID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
groupID INT(10) NOT NULL,
label VARCHAR(80) NOT NULL,
- cssClassName VARCHAR(255) NOT NULL DEFAULT ''
+ cssClassName VARCHAR(255) NOT NULL DEFAULT '',
+ showOrder INT(10) NOT NULL DEFAULT 0
);
DROP TABLE IF EXISTS wcf1_label_group;