Implemented individual box show orders per page
authorAlexander Ebert <ebert@woltlab.com>
Thu, 20 Apr 2017 12:07:50 +0000 (14:07 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Thu, 20 Apr 2017 12:07:56 +0000 (14:07 +0200)
See #2208

wcfsetup/install/files/acp/templates/pageAdd.tpl
wcfsetup/install/files/acp/templates/pageBoxOrder.tpl [new file with mode: 0644]
wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Page/BoxOrder.js [new file with mode: 0644]
wcfsetup/install/files/lib/acp/page/PageBoxOrderPage.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/data/box/Box.class.php
wcfsetup/install/files/lib/data/page/PageAction.class.php
wcfsetup/install/files/lib/system/box/BoxHandler.class.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml
wcfsetup/setup/db/install.sql

index 4efacf043582d13f5ed706fd320ea099629187ee..3eb631fc1375b02de038b0a5e2c5b6ab9354260f 100644 (file)
        
        <nav class="contentHeaderNavigation">
                <ul>
-                       {if $action == 'edit' && !$page->requireObjectID}
-                               <li><a href="{$page->getLink()}" class="button"><span class="icon icon16 fa-search"></span> <span>{lang}wcf.acp.page.button.viewPage{/lang}</span></a></li>
+                       {if $action == 'edit'}
+                               {if !$page->requireObjectID}
+                                       <li><a href="{$page->getLink()}" class="button"><span class="icon icon16 fa-search"></span> <span>{lang}wcf.acp.page.button.viewPage{/lang}</span></a></li>
+                               {/if}
+                               
+                               <li><a href="{link controller='PageBoxOrder' id=$page->pageID}{/link}" class="button"><span class="icon icon16 fa-sort-amount-asc"></span> <span>{lang}wcf.acp.page.button.boxOrder{/lang}</span></a></li>
                        {/if}
                        <li><a href="{link controller='PageList'}{/link}" class="button"><span class="icon icon16 fa-list"></span> <span>{lang}wcf.acp.menu.link.cms.page.list{/lang}</span></a></li>
                        
                
                <div id="boxes" class="tabMenuContent">
                        <div class="section">
+                               <p class="info">{lang}wcf.acp.page.boxOrder.page{@$action|ucfirst}{/lang}</p>
+                               
                                <dl{if $errorField == 'boxIDs'} class="formError"{/if}>
                                        <dt>{lang}wcf.acp.page.boxes{/lang}</dt>
                                        <dd>
diff --git a/wcfsetup/install/files/acp/templates/pageBoxOrder.tpl b/wcfsetup/install/files/acp/templates/pageBoxOrder.tpl
new file mode 100644 (file)
index 0000000..a88fb30
--- /dev/null
@@ -0,0 +1,44 @@
+{include file='header' pageTitle='wcf.acp.page.boxOrder'}
+
+<style>
+       #pbo [data-placeholder] {
+               background-color: rgb(224, 224, 224);
+               padding: 10px;
+       }
+</style>
+
+<header class="contentHeader">
+       <div class="contentHeaderTitle">
+               <h1 class="contentTitle">{lang}wcf.acp.page.boxOrder{/lang}</h1>
+       </div>
+       
+       <nav class="contentHeaderNavigation">
+               <ul>
+                       <li><a href="{link controller='LabelAdd'}{/link}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.acp.label.add{/lang}</span></a></li>
+                       
+                       {event name='contentHeaderNavigation'}
+               </ul>
+       </nav>
+</header>
+
+<div class="section" id="pbo">
+       <div data-placeholder="hero"></div>
+       <div class="pbo-quad" data-placeholder="headerBoxes"></div>
+       <div data-placeholder="top"></div>
+       
+       <div class="pbo-main">
+               <div data-placeholder="sidebarLeft"></div>
+               <div>
+                       <div data-placeholder="contentTop"></div>
+                       <div class="pbo-content">{lang}wcf.acp.page.boxOrder.position.content{/lang}</div>
+                       <div data-placeholder="contentBottom"></div>
+               </div>
+               <div data-placeholder="sidebarRight"></div>
+       </div>
+       
+       <div data-placeholder="bottom"></div>
+       <div class="pbo-quad" data-placeholder="footerBoxes"></div>
+       <div data-placeholder="footer"></div>
+</div>
+
+{include file='footer'}
diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Page/BoxOrder.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Page/BoxOrder.js
new file mode 100644 (file)
index 0000000..a898d8f
--- /dev/null
@@ -0,0 +1,98 @@
+define(['Ajax', 'Language', 'Ui/Confirmation', 'Ui/Notification'], function (Ajax, Language, UiConfirmation, UiNotification) {
+       "use strict";
+       
+       var _pageId = 0;
+       var _pbo = elById('pbo');
+       
+       return {
+               init: function (pageId, boxes) {
+                       _pageId = pageId;
+                       
+                       boxes.forEach(function(boxData, position) {
+                               var container = elCreate('ul');
+                               boxData.forEach(function(box) {
+                                       var item = elCreate('li');
+                                       elData(item, 'box-id', box.boxID);
+                                       item.innerHTML = box.name;
+                                       
+                                       container.appendChild(item);
+                               });
+                               
+                               if (boxData.length > 1) {
+                                       window.jQuery(container).sortable({
+                                               opacity: .6,
+                                               placeholder: 'sortablePlaceholder'
+                                       });
+                               }
+                               
+                               elBySel('[data-placeholder="' + position + '"]', _pbo).appendChild(container);
+                       });
+                       
+                       elBySel('button[data-type="submit"]').addEventListener(WCF_CLICK_EVENT, this._save.bind(this));
+                       
+                       var buttonDiscard = elBySel('.jsButtonCustomShowOrder');
+                       if (buttonDiscard) buttonDiscard.addEventListener(WCF_CLICK_EVENT, this._discard.bind(this));
+               },
+               
+               _save: function (event) {
+                       event.preventDefault();
+                       
+                       var data = {};
+                       
+                       // collect data
+                       elBySelAll('[data-placeholder]', _pbo, function (position) {
+                               var boxes = [];
+                               elBySelAll('li', position, function (li) {
+                                       var id = ~~elData(li, 'box-id');
+                                       if (id) boxes.push(id);
+                               });
+                               
+                               data[elData(position, 'placeholder')] = boxes;
+                       });
+                       
+                       Ajax.api(this, {
+                               parameters: {
+                                       position: data
+                               }
+                       });
+               },
+               
+               _discard: function (event) {
+                       event.preventDefault();
+                       
+                       UiConfirmation.show({
+                               confirm: (function () {
+                                       Ajax.api(this, {
+                                               actionName: 'resetPosition'
+                                       });
+                               }).bind(this),
+                               message: Language.get('wcf.acp.page.boxOrder.discard.confirmMessage')
+                       })
+               },
+               
+               _ajaxSuccess: function (data) {
+                       switch (data.actionName) {
+                               case 'updatePosition':
+                                       UiNotification.show();
+                                       break;
+                                       
+                               case 'resetPosition':
+                                       UiNotification.show(undefined, function () {
+                                               window.location.reload();
+                                       });
+                                       break;
+                       }
+               },
+               
+               _ajaxSetup: function () {
+                       return {
+                               data: {
+                                       actionName: 'updatePosition',
+                                       className: 'wcf\\data\\page\\PageAction',
+                                       interfaceName: 'wcf\\data\\ISortableAction',
+                                       objectIDs: [_pageId]
+                               }
+                       };
+               }
+       };
+});
\ No newline at end of file
diff --git a/wcfsetup/install/files/lib/acp/page/PageBoxOrderPage.class.php b/wcfsetup/install/files/lib/acp/page/PageBoxOrderPage.class.php
new file mode 100644 (file)
index 0000000..a6c090f
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+namespace wcf\acp\page;
+use wcf\data\box\Box;
+use wcf\data\page\Page;
+use wcf\data\page\PageCache;
+use wcf\page\AbstractPage;
+use wcf\system\box\BoxHandler;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\WCF;
+
+/**
+ * Shows the list of boxes for selected page and offers sorting capabilities.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2017 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\Acp\Page
+ * @since      3.0
+ */
+class PageBoxOrderPage extends AbstractPage {
+       /**
+        * @inheritDoc
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.cms.page.list';
+       
+       /**
+        * list of boxes by position
+        * @var Box[][]
+        */
+       public $boxes;
+       
+       /**
+        * @inheritDoc
+        */
+       public $neededPermissions = ['admin.content.cms.canManagePage'];
+       
+       /**
+        * page object
+        * @var Page
+        */
+       public $page;
+       
+       /**
+        * page id
+        * @var integer
+        */
+       public $pageID = 0;
+       
+       /**
+        * @inheritDoc
+        */
+       public function readParameters() {
+               parent::readParameters();
+               
+               if (!empty($_REQUEST['id'])) $this->pageID = intval($_REQUEST['id']);
+               
+               $this->page = PageCache::getInstance()->getPage($this->pageID);
+               if (!$this->page->pageID) {
+                       throw new IllegalLinkException();
+               }
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function readData() {
+               parent::readData();
+               
+               $this->boxes = BoxHandler::loadBoxes($this->pageID, false);
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               WCF::getTPL()->assign([
+                       'boxes' => $this->boxes,
+                       'hasCustomShowOrder' => BoxHandler::hasCustomShowOrder($this->pageID),
+                       'page' => $this->page,
+                       'pageID' => $this->pageID
+               ]);
+       }
+}
index 284c10593479d47b7c324123feb459c8b3928a2c..ebc1e4048b3a003a8bf80adcec5de90e4c8227fe 100644 (file)
@@ -109,6 +109,12 @@ class Box extends DatabaseObject {
         */
        protected $linkPage;
        
+       /**
+        * virtual show order of this box
+        * @var integer
+        */
+       public $virtualShowOrder = -1;
+       
        /**
         * @inheritDoc
         */
@@ -488,6 +494,15 @@ class Box extends DatabaseObject {
                return SimpleAclResolver::getInstance()->canAccess('com.woltlab.wcf.box', $this->boxID);
        }
        
+       /**
+        * Sets the virtual show order of this box.
+        * 
+        * @param       integer         $virtualShowOrder
+        */
+       public function setVirtualShowOrder($virtualShowOrder) {
+               $this->virtualShowOrder = $virtualShowOrder;
+       }
+       
        /**
         * Returns the box with the given identifier.
         *
index b30a84d79d1f60f7c29e3b208280cd96774cd265..4e929f8d92dedb12c160f79309ca7c8f7d6774e0 100644 (file)
@@ -1,10 +1,13 @@
 <?php
 namespace wcf\data\page;
+use wcf\data\box\Box;
+use wcf\data\ISortableAction;
 use wcf\data\page\content\PageContent;
 use wcf\data\page\content\PageContentEditor;
 use wcf\data\AbstractDatabaseObjectAction;
 use wcf\data\ISearchAction;
 use wcf\data\IToggleAction;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\exception\PermissionDeniedException;
 use wcf\system\exception\UserInputException;
 use wcf\system\html\simple\HtmlSimpleParser;
@@ -26,7 +29,7 @@ use wcf\system\WCF;
  * @method     PageEditor[]    getObjects()
  * @method     PageEditor      getSingleObject()
  */
-class PageAction extends AbstractDatabaseObjectAction implements ISearchAction, IToggleAction {
+class PageAction extends AbstractDatabaseObjectAction implements ISearchAction, ISortableAction, IToggleAction {
        /**
         * @inheritDoc
         */
@@ -55,7 +58,7 @@ class PageAction extends AbstractDatabaseObjectAction implements ISearchAction,
        /**
         * @inheritDoc
         */
-       protected $requireACP = ['create', 'delete', 'getSearchResultList', 'search', 'toggle', 'update'];
+       protected $requireACP = ['create', 'delete', 'getSearchResultList', 'resetPosition', 'search', 'toggle', 'update', 'updatePosition'];
        
        /**
         * @inheritDoc
@@ -387,4 +390,102 @@ class PageAction extends AbstractDatabaseObjectAction implements ISearchAction,
                        SearchIndexManager::getInstance()->delete('com.woltlab.wcf.page', $pageContentIDs);
                }
        }
+       
+       /**
+        * @inheritDoc
+        */
+       public function validateUpdatePosition() {
+               WCF::getSession()->checkPermissions(['admin.content.cms.canManagePage']);
+               
+               $this->pageEditor = $this->getSingleObject();
+               
+               if (empty($this->parameters['position']) || !is_array($this->parameters['position'])) {
+                       throw new UserInputException('position');
+               }
+               
+               $seenBoxIDs = [];
+               foreach ($this->parameters['position'] as $position => $boxIDs) {
+                       // validate each position for both existence and the supplied box ids
+                       if (!in_array($position, Box::$availablePositions) || !is_array($boxIDs)) {
+                               throw new UserInputException('position');
+                       }
+                       
+                       foreach ($boxIDs as $boxID) {
+                               // check for duplicate box ids
+                               if (in_array($boxID, $seenBoxIDs)) {
+                                       throw new UserInputException('position');
+                               }
+                               
+                               $seenBoxIDs[] = $boxID;
+                       }
+               }
+               
+               // validates box ids
+               $conditions = new PreparedStatementConditionBuilder();
+               $conditions->add("boxID IN (?)", [$seenBoxIDs]);
+               
+               $sql = "SELECT  boxID
+                       FROM    wcf".WCF_N."_box
+                       ".$conditions;
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute($conditions->getParameters());
+               $validBoxIDs = [];
+               while ($boxID = $statement->fetchColumn()) {
+                       $validBoxIDs[] = $boxID;
+               }
+               
+               foreach ($seenBoxIDs as $boxID) {
+                       if (!in_array($boxID, $validBoxIDs)) {
+                               throw new UserInputException('position');
+                       }
+               }
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function updatePosition() {
+               $pageID = $this->pageEditor->getDecoratedObject()->pageID;
+               
+               $sql = "DELETE FROM     wcf".WCF_N."_page_box_order
+                       WHERE           pageID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([$pageID]);
+               
+               $sql = "INSERT INTO     wcf".WCF_N."_page_box_order
+                                       (pageID, boxID, showOrder)
+                       VALUES          (?, ?, ?)";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               
+               WCF::getDB()->beginTransaction();
+               foreach ($this->parameters['position'] as $boxIDs) {
+                       for ($i = 0, $length = count($boxIDs); $i < $length; $i++) {
+                               $statement->execute([
+                                       $pageID,
+                                       $boxIDs[$i],
+                                       $i
+                               ]);
+                       }
+               }
+               WCF::getDB()->commitTransaction();
+       }
+       
+       /**
+        * Validates parameters to reset the custom box positions for provided page.
+        */
+       public function validateResetPosition() {
+               WCF::getSession()->checkPermissions(['admin.content.cms.canManagePage']);
+               
+               $this->pageEditor = $this->getSingleObject();
+       }
+       
+       /**
+        * Resets the custom box positions for provided page.
+        */
+       public function resetPosition() {
+               $sql = "DELETE FROM     wcf".WCF_N."_page_box_order
+                       WHERE           pageID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([$this->pageEditor->getDecoratedObject()->pageID]);
+       }
 }
index c097762409021414a10f5ff4d41063cce3682d3f..3a1981f52774c53a83bf89c49abb7916e8a09c74 100644 (file)
@@ -53,20 +53,10 @@ class BoxHandler extends SingletonFactory {
                        }
                }
                
-               // load box layout for active page
-               $boxList = new BoxList();
-               $boxList->enableContentLoading();
-               if ($pageID) $boxList->getConditionBuilder()->add('(box.visibleEverywhere = ? AND boxID NOT IN (SELECT boxID FROM wcf'.WCF_N.'_box_to_page WHERE pageID = ? AND visible = ?)) OR boxID IN (SELECT boxID FROM wcf'.WCF_N.'_box_to_page WHERE pageID = ? AND visible = ?)', [1, $pageID, 0, $pageID, 1]);
-               else $boxList->getConditionBuilder()->add('box.visibleEverywhere = ?', [1]);
-               $boxList->sqlOrderBy = 'showOrder';
-               $boxList->readObjects();
-               
-               $this->boxes = $boxList->getObjects();
-               foreach ($boxList as $box) {
-                       if ($box->isAccessible()) {
-                               if (!isset($this->boxesByPosition[$box->position])) $this->boxesByPosition[$box->position] = [];
-                               $this->boxesByPosition[$box->position][] = $box;
-                               
+               $this->boxesByPosition = self::loadBoxes($pageID, true);
+               foreach ($this->boxesByPosition as $boxes) {
+                       foreach ($boxes as $box) {
+                               $this->boxes[$box->boxID] = $box;
                                $this->boxesByIdentifier[$box->identifier] = $box;
                        }
                }
@@ -206,4 +196,74 @@ class BoxHandler extends SingletonFactory {
        public static function disablePageLayout() {
                self::$disablePageLayout = true;
        }
+       
+       /**
+        * Returns the list of boxes sorted by their global and page-local show order.
+        * 
+        * @param       integer         $pageID         page id
+        * @param       boolean         $forDisplay     enables content loading and removes inaccessible boxes from view
+        * @return      Box[][]
+        */
+       public static function loadBoxes($pageID, $forDisplay) {
+               // load box layout for active page
+               $boxList = new BoxList();
+               if ($pageID) $boxList->getConditionBuilder()->add('(box.visibleEverywhere = ? AND boxID NOT IN (SELECT boxID FROM wcf'.WCF_N.'_box_to_page WHERE pageID = ? AND visible = ?)) OR boxID IN (SELECT boxID FROM wcf'.WCF_N.'_box_to_page WHERE pageID = ? AND visible = ?)', [1, $pageID, 0, $pageID, 1]);
+               else $boxList->getConditionBuilder()->add('box.visibleEverywhere = ?', [1]);
+               
+               if ($forDisplay) $boxList->enableContentLoading();
+               
+               $boxList->readObjects();
+               
+               $showOrders = [];
+               if ($pageID) {
+                       $sql = "SELECT  boxID, showOrder
+                               FROM    wcf" . WCF_N . "_page_box_order
+                               WHERE   pageID = ?";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute([$pageID]);
+                       while ($row = $statement->fetchArray()) {
+                               $showOrders[$row['boxID']] = $row['showOrder'];
+                       }
+               }
+               
+               $boxes = [];
+               foreach ($boxList as $box) {
+                       if (!$forDisplay || $box->isAccessible()) {
+                               $virtualShowOrder = (isset($showOrders[$box->boxID])) ? $showOrders[$box->boxID] : ($box->showOrder + 1000);
+                               $box->setVirtualShowOrder($virtualShowOrder);
+                               
+                               if (!isset($boxes[$box->position])) $boxes[$box->position] = [];
+                               $boxes[$box->position][] = $box;
+                       }
+               }
+               
+               foreach ($boxes as &$positionBoxes) {
+                       usort($positionBoxes, function($a, $b) {
+                               if ($a->virtualShowOrder == $b->virtualShowOrder) {
+                                       return 0;
+                               }
+                               
+                               return ($a->virtualShowOrder < $b->virtualShowOrder) ? -1 : 1;
+                       });
+               }
+               unset($positionBoxes);
+               
+               return $boxes;
+       }
+       
+       /**
+        * Returns true if provided page id uses a custom box show order.
+        * 
+        * @param       integer         $pageID         page id
+        * @return      boolean         true if there is a custom show order for boxes
+        */
+       public static function hasCustomShowOrder($pageID) {
+               $sql = "SELECT  COUNT(*) AS count
+                       FROM    wcf".WCF_N."_page_box_order
+                       WHERE   pageID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([$pageID]);
+               
+               return $statement->fetchColumn() > 0;
+       }
 }
index 8c9ead7d27cf5b07987ebcca09720baa6a0e7eab..18f42a32f12620204f957b2d9a075f5baeb2dd67 100644 (file)
@@ -1406,6 +1406,13 @@ GmbH=Gesellschaft mit beschränkter Haftung]]></item>
                <item name="wcf.acp.page.add"><![CDATA[Seite hinzufügen]]></item>
                <item name="wcf.acp.page.application"><![CDATA[App]]></item>
                <item name="wcf.acp.page.boxes"><![CDATA[Ausgewählte Boxen auf dieser Seite anzeigen]]></item>
+               <item name="wcf.acp.page.boxOrder"><![CDATA[Boxen sortieren]]></item>
+               <item name="wcf.acp.page.boxOrder.discard"><![CDATA[Sortierung verwerfen]]></item>
+               <item name="wcf.acp.page.boxOrder.discard.confirmMessage"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Willst du{else}Wollen Sie{/if} individuelle Sortierung der Boxen für diese Seite wirklich löschen?]]></item>
+               <item name="wcf.acp.page.boxOrder.pageAdd"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du kannst{else}Sie können{/if} die individuelle Sortierung der Boxen für diese Seite nach dem Speichern festlegen.]]></item>
+               <item name="wcf.acp.page.boxOrder.pageEdit"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du kannst{else}Sie können{/if} die Sortierung der angezeigten Boxen <a href="{link controller='PageBoxOrder' id=$page->pageID}{/link}">individuell festlegen</a>, bitte {if LANGUAGE_USE_INFORMAL_VARIANT}speichere{else}speichern Sie{/if} zuvor {if LANGUAGE_USE_INFORMAL_VARIANT}deine{else}Ihre{/if} Änderungen.]]></item>
+               <item name="wcf.acp.page.boxOrder.position.content"><![CDATA[(Inhalt)]]></item>
+               <item name="wcf.acp.page.button.boxOrder"><![CDATA[Boxen sortieren]]></item>
                <item name="wcf.acp.page.button.viewPage"><![CDATA[Vorschau anzeigen]]></item>
                <item name="wcf.acp.page.content"><![CDATA[Inhalt]]></item>
                <item name="wcf.acp.page.contents"><![CDATA[Inhalte]]></item>
index 7e04e5ca320c9b230398fe63f2e50a9c037a1d46..d43fbba8ba2ecf5c7b19f7cf3e0bf76aa50b57b8 100644 (file)
@@ -2900,6 +2900,13 @@ Errors are:
                <item name="wcf.acp.page.add"><![CDATA[Add Page]]></item>
                <item name="wcf.acp.page.application"><![CDATA[App]]></item>
                <item name="wcf.acp.page.boxes"><![CDATA[Display the Selected Boxes on This Page]]></item>
+               <item name="wcf.acp.page.boxOrder"><![CDATA[Sort Boxes]]></item>
+               <item name="wcf.acp.page.boxOrder.discard"><![CDATA[Discard Sorting]]></item>
+               <item name="wcf.acp.page.boxOrder.discard.confirmMessage"><![CDATA[Do you really want to discard the invidiual box sorting for this page?]]></item>
+               <item name="wcf.acp.page.boxOrder.pageAdd"><![CDATA[You can set an individual sort order for boxes after saving.]]></item>
+               <item name="wcf.acp.page.boxOrder.pageEdit"><![CDATA[You can set an individual <a href="{link controller='PageBoxOrder' id=$page->pageID}{/link}">sort order for boxes</a>, please save your changes before continuing.]]></item>
+               <item name="wcf.acp.page.boxOrder.position.content"><![CDATA[(Content)]]></item>
+               <item name="wcf.acp.page.button.boxOrder"><![CDATA[Sort Boxes]]></item>
                <item name="wcf.acp.page.button.viewPage"><![CDATA[Show Preview]]></item>
                <item name="wcf.acp.page.content"><![CDATA[Content]]></item>
                <item name="wcf.acp.page.contents"><![CDATA[Contents]]></item>
index 4617265ab4ea35684ff85c1bd9121f117c7afae8..1c4f2fa6f2ee4a55a5c55c7cc88ef2cec46f452a 100644 (file)
@@ -988,6 +988,14 @@ CREATE TABLE wcf1_page (
        options TEXT NULL
 );
 
+DROP TABLE IF EXISTS wcf1_page_box_order;
+CREATE TABLE wcf1_page_box_order (
+       pageID INT(10) NOT NULL,
+       boxID INT(10) NOT NULL,
+       showOrder INT(10) NOT NULL DEFAULT 0,
+       UNIQUE KEY pageToBox (pageID, boxID)
+);
+
 DROP TABLE IF EXISTS wcf1_page_content;
 CREATE TABLE wcf1_page_content (
        pageContentID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
@@ -1823,6 +1831,9 @@ ALTER TABLE wcf1_page ADD FOREIGN KEY (parentPageID) REFERENCES wcf1_page (pageI
 ALTER TABLE wcf1_page ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;
 ALTER TABLE wcf1_page ADD FOREIGN KEY (applicationPackageID) REFERENCES wcf1_package (packageID) ON DELETE SET NULL;
 
+ALTER TABLE wcf1_page_box_order ADD FOREIGN KEY (pageID) REFERENCES wcf1_page (pageID) ON DELETE CASCADE;
+ALTER TABLE wcf1_page_box_order ADD FOREIGN KEY (boxID) REFERENCES wcf1_box (boxID) ON DELETE CASCADE;
+
 ALTER TABLE wcf1_page_content ADD FOREIGN KEY (pageID) REFERENCES wcf1_page (pageID) ON DELETE CASCADE;
 ALTER TABLE wcf1_page_content ADD FOREIGN KEY (languageID) REFERENCES wcf1_language (languageID) ON DELETE CASCADE;