Added page menu editor and improvements to I18nHandler
authorAlexander Ebert <ebert@woltlab.com>
Tue, 4 Dec 2012 00:37:25 +0000 (01:37 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Tue, 4 Dec 2012 00:37:25 +0000 (01:37 +0100)
15 files changed:
com.woltlab.wcf/acpMenu.xml
com.woltlab.wcf/userGroupOption.xml
wcfsetup/install/files/acp/templates/header.tpl
wcfsetup/install/files/acp/templates/pageMenuItemAdd.tpl [new file with mode: 0644]
wcfsetup/install/files/acp/templates/pageMenuItemList.tpl [new file with mode: 0644]
wcfsetup/install/files/lib/acp/form/PageMenuItemAddForm.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/acp/form/PageMenuItemEditForm.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/acp/page/PageMenuItemListPage.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/ISortableAction.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/page/menu/item/PageMenuItem.class.php
wcfsetup/install/files/lib/data/page/menu/item/PageMenuItemAction.class.php
wcfsetup/install/files/lib/data/page/menu/item/PageMenuItemEditor.class.php
wcfsetup/install/files/lib/data/page/menu/item/ViewablePageMenuItem.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/language/I18nHandler.class.php
wcfsetup/setup/db/install.sql

index 8eaab390cc366e1a4cd5a562a2e97a847d72ce5b..434a4849d727de814384e52594461e214d841ed9 100644 (file)
                        <showorder>3</showorder>
                </acpmenuitem>
                
+               <!-- page menu -->
+               <acpmenuitem name="wcf.acp.menu.link.pageMenu">
+                       <parent>wcf.acp.menu.link.display</parent>
+               </acpmenuitem>
+               
+               <acpmenuitem name="wcf.acp.menu.link.pageMenu.list">
+                       <link>index.php/PageMenuItemList/</link>
+                       <parent>wcf.acp.menu.link.pageMenu</parent>
+                       <permissions>admin.display.canManagePageMenu</permissions>
+                       <showorder>1</showorder>
+               </acpmenuitem>
+               
+               <acpmenuitem name="wcf.acp.menu.link.pageMenu.add">
+                       <link>index.php/PageMenuItemAdd/</link>
+                       <parent>wcf.acp.menu.link.pageMenu</parent>
+                       <permissions>admin.display.canManagePageMenu</permissions>
+                       <showorder>2</showorder>
+               </acpmenuitem>
+               <!-- /page menu -->
+               
                <acpmenuitem name="wcf.acp.menu.link.content">
                        <showorder>4</showorder>
                </acpmenuitem>
index aa6471d9f7c7d2fc672b80ed6e6f3a69aaa5c06b..d1069f6033a96caa8988ea08a99bc420e7824afb 100644 (file)
@@ -41,6 +41,9 @@
                        <category name="admin.style">
                                <parent>admin.display</parent>
                        </category>
+                       <category name="admin.display.pageMenu">
+                               <parent>admin.display</parent>
+                       </category>
                        
                        <category name="admin.content">
                                <parent>admin</parent>
                                <admindefaultvalue>1</admindefaultvalue>
                                <showorder>4</showorder>
                        </option>
+                       <option name="admin.display.canManagePageMenu">
+                               <categoryname>admin.display.pageMenu</categoryname>
+                               <optiontype>boolean</optiontype>
+                               <defaultvalue>0</defaultvalue>
+                               <admindefaultvalue>1</admindefaultvalue>
+                       </option>
                </options>
        </import>
 </data>
index c0f090ed5bc30406a36b4e81f1cc1962127c8dec..fa22af07053ffa28117138464028e59093277d39 100644 (file)
                                        <nav id="mainMenu" class="mainMenu">
                                                <ul>
                                                        {content}
-                                                               {foreach from=$__wcf->getACPMenu()->getMenuItems('') item=menuItem}
-                                                                       <li data-menu-item="{$menuItem->menuItem}"><a>{lang}{@$menuItem->menuItem}{/lang}</a></li>
+                                                               {foreach from=$__wcf->getACPMenu()->getMenuItems('') item=_menuItem}
+                                                                       <li data-menu-item="{$_menuItem->menuItem}"><a>{lang}{@$_menuItem->menuItem}{/lang}</a></li>
                                                                {/foreach}
                                                        {/content}
                                                </ul>
                                        {content}
                                                {* work-around for unknown core-object during WCFSetup *}
                                                {if PACKAGE_ID}
-                                                       {foreach from=$__wcf->getACPMenu()->getMenuItems('') item=parentMenuItem}
-                                                               <div id="{$parentMenuItem->menuItem}-container" style="display: none;" class="menuGroup collapsibleMenus" data-parent-menu-item="{$parentMenuItem->menuItem}">
-                                                                       {foreach from=$__wcf->getACPMenu()->getMenuItems($parentMenuItem->menuItem) item=menuItem}
+                                                       {foreach from=$__wcf->getACPMenu()->getMenuItems('') item=_parentMenuItem}
+                                                               <div id="{$_parentMenuItem->menuItem}-container" style="display: none;" class="menuGroup collapsibleMenus" data-parent-menu-item="{$_parentMenuItem->menuItem}">
+                                                                       {foreach from=$__wcf->getACPMenu()->getMenuItems($_parentMenuItem->menuItem) item=_menuItem}
                                                                                <fieldset>
-                                                                                       <legend class="menuHeader" data-menu-item="{$menuItem->menuItem}">{lang}{@$menuItem->menuItem}{/lang}</legend>
+                                                                                       <legend class="menuHeader" data-menu-item="{$_menuItem->menuItem}">{lang}{@$_menuItem->menuItem}{/lang}</legend>
                                                                                        
                                                                                        <nav class="menuGroupItems">
-                                                                                               <ul id="{$menuItem->menuItem}">
-                                                                                                       {foreach from=$__wcf->getACPMenu()->getMenuItems($menuItem->menuItem) item=menuItemCategory}
+                                                                                               <ul id="{$_menuItem->menuItem}">
+                                                                                                       {foreach from=$__wcf->getACPMenu()->getMenuItems($_menuItem->menuItem) item=menuItemCategory}
                                                                                                                {if $__wcf->getACPMenu()->getMenuItems($menuItemCategory->menuItem)|count > 0}
                                                                                                                        {foreach from=$__wcf->getACPMenu()->getMenuItems($menuItemCategory->menuItem) item=subMenuItem}
                                                                                                                                <li id="{$subMenuItem->menuItem}" data-menu-item="{$subMenuItem->menuItem}"><a href="{$subMenuItem->getLink()}">{lang}{$subMenuItem->menuItem}{/lang}</a></li>
diff --git a/wcfsetup/install/files/acp/templates/pageMenuItemAdd.tpl b/wcfsetup/install/files/acp/templates/pageMenuItemAdd.tpl
new file mode 100644 (file)
index 0000000..0fbeeaa
--- /dev/null
@@ -0,0 +1,191 @@
+{include file='header' pageTitle='wcf.acp.pageMenu.'|concat:$action}
+
+<script type="text/javascript">
+       //<![CDATA[
+       $(function() {
+               var $isDisabled = $('#isDisabled');
+               var $isLandingPageContainer = $('#isLandingPageContainer');
+               var $menuPosition = $('#menuPosition');
+               var $parentMenuItemContainer = $('#parentMenuItemContainer');
+               
+               function handleMenuPosition() {
+                       if ($menuPosition.val() === 'header') {
+                               $parentMenuItemContainer.show();
+                               
+                               if (!$isDisabled.is(':checked')) {
+                                       $isLandingPageContainer.show();
+                               }
+                       }
+                       else {
+                               $parentMenuItemContainer.hide();
+                               $isLandingPageContainer.hide();
+                       }
+               }
+               
+               function handleIsDisabled() {
+                       if ($isDisabled.is(':checked')) {
+                               $isLandingPageContainer.hide();
+                       }
+                       else {
+                               $isLandingPageContainer.show();
+                       }
+               }
+               
+               $isDisabled.change(handleIsDisabled);
+               $menuPosition.change(handleMenuPosition);
+               
+               handleIsDisabled();
+               handleMenuPosition();
+       });
+       //]]>
+</script>
+
+<header class="boxHeadline">
+       <hgroup>
+               <h1>{lang}wcf.acp.pageMenu.{$action}{/lang}</h1>
+       </hgroup>
+</header>
+
+{if $errorField}
+       <p class="error">{lang}wcf.global.form.error{/lang}</p>
+{/if}
+
+{if $success|isset}
+       <p class="success">{lang}wcf.global.form.{$action}.success{/lang}</p>   
+{/if}
+
+<div class="contentNavigation">
+       <nav>
+               <ul>
+                       <li><a href="{link controller='PageMenuItemList'}{/link}" class="button"><img src="{@RELATIVE_WCF_DIR}icon/list.svg" alt="" /> <span>{lang}wcf.acp.pageMenu.list{/lang}</span></a></li>
+               </ul>
+       </nav>
+</div>
+
+<div class="container containerPadding marginTop">
+       <form method="post" action="{if $action == 'add'}{link controller='PageMenuItemAdd'}{/link}{else}{link controller='PageMenuItemEdit' id=$menuItem->menuItemID}{/link}{/if}">
+               <fieldset>
+                       <legend>{lang}wcf.acp.pageMenu.data{/lang}</legend>
+                       
+                       <dl{if $errorField == 'menuPosition'} class="formError"{/if}>
+                               <dt><label for="menuPosition">{lang}wcf.acp.pageMenu.menuPosition{/lang}</label></dt>
+                               <dd>
+                                       <select name="menuPosition" id="menuPosition">
+                                               <option value="header"{if $menuPosition == 'header'} selected="selected"{/if}>{lang}wcf.acp.pageMenu.menuPosition.header{/lang}</option>
+                                               <option value="footer"{if $menuPosition == 'footer'} selected="selected"{/if}>{lang}wcf.acp.pageMenu.menuPosition.footer{/lang}</option>
+                                       </select>
+                                       {if $errorField == 'menuPosition'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}
+                                                               {lang}wcf.global.form.error.empty{/lang}
+                                                       {else}
+                                                               {lang}wcf.acp.pageMenu.menuPosition.error.{$errorType}{/lang}
+                                                       {/if}
+                                               </small>
+                                       {/if}
+                               </dd>
+                       </dl>
+                       
+                       <dl id="parentMenuItemContainer"{if $errorField == 'parentMenuItem'} class="formError"{/if}>
+                               <dt><label for="parentMenuItem">{lang}wcf.acp.pageMenu.parentMenuItem{/lang}</label></dt>
+                               <dd>
+                                       <select name="parentMenuItem" id="parentMenuItem">
+                                               <option value=""{if $parentMenuItem == ''} selected="selected"{/if}></option>
+                                               {foreach from=$availableParentMenuItems item=availableParentMenuItem}
+                                                       <option value="{$availableParentMenuItem->menuItem}"{if $parentMenuItem == $availableParentMenuItem->menuItem} selected="selected"{/if}>{$availableParentMenuItem}</option>
+                                               {/foreach}
+                                       </select>
+                                       {if $errorField == 'parentMenuItem'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}
+                                                               {lang}wcf.global.form.error.empty{/lang}
+                                                       {else}
+                                                               {lang}wcf.acp.pageMenu.parentMenuItem.error.{$errorType}{/lang}
+                                                       {/if}
+                                               </small>
+                                       {/if}
+                               </dd>
+                       </dl>
+                       
+                       <dl{if $errorField == 'pageMenuItem'} class="formError"{/if}>
+                               <dt><label for="pageMenuItem">{lang}wcf.acp.pageMenu.pageMenuItem{/lang}</label></dt>
+                               <dd>
+                                       <input type="text" name="pageMenuItem" id="pageMenuItem" value="{$pageMenuItem}" class="long" required="required" />
+                                       {if $errorField == 'pageMenuItem'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}
+                                                               {lang}wcf.global.form.error.empty{/lang}
+                                                       {else}
+                                                               {lang}wcf.acp.pageMenu.pageMenuItem.error.{$errorType}{/lang}
+                                                       {/if}
+                                               </small>
+                                       {/if}
+                                       
+                                       {include file='multipleLanguageInputJavascript' elementIdentifier='pageMenuItem' forceSelection=true}
+                               </dd>
+                       </dl>
+                       
+                       <dl{if $errorField == 'menuItemLink'} class="formError"{/if}>
+                               <dt><label for="menuItemLink">{lang}wcf.acp.pageMenu.menuItemLink{/lang}</label></dt>
+                               <dd>
+                                       <input type="text" name="menuItemLink" id="menuItemLink" value="{$menuItemLink}" class="long" required="required" />
+                                       {if $errorField == 'menuItemLink'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}
+                                                               {lang}wcf.global.form.error.empty{/lang}
+                                                       {else}
+                                                               {lang}wcf.acp.pageMenu.menuItemLink.error.{$errorType}{/lang}
+                                                       {/if}
+                                               </small>
+                                       {/if}
+                                       
+                                       {include file='multipleLanguageInputJavascript' elementIdentifier='menuItemLink' forceSelection=false}
+                               </dd>
+                       </dl>
+                       
+                       <dl>
+                               <dd>
+                                       <label><input type="checkbox" name="newWindow" id="newWindow" value="1"{if $newWindow} checked="checked"{/if} /> <span>{lang}wcf.acp.pageMenu.newWindow{/lang}</span></label>
+                               </dd>
+                       </dl>
+               </fieldset>
+               
+               <fieldset>
+                       <legend>{lang}wcf.acp.pageMenu.advanced{/lang}</legend>
+                       
+                       <dl>
+                               <dt><label for="showOrder">{lang}wcf.acp.pageMenu.showOrder{/lang}</label></dt>
+                               <dd>
+                                       <input type="number" name="showOrder" id="showOrder" value="{@$showOrder}" class="long" min="0" />
+                               </dd>
+                       </dl>
+                       
+                       <dl>
+                               <dd>
+                                       <label><input type="checkbox" name="isDisabled" id="isDisabled" value="1"{if $isDisabled} checked="checked"{/if} /> <span>{lang}wcf.acp.pageMenu.isDisabled{/lang}</span></label>
+                               </dd>
+                       </dl>
+                       
+                       <dl id="isLandingPageContainer">
+                               <dd>
+                                       <label><input type="checkbox" name="isLandingPage" id="isLandingPage" value="1"{if $isLandingPage} checked="checked"{/if} /> <span>{lang}wcf.acp.pageMenu.isLandingPage{/lang}</span></label>
+                                       <small>{lang}wcf.acp.pageMenu.isLandingPage.description{/lang}</small>
+                               </dd>
+                       </dl>
+               </fieldset>
+               
+               <div class="formSubmit">
+                       <input type="submit" value="{lang}wcf.global.button.submit{/lang}" />
+               </div>
+       </form>
+</div>
+
+<div class="contentNavigation">
+       <nav>
+               <ul>
+                       <li><a href="{link controller='PageMenuItemList'}{/link}" class="button"><img src="{@RELATIVE_WCF_DIR}icon/list.svg" alt="" /> <span>{lang}wcf.acp.pageMenu.list{/lang}</span></a></li>
+               </ul>
+       </nav>
+</div>
+
+{include file='footer'}
diff --git a/wcfsetup/install/files/acp/templates/pageMenuItemList.tpl b/wcfsetup/install/files/acp/templates/pageMenuItemList.tpl
new file mode 100644 (file)
index 0000000..2b472ee
--- /dev/null
@@ -0,0 +1,115 @@
+{include file='header' pageTitle='wcf.acp.pageMenu.list'}
+
+<header class="boxHeadline">
+       <hgroup>
+               <h1>{lang}wcf.acp.pageMenu.list{/lang}</h1>
+       </hgroup>
+</header>
+
+<script type="text/javascript">
+       //<![CDATA[
+       $(function() {
+               new WCF.Action.Delete('wcf\\data\\page\\menu\\item\\PageMenuItemAction', $('.sortableNode'));
+               new WCF.Action.Toggle('wcf\\data\\page\\menu\\item\\PageMenuItemAction', $('.sortableNode'));
+               
+               {if $headerItems|count}new WCF.Sortable.List('pageMenuItemHeaderList', 'wcf\\data\\page\\menu\\item\\PageMenuItemAction', undefined, { protectRoot: true }, false, { menuPosition: 'header' });{/if}
+               {if $footerItems|count}new WCF.Sortable.List('pageMenuItemFooterList', 'wcf\\data\\page\\menu\\item\\PageMenuItemAction', undefined, { }, true, { menuPosition: 'footer' });{/if}
+       });
+       //]]>
+</script>
+
+<div class="contentNavigation">
+       <nav>
+               <ul>
+                       <li><a href="{link controller='PageMenuItemAdd'}{/link}" title="{lang}wcf.acp.pageMenu.add{/lang}" class="button"><img src="{@$__wcf->getPath()}icon/add.svg" alt="" class="icon24" /> <span>{lang}wcf.acp.pageMenu.add{/lang}</span></a></li>
+                       
+                       {event name='largeButtonsTop'}
+               </ul>
+       </nav>
+</div>
+
+{hascontent}
+       <fieldset>
+               <legend>{lang}wcf.acp.pageMenu.header{/lang}</legend>
+               
+               <div id="pageMenuItemHeaderList" class="container containerPadding sortableListContainer">
+                       <ol class="sortableList" data-object-id="0">
+                               {content}
+                                       {foreach from=$headerItems item=menuItem}
+                                               <li class="sortableNode" data-object-id="{@$menuItem->menuItemID}">
+                                                       <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}" />
+                                                                       <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}wcf.acp.pageMenu.delete.sure{/lang}" />
+                                                               </span>
+                                                       </span>
+                                                       {if $menuItem|count}
+                                                               <ol class="sortableList" data-object-id="{@$menuItem->menuItemID}">
+                                                                       {foreach from=$menuItem item=childMenuItem}
+                                                                               <li class="sortableNode sortableNoNesting" data-object-id="{@$childMenuItem->menuItemID}">
+                                                                                       <span class="sortableNodeLabel">
+                                                                                               <a href="{link controller='PageMenuItemEdit' id=$childMenuItem->menuItemID}{/link}">{lang}{$childMenuItem->menuItem}{/lang}</a>
+                                                                                               <span class="statusDisplay sortableButtonContainer">
+                                                                                                       <img src="{@$__wcf->getPath()}icon/{if $childMenuItem->isDisabled}disabled{else}enabled{/if}.svg" alt="" title="{lang}wcf.global.button.{if $childMenuItem->isDisabled}enable{else}disable{/if}{/lang}" class="icon16 jsToggleButton jsTooltip pointer" data-object-id="{@$childMenuItem->menuItemID}" data-disable-message="{lang}wcf.global.button.disable{/lang}" data-enable-message="{lang}wcf.global.button.enable{/lang}" />
+                                                                                                       <a href="{link controller='PageMenuItemEdit' id=$childMenuItem->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="{@$childMenuItem->menuItemID}" data-confirm-message="{lang}wcf.acp.pageMenu.delete.sure{/lang}" />
+                                                                                               </span>
+                                                                                       </span>
+                                                                               </li>
+                                                                       {/foreach}
+                                                               </ol>
+                                                       {/if}
+                                               </li>
+                                       {/foreach}
+                               {/content}
+                       </ol>
+                       
+                       <div class="formSubmit">
+                               <button data-type="submit">{lang}wcf.global.button.save{/lang}</button>
+                       </div>
+               </div>
+       </fieldset>
+{/hascontent}
+
+{hascontent}
+       <fieldset>
+               <legend>{lang}wcf.acp.pageMenu.footer{/lang}</legend>
+               
+               <div id="pageMenuItemFooterList" class="container containerPadding sortableListContainer">
+                       <ol class="sortableList simpleSortableList">
+                               {content}
+                                       {foreach from=$footerItems item=menuItem}
+                                               <li class="sortableNode" data-object-id="{@$menuItem->menuItemID}">
+                                                       <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}" />
+                                                                       <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}wcf.acp.pageMenu.delete.sure{/lang}" />
+                                                               </span>
+                                                       </span>
+                                               </li>
+                                       {/foreach}
+                               {/content}
+                       </ol>
+                       
+                       <div class="formSubmit">
+                               <button data-type="submit">{lang}wcf.global.button.save{/lang}</button>
+                       </div>
+               </div>
+       </fieldset>
+{/hascontent}
+
+<div class="contentNavigation">
+       <nav>
+               <ul>
+                       <li><a href="{link controller='PageMenuItemAdd'}{/link}" title="{lang}wcf.acp.pageMenu.add{/lang}" class="button"><img src="{@$__wcf->getPath()}icon/add.svg" alt="" class="icon24" /> <span>{lang}wcf.acp.pageMenu.add{/lang}</span></a></li>
+                       
+                       {event name='largeButtonsBottom'}
+               </ul>
+       </nav>
+</div>
+
+{include file='footer'}
diff --git a/wcfsetup/install/files/lib/acp/form/PageMenuItemAddForm.class.php b/wcfsetup/install/files/lib/acp/form/PageMenuItemAddForm.class.php
new file mode 100644 (file)
index 0000000..9208408
--- /dev/null
@@ -0,0 +1,260 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\page\menu\item\PageMenuItemAction;
+use wcf\data\page\menu\item\PageMenuItemEditor;
+use wcf\data\page\menu\item\PageMenuItemList;
+use wcf\system\exception\UserInputException;
+use wcf\system\language\I18nHandler;
+use wcf\system\package\PackageDependencyHandler;
+use wcf\system\WCF;
+use wcf\util\StringUtil;
+
+/**
+ * Shows the page menu item add form.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class PageMenuItemAddForm extends ACPForm {
+       /**
+        * @see wcf\acp\form\ACPForm::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.pageMenu.add';
+       
+       /**
+        * list of available parent menu items
+        * @var wcf\data\page\menu\item\PageMenuItemList
+        */
+       public $availableParentMenuItems = null;
+       
+       /**
+        * activation state
+        * @var boolean
+        */
+       public $isDisabled = false;
+       
+       /**
+        * true, if menu item is landing page
+        * @var boolean
+        */
+       public $isLandingPage = false;
+       
+       /**
+        * menu item link
+        * @var string
+        */
+       public $menuItemLink = '';
+       
+       /**
+        * menu item position
+        * @var string
+        */
+       public $menuPosition = 'header';
+       
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.display.canManagePageMenu');
+       
+       /**
+        * open link in new window
+        * @var boolean
+        */
+       public $newWindow = false;
+       
+       /**
+        * page menu item name
+        * @var string
+        */
+       public $pageMenuItem = '';
+       
+       /**
+        * parent menu item
+        * @var string
+        */
+       public $parentMenuItem = '';
+       
+       /**
+        * show order
+        * @var integer
+        */
+       public $showOrder = 0;
+       
+       /**
+        * @see wcf\page\IPage::readParameters()
+        */
+       public function readParameters() {
+               parent::readParameters();
+               
+               I18nHandler::getInstance()->register('menuItemLink');
+               I18nHandler::getInstance()->register('pageMenuItem');
+               
+               $this->readAvailableParentMenuItems();
+       }
+       
+       /**
+        * Prepares list object to read available parent menu items.
+        */
+       protected function initAvailableParentMenuItems() {
+               $this->availableParentMenuItems = new PageMenuItemList();
+               $this->availableParentMenuItems->getConditionBuilder()->add("page_menu_item.packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+               $this->availableParentMenuItems->getConditionBuilder()->add("page_menu_item.parentMenuItem = ''");
+               $this->availableParentMenuItems->sqlOrderBy = "page_menu_item.showOrder ASC";
+       }
+       
+       /**
+        * Reads a list of available parent menu items.
+        */
+       protected function readAvailableParentMenuItems() {
+               $this->initAvailableParentMenuItems();
+               
+               $this->availableParentMenuItems->readObjects();
+       }
+       
+       /**
+        * @see wcf\form\IForm::readFormParameters()
+        */
+       public function readFormParameters() {
+               parent::readFormParameters();
+               
+               I18nHandler::getInstance()->readValues();
+               if (I18nHandler::getInstance()->isPlainValue('menuItemLink')) $this->menuItemLink = I18nHandler::getInstance()->getValue('menuItemLink');
+               if (I18nHandler::getInstance()->isPlainValue('pageMenuItem')) $this->pageMenuItem = I18nHandler::getInstance()->getValue('pageMenuItem');
+               
+               if (isset($_POST['isDisabled'])) $this->isDisabled = true;
+               if (isset($_POST['isLandingPage'])) $this->isLandingPage = true;
+               if (isset($_POST['menuPosition'])) $this->menuPosition = StringUtil::trim($_POST['menuPosition']);
+               if (isset($_POST['newWindow'])) $this->newWindow = true;
+               if (isset($_POST['parentMenuItem'])) $this->parentMenuItem = StringUtil::trim($_POST['parentMenuItem']);
+               if (isset($_POST['showOrder'])) $this->showOrder = intval($_POST['showOrder']);
+       }
+       
+       /**
+        * @see wcf\form\IForm::validate()
+        */
+       public function validate() {
+               parent::validate();
+               
+               // validate menu position
+               if (empty($this->menuPosition)) {
+                       throw new UserInputException('menuPosition');
+               }
+               else if ($this->menuPosition != 'header' && $this->menuPosition != 'footer') {
+                       throw new UserInputException('menuPosition', 'notValid');
+               }
+               
+               // validate menu item link
+               if (!I18nHandler::getInstance()->validateValue('menuItemLink')) {
+                       throw new UserInputException('menuItemLink');
+               }
+               
+               // validate page menu item name
+               if (!I18nHandler::getInstance()->validateValue('pageMenuItem', true)) {
+                       throw new UserInputException('pageMenuItem');
+               }
+               
+               // validate parent menu item
+               if ($this->menuPosition == 'footer') {
+                       $this->parentMenuItem = '';
+               }
+               else if (!empty($this->parentMenuItem)) {
+                       $valid = false;
+                       foreach ($this->availableParentMenuItems as $menuItem) {
+                               if ($menuItem->menuItem == $this->parentMenuItem) {
+                                       $valid = true;
+                                       break;
+                               }
+                       }
+                       
+                       if (!$valid) {
+                               throw new UserInputException('parentMenuItem', 'notValid');
+                       }
+               }
+               
+               // validate landing page
+               if ($this->isDisabled) {
+                       $this->isLandingPage = false;
+               }
+               else if ($this->menuPosition == 'footer' || !empty($this->parentMenuItem)) {
+                       $this->isLandingPage = false;
+               }
+       }
+       
+       /**
+        * @see wcf\form\IForm::save()
+        */
+       public function save() {
+               parent::save();
+               
+               $this->objectAction = new PageMenuItemAction(array(), 'create', array('data' => array(
+                       'isDisabled' => ($this->isDisabled) ? 1 : 0,
+                       'isLandingPage' => ($this->isLandingPage) ? 1 : 0,
+                       'menuItem' => $this->pageMenuItem,
+                       'menuItemLink' => $this->menuItemLink,
+                       'menuPosition' => $this->menuPosition,
+                       'newWindow' => ($this->newWindow) ? 1 : 0,
+                       'parentMenuItem' => $this->parentMenuItem,
+                       'showOrder' => $this->showOrder
+               )));
+               $this->objectAction->executeAction();
+               
+               $returnValues = $this->objectAction->getReturnValues();
+               $menuItem = $returnValues['returnValues'];
+               $data = array();
+               if (!I18nHandler::getInstance()->isPlainValue('menuItemLink')) {
+                       I18nHandler::getInstance()->save('menuItemLink', 'wcf.page.menuItemLink'.$menuItem->menuItemID, 'wcf.page');
+                       $data['menuItemLink'] = 'wcf.page.menuItemLink'.$menuItem->menuItemID;
+               }
+               
+               // save menu item
+               I18nHandler::getInstance()->save('pageMenuItem', 'wcf.page.menuItem'.$menuItem->menuItemID, 'wcf.page');
+               $data['menuItem'] = 'wcf.page.menuItem'.$menuItem->menuItemID;
+               
+               // update i18n values
+               $menuItemEditor = new PageMenuItemEditor($menuItem);
+               $menuItemEditor->update($data);
+               
+               // call saved event
+               $this->saved();
+               
+               // show success
+               WCF::getTPL()->assign('success', true);
+               
+               // reset variables
+               $this->isDisabled = $this->isLandingPage = $this->newWindow = false;
+               $this->menuPosition = 'header';
+               $this->menuItemLink = $this->pageMenuItem = $this->parentMenuItem = '';
+               $this->showOrder = 0;
+               
+               // reload parent menu items
+               if ($menuItem->menuPosition == 'header' && $menuItem->parentMenuItem != '') {
+                       $this->readAvailableParentMenuItems();
+               }
+       }
+       
+       /**
+        * @see wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               I18nHandler::getInstance()->assignVariables();
+               
+               WCF::getTPL()->assign(array(
+                       'action' => 'add',
+                       'availableParentMenuItems' => $this->availableParentMenuItems,
+                       'isDisabled' => $this->isDisabled,
+                       'isLandingPage' => $this->isLandingPage,
+                       'menuItemLink' => $this->menuItemLink,
+                       'menuPosition' => $this->menuPosition,
+                       'newWindow' => $this->newWindow,
+                       'pageMenuItem' => $this->pageMenuItem,
+                       'parentMenuItem' => $this->parentMenuItem,
+                       'showOrder' => $this->showOrder
+               ));
+       }
+}
diff --git a/wcfsetup/install/files/lib/acp/form/PageMenuItemEditForm.class.php b/wcfsetup/install/files/lib/acp/form/PageMenuItemEditForm.class.php
new file mode 100644 (file)
index 0000000..52127b9
--- /dev/null
@@ -0,0 +1,129 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\page\menu\item\PageMenuItem;
+use wcf\data\page\menu\item\PageMenuItemAction;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\language\I18nHandler;
+use wcf\system\WCF;
+
+/**
+ * Shows the page menu item edit form.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class PageMenuItemEditForm extends PageMenuItemAddForm {
+       /**
+        * @see wcf\acp\form\ACPForm::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.pageMenu';
+       
+       /**
+        * page menu item object
+        * @var wcf\data\page\menu\item\PageMenuItem
+        */
+       public $menuItem = null;
+       
+       /**
+        * menu item id
+        * @var integer
+        */
+       public $menuItemID = 0;
+       
+       /**
+        * @see wcf\page\IPage::readParameters()
+        */
+       public function readParameters() {
+               if (isset($_REQUEST['id'])) $this->menuItemID = intval($_REQUEST['id']);
+               $this->menuItem = new PageMenuItem($this->menuItemID);
+               if (!$this->menuItem->menuItemID) {
+                       throw new IllegalLinkException();
+               }
+               
+               parent::readParameters();
+       }
+       
+       /**
+        * @see wcf\acp\form\PageMenuItemAddForm::initAvailableParentMenuItems()
+        */
+       protected function initAvailableParentMenuItems() {
+               parent::initAvailableParentMenuItems();
+               
+               // remove current item as valid parent menu item
+               $this->availableParentMenuItems->getConditionBuilder()->add("page_menu_item.menuItem <> ?", array($this->menuItem->menuItem));
+       }
+       
+       /**
+        * @see wcf\page\IPage::readData()
+        */
+       public function readData() {
+               parent::readData();
+               
+               I18nHandler::getInstance()->setOptions('menuItemLink', PACKAGE_ID, $this->menuItem->menuItemLink, 'wcf.page.menuItemLink\d+');
+               I18nHandler::getInstance()->setOptions('pageMenuItem', PACKAGE_ID, $this->menuItem->menuItem, 'wcf.page.menuItem\d+');
+               
+               if (empty($_POST)) {
+                       $this->isDisabled = ($this->menuItem->isDisabled) ? true : false;
+                       $this->isLandingPage = ($this->menuItem->isLandingPage) ? true : false;
+                       $this->menuPosition = $this->menuItem->menuPosition;
+                       $this->newWindow = ($this->menuItem->newWindow) ? true : false;
+                       $this->pageMenuItem = $this->menuItem->menuItem;
+                       $this->parentMenuItem = $this->menuItem->parentMenuItem;
+                       $this->showOrder = $this->menuItem->showOrder;
+               }
+       }
+       
+       /**
+        * @see wcf\form\IForm::save()
+        */
+       public function save() {
+               ACPForm::save();
+               
+               // save menu item
+               I18nHandler::getInstance()->save('pageMenuItem', $this->menuItem->menuItem, 'wcf.page');
+               
+               // save menu item link
+               $this->menuItemLink = 'wcf.page.menuItemLink'.$this->menuItem->menuItemID;
+               if (I18nHandler::getInstance()->isPlainValue('menuItemLink')) {
+                       I18nHandler::getInstance()->remove($this->menuItemLink);
+                       $this->menuItemLink= I18nHandler::getInstance()->getValue('menuItemLink');
+               }
+               else {
+                       I18nHandler::getInstance()->save('menuItemLink', $this->menuItemLink, 'wcf.page');
+               }
+               
+               // save menu item
+               $this->objectAction = new PageMenuItemAction(array($this->menuItem), 'update', array('data' => array(
+                       'isDisabled' => ($this->isDisabled) ? 1 : 0,
+                       'isLandingPage' => ($this->isLandingPage) ? 1 : 0,
+                       'menuItemLink' => $this->menuItemLink,
+                       'newWindow' => ($this->newWindow) ? 1 : 0,
+                       'parentMenuItem' => ($this->menuItem->menuPosition == 'header' ? $this->parentMenuItem : ''),
+                       'showOrder' => $this->showOrder
+               )));
+               $this->objectAction->executeAction();
+               
+               $this->saved();
+               
+               WCF::getTPL()->assign('success', true);
+       }
+       
+       /**
+        * @see wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               I18nHandler::getInstance()->assignVariables(!empty($_POST));
+               
+               WCF::getTPL()->assign(array(
+                       'action' => 'edit',
+                       'menuItem' => $this->menuItem,
+                       'menuItemID' => $this->menuItemID
+               ));
+       }
+}
diff --git a/wcfsetup/install/files/lib/acp/page/PageMenuItemListPage.class.php b/wcfsetup/install/files/lib/acp/page/PageMenuItemListPage.class.php
new file mode 100644 (file)
index 0000000..57a160b
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+namespace wcf\acp\page;
+use wcf\data\page\menu\item\PageMenuItemList;
+use wcf\data\page\menu\item\ViewablePageMenuItem;
+use wcf\page\AbstractPage;
+use wcf\system\menu\acp\ACPMenu;
+use wcf\system\package\PackageDependencyHandler;
+use wcf\system\WCF;
+
+/**
+ * Shows a list of page menu items.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.page
+ * @category   Community Framework
+ */
+class PageMenuItemListPage extends AbstractPage {
+       /**
+        * list of footer page menu items
+        * @var array<wcf\data\page\menu\item\PageMenuItem>
+        */
+       public $footerItems = array();
+       
+       /**
+        * list of header page menu items
+        * @var array<wcf\data\page\menu\item\PageMenuItem>
+        */
+       public $headerItems = array();
+       
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.display.canManagePageMenu');
+       
+       /**
+        * @see wcf\page\IPage::readData()
+        */
+       public function readData() {
+               parent::readData();
+               
+               $menuItemList = new PageMenuItemList();
+               $menuItemList->getConditionBuilder()->add("page_menu_item.packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+               $menuItemList->sqlOrderBy = "page_menu_item.parentMenuItem ASC, page_menu_item.showOrder ASC";
+               $menuItemList->readObjects();
+               
+               foreach ($menuItemList as $menuItem) {
+                       if ($menuItem->menuPosition == 'footer') {
+                               if ($menuItem->parentMenuItem) {
+                                       $this->footerItems[$menuItem->parentMenuItem]->addChild($menuItem);
+                               }
+                               else {
+                                       $this->footerItems[$menuItem->menuItem] = $menuItem;
+                               }
+                       }
+                       else {
+                               if ($menuItem->parentMenuItem) {
+                                       $this->headerItems[$menuItem->parentMenuItem]->addChild($menuItem);
+                               }
+                               else {
+                                       $this->headerItems[$menuItem->menuItem] = new ViewablePageMenuItem($menuItem);
+                               }
+                       }
+               }
+       }
+       
+       /**
+        * @see wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               WCF::getTPL()->assign(array(
+                       'footerItems' => $this->footerItems,
+                       'headerItems' => $this->headerItems
+               ));
+       }
+       
+       /**
+        * @see wcf\page\IPage::show()
+        */
+       public function show() {
+               // set active menu item.
+               ACPMenu::getInstance()->setActiveMenuItem('wcf.acp.menu.link.pageMenu.list');
+               
+               parent::show();
+       }
+}
diff --git a/wcfsetup/install/files/lib/data/ISortableAction.class.php b/wcfsetup/install/files/lib/data/ISortableAction.class.php
new file mode 100644 (file)
index 0000000..86decc8
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+namespace wcf\data;
+
+/**
+ * Default interface for sortable database objects.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data
+ * @category   Community Framework
+ */
+interface ISortableAction {
+       /**
+        * Validates the 'updatePosition' action.
+        */
+       public function validateUpdatePosition();
+       
+       /**
+        * Updates the position of given objects.
+        */
+       public function updatePosition();
+}
index 3ade88de0abf8fc1e1b5947376fcecfd79417cdf..adb7879e23b6a67910497fd466bfece4bfc03f38 100644 (file)
@@ -5,9 +5,10 @@ use wcf\system\application\ApplicationHandler;
 use wcf\system\menu\page\DefaultPageMenuItemProvider;
 use wcf\system\menu\ITreeMenuItem;
 use wcf\system\request\LinkHandler;
+use wcf\system\WCF;
 
 /**
- * Represents an page menu item.
+ * Represents a page menu item.
  * 
  * @author     Alexander Ebert
  * @copyright  2001-2012 WoltLab GmbH
@@ -54,6 +55,15 @@ class PageMenuItem extends ProcessibleDatabaseObject implements ITreeMenuItem {
                        $parameters['application'] = $abbreviation;
                }
                
-               return LinkHandler::getInstance()->getLink(null, $parameters, $this->menuItemLink);
+               return LinkHandler::getInstance()->getLink(null, $parameters, WCF::getLanguage()->get($this->menuItemLink));
+       }
+       
+       /**
+        * Returns the menu item name.
+        * 
+        * @return      string
+        */
+       public function __toString() {
+               return WCF::getLanguage()->get($this->menuItem);
        }
 }
index e8481ec82de769ec85975ff546855c5b40d4c3f5..62b767f97ae939899310899ec7fe208b93a117f1 100644 (file)
@@ -1,6 +1,10 @@
 <?php
 namespace wcf\data\page\menu\item;
 use wcf\data\AbstractDatabaseObjectAction;
+use wcf\data\ISortableAction;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\exception\UserInputException;
+use wcf\system\WCF;
 
 /**
  * Executes page menu item-related actions.
@@ -12,9 +16,99 @@ use wcf\data\AbstractDatabaseObjectAction;
  * @subpackage data.page.menu.item
  * @category   Community Framework
  */
-class PageMenuItemAction extends AbstractDatabaseObjectAction {
+class PageMenuItemAction extends AbstractDatabaseObjectAction implements ISortableAction {
        /**
         * @see wcf\data\AbstractDatabaseObjectAction::$className
         */
        protected $className = 'wcf\data\page\menu\item\PageMenuItemEditor';
+       
+       /**
+        * list of menu items
+        * @var array<wcf\data\page\menu\item\PageMenuItem>
+        */
+       public $menuItems = array();
+       
+       /**
+        * @see wcf\data\IDatabaseObjectAction::create()
+        */
+       public function create() {
+               if (!isset($this->parameters['data']['packageID'])) {
+                       $this->parameters['data']['packageID'] = PACKAGE_ID;
+               }
+               
+               $menuItem = parent::create();
+               
+               if ($menuItem->isLandingPage) {
+                       $menuItemEditor = new PageMenuItemEditor($menuItem);
+                       $menuItemEditor->setAsLandingPage();
+               }
+               
+               return $menuItem;
+       }
+       
+       /**
+        * @see wcf\data\ISortableAction::validateUpdatePosition()
+        */
+       public function validateUpdatePosition() {
+               WCF::getSession()->checkPermissions(array('admin.display.canManagePageMenu'));
+               
+               if (!isset($this->parameters['data']) || !isset($this->parameters['data']['structure']) || !is_array($this->parameters['data']['structure'])) {
+                       throw new UserInputException('structure');
+               }
+               
+               if (!isset($this->parameters['menuPosition']) || !in_array($this->parameters['menuPosition'], array('footer', 'header'))) {
+                       throw new UserInputException('structure');
+               }
+               
+               if ($this->parameters['menuPosition'] == 'footer') {
+                       if (count($this->parameters['data']['structure']) > 1 || !isset($this->parameters['data']['structure'][0])) {
+                               throw new UserInputException('structure');
+                       }
+               }
+               
+               $menuItemIDs = array();
+               foreach ($this->parameters['data']['structure'] as $menuItems) {
+                       $menuItemIDs = array_merge($menuItemIDs, $menuItems);
+               }
+               
+               $menuItemList = new PageMenuItemList();
+               $menuItemList->getConditionBuilder()->add("page_menu_item.menuItemID IN (?)", array($menuItemIDs));
+               $menuItemList->getConditionBuilder()->add("page_menu_item.menuPosition = ?", array($this->parameters['menuPosition']));
+               $menuItemList->sqlLimit = 0;
+               $menuItemList->readObjects();
+               $this->menuItems = $menuItemList->getObjects();
+               
+               if (count($this->menuItems) != count($menuItemIDs)) {
+                       throw new UserInputException('structure');
+               }
+               
+               foreach ($this->parameters['data']['structure'] as $parentMenuItemID => $menuItems) {
+                       if ($parentMenuItemID && !isset($this->menuItems[$parentMenuItemID])) {
+                               throw new UserInputException('structure');
+                       }
+               }
+       }
+       
+       /**
+        * @see wcf\data\ISortableAction::updatePosition()
+        */
+       public function updatePosition() {
+               $sql = "UPDATE  wcf".WCF_N."_page_menu_item
+                       SET     parentMenuItem = ?,
+                               showOrder = ?
+                       WHERE   menuItemID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               
+               WCF::getDB()->beginTransaction();
+               foreach ($this->parameters['data']['structure'] as $parentMenuItemID => $menuItems) {
+                       foreach ($menuItems as $showOrder => $menuItemID) {
+                               $statement->execute(array(
+                                       ($parentMenuItemID ? $this->menuItems[$parentMenuItemID]->menuItem : ''),
+                                       $showOrder,
+                                       $menuItemID
+                               ));
+                       }
+               }
+               WCF::getDB()->commitTransaction();
+       }
 }
index 33378667ea1a536b4bf35c12d2f6cc53a40a5de0..35bdcd909d590073c739d6ca9ef3d7507a49f335 100644 (file)
@@ -3,6 +3,8 @@ namespace wcf\data\page\menu\item;
 use wcf\data\DatabaseObjectEditor;
 use wcf\data\IEditableCachedObject;
 use wcf\system\cache\CacheHandler;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\package\PackageDependencyHandler;
 use wcf\system\WCF;
 
 /**
@@ -50,16 +52,17 @@ class PageMenuItemEditor extends DatabaseObjectEditor implements IEditableCached
         * @see wcf\data\IEditableObject::delete()
         */
        public function delete() {
+               $conditions = new PreparedStatementConditionBuilder();
+               $conditions->add("packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+               $conditions->add("showOrder >= ?", array($this->showOrder));
+               $conditions->add("menuPosition = ?", array($this->menuPosition));
+               
                // update show order
                $sql = "UPDATE  wcf".WCF_N."_page_menu_item
                        SET     showOrder = showOrder - 1
-                       WHERE   showOrder >= ?
-                               AND menuPosition = ?";
+                       ".$conditions;
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array(
-                       $this->showOrder,
-                       $this->menuPosition
-               ));
+               $statement->execute($conditions->getParameters());
                
                parent::delete();
        }
@@ -72,17 +75,38 @@ class PageMenuItemEditor extends DatabaseObjectEditor implements IEditableCached
         * @param       integer         $showOrder
         */
        public static function setShowOrder($menuItemID, $menuPosition = 'header', $showOrder = 1) {
-               // Update
+               $conditions = new PreparedStatementConditionBuilder();
+               $conditions->add("packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+               $conditions->add("menuItemID = ?", array($menuItemID));
+               
+               // update show order
                $sql = "UPDATE  wcf".WCF_N."_page_menu_item
                        SET     showOrder = ?,
                                menuPosition = ?
-                       WHERE   menuItemID = ?";
+                       ".$conditions;
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array(
+               
+               $parameters = array_merge(array(
                        $showOrder,
-                       $menuPosition,
-                       $menuItemID
-               ));
+                       $menuPosition
+               ), $conditions->getParameters());
+               $statement->execute($parameters);
+       }
+       
+       /**
+        * Sets current page menu item as landing page.
+        */
+       public function setAsLandingPage() {
+               $conditions = new PreparedStatementConditionBuilder();
+               $conditions->add("packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+               
+               $sql = "UPDATE  wcf".WCF_N."_page_menu_item
+                       SET     isLandingPage = 0
+                       ".$conditions;
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute($conditions->getParameters());
+               
+               $this->update(array('isLandingPage' => 1));
        }
        
        /**
@@ -94,18 +118,18 @@ class PageMenuItemEditor extends DatabaseObjectEditor implements IEditableCached
        protected function updateShowOrder($showOrder, $menuPosition) {
                if ($menuPosition == $this->menuPosition) {
                        if ($this->showOrder != $showOrder) {
+                               $conditions = new PreparedStatementConditionBuilder();
+                               $conditions->add("packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+                               $conditions->add("showOrder <= ?", array($showOrder));
+                               $conditions->add("showOrder > ?", array($this->showOrder));
+                               $conditions->add("menuPosition = ?", array($menuPosition));
+                               
                                if ($showOrder < $this->showOrder) {
                                        $sql = "UPDATE  wcf".WCF_N."_page_menu_item
                                                SET     showOrder = showOrder + 1
-                                               WHERE   showOrder >= ?
-                                                       AND showOrder < ?
-                                                       AND menuPosition = ?";
+                                               ".$conditions;
                                        $statement = WCF::getDB()->prepareStatement($sql);
-                                       $statement->execute(array(
-                                               $showOrder,
-                                               $this->showOrder,
-                                               $menuPosition
-                                       ));
+                                       $statement->execute($conditions->getParameters());
                                }
                                else if ($showOrder > $this->showOrder) {
                                        $sql = "UPDATE  wcf".WCF_N."_page_menu_item
@@ -114,34 +138,32 @@ class PageMenuItemEditor extends DatabaseObjectEditor implements IEditableCached
                                                        AND showOrder > ?
                                                        AND menuPosition = ?";
                                        $statement = WCF::getDB()->prepareStatement($sql);
-                                       $statement->execute(array(
-                                               $showOrder,
-                                               $this->showOrder,
-                                               $menuPosition
-                                       ));
+                                       $statement->execute($conditions->getParameters());
                                }
                        }
                }
                else {
+                       $conditions = new PreparedStatementConditionBuilder();
+                       $conditions->add("packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+                       $conditions->add("showOrder >= ?", array($this->showOrder));
+                       $conditions->add("menuPosition = ?", array($this->menuPosition));
+                       
                        $sql = "UPDATE  wcf".WCF_N."_page_menu_item
                                SET     showOrder = showOrder - 1
-                               WHERE   showOrder >= ?
-                                       AND menuPosition = ?";
+                               ".$conditions;
                        $statement = WCF::getDB()->prepareStatement($sql);
-                       $statement->execute(array(
-                               $this->showOrder,
-                               $this->menuPosition
-                       ));
-                               
+                       $statement->execute($conditions->getParameters());
+                       
+                       $conditions = new PreparedStatementConditionBuilder();
+                       $conditions->add("packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+                       $conditions->add("showOrder >= ?", array($showOrder));
+                       $conditions->add("menuPosition = ?", array($menuPosition));
+                       
                        $sql = "UPDATE  wcf".WCF_N."_page_menu_item
                                SET     showOrder = showOrder + 1
-                               WHERE   showOrder >= ?
-                                       AND menuPosition = ?";
+                               ".$conditions;
                        $statement = WCF::getDB()->prepareStatement($sql);
-                       $statement->execute(array(
-                               $showOrder,
-                               $menuPosition
-                       ));
+                       $statement->execute($conditions->getParameters());
                }
        }
        
@@ -154,26 +176,31 @@ class PageMenuItemEditor extends DatabaseObjectEditor implements IEditableCached
         */
        protected static function getShowOrder($showOrder, $menuPosition) {
                if ($showOrder == 0) {
+                       $conditions = new PreparedStatementConditionBuilder();
+                       $conditions->add("packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+                       $conditions->add("menuPosition = ?", array($menuPosition));
+                       
                        // get next number in row
                        $sql = "SELECT  MAX(showOrder) AS showOrder
                                FROM    wcf".WCF_N."_page_menu_item
-                               WHERE   menuPosition = ?";
+                               ".$conditions;
                        $statement = WCF::getDB()->prepareStatement($sql);
-                       $statement->execute(array($menuPosition));
+                       $statement->execute($conditions->getParameters());
                        $row = $statement->fetchArray();
                        if (!empty($row)) $showOrder = intval($row['showOrder']) + 1;
                        else $showOrder = 1;
                }
                else {
+                       $conditions = new PreparedStatementConditionBuilder();
+                       $conditions->add("packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+                       $conditions->add("showOrder >= ?", array($showOrder));
+                       $conditions->add("menuPosition = ?", array($menuPosition));
+                       
                        $sql = "UPDATE  wcf".WCF_N."_page_menu_item
                                SET     showOrder = showOrder + 1
-                               WHERE   showOrder >= ?
-                                       AND menuPosition = ?";
+                               ".$conditions;
                        $statement = WCF::getDB()->prepareStatement($sql);
-                       $statement->execute(array(
-                               $showOrder,
-                               $menuPosition
-                       ));
+                       $statement->execute($conditions->getParameters());
                }
                
                return $showOrder;
diff --git a/wcfsetup/install/files/lib/data/page/menu/item/ViewablePageMenuItem.class.php b/wcfsetup/install/files/lib/data/page/menu/item/ViewablePageMenuItem.class.php
new file mode 100644 (file)
index 0000000..2730506
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+namespace wcf\data\page\menu\item;
+use wcf\data\DatabaseObjectDecorator;
+
+/**
+ * Provides a viewable page menu item with children support.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage data.page.menu.item
+ * @category   Community Framework
+ */
+class ViewablePageMenuItem extends DatabaseObjectDecorator implements \Countable, \Iterator {
+       /**
+        * @see wcf\data\DatabaseObjectDecorator::$baseClass
+        */
+       protected static $baseClass = 'wcf\data\page\menu\item\PageMenuItem';
+       
+       /**
+        * current iterator index
+        * @var integer
+        */
+       protected $index = 0;
+       
+       /**
+        * list of page menu items
+        * @var array<wcf\data\page\menu\item\PageMenuItem>
+        */
+       protected $objects = array();
+       
+       /**
+        * Adds a page menu item to collection.
+        * 
+        * @param       wcf\data\page\menu\item\PageMenuItem    $menuItem
+        */
+       public function addChild(PageMenuItem $menuItem) {
+               if ($menuItem->parentMenuItem == $this->menuItem) {
+                       $this->objects[] = $menuItem;
+               }
+       }
+       
+       /**
+        * @see \Countable::count()
+        */
+       public function count() {
+               return count($this->objects);
+       }
+       
+       /**
+        * @see \Iterator::current()
+        */
+       public function current() {
+               return $this->objects[$this->index];
+       }
+       
+       /**
+        * @see \Iterator::key()
+        */
+       public function key() {
+               return $this->index;
+       }
+       
+       /**
+        * @see \Iterator::next()
+        */
+       public function next() {
+               ++$this->index;
+       }
+       
+       /**
+        * @see \Iterator::rewind()
+        */
+       public function rewind() {
+               $this->index = 0;
+       }
+       
+       /**
+        * @see \Iterator::valid()
+        */
+       public function valid() {
+               return isset($this->objects[$this->index]);
+       }
+}
index 07f61d82ef5dea547957f7dc7ff2cfc80c815be4..598ad03e9fdaef791209f024277800f9ec308462 100644 (file)
@@ -3,6 +3,8 @@ namespace wcf\system\language;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\exception\SystemException;
 use wcf\system\language\LanguageFactory;
+use wcf\system\package\PackageDependencyHandler;
+use wcf\system\Regex;
 use wcf\system\SingletonFactory;
 use wcf\system\WCF;
 use wcf\util\StringUtil;
@@ -54,6 +56,12 @@ class I18nHandler extends SingletonFactory {
         */
        protected $elementOptions = array();
        
+       /**
+        * language variable regex object
+        * @var wcf\system\Regex
+        */
+       protected $regex = null;
+       
        /**
         * @see wcf\system\SingletonFactory::init()
         */
@@ -246,16 +254,14 @@ class I18nHandler extends SingletonFactory {
        }
        
        /**
-        * Saves language variable for i18n. Given package id must match the associated
-        * packages, using PACKAGE_ID is highly discouraged as this breaks the ability
-        * to delete unused language items on package uninstallation using foreign keys.
+        * Saves language variable for i18n.
         * 
         * @param       string          $elementID
         * @param       string          $languageVariable
         * @param       string          $languageCategory
         * @param       integer         $packageID
         */
-       public function save($elementID, $languageVariable, $languageCategory, $packageID) {
+       public function save($elementID, $languageVariable, $languageCategory, $packageID = PACKAGE_ID) {
                // get language category id
                $sql = "SELECT  languageCategoryID
                        FROM    wcf".WCF_N."_language_category
@@ -270,7 +276,13 @@ class I18nHandler extends SingletonFactory {
                $conditions = new PreparedStatementConditionBuilder();
                $conditions->add("languageID IN (?)", array($languageIDs));
                $conditions->add("languageItem = ?", array($languageVariable));
-               $conditions->add("packageID = ?", array($packageID));
+               
+               if (isset($this->elementOptions[$elementID]) && !Regex::compile('^'.$this->elementOptions[$elementID]['pattern'].'$')->match($languageVariable) && $this->isLanguageVariable($languageVariable)) {
+                       $conditions->add("packageID IN (?)", array(PackageDependencyHandler::getInstance()->getDependencies()));
+               }
+               else {
+                       $conditions->add("packageID = ?", array($packageID));
+               }
                
                $sql = "SELECT  languageItemID, languageID
                        FROM    wcf".WCF_N."_language_item
@@ -336,7 +348,7 @@ class I18nHandler extends SingletonFactory {
         * @param       string          $languageVariable
         * @param       integer         $packageID
         */
-       public function remove($languageVariable, $packageID) {
+       public function remove($languageVariable, $packageID = PACKAGE_ID) {
                $sql = "DELETE FROM     wcf".WCF_N."_language_item
                        WHERE           languageItem = ?
                                        AND packageID = ?";
@@ -399,7 +411,13 @@ class I18nHandler extends SingletonFactory {
                                        }
                                }
                                else {
-                                       if (preg_match('~^'.$this->elementOptions[$elementID]['pattern'].'$~', $this->elementOptions[$elementID]['value'])) {
+                                       $isI18n = Regex::compile('^'.$this->elementOptions[$elementID]['pattern'].'$')->match($this->elementOptions[$elementID]['value']);
+                                       if (!$isI18n) {
+                                               // check if it's a regular language variable
+                                               $isI18n = Regex::compile('^([a-zA-Z0-9-_]+\.)+[a-zA-Z0-9-_]+$')->match($this->elementOptions[$elementID]['value']);
+                                       }
+                                       
+                                       if ($isI18n) {
                                                // use i18n values from language items
                                                $sql = "SELECT  languageID, languageItemValue
                                                        FROM    wcf".WCF_N."_language_item
@@ -445,4 +463,18 @@ class I18nHandler extends SingletonFactory {
        public function enableAssignValueVariables() {
                $this->assignValueVariablesDisabled = false;
        }
+       
+       /**
+        * Returns true, if given string equals a language variable.
+        * 
+        * @param       string          $string
+        * @return      boolean
+        */
+       protected function isLanguageVariable($string) {
+               if ($this->regex === null) {
+                       $this->regex = new Regex('^([a-zA-Z0-9-_]+\.)+[a-zA-Z0-9-_]+$');
+               }
+               
+               return $this->regex->match($string);
+       }
 }
index 062fce5f05bf5743011bf76b47ebf6a6bf993d83..92136c07e89d8819cb74fdfa8dc729da4e0a91ea 100644 (file)
@@ -507,6 +507,7 @@ CREATE TABLE wcf1_page_menu_item (
        isDisabled TINYINT(1) NOT NULL DEFAULT 0,
        className VARCHAR(255) NOT NULL DEFAULT '',
        isLandingPage TINYINT(1) NOT NULL DEFAULT 0,
+       newWindow TINYINT(1) NOT NULL DEFAULT 0,
        UNIQUE KEY (packageID, menuItem)
 );