Add unread article page feature
authorJoshua Rüsweg <josh@bastelstu.be>
Wed, 29 Aug 2018 19:12:26 +0000 (21:12 +0200)
committerJoshua Rüsweg <josh@bastelstu.be>
Wed, 29 Aug 2018 19:12:26 +0000 (21:12 +0200)
See #2623

com.woltlab.wcf/menuItem.xml
com.woltlab.wcf/page.xml
com.woltlab.wcf/templates/unreadArticleList.tpl [new file with mode: 0644]
wcfsetup/install/files/lib/page/UnreadArticleListPage.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/page/handler/UnreadArticleListPageHandler.class.php [new file with mode: 0644]

index 8b46b4c481711b4a7edace3500a7060f3e293559..736c2e3e12786f75b4e231e674391ff32e1b28aa 100644 (file)
                        <title language="en">Articles</title>
                        <page>com.woltlab.wcf.ArticleList</page>
                </item>
+               <item identifier="com.woltlab.wcf.UnreadArticleList">
+                       <parent>com.woltlab.wcf.ArticleList</parent>
+                       <title language="de">Ungelesene Artikel</title>
+                       <title language="en">Unread Articles</title>
+                       <page>com.woltlab.wcf.UnreadArticleList</page>
+               </item>
                <item identifier="com.woltlab.wcf.WatchedArticleList">
                        <parent>com.woltlab.wcf.ArticleList</parent>
                        <title language="de">Abonnierte Artikel</title>
index a8b1cf596a99a631cd4c3795b76eeaeaa385ff25..959bcabe3859781df1c887c388b28a9810fc4b31 100644 (file)
                                <title>Artikel</title>
                        </content>
                </page>
+               <page identifier="com.woltlab.wcf.UnreadArticleList">
+                       <pageType>system</pageType>
+                       <controller>wcf\page\UnreadArticleListPage</controller>
+                       <handler>wcf\system\page\handler\UnreadArticleListPageHandler</handler>
+                       <name language="de">Ungelesene Artikel</name>
+                       <name language="en">Unread Articles</name>
+                       <options>module_article</options>
+                       <parent>com.woltlab.wcf.ArticleList</parent>
+                       
+                       <content language="en">
+                               <title>Unread Articles</title>
+                       </content>
+                       <content language="de">
+                               <title>Ungelesene Artikel</title>
+                       </content>
+               </page>
                <page identifier="com.woltlab.wcf.WatchedArticleList">
                        <pageType>system</pageType>
                        <controller>wcf\page\WatchedArticleListPage</controller>
diff --git a/com.woltlab.wcf/templates/unreadArticleList.tpl b/com.woltlab.wcf/templates/unreadArticleList.tpl
new file mode 100644 (file)
index 0000000..9b446fe
--- /dev/null
@@ -0,0 +1,117 @@
+{capture assign='headContent'}
+       {if $pageNo < $pages}
+               <link rel="next" href="{link controller='UnreadArticleList'}pageNo={@$pageNo+1}{/link}">
+       {/if}
+       {if $pageNo > 1}
+               <link rel="prev" href="{link controller='UnreadArticleList'}{if $pageNo > 2}pageNo={@$pageNo-1}{/if}{/link}">
+       {/if}
+{/capture}
+
+{capture assign='headerNavigation'}
+       {if ARTICLE_ENABLE_VISIT_TRACKING}
+               <li class="jsOnly"><a href="#" title="{lang}wcf.article.markAllAsRead{/lang}" class="markAllAsReadButton jsTooltip"><span class="icon icon16 fa-check"></span> <span class="invisible">{lang}wcf.article.markAllAsRead{/lang}</span></a></li>
+       {/if}
+{/capture}
+
+{capture assign='sidebarRight'}
+       {if !$labelGroups|empty}
+               <form id="sidebarForm" method="post" action="{link application='wcf' controller=$controllerName object=$controllerObject}{/link}">
+                       <section class="box">
+                               <h2 class="boxTitle">{lang}wcf.label.label{/lang}</h2>
+                               
+                               <div class="boxContent">
+                                       <dl>
+                                               {foreach from=$labelGroups item=labelGroup}
+                                                       {if $labelGroup|count}
+                                                               <dt>{$labelGroup->getTitle()}</dt>
+                                                               <dd>
+                                                                       <ul class="labelList jsOnly">
+                                                                               <li class="dropdown labelChooser" id="labelGroup{@$labelGroup->groupID}" data-group-id="{@$labelGroup->groupID}">
+                                                                                       <div class="dropdownToggle" data-toggle="labelGroup{@$labelGroup->groupID}"><span class="badge label">{lang}wcf.label.none{/lang}</span></div>
+                                                                                       <div class="dropdownMenu">
+                                                                                               <ul class="scrollableDropdownMenu">
+                                                                                                       {foreach from=$labelGroup item=label}
+                                                                                                               <li data-label-id="{@$label->labelID}"><span><span class="badge label{if $label->getClassNames()} {@$label->getClassNames()}{/if}">{lang}{$label->label}{/lang}</span></span></li>
+                                                                                                       {/foreach}
+                                                                                               </ul>
+                                                                                       </div>
+                                                                               </li>
+                                                                       </ul>
+                                                                       <noscript>
+                                                                               {foreach from=$labelGroups item=labelGroup}
+                                                                                       <select name="labelIDs[{@$labelGroup->groupID}]">
+                                                                                               <option value="0">{lang}wcf.label.none{/lang}</option>
+                                                                                               <option value="-1">{lang}wcf.label.withoutSelection{/lang}</option>
+                                                                                               {foreach from=$labelGroup item=label}
+                                                                                                       <option value="{@$label->labelID}"{if $labelIDs[$labelGroup->groupID]|isset && $labelIDs[$labelGroup->groupID] == $label->labelID} selected{/if}>{lang}{$label->label}{/lang}</option>
+                                                                                               {/foreach}
+                                                                                       </select>
+                                                                               {/foreach}
+                                                                       </noscript>
+                                                               </dd>
+                                                       {/if}
+                                               {/foreach}
+                                       </dl>
+                                       <div class="formSubmit">
+                                               <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
+                                       </div>
+                               </div>
+                       </section>
+               </form>
+               
+               <script data-relocate="true">
+                       $(function() {
+                               WCF.Language.addObject({
+                                       'wcf.label.none': '{lang}wcf.label.none{/lang}',
+                                       'wcf.label.withoutSelection': '{lang}wcf.label.withoutSelection{/lang}'
+                               });
+                               
+                               new WCF.Label.Chooser({ {implode from=$labelIDs key=groupID item=labelID}{@$groupID}: {@$labelID}{/implode} }, '#sidebarForm', undefined, true);
+                       });
+               </script>
+       {/if}
+{/capture}
+
+{include file='header'}
+
+{hascontent}
+       <div class="paginationTop">
+               {content}
+                       {pages print=true assign='pagesLinks' controller='UnreadArticleList' link="pageNo=%d"}
+               {/content}
+       </div>
+{/hascontent}
+
+{if $objects|count}
+       <div class="section">
+               {include file='articleListItems'}
+       </div>
+{else}
+       <p class="info">{lang}wcf.global.noItems{/lang}</p>
+{/if}
+
+<footer class="contentFooter">
+       {hascontent}
+               <div class="paginationBottom">
+                       {content}{@$pagesLinks}{/content}
+               </div>
+       {/hascontent}
+       
+       {hascontent}
+               <nav class="contentFooterNavigation">
+                       <ul>
+                               {content}{event name='contentFooterNavigation'}{/content}
+                       </ul>
+               </nav>
+       {/hascontent}
+</footer>
+
+{if ARTICLE_ENABLE_VISIT_TRACKING}
+       <script data-relocate="true">
+               require(['WoltLabSuite/Core/Ui/Article/MarkAllAsRead'], function(UiArticleMarkAllAsRead) {
+                       UiArticleMarkAllAsRead.init();
+               });
+       </script>
+{/if}
+
+{include file='footer'}
diff --git a/wcfsetup/install/files/lib/page/UnreadArticleListPage.class.php b/wcfsetup/install/files/lib/page/UnreadArticleListPage.class.php
new file mode 100644 (file)
index 0000000..89efac7
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+namespace wcf\page;
+use wcf\system\request\LinkHandler;
+use wcf\system\visitTracker\VisitTracker;
+use wcf\system\WCF;
+
+/**
+ * Shows a list of unread articles.
+ *
+ * @author     Joshua Ruesweg
+ * @copyright  2001-2018 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\Page
+ * @since       3.2
+ */
+class UnreadArticleListPage extends ArticleListPage {
+       /**
+        * @inheritDoc
+        */
+       public $loginRequired = true;
+       
+       /**
+        * @inheritDoc
+        */
+       public $neededModules = ['ARTICLE_ENABLE_VISIT_TRACKING', 'MODULE_ARTICLE'];
+       
+       /**
+        * @inheritDoc
+        */
+       public $controllerName = 'UnreadArticleList';
+       
+       /**
+        * @inheritDoc
+        */
+       public function readParameters() {
+               parent::readParameters();
+               
+               $this->canonicalURL = LinkHandler::getInstance()->getLink('UnreadArticleList', $this->controllerParameters, ($this->pageNo > 1 ? 'pageNo=' . $this->pageNo : ''));
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function initObjectList() {
+               parent::initObjectList();
+               
+               $this->objectList->getConditionBuilder()->add('article.time > ?', [VisitTracker::getInstance()->getVisitTime('com.woltlab.wcf.article')]);
+               
+               if (WCF::getUser()->userID) {
+                       $this->objectList->sqlConditionJoins = "LEFT JOIN wcf".WCF_N."_tracked_visit tracked_visit ON (tracked_visit.objectTypeID = ".VisitTracker::getInstance()->getObjectTypeID('com.woltlab.wcf.article')." AND tracked_visit.objectID = article.articleID AND tracked_visit.userID = ".WCF::getUser()->userID.")";
+                       $this->objectList->getConditionBuilder()->add("(article.time > tracked_visit.visitTime OR tracked_visit.visitTime IS NULL)");
+               }
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/page/handler/UnreadArticleListPageHandler.class.php b/wcfsetup/install/files/lib/system/page/handler/UnreadArticleListPageHandler.class.php
new file mode 100644 (file)
index 0000000..ac4849e
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+namespace wcf\system\page\handler;
+use wcf\data\article\ViewableArticle;
+
+/**
+ * Page handler implementation for the page showing the list of unread articles.
+ *
+ * @author     Joshua Ruesweg
+ * @copyright  2001-2018 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Page\Handler
+ * @since      3.2
+ */
+class UnreadArticleListPageHandler extends AbstractMenuPageHandler {
+       /** @noinspection PhpMissingParentCallCommonInspection */
+       /**
+        * @inheritDoc
+        */
+       public function getOutstandingItemCount(/** @noinspection PhpUnusedParameterInspection */$objectID = null) {
+               return ViewableArticle::getUnreadArticles();
+       }
+       
+       /** @noinspection PhpMissingParentCallCommonInspection */
+       /**
+        * @inheritDoc
+        */
+       public function isVisible(/** @noinspection PhpUnusedParameterInspection */$objectID = null) {
+               return ARTICLE_ENABLE_VISIT_TRACKING && !empty(ViewableArticle::getUnreadArticles());
+       }
+}