{include file='header' pageTitle='wcf.acp.menu.item.'|concat:$action}
-<script data-relocate="true">
- require(['Dictionary', 'Language', 'WoltLabSuite/Core/Acp/Ui/Menu/Item/Handler'], function(Dictionary, Language, AcpUiMenuItemHandler) {
- Language.addObject({
- 'wcf.page.pageObjectID': '{jslang}wcf.page.pageObjectID{/jslang}',
- {foreach from=$pageNodeList item=pageNode}
- {capture assign='pageObjectIDLanguageItem'}{lang __optional=true}wcf.page.pageObjectID.{@$pageNode->identifier}{/lang}{/capture}
- {if $pageObjectIDLanguageItem}
- 'wcf.page.pageObjectID.{@$pageNode->identifier}': '{@$pageObjectIDLanguageItem|encodeJS}',
- {/if}
- {capture assign='pageObjectIDLanguageItem'}{lang __optional=true}wcf.page.pageObjectID.search.{@$pageNode->identifier}{/lang}{/capture}
- {if $pageObjectIDLanguageItem}
- 'wcf.page.pageObjectID.search.{@$pageNode->identifier}': '{@$pageObjectIDLanguageItem|encodeJS}',
- {/if}
- {/foreach}
- 'wcf.page.pageObjectID.search.noResults': '{jslang}wcf.page.pageObjectID.search.noResults{/jslang}',
- 'wcf.page.pageObjectID.search.results': '{jslang}wcf.page.pageObjectID.search.results{/jslang}',
- 'wcf.page.pageObjectID.search.terms': '{jslang}wcf.page.pageObjectID.search.terms{/jslang}'
- });
-
- var handlers = new Dictionary();
- {foreach from=$pageHandlers key=handlerPageID item=requireObjectID}
- handlers.set({@$handlerPageID}, {if $requireObjectID}true{else}false{/if});
- {/foreach}
-
- AcpUiMenuItemHandler.init(handlers);
- });
-</script>
-
<header class="contentHeader">
<div class="contentHeaderTitle">
<h1 class="contentTitle">{lang}wcf.acp.menu.item.{$action}{/lang}</h1>
<div class="dropdownMenu">
<ul class="scrollableDropdownMenu">
{foreach from=$menuItemNodeList item='menuItemNode'}
- <li{if $menuItemNode->itemID == $itemID} class="active"{/if}><a href="{link controller='MenuItemEdit' object=$menuItemNode}{/link}">{if $menuItemNode->getDepth() > 1}{@" "|str_repeat:($menuItemNode->getDepth() - 1)}{/if}{$menuItemNode->getTitle()}</a></li>
+ <li{if $menuItemNode->itemID == $formObject->itemID} class="active"{/if}><a href="{link controller='MenuItemEdit' object=$menuItemNode}{/link}">{if $menuItemNode->getDepth() > 1}{@" "|str_repeat:($menuItemNode->getDepth() - 1)}{/if}{$menuItemNode->getTitle()}</a></li>
{/foreach}
</ul>
</div>
</nav>
</header>
-{include file='shared_formNotice'}
-
-<form method="post" action="{if $action == 'add'}{link controller='MenuItemAdd'}{/link}{else}{link controller='MenuItemEdit' id=$itemID}{/link}{/if}">
- <div class="section">
- <dl{if $errorField == 'parentItemID'} class="formError"{/if}>
- <dt><label for="parentItemID">{lang}wcf.acp.menu.item.parentItem{/lang}</label></dt>
- <dd>
- <select name="parentItemID" id="parentItemID">
- <option value="0">{lang}wcf.global.noSelection{/lang}</option>
-
- {foreach from=$menuItemNodeList item=menuItemNode}
- <option
- value="{$menuItemNode->itemID}"
- {if $menuItemNode->itemID == $parentItemID} selected{/if}
- {if $action === 'edit' && $menuItemNode->itemID == $itemID} disabled{/if}
- >
- {if $menuItemNode->getDepth() > 1}{@" "|str_repeat:($menuItemNode->getDepth() - 1)}{/if}{$menuItemNode->getTitle()}
- </option>
- {/foreach}
- </select>
- {if $errorField == 'parentItemID'}
- <small class="innerError">
- {if $errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
- {else}
- {lang}wcf.acp.menu.item.parentItemID.error.{$errorType}{/lang}
- {/if}
- </small>
- {/if}
- </dd>
- </dl>
-
- <dl{if $errorField == 'title'} class="formError"{/if}>
- <dt><label for="title">{lang}wcf.global.name{/lang}</label></dt>
- <dd>
- <input type="text" name="title" id="title" value="{$i18nPlainValues['title']}" maxlength="255" class="long" required>
- {if $errorField == 'title'}
- <small class="innerError">
- {if $errorType == 'empty' || $errorType == 'multilingual'}
- {lang}wcf.global.form.error.{@$errorType}{/lang}
- {else}
- {lang}wcf.acp.menu.item.title.error.{$errorType}{/lang}
- {/if}
- </small>
- {/if}
-
- {include file='shared_multipleLanguageInputJavascript' elementIdentifier='title' forceSelection=false}
- </dd>
- </dl>
-
- <dl>
- <dt><label for="showOrder">{lang}wcf.global.showOrder{/lang}</label></dt>
- <dd>
- <input type="number" name="showOrder" id="showOrder" value="{$showOrder}" class="tiny" min="0">
- </dd>
- </dl>
-
- <dl>
- <dt></dt>
- <dd>
- <label><input type="checkbox" name="isDisabled" id="isDisabled" value="1"{if $isDisabled} checked{/if}> <span>{lang}wcf.acp.menu.item.isDisabled{/lang}</span></label>
- </dd>
- </dl>
-
- {event name='dataFields'}
- </div>
-
- <section class="section">
- <h2 class="sectionTitle">{lang}wcf.acp.menu.item.link{/lang}</h2>
-
- <dl>
- <dt></dt>
- <dd class="floated">
- <label><input type="radio" name="isInternalLink" value="1"{if $isInternalLink} checked{/if}> {lang}wcf.acp.menu.item.link.internal{/lang}</label>
- <label><input type="radio" name="isInternalLink" value="0"{if !$isInternalLink} checked{/if}> {lang}wcf.acp.menu.item.link.external{/lang}</label>
- </dd>
- </dl>
-
- <dl id="pageIDContainer"{if $errorField == 'pageID'} class="formError"{/if}{if !$isInternalLink} style="display: none;"{/if}>
- <dt><label for="pageID">{lang}wcf.acp.page.page{/lang}</label></dt>
- <dd>
- <select name="pageID" id="pageID">
- <option value="0">{lang}wcf.global.noSelection{/lang}</option>
-
- {foreach from=$pageNodeList item=pageNode}
- {if !$pageNode->requireObjectID || $pageHandlers[$pageNode->pageID]|isset}
- <option value="{$pageNode->pageID}"{if $pageNode->pageID == $pageID} selected{/if} data-identifier="{@$pageNode->identifier}">{if $pageNode->getDepth() > 1}{@" "|str_repeat:($pageNode->getDepth() - 1)}{/if}{$pageNode->name}</option>
- {/if}
- {/foreach}
- </select>
- {if $errorField == 'pageID'}
- <small class="innerError">
- {if $errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
- {else}
- {lang}wcf.acp.menu.item.pageID.error.{@$errorType}{/lang}
- {/if}
- </small>
- {/if}
- </dd>
- </dl>
-
- <dl id="pageObjectIDContainer"{if $errorField == 'pageObjectID'} class="formError"{/if}{if !$pageID || !$pageHandler[$pageID]|isset} style="display: none;"{/if}>
- <dt><label for="pageObjectID">{lang}wcf.page.pageObjectID{/lang}</label></dt>
- <dd>
- <div class="inputAddon">
- <input type="text" id="pageObjectID" name="pageObjectID" value="{$pageObjectID}" class="short">
- <a href="#" id="searchPageObjectID" class="inputSuffix button jsTooltip" title="{lang}wcf.page.pageObjectID.search{/lang}">{icon name='magnifying-glass'}</a>
- </div>
- {if $errorField == 'pageObjectID'}
- <small class="innerError">
- {if $errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
- {else}
- {lang}wcf.acp.menu.item.pageObjectID.error.{@$errorType}{/lang}
- {/if}
- </small>
- {/if}
- </dd>
- </dl>
-
- <dl id="externalURLContainer"{if $errorField == 'externalURL'} class="formError"{/if}{if $isInternalLink} style="display: none;"{/if}>
- <dt><label for="externalURL">{lang}wcf.acp.menu.item.externalURL{/lang}</label></dt>
- <dd>
- <input type="text" name="externalURL" id="externalURL" value="{$externalURL}" class="long" maxlength="255" placeholder="http://">
- {if $errorField == 'externalURL'}
- <small class="innerError">
- {if $errorType == 'empty'}
- {lang}wcf.global.form.error.empty{/lang}
- {else}
- {lang}wcf.acp.menu.item.externalURL.error.{$errorType}{/lang}
- {/if}
- </small>
- {/if}
-
- {include file='shared_multipleLanguageInputJavascript' elementIdentifier='externalURL' forceSelection=false}
- </dd>
- </dl>
-
- {event name='linkFields'}
- </section>
-
- {event name='sections'}
-
- <div class="formSubmit">
- <input type="submit" value="{lang}wcf.global.button.submit{/lang}">
- {if $action == 'add'}<input type="hidden" name="menuID" value="{$menuID}">{/if}
- {csrfToken}
- </div>
-</form>
+{unsafe:$form->getHtml()}
{include file='footer'}
use wcf\data\menu\item\MenuItem;
use wcf\data\menu\item\MenuItemAction;
-use wcf\data\menu\item\MenuItemEditor;
use wcf\data\menu\item\MenuItemNodeTree;
use wcf\data\menu\Menu;
use wcf\data\page\Page;
use wcf\data\page\PageNodeTree;
-use wcf\form\AbstractForm;
+use wcf\form\AbstractFormBuilderForm;
use wcf\system\exception\IllegalLinkException;
-use wcf\system\exception\UserInputException;
-use wcf\system\language\I18nHandler;
+use wcf\system\form\builder\container\FormContainer;
+use wcf\system\form\builder\data\processor\CustomFormDataProcessor;
+use wcf\system\form\builder\field\BooleanFormField;
+use wcf\system\form\builder\field\dependency\ValueFormFieldDependency;
+use wcf\system\form\builder\field\IntegerFormField;
+use wcf\system\form\builder\field\RadioButtonFormField;
+use wcf\system\form\builder\field\SelectFormField;
+use wcf\system\form\builder\field\SingleSelectionFormField;
+use wcf\system\form\builder\field\TitleFormField;
+use wcf\system\form\builder\field\UrlFormField;
+use wcf\system\form\builder\field\validation\FormFieldValidationError;
+use wcf\system\form\builder\field\validation\FormFieldValidator;
+use wcf\system\form\builder\IFormDocument;
use wcf\system\page\handler\ILookupPageHandler;
use wcf\system\request\LinkHandler;
use wcf\system\WCF;
-use wcf\util\StringUtil;
/**
* Shows the menu item add form.
*
- * @author Marcel Werk
- * @copyright 2001-2019 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @since 3.0
+ * @author Olaf Braun, Marcel Werk
+ * @copyright 2001-2024 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @since 3.0
+ *
+ * @property MenuItem $formObject
*/
-class MenuItemAddForm extends AbstractForm
+class MenuItemAddForm extends AbstractFormBuilderForm
{
/**
* @inheritDoc
/**
* menu id
- * @var int
*/
- public $menuID = 0;
+ public int $menuID = 0;
/**
* menu object
- * @var Menu
- */
- public $menu;
-
- /**
- * activation state
- * @var bool
- */
- public $isDisabled = false;
-
- /**
- * internal link
- * @var bool
- */
- public $isInternalLink = true;
-
- /**
- * list of page handlers by page id
- * @var \wcf\system\page\handler\IMenuPageHandler[]
- */
- public $pageHandlers = [];
-
- /**
- * page id
- * @var int
- */
- public $pageID;
-
- /**
- * page object id
- * @var int
- */
- public $pageObjectID;
-
- /**
- * menu item title
- * @var string
- */
- public $title = '';
-
- /**
- * external url
- * @var string
- */
- public $externalURL = '';
-
- /**
- * id of the parent menu item
- * @var int
- */
- public $parentItemID;
-
- /**
- * show order
- * @var int
*/
- public $showOrder = 0;
+ public Menu $menu;
- /**
- * menu item node tree
- * @var MenuItemNodeTree
- */
- public $menuItems;
+ public \RecursiveIteratorIterator $menuItemNodeList;
/**
- * nested list of page nodes
- * @var \RecursiveIteratorIterator
+ * @inheritDoc
*/
- public $pageNodeList;
+ public $objectEditLinkController = MenuItemEditForm::class;
/**
* @inheritDoc
*/
+ public $objectActionClass = MenuItemAction::class;
+
+ #[\Override]
public function readParameters()
{
parent::readParameters();
if (!$this->menu->menuID) {
throw new IllegalLinkException();
}
-
- I18nHandler::getInstance()->register('title');
- I18nHandler::getInstance()->register('externalURL');
-
- $this->pageNodeList = (new PageNodeTree())->getNodeList();
-
- // fetch page handlers
- foreach ($this->pageNodeList as $pageNode) {
- $handler = $pageNode->getHandler();
- if ($handler !== null) {
- if ($handler instanceof ILookupPageHandler) {
- $this->pageHandlers[$pageNode->pageID] = $pageNode->requireObjectID;
- }
- }
- }
}
- /**
- * @inheritDoc
- */
- public function readFormParameters()
+ #[\Override]
+ protected function createForm()
{
- parent::readFormParameters();
-
- I18nHandler::getInstance()->readValues();
- if (I18nHandler::getInstance()->isPlainValue('title')) {
- $this->title = I18nHandler::getInstance()->getValue('title');
- }
- if (I18nHandler::getInstance()->isPlainValue('externalURL')) {
- $this->externalURL = I18nHandler::getInstance()->getValue('externalURL');
- }
-
- if (isset($_POST['isDisabled'])) {
- $this->isDisabled = true;
- }
- $this->isInternalLink = false;
- if (isset($_POST['isInternalLink'])) {
- $this->isInternalLink = (bool)$_POST['isInternalLink'];
- }
- if (!empty($_POST['pageID'])) {
- $this->pageID = \intval($_POST['pageID']);
- }
- if (!empty($_POST['pageObjectID'])) {
- $this->pageObjectID = \intval($_POST['pageObjectID']);
- }
- if (!empty($_POST['parentItemID'])) {
- $this->parentItemID = \intval($_POST['parentItemID']);
- }
- if (isset($_POST['showOrder'])) {
- $this->showOrder = \intval($_POST['showOrder']);
- }
+ parent::createForm();
+
+ $this->menuItemNodeList = (new MenuItemNodeTree($this->menuID, null, false))->getNodeList();
+
+ $this->form->appendChildren([
+ FormContainer::create('generalContainer')
+ ->appendChildren([
+ SelectFormField::create('parentItemID')
+ ->label('wcf.acp.menu.item.parentItem')
+ ->options($this->menuItemNodeList, true),
+ TitleFormField::create()
+ ->i18n()
+ ->required()
+ ->languageItemPattern('wcf.menu.item.[\w\.]+'),
+ IntegerFormField::create('showOrder')
+ ->label('wcf.global.showOrder')
+ ->minimum(0)
+ ->value(0),
+ BooleanFormField::create('isDisabled')
+ ->label('wcf.acp.menu.item.isDisabled')
+ ->value(false)
+ ]),
+ FormContainer::create('linkContainer')
+ ->label('wcf.acp.menu.item.link')
+ ->appendChildren([
+ RadioButtonFormField::create('isInternalLink')
+ ->options([
+ 0 => 'wcf.acp.menu.item.link.external',
+ 1 => 'wcf.acp.menu.item.link.internal',
+ ])
+ ->value(1),
+ SingleSelectionFormField::create('pageID')
+ ->label('wcf.acp.page.page')
+ ->options((new PageNodeTree())->getNodeList(), true)
+ ->required()
+ ->addDependency(
+ ValueFormFieldDependency::create('isInternalLinkDependency')
+ ->fieldId('isInternalLink')
+ ->values([1])
+ ),
+ // TODO change this to an new FormField
+ IntegerFormField::create('pageObjectID')
+ ->label('wcf.page.pageObjectID')
+ ->addFieldClass('short')
+ ->addValidator(
+ new FormFieldValidator('requiredObjectIDValidator', function (IntegerFormField $formField) {
+ $pageFormField = $this->form->getNodeById('pageID');
+ \assert($pageFormField instanceof SingleSelectionFormField);
+ $pageID = $pageFormField->getValue();
+ $page = new Page($pageID);
+ $pageObjectID = $formField->getValue();
+
+ if (!$page->pageID) {
+ return;
+ }
+
+ if ($page->requireObjectID) {
+ $pageHandler = $page->getHandler();
+
+ if ($pageHandler instanceof ILookupPageHandler) {
+ if (empty($pageObjectID)) {
+ $formField->addValidationError(new FormFieldValidationError('empty'));
+ return;
+ }
+ if (!$pageHandler->isValid($pageObjectID)) {
+ $formField->addValidationError(
+ new FormFieldValidationError(
+ 'invalid',
+ 'wcf.acp.menu.item.pageObjectID.error.invalid'
+ )
+ );
+ }
+ } elseif ($pageHandler !== null) {
+ // page requires an object id, but no handler is registered
+ $pageFormField->addValidationError(
+ new FormFieldValidationError(
+ 'invalid',
+ 'wcf.acp.menu.item.pageID.error.invalid'
+ )
+ );
+ }
+ }
+ })
+ )
+ ->addDependency(
+ ValueFormFieldDependency::create('isInternalLinkDependency')
+ ->fieldId('isInternalLink')
+ ->values([1])
+ ),
+ UrlFormField::create('externalURL')
+ ->label('wcf.acp.menu.item.externalURL')
+ ->maximumLength(255)
+ ->placeholder('http://')
+ ->i18n()
+ ->required()
+ ->languageItemPattern('wcf.menu.item.externalURL\d+')
+ ->addDependency(
+ ValueFormFieldDependency::create('isInternalLinkDependency')
+ ->fieldId('isInternalLink')
+ ->values([0])
+ )
+ ])
+ ]);
}
- /**
- * @inheritDoc
- */
- public function validate()
+ #[\Override]
+ protected function finalizeForm()
{
- parent::validate();
-
- // validate parent menu item
- if ($this->parentItemID) {
- $parentMenuItem = new MenuItem($this->parentItemID);
- if (!$parentMenuItem->itemID || $parentMenuItem->menuID != $this->menuID) {
- throw new UserInputException('parentItemID', 'invalid');
- }
- }
-
- // validate page menu item name
- if (!I18nHandler::getInstance()->validateValue('title')) {
- if (I18nHandler::getInstance()->isPlainValue('title')) {
- throw new UserInputException('title');
- } else {
- throw new UserInputException('title', 'multilingual');
- }
- }
-
- // validate menu item controller
- if ($this->isInternalLink) {
- $this->externalURL = '';
-
- if (!$this->pageID) {
- throw new UserInputException('pageID');
- }
- $page = new Page($this->pageID);
- if (!$page->pageID) {
- throw new UserInputException('pageID', 'invalid');
- }
-
- // validate page object id
- if ($page->requireObjectID) {
- if (isset($this->pageHandlers[$page->pageID])) {
- if ($this->pageHandlers[$page->pageID] && !$this->pageObjectID) {
- throw new UserInputException('pageObjectID');
+ parent::finalizeForm();
+
+ $this->form
+ ->getDataHandler()
+ ->addProcessor(
+ new CustomFormDataProcessor(
+ 'externalLinkDataProcessor',
+ function (IFormDocument $document, array $parameters) {
+ if ($parameters['data']['isInternalLink']) {
+ $parameters['data']['externalURL'] = '';
+ } else {
+ $parameters['data']['pageID'] = null;
+ $parameters['data']['pageObjectID'] = null;
+ }
+ unset($parameters['data']['isInternalLink']);
+
+ return $parameters;
}
-
- /** @var ILookupPageHandler $handler */
- $handler = $page->getHandler();
- if ($this->pageObjectID && !$handler->isValid($this->pageObjectID)) {
- throw new UserInputException('pageObjectID', 'invalid');
- }
- } else {
- // page requires an object id, but no handler is registered
- throw new UserInputException('pageID', 'invalid');
- }
- }
- } else {
- $this->pageID = $this->pageObjectID = null;
-
- // validate external url
- if (!I18nHandler::getInstance()->validateValue('externalURL')) {
- throw new UserInputException('externalURL');
- }
- }
+ )
+ );
}
- /**
- * @inheritDoc
- */
+ #[\Override]
public function save()
{
- parent::save();
-
- $this->objectAction = new MenuItemAction([], 'create', [
- 'data' => \array_merge($this->additionalFields, [
- 'isDisabled' => $this->isDisabled ? 1 : 0,
- 'title' => $this->title,
- 'pageID' => $this->pageID,
- 'pageObjectID' => $this->pageObjectID ?: 0,
- 'externalURL' => $this->externalURL,
- 'menuID' => $this->menuID,
- 'parentItemID' => $this->parentItemID,
- 'showOrder' => $this->showOrder,
- 'identifier' => StringUtil::getRandomID(),
- 'packageID' => 1,
- ]),
- ]);
- $this->objectAction->executeAction();
-
- $returnValues = $this->objectAction->getReturnValues();
- $menuItem = $returnValues['returnValues'];
-
- // set generic identifier
- $data = [
- 'identifier' => 'com.woltlab.wcf.generic' . $menuItem->itemID,
- ];
- if (!I18nHandler::getInstance()->isPlainValue('title')) {
- I18nHandler::getInstance()->save('title', 'wcf.menu.item.' . $data['identifier'], 'wcf.menu');
- $data['title'] = 'wcf.menu.item.' . $data['identifier'];
- }
- if (!I18nHandler::getInstance()->isPlainValue('externalURL')) {
- I18nHandler::getInstance()->save(
- 'externalURL',
- 'wcf.menu.item.externalURL' . $menuItem->itemID,
- 'wcf.menu'
- );
- $data['externalURL'] = 'wcf.menu.item.externalURL' . $menuItem->itemID;
+ if ($this->formAction === 'create') {
+ $this->additionalFields['menuID'] = $this->menuID;
+ $this->additionalFields['identifier'] = '';
+ $this->additionalFields['packageID'] = PACKAGE_ID;
}
- // update values
- $menuItemEditor = new MenuItemEditor($menuItem);
- $menuItemEditor->update($data);
-
- // call saved event
- $this->saved();
-
- // show success message
- WCF::getTPL()->assign([
- 'success' => true,
- 'objectEditLink' => LinkHandler::getInstance()->getControllerLink(
- MenuItemEditForm::class,
- ['id' => $menuItem->itemID]
- ),
- ]);
-
- // reset variables
- $this->isInternalLink = true;
- $this->isDisabled = false;
- $this->pageID = $this->pageObjectID = $this->parentItemID = null;
- $this->externalURL = $this->title = '';
- $this->showOrder = 0;
-
- I18nHandler::getInstance()->reset();
- }
-
- /**
- * @inheritDoc
- */
- public function readData()
- {
- parent::readData();
-
- $this->menuItems = new MenuItemNodeTree($this->menuID, null, false);
+ parent::save();
}
- /**
- * @inheritDoc
- */
+ #[\Override]
public function assignVariables()
{
parent::assignVariables();
- I18nHandler::getInstance()->assignVariables();
-
WCF::getTPL()->assign([
- 'action' => 'add',
'menuID' => $this->menuID,
'menu' => $this->menu,
- 'isDisabled' => $this->isDisabled,
- 'isInternalLink' => $this->isInternalLink,
- 'pageID' => $this->pageID,
- 'pageObjectID' => $this->pageObjectID,
- 'title' => $this->title,
- 'externalURL' => $this->externalURL,
- 'parentItemID' => $this->parentItemID,
- 'showOrder' => $this->showOrder,
- 'menuItemNodeList' => $this->menuItems->getNodeList(),
- 'pageNodeList' => $this->pageNodeList,
- 'pageHandlers' => $this->pageHandlers,
+ 'menuItemNodeList' => $this->menuItemNodeList,
]);
}
+
+ #[\Override]
+ protected function setFormAction()
+ {
+ $this->form->action(
+ LinkHandler::getInstance()->getLink(
+ 'MenuItemAdd',
+ [
+ 'menuID' => $this->menuID,
+ 'isACP' => true
+ ]
+ )
+ );
+ }
}
namespace wcf\acp\form;
+use CuyZ\Valinor\Mapper\MappingError;
use wcf\data\menu\item\MenuItem;
-use wcf\data\menu\item\MenuItemAction;
use wcf\data\menu\Menu;
-use wcf\data\page\PageNodeTree;
-use wcf\form\AbstractForm;
+use wcf\form\AbstractFormBuilderForm;
+use wcf\http\Helper;
use wcf\system\exception\IllegalLinkException;
-use wcf\system\exception\UserInputException;
-use wcf\system\language\I18nHandler;
-use wcf\system\page\handler\ILookupPageHandler;
-use wcf\system\WCF;
/**
* Shows the menu item edit form.
*/
class MenuItemEditForm extends MenuItemAddForm
{
- /**
- * menu item id
- * @var int
- */
- public $itemID = 0;
-
- /**
- * menu item object
- * @var MenuItem
- */
- public $menuItem;
-
- /**
- * @inheritDoc
- */
- public function readParameters()
- {
- AbstractForm::readParameters();
-
- if (isset($_REQUEST['id'])) {
- $this->itemID = \intval($_REQUEST['id']);
- }
- $this->menuItem = new MenuItem($this->itemID);
- if (!$this->menuItem->itemID) {
- throw new IllegalLinkException();
- }
-
- $this->menu = new Menu($this->menuItem->menuID);
- $this->menuID = $this->menu->menuID;
-
- I18nHandler::getInstance()->register('title');
- I18nHandler::getInstance()->register('externalURL');
-
- $this->pageNodeList = (new PageNodeTree())->getNodeList();
-
- // fetch page handlers
- foreach ($this->pageNodeList as $pageNode) {
- $handler = $pageNode->getHandler();
- if ($handler !== null) {
- if ($handler instanceof ILookupPageHandler) {
- $this->pageHandlers[$pageNode->pageID] = $pageNode->requireObjectID;
- }
- }
- }
- }
-
/**
* @inheritDoc
*/
- public function validate()
- {
- parent::validate();
+ public $formAction = 'edit';
- if ($this->parentItemID == $this->itemID) {
- throw new UserInputException('parentItemID');
- }
- }
-
- /**
- * @inheritDoc
- */
- public function save()
- {
- AbstractForm::save();
-
- $this->title = 'wcf.menu.item.' . $this->menuItem->identifier;
- if (I18nHandler::getInstance()->isPlainValue('title')) {
- I18nHandler::getInstance()->remove($this->title);
- $this->title = I18nHandler::getInstance()->getValue('title');
- } else {
- I18nHandler::getInstance()->save('title', $this->title, 'wcf.menu', 1);
- }
- $this->externalURL = 'wcf.menu.item.externalURL' . $this->menuItem->itemID;
- if (I18nHandler::getInstance()->isPlainValue('externalURL')) {
- I18nHandler::getInstance()->remove($this->externalURL);
- $this->externalURL = I18nHandler::getInstance()->getValue('externalURL');
- } else {
- I18nHandler::getInstance()->save('externalURL', $this->externalURL, 'wcf.menu', 1);
- }
-
- // update menu
- $this->objectAction = new MenuItemAction([$this->itemID], 'update', [
- 'data' => \array_merge($this->additionalFields, [
- 'isDisabled' => $this->isDisabled ? 1 : 0,
- 'title' => $this->title,
- 'pageID' => $this->pageID,
- 'pageObjectID' => $this->pageObjectID ?: 0,
- 'externalURL' => $this->externalURL,
- 'parentItemID' => $this->parentItemID,
- 'showOrder' => $this->showOrder,
- ]),
- ]);
- $this->objectAction->executeAction();
- $this->saved();
-
- // show success message
- WCF::getTPL()->assign('success', true);
- }
-
- /**
- * @inheritDoc
- */
- public function readData()
+ #[\Override]
+ public function readParameters()
{
- parent::readData();
-
- if (empty($_POST)) {
- I18nHandler::getInstance()->setOptions(
- 'title',
- 1,
- $this->menuItem->title,
- 'wcf.menu.item.' . $this->menuItem->identifier
- );
- I18nHandler::getInstance()->setOptions(
- 'externalURL',
- 1,
- $this->menuItem->externalURL,
- 'wcf.menu.item.externalURL\d+'
+ AbstractFormBuilderForm::readParameters();
+
+ try {
+ $queryParameters = Helper::mapQueryParameters(
+ $_GET,
+ <<<'EOT'
+ array {
+ id: positive-int
+ }
+ EOT
);
+ $this->formObject = new MenuItem($queryParameters['id']);
- $this->parentItemID = $this->menuItem->parentItemID;
- $this->title = $this->menuItem->title;
- $this->pageID = $this->menuItem->pageID;
- $this->pageObjectID = $this->menuItem->pageObjectID;
- $this->externalURL = $this->menuItem->externalURL;
- $this->showOrder = $this->menuItem->showOrder;
- $this->isDisabled = $this->menuItem->isDisabled;
- if (!$this->pageID) {
- $this->isInternalLink = false;
+ if (!$this->formObject->getObjectID()) {
+ throw new IllegalLinkException();
}
+ } catch (MappingError) {
+ throw new IllegalLinkException();
}
+
+ $this->menuID = $this->formObject->menuID;
+ $this->menu = new Menu($this->menuID);
}
- /**
- * @inheritDoc
- */
- public function assignVariables()
+ #[\Override]
+ protected function setFormAction()
{
- parent::assignVariables();
-
- I18nHandler::getInstance()->assignVariables(!empty($_POST));
-
- WCF::getTPL()->assign([
- 'action' => 'edit',
- 'itemID' => $this->itemID,
- 'menuItem' => $this->menuItem,
- ]);
+ AbstractFormBuilderForm::setFormAction();
}
}
namespace wcf\data\menu\item;
use wcf\data\AbstractDatabaseObjectAction;
+use wcf\data\DatabaseObject;
use wcf\data\ISortableAction;
use wcf\data\IToggleAction;
use wcf\data\menu\Menu;
use wcf\data\TDatabaseObjectToggle;
+use wcf\data\TI18nDatabaseObjectAction;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\UserInputException;
use wcf\system\WCF;
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @since 3.0
*
- * @method MenuItem create()
* @method MenuItemEditor[] getObjects()
* @method MenuItemEditor getSingleObject()
*/
class MenuItemAction extends AbstractDatabaseObjectAction implements ISortableAction, IToggleAction
{
use TDatabaseObjectToggle;
+ use TI18nDatabaseObjectAction;
/**
* @inheritDoc
*/
protected $requireACP = ['create', 'delete', 'toggle', 'update'];
+ public function create()
+ {
+ // `title` column doesn't have a default value
+ $this->parameters['data']['title'] = $this->parameters['data']['title'] ?? '';
+
+ /** @var MenuItem $menuItem */
+ $menuItem = parent::create();
+
+ if (!$menuItem->identifier) {
+ $editor = new MenuItemEditor($menuItem);
+ $editor->update([
+ 'identifier' => 'com.woltlab.wcf.generic' . $menuItem->itemID,
+ ]);
+ $menuItem = new MenuItem($menuItem->itemID);
+ }
+
+ $this->saveI18nValue($menuItem);
+
+ return $menuItem;
+ }
+
+ #[\Override]
+ public function update()
+ {
+ parent::update();
+
+ foreach ($this->getObjects() as $editor) {
+ $this->saveI18nValue($editor->getDecoratedObject());
+ }
+ }
+
/**
* @inheritDoc
*/
}
WCF::getDB()->commitTransaction();
}
+
+ #[\Override]
+ public function getI18nSaveTypes(): array
+ {
+ return ['title' => 'wcf.menu.item.\w+'];
+ }
+
+ #[\Override]
+ public function getLanguageCategory(): string
+ {
+ return 'wcf.menu';
+ }
+
+ #[\Override]
+ public function getPackageID(): int
+ {
+ return PACKAGE_ID;
+ }
+
+ protected function getLanguageItem(DatabaseObject $object, string $regex): string
+ {
+ \assert($object instanceof MenuItem);
+
+ return \str_replace(
+ '\w+',
+ $object->identifier ?: 'com.woltlab.wcf.generic' . $object->itemID,
+ $regex
+ );
+ }
}
namespace wcf\data\menu\item;
use wcf\data\DatabaseObjectDecorator;
+use wcf\data\IObjectTreeNode;
+use wcf\data\TObjectTreeNode;
/**
* Represents a menu item node element.
* @method MenuItem getDecoratedObject()
* @mixin MenuItem
*/
-class MenuItemNode extends DatabaseObjectDecorator implements \Countable, \RecursiveIterator
+class MenuItemNode extends DatabaseObjectDecorator implements IObjectTreeNode
{
- /**
- * children of this node
- * @var MenuItemNode[]
- */
- protected $children = [];
+ use TObjectTreeNode;
/**
* node depth
*/
protected bool $isActive = false;
- /**
- * parent node
- * @var MenuItemNode
- */
- protected $parentNode;
-
/**
* iterator position
* @var int
$this->children = $children;
}
- /**
- * Returns the parent node
- */
- public function getParentNode(): self
- {
- return $this->parentNode;
- }
-
- /**
- * Returns the number of children.
- */
- public function count(): int
- {
- return \count($this->children);
- }
-
- /**
- * Returns true if this element is the last sibling.
- */
- public function isLastSibling(): bool
- {
- foreach ($this->parentNode as $key => $child) {
- if ($child === $this) {
- if ($key == \count($this->parentNode) - 1) {
- return true;
- }
-
- return false;
- }
- }
- }
-
- /**
- * Returns the number of open parent nodes.
- */
- public function getOpenParentNodes(): int
- {
- $element = $this;
- $i = 0;
-
- while ($element->parentNode->parentNode != null && $element->isLastSibling()) {
- $i++;
- $element = $element->parentNode;
- }
-
- return $i;
- }
-
/**
* Marks this item and all its direct ancestors as active.
*/
return $this->isActive;
}
- /**
- * @inheritDoc
- */
- public function rewind(): void
- {
- $this->position = 0;
- }
-
- /**
- * @inheritDoc
- */
- public function valid(): bool
- {
- return isset($this->children[$this->position]);
- }
-
- /**
- * @inheritDoc
- */
- public function next(): void
- {
- $this->position++;
- }
-
- /**
- * @inheritDoc
- */
- public function current(): self
- {
- return $this->children[$this->position];
- }
-
- /**
- * @inheritDoc
- */
- public function key(): int
- {
- return $this->position;
- }
-
- /**
- * @inheritDoc
- */
- public function getChildren(): self
- {
- return $this->children[$this->position];
- }
-
- /**
- * @inheritDoc
- */
- public function hasChildren(): bool
- {
- return \count($this->children) > 0;
- }
-
/**
* Returns node depth.
*/