}
});
+/**
+ * Namespace for page menu.
+ */
+WCF.ACP.PageMenu = { };
+
+/**
+ * Allows menu items to be set as landing page.
+ *
+ * @param integer menuItemID
+ */
+WCF.ACP.PageMenu.SetAsLandingPage = Class.extend({
+ /**
+ * menu item id
+ * @var integer
+ */
+ _menuItemID: 0,
+
+ /**
+ * Initializes the WCF.ACP.PageMenu.SetAsLandingPage class.
+ *
+ * @param integer menuItemID
+ */
+ init: function(menuItemID) {
+ this._menuItemID = menuItemID;
+
+ $('#setAsLandingPage').click($.proxy(this._click, this));
+ },
+
+ /**
+ * Handles button clicks.
+ */
+ _click: function() {
+ var self = this;
+ WCF.System.Confirmation.show(WCF.Language.get('wcf.acp.pageMenu.isLandingPage.confirmMessage'), function(action) {
+ if (action === 'confirm') {
+ new WCF.Action.Proxy({
+ autoSend: true,
+ data: {
+ actionName: 'setAsLandingPage',
+ className: 'wcf\\data\\page\\menu\\item\\PageMenuItemAction',
+ objectIDs: [ self._menuItemID ]
+ },
+ success: $.proxy(self._success, self)
+ });
+ }
+ });
+ },
+
+ /**
+ * Handles successful AJAX requests.
+ *
+ * @param object data
+ * @param string textStatus
+ * @param jQuery jqXHR
+ */
+ _success: function(data, textStatus, jqXHR) {
+ var $notification = new WCF.System.Notification(WCF.Language.get('wcf.acp.pageMenu.isLandingPage.success'));
+ $notification.show(function() { window.location.reload(); });
+ }
+});
+
/**
* Handles option selection.
*/
handleMenuPosition();
handleIsInternalLink();
+
+ {if $action == 'edit' && $menuItem->isValidLandingPage()}
+ WCF.Language.addObject({
+ 'wcf.acp.pageMenu.isLandingPage.confirmMessage': '{lang}wcf.acp.pageMenu.isLandingPage.confirmMessage{/lang}',
+ 'wcf.acp.pageMenu.isLandingPage.success': '{lang}wcf.acp.pageMenu.isLandingPage.success{/lang}'
+ });
+
+ new WCF.ACP.PageMenu.SetAsLandingPage({@$menuItem->menuItemID});
+ {/if}
});
//]]>
</script>
<div class="contentNavigation">
<nav>
<ul>
+ {if $action == 'edit' && $menuItem->isValidLandingPage()}
+ <li id="setAsLandingPage"><a class="button"><img src="{@$__wcf->getPath()}icon/default.svg" /> <span>{lang}wcf.acp.pageMenu.setAsLandingPage{/lang}</span></a></li>
+ {/if}
<li><a href="{link controller='PageMenuItemList'}{/link}" class="button"><img src="{@$__wcf->getPath()}icon/list.svg" alt="" /> <span>{lang}wcf.acp.pageMenu.list{/lang}</span></a></li>
</ul>
</nav>
<span class="sortableNodeLabel">
<a href="{link controller='PageMenuItemEdit' id=$menuItem->menuItemID}{/link}">{lang}{$menuItem->menuItem}{/lang}</a>
<span class="statusDisplay sortableButtonContainer">
- <img src="{@$__wcf->getPath()}icon/{if $menuItem->isDisabled}disabled{else}enabled{/if}.svg" alt="" title="{lang}wcf.global.button.{if $menuItem->isDisabled}enable{else}disable{/if}{/lang}" class="icon16 jsToggleButton jsTooltip pointer" data-object-id="{@$menuItem->menuItemID}" data-disable-message="{lang}wcf.global.button.disable{/lang}" data-enable-message="{lang}wcf.global.button.enable{/lang}" />
+ {if $menuItem->canDisable()}
+ <img src="{@$__wcf->getPath()}icon/{if $menuItem->isDisabled}disabled{else}enabled{/if}.svg" alt="" title="{lang}wcf.global.button.{if $menuItem->isDisabled}enable{else}disable{/if}{/lang}" class="icon16 jsToggleButton jsTooltip pointer" data-object-id="{@$menuItem->menuItemID}" data-disable-message="{lang}wcf.global.button.disable{/lang}" data-enable-message="{lang}wcf.global.button.enable{/lang}" />
+ {else}
+ <img src="{@$__wcf->getPath()}icon/enabled.svg" alt="" class="icon16 disabled" />
+ {/if}
<a href="{link controller='PageMenuItemEdit' id=$menuItem->menuItemID}{/link}" class="jsTooltip" title="{lang}wcf.global.button.edit{/lang}"><img src="{@$__wcf->getPath()}icon/edit.svg" alt="" class="icon16" /></a>
- <img src="{@$__wcf->getPath()}icon/delete.svg" alt="" title="{lang}wcf.global.button.delete{/lang}" class="icon16 jsDeleteButton jsTooltip pointer" data-object-id="{@$menuItem->menuItemID}" data-confirm-message="{lang __menuItem=$menuItem}wcf.acp.pageMenu.delete.sure{/lang}" />
+ {if $menuItem->canDelete()}
+ <img src="{@$__wcf->getPath()}icon/delete.svg" alt="" title="{lang}wcf.global.button.delete{/lang}" class="icon16 jsDeleteButton jsTooltip pointer" data-object-id="{@$menuItem->menuItemID}" data-confirm-message="{lang __menuItem=$menuItem}wcf.acp.pageMenu.delete.sure{/lang}" />
+ {else}
+ <img src="{@$__wcf->getPath()}icon/delete.svg" alt="" class="icon16 disabled" />
+ {/if}
</span>
</span>
{if $menuItem|count}
*/
protected static $processorInterface = 'wcf\system\menu\page\IPageMenuItemProvider';
+ /**
+ * application abbreviation
+ * @var string
+ */
+ protected $application = '';
+
+ /**
+ * menu item controller
+ * @var string
+ */
+ protected $controller = null;
+
/**
* @see wcf\data\ProcessibleDatabaseObject::getProcessor()
*/
return WCF::getLanguage()->get($this->menuItemLink);
}
- // resolve application and controller
- $parts = explode('\\', $this->menuItemController);
- $abbreviation = array_shift($parts);
- $controller = array_pop($parts);
+ $this->parseController();
+ return LinkHandler::getInstance()->getLink($this->controller, array('application' => $this->application), WCF::getLanguage()->get($this->menuItemLink));
+ }
+
+ /**
+ * Returns true, if current menu item may be set as landing page.
+ *
+ * @return boolean
+ */
+ public function isValidLandingPage() {
+ // item must be a top header menu item without parents
+ if ($this->menuPosition != 'header' || $this->parentMenuItem) {
+ return false;
+ }
+
+ // external links are not valid
+ if (!$this->menuItemController) {
+ return false;
+ }
+
+ // already is landing page
+ if ($this->isLandingPage) {
+ return false;
+ }
- // drop controller suffix
- $controller = Regex::compile('(Action|Form|Page)$')->replace($controller, '');
+ // disabled items cannot be a landing page
+ if ($this->isDisabled) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true, if this item can be deleted.
+ *
+ * @return boolean
+ */
+ public function canDelete() {
+ return ($this->isLandingPage ? false : true);
+ }
+
+ /**
+ * Returns true, if this item can be disabled.
+ *
+ * @return boolean
+ */
+ public function canDisable() {
+ return ($this->isLandingPage ? false : true);
+ }
+
+ /**
+ * Returns controller name.
+ *
+ * @return string
+ */
+ public function getController() {
+ $this->parseController();
- return LinkHandler::getInstance()->getLink($controller, array('application' => $abbreviation), WCF::getLanguage()->get($this->menuItemLink));
+ return $this->controller;
+ }
+
+ /**
+ * Parses controller name.
+ */
+ protected function parseController() {
+ if ($this->controller === null) {
+ $this->controller = '';
+
+ // resolve application and controller
+ if ($this->menuItemController) {
+ $parts = explode('\\', $this->menuItemController);
+ $this->application = array_shift($parts);
+ $menuItemController = array_pop($parts);
+
+ // drop controller suffix
+ $this->controller = Regex::compile('(Action|Form|Page)$')->replace($menuItemController, '');
+ }
+ }
}
/**
use wcf\data\AbstractDatabaseObjectAction;
use wcf\data\ISortableAction;
use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\UserInputException;
use wcf\system\WCF;
*/
protected $className = 'wcf\data\page\menu\item\PageMenuItemEditor';
+ /**
+ * page menu item editor
+ * @var wcf\data\page\menu\item\PageMenuItemEditor
+ */
+ public $menuItemEditor = null;
+
/**
* list of menu items
* @var array<wcf\data\page\menu\item\PageMenuItem>
return $menuItem;
}
+ /**
+ * Validates parameters to set a menu item as landing page.
+ */
+ public function validateSetAsLandingPage() {
+ WCF::getSession()->checkPermissions(array('admin.display.canManagePageMenu'));
+
+ $this->menuItemEditor = $this->getSingleObject();
+ if (!$this->menuItemEditor->isValidLandingPage()) {
+ throw new PermissionDeniedException();
+ }
+ }
+
+ /**
+ * Sets a menu item as landing page.
+ */
+ public function setAsLandingPage() {
+ $this->menuItemEditor->setAsLandingPage();
+ }
+
/**
* @see wcf\data\ISortableAction::validateUpdatePosition()
*/
$statement->execute();
$this->update(array('isLandingPage' => 1));
+
+ self::resetCache();
}
/**
* @category Community Framework
*/
class PageMenu extends TreeMenu {
+ /**
+ * landing page menu item
+ * @var wcf\data\page\menu\item\PageMenuItem
+ */
+ protected $landingPage = null;
+
/**
* @see wcf\system\SingletonFactory::init()
*/
// call init event
EventHandler::getInstance()->fireAction($this, 'init');
+
+ foreach ($this->menuItems as $menuItems) {
+ foreach ($menuItems as $menuItem) {
+ if ($menuItem->isLandingPage) {
+ $this->landingPage = $menuItem;
+ break 2;
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns landing page menu item.
+ *
+ * @return wcf\data\page\menu\item\PageMenuItem
+ */
+ public function getLandingPage() {
+ return $this->landingPage;
}
/**
<?php
namespace wcf\system\request;
-use wcf\util\HeaderUtil;
+use wcf\util\StringUtil;
use wcf\system\exception\IllegalLinkException;
use wcf\system\exception\SystemException;
+use wcf\system\menu\page\PageMenu;
use wcf\system\SingletonFactory;
use wcf\system\WCF;
+use wcf\util\HeaderUtil;
/**
* Handles http requests.
* @param string $application
*/
protected function buildRequest($application) {
- try {
+ //try {
$routeData = RouteHandler::getInstance()->getRouteData();
- $controller = $routeData['controller'];
- /*
- * @todo redirect to landing page once page menu items support controller based URLs (see https://github.com/WoltLab/WCF/issues/998)
- *
- if (RouteHandler::getInstance()->isDefaultController()) {
- HeaderUtil::redirect(..., true);
- exit;
+ // handle landing page for frontend requests
+ if (!$this->isACPRequest()) {
+ $landingPage = PageMenu::getInstance()->getLandingPage();
+ if ($landingPage !== null && RouteHandler::getInstance()->isDefaultController()) {
+ // check if redirect URL matches current URL
+ $redirectURL = $landingPage->getLink();
+ if (StringUtil::replace(RouteHandler::getHost(), '', $redirectURL) == $_SERVER['REQUEST_URI']) {
+ $routeData['controller'] = $landingPage->getController();
+ }
+ else {
+ // redirect to landing page
+ HeaderUtil::redirect($landingPage->getLink(), true);
+ exit;
+ }
+ }
}
- */
+
+ $controller = $routeData['controller'];
// validate class name
if (!preg_match('~^[a-z0-9_]+$~i', $controller)) {
}
$this->activeRequest = new Request($classData['className'], $classData['controller'], $classData['pageType']);
- }
- catch (SystemException $e) {
- throw new IllegalLinkException();
- }
+ //}
+ //catch (SystemException $e) {
+ // throw new IllegalLinkException();
+ //}
}
/**
<?php
namespace wcf\system\request;
+use wcf\system\menu\page\PageMenu;
+
use wcf\system\exception\SystemException;
/**
* @param boolean $isOptional
*/
public function setParameterOption($key, $default = null, $regexPattern = null, $isOptional = false) {
- if ($key == 'controller' && (empty($default) && $isOptional)) {
- throw new SystemException('Routes require a controller, it is not possible to regard them as optional without a default value.');
- }
-
$this->parameterOptions[$key] = array(
'default' => $default,
'isOptional' => $isOptional,
}
if (!isset($data['isDefaultController'])) {
- $data['isDefaultController'] = true;
+ $data['isDefaultController'] = false;
}
$this->routeData = $data;
$this->routeData['controller'] = $this->controller;
}
+ if (!isset($this->routeData['controller'])) {
+ $this->routeData['isDefaultController'] = true;
+ }
+
return true;
}
// handle default values for controller
$buildRoute = true;
- if (count($components) == 1) {
+ if (count($components) == 1 && isset($components['controller'])) {
+ $ignoreController = false;
if (isset($this->parameterOptions['controller']) && strcasecmp($this->parameterOptions['controller']['default'], $components['controller']) == 0) {
// only the controller was given and matches default, omit routing
+ $ignoreController = true;
+ }
+ else {
+ $landingPage = PageMenu::getInstance()->getLandingPage();
+ if ($landingPage !== null && ($landingPage->getController() == $components['controller'])) {
+ $ignoreController = true;
+ }
+ }
+
+ // drops controller from route
+ if ($ignoreController) {
$buildRoute = false;
// unset the controller, since it would otherwise added with http_build_query()
}
}
- $link = 'index.php' . (!empty($link) ? '/' : '') . $link;
+ if (!empty($link)) {
+ $link = 'index.php/' . $link;
+ }
if (!empty($components)) {
$link .= '?' . http_build_query($components, '', '&');
$defaultRoute = new Route('default');
$defaultRoute->setSchema('/{controller}/{id}');
- $defaultRoute->setParameterOption('controller', 'Index', null, true);
+ $defaultRoute->setParameterOption('controller', null, null, true);
$defaultRoute->setParameterOption('id', null, '\d+', true);
$this->addRoute($defaultRoute);
}
<item name="wcf.acp.pageMenu.footer"><![CDATA[Fußzeile]]></item>
<item name="wcf.acp.pageMenu.header"><![CDATA[Hauptmenü]]></item>
<item name="wcf.acp.pageMenu.isDisabled"><![CDATA[Menüpunkt deaktivieren]]></item>
- <item name="wcf.acp.pageMenu.isLandingPage"><![CDATA[Startseite Ihrer Website]]></item>
- <item name="wcf.acp.pageMenu.isLandingPage.description"><![CDATA[Beim direkten Aufruf Ihrer Website wird diese Menüpunkt aufgerufen.]]></item>
+ <item name="wcf.acp.pageMenu.isLandingPage.confirmMessage"><![CDATA[Möchten Sie den Menüpunkt „{$menuItem}“ als Startseite Ihrer Website festlegen?]]></item>
+ <item name="wcf.acp.pageMenu.isLandingPage.success"><![CDATA[„{$menuItem}“ ist nun als Startseite festgelegt]]></item>
<item name="wcf.acp.pageMenu.link"><![CDATA[Link]]></item>
<item name="wcf.acp.pageMenu.link.external"><![CDATA[Externer Link]]></item>
<item name="wcf.acp.pageMenu.link.internal"><![CDATA[Interner Link]]></item>
<item name="wcf.acp.pageMenu.menuPosition.header"><![CDATA[Hauptmenü]]></item>
<item name="wcf.acp.pageMenu.pageMenuItem"><![CDATA[Name]]></item>
<item name="wcf.acp.pageMenu.parentMenuItem"><![CDATA[Übergeordneter Menüpunkt]]></item>
+ <item name="wcf.acp.pageMenu.setAsLandingPage"><![CDATA[Als Startseite festlegen]]></item>
<item name="wcf.acp.pageMenu.showOrder"><![CDATA[Reihenfolge]]></item>
</category>