Merge remote-tracking branch 'refs/remotes/origin/next'
authorAlexander Ebert <ebert@woltlab.com>
Wed, 12 Oct 2016 11:28:03 +0000 (13:28 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 12 Oct 2016 11:28:03 +0000 (13:28 +0200)
115 files changed:
.gitignore
.travis.yml
CHANGELOG.md [new file with mode: 0644]
clipboardAction.xml
constants.php [new file with mode: 0644]
coreObject.xml
eventListener_update210.xml [deleted file]
files/acp/install_com.woltlab.wcf.conversation.php [new file with mode: 0644]
files/acp/install_com.woltlab.wcf.conversation_2.0.0.php [deleted file]
files/js/WCF.Conversation.js
files/js/WCF.Conversation.min.js
files/js/WoltLabSuite.Core.Conversation.min.js [new file with mode: 0644]
files/js/WoltLabSuite/Core/Conversation/Ui/Participant/Add.js [new file with mode: 0644]
files/js/require.build.js [new file with mode: 0644]
files/js/require.build.min.js [new file with mode: 0644]
files/lib/data/conversation/Conversation.class.php
files/lib/data/conversation/ConversationAction.class.php
files/lib/data/conversation/ConversationEditor.class.php
files/lib/data/conversation/ConversationList.class.php
files/lib/data/conversation/ConversationParticipantList.class.php
files/lib/data/conversation/FeedConversation.class.php
files/lib/data/conversation/FeedConversationList.class.php
files/lib/data/conversation/UserConversationList.class.php
files/lib/data/conversation/ViewableConversation.class.php
files/lib/data/conversation/label/ConversationLabel.class.php
files/lib/data/conversation/label/ConversationLabelAction.class.php
files/lib/data/conversation/label/ConversationLabelEditor.class.php
files/lib/data/conversation/label/ConversationLabelList.class.php
files/lib/data/conversation/message/ConversationMessage.class.php
files/lib/data/conversation/message/ConversationMessageAction.class.php
files/lib/data/conversation/message/ConversationMessageEditor.class.php
files/lib/data/conversation/message/ConversationMessageList.class.php
files/lib/data/conversation/message/SearchResultConversationMessage.class.php
files/lib/data/conversation/message/SearchResultConversationMessageList.class.php
files/lib/data/conversation/message/SimplifiedViewableConversationMessageList.class.php
files/lib/data/conversation/message/ViewableConversationMessage.class.php
files/lib/data/conversation/message/ViewableConversationMessageList.class.php
files/lib/data/modification/log/ConversationLogModificationLogList.class.php
files/lib/data/modification/log/ViewableConversationModificationLog.class.php
files/lib/form/ConversationAddForm.class.php
files/lib/form/ConversationMessageAddForm.class.php [deleted file]
files/lib/form/ConversationMessageEditForm.class.php [deleted file]
files/lib/page/ConversationFeedPage.class.php
files/lib/page/ConversationListPage.class.php
files/lib/page/ConversationPage.class.php
files/lib/system/attachment/ConversationMessageAttachmentObjectType.class.php
files/lib/system/cache/runtime/ConversationRuntimeCache.class.php [new file with mode: 0644]
files/lib/system/cache/runtime/UserConversationRuntimeCache.class.php [new file with mode: 0644]
files/lib/system/clipboard/action/ConversationClipboardAction.class.php
files/lib/system/conversation/ConversationHandler.class.php
files/lib/system/event/listener/ConversationUserActionRenameListener.class.php
files/lib/system/event/listener/ConversationUserMergeListener.class.php
files/lib/system/importer/ConversationAttachmentImporter.class.php
files/lib/system/importer/ConversationImporter.class.php
files/lib/system/importer/ConversationLabelImporter.class.php
files/lib/system/importer/ConversationMessageImporter.class.php
files/lib/system/importer/ConversationUserImporter.class.php
files/lib/system/log/modification/ConversationModificationLogHandler.class.php
files/lib/system/message/quote/ConversationMessageQuoteHandler.class.php
files/lib/system/moderation/queue/report/ConversationMessageModerationQueueReportHandler.class.php
files/lib/system/page/handler/ConversationListPageHandler.class.php [new file with mode: 0644]
files/lib/system/page/handler/DefaultConversationRelatedPageHandler.class.php [new file with mode: 0644]
files/lib/system/page/handler/TConversationOnlineLocationPageHandler.class.php [new file with mode: 0644]
files/lib/system/search/ConversationMessageSearch.class.php
files/lib/system/stat/ConversationMessageStatDailyHandler.class.php
files/lib/system/stat/ConversationStatDailyHandler.class.php
files/lib/system/user/notification/event/ConversationMessageUserNotificationEvent.class.php
files/lib/system/user/notification/event/ConversationUserNotificationEvent.class.php
files/lib/system/user/notification/object/ConversationMessageUserNotificationObject.class.php
files/lib/system/user/notification/object/ConversationUserNotificationObject.class.php
files/lib/system/user/notification/object/type/ConversationMessageNotificationObjectType.class.php
files/lib/system/user/notification/object/type/ConversationNotificationObjectType.class.php
files/lib/system/user/online/location/ConversationLocation.class.php [deleted file]
files/lib/system/worker/ConversationMessageRebuildDataWorker.class.php
files/lib/system/worker/ConversationRebuildDataWorker.class.php
files/style/conversation.less [deleted file]
files/style/conversation.scss [new file with mode: 0644]
install.sql
language/de.xml
language/en.xml
objectType.xml
option.xml
package.xml
page.xml [new file with mode: 0644]
templateListener.xml
templates/__mobileMenuConversation.tpl [new file with mode: 0644]
templates/__searchAreaConversationSettings.tpl
templates/__userInformationStartConversation.tpl
templates/__userPanelConversationDropdown.tpl
templates/__userProfileStartConversation.tpl [new file with mode: 0644]
templates/__userStartConversation.tpl
templates/conversation.tpl
templates/conversationAdd.tpl
templates/conversationAddParticipants.tpl
templates/conversationLabelAssignment.tpl
templates/conversationLabelManagement.tpl
templates/conversationLeave.tpl
templates/conversationList.tpl
templates/conversationListUserPanel.tpl
templates/conversationMessageAdd.tpl [deleted file]
templates/conversationMessageEdit.tpl [deleted file]
templates/conversationMessageInlineEditor.tpl
templates/conversationMessageList.tpl
templates/conversationMessageListLog.tpl
templates/conversationMessagePreview.tpl
templates/conversationQuickReply.tpl
templates/email_notification_conversation.tpl [new file with mode: 0644]
templates/email_notification_conversationMessage.tpl [new file with mode: 0644]
templates/moderationConversationMessage.tpl
templates/searchConversationMessage.tpl [new file with mode: 0644]
update1_210.sql [deleted file]
update2_210.sql [deleted file]
update3_210.sql [deleted file]
userGroupOption.xml
userOption.xml

index d9b96dd61cea96d7d725476469a9d25fd6e8453a..78788ea932a3c18320c4f34c2296a5222f0c0802 100644 (file)
@@ -44,7 +44,7 @@ nbactions.xml
 *.imlworkspace
 .xml
 
-# Community Framework
+# WoltLab Suite
 # Ignore packages build directly in the workspace. They can however be added manually via git add, if wanted.
 *.tar
 *.tar.gz
\ No newline at end of file
index 56a77f52ea939427ef265972e374a68271940cb3..87ce43b8b9a323154c61bdec312fea55e09fb82d 100644 (file)
@@ -2,7 +2,7 @@ language: php
 sudo: false
 php:
   - 5.6
-  - 5.3
+  - 5.5
 before_install:
   - pyrus install pear/PHP_CodeSniffer
   - phpenv rehash
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644 (file)
index 0000000..ebeae33
--- /dev/null
@@ -0,0 +1,15 @@
+# Changelog
+
+## 3.0
+
+### 3.0.0 Alpha 1 (XXXX-YY-ZZ)
+
+* Only search active conversation when using search bar in a conversation.
+* Filter option for conversation participants on conversation list page.
+* Increased number of items in conversation drop down to 10.
+* Overhauled conversation drop down.
+* Changed label of wcf.conversation.lastVisitTime
+
+#### Documentation
+
+* `@property-read` tags for database table columns of classes extending `wcf\data\DatabaseObject`.
index 25015b44e5af8e54065e71f3dc869b70d53d9d7f..a541fc7a4a170542327ec7af39b5cf7466d4a93f 100644 (file)
@@ -3,52 +3,52 @@
        <import>
                <!-- conversation -->
                <action name="assignLabel">
-                       <actionclassname><![CDATA[wcf\system\clipboard\action\ConversationClipboardAction]]></actionclassname>
+                       <actionclassname>wcf\system\clipboard\action\ConversationClipboardAction</actionclassname>
                        <showorder>1</showorder>
                        <pages>
-                               <page><![CDATA[wcf\page\ConversationListPage]]></page>
+                               <page>wcf\page\ConversationListPage</page>
                        </pages>
                </action>
                <action name="markAsRead">
-                       <actionclassname><![CDATA[wcf\system\clipboard\action\ConversationClipboardAction]]></actionclassname>
+                       <actionclassname>wcf\system\clipboard\action\ConversationClipboardAction</actionclassname>
                        <showorder>2</showorder>
                        <pages>
-                               <page><![CDATA[wcf\page\ConversationListPage]]></page>
+                               <page>wcf\page\ConversationListPage</page>
                        </pages>
                </action>
                <action name="restore">
-                       <actionclassname><![CDATA[wcf\system\clipboard\action\ConversationClipboardAction]]></actionclassname>
+                       <actionclassname>wcf\system\clipboard\action\ConversationClipboardAction</actionclassname>
                        <showorder>3</showorder>
                        <pages>
-                               <page><![CDATA[wcf\page\ConversationListPage]]></page>
+                               <page>wcf\page\ConversationListPage</page>
                        </pages>
                </action>
                <action name="leave">
-                       <actionclassname><![CDATA[wcf\system\clipboard\action\ConversationClipboardAction]]></actionclassname>
+                       <actionclassname>wcf\system\clipboard\action\ConversationClipboardAction</actionclassname>
                        <showorder>4</showorder>
                        <pages>
-                               <page><![CDATA[wcf\page\ConversationListPage]]></page>
+                               <page>wcf\page\ConversationListPage</page>
                        </pages>
                </action>
                <action name="leavePermanently">
-                       <actionclassname><![CDATA[wcf\system\clipboard\action\ConversationClipboardAction]]></actionclassname>
+                       <actionclassname>wcf\system\clipboard\action\ConversationClipboardAction</actionclassname>
                        <showorder>5</showorder>
                        <pages>
-                               <page><![CDATA[wcf\page\ConversationListPage]]></page>
+                               <page>wcf\page\ConversationListPage</page>
                        </pages>
                </action>
                <action name="open">
-                       <actionclassname><![CDATA[wcf\system\clipboard\action\ConversationClipboardAction]]></actionclassname>
+                       <actionclassname>wcf\system\clipboard\action\ConversationClipboardAction</actionclassname>
                        <showorder>6</showorder>
                        <pages>
-                               <page><![CDATA[wcf\page\ConversationListPage]]></page>
+                               <page>wcf\page\ConversationListPage</page>
                        </pages>
                </action>
                <action name="close">
-                       <actionclassname><![CDATA[wcf\system\clipboard\action\ConversationClipboardAction]]></actionclassname>
+                       <actionclassname>wcf\system\clipboard\action\ConversationClipboardAction</actionclassname>
                        <showorder>7</showorder>
                        <pages>
-                               <page><![CDATA[wcf\page\ConversationListPage]]></page>
+                               <page>wcf\page\ConversationListPage</page>
                        </pages>
                </action>
                <!-- /conversation -->
diff --git a/constants.php b/constants.php
new file mode 100644 (file)
index 0000000..dd1e0fd
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Defines constants for autocompletion in IDEs. This file is not meant to be actively used anywhere!
+ *
+ * @author     Matthias Schmidt
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core
+ */
+
+// option constants
+define('MODULE_CONVERSATION', 1);
+define('CONVERSATIONS_PER_PAGE', 10);
+define('CONVERSATION_MESSAGES_PER_PAGE', 20);
+define('CONVERSATION_REPLY_SHOW_MESSAGES_MAX', 10);
+define('CONVERSATION_LIST_DEFAULT_SORT_FIELD', 'lastPostTime');
+define('CONVERSATION_LIST_DEFAULT_SORT_ORDER', 'DESC');
index 371330d509d5367113e80a24261ccebc01d62607..f41dbe38132d23bcd1eeb0b8c2e806afd5bdf875 100644 (file)
@@ -2,7 +2,7 @@
 <data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/coreObject.xsd">
        <import>
                <coreobject>
-                       <objectname><![CDATA[wcf\system\conversation\ConversationHandler]]></objectname>
+                       <objectname>wcf\system\conversation\ConversationHandler</objectname>
                </coreobject>
        </import>
 </data>
diff --git a/eventListener_update210.xml b/eventListener_update210.xml
deleted file mode 100644 (file)
index da3e538..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/maelstrom/eventListener.xsd">
-       <import>
-               <eventlistener>
-                       <eventclassname>wcf\data\user\UserAction</eventclassname>
-                       <eventname>rename</eventname>
-                       <listenerclassname>wcf\system\event\listener\ConversationUserActionRenameListener</listenerclassname>
-                       <environment>user</environment>
-               </eventlistener>
-               <eventlistener>
-                       <eventclassname>wcf\data\user\UserAction</eventclassname>
-                       <eventname>rename</eventname>
-                       <listenerclassname>wcf\system\event\listener\ConversationUserActionRenameListener</listenerclassname>
-                       <environment>admin</environment>
-               </eventlistener>
-       </import>
-</data>
diff --git a/files/acp/install_com.woltlab.wcf.conversation.php b/files/acp/install_com.woltlab.wcf.conversation.php
new file mode 100644 (file)
index 0000000..956644e
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+use wcf\data\user\group\UserGroup;
+use wcf\system\WCF;
+
+/**
+ * @author     Matthias Schmidt
+ * @copyright  2001-2015 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ */
+// set default mod permissions
+$group = new UserGroup(5);
+if ($group->groupID) {
+       $sql = "REPLACE INTO    wcf".WCF_N."_user_group_option_value
+                               (groupID, optionID, optionValue)
+               SELECT          5, optionID, 1
+               FROM            wcf".WCF_N."_user_group_option
+               WHERE           optionName LIKE 'mod.conversation.%'";
+       $statement = WCF::getDB()->prepareStatement($sql);
+       $statement->execute();
+}
+
+$group = new UserGroup(6);
+if ($group->groupID) {
+       $sql = "REPLACE INTO    wcf".WCF_N."_user_group_option_value
+                               (groupID, optionID, optionValue)
+               SELECT          6, optionID, 1
+               FROM            wcf".WCF_N."_user_group_option
+               WHERE           optionName LIKE 'mod.conversation.%'";
+       $statement = WCF::getDB()->prepareStatement($sql);
+       $statement->execute();
+}
diff --git a/files/acp/install_com.woltlab.wcf.conversation_2.0.0.php b/files/acp/install_com.woltlab.wcf.conversation_2.0.0.php
deleted file mode 100644 (file)
index 956644e..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-use wcf\data\user\group\UserGroup;
-use wcf\system\WCF;
-
-/**
- * @author     Matthias Schmidt
- * @copyright  2001-2015 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- */
-// set default mod permissions
-$group = new UserGroup(5);
-if ($group->groupID) {
-       $sql = "REPLACE INTO    wcf".WCF_N."_user_group_option_value
-                               (groupID, optionID, optionValue)
-               SELECT          5, optionID, 1
-               FROM            wcf".WCF_N."_user_group_option
-               WHERE           optionName LIKE 'mod.conversation.%'";
-       $statement = WCF::getDB()->prepareStatement($sql);
-       $statement->execute();
-}
-
-$group = new UserGroup(6);
-if ($group->groupID) {
-       $sql = "REPLACE INTO    wcf".WCF_N."_user_group_option_value
-                               (groupID, optionID, optionValue)
-               SELECT          6, optionID, 1
-               FROM            wcf".WCF_N."_user_group_option
-               WHERE           optionName LIKE 'mod.conversation.%'";
-       $statement = WCF::getDB()->prepareStatement($sql);
-       $statement->execute();
-}
index 9c69987373ef26086466b8848167be82c6bc7d4f..24059decfd6cecdf1da7497a2c9648bc68014695 100644 (file)
@@ -146,7 +146,7 @@ WCF.Conversation.EditorHandler = Class.extend({
                
                switch (key) {
                        case 'close':
-                               $('<li><span class="icon icon16 icon-lock jsTooltip jsIconLock" title="' + WCF.Language.get('wcf.global.state.closed') + '" /></li>').prependTo($conversation.find('.statusIcons'));
+                               $('<li><span class="icon icon16 fa-lock jsTooltip jsIconLock" title="' + WCF.Language.get('wcf.global.state.closed') + '" /></li>').prependTo($conversation.find('.statusIcons'));
                                
                                this._attributes[conversationID].isClosed = 1;
                        break;
@@ -179,7 +179,7 @@ WCF.Conversation.EditorHandler = Class.extend({
                                        // insert labels
                                        for (var $i = 0, $length = data.length; $i < $length; $i++) {
                                                var $label = $labels[data[$i]];
-                                               $('<li><a href="' + $label.url + '" class="badge label' + ($label.cssClassName ? " " + $label.cssClassName : "") + '">' + WCF.String.escapeHTML($label.label) + '</a>&nbsp;</li>').appendTo($labelList);
+                                               $('<li><a href="' + $label.url + '" class="badge label' + ($label.cssClassName ? " " + $label.cssClassName : "") + '">' + WCF.String.escapeHTML($label.label) + '</a></li>').appendTo($labelList);
                                        }
                                }
                        break;
@@ -241,46 +241,43 @@ WCF.Conversation.EditorHandlerConversation = WCF.Conversation.EditorHandler.exte
                        return;
                }
                
+               var container = $('.contentHeaderTitle > .contentHeaderMetaData');
+               
                switch (key) {
                        case 'close':
-                               $('<span class="icon icon16 icon-lock jsTooltip jsIconLock" title="' + WCF.Language.get('wcf.global.state.closed') + '" />').appendTo($('#content > header > h1'));
+                               $('<li><span class="icon icon16 fa-lock jsIconLock" /> ' + WCF.Language.get('wcf.global.state.closed') + '</li>').appendTo(container);
                                
                                this._attributes[conversationID].isClosed = 1;
                        break;
                        
                        case 'labelIDs':
-                               var $container = $('.conversationHeadline');
+                               var labelList = container.find('.labelList');
                                if (!data.length) {
-                                       // remove all labels
-                                       $container.find('ul.labelList').remove();
+                                       labelList.parent().remove();
                                }
                                else {
-                                       var $labelList = $container.find('ul.labelList');
-                                       if (!$labelList.length) {
-                                               $labelList = $('<ul class="labelList" />').appendTo($container);
-                                       }
+                                       var availableLabels = this.getAvailableLabels();
                                        
-                                       // remove existing labels
-                                       $labelList.empty();
+                                       if (!labelList.length) {
+                                               labelList = $('<li><span class="icon icon16 fa-tags"></span> <ul class="labelList"></ul></li>').prependTo(container);
+                                               labelList = labelList.children('ul');
+                                       }
                                        
-                                       // add new labels
-                                       for (var $i = 0, $length = data.length; $i < $length; $i++) {
-                                               var $labelID = data[$i];
-                                               
-                                               for (var $j = 0, $innerLength = this.getAvailableLabels().length; $j < $innerLength; $j++) {
-                                                       var $label = this.getAvailableLabels()[$j];
-                                                       if ($label.labelID == $labelID) {
-                                                               $('<li><span class="label badge' + ($label.cssClassName ? " " + $label.cssClassName : "") + '">' + $label.label + '</span>&nbsp;</li>').appendTo($labelList);
-                                                               
-                                                               break;
+                                       var html = '';
+                                       data.forEach(function(labelId) {
+                                               availableLabels.forEach(function(label) {
+                                                       if (label.labelID == labelId) {
+                                                               html += '<li><span class="label badge' + (label.cssClassName ? ' ' + label.cssClassName : '') + '">' + label.label + '</span></li>';
                                                        }
-                                               }
-                                       }
+                                               });
+                                       });
+                                       
+                                       labelList[0].innerHTML = html;
                                }
                        break;
                        
                        case 'open':
-                               $('#content > header span.jsIconLock').remove();
+                               container.find('.jsIconLock').parent().remove();
                                
                                this._attributes[conversationID].isClosed = 0;
                        break;
@@ -301,33 +298,29 @@ WCF.Conversation.Clipboard = Class.extend({
        /**
         * Initializes a new WCF.Conversation.Clipboard object.
         * 
-        * @param       WCF.Conversation.EditorHandler  editorHandler
+        * @param       {WCF.Conversation.EditorHandler}        editorHandler
         */
        init: function(editorHandler) {
                this._editorHandler = editorHandler;
                
-               // bind listener
-               $('.jsClipboardEditor').each($.proxy(function(index, container) {
-                       var $container = $(container);
-                       var $types = eval($container.data('types'));
-                       if (WCF.inArray('com.woltlab.wcf.conversation.conversation', $types)) {
-                               $container.on('clipboardAction', $.proxy(this._execute, this));
-                               $container.on('clipboardActionResponse', $.proxy(this._evaluateResponse, this));
-                               return false;
+               WCF.System.Event.addListener('com.woltlab.wcf.clipboard', 'com.woltlab.wcf.conversation.conversation', (function (data) {
+                       if (data.responseData === null) {
+                               this._execute(data.data.actionName, data.data.parameters);
+                       }
+                       else {
+                               this._evaluateResponse(data.data.actionName, data.responseData);
                        }
-               }this));
+               }).bind(this));
        },
        
        /**
         * Handles clipboard actions.
         * 
-        * @param       object          event
-        * @param       string          type
-        * @param       string          actionName
-        * @param       object          parameters
+        * @param       {string}        actionName
+        * @param       {Object}        parameters
         */
-       _execute: function(event, type, actionName, parameters) {
-               if (type === 'com.woltlab.wcf.conversation.conversation' && actionName === 'com.woltlab.wcf.conversation.conversation.assignLabel') {
+       _execute: function(actionName, parameters) {
+               if (actionName === 'com.woltlab.wcf.conversation.conversation.assignLabel') {
                        new WCF.Conversation.Label.Editor(this._editorHandler, null, parameters.objectIDs);
                }
        },
@@ -335,18 +328,10 @@ WCF.Conversation.Clipboard = Class.extend({
        /**
         * Evaluates AJAX responses.
         * 
-        * @param       object          event
-        * @param       object          data
-        * @param       string          type
-        * @param       string          actionName
-        * @param       object          parameters
+        * @param       {Object}        data
+        * @param       {string}        actionName
         */
-       _evaluateResponse: function(event, data, type, actionName, parameters) {
-               if (type !== 'com.woltlab.wcf.conversation.conversation') {
-                       // ignore unreleated events
-                       return;
-               }
-               
+       _evaluateResponse: function(actionName, data) {
                switch (actionName) {
                        case 'com.woltlab.wcf.conversation.conversation.leave':
                        case 'com.woltlab.wcf.conversation.conversation.leavePermanently':
@@ -357,10 +342,15 @@ WCF.Conversation.Clipboard = Class.extend({
                        
                        case 'com.woltlab.wcf.conversation.conversation.close':
                        case 'com.woltlab.wcf.conversation.conversation.open':
-                               for (var $conversationID in data.returnValues.conversationData) {
-                                       var $data = data.returnValues.conversationData[$conversationID];
-                                       
-                                       this._editorHandler.update($conversationID, ($data.isClosed ? 'close' : 'open'), $data);
+                               //noinspection JSUnresolvedVariable
+                               for (var conversationId in data.returnValues.conversationData) {
+                                       //noinspection JSUnresolvedVariable
+                                       if (data.returnValues.conversationData.hasOwnProperty(conversationId)) {
+                                               //noinspection JSUnresolvedVariable
+                                               var $data = data.returnValues.conversationData[conversationId];
+                                               
+                                               this._editorHandler.update(conversationId, ($data.isClosed ? 'close' : 'open'), $data);
+                                       }
                                }
                        break;
                }
@@ -470,7 +460,9 @@ WCF.Conversation.InlineEditor = WCF.InlineEditor.extend({
                
                switch (optionName) {
                        case 'addParticipants':
-                               new WCF.Conversation.AddParticipants($('#' + elementID).data('conversationID'));
+                               require(['WoltLabSuite/Core/Conversation/Ui/Participant/Add'], function(UiParticipantAdd) {
+                                       new UiParticipantAdd(document.getElementById(elementID).getAttribute('data-conversation-id'));
+                               });
                        break;
                        
                        case 'assignLabel':
@@ -666,143 +658,6 @@ WCF.Conversation.Leave = Class.extend({
        }
 });
 
-/**
- * Provides methods to add new participants.
- * 
- * @param      integer         conversationID
- */
-WCF.Conversation.AddParticipants = Class.extend({
-       /**
-        * conversation id
-        * @var integer
-        */
-       _conversationID: 0,
-       
-       /**
-        * dialog overlay
-        * @var jQuery
-        */
-       _dialog: null,
-       
-       /**
-        * action proxy
-        * @var WCF.Action.Proxy
-        */
-       _proxy: null,
-       
-       /**
-        * Initializes the WCF.Conversation.AddParticipants class
-        * 
-        * @param       integer         conversationID
-        */
-       init: function(conversationID) {
-               this._conversationID = conversationID;
-               
-               this._dialog = $('#conversationAddParticipants');
-               if (!this._dialog.length) {
-                       this._dialog = $('<div id="conversationAddParticipants" />').hide().appendTo(document.body);
-               }
-               
-               this._proxy = new WCF.Action.Proxy({
-                       autoSend: true,
-                       data: {
-                               actionName: 'getAddParticipantsForm',
-                               className: 'wcf\\data\\conversation\\ConversationAction',
-                               objectIDs: [ this._conversationID ]
-                       },
-                       success: $.proxy(this._success, this)
-               });
-       },
-       
-       /**
-        * Handles successful AJAX requests.
-        * 
-        * @param       object          data
-        * @param       string          textStatus
-        * @param       jQuery          jqXHR
-        */
-       _success: function(data, textStatus, jqXHR) {
-               switch (data.returnValues.actionName) {
-                       case 'addParticipants':
-                               if (data.returnValues.errorMessage) {
-                                       this._dialog.find('dl.jsAddParticipants').addClass('formError');
-                                       this._dialog.find('dl.jsAddParticipants > dd small.innerError').remove();
-                                       $('<small class="innerError">' + data.returnValues.errorMessage + '</small>').appendTo(this._dialog.find('dl.jsAddParticipants > dd'));
-                                       return;
-                               }
-                               
-                               if (data.returnValues.count) {
-                                       var $notification = new WCF.System.Notification(data.returnValues.successMessage);
-                                       $notification.show();
-                               }
-                               
-                               this._dialog.find('dl.jsAddParticipants').removeClass('formError').find('small.innerError').remove();
-                               this._dialog.wcfDialog('close');
-                       break;
-                       
-                       case 'getAddParticipantsForm':
-                               this._renderForm(data);
-                       break;
-               }
-       },
-       
-       /**
-        * Renders the 'add participants' form.
-        * 
-        * @param       object          data
-        */
-       _renderForm: function(data) {
-               this._dialog.html(data.returnValues.template);
-               this._dialog.find('#addParticipants').disable().click($.proxy(this._submit, this));
-               
-               new WCF.Search.User('#participantsInput', null, false, data.returnValues.excludeSearchValues, true);
-               
-               var $participantsInput = $('#participantsInput');
-               $participantsInput.keyup($.proxy(this._toggleSubmitButton, this));
-               
-               if ($.browser.mozilla && $.browser.touch) {
-                       $participantsInput.on('input', $.proxy(this._toggleSubmitButton, this));
-               }
-               
-               this._dialog.wcfDialog({
-                       title: WCF.Language.get('wcf.conversation.edit.addParticipants')
-               });
-       },
-       
-       /**
-        * Toggles the submit button if the input field contains a/no particiant.
-        */
-       _toggleSubmitButton: function() {
-               var $submitButton = this._dialog.find('#addParticipants');
-               if ($.trim($('#participantsInput').val()) === '') {
-                       $submitButton.disable();
-               }
-               else {
-                       $submitButton.enable();
-               }
-       },
-       
-       /**
-        * Submits the form to add new participants.
-        */
-       _submit: function() {
-               var $participants = $.trim($('#participantsInput').val());
-               if ($participants == '') {
-                       this._dialog.wcfDialog('close');
-               }
-               
-               this._proxy.setOption('data', {
-                       actionName: 'addParticipants',
-                       className: 'wcf\\data\\conversation\\ConversationAction',
-                       objectIDs: [ this._conversationID ],
-                       parameters: {
-                               participants: $participants
-                       }
-               });
-               this._proxy.sendRequest();
-       }
-});
-
 /**
  * Provides methods to remove participants from conversations.
  * 
@@ -1261,7 +1116,7 @@ WCF.Conversation.Label.Manager = Class.extend({
                                
                                this._deletedLabelID = $('#conversationLabelManagementForm').data('labelID');
                        }
-               }, this));
+               }, this), undefined, undefined, true);
        },
        
        /**
@@ -1370,6 +1225,14 @@ WCF.User.Panel.Conversation = WCF.User.Panel.Abstract.extend({
                        this.updateBadge(0);
                        this._loadData = true;
                }).bind(this));
+               
+               require(['EventHandler'], (function(EventHandler) {
+                       EventHandler.add('com.woltlab.wcf.UserMenuMobile', 'more', (function(data) {
+                               if (data.identifier === 'com.woltlab.wcf.conversation') {
+                                       this.toggle();
+                               }
+                       }).bind(this));
+               }).bind(this));
        },
        
        /**
@@ -1378,7 +1241,7 @@ WCF.User.Panel.Conversation = WCF.User.Panel.Abstract.extend({
        _initDropdown: function() {
                var $dropdown = this._super();
                
-               $('<li><a href="' + this._options.newConversationLink + '" title="' + this._options.newConversation + '" class="jsTooltip"><span class="icon icon16 fa-plus" /></a></li>').appendTo($dropdown.getLinkList());
+               $('<li><a href="' + this._options.newConversationLink + '" title="' + this._options.newConversation + '" class="jsTooltip"><span class="icon icon24 fa-plus" /></a></li>').appendTo($dropdown.getLinkList());
                
                return $dropdown;
        },
@@ -1418,33 +1281,6 @@ WCF.User.Panel.Conversation = WCF.User.Panel.Abstract.extend({
        }
 });
 
-/**
- * Provides an AJAX-based quick reply for conversations.
- */
-WCF.Conversation.QuickReply = WCF.Message.QuickReply.extend({
-       /**
-        * @see WCF.Message.QuickReply.init()
-        */
-       init: function(quoteManager) {
-               this._super(true, quoteManager);
-       },
-       
-       /**
-        * @see WCF.Message.QuickReply._getClassName()
-        */
-       _getClassName: function() {
-               return 'wcf\\data\\conversation\\message\\ConversationMessageAction';
-       },
-       
-       /**
-        * @see WCF.Message.QuickReply._getObjectID()
-        * @returns
-        */
-       _getObjectID: function() {
-               return this._container.data('conversationID');
-       }
-});
-
 /**
  * Marks one conversation as read.
  */
index 418a9adf3dcbb2cd136c7e2ff1993b3af37b20e4..2c079f37305650bda6298f38ba3db9ae26427b3e 100755 (executable)
@@ -1 +1 @@
-WCF.Conversation={},WCF.Conversation.EditorHandler=Class.extend({_attributes:{},_conversations:{},_permissions:{},init:function(availableLabels){this._conversations={};var self=this;$(".conversation").each(function(index,conversation){var $conversation=$(conversation),$conversationID=$conversation.data("conversationID");if(!self._conversations[$conversationID]){self._conversations[$conversationID]=$conversation;var $labelIDs=eval($conversation.data("labelIDs"));self._attributes[$conversationID]={isClosed:$conversation.data("isClosed")?!0:!1,labelIDs:$labelIDs},self._permissions[$conversationID]={canAddParticipants:$conversation.data("canAddParticipants")?!0:!1,canCloseConversation:$conversation.data("canCloseConversation")?!0:!1}}})},getPermission:function(e,a){return void 0===this._permissions[e][a]?!1:this._permissions[e][a]?!0:!1},getValue:function(e,a){switch(a){case"labelIDs":return void 0===this._attributes[e].labelIDs&&(this._attributes[e].labelIDs=[]),this._attributes[e].labelIDs;case"isClosed":return this._attributes[e].isClosed?!0:!1}},countAvailableLabels:function(){return this.getAvailableLabels().length},getAvailableLabels:function(){var e=[];return WCF.Dropdown.getDropdownMenu("conversationLabelFilter").children(".scrollableDropdownMenu").children("li").each(function(a,t){var n=$(t);if(n.hasClass("dropdownDivider"))return!1;var s=n.find("span");e.push({cssClassName:s.data("cssClassName"),labelID:s.data("labelID"),label:s.text()})}),e},update:function(e,a,t){if(!this._conversations[e])return void console.debug("[WCF.Conversation.EditorHandler] Unknown conversation id '"+e+"'");var n=this._conversations[e];switch(a){case"close":$('<li><span class="icon icon16 icon-lock jsTooltip jsIconLock" title="'+WCF.Language.get("wcf.global.state.closed")+'" /></li>').prependTo(n.find(".statusIcons")),this._attributes[e].isClosed=1;break;case"labelIDs":var s={};WCF.Dropdown.getDropdownMenu("conversationLabelFilter").find("li > a > span").each(function(e,a){var t=$(a);s[t.data("labelID")]={cssClassName:t.data("cssClassName"),label:t.text(),url:t.parent().attr("href")}});var i=n.find(".columnSubject > .labelList");if(t.length){i.length||(i=$('<ul class="labelList" />').prependTo(n.find(".columnSubject"))),i.empty();for(var o=0,l=t.length;l>o;o++){var r=s[t[o]];$('<li><a href="'+r.url+'" class="badge label'+(r.cssClassName?" "+r.cssClassName:"")+'">'+WCF.String.escapeHTML(r.label)+"</a>&nbsp;</li>").appendTo(i)}}else i.length&&i.remove();break;case"open":n.find(".statusIcons li").each(function(e,a){var t=$(a);return t.children("span.jsIconLock").length?(t.remove(),!1):void 0}),this._attributes[e].isClosed=0}WCF.Clipboard.reload()}}),WCF.Conversation.EditorHandlerConversation=WCF.Conversation.EditorHandler.extend({_availableLabels:null,init:function(e){this._availableLabels=e||[],this._super()},getAvailableLabels:function(){return this._availableLabels},update:function(e,a,t){if(!this._conversations[e])return void console.debug("[WCF.Conversation.EditorHandler] Unknown conversation id '"+e+"'");switch(a){case"close":$('<span class="icon icon16 icon-lock jsTooltip jsIconLock" title="'+WCF.Language.get("wcf.global.state.closed")+'" />').appendTo($("#content > header > h1")),this._attributes[e].isClosed=1;break;case"labelIDs":var n=$(".conversationHeadline");if(t.length){var s=n.find("ul.labelList");s.length||(s=$('<ul class="labelList" />').appendTo(n)),s.empty();for(var i=0,o=t.length;o>i;i++)for(var l=t[i],r=0,c=this.getAvailableLabels().length;c>r;r++){var d=this.getAvailableLabels()[r];if(d.labelID==l){$('<li><span class="label badge'+(d.cssClassName?" "+d.cssClassName:"")+'">'+d.label+"</span>&nbsp;</li>").appendTo(s);break}}}else n.find("ul.labelList").remove();break;case"open":$("#content > header span.jsIconLock").remove(),this._attributes[e].isClosed=0}}}),WCF.Conversation.Clipboard=Class.extend({_editorHandler:null,init:function(editorHandler){this._editorHandler=editorHandler,$(".jsClipboardEditor").each($.proxy(function(index,container){var $container=$(container),$types=eval($container.data("types"));return WCF.inArray("com.woltlab.wcf.conversation.conversation",$types)?($container.on("clipboardAction",$.proxy(this._execute,this)),$container.on("clipboardActionResponse",$.proxy(this._evaluateResponse,this)),!1):void 0},this))},_execute:function(e,a,t,n){"com.woltlab.wcf.conversation.conversation"===a&&"com.woltlab.wcf.conversation.conversation.assignLabel"===t&&new WCF.Conversation.Label.Editor(this._editorHandler,null,n.objectIDs)},_evaluateResponse:function(e,a,t,n){if("com.woltlab.wcf.conversation.conversation"===t)switch(n){case"com.woltlab.wcf.conversation.conversation.leave":case"com.woltlab.wcf.conversation.conversation.leavePermanently":case"com.woltlab.wcf.conversation.conversation.markAsRead":case"com.woltlab.wcf.conversation.conversation.restore":window.location.reload();break;case"com.woltlab.wcf.conversation.conversation.close":case"com.woltlab.wcf.conversation.conversation.open":for(var s in a.returnValues.conversationData){var i=a.returnValues.conversationData[s];this._editorHandler.update(s,i.isClosed?"close":"open",i)}}}}),WCF.Conversation.InlineEditor=WCF.InlineEditor.extend({_editorHandler:null,_environment:"conversation",_setOptions:function(){this._options=[{label:WCF.Language.get("wcf.conversation.edit.close"),optionName:"close"},{label:WCF.Language.get("wcf.conversation.edit.open"),optionName:"open"},{label:WCF.Language.get("wcf.conversation.edit.assignLabel"),optionName:"assignLabel"},{optionName:"divider"},{label:WCF.Language.get("wcf.conversation.edit.addParticipants"),optionName:"addParticipants"},{label:WCF.Language.get("wcf.conversation.edit.leave"),optionName:"leave"}]},setEditorHandler:function(e,a){this._editorHandler=e,this._environment="list"==a?"list":"conversation"},_getTriggerElement:function(e){return e.find(".jsConversationInlineEditor")},_validate:function(e,a){var t=$("#"+e).data("conversationID");switch(a){case"addParticipants":return this._editorHandler.getPermission(t,"canAddParticipants");case"assignLabel":return this._editorHandler.countAvailableLabels()?!0:!1;case"close":case"open":return this._editorHandler.getPermission(t,"canCloseConversation")?"close"===a?!this._editorHandler.getValue(t,"isClosed"):this._editorHandler.getValue(t,"isClosed"):!1;case"leave":return!0}return!1},_execute:function(e,a){if(!this._validate(e,a))return!1;switch(a){case"addParticipants":new WCF.Conversation.AddParticipants($("#"+e).data("conversationID"));break;case"assignLabel":new WCF.Conversation.Label.Editor(this._editorHandler,e);break;case"close":case"open":this._updateConversation(e,a,{isClosed:"close"===a?1:0});break;case"leave":new WCF.Conversation.Leave([$("#"+e).data("conversationID")],this._environment)}},_updateConversation:function(e,a,t){var n=this._elements[e].data("conversationID");switch(a){case"close":case"open":this._updateData.push({elementID:e,optionName:a,data:t}),this._proxy.setOption("data",{actionName:a,className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[n]}),this._proxy.sendRequest()}},_updateState:function(){for(var e=0,a=this._updateData.length;a>e;e++){var t=this._updateData[e],n=this._elements[t.elementID].data("conversationID");switch(t.optionName){case"close":this._editorHandler.update(n,"close",t.data);break;case"open":this._editorHandler.update(n,"open",t.data)}}}}),WCF.Conversation.Leave=Class.extend({_conversationIDs:[],_dialog:null,_environment:"",_proxy:null,init:function(e,a){this._conversationIDs=e,this._dialog=null,this._environment=a,this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)}),this._loadDialog()},_loadDialog:function(){this._proxy.setOption("data",{actionName:"getLeaveForm",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:this._conversationIDs}),this._proxy.sendRequest()},_success:function(e){switch(e.returnValues.actionName){case"getLeaveForm":this._showDialog(e);break;case"hideConversation":"conversation"===this._environment?window.location=e.returnValues.redirectURL:window.location.reload()}},_showDialog:function(e){null===this._dialog&&(this._dialog=$("#leaveDialog"),this._dialog.length||(this._dialog=$('<div id="leaveDialog" />').hide().appendTo(document.body))),this._dialog.html(e.returnValues.template),this._dialog.wcfDialog({title:WCF.Language.get("wcf.conversation.leave.title")}),this._dialog.wcfDialog("render"),this._dialog.find("#hideConversation").click($.proxy(this._click,this))},_click:function(){var e=this._dialog.find("input[type=radio]:checked");1===e.length&&(this._proxy.setOption("data",{actionName:"hideConversation",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:this._conversationIDs,parameters:{hideConversation:e.val()}}),this._proxy.sendRequest())}}),WCF.Conversation.AddParticipants=Class.extend({_conversationID:0,_dialog:null,_proxy:null,init:function(e){this._conversationID=e,this._dialog=$("#conversationAddParticipants"),this._dialog.length||(this._dialog=$('<div id="conversationAddParticipants" />').hide().appendTo(document.body)),this._proxy=new WCF.Action.Proxy({autoSend:!0,data:{actionName:"getAddParticipantsForm",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[this._conversationID]},success:$.proxy(this._success,this)})},_success:function(e){switch(e.returnValues.actionName){case"addParticipants":if(e.returnValues.errorMessage)return this._dialog.find("dl.jsAddParticipants").addClass("formError"),this._dialog.find("dl.jsAddParticipants > dd small.innerError").remove(),void $('<small class="innerError">'+e.returnValues.errorMessage+"</small>").appendTo(this._dialog.find("dl.jsAddParticipants > dd"));if(e.returnValues.count){var a=new WCF.System.Notification(e.returnValues.successMessage);a.show()}this._dialog.find("dl.jsAddParticipants").removeClass("formError").find("small.innerError").remove(),this._dialog.wcfDialog("close");break;case"getAddParticipantsForm":this._renderForm(e)}},_renderForm:function(e){this._dialog.html(e.returnValues.template),this._dialog.find("#addParticipants").disable().click($.proxy(this._submit,this)),new WCF.Search.User("#participantsInput",null,!1,e.returnValues.excludeSearchValues,!0);var a=$("#participantsInput");a.keyup($.proxy(this._toggleSubmitButton,this)),$.browser.mozilla&&$.browser.touch&&a.on("input",$.proxy(this._toggleSubmitButton,this)),this._dialog.wcfDialog({title:WCF.Language.get("wcf.conversation.edit.addParticipants")})},_toggleSubmitButton:function(){var e=this._dialog.find("#addParticipants");""===$.trim($("#participantsInput").val())?e.disable():e.enable()},_submit:function(){var e=$.trim($("#participantsInput").val());""==e&&this._dialog.wcfDialog("close"),this._proxy.setOption("data",{actionName:"addParticipants",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[this._conversationID],parameters:{participants:e}}),this._proxy.sendRequest()}}),WCF.Conversation.RemoveParticipant=WCF.Action.Delete.extend({_conversationID:0,init:function(e){this._conversationID=e,this._super("wcf\\data\\conversation\\ConversationAction",".jsParticipant")},_sendRequest:function(e){this.proxy.setOption("data",{actionName:"removeParticipant",className:this._className,objectIDs:[this._conversationID],parameters:{userID:$(e).data("objectID")}}),this.proxy.sendRequest()},_success:function(e){var a=e.returnValues.userID;for(var t in this._containers){var n=$("#"+this._containers[t]);n.find(".jsDeleteButton").data("objectID")==a&&(n.find(".userLink").addClass("conversationLeft"),n.find(".jsDeleteButton").remove())}}}),WCF.Conversation.Label={},WCF.Conversation.Label.Editor=Class.extend({_conversationIDs:0,_dialog:null,_editorHandler:null,_notification:null,_proxy:null,init:function(e,a,t){this._conversationIDs=a?[$("#"+a).data("conversationID")]:t,this._dialog=null,this._editorHandler=e,this._notification=new WCF.System.Notification(WCF.Language.get("wcf.global.success.edit")),this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)}),this._loadDialog()},_loadDialog:function(){this._proxy.setOption("data",{actionName:"getLabelForm",className:"wcf\\data\\conversation\\label\\ConversationLabelAction",parameters:{conversationIDs:this._conversationIDs}}),this._proxy.sendRequest()},_success:function(e){switch(e.returnValues.actionName){case"assignLabel":this._assignLabels(e);break;case"getLabelForm":this._renderDialog(e)}},_renderDialog:function(e){null===this._dialog&&(this._dialog=$("#conversationLabelForm"),this._dialog.length||(this._dialog=$('<div id="conversationLabelForm" />').hide().appendTo(document.body))),this._dialog.html(e.returnValues.template),this._dialog.wcfDialog({title:WCF.Language.get("wcf.conversation.label.assignLabels")}),this._dialog.wcfDialog("render"),$("#assignLabels").click($.proxy(this._save,this))},_save:function(){var e=[];this._dialog.find("input").each(function(a,t){var n=$(t);n.is(":checked")&&e.push(n.data("labelID"))}),this._proxy.setOption("data",{actionName:"assignLabel",className:"wcf\\data\\conversation\\label\\ConversationLabelAction",parameters:{conversationIDs:this._conversationIDs,labelIDs:e}}),this._proxy.sendRequest()},_assignLabels:function(e){for(var a=0,t=this._conversationIDs.length;t>a;a++)this._editorHandler.update(this._conversationIDs[a],"labelIDs",e.returnValues.labelIDs);this._dialog.wcfDialog("close"),this._notification.show()}}),WCF.Conversation.Label.Manager=Class.extend({_deletedLabelID:0,_dialog:null,_labels:null,_link:"",_notification:"",_proxy:null,_maxLabels:0,_labelCount:0,init:function(e){this._deletedLabelID=0,this._maxLabels=0,this._labelCount=0,this._link=e,this._labels=WCF.Dropdown.getDropdownMenu("conversationLabelFilter").children(".scrollableDropdownMenu"),$("#manageLabel").click($.proxy(this._click,this)),this._notification=new WCF.System.Notification(WCF.Language.get("wcf.conversation.label.management.addLabel.success")),this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)})},_click:function(){this._proxy.setOption("data",{actionName:"getLabelManagement",className:"wcf\\data\\conversation\\ConversationAction"}),this._proxy.sendRequest()},_success:function(e){if(null===this._dialog&&(this._dialog=$('<div id="labelManagement" />').hide().appendTo(document.body)),e.returnValues&&e.returnValues.actionName)switch(e.returnValues.actionName){case"add":this._insertLabel(e);break;case"getLabelManagement":this._maxLabels=parseInt(e.returnValues.maxLabels),this._labelCount=parseInt(e.returnValues.labelCount),this._dialog.empty().html(e.returnValues.template),this._dialog.wcfDialog({title:WCF.Language.get("wcf.conversation.label.management")}),this._dialog.wcfDialog("render"),this._bindListener()}else if(this._deletedLabelID){var a=new RegExp("(\\?|&)labelID="+this._deletedLabelID);window.location=window.location.toString().replace(a,"")}else window.location.reload()},_insertLabel:function(e){var a=$('<li><a href="'+this._link+"&labelID="+e.returnValues.labelID+'"><span class="badge label'+(e.returnValues.cssClassName?" "+e.returnValues.cssClassName:"")+'">'+e.returnValues.label+"</span></a></li>");a.find("a > span").data("labelID",e.returnValues.labelID).data("cssClassName",e.returnValues.cssClassName),this._labels.append(a),this._notification.show(),this._labelCount++,this._labelCount>=this._maxLabels&&$("#conversationLabelManagementForm").hide()},_bindListener:function(){$("#labelName").on("keyup keydown keypress",$.proxy(this._updateLabels,this)),$.browser.mozilla&&$.browser.touch&&$("#labelName").on("input",$.proxy(this._updateLabels,this)),this._labelCount>=this._maxLabels&&($("#conversationLabelManagementForm").hide(),this._dialog.wcfDialog("render")),$("#addLabel").disable().click($.proxy(this._addLabel,this)),$("#editLabel").disable(),this._dialog.find(".conversationLabelList a.label").click($.proxy(this._edit,this))},_edit:function(e){this._labelCount>=this._maxLabels&&($("#conversationLabelManagementForm").show(),this._dialog.wcfDialog("render"));var a=$(e.currentTarget),t=WCF.Language.get("wcf.conversation.label.management.editLabel").replace(/#labelName#/,WCF.String.escapeHTML(a.text()));$("#conversationLabelManagementForm").data("labelID",a.data("labelID")).children("legend").html(t),$("#labelName").val(a.text()).trigger("keyup");var n=a.data("cssClassName");$("#labelManagementList input").each(function(e,a){var t=$(a);t.val()==n&&t.attr("checked","checked")}),$("#addLabel").hide(),$("#editLabel").show().click($.proxy(this._editLabel,this)),$("#deleteLabel").show().click($.proxy(this._deleteLabel,this))},_editLabel:function(){this._proxy.setOption("data",{actionName:"update",className:"wcf\\data\\conversation\\label\\ConversationLabelAction",objectIDs:[$("#conversationLabelManagementForm").data("labelID")],parameters:{data:{cssClassName:$("#labelManagementList input:checked").val(),label:$("#labelName").val()}}}),this._proxy.sendRequest()},_deleteLabel:function(){var e=WCF.Language.get("wcf.conversation.label.management.deleteLabel.confirmMessage").replace(/#labelName#/,$("#labelName").val());WCF.System.Confirmation.show(e,$.proxy(function(e){"confirm"===e&&(this._proxy.setOption("data",{actionName:"delete",className:"wcf\\data\\conversation\\label\\ConversationLabelAction",objectIDs:[$("#conversationLabelManagementForm").data("labelID")]}),this._proxy.sendRequest(),this._deletedLabelID=$("#conversationLabelManagementForm").data("labelID"))},this))},_updateLabels:function(){var e=$.trim($("#labelName").val());e?$("#addLabel, #editLabel").enable():($("#addLabel, #editLabel").disable(),e=WCF.Language.get("wcf.conversation.label.placeholder")),$("#labelManagementList").find("span.label").text(e)},_addLabel:function(){var e=$("#labelName").val(),a=$("#labelManagementList input:checked").val();this._proxy.setOption("data",{actionName:"add",className:"wcf\\data\\conversation\\label\\ConversationLabelAction",parameters:{data:{cssClassName:a,labelName:e}}}),this._proxy.sendRequest(),this._dialog.wcfDialog("close")}}),WCF.Conversation.Preview=WCF.Popover.extend({_proxy:null,init:function(){this._super(".conversationLink"),this._proxy=new WCF.Action.Proxy({showLoadingOverlay:!1}),WCF.DOMNodeInsertedHandler.addCallback("WCF.Conversation.Preview",$.proxy(this._initContainers,this))},_loadContent:function(){var e=$("#"+this._activeElementID);this._proxy.setOption("data",{actionName:"getMessagePreview",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[e.data("conversationID")]});var a=this._activeElementID,t=this;this._proxy.setOption("success",function(e){t._insertContent(a,e.returnValues.template,!0)}),this._proxy.sendRequest()}}),WCF.User.Panel.Conversation=WCF.User.Panel.Abstract.extend({init:function(e){e.enableMarkAsRead=!0,this._super($("#unreadConversations"),"unreadConversations",e),WCF.System.Event.addListener("com.woltlab.wcf.conversation.userPanel","reset",function(){this.resetItems(),this.updateBadge(0),this._loadData=!0}.bind(this))},_initDropdown:function(){var e=this._super();return $('<li><a href="'+this._options.newConversationLink+'" title="'+this._options.newConversation+'" class="jsTooltip"><span class="icon icon16 fa-plus" /></a></li>').appendTo(e.getLinkList()),e},_load:function(){this._proxy.setOption("data",{actionName:"getMixedConversationList",className:"wcf\\data\\conversation\\ConversationAction"}),this._proxy.sendRequest()},_markAsRead:function(e,a){this._proxy.setOption("data",{actionName:"markAsRead",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[a]}),this._proxy.sendRequest()},_markAllAsRead:function(){this._proxy.setOption("data",{actionName:"markAllAsRead",className:"wcf\\data\\conversation\\ConversationAction"}),this._proxy.sendRequest()}}),WCF.Conversation.QuickReply=WCF.Message.QuickReply.extend({init:function(e){this._super(!0,e)},_getClassName:function(){return"wcf\\data\\conversation\\message\\ConversationMessageAction"},_getObjectID:function(){return this._container.data("conversationID")}}),WCF.Conversation.MarkAsRead=Class.extend({_proxy:null,init:function(){this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)}),$(document).on("dblclick",".conversationList .new .columnAvatar",$.proxy(this._dblclick,this))},_dblclick:function(e){this._proxy.setOption("data",{actionName:"markAsRead",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[$(e.currentTarget).parents("tr:eq(0)").data("conversationID")]}),this._proxy.sendRequest()},_success:function(e){$(".conversationList .new").each(function(a,t){var n=$(t);WCF.inArray(n.data("conversationID"),e.objectIDs)&&(n.removeClass("new"),n.find(".firstNewPost").parent().remove(),n.find(".columnAvatar").off("dblclick"))})}}),WCF.Conversation.MarkAllAsRead=Class.extend({_proxy:null,init:function(){this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)}),$(".markAllAsReadButton").click($.proxy(this._click,this))},_click:function(e){e.preventDefault(),this._proxy.setOption("data",{actionName:"markAllAsRead",className:"wcf\\data\\conversation\\ConversationAction"}),this._proxy.sendRequest()},_success:function(){WCF.System.Event.fireEvent("com.woltlab.wcf.conversation.userPanel","reset");var e=$(".conversationList");e.find(".new").removeClass("new"),e.find(".columnAvatar").off("dblclick")}}),WCF.Conversation.Message={},WCF.Conversation.Message.InlineEditor=WCF.Message.InlineEditor.extend({init:function(e,a){this._super(e,!0,a)},_getClassName:function(){return"wcf\\data\\conversation\\message\\ConversationMessageAction"}}),WCF.Conversation.Message.QuoteHandler=WCF.Message.Quote.Handler.extend({init:function(e){this._super(e,"wcf\\data\\conversation\\message\\ConversationMessageAction","com.woltlab.wcf.conversation.message",".message",".messageBody",".messageBody > div > div.messageText",!0)}});
\ No newline at end of file
+WCF.Conversation={},WCF.Conversation.EditorHandler=Class.extend({_attributes:{},_conversations:{},_permissions:{},init:function(availableLabels){this._conversations={};var self=this;$(".conversation").each(function(index,conversation){var $conversation=$(conversation),$conversationID=$conversation.data("conversationID");if(!self._conversations[$conversationID]){self._conversations[$conversationID]=$conversation;var $labelIDs=eval($conversation.data("labelIDs"));self._attributes[$conversationID]={isClosed:$conversation.data("isClosed")?!0:!1,labelIDs:$labelIDs},self._permissions[$conversationID]={canAddParticipants:$conversation.data("canAddParticipants")?!0:!1,canCloseConversation:$conversation.data("canCloseConversation")?!0:!1}}})},getPermission:function(e,a){return void 0===this._permissions[e][a]?!1:this._permissions[e][a]?!0:!1},getValue:function(e,a){switch(a){case"labelIDs":return void 0===this._attributes[e].labelIDs&&(this._attributes[e].labelIDs=[]),this._attributes[e].labelIDs;case"isClosed":return this._attributes[e].isClosed?!0:!1}},countAvailableLabels:function(){return this.getAvailableLabels().length},getAvailableLabels:function(){var e=[];return WCF.Dropdown.getDropdownMenu("conversationLabelFilter").children(".scrollableDropdownMenu").children("li").each(function(a,t){var n=$(t);if(n.hasClass("dropdownDivider"))return!1;var s=n.find("span");e.push({cssClassName:s.data("cssClassName"),labelID:s.data("labelID"),label:s.text()})}),e},update:function(e,a,t){if(!this._conversations[e])return void console.debug("[WCF.Conversation.EditorHandler] Unknown conversation id '"+e+"'");var n=this._conversations[e];switch(a){case"close":$('<li><span class="icon icon16 fa-lock jsTooltip jsIconLock" title="'+WCF.Language.get("wcf.global.state.closed")+'" /></li>').prependTo(n.find(".statusIcons")),this._attributes[e].isClosed=1;break;case"labelIDs":var s={};WCF.Dropdown.getDropdownMenu("conversationLabelFilter").find("li > a > span").each(function(e,a){var t=$(a);s[t.data("labelID")]={cssClassName:t.data("cssClassName"),label:t.text(),url:t.parent().attr("href")}});var i=n.find(".columnSubject > .labelList");if(t.length){i.length||(i=$('<ul class="labelList" />').prependTo(n.find(".columnSubject"))),i.empty();for(var o=0,l=t.length;l>o;o++){var r=s[t[o]];$('<li><a href="'+r.url+'" class="badge label'+(r.cssClassName?" "+r.cssClassName:"")+'">'+WCF.String.escapeHTML(r.label)+"</a></li>").appendTo(i)}}else i.length&&i.remove();break;case"open":n.find(".statusIcons li").each(function(e,a){var t=$(a);return t.children("span.jsIconLock").length?(t.remove(),!1):void 0}),this._attributes[e].isClosed=0}WCF.Clipboard.reload()}}),WCF.Conversation.EditorHandlerConversation=WCF.Conversation.EditorHandler.extend({_availableLabels:null,init:function(e){this._availableLabels=e||[],this._super()},getAvailableLabels:function(){return this._availableLabels},update:function(e,a,t){if(!this._conversations[e])return void console.debug("[WCF.Conversation.EditorHandler] Unknown conversation id '"+e+"'");var n=$(".contentHeaderTitle > .contentHeaderMetaData");switch(a){case"close":$('<li><span class="icon icon16 fa-lock jsIconLock" /> '+WCF.Language.get("wcf.global.state.closed")+"</li>").appendTo(n),this._attributes[e].isClosed=1;break;case"labelIDs":var s=n.find(".labelList");if(t.length){var i=this.getAvailableLabels();s.length||(s=$('<li><span class="icon icon16 fa-tags"></span> <ul class="labelList"></ul></li>').prependTo(n),s=s.children("ul"));var o="";t.forEach(function(e){i.forEach(function(a){a.labelID==e&&(o+='<li><span class="label badge'+(a.cssClassName?" "+a.cssClassName:"")+'">'+a.label+"</span></li>")})}),s[0].innerHTML=o}else s.parent().remove();break;case"open":n.find(".jsIconLock").parent().remove(),this._attributes[e].isClosed=0}}}),WCF.Conversation.Clipboard=Class.extend({_editorHandler:null,init:function(e){this._editorHandler=e,WCF.System.Event.addListener("com.woltlab.wcf.clipboard","com.woltlab.wcf.conversation.conversation",function(e){null===e.responseData?this._execute(e.data.actionName,e.data.parameters):this._evaluateResponse(e.data.actionName,e.responseData)}.bind(this))},_execute:function(e,a){"com.woltlab.wcf.conversation.conversation.assignLabel"===e&&new WCF.Conversation.Label.Editor(this._editorHandler,null,a.objectIDs)},_evaluateResponse:function(e,a){switch(e){case"com.woltlab.wcf.conversation.conversation.leave":case"com.woltlab.wcf.conversation.conversation.leavePermanently":case"com.woltlab.wcf.conversation.conversation.markAsRead":case"com.woltlab.wcf.conversation.conversation.restore":window.location.reload();break;case"com.woltlab.wcf.conversation.conversation.close":case"com.woltlab.wcf.conversation.conversation.open":for(var t in a.returnValues.conversationData)if(a.returnValues.conversationData.hasOwnProperty(t)){var n=a.returnValues.conversationData[t];this._editorHandler.update(t,n.isClosed?"close":"open",n)}}}}),WCF.Conversation.InlineEditor=WCF.InlineEditor.extend({_editorHandler:null,_environment:"conversation",_setOptions:function(){this._options=[{label:WCF.Language.get("wcf.conversation.edit.close"),optionName:"close"},{label:WCF.Language.get("wcf.conversation.edit.open"),optionName:"open"},{label:WCF.Language.get("wcf.conversation.edit.assignLabel"),optionName:"assignLabel"},{optionName:"divider"},{label:WCF.Language.get("wcf.conversation.edit.addParticipants"),optionName:"addParticipants"},{label:WCF.Language.get("wcf.conversation.edit.leave"),optionName:"leave"}]},setEditorHandler:function(e,a){this._editorHandler=e,this._environment="list"==a?"list":"conversation"},_getTriggerElement:function(e){return e.find(".jsConversationInlineEditor")},_validate:function(e,a){var t=$("#"+e).data("conversationID");switch(a){case"addParticipants":return this._editorHandler.getPermission(t,"canAddParticipants");case"assignLabel":return this._editorHandler.countAvailableLabels()?!0:!1;case"close":case"open":return this._editorHandler.getPermission(t,"canCloseConversation")?"close"===a?!this._editorHandler.getValue(t,"isClosed"):this._editorHandler.getValue(t,"isClosed"):!1;case"leave":return!0}return!1},_execute:function(e,a){if(!this._validate(e,a))return!1;switch(a){case"addParticipants":require(["WoltLabSuite/Core/Conversation/Ui/Participant/Add"],function(a){new a(document.getElementById(e).getAttribute("data-conversation-id"))});break;case"assignLabel":new WCF.Conversation.Label.Editor(this._editorHandler,e);break;case"close":case"open":this._updateConversation(e,a,{isClosed:"close"===a?1:0});break;case"leave":new WCF.Conversation.Leave([$("#"+e).data("conversationID")],this._environment)}},_updateConversation:function(e,a,t){var n=this._elements[e].data("conversationID");switch(a){case"close":case"open":this._updateData.push({elementID:e,optionName:a,data:t}),this._proxy.setOption("data",{actionName:a,className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[n]}),this._proxy.sendRequest()}},_updateState:function(){for(var e=0,a=this._updateData.length;a>e;e++){var t=this._updateData[e],n=this._elements[t.elementID].data("conversationID");switch(t.optionName){case"close":this._editorHandler.update(n,"close",t.data);break;case"open":this._editorHandler.update(n,"open",t.data)}}}}),WCF.Conversation.Leave=Class.extend({_conversationIDs:[],_dialog:null,_environment:"",_proxy:null,init:function(e,a){this._conversationIDs=e,this._dialog=null,this._environment=a,this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)}),this._loadDialog()},_loadDialog:function(){this._proxy.setOption("data",{actionName:"getLeaveForm",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:this._conversationIDs}),this._proxy.sendRequest()},_success:function(e){switch(e.returnValues.actionName){case"getLeaveForm":this._showDialog(e);break;case"hideConversation":"conversation"===this._environment?window.location=e.returnValues.redirectURL:window.location.reload()}},_showDialog:function(e){null===this._dialog&&(this._dialog=$("#leaveDialog"),this._dialog.length||(this._dialog=$('<div id="leaveDialog" />').hide().appendTo(document.body))),this._dialog.html(e.returnValues.template),this._dialog.wcfDialog({title:WCF.Language.get("wcf.conversation.leave.title")}),this._dialog.wcfDialog("render"),this._dialog.find("#hideConversation").click($.proxy(this._click,this))},_click:function(){var e=this._dialog.find("input[type=radio]:checked");1===e.length&&(this._proxy.setOption("data",{actionName:"hideConversation",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:this._conversationIDs,parameters:{hideConversation:e.val()}}),this._proxy.sendRequest())}}),WCF.Conversation.RemoveParticipant=WCF.Action.Delete.extend({_conversationID:0,init:function(e){this._conversationID=e,this._super("wcf\\data\\conversation\\ConversationAction",".jsParticipant")},_sendRequest:function(e){this.proxy.setOption("data",{actionName:"removeParticipant",className:this._className,objectIDs:[this._conversationID],parameters:{userID:$(e).data("objectID")}}),this.proxy.sendRequest()},_success:function(e){var a=e.returnValues.userID;for(var t in this._containers){var n=$("#"+this._containers[t]);n.find(".jsDeleteButton").data("objectID")==a&&(n.find(".userLink").addClass("conversationLeft"),n.find(".jsDeleteButton").remove())}}}),WCF.Conversation.Label={},WCF.Conversation.Label.Editor=Class.extend({_conversationIDs:0,_dialog:null,_editorHandler:null,_notification:null,_proxy:null,init:function(e,a,t){this._conversationIDs=a?[$("#"+a).data("conversationID")]:t,this._dialog=null,this._editorHandler=e,this._notification=new WCF.System.Notification(WCF.Language.get("wcf.global.success.edit")),this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)}),this._loadDialog()},_loadDialog:function(){this._proxy.setOption("data",{actionName:"getLabelForm",className:"wcf\\data\\conversation\\label\\ConversationLabelAction",parameters:{conversationIDs:this._conversationIDs}}),this._proxy.sendRequest()},_success:function(e){switch(e.returnValues.actionName){case"assignLabel":this._assignLabels(e);break;case"getLabelForm":this._renderDialog(e)}},_renderDialog:function(e){null===this._dialog&&(this._dialog=$("#conversationLabelForm"),this._dialog.length||(this._dialog=$('<div id="conversationLabelForm" />').hide().appendTo(document.body))),this._dialog.html(e.returnValues.template),this._dialog.wcfDialog({title:WCF.Language.get("wcf.conversation.label.assignLabels")}),this._dialog.wcfDialog("render"),$("#assignLabels").click($.proxy(this._save,this))},_save:function(){var e=[];this._dialog.find("input").each(function(a,t){var n=$(t);n.is(":checked")&&e.push(n.data("labelID"))}),this._proxy.setOption("data",{actionName:"assignLabel",className:"wcf\\data\\conversation\\label\\ConversationLabelAction",parameters:{conversationIDs:this._conversationIDs,labelIDs:e}}),this._proxy.sendRequest()},_assignLabels:function(e){for(var a=0,t=this._conversationIDs.length;t>a;a++)this._editorHandler.update(this._conversationIDs[a],"labelIDs",e.returnValues.labelIDs);this._dialog.wcfDialog("close"),this._notification.show()}}),WCF.Conversation.Label.Manager=Class.extend({_deletedLabelID:0,_dialog:null,_labels:null,_link:"",_notification:"",_proxy:null,_maxLabels:0,_labelCount:0,init:function(e){this._deletedLabelID=0,this._maxLabels=0,this._labelCount=0,this._link=e,this._labels=WCF.Dropdown.getDropdownMenu("conversationLabelFilter").children(".scrollableDropdownMenu"),$("#manageLabel").click($.proxy(this._click,this)),this._notification=new WCF.System.Notification(WCF.Language.get("wcf.conversation.label.management.addLabel.success")),this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)})},_click:function(){this._proxy.setOption("data",{actionName:"getLabelManagement",className:"wcf\\data\\conversation\\ConversationAction"}),this._proxy.sendRequest()},_success:function(e){if(null===this._dialog&&(this._dialog=$('<div id="labelManagement" />').hide().appendTo(document.body)),e.returnValues&&e.returnValues.actionName)switch(e.returnValues.actionName){case"add":this._insertLabel(e);break;case"getLabelManagement":this._maxLabels=parseInt(e.returnValues.maxLabels),this._labelCount=parseInt(e.returnValues.labelCount),this._dialog.empty().html(e.returnValues.template),this._dialog.wcfDialog({title:WCF.Language.get("wcf.conversation.label.management")}),this._dialog.wcfDialog("render"),this._bindListener()}else if(this._deletedLabelID){var a=new RegExp("(\\?|&)labelID="+this._deletedLabelID);window.location=window.location.toString().replace(a,"")}else window.location.reload()},_insertLabel:function(e){var a=$('<li><a href="'+this._link+"&labelID="+e.returnValues.labelID+'"><span class="badge label'+(e.returnValues.cssClassName?" "+e.returnValues.cssClassName:"")+'">'+e.returnValues.label+"</span></a></li>");a.find("a > span").data("labelID",e.returnValues.labelID).data("cssClassName",e.returnValues.cssClassName),this._labels.append(a),this._notification.show(),this._labelCount++,this._labelCount>=this._maxLabels&&$("#conversationLabelManagementForm").hide()},_bindListener:function(){$("#labelName").on("keyup keydown keypress",$.proxy(this._updateLabels,this)),$.browser.mozilla&&$.browser.touch&&$("#labelName").on("input",$.proxy(this._updateLabels,this)),this._labelCount>=this._maxLabels&&($("#conversationLabelManagementForm").hide(),this._dialog.wcfDialog("render")),$("#addLabel").disable().click($.proxy(this._addLabel,this)),$("#editLabel").disable(),this._dialog.find(".conversationLabelList a.label").click($.proxy(this._edit,this))},_edit:function(e){this._labelCount>=this._maxLabels&&($("#conversationLabelManagementForm").show(),this._dialog.wcfDialog("render"));var a=$(e.currentTarget),t=WCF.Language.get("wcf.conversation.label.management.editLabel").replace(/#labelName#/,WCF.String.escapeHTML(a.text()));$("#conversationLabelManagementForm").data("labelID",a.data("labelID")).children("legend").html(t),$("#labelName").val(a.text()).trigger("keyup");var n=a.data("cssClassName");$("#labelManagementList input").each(function(e,a){var t=$(a);t.val()==n&&t.attr("checked","checked")}),$("#addLabel").hide(),$("#editLabel").show().click($.proxy(this._editLabel,this)),$("#deleteLabel").show().click($.proxy(this._deleteLabel,this))},_editLabel:function(){this._proxy.setOption("data",{actionName:"update",className:"wcf\\data\\conversation\\label\\ConversationLabelAction",objectIDs:[$("#conversationLabelManagementForm").data("labelID")],parameters:{data:{cssClassName:$("#labelManagementList input:checked").val(),label:$("#labelName").val()}}}),this._proxy.sendRequest()},_deleteLabel:function(){var e=WCF.Language.get("wcf.conversation.label.management.deleteLabel.confirmMessage").replace(/#labelName#/,$("#labelName").val());WCF.System.Confirmation.show(e,$.proxy(function(e){"confirm"===e&&(this._proxy.setOption("data",{actionName:"delete",className:"wcf\\data\\conversation\\label\\ConversationLabelAction",objectIDs:[$("#conversationLabelManagementForm").data("labelID")]}),this._proxy.sendRequest(),this._deletedLabelID=$("#conversationLabelManagementForm").data("labelID"))},this),void 0,void 0,!0)},_updateLabels:function(){var e=$.trim($("#labelName").val());e?$("#addLabel, #editLabel").enable():($("#addLabel, #editLabel").disable(),e=WCF.Language.get("wcf.conversation.label.placeholder")),$("#labelManagementList").find("span.label").text(e)},_addLabel:function(){var e=$("#labelName").val(),a=$("#labelManagementList input:checked").val();this._proxy.setOption("data",{actionName:"add",className:"wcf\\data\\conversation\\label\\ConversationLabelAction",parameters:{data:{cssClassName:a,labelName:e}}}),this._proxy.sendRequest(),this._dialog.wcfDialog("close")}}),WCF.Conversation.Preview=WCF.Popover.extend({_proxy:null,init:function(){this._super(".conversationLink"),this._proxy=new WCF.Action.Proxy({showLoadingOverlay:!1}),WCF.DOMNodeInsertedHandler.addCallback("WCF.Conversation.Preview",$.proxy(this._initContainers,this))},_loadContent:function(){var e=$("#"+this._activeElementID);this._proxy.setOption("data",{actionName:"getMessagePreview",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[e.data("conversationID")]});var a=this._activeElementID,t=this;this._proxy.setOption("success",function(e){t._insertContent(a,e.returnValues.template,!0)}),this._proxy.sendRequest()}}),WCF.User.Panel.Conversation=WCF.User.Panel.Abstract.extend({init:function(e){e.enableMarkAsRead=!0,this._super($("#unreadConversations"),"unreadConversations",e),WCF.System.Event.addListener("com.woltlab.wcf.conversation.userPanel","reset",function(){this.resetItems(),this.updateBadge(0),this._loadData=!0}.bind(this)),require(["EventHandler"],function(e){e.add("com.woltlab.wcf.UserMenuMobile","more",function(e){"com.woltlab.wcf.conversation"===e.identifier&&this.toggle()}.bind(this))}.bind(this))},_initDropdown:function(){var e=this._super();return $('<li><a href="'+this._options.newConversationLink+'" title="'+this._options.newConversation+'" class="jsTooltip"><span class="icon icon24 fa-plus" /></a></li>').appendTo(e.getLinkList()),e},_load:function(){this._proxy.setOption("data",{actionName:"getMixedConversationList",className:"wcf\\data\\conversation\\ConversationAction"}),this._proxy.sendRequest()},_markAsRead:function(e,a){this._proxy.setOption("data",{actionName:"markAsRead",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[a]}),this._proxy.sendRequest()},_markAllAsRead:function(){this._proxy.setOption("data",{actionName:"markAllAsRead",className:"wcf\\data\\conversation\\ConversationAction"}),this._proxy.sendRequest()}}),WCF.Conversation.MarkAsRead=Class.extend({_proxy:null,init:function(){this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)}),$(document).on("dblclick",".conversationList .new .columnAvatar",$.proxy(this._dblclick,this))},_dblclick:function(e){this._proxy.setOption("data",{actionName:"markAsRead",className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[$(e.currentTarget).parents("tr:eq(0)").data("conversationID")]}),this._proxy.sendRequest()},_success:function(e){$(".conversationList .new").each(function(a,t){var n=$(t);WCF.inArray(n.data("conversationID"),e.objectIDs)&&(n.removeClass("new"),n.find(".firstNewPost").parent().remove(),n.find(".columnAvatar").off("dblclick"))})}}),WCF.Conversation.MarkAllAsRead=Class.extend({_proxy:null,init:function(){this._proxy=new WCF.Action.Proxy({success:$.proxy(this._success,this)}),$(".markAllAsReadButton").click($.proxy(this._click,this))},_click:function(e){e.preventDefault(),this._proxy.setOption("data",{actionName:"markAllAsRead",className:"wcf\\data\\conversation\\ConversationAction"}),this._proxy.sendRequest()},_success:function(){WCF.System.Event.fireEvent("com.woltlab.wcf.conversation.userPanel","reset");var e=$(".conversationList");e.find(".new").removeClass("new"),e.find(".columnAvatar").off("dblclick")}}),WCF.Conversation.Message={},WCF.Conversation.Message.InlineEditor=WCF.Message.InlineEditor.extend({init:function(e,a){this._super(e,!0,a)},_getClassName:function(){return"wcf\\data\\conversation\\message\\ConversationMessageAction"}}),WCF.Conversation.Message.QuoteHandler=WCF.Message.Quote.Handler.extend({init:function(e){this._super(e,"wcf\\data\\conversation\\message\\ConversationMessageAction","com.woltlab.wcf.conversation.message",".message",".messageBody",".messageBody > div > div.messageText",!0)}});
\ No newline at end of file
diff --git a/files/js/WoltLabSuite.Core.Conversation.min.js b/files/js/WoltLabSuite.Core.Conversation.min.js
new file mode 100644 (file)
index 0000000..f257681
--- /dev/null
@@ -0,0 +1 @@
+define("WoltLabSuite/Core/Conversation/Ui/Participant/Add",["Ajax","Language","Ui/Dialog","Ui/Notification","WoltLabSuite/Core/Ui/ItemList/User"],function(t,e,i,a,n){"use strict";function s(t){this.init(t)}return s.prototype={init:function(e){this._conversationId=e,t.api(this,{actionName:"getAddParticipantsForm"})},_ajaxSetup:function(){return{data:{className:"wcf\\data\\conversation\\ConversationAction",objectIDs:[this._conversationId]}}},_ajaxSuccess:function(t){switch(t.actionName){case"addParticipants":this._handleResponse(t);break;case"getAddParticipantsForm":this._render(t)}},_handleResponse:function(t){t.returnValues.count&&a.show(t.returnValues.successMessage,window.location.reload.bind(window.location)),i.close(this)},_render:function(t){i.open(this,t.returnValues.template);var e=document.getElementById("addParticipants");e.disabled=!0,n.init("participantsInput",{callbackChange:function(t,i){e.disabled=0===i.length},excludedSearchValues:t.returnValues.excludedSearchValues,maxItems:t.returnValues.maxItems}),e.addEventListener("click",this._submit.bind(this))},_submit:function(){for(var e=n.getValues("participantsInput"),i=[],a=0,s=e.length;s>a;a++)i.push(e[a].value);t.api(this,{actionName:"addParticipants",parameters:{participants:i}})},_dialogSetup:function(){return{id:"conversationAddParticipants",options:{title:e.get("wcf.conversation.edit.addParticipants")},source:null}}},s});
\ No newline at end of file
diff --git a/files/js/WoltLabSuite/Core/Conversation/Ui/Participant/Add.js b/files/js/WoltLabSuite/Core/Conversation/Ui/Participant/Add.js
new file mode 100644 (file)
index 0000000..d68e41d
--- /dev/null
@@ -0,0 +1,123 @@
+/**
+ * Adds participants to an existing conversation.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module     WoltLabSuite/Core/Conversation/Ui/Participant/Add
+ */
+define(['Ajax', 'Language', 'Ui/Dialog', 'Ui/Notification', 'WoltLabSuite/Core/Ui/ItemList/User'], function(Ajax, Language, UiDialog, UiNotification, UiItemListUser) {
+       "use strict";
+       
+       /**
+        * @constructor
+        * @param       {int}   conversationId          conversation id
+        */
+       function UiParticipantAdd(conversationId) { this.init(conversationId); }
+       UiParticipantAdd.prototype = {
+               /**
+                * Manages the form to add one or more participants to an existing conversation.
+                * 
+                * @param       {int}   conversationId          conversation id
+                */
+               init: function(conversationId) {
+                       this._conversationId = conversationId;
+                       
+                       Ajax.api(this, {
+                               actionName: 'getAddParticipantsForm'
+                       });
+               },
+               
+               _ajaxSetup: function() {
+                       return {
+                               data: {
+                                       className: 'wcf\\data\\conversation\\ConversationAction',
+                                       objectIDs: [ this._conversationId ]
+                               }
+                       };
+               },
+               
+               /**
+                * Handles successful Ajax requests.
+                * 
+                * @param       {Object}        data            response data
+                */
+               _ajaxSuccess: function(data) {
+                       switch (data.actionName) {
+                               case 'addParticipants':
+                                       this._handleResponse(data);
+                                       break;
+                               
+                               case 'getAddParticipantsForm':
+                                       this._render(data);
+                                       break;
+                       }
+               },
+               
+               /**
+                * Shows the success message and closes the dialog overlay.
+                * 
+                * @param       {Object}        data            response data
+                */
+               _handleResponse: function(data) {
+                       //noinspection JSUnresolvedVariable
+                       if (data.returnValues.count) {
+                               //noinspection JSUnresolvedVariable
+                               UiNotification.show(data.returnValues.successMessage, window.location.reload.bind(window.location));
+                       }
+                       
+                       UiDialog.close(this);
+               },
+               
+               /**
+                * Renders the dialog to add participants.
+                * 
+                * @param       {object}        data            response data
+                */
+               _render: function(data) {
+                       //noinspection JSUnresolvedVariable
+                       UiDialog.open(this, data.returnValues.template);
+                       
+                       var buttonSubmit = document.getElementById('addParticipants');
+                       buttonSubmit.disabled = true;
+                       
+                       //noinspection JSUnresolvedVariable
+                       UiItemListUser.init('participantsInput', {
+                               callbackChange: function(elementId, values) { buttonSubmit.disabled = (values.length === 0); },
+                               excludedSearchValues: data.returnValues.excludedSearchValues,
+                               maxItems: data.returnValues.maxItems
+                       });
+                       
+                       buttonSubmit.addEventListener('click', this._submit.bind(this));
+               },
+               
+               /**
+                * Sends a request to add participants.
+                */
+               _submit: function() {
+                       var values = UiItemListUser.getValues('participantsInput'), participants = [];
+                       for (var i = 0, length = values.length; i < length; i++) {
+                               participants.push(values[i].value);
+                       }
+                       
+                       Ajax.api(this, {
+                               actionName: 'addParticipants',
+                               parameters: {
+                                       participants: participants
+                               }
+                       });
+               },
+               
+               _dialogSetup: function() {
+                       return {
+                               id: 'conversationAddParticipants',
+                               options: {
+                                       title: Language.get('wcf.conversation.edit.addParticipants')
+                               },
+                               source: null
+                       };
+               }
+       };
+       
+       return UiParticipantAdd;
+});
diff --git a/files/js/require.build.js b/files/js/require.build.js
new file mode 100644 (file)
index 0000000..a399391
--- /dev/null
@@ -0,0 +1,71 @@
+(function () {
+       var config;
+       config = {
+               name: "WoltLabSuite/_Meta",
+               out: "WoltLabSuite.Core.Conversation.min.js",
+               useStrict: true,
+               preserveLicenseComments: false,
+               optimize: 'uglify2',
+               uglify2: {},
+               excludeShallow: [
+                       'WoltLabSuite/_Meta'
+               ],
+               rawText: {
+                       'WoltLabSuite/_Meta': 'define([], function() {});'
+               },
+               onBuildRead: function(moduleName, path, contents) {
+                       if (!process.versions.node) {
+                               throw new Error('You need to run node.js');
+                       }
+                       
+                       if (moduleName === 'WoltLabSuite/_Meta') {
+                               if (global.allModules == undefined) {
+                                       var fs   = module.require('fs'),
+                                           path = module.require('path');
+                                       global.allModules = [];
+                                       
+                                       var queue = ['WoltLabSuite'];
+                                       var folder;
+                                       while (folder = queue.shift()) {
+                                               var files = fs.readdirSync(folder);
+                                               for (var i = 0; i < files.length; i++) {
+                                                       var filename = path.join(folder, files[i]);
+                                                       if (filename === 'WoltLabSuite/Core/Acp') continue;
+                                                       
+                                                       if (path.extname(filename) == '.js') {
+                                                               global.allModules.push(filename);
+                                                       }
+                                                       else if (fs.statSync(filename).isDirectory()) {
+                                                               queue.push(filename);
+                                                       }
+                                               }
+                                       }
+                               }
+                               
+                               return 'define([' + global.allModules.map(function (item) { return "'" + item.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/\.js$/, '') + "'"; }).join(', ') + '], function() { });';
+                       }
+                       
+                       return contents;
+               }
+       };
+       
+       var _isSupportedBuildUrl = require._isSupportedBuildUrl;
+       require._isSupportedBuildUrl = function (url) {
+               var result = _isSupportedBuildUrl(url);
+               if (!result) return result;
+               if (Object.keys(config.rawText).map(function (item) { return process.cwd() + '/' + item + '.js'; }).indexOf(url) !== -1) return result;
+
+               var fs = module.require('fs');
+               try {
+                       fs.statSync(url);
+               }
+               catch (e) {
+                       console.log('Unable to find module:', url, 'ignoring.');
+
+                       return false;
+               }
+               return true;
+       };
+
+       return config;
+})();
diff --git a/files/js/require.build.min.js b/files/js/require.build.min.js
new file mode 100644 (file)
index 0000000..cde77c6
--- /dev/null
@@ -0,0 +1 @@
+!function(){var e;e={name:"WoltLabSuite/_Meta",out:"WoltLabSuite.Core.Conversation.min.js",useStrict:!0,preserveLicenseComments:!1,optimize:"uglify2",uglify2:{},excludeShallow:["WoltLabSuite/_Meta"],rawText:{"WoltLabSuite/_Meta":"define([], function() {});"},onBuildRead:function(e,r,t){if(!process.versions.node)throw new Error("You need to run node.js");if("WoltLabSuite/_Meta"===e){if(void 0==global.allModules){var o=module.require("fs"),r=module.require("path");global.allModules=[];for(var i,n=["WoltLabSuite"];i=n.shift();)for(var u=o.readdirSync(i),l=0;l<u.length;l++){var a=r.join(i,u[l]);"WoltLabSuite/Core/Acp"!==a&&(".js"==r.extname(a)?global.allModules.push(a):o.statSync(a).isDirectory()&&n.push(a))}}return"define(["+global.allModules.map(function(e){return"'"+e.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\.js$/,"")+"'"}).join(", ")+"], function() { });"}return t}};var r=require._isSupportedBuildUrl;return require._isSupportedBuildUrl=function(t){var o=r(t);if(!o)return o;if(-1!==Object.keys(e.rawText).map(function(e){return process.cwd()+"/"+e+".js"}).indexOf(t))return o;var i=module.require("fs");try{i.statSync(t)}catch(e){return console.log("Unable to find module:",t,"ignoring."),!1}return!0},e}();
\ No newline at end of file
index f86437a94c055eea0e33c9294791843e7b11708f..d085a85cee2abcf5da96cd8cdc048ebefa816be2 100644 (file)
@@ -3,8 +3,7 @@ namespace wcf\data\conversation;
 use wcf\data\conversation\message\ConversationMessage;
 use wcf\data\user\UserProfile;
 use wcf\data\DatabaseObject;
-use wcf\system\breadcrumb\Breadcrumb;
-use wcf\system\breadcrumb\IBreadcrumbProvider;
+use wcf\data\ITitledLinkObject;
 use wcf\system\conversation\ConversationHandler;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\exception\UserInputException;
@@ -18,23 +17,33 @@ use wcf\util\ArrayUtil;
  * Represents a conversation.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation
+ * 
+ * @property-read      integer         $conversationID
+ * @property-read      string          $subject
+ * @property-read      integer         $time
+ * @property-read      integer         $firstMessageID
+ * @property-read      integer|null    $userID
+ * @property-read      string          $username
+ * @property-read      integer         $lastPostTime
+ * @property-read      integer|null    $lastPosterID
+ * @property-read      string          $lastPoster
+ * @property-read      integer         $replies
+ * @property-read      integer         $attachments
+ * @property-read      integer         $participants
+ * @property-read      string          $participantSummary
+ * @property-read      integer         $participantCanInvite
+ * @property-read      integer         $isClosed
+ * @property-read      integer         $isDraft
+ * @property-read      string          $draftData
+ * @property-read      integer|null    $participantID
+ * @property-read      integer|null    $hideConversation
+ * @property-read      integer|null    $isInvisible
+ * @property-read      integer|null    $lastVisitTime
  */
-class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRouteController {
-       /**
-        * @see \wcf\data\DatabaseObject::$databaseTableName
-        */
-       protected static $databaseTableName = 'conversation';
-       
-       /**
-        * @see \wcf\data\DatabaseObject::$databaseIndexName
-        */
-       protected static $databaseTableIndexName = 'conversationID';
-       
+class Conversation extends DatabaseObject implements IRouteController, ITitledLinkObject {
        /**
         * default participation state
         * @var integer
@@ -55,24 +64,22 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
        
        /**
         * first message object
-        * @var \wcf\data\conversation\message\ConversationMessage
+        * @var ConversationMessage
         */
-       protected $firstMessage = null;
+       protected $firstMessage;
        
        /**
-        * @see \wcf\system\request\IRouteController::getTitle()
+        * @inheritDoc
         */
        public function getTitle() {
                return $this->subject;
        }
        
        /**
-        * @see \wcf\system\breadcrumb\IBreadcrumbProvider::getBreadcrumb()
+        * @inheritDoc
         */
-       public function getBreadcrumb() {
-               return new Breadcrumb($this->subject, LinkHandler::getInstance()->getLink('Conversation', array(
-                       'object' => $this
-               )));
+       public function getLink() {
+               return LinkHandler::getInstance()->getLink('Conversation', ['object' => $this]);
        }
        
        /**
@@ -91,7 +98,7 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
        /**
         * Returns true if the active user doesn't have read the given message.
         * 
-        * @param       \wcf\data\conversation\message\ConversationMessage      $message
+        * @param       ConversationMessage     $message
         * @return      boolean
         */
        public function isNewMessage(ConversationMessage $message) {
@@ -104,7 +111,7 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
        
        /**
         * Loads participation data for given user id (default: current user) on runtime.
-        * You should use \wcf\data\conversation\Conversation::getUserConversation() instead if possible.
+        * You should use Conversation::getUserConversation() instead if possible.
         *
         * @param       integer         $userID
         */
@@ -118,7 +125,7 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
                        WHERE   participantID = ?
                                AND conversationID = ?";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array($userID, $this->conversationID));
+               $statement->execute([$userID, $this->conversationID]);
                $row = $statement->fetchArray();
                if ($row !== false) {
                        $this->data = array_merge($this->data, $row);
@@ -130,7 +137,7 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
         * 
         * @param       integer         $conversationID
         * @param       integer         $userID
-        * @return      \wcf\data\conversation\Conversation
+        * @return      Conversation
         */
        public static function getUserConversation($conversationID, $userID) {
                $sql = "SELECT          conversation_to_user.*, conversation.*
@@ -139,7 +146,7 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
                        ON              (conversation_to_user.participantID = ? AND conversation_to_user.conversationID = conversation.conversationID)
                        WHERE           conversation.conversationID = ?";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array($userID, $conversationID));
+               $statement->execute([$userID, $conversationID]);
                $row = $statement->fetchArray();
                if ($row !== false) {
                        return new Conversation(null, $row);
@@ -151,13 +158,13 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
        /**
         * Returns a list of user conversations.
         * 
-        * @param       array<integer>          $conversationIDs
+        * @param       integer[]               $conversationIDs
         * @param       integer                 $userID
-        * @return      array<\wcf\data\conversation\Conversation>
+        * @return      Conversation[]
         */
        public static function getUserConversations(array $conversationIDs, $userID) {
                $conditionBuilder = new PreparedStatementConditionBuilder();
-               $conditionBuilder->add('conversation.conversationID IN (?)', array($conversationIDs));
+               $conditionBuilder->add('conversation.conversationID IN (?)', [$conversationIDs]);
                $sql = "SELECT          conversation_to_user.*, conversation.*
                        FROM            wcf".WCF_N."_conversation conversation
                        LEFT JOIN       wcf".WCF_N."_conversation_to_user conversation_to_user
@@ -165,11 +172,11 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
                        ".$conditionBuilder;
                $statement = WCF::getDB()->prepareStatement($sql);
                $statement->execute($conditionBuilder->getParameters());
-               $conversations = array();
+               $conversations = [];
                while ($row = $statement->fetchArray()) {
                        $conversations[$row['conversationID']] = new Conversation(null, $row);
                }
-                       
+               
                return $conversations;
        }
        
@@ -215,7 +222,7 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
        /**
         * Returns the first message in this conversation.
         * 
-        * @return      \wcf\data\conversation\message\ConversationMessage
+        * @return      ConversationMessage
         */
        public function getFirstMessage() {
                if ($this->firstMessage === null) {
@@ -228,7 +235,7 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
        /**
         * Sets the first message.
         * 
-        * @param       \wcf\data\conversation\message\ConversationMessage      $message
+        * @param       ConversationMessage     $message
         */
        public function setFirstMessage(ConversationMessage $message) {
                $this->firstMessage = $message;
@@ -238,45 +245,37 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
         * Returns a list of the ids of all participants.
         * 
         * @param       boolean         $excludeLeftParticipants
-        * @return      array<integer>
+        * @return      integer[]
         */
        public function getParticipantIDs($excludeLeftParticipants = false) {
                $conditions = new PreparedStatementConditionBuilder();
-               $conditions->add("conversationID = ?", array($this->conversationID));
-               if ($excludeLeftParticipants) $conditions->add("hideConversation <> ?", array(self::STATE_LEFT));
+               $conditions->add("conversationID = ?", [$this->conversationID]);
+               if ($excludeLeftParticipants) $conditions->add("hideConversation <> ?", [self::STATE_LEFT]);
                
                $sql = "SELECT          participantID
                        FROM            wcf".WCF_N."_conversation_to_user
                        ".$conditions;
                $statement = WCF::getDB()->prepareStatement($sql);
                $statement->execute($conditions->getParameters());
-               $participantIDs = array();
-               while ($row = $statement->fetchArray()) {
-                       $participantIDs[] = $row['participantID'];
-               }
                
-               return $participantIDs;
+               return $statement->fetchAll(\PDO::FETCH_COLUMN);
        }
        
        /**
         * Returns a list of the usernames of all participants.
         * 
-        * @return      array<string>
+        * @return      string[]
         */
        public function getParticipantNames() {
-               $participants = array();
                $sql = "SELECT          user_table.username
                        FROM            wcf".WCF_N."_conversation_to_user conversation_to_user
                        LEFT JOIN       wcf".WCF_N."_user user_table
                        ON              (user_table.userID = conversation_to_user.participantID)
                        WHERE           conversationID = ?";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array($this->conversationID));
-               while ($row = $statement->fetchArray()) {
-                       $participants[] = $row['username'];
-               }
+               $statement->execute([$this->conversationID]);
                
-               return $participants;
+               return $statement->fetchAll(\PDO::FETCH_COLUMN);
        }
        
        /**
@@ -301,7 +300,7 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
                                        WHERE   conversationID = ?
                                                AND participantID = ?";
                                $statement = WCF::getDB()->prepareStatement($sql);
-                               $statement->execute(array($this->conversationID, $this->userID));
+                               $statement->execute([$this->conversationID, $this->userID]);
                                $row = $statement->fetchArray();
                                if ($row !== false) {
                                        if ($row['hideConversation'] != self::STATE_LEFT) return true;
@@ -316,8 +315,8 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
         * Returns true if given user id (default: current user) is participant
         * of all given conversation ids.
         * 
-        * @param       array<integer>          $conversationIDs
-        * @param       integer                 $userID
+        * @param       integer[]       $conversationIDs
+        * @param       integer         $userID
         * @return      boolean
         */
        public static function isParticipant(array $conversationIDs, $userID = null) {
@@ -325,8 +324,8 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
                
                // check if user is the initial author
                $conditions = new PreparedStatementConditionBuilder();
-               $conditions->add("conversationID IN (?)", array($conversationIDs));
-               $conditions->add("userID = ?", array($userID));
+               $conditions->add("conversationID IN (?)", [$conversationIDs]);
+               $conditions->add("userID = ?", [$userID]);
                
                $sql = "SELECT  conversationID
                        FROM    wcf".WCF_N."_conversation
@@ -341,9 +340,9 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
                // check for participation
                if (!empty($conversationIDs)) {
                        $conditions = new PreparedStatementConditionBuilder();
-                       $conditions->add("conversationID IN (?)", array($conversationIDs));
-                       $conditions->add("participantID = ?", array($userID));
-                       $conditions->add("hideConversation <> ?", array(self::STATE_LEFT));
+                       $conditions->add("conversationID IN (?)", [$conversationIDs]);
+                       $conditions->add("participantID = ?", [$userID]);
+                       $conditions->add("hideConversation <> ?", [self::STATE_LEFT]);
                        
                        $sql = "SELECT  conversationID
                                FROM    wcf".WCF_N."_conversation_to_user
@@ -366,20 +365,21 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
        /**
         * Validates the participants.
         * 
-        * @param       string          $participants
+        * @param       mixed           $participants
         * @param       string          $field
-        * @param       array<integer>  $existingParticipants
+        * @param       integer[]       $existingParticipants
         * @return      array           $result
+        * @throws      UserInputException
         */
-       public static function validateParticipants($participants, $field = 'participants', array $existingParticipants = array()) {
-               $result = array();
-               $error = array();
+       public static function validateParticipants($participants, $field = 'participants', array $existingParticipants = []) {
+               $result = [];
+               $error = [];
                
                // loop through participants and check their settings
-               $participantList = UserProfile::getUserProfilesByUsername(ArrayUtil::trim(explode(',', $participants)));
+               $participantList = UserProfile::getUserProfilesByUsername((is_array($participants) ? $participants : ArrayUtil::trim(explode(',', $participants))));
                
                // load user storage at once to avoid multiple queries
-               $userIDs = array();
+               $userIDs = [];
                foreach ($participantList as $user) {
                        if ($user) {
                                $userIDs[] = $user->userID;
@@ -408,7 +408,7 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
                                $existingParticipants[] = $result[] = $user->userID;
                        }
                        catch (UserInputException $e) {
-                               $error[] = array('type' => $e->getType(), 'username' => $participant);
+                               $error[] = ['type' => $e->getType(), 'username' => $participant];
                        }
                }
                
@@ -422,8 +422,9 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
        /**
         * Validates the given participant.
         * 
-        * @param       \wcf\data\user\UserProfile      $user
-        * @param       string                          $field
+        * @param       UserProfile     $user
+        * @param       string          $field
+        * @throws      UserInputException
         */
        public static function validateParticipant(UserProfile $user, $field = 'participants') {
                // check participant's settings and permissions
@@ -433,6 +434,7 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
                
                if (!WCF::getSession()->getPermission('user.profile.cannotBeIgnored')) {
                        // check if user wants to receive any conversations
+                       /** @noinspection PhpUndefinedFieldInspection */
                        if ($user->canSendConversation == 2) {
                                throw new UserInputException($field, 'doesNotAcceptConversation');
                        }
@@ -440,6 +442,7 @@ class Conversation extends DatabaseObject implements IBreadcrumbProvider, IRoute
                        // check if user only wants to receive conversations by
                        // users they are following and if the active user is followed
                        // by the relevant user
+                       /** @noinspection PhpUndefinedFieldInspection */
                        if ($user->canSendConversation == 1 && !$user->isFollowing(WCF::getUser()->userID)) {
                                throw new UserInputException($field, 'doesNotAcceptConversation');
                        }
index 6830bb4997fed9530d6125445f2d64634c7e92aa..1ad10cecd78527aa1cd92bf1703b652bd36a9531 100644 (file)
@@ -23,32 +23,35 @@ use wcf\system\WCF;
  * Executes conversation-related actions.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation
+ * 
+ * @method     ConversationEditor[]    getObjects()
+ * @method     ConversationEditor      getSingleObject()
  */
 class ConversationAction extends AbstractDatabaseObjectAction implements IClipboardAction, IVisitableObjectAction {
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::$className
+        * @inheritDoc
         */
-       protected $className = 'wcf\data\conversation\ConversationEditor';
+       protected $className = ConversationEditor::class;
        
        /**
         * conversation object
-        * @var \wcf\data\conversation\ConversationEditor
+        * @var ConversationEditor
         */
-       protected $conversation = null;
+       protected $conversation;
        
        /**
         * list of conversation data modifications
-        * @var array<array>
+        * @var mixed[][]
         */
-       protected $conversationData = array();
+       protected $conversationData = [];
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::create()
+        * @inheritDoc
+        * @return      Conversation
         */
        public function create() {
                // create conversation
@@ -64,15 +67,15 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) {
                        $data['attachments'] = count($this->parameters['attachmentHandler']);
                }
-               $conversation = call_user_func(array($this->className, 'create'), $data);
+               $conversation = call_user_func([$this->className, 'create'], $data);
                $conversationEditor = new ConversationEditor($conversation);
                
                if (!$conversation->isDraft) {
                        // save participants
-                       $conversationEditor->updateParticipants((!empty($this->parameters['participants']) ? $this->parameters['participants'] : array()), (!empty($this->parameters['invisibleParticipants']) ? $this->parameters['invisibleParticipants'] : array()));
+                       $conversationEditor->updateParticipants((!empty($this->parameters['participants']) ? $this->parameters['participants'] : []), (!empty($this->parameters['invisibleParticipants']) ? $this->parameters['invisibleParticipants'] : []));
                        
                        // add author
-                       $conversationEditor->updateParticipants(array($data['userID']));
+                       $conversationEditor->updateParticipants([$data['userID']]);
                        
                        // update conversation count
                        UserStorageHandler::getInstance()->reset($conversation->getParticipantIDs(), 'conversationCount');
@@ -83,11 +86,11 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                                WHERE   participantID = ?
                                        AND conversationID = ?";
                        $statement = WCF::getDB()->prepareStatement($sql);
-                       $statement->execute(array($data['time'], $data['userID'], $conversation->conversationID));
+                       $statement->execute([$data['time'], $data['userID'], $conversation->conversationID]);
                }
                else {
                        // update conversation count
-                       UserStorageHandler::getInstance()->reset(array($data['userID']), 'conversationCount');
+                       UserStorageHandler::getInstance()->reset([$data['userID']], 'conversationCount');
                }
                
                // update participant summary
@@ -100,36 +103,42 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                $messageData['userID'] = $this->parameters['data']['userID'];
                $messageData['username'] = $this->parameters['data']['username'];
                
-               $messageAction = new ConversationMessageAction(array(), 'create', array(
+               $messageAction = new ConversationMessageAction([], 'create', [
                        'data' => $messageData,
                        'conversation' => $conversation,
                        'isFirstPost' => true,
-                       'attachmentHandler' => (isset($this->parameters['attachmentHandler']) ? $this->parameters['attachmentHandler'] : null) 
-               ));
+                       'attachmentHandler' => isset($this->parameters['attachmentHandler']) ? $this->parameters['attachmentHandler'] : null,
+                       'htmlInputProcessor' => isset($this->parameters['htmlInputProcessor']) ? $this->parameters['htmlInputProcessor'] : null
+               ]);
                $resultValues = $messageAction->executeAction();
                
                // update first message id
-               $conversationEditor->update(array(
+               $conversationEditor->update([
                        'firstMessageID' => $resultValues['returnValues']->messageID
-               ));
+               ]);
                
                $conversation->setFirstMessage($resultValues['returnValues']);
                if (!$conversation->isDraft) {
                        // fire notification event
-                       $notificationRecipients = array_merge((!empty($this->parameters['participants']) ? $this->parameters['participants'] : array()), (!empty($this->parameters['invisibleParticipants']) ? $this->parameters['invisibleParticipants'] : array()));
-                       UserNotificationHandler::getInstance()->fireEvent('conversation', 'com.woltlab.wcf.conversation.notification', new ConversationUserNotificationObject($conversation), $notificationRecipients);
+                       $notificationRecipients = array_merge((!empty($this->parameters['participants']) ? $this->parameters['participants'] : []), (!empty($this->parameters['invisibleParticipants']) ? $this->parameters['invisibleParticipants'] : []));
+                       UserNotificationHandler::getInstance()->fireEvent(
+                               'conversation',
+                               'com.woltlab.wcf.conversation.notification',
+                               new ConversationUserNotificationObject($conversation),
+                               $notificationRecipients
+                       );
                }
                
                return $conversation;
        }
        
        /**
-        * @see \wcf\data\IDeleteAction::delete()
+        * @inheritDoc
         */
        public function delete() {
                // deletes messages
                $messageList = new ConversationMessageList();
-               $messageList->getConditionBuilder()->add('conversation_message.conversationID IN (?)', array($this->objectIDs));
+               $messageList->getConditionBuilder()->add('conversation_message.conversationID IN (?)', [$this->objectIDs]);
                $messageList->readObjectIDs();
                $action = new ConversationMessageAction($messageList->getObjectIDs(), 'delete');
                $action->executeAction();
@@ -139,19 +148,19 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                
                if (!empty($this->objectIDs)) {
                        // delete notifications
-                       UserNotificationHandler::getInstance()->deleteNotifications('conversation', 'com.woltlab.wcf.conversation.notification', array(), $this->objectIDs);
+                       UserNotificationHandler::getInstance()->removeNotifications('com.woltlab.wcf.conversation.notification', $this->objectIDs);
                        
                        // remove modification logs
-                       ConversationModificationLogHandler::getInstance()->remove($this->objectIDs);
+                       ConversationModificationLogHandler::getInstance()->deleteLogs($this->objectIDs);
                }
        }
        
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::update()
+        * @inheritDoc
         */
        public function update() {
-               if (!isset($this->parameters['participants'])) $this->parameters['participants'] = array();
-               if (!isset($this->parameters['invisibleParticipants'])) $this->parameters['invisibleParticipants'] = array();
+               if (!isset($this->parameters['participants'])) $this->parameters['participants'] = [];
+               if (!isset($this->parameters['invisibleParticipants'])) $this->parameters['invisibleParticipants'] = [];
                
                // count participants
                if (!empty($this->parameters['participants'])) {
@@ -160,13 +169,13 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                
                parent::update();
                
-               foreach ($this->objects as $conversation) {
-                       // partipants
+               foreach ($this->getObjects() as $conversation) {
+                       // participants
                        if (!empty($this->parameters['participants']) || !empty($this->parameters['invisibleParticipants'])) {
                                // get current participants
                                $participantIDs = $conversation->getParticipantIDs();
                                
-                               $conversation->updateParticipants((!empty($this->parameters['participants']) ? $this->parameters['participants'] : array()), (!empty($this->parameters['invisibleParticipants']) ? $this->parameters['invisibleParticipants'] : array()));
+                               $conversation->updateParticipants((!empty($this->parameters['participants']) ? $this->parameters['participants'] : []), (!empty($this->parameters['invisibleParticipants']) ? $this->parameters['invisibleParticipants'] : []));
                                $conversation->updateParticipantSummary();
                                
                                // check if new participants have been added
@@ -177,7 +186,12 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                                        UserStorageHandler::getInstance()->reset($newParticipantIDs, 'conversationCount');
                                        
                                        // fire notification event
-                                       UserNotificationHandler::getInstance()->fireEvent('conversation', 'com.woltlab.wcf.conversation.notification', new ConversationUserNotificationObject($conversation->getDecoratedObject()), $newParticipantIDs);
+                                       UserNotificationHandler::getInstance()->fireEvent(
+                                               'conversation',
+                                               'com.woltlab.wcf.conversation.notification',
+                                               new ConversationUserNotificationObject($conversation->getDecoratedObject()),
+                                               $newParticipantIDs
+                                       );
                                }
                        }
                        
@@ -185,7 +199,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                        if (isset($this->parameters['data']['isDraft'])) {
                                if ($conversation->isDraft && !$this->parameters['data']['isDraft']) {
                                        // add author
-                                       $conversation->updateParticipants(array($conversation->userID));
+                                       $conversation->updateParticipants([$conversation->userID]);
                                        
                                        // update conversation count
                                        UserStorageHandler::getInstance()->reset($conversation->getParticipantIDs(), 'unreadConversationCount');
@@ -196,7 +210,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
        }
        
        /**
-        * @see \wcf\data\IVisitableObjectAction::markAsRead()
+        * @inheritDoc
         */
        public function markAsRead() {
                if (empty($this->parameters['visitTime'])) {
@@ -207,35 +221,35 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                        $this->readObjects();
                }
                
-               $conversationIDs = array();
+               $conversationIDs = [];
                $sql = "UPDATE  wcf".WCF_N."_conversation_to_user
                        SET     lastVisitTime = ?
                        WHERE   participantID = ?
                                AND conversationID = ?";
                $statement = WCF::getDB()->prepareStatement($sql);
                WCF::getDB()->beginTransaction();
-               foreach ($this->objects as $conversation) {
-                       $statement->execute(array(
+               foreach ($this->getObjects() as $conversation) {
+                       $statement->execute([
                                $this->parameters['visitTime'],
                                WCF::getUser()->userID,
                                $conversation->conversationID
-                       ));
+                       ]);
                        $conversationIDs[] = $conversation->conversationID;
                }
                WCF::getDB()->commitTransaction();
                
                // reset storage
-               UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'unreadConversationCount');
+               UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadConversationCount');
                
                // mark notifications as confirmed
                if (!empty($conversationIDs)) {
                        // conversation start notification
                        $conditionBuilder = new PreparedStatementConditionBuilder();
-                       $conditionBuilder->add('notification.eventID = ?', array(UserNotificationHandler::getInstance()->getEvent('com.woltlab.wcf.conversation.notification', 'conversation')->eventID));
+                       $conditionBuilder->add('notification.eventID = ?', [UserNotificationHandler::getInstance()->getEvent('com.woltlab.wcf.conversation.notification', 'conversation')->eventID]);
                        $conditionBuilder->add('notification.objectID = conversation.conversationID');
-                       $conditionBuilder->add('notification.userID = ?', array(WCF::getUser()->userID));
-                       $conditionBuilder->add('conversation.conversationID IN (?)', array($conversationIDs));
-                       $conditionBuilder->add('conversation.time <= ?', array($this->parameters['visitTime']));
+                       $conditionBuilder->add('notification.userID = ?', [WCF::getUser()->userID]);
+                       $conditionBuilder->add('conversation.conversationID IN (?)', [$conversationIDs]);
+                       $conditionBuilder->add('conversation.time <= ?', [$this->parameters['visitTime']]);
                        
                        $sql = "SELECT          conversation.conversationID
                                FROM            wcf".WCF_N."_conversation conversation,
@@ -243,22 +257,19 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                                ".$conditionBuilder;
                        $statement = WCF::getDB()->prepareStatement($sql);
                        $statement->execute($conditionBuilder->getParameters());
-                       $notificationObjectIDs = array();
-                       while ($row = $statement->fetchArray()) {
-                               $notificationObjectIDs[] = $row['conversationID'];
-                       }
+                       $notificationObjectIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
                        
                        if (!empty($notificationObjectIDs)) {
-                               UserNotificationHandler::getInstance()->markAsConfirmed('conversation', 'com.woltlab.wcf.conversation.notification', array(WCF::getUser()->userID), $notificationObjectIDs);
+                               UserNotificationHandler::getInstance()->markAsConfirmed('conversation', 'com.woltlab.wcf.conversation.notification', [WCF::getUser()->userID], $notificationObjectIDs);
                        }
                        
                        // conversation reply notification
                        $conditionBuilder = new PreparedStatementConditionBuilder();
-                       $conditionBuilder->add('notification.eventID = ?', array(UserNotificationHandler::getInstance()->getEvent('com.woltlab.wcf.conversation.message.notification', 'conversationMessage')->eventID));
+                       $conditionBuilder->add('notification.eventID = ?', [UserNotificationHandler::getInstance()->getEvent('com.woltlab.wcf.conversation.message.notification', 'conversationMessage')->eventID]);
                        $conditionBuilder->add('notification.objectID = conversation_message.messageID');
-                       $conditionBuilder->add('notification.userID = ?', array(WCF::getUser()->userID));
-                       $conditionBuilder->add('conversation_message.conversationID IN (?)', array($conversationIDs));
-                       $conditionBuilder->add('conversation_message.time <= ?', array($this->parameters['visitTime']));
+                       $conditionBuilder->add('notification.userID = ?', [WCF::getUser()->userID]);
+                       $conditionBuilder->add('conversation_message.conversationID IN (?)', [$conversationIDs]);
+                       $conditionBuilder->add('conversation_message.time <= ?', [$this->parameters['visitTime']]);
                        
                        $sql = "SELECT          conversation_message.messageID
                                FROM            wcf".WCF_N."_conversation_message conversation_message,
@@ -266,13 +277,10 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                                ".$conditionBuilder;
                        $statement = WCF::getDB()->prepareStatement($sql);
                        $statement->execute($conditionBuilder->getParameters());
-                       $notificationObjectIDs = array();
-                       while ($row = $statement->fetchArray()) {
-                               $notificationObjectIDs[] = $row['messageID'];
-                       }
+                       $notificationObjectIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
                        
                        if (!empty($notificationObjectIDs)) {
-                               UserNotificationHandler::getInstance()->markAsConfirmed('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', array(WCF::getUser()->userID), $notificationObjectIDs);
+                               UserNotificationHandler::getInstance()->markAsConfirmed('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', [WCF::getUser()->userID], $notificationObjectIDs);
                        }
                }
                
@@ -280,9 +288,9 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                        $this->unmarkItems($conversationIDs);
                }
                
-               $returnValues = array(
+               $returnValues = [
                        'totalCount' => ConversationHandler::getInstance()->getUnreadConversationCount(null, true)
-               );
+               ];
                
                if (count($conversationIDs) == 1) {
                        $returnValues['markAsRead'] = reset($conversationIDs);
@@ -292,7 +300,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
        }
        
        /**
-        * @see \wcf\data\IVisitableObjectAction::validateMarkAsRead()
+        * @inheritDoc
         */
        public function validateMarkAsRead() {
                // visitTime might not be in the future
@@ -308,8 +316,8 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                }
                
                // check participation
-               $conversationIDs = array();
-               foreach ($this->objects as $conversation) {
+               $conversationIDs = [];
+               foreach ($this->getObjects() as $conversation) {
                        $conversationIDs[] = $conversation->conversationID;
                }
                
@@ -330,32 +338,34 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                        SET     lastVisitTime = ?
                        WHERE   participantID = ?";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array(
+               $statement->execute([
                        TIME_NOW,
                        WCF::getUser()->userID
-               ));
+               ]);
                
                // reset storage
-               UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'unreadConversationCount');
+               UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadConversationCount');
                
-               // delete obsolete notifications
-               UserNotificationHandler::getInstance()->deleteNotifications('conversation', 'com.woltlab.wcf.conversation.notification', array(WCF::getUser()->userID));
-               UserNotificationHandler::getInstance()->deleteNotifications('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', array(WCF::getUser()->userID));
+               // confirm obsolete notifications
+               UserNotificationHandler::getInstance()->markAsConfirmed('conversation', 'com.woltlab.wcf.conversation.notification', [WCF::getUser()->userID]);
+               UserNotificationHandler::getInstance()->markAsConfirmed('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', [WCF::getUser()->userID]);
                
-               return array(
+               return [
                        'markAllAsRead' => true
-               );
+               ];
        }
        
        /**
         * Validates the markAllAsRead action.
         */
-       public function validateMarkAllAsRead() {}
+       public function validateMarkAllAsRead() {
+               // does nothing
+       }
        
        /**
         * Validates user access for label management.
         */
-       public function validateGetLabelmanagement() {
+       public function validateGetLabelManagement() {
                if (!WCF::getSession()->getPermission('user.conversation.canUseConversation')) {
                        throw new PermissionDeniedException();
                }
@@ -367,17 +377,17 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
         * @return      array
         */
        public function getLabelManagement() {
-               WCF::getTPL()->assign(array(
+               WCF::getTPL()->assign([
                        'cssClassNames' => ConversationLabel::getLabelCssClassNames(),
                        'labelList' => ConversationLabel::getLabelsByUser()
-               ));
+               ]);
                
-               return array(
+               return [
                        'actionName' => 'getLabelManagement',
                        'template' => WCF::getTPL()->fetch('conversationLabelManagement'),
                        'maxLabels' => WCF::getSession()->getPermission('user.conversation.maxLabels'),
                        'labelCount' => count(ConversationLabel::getLabelsByUser())
-               );
+               ];
        }
        
        /**
@@ -385,7 +395,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
         */
        public function validateGetMessagePreview() {
                $this->conversation = $this->getSingleObject();
-               if (!Conversation::isParticipant(array($this->conversation->conversationID))) {
+               if (!Conversation::isParticipant([$this->conversation->conversationID])) {
                        throw new PermissionDeniedException();
                }
        }
@@ -393,21 +403,21 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
        /**
         * Returns a preview of a message in a specific conversation.
         * 
-        * @return      array
+        * @return      string[]
         */
        public function getMessagePreview() {
                $messageList = new SimplifiedViewableConversationMessageList();
                
-               $messageList->getConditionBuilder()->add("conversation_message.messageID = ?", array($this->conversation->firstMessageID));
+               $messageList->getConditionBuilder()->add("conversation_message.messageID = ?", [$this->conversation->firstMessageID]);
                $messageList->readObjects();
                $messages = $messageList->getObjects();
                
-               WCF::getTPL()->assign(array(
+               WCF::getTPL()->assign([
                        'message' => reset($messages)
-               ));
-               return array(
+               ]);
+               return [
                        'template' => WCF::getTPL()->fetch('conversationMessagePreview')
-               );
+               ];
        }
        
        /**
@@ -424,7 +434,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                }
                
                // validate ownership
-               foreach ($this->objects as $conversation) {
+               foreach ($this->getObjects() as $conversation) {
                        if ($conversation->isClosed || ($conversation->userID != WCF::getUser()->userID)) {
                                throw new PermissionDeniedException();
                        }
@@ -434,11 +444,11 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
        /**
         * Closes conversations.
         * 
-        * @return      array<array>
+        * @return      mixed[][]
         */
        public function close() {
-               foreach ($this->objects as $conversation) {
-                       $conversation->update(array('isClosed' => 1));
+               foreach ($this->getObjects() as $conversation) {
+                       $conversation->update(['isClosed' => 1]);
                        $this->addConversationData($conversation->getDecoratedObject(), 'isClosed', 1);
                        
                        ConversationModificationLogHandler::getInstance()->close($conversation->getDecoratedObject());
@@ -463,7 +473,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                }
                
                // validate ownership
-               foreach ($this->objects as $conversation) {
+               foreach ($this->getObjects() as $conversation) {
                        if (!$conversation->isClosed || ($conversation->userID != WCF::getUser()->userID)) {
                                throw new PermissionDeniedException();
                        }
@@ -473,11 +483,11 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
        /**
         * Opens conversations.
         * 
-        * @return      array<array>
+        * @return      mixed[][]
         */
        public function open() {
-               foreach ($this->objects as $conversation) {
-                       $conversation->update(array('isClosed' => 0));
+               foreach ($this->getObjects() as $conversation) {
+                       $conversation->update(['isClosed' => 0]);
                        $this->addConversationData($conversation->getDecoratedObject(), 'isClosed', 0);
                        
                        ConversationModificationLogHandler::getInstance()->open($conversation->getDecoratedObject());
@@ -514,26 +524,26 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                        WHERE   conversationID = ?
                                AND participantID = ?";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array(
+               $statement->execute([
                        current($this->objectIDs),
                        WCF::getUser()->userID
-               ));
+               ]);
                $row = $statement->fetchArray();
                
                WCF::getTPL()->assign('hideConversation', $row['hideConversation']);
                
-               return array(
+               return [
                        'actionName' => 'getLeaveForm',
                        'template' => WCF::getTPL()->fetch('conversationLeave')
-               );
+               ];
        }
        
        /**
         * Validates parameters to hide conversations.
         */
        public function validateHideConversation() {
-               $this->parameters['hideConversation'] = (isset($this->parameters['hideConversation'])) ? intval($this->parameters['hideConversation']) : null;
-               if ($this->parameters['hideConversation'] === null || !in_array($this->parameters['hideConversation'], array(Conversation::STATE_DEFAULT, Conversation::STATE_HIDDEN, Conversation::STATE_LEFT))) {
+               $this->parameters['hideConversation'] = isset($this->parameters['hideConversation']) ? intval($this->parameters['hideConversation']) : null;
+               if ($this->parameters['hideConversation'] === null || !in_array($this->parameters['hideConversation'], [Conversation::STATE_DEFAULT, Conversation::STATE_HIDDEN, Conversation::STATE_LEFT])) {
                        throw new UserInputException('hideConversation');
                }
                
@@ -550,7 +560,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
        /**
         * Hides or restores conversations.
         * 
-        * @return      array
+        * @return      string[]
         */
        public function hideConversation() {
                $sql = "UPDATE  wcf".WCF_N."_conversation_to_user
@@ -561,26 +571,26 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                
                WCF::getDB()->beginTransaction();
                foreach ($this->objectIDs as $conversationID) {
-                       $statement->execute(array(
+                       $statement->execute([
                                $this->parameters['hideConversation'],
                                $conversationID,
                                WCF::getUser()->userID
-                       ));
+                       ]);
                }
                WCF::getDB()->commitTransaction();
                
                // reset user's conversation counters if user leaves conversation
                // permanently
                if ($this->parameters['hideConversation'] == Conversation::STATE_LEFT) {
-                       UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'conversationCount');
-                       UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'unreadConversationCount');
+                       UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'conversationCount');
+                       UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadConversationCount');
                }
                
                // add modification log entry
                if ($this->parameters['hideConversation'] == Conversation::STATE_LEFT) {
                        if (empty($this->objects)) $this->readObjects();
                        
-                       foreach ($this->objects as $conversation) {
+                       foreach ($this->getObjects() as $conversation) {
                                ConversationModificationLogHandler::getInstance()->leave($conversation->getDecoratedObject());
                        }
                }
@@ -595,9 +605,8 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                        
                        // delete conversation if all users have left it
                        $conditionBuilder = new PreparedStatementConditionBuilder();
-                       $conditionBuilder->add('conversation.conversationID IN (?)', array($this->objectIDs));
+                       $conditionBuilder->add('conversation.conversationID IN (?)', [$this->objectIDs]);
                        $conditionBuilder->add('conversation_to_user.conversationID IS NULL');
-                       $conversationIDs = array();
                        $sql = "SELECT          DISTINCT conversation.conversationID
                                FROM            wcf".WCF_N."_conversation conversation
                                LEFT JOIN       wcf".WCF_N."_conversation_to_user conversation_to_user
@@ -607,19 +616,18 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                                ".$conditionBuilder;
                        $statement = WCF::getDB()->prepareStatement($sql);
                        $statement->execute($conditionBuilder->getParameters());
-                       while ($row = $statement->fetchArray()) {
-                               $conversationIDs[] = $row['conversationID'];
-                       }
+                       $conversationIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
+                       
                        if (!empty($conversationIDs)) {
                                $action = new ConversationAction($conversationIDs, 'delete');
                                $action->executeAction();
                        }
                }
                
-               return array(
+               return [
                        'actionName' => 'hideConversation',
                        'redirectURL' => LinkHandler::getInstance()->getLink('ConversationList')
-               );
+               ];
        }
        
        /**
@@ -630,28 +638,33 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
        }
        
        /**
-        * Returns a mixed conversation list with up to 5 unread conversations.
+        * Returns a mixed conversation list with up to 10 unread conversations.
         * 
-        * @return      array<mixed>
+        * @return      mixed[][]
         */
        public function getMixedConversationList() {
+               $sqlSelect = '  , (SELECT participantID FROM wcf'.WCF_N.'_conversation_to_user WHERE conversationID = conversation.conversationID AND participantID <> conversation.userID AND isInvisible = 0 ORDER BY username, participantID LIMIT 1) AS otherParticipantID
+                               , (SELECT username FROM wcf'.WCF_N.'_conversation_to_user WHERE conversationID = conversation.conversationID AND participantID <> conversation.userID AND isInvisible = 0 ORDER BY username, participantID LIMIT 1) AS otherParticipant';
+               
                $unreadConversationList = new UserConversationList(WCF::getUser()->userID);
+               $unreadConversationList->sqlSelects .= $sqlSelect;
                $unreadConversationList->getConditionBuilder()->add('conversation_to_user.lastVisitTime < conversation.lastPostTime');
-               $unreadConversationList->sqlLimit = 5;
+               $unreadConversationList->sqlLimit = 10;
                $unreadConversationList->sqlOrderBy = 'conversation.lastPostTime DESC';
                $unreadConversationList->readObjects();
                
-               $conversations = array();
+               $conversations = [];
                $count = 0;
                foreach ($unreadConversationList as $conversation) {
                        $conversations[] = $conversation;
                        $count++;
                }
                
-               if ($count < 5) {
+               if ($count < 10) {
                        $conversationList = new UserConversationList(WCF::getUser()->userID);
+                       $conversationList->sqlSelects .= $sqlSelect;
                        $conversationList->getConditionBuilder()->add('conversation_to_user.lastVisitTime >= conversation.lastPostTime');
-                       $conversationList->sqlLimit = (5 - $count);
+                       $conversationList->sqlLimit = (10 - $count);
                        $conversationList->sqlOrderBy = 'conversation.lastPostTime DESC';
                        $conversationList->readObjects();
                        
@@ -660,19 +673,19 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                        }
                }
                
-               WCF::getTPL()->assign(array(
+               WCF::getTPL()->assign([
                        'conversations' => $conversations
-               ));
+               ]);
                
                $totalCount = ConversationHandler::getInstance()->getUnreadConversationCount();
-               if ($count < 5 && $count < $totalCount) {
-                       UserStorageHandler::getInstance()->reset(array(WCF::getUser()->userID), 'unreadConversationCount');
+               if ($count < 10 && $count < $totalCount) {
+                       UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadConversationCount');
                }
                
-               return array(
+               return [
                        'template' => WCF::getTPL()->fetch('conversationListUserPanel'),
                        'totalCount' => $totalCount
-               );
+               ];
        }
        
        /**
@@ -694,7 +707,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
         */
        public function validateGetAddParticipantsForm() {
                $this->conversation = $this->getSingleObject();
-               if (!Conversation::isParticipant(array($this->conversation->conversationID)) || !$this->conversation->canAddParticipants()) {
+               if (!Conversation::isParticipant([$this->conversation->conversationID]) || !$this->conversation->canAddParticipants()) {
                        throw new PermissionDeniedException();
                }
        }
@@ -705,11 +718,11 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
         * @return      array
         */
        public function getAddParticipantsForm() {
-               return array(
-                       'actionName' => 'getAddParticipantsForm',
-                       'excludeSearchValues' => $this->conversation->getParticipantNames(),
+               return [
+                       'excludedSearchValues' => $this->conversation->getParticipantNames(),
+                       'maxItems' => WCF::getSession()->getPermission('user.conversation.maxParticipants') - $this->conversation->participants,
                        'template' => WCF::getTPL()->fetch('conversationAddParticipants')
-               );
+               ];
        }
        
        /**
@@ -719,7 +732,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                $this->validateGetAddParticipantsForm();
                
                // validate participants
-               $this->readString('participants');
+               $this->readStringArray('participants');
        }
        
        /**
@@ -735,43 +748,42 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                        $errorMessage = '';
                        foreach ($e->getType() as $type) {
                                if (!empty($errorMessage)) $errorMessage .= ' ';
-                               $errorMessage .= WCF::getLanguage()->getDynamicVariable('wcf.conversation.participants.error.'.$type['type'], array('errorData' => array('username' => $type['username'])));
+                               $errorMessage .= WCF::getLanguage()->getDynamicVariable('wcf.conversation.participants.error.'.$type['type'], ['errorData' => ['username' => $type['username']]]);
                        }
                        
-                       return array(
+                       return [
                                'actionName' => 'addParticipants',
                                'errorMessage' => $errorMessage
-                       );
+                       ];
                }
                
                // validate limit
                $newCount = $this->conversation->participants + count($participantIDs);
                if ($newCount > WCF::getSession()->getPermission('user.conversation.maxParticipants')) {
-                       return array(
+                       return [
                                'actionName' => 'addParticipants',
                                'errorMessage' => WCF::getLanguage()->getDynamicVariable('wcf.conversation.participants.error.tooManyParticipants')
-                       );
+                       ];
                }
                
                $count = 0;
                $successMessage = '';
                if (!empty($participantIDs)) {
                        // check for already added participants
-                       $data = array();
                        if ($this->conversation->isDraft) {
                                $draftData = unserialize($this->conversation->draftData);
                                $draftData['participants'] = array_merge($draftData['participants'], $participantIDs);
-                               $data = array('data' => array('draftData' => serialize($draftData)));
+                               $data = ['data' => ['draftData' => serialize($draftData)]];
                        }
                        else {
-                               $data = array('participants' => $participantIDs);
+                               $data = ['participants' => $participantIDs];
                        }
                        
-                       $conversationAction = new ConversationAction(array($this->conversation), 'update', $data);
+                       $conversationAction = new ConversationAction([$this->conversation], 'update', $data);
                        $conversationAction->executeAction();
                        
                        $count = count($participantIDs);
-                       $successMessage = WCF::getLanguage()->getDynamicVariable('wcf.conversation.edit.addParticipants.success', array('count' => $count));
+                       $successMessage = WCF::getLanguage()->getDynamicVariable('wcf.conversation.edit.addParticipants.success', ['count' => $count]);
                        
                        ConversationModificationLogHandler::getInstance()->addParticipants($this->conversation->getDecoratedObject(), $participantIDs);
                        
@@ -781,11 +793,10 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                        }
                }
                
-               return array(
-                       'actionName' => 'addParticipants',
+               return [
                        'count' => $count,
                        'successMessage' => $successMessage
-               );
+               ];
        }
        
        /**
@@ -806,7 +817,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                }
                
                // validate participants
-               if ($this->parameters['userID'] == WCF::getUser()->userID || !Conversation::isParticipant(array($this->conversation->conversationID)) || !Conversation::isParticipant(array($this->conversation->conversationID), $this->parameters['userID'])) {
+               if ($this->parameters['userID'] == WCF::getUser()->userID || !Conversation::isParticipant([$this->conversation->conversationID]) || !Conversation::isParticipant([$this->conversation->conversationID], $this->parameters['userID'])) {
                        throw new PermissionDeniedException();
                }
                
@@ -822,11 +833,11 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                ConversationModificationLogHandler::getInstance()->removeParticipant($this->conversation->getDecoratedObject(), $this->parameters['userID']);
                
                // reset storage
-               UserStorageHandler::getInstance()->reset(array($this->parameters['userID']), 'unreadConversationCount');
+               UserStorageHandler::getInstance()->reset([$this->parameters['userID']], 'unreadConversationCount');
                
-               return array(
+               return [
                        'userID' => $this->parameters['userID']
-               );
+               ];
        }
        
        /**
@@ -839,7 +850,7 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                
                // collect number of messages for each conversation
                $conditionBuilder = new PreparedStatementConditionBuilder();
-               $conditionBuilder->add('conversation_message.conversationID IN (?)', array($this->objectIDs));
+               $conditionBuilder->add('conversation_message.conversationID IN (?)', [$this->objectIDs]);
                $sql = "SELECT          conversationID, COUNT(messageID) AS messages, SUM(attachments) AS attachments
                        FROM            wcf".WCF_N."_conversation_message conversation_message
                        ".$conditionBuilder."
@@ -847,20 +858,20 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
                $statement = WCF::getDB()->prepareStatement($sql);
                $statement->execute($conditionBuilder->getParameters());
                
-               $objectIDs = array();
+               $objectIDs = [];
                while ($row = $statement->fetchArray()) {
                        if (!$row['messages']) {
                                continue;
                        }
                        $objectIDs[] = $row['conversationID'];
                        
-                       $conversationEditor = new ConversationEditor(new Conversation(null, array(
+                       $conversationEditor = new ConversationEditor(new Conversation(null, [
                                'conversationID' => $row['conversationID']
-                       )));
-                       $conversationEditor->update(array(
+                       ]));
+                       $conversationEditor->update([
                                'attachments' => $row['attachments'],
                                'replies' => $row['messages'] - 1
-                       ));
+                       ]);
                        $conversationEditor->updateFirstMessage();
                        $conversationEditor->updateLastMessage();
                }
@@ -876,13 +887,13 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
        /**
         * Adds conversation modification data.
         * 
-        * @param       \wcf\data\conversation\Conversation     $conversation
-        * @param       string                                  $key
-        * @param       mixed                                   $value
+        * @param       Conversation    $conversation
+        * @param       string          $key
+        * @param       mixed           $value
         */
        protected function addConversationData(Conversation $conversation, $key, $value) {
                if (!isset($this->conversationData[$conversation->conversationID])) {
-                       $this->conversationData[$conversation->conversationID] = array();
+                       $this->conversationData[$conversation->conversationID] = [];
                }
                
                $this->conversationData[$conversation->conversationID][$key] = $value;
@@ -891,20 +902,20 @@ class ConversationAction extends AbstractDatabaseObjectAction implements IClipbo
        /**
         * Returns conversation data.
         * 
-        * @return      array<array>
+        * @return      mixed[][]
         */
        protected function getConversationData() {
-               return array(
+               return [
                        'conversationData' => $this->conversationData
-               );
+               ];
        }
        
        /**
         * Unmarks conversations.
         * 
-        * @param       array<integer>          $conversationIDs
+        * @param       integer[]               $conversationIDs
         */
-       protected function unmarkItems(array $conversationIDs = array()) {
+       protected function unmarkItems(array $conversationIDs = []) {
                if (empty($conversationIDs)) {
                        $conversationIDs = $this->objectIDs;
                }
index 34c6244413b9daa27cd383592f0ffaf6d7352416..90ec00ba96176f6a4c1ef11e28cb57dbd67f06be 100644 (file)
@@ -9,33 +9,33 @@ use wcf\system\WCF;
  * Extends the conversation object with functions to create, update and delete conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation
+ * 
+ * @method static      Conversation    create(array $parameters = [])
+ * @method             Conversation    getDecoratedObject()
+ * @mixin              Conversation
  */
 class ConversationEditor extends DatabaseObjectEditor {
        /**
-        * @see \wcf\data\DatabaseObjectEditor::$baseClass
+        * @inheritDoc
         */
-       protected static $baseClass = 'wcf\data\conversation\Conversation';
+       protected static $baseClass = Conversation::class;
        
        /**
         * Adds a new message to this conversation.
         * 
-        * @param       \wcf\data\conversation\message\ConversationMessage      $message
+        * @param       ConversationMessage     $message
         */
        public function addMessage(ConversationMessage $message) {
-               $data = array(
+               $this->update([
                        'lastPoster' => $message->username,
                        'lastPostTime' => $message->time,
                        'lastPosterID' => $message->userID,
                        'replies' => $this->replies + 1,
                        'attachments' => $this->attachments + $message->attachments
-               );
-               
-               $this->update($data);
+               ]);
        }
        
        /**
@@ -46,20 +46,20 @@ class ConversationEditor extends DatabaseObjectEditor {
                        WHERE           conversationID = ?
                                        AND participantID <> ?";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array($this->conversationID, $this->userID));
+               $statement->execute([$this->conversationID, $this->userID]);
        }
        
        /**
         * Updates the participants of this conversation.
         * 
-        * @param       array<integer>  $participantIDs
-        * @param       array<integer>  $invisibleParticipantIDs
+        * @param       integer[]       $participantIDs
+        * @param       integer[]       $invisibleParticipantIDs
         */
-       public function updateParticipants(array $participantIDs, array $invisibleParticipantIDs = array()) {
-               $usernames = array();
+       public function updateParticipants(array $participantIDs, array $invisibleParticipantIDs = []) {
+               $usernames = [];
                if (!empty($participantIDs) || !empty($invisibleParticipantIDs)) {
                        $conditions = new PreparedStatementConditionBuilder();
-                       $conditions->add("userID IN (?)", array(array_merge($participantIDs, $invisibleParticipantIDs)));
+                       $conditions->add("userID IN (?)", [array_merge($participantIDs, $invisibleParticipantIDs)]);
                        
                        $sql = "SELECT  userID, username
                                FROM    wcf".WCF_N."_user
@@ -81,12 +81,12 @@ class ConversationEditor extends DatabaseObjectEditor {
                        $statement = WCF::getDB()->prepareStatement($sql);
                        
                        foreach ($participantIDs as $userID) {
-                               $statement->execute(array(
+                               $statement->execute([
                                        $this->conversationID,
                                        $userID,
                                        $usernames[$userID],
                                        0
-                               ));
+                               ]);
                        }
                        WCF::getDB()->commitTransaction();
                }
@@ -99,12 +99,12 @@ class ConversationEditor extends DatabaseObjectEditor {
                        $statement = WCF::getDB()->prepareStatement($sql);
                        
                        foreach ($invisibleParticipantIDs as $userID) {
-                               $statement->execute(array(
+                               $statement->execute([
                                        $this->conversationID,
                                        $userID,
                                        $usernames[$userID],
                                        1
-                               ));
+                               ]);
                        }
                        WCF::getDB()->commitTransaction();
                }
@@ -127,19 +127,18 @@ class ConversationEditor extends DatabaseObjectEditor {
                                )
                        WHERE   conversation.conversationID = ?";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array(
+               $statement->execute([
                        Conversation::STATE_LEFT,
                        $this->userID,
                        0,
                        $this->conversationID
-               ));
+               ]);
        }
        
        /**
         * Updates the participant summary of this conversation.
         */
        public function updateParticipantSummary() {
-               $users = array();
                $sql = "SELECT          participantID AS userID, hideConversation, username
                        FROM            wcf".WCF_N."_conversation_to_user
                        WHERE           conversationID = ?
@@ -147,14 +146,9 @@ class ConversationEditor extends DatabaseObjectEditor {
                                        AND isInvisible = 0
                        ORDER BY        username";
                $statement = WCF::getDB()->prepareStatement($sql, 5);
-               $statement->execute(array($this->conversationID, $this->userID));
-               while ($row = $statement->fetchArray()) {
-                       $users[] = $row;
-               }
+               $statement->execute([$this->conversationID, $this->userID]);
                
-               $this->update(array(
-                       'participantSummary' => serialize($users)
-               ));
+               $this->update(['participantSummary' => serialize($statement->fetchAll(\PDO::FETCH_ASSOC))]);
        }
        
        /**
@@ -168,17 +162,17 @@ class ConversationEditor extends DatabaseObjectEditor {
                        WHERE   conversationID = ?
                                AND participantID = ?";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array(
+               $statement->execute([
                        2,
                        $this->conversationID,
                        $userID
-               ));
+               ]);
                
                // decrease participant count unless it is the author
                if ($userID != $this->userID) {
-                       $this->updateCounters(array(
+                       $this->updateCounters([
                                'participants' => -1
-                       ));
+                       ]);
                }
        }
        
@@ -191,13 +185,13 @@ class ConversationEditor extends DatabaseObjectEditor {
                        WHERE           conversationID = ?
                        ORDER BY        time ASC";
                $statement = WCF::getDB()->prepareStatement($sql, 1);
-               $statement->execute(array(
+               $statement->execute([
                        $this->conversationID
-               ));
+               ]);
                
-               $this->update(array(
+               $this->update([
                        'firstMessageID' => $statement->fetchColumn()
-               ));
+               ]);
        }
        
        /**
@@ -209,26 +203,26 @@ class ConversationEditor extends DatabaseObjectEditor {
                        WHERE           conversationID = ?
                        ORDER BY        time DESC";
                $statement = WCF::getDB()->prepareStatement($sql, 1);
-               $statement->execute(array(
+               $statement->execute([
                        $this->conversationID
-               ));
+               ]);
                $row = $statement->fetchArray();
                
-               $this->update(array(
+               $this->update([
                        'lastPostTime' => $row['time'],
                        'lastPosterID' => $row['userID'],
                        'lastPoster' => $row['username']
-               ));
+               ]);
        }
        
        /**
         * Updates the participant summary of the given conversations.
         * 
-        * @param       array<integer>          $conversationIDs
+        * @param       integer[]               $conversationIDs
         */
        public static function updateParticipantSummaries(array $conversationIDs) {
                $conversationList = new ConversationList();
-               $conversationList->getConditionBuilder()->add('conversation.conversationID IN (?)', array($conversationIDs));
+               $conversationList->setObjectIDs($conversationIDs);
                $conversationList->readObjects();
                
                foreach ($conversationList as $conversation) {
@@ -240,11 +234,11 @@ class ConversationEditor extends DatabaseObjectEditor {
        /**
         * Updates the participant counts of the given conversations.
         * 
-        * @param       array<integer>          $conversationIDs
+        * @param       integer[]               $conversationIDs
         */
        public static function updateParticipantCounts(array $conversationIDs) {
                $conversationList = new ConversationList();
-               $conversationList->getConditionBuilder()->add('conversation.conversationID IN (?)', array($conversationIDs));
+               $conversationList->setObjectIDs($conversationIDs);
                $conversationList->readObjects();
                
                foreach ($conversationList as $conversation) {
index 910642ebe58d7b240099960ba9ff151a8cffca42..88c70debd6d709235b45bae30b17d1321cb595af 100644 (file)
@@ -6,15 +6,18 @@ use wcf\data\DatabaseObjectList;
  * Represents a list of conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation
+ *
+ * @method     Conversation            current()
+ * @method     Conversation[]          getObjects()
+ * @method     Conversation|null       search($objectID)
+ * @property   Conversation[]          $objects
  */
 class ConversationList extends DatabaseObjectList {
        /**
-        * @see \wcf\data\DatabaseObjectList::$className
+        * @inheritDoc
         */
-       public $className = 'wcf\data\conversation\Conversation';
+       public $className = Conversation::class;
 }
index f4a27756f5bcbf5be5b3ca79a7b363886dd4c9b5..1cccb484b881ae76c5018fba238df53c4c5a63f4 100644 (file)
@@ -1,6 +1,5 @@
 <?php
 namespace wcf\data\conversation;
-use wcf\data\user\User;
 use wcf\data\user\UserProfile;
 use wcf\data\user\UserProfileList;
 use wcf\system\WCF;
@@ -9,11 +8,9 @@ use wcf\system\WCF;
  * Represents a list of conversation participants.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation
  */
 class ConversationParticipantList extends UserProfileList {
        /**
@@ -23,7 +20,7 @@ class ConversationParticipantList extends UserProfileList {
        public $conversationID = 0;
        
        /**
-        * @see \wcf\data\DatabaseObjectList::$sqlLimit
+        * @inheritDoc
         */
        public $sqlLimit = 0;
        
@@ -31,16 +28,17 @@ class ConversationParticipantList extends UserProfileList {
         * Creates a new ConversationParticipantList object.
         * 
         * @param       integer         $conversationID
+        * @param       integer         $userID
         * @param       boolean         $isAuthor               true if given user is the author of this conversation
         */
        public function __construct($conversationID, $userID = 0, $isAuthor = false) {
                parent::__construct();
                
                $this->conversationID = $conversationID;
-               $this->getConditionBuilder()->add('conversation_to_user.conversationID = ?', array($conversationID));
+               $this->getConditionBuilder()->add('conversation_to_user.conversationID = ?', [$conversationID]);
                if (!$isAuthor) {
                        if ($userID) {
-                               $this->getConditionBuilder()->add('conversation_to_user.isInvisible = 0 OR conversation_to_user.participantID = ?', array($userID));
+                               $this->getConditionBuilder()->add('conversation_to_user.isInvisible = 0 OR conversation_to_user.participantID = ?', [$userID]);
                        }
                        else {
                                $this->getConditionBuilder()->add('conversation_to_user.isInvisible = 0');
@@ -53,8 +51,9 @@ class ConversationParticipantList extends UserProfileList {
                $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_conversation_to_user conversation_to_user ON (conversation_to_user.participantID = user_table.userID AND conversation_to_user.conversationID = ".$conversationID.")";
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\data\DatabaseObjectList::countObjects()
+        * @inheritDoc
         */
        public function countObjects() {
                $sql = "SELECT  COUNT(*) AS count
@@ -67,11 +66,12 @@ class ConversationParticipantList extends UserProfileList {
                return $row['count'];
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\data\DatabaseObjectList::readObjectIDs()
+        * @inheritDoc
         */
        public function readObjectIDs() {
-               $this->objectIDs = array();
+               $this->objectIDs = [];
                $sql = "SELECT  conversation_to_user.participantID AS objectID
                        FROM    wcf".WCF_N."_conversation_to_user conversation_to_user
                                ".$this->sqlConditionJoins."
@@ -79,13 +79,11 @@ class ConversationParticipantList extends UserProfileList {
                                ".(!empty($this->sqlOrderBy) ? "ORDER BY ".$this->sqlOrderBy : '');
                $statement = WCF::getDB()->prepareStatement($sql, $this->sqlLimit, $this->sqlOffset);
                $statement->execute($this->getConditionBuilder()->getParameters());
-               while ($row = $statement->fetchArray()) {
-                       $this->objectIDs[] = $row['objectID'];
-               }
+               $this->objectIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
        }
        
        /**
-        * @see \wcf\data\user\UserProfileList::readObjects()
+        * @inheritDoc
         */
        public function readObjects() {
                parent::readObjects();
@@ -96,12 +94,11 @@ class ConversationParticipantList extends UserProfileList {
                        WHERE   conversationID = ?
                                AND participantID IS NULL";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array($this->conversationID));
+               $statement->execute([$this->conversationID]);
                $i = 0;
                while ($row = $statement->fetchArray()) {
                        // create fake user profiles
-                       $user = new User(null, array('userID' => 0, 'username' => $row['username']));
-                       $this->objects['x'.(++$i)] = new UserProfile($user);
+                       $this->objects['x'.(++$i)] = UserProfile::getGuestUserProfile($row['username']);
                        $this->indexToObject[] = 'x'.$i;
                }
        }
index 31d94cbcd241fcc3403395b6ec795aa8a1662aa2..df58e58e88bb484b3711b05989f0159a8cf9a086 100644 (file)
@@ -8,101 +8,101 @@ use wcf\system\request\LinkHandler;
  * Represents a conversation for RSS feeds.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation
+ *
+ * @method     Conversation    getDecoratedObject()
+ * @mixin      Conversation
  */
 class FeedConversation extends DatabaseObjectDecorator implements IFeedEntry {
        /**
-        * @see \wcf\data\DatabaseObjectDecorator::$baseClass
+        * @inheritDoc
         */
-       protected static $baseClass = 'wcf\data\conversation\Conversation';
+       protected static $baseClass = Conversation::class;
        
        /**
-        * @see \wcf\data\ILinkableObject::getLink()
+        * @inheritDoc
         */
        public function getLink() {
-               return LinkHandler::getInstance()->getLink('Conversation', array(
+               return LinkHandler::getInstance()->getLink('Conversation', [
                        'object' => $this->getDecoratedObject(),
-                       'appendSession' => false,
                        'encodeTitle' => true
-               ));
+               ]);
        }
        
        /**
-        * @see \wcf\data\ITitledObject::getTitle()
+        * @inheritDoc
         */
        public function getTitle() {
                return $this->getDecoratedObject()->getTitle();
        }
        
        /**
-        * @see \wcf\data\IMessage::getFormattedMessage()
+        * @inheritDoc
         */
        public function getFormattedMessage() {
                return '';
        }
        
        /**
-        * @see \wcf\data\IMessage::getMessage()
+        * @inheritDoc
         */
        public function getMessage() {
                return '';
        }
        
        /**
-        * @see \wcf\data\IMessage::getExcerpt()
+        * @inheritDoc
         */
        public function getExcerpt($maxLength = 255) {
                return '';
        }
        
        /**
-        * @see \wcf\data\IMessage::getUserID()
+        * @inheritDoc
         */
        public function getUserID() {
                return $this->getDecoratedObject()->lastPosterID;
        }
        
        /**
-        * @see \wcf\data\IMessage::getUsername()
+        * @inheritDoc
         */
        public function getUsername() {
                return $this->getDecoratedObject()->lastPoster;
        }
        
        /**
-        * @see \wcf\data\IMessage::getTime()
+        * @inheritDoc
         */
        public function getTime() {
                return $this->getDecoratedObject()->lastPostTime;
        }
        
        /**
-        * @see \wcf\data\IMessage::__toString()
+        * @inheritDoc
         */
        public function __toString() {
                return $this->getFormattedMessage();
        }
        
        /**
-        * @see \wcf\data\IFeedEntry::getComments()
+        * @inheritDoc
         */
        public function getComments() {
                return $this->replies;
        }
        
        /**
-        * @see \wcf\data\IFeedEntry::getCategories()
+        * @inheritDoc
         */
        public function getCategories() {
-               return array();
+               return [];
        }
        
        /**
-        * @see \wcf\data\IMessage::isVisible()
+        * @inheritDoc
         */
        public function isVisible() {
                return $this->canRead();
index 46adecb86854420592b23c1f9699134b5a9aee78..90a209b59a2981df8aa24c30a2e9bcd68dda4cc0 100644 (file)
@@ -6,28 +6,31 @@ use wcf\system\WCF;
  * Represents a list of conversations for RSS feeds.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation
+ *
+ * @method     FeedConversation        current()
+ * @method     FeedConversation[]      getObjects()
+ * @method     FeedConversation|null   search($objectID)
+ * @property   FeedConversation[]      $objects
  */
 class FeedConversationList extends ConversationList {
        /**
-        * @see \wcf\data\DatabaseObjectList::$decoratorClassName
+        * @inheritDoc
         */
-       public $decoratorClassName = 'wcf\data\conversation\FeedConversation';
+       public $decoratorClassName = FeedConversation::class;
        
        /**
-        * @see \wcf\data\DatabaseObjectList::$sqlOrderBy
+        * @inheritDoc
         */
        public $sqlOrderBy = 'conversation.lastPostTime DESC';
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\data\DatabaseObjectList::readObjectIDs()
+        * @inheritDoc
         */
        public function readObjectIDs() {
-               $this->objectIDs = array();
                $sql = "SELECT  conversation_to_user.conversationID AS objectID
                        FROM    wcf".WCF_N."_conversation_to_user conversation_to_user
                                ".$this->sqlConditionJoins."
@@ -35,13 +38,11 @@ class FeedConversationList extends ConversationList {
                                ".(!empty($this->sqlOrderBy) ? "ORDER BY ".$this->sqlOrderBy : '');
                $statement = WCF::getDB()->prepareStatement($sql, $this->sqlLimit, $this->sqlOffset);
                $statement->execute($this->getConditionBuilder()->getParameters());
-               while ($row = $statement->fetchArray()) {
-                       $this->objectIDs[] = $row['objectID'];
-               }
+               $this->objectIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
        }
        
        /**
-        * @see \wcf\data\DatabaseObjectList::readObjects()
+        * @inheritDoc
         */
        public function readObjects() {
                if ($this->objectIDs === null) {
index f1e502a1bb9101c86b2a27fc3750e353e01e894b..9eec01d0a21ce011ca6629fcf6f3c1c1a3873656 100644 (file)
@@ -2,6 +2,7 @@
 namespace wcf\data\conversation;
 use wcf\data\conversation\label\ConversationLabel;
 use wcf\data\conversation\label\ConversationLabelList;
+use wcf\system\cache\runtime\UserProfileRuntimeCache;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\WCF;
 
@@ -9,18 +10,21 @@ use wcf\system\WCF;
  * Represents a list of conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation
+ * 
+ * @method     ViewableConversation            current()
+ * @method     ViewableConversation[]          getObjects()
+ * @method     ViewableConversation|null       search($objectID)
+ * @property   ViewableConversation[]          $objects
  */
 class UserConversationList extends ConversationList {
        /**
         * list of available filters
-        * @var array<string>
+        * @var string[]
         */
-       public static $availableFilters = array('hidden', 'draft', 'outbox');
+       public static $availableFilters = ['hidden', 'draft', 'outbox'];
        
        /**
         * active filter
@@ -30,14 +34,14 @@ class UserConversationList extends ConversationList {
        
        /**
         * label list object
-        * @var \wcf\data\conversation\label\ConversationLabelList
+        * @var ConversationLabelList
         */
-       public $labelList = null;
+       public $labelList;
        
        /**
-        * @see \wcf\data\DatabaseObjectList::$decoratorClassName
+        * @inheritDoc
         */
-       public $decoratorClassName = 'wcf\data\conversation\ViewableConversation';
+       public $decoratorClassName = ViewableConversation::class;
        
        /**
         * Creates a new UserConversationList
@@ -53,14 +57,14 @@ class UserConversationList extends ConversationList {
                
                // apply filter
                if ($this->filter == 'draft') {
-                       $this->getConditionBuilder()->add('conversation.userID = ?', array($userID));
+                       $this->getConditionBuilder()->add('conversation.userID = ?', [$userID]);
                        $this->getConditionBuilder()->add('conversation.isDraft = 1');
                }
                else {
-                       $this->getConditionBuilder()->add('conversation_to_user.participantID = ?', array($userID));
-                       $this->getConditionBuilder()->add('conversation_to_user.hideConversation = ?', array(($this->filter == 'hidden' ? 1 : 0)));
+                       $this->getConditionBuilder()->add('conversation_to_user.participantID = ?', [$userID]);
+                       $this->getConditionBuilder()->add('conversation_to_user.hideConversation = ?', [$this->filter == 'hidden' ? 1 : 0]);
                        $this->sqlConditionJoins = "LEFT JOIN wcf".WCF_N."_conversation conversation ON (conversation.conversationID = conversation_to_user.conversationID)";
-                       if ($this->filter == 'outbox') $this->getConditionBuilder()->add('conversation.userID = ?', array($userID));
+                       if ($this->filter == 'outbox') $this->getConditionBuilder()->add('conversation.userID = ?', [$userID]);
                }
                
                // filter by label id
@@ -69,7 +73,7 @@ class UserConversationList extends ConversationList {
                                SELECT  conversationID
                                FROM    wcf".WCF_N."_conversation_label_to_object
                                WHERE   labelID = ?
-                       )", array($labelID));
+                       )", [$labelID]);
                }
                
                // own posts
@@ -80,31 +84,19 @@ class UserConversationList extends ConversationList {
                if (!empty($this->sqlSelects)) $this->sqlSelects .= ',';
                $this->sqlSelects .= "conversation_to_user.*";
                $this->sqlJoins .= "LEFT JOIN wcf".WCF_N."_conversation_to_user conversation_to_user ON (conversation_to_user.participantID = ".$userID." AND conversation_to_user.conversationID = conversation.conversationID)";
-               
-               // get avatars
-               if (!empty($this->sqlSelects)) $this->sqlSelects .= ',';
-               $this->sqlSelects .= "user_avatar.*, user_table.email, user_table.disableAvatar, user_table.enableGravatar, user_table.gravatarFileExtension";
-               $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user user_table ON (user_table.userID = conversation.userID)";
-               $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user_avatar user_avatar ON (user_avatar.avatarID = user_table.avatarID)";
-               
-               if (!empty($this->sqlSelects)) $this->sqlSelects .= ',';
-               $this->sqlSelects .= "lastposter_avatar.avatarID AS lastPosterAvatarID, lastposter_avatar.avatarName AS lastPosterAvatarName, lastposter_avatar.avatarExtension AS lastPosterAvatarExtension, lastposter_avatar.width AS lastPosterAvatarWidth, lastposter_avatar.height AS lastPosterAvatarHeight,";
-               $this->sqlSelects .= "lastposter.email AS lastPosterEmail, lastposter.disableAvatar AS lastPosterDisableAvatar, lastposter.enableGravatar AS lastPosterEnableGravatar, lastposter.gravatarFileExtension AS lastPosterGravatarFileExtension";
-               $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user lastposter ON (lastposter.userID = conversation.lastPosterID)";
-               $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user_avatar lastposter_avatar ON (lastposter_avatar.avatarID = lastposter.avatarID)";
        }
        
        /**
         * Sets the label list of the user the conversations belong to.
         * 
-        * @param       \wcf\data\conversation\label\ConversationLabelList      $labelList
+        * @param       ConversationLabelList   $labelList
         */
        public function setLabelList(ConversationLabelList $labelList) {
                $this->labelList = $labelList;
        }
        
        /**
-        * @see \wcf\data\DatabaseObjectList::countObjects()
+        * @inheritDoc
         */
        public function countObjects() {
                if ($this->filter == 'draft') return parent::countObjects();
@@ -120,12 +112,15 @@ class UserConversationList extends ConversationList {
        }
        
        /**
-        * @see \wcf\data\DatabaseObjectList::readObjectIDs()
+        * @inheritDoc
         */
        public function readObjectIDs() {
-               if ($this->filter == 'draft') return parent::readObjectIDs();
+               if ($this->filter == 'draft') {
+                       parent::readObjectIDs();
+                       
+                       return;
+               }
                
-               $this->objectIDs = array();
                $sql = "SELECT  conversation_to_user.conversationID AS objectID
                        FROM    wcf".WCF_N."_conversation_to_user conversation_to_user
                                ".$this->sqlConditionJoins."
@@ -133,13 +128,11 @@ class UserConversationList extends ConversationList {
                                ".(!empty($this->sqlOrderBy) ? "ORDER BY ".$this->sqlOrderBy : '');
                $statement = WCF::getDB()->prepareStatement($sql, $this->sqlLimit, $this->sqlOffset);
                $statement->execute($this->getConditionBuilder()->getParameters());
-               while ($row = $statement->fetchArray()) {
-                       $this->objectIDs[] = $row['objectID'];
-               }
+               $this->objectIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
        }
        
        /**
-        * @see \wcf\data\DatabaseObjectList::readObjects()
+        * @inheritDoc
         */
        public function readObjects() {
                if ($this->objectIDs === null) {
@@ -151,12 +144,24 @@ class UserConversationList extends ConversationList {
                if (!empty($this->objects)) {
                        $labels = $this->loadLabelAssignments();
                        
+                       $userIDs = [];
                        foreach ($this->objects as $conversationID => $conversation) {
                                if (isset($labels[$conversationID])) {
                                        foreach ($labels[$conversationID] as $label) {
                                                $conversation->assignLabel($label);
                                        }
                                }
+                               
+                               if ($conversation->userID) {
+                                       $userIDs[] = $conversation->userID;
+                               }
+                               if ($conversation->lastPosterID) {
+                                       $userIDs[] = $conversation->lastPosterID;
+                               }
+                       }
+                       
+                       if (!empty($userIDs)) {
+                               UserProfileRuntimeCache::getInstance()->cacheObjectIDs($userIDs);
                        }
                }
        }
@@ -164,7 +169,7 @@ class UserConversationList extends ConversationList {
        /**
         * Returns a list of conversation labels.
         * 
-        * @return      array<\wcf\data\conversation\label\ConversationLabel>
+        * @return      ConversationLabel[]
         */
        protected function getLabels() {
                if ($this->labelList === null) {
@@ -177,27 +182,27 @@ class UserConversationList extends ConversationList {
        /**
         * Returns label assignments per conversation.
         * 
-        * @return      array<array>
+        * @return      ConversationLabel[][]
         */
        protected function loadLabelAssignments() {
                $labels = $this->getLabels();
                if (empty($labels)) {
-                       return array();
+                       return [];
                }
                
                $conditions = new PreparedStatementConditionBuilder();
-               $conditions->add("conversationID IN (?)", array(array_keys($this->objects)));
-               $conditions->add("labelID IN (?)", array(array_keys($labels)));
+               $conditions->add("conversationID IN (?)", [array_keys($this->objects)]);
+               $conditions->add("labelID IN (?)", [array_keys($labels)]);
                
                $sql = "SELECT  labelID, conversationID
                        FROM    wcf".WCF_N."_conversation_label_to_object
                        ".$conditions;
                $statement = WCF::getDB()->prepareStatement($sql);
                $statement->execute($conditions->getParameters());
-               $data = array();
+               $data = [];
                while ($row = $statement->fetchArray()) {
                        if (!isset($data[$row['conversationID']])) {
-                               $data[$row['conversationID']] = array();
+                               $data[$row['conversationID']] = [];
                        }
                        
                        $data[$row['conversationID']][$row['labelID']] = $labels[$row['labelID']];
index d7f4a05f1814c5aaf92fd3fbcfeb2f96b85b2860..75e7e1b5892bb9845d80d10d96ca95aa0ca2c7d2 100644 (file)
@@ -5,6 +5,8 @@ use wcf\data\conversation\label\ConversationLabelList;
 use wcf\data\user\User;
 use wcf\data\user\UserProfile;
 use wcf\data\DatabaseObjectDecorator;
+use wcf\data\TLegacyUserPropertyAccess;
+use wcf\system\cache\runtime\UserProfileRuntimeCache;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\WCF;
 
@@ -12,50 +14,111 @@ use wcf\system\WCF;
  * Represents a viewable conversation.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation
+ * 
+ * @method     Conversation    getDecoratedObject()
+ * @mixin      Conversation
+ * @property-read      integer|null    $otherParticipantID
+ * @property-read      string|null     $otherParticipant
  */
 class ViewableConversation extends DatabaseObjectDecorator {
+       use TLegacyUserPropertyAccess;
+       
        /**
         * participant summary
         * @var string
         */
-       protected $__participantSummary = null;
+       protected $__participantSummary;
        
        /**
         * user profile object
-        * @var \wcf\data\user\UserProfile
+        * @var UserProfile
         */
-       protected $userProfile = null;
+       protected $userProfile;
        
        /**
         * last poster's profile
-        * @var \wcf\data\user\UserProfile
+        * @var UserProfile
         */
-       protected $lastPosterProfile = null;
+       protected $lastPosterProfile;
        
        /**
-        * @see \wcf\data\DatabaseObjectDecorator::$baseClass
+        * other participant's profile
+        * @var UserProfile
         */
-       protected static $baseClass = 'wcf\data\conversation\Conversation';
+       protected $otherParticipantProfile;
        
        /**
         * list of assigned labels
-        * @var array<\wcf\data\conversation\label\ConversationLabel>
+        * @var ConversationLabel[]
+        */
+       protected $labels = [];
+       
+       /**
+        * @inheritDoc
+        */
+       protected static $baseClass = Conversation::class;
+       
+       /**
+        * maps legacy direct access to last poster's user profile data to the real
+        * user profile property names
+        * @var string[]
+        * @deprecated
         */
-       protected $labels = array();
+       protected static $__lastUserAvatarPropertyMapping = [
+               'lastPosterAvatarID' => 'avatarID',
+               'lastPosterAvatarName' => 'avatarName',
+               'lastPosterAvatarExtension' => 'avatarExtension',
+               'lastPosterAvatarWidth' => 'width',
+               'lastPosterAvatarHeight' => 'height',
+               'lastPosterEmail' => 'email',
+               'lastPosterDisableAvatar' => 'disableAvatar',
+               'lastPosterEnableGravatar' => 'enableGravatar',
+               'lastPosterGravatarFileExtension' => 'gravatarFileExtension',
+               'lastPosterAvatarFileHash' => 'fileHash'
+       ];
+       
+       /**
+        * @inheritDoc
+        * @deprecated
+        */
+       public function __get($name) {
+               $value = parent::__get($name);
+               if ($value !== null) {
+                       return $value;
+               }
+               else if (array_key_exists($name, $this->object->data)) {
+                       return null;
+               }
+               
+               /** @noinspection PhpVariableVariableInspection */
+               $value = $this->getUserProfile()->$name;
+               if ($value !== null) {
+                       return $value;
+               }
+               
+               if (isset(static::$__lastUserAvatarPropertyMapping[$name])) {
+                       return $this->getLastPosterProfile()->getAvatar()->{static::$__lastUserAvatarPropertyMapping[$name]};
+               }
+               
+               return null;
+       }
        
        /**
         * Returns the user profile object.
         * 
-        * @return      \wcf\data\user\UserProfile
+        * @return      UserProfile
         */
        public function getUserProfile() {
                if ($this->userProfile === null) {
-                       $this->userProfile = new UserProfile(new User(null, $this->getDecoratedObject()->data));
+                       if ($this->userID) {
+                               $this->userProfile = UserProfileRuntimeCache::getInstance()->getObject($this->userID);
+                       }
+                       else {
+                               $this->userProfile = UserProfile::getGuestUserProfile($this->username);
+                       }
                }
                
                return $this->userProfile;
@@ -64,27 +127,15 @@ class ViewableConversation extends DatabaseObjectDecorator {
        /**
         * Returns the last poster's profile object.
         * 
-        * @return      \wcf\data\user\UserProfile
+        * @return      UserProfile
         */
        public function getLastPosterProfile() {
                if ($this->lastPosterProfile === null) {
-                       if ($this->userID && $this->userID == $this->lastPosterID) {
-                               $this->lastPosterProfile = $this->getUserProfile();
+                       if ($this->lastPosterID) {
+                               $this->lastPosterProfile = UserProfileRuntimeCache::getInstance()->getObject($this->lastPosterID);
                        }
                        else {
-                               $this->lastPosterProfile = new UserProfile(new User(null, array(
-                                       'userID' => $this->lastPosterID,
-                                       'username' => $this->lastPoster,
-                                       'avatarID' => $this->lastPosterAvatarID,
-                                       'avatarName' => $this->lastPosterAvatarName,
-                                       'avatarExtension' => $this->lastPosterAvatarExtension,
-                                       'width' => $this->lastPosterAvatarWidth,
-                                       'height' => $this->lastPosterAvatarHeight,
-                                       'email' => $this->lastPosterEmail,
-                                       'disableAvatar' => $this->lastPosterDisableAvatar,
-                                       'enableGravatar' => $this->lastPosterEnableGravatar,
-                                       'gravatarFileExtension' => $this->lastPosterGravatarFileExtension
-                               )));
+                               $this->lastPosterProfile = UserProfile::getGuestUserProfile($this->lastPoster);
                        }
                }
                
@@ -97,7 +148,9 @@ class ViewableConversation extends DatabaseObjectDecorator {
         * @return      integer
         */
        public function getPages() {
+               /** @noinspection PhpUndefinedFieldInspection */
                if (WCF::getUser()->conversationMessagesPerPage) {
+                       /** @noinspection PhpUndefinedFieldInspection */
                        $messagesPerPage = WCF::getUser()->conversationMessagesPerPage;
                }
                else {
@@ -110,21 +163,21 @@ class ViewableConversation extends DatabaseObjectDecorator {
        /**
         * Returns a summary of the participants.
         * 
-        * @return      array<\wcf\data\user\User>
+        * @return      User[]
         */
        public function getParticipantSummary() {
                if ($this->__participantSummary === null) {
-                       $this->__participantSummary = array();
+                       $this->__participantSummary = [];
                        
                        if ($this->participantSummary) {
                                $data = unserialize($this->participantSummary);
                                if ($data !== false) {
                                        foreach ($data as $userData) {
-                                               $this->__participantSummary[] = new User(null, array(
+                                               $this->__participantSummary[] = new User(null, [
                                                        'userID' => $userData['userID'],
                                                        'username' => $userData['username'],
                                                        'hideConversation' => $userData['hideConversation']
-                                               ));
+                                               ]);
                                        }
                                }
                        }
@@ -133,10 +186,28 @@ class ViewableConversation extends DatabaseObjectDecorator {
                return $this->__participantSummary;
        }
        
+       /**
+        * Returns the other participant's profile object.
+        *
+        * @return      UserProfile
+        */
+       public function getOtherParticipantProfile() {
+               if ($this->otherParticipantProfile === null) {
+                       if ($this->otherParticipantID) {
+                               $this->otherParticipantProfile = UserProfileRuntimeCache::getInstance()->getObject($this->otherParticipantID);
+                       }
+                       else {
+                               $this->otherParticipantProfile = UserProfile::getGuestUserProfile($this->otherParticipant);
+                       }
+               }
+               
+               return $this->otherParticipantProfile;
+       }
+       
        /**
         * Assigns a label.
         * 
-        * @param       \wcf\data\conversation\label\ConversationLabel  $label
+        * @param       ConversationLabel       $label
         */
        public function assignLabel(ConversationLabel $label) {
                $this->labels[$label->labelID] = $label;
@@ -145,7 +216,7 @@ class ViewableConversation extends DatabaseObjectDecorator {
        /**
         * Returns a list of assigned labels.
         * 
-        * @return      array<\wcf\data\conversation\label\ConversationLabel>
+        * @return      ConversationLabel[]
         */
        public function getAssignedLabels() {
                return $this->labels;
@@ -154,9 +225,9 @@ class ViewableConversation extends DatabaseObjectDecorator {
        /**
         * Converts a conversation into a viewable conversation.
         * 
-        * @param       \wcf\data\conversation\Conversation                     $conversation
-        * @param       \wcf\data\conversation\label\ConversationLabelList      $labelList
-        * @return      \wcf\data\conversation\ViewableConversation
+        * @param       Conversation            $conversation
+        * @param       ConversationLabelList   $labelList
+        * @return      ViewableConversation
         */
        public static function getViewableConversation(Conversation $conversation, ConversationLabelList $labelList = null) {
                $conversation = new ViewableConversation($conversation);
@@ -168,15 +239,14 @@ class ViewableConversation extends DatabaseObjectDecorator {
                $labels = $labelList->getObjects();
                if (!empty($labels)) {
                        $conditions = new PreparedStatementConditionBuilder();
-                       $conditions->add("conversationID = ?", array($conversation->conversationID));
-                       $conditions->add("labelID IN (?)", array(array_keys($labels)));
+                       $conditions->add("conversationID = ?", [$conversation->conversationID]);
+                       $conditions->add("labelID IN (?)", [array_keys($labels)]);
                        
                        $sql = "SELECT  labelID
                                FROM    wcf".WCF_N."_conversation_label_to_object
                                ".$conditions;
                        $statement = WCF::getDB()->prepareStatement($sql);
                        $statement->execute($conditions->getParameters());
-                       $data = array();
                        while ($row = $statement->fetchArray()) {
                                $conversation->assignLabel($labels[$row['labelID']]);
                        }
index afd2a8d414a41370c5b0890774af2af3492ed8be..1e0487ebddcf586ab47a960f8ae9c2dbcf1b54be 100644 (file)
@@ -7,28 +7,21 @@ use wcf\system\WCF;
  * Represents a conversation label.
  * 
  * @author     Marcel Werk
- * @copyright  2009-2012 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.label
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Label
+ * 
+ * @property-read      integer         $labelID
+ * @property-read      integer         $userID
+ * @property-read      string          $label
+ * @property-read      string          $cssClassName
  */
 class ConversationLabel extends DatabaseObject {
-       /**
-        * @see \wcf\data\DatabaseObject::$databaseTableName
-        */
-       protected static $databaseTableName = 'conversation_label';
-       
-       /**
-        * @see \wcf\data\DatabaseObject::$databaseIndexName
-        */
-       protected static $databaseTableIndexName = 'labelID';
-       
        /**
         * list of pre-defined css class names
-        * @var array<string>
+        * @var string[]
         */
-       public static $availableCssClassNames = array(
+       public static $availableCssClassNames = [
                'yellow',
                'orange',
                'brown',
@@ -40,19 +33,19 @@ class ConversationLabel extends DatabaseObject {
                'black',
                
                'none' /* not a real value */
-       );
+       ];
        
        /**
         * Returns a list of conversation labels for given user id.
         * 
         * @param       integer         $userID
-        * @return      \wcf\data\conversation\label\ConversationLabelList
+        * @return      ConversationLabelList
         */
        public static function getLabelsByUser($userID = null) {
                if ($userID === null) $userID = WCF::getUser()->userID;
                
                $labelList = new ConversationLabelList();
-               $labelList->getConditionBuilder()->add("conversation_label.userID = ?", array($userID));
+               $labelList->getConditionBuilder()->add("conversation_label.userID = ?", [$userID]);
                $labelList->readObjects();
                
                return $labelList;
@@ -61,7 +54,7 @@ class ConversationLabel extends DatabaseObject {
        /**
         * Returns a list of available CSS class names.
         * 
-        * @return      array<string>
+        * @return      string[]
         */
        public static function getLabelCssClassNames() {
                return self::$availableCssClassNames;
index de39825aa3a3c11ff7b3230b7670bbcbe882fdec..ae6e2525a76b38aa2b5352c349d64407e733bf52 100644 (file)
@@ -15,42 +15,44 @@ use wcf\util\StringUtil;
  * Executes label-related actions.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.label
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Label
+ * 
+ * @method     ConversationLabel               create()
+ * @method     ConversationLabelEditor[]       getObjects()
+ * @method     ConversationLabelEditor         getSingleObject()
  */
 class ConversationLabelAction extends AbstractDatabaseObjectAction {
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::$className
+        * @inheritDoc
         */
-       protected $className = 'wcf\data\conversation\label\ConversationLabelEditor';
+       protected $className = ConversationLabelEditor::class;
        
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsDelete
+        * @inheritDoc
         */
-       protected $permissionsDelete = array('user.conversation.canUseConversation');
+       protected $permissionsDelete = ['user.conversation.canUseConversation'];
        
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate
+        * @inheritDoc
         */
-       protected $permissionsUpdate = array('user.conversation.canUseConversation');
+       protected $permissionsUpdate = ['user.conversation.canUseConversation'];
        
        /**
         * conversation object
-        * @var \wcf\data\conversation\Conversation
+        * @var Conversation
         */
-       public $conversation = null;
+       public $conversation;
        
        /**
         * conversation label list object
-        * @var \wcf\data\conversation\label\ConversationLabelList
+        * @var ConversationLabelList
         */
-       public $labelList = null;
+       public $labelList;
        
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::validateUpdate()
+        * @inheritDoc
         */
        public function validateUpdate() {
                parent::validateUpdate();
@@ -66,7 +68,7 @@ class ConversationLabelAction extends AbstractDatabaseObjectAction {
        }
        
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::validateDelete()
+        * @inheritDoc
         */
        public function validateDelete() {
                parent::validateDelete();
@@ -110,18 +112,18 @@ class ConversationLabelAction extends AbstractDatabaseObjectAction {
         * @return      array
         */
        public function add() {
-               $label = ConversationLabelEditor::create(array(
+               $label = ConversationLabelEditor::create([
                        'userID' => WCF::getUser()->userID,
                        'label' => $this->parameters['data']['labelName'],
                        'cssClassName' => $this->parameters['data']['cssClassName']
-               ));
+               ]);
                
-               return array(
+               return [
                        'actionName' => 'add',
                        'cssClassName' => $label->cssClassName,
                        'label' => StringUtil::encodeHTML($label->label),
                        'labelID' => $label->labelID
-               );
+               ];
        }
        
        /**
@@ -133,7 +135,7 @@ class ConversationLabelAction extends AbstractDatabaseObjectAction {
                }
                
                // validate conversation id
-               $this->parameters['conversationIDs'] = (isset($this->parameters['conversationIDs'])) ? ArrayUtil::toIntegerArray($this->parameters['conversationIDs']) : array();
+               $this->parameters['conversationIDs'] = isset($this->parameters['conversationIDs']) ? ArrayUtil::toIntegerArray($this->parameters['conversationIDs']) : [];
                if (empty($this->parameters['conversationIDs'])) {
                        throw new UserInputException('conversationID');
                }
@@ -156,41 +158,38 @@ class ConversationLabelAction extends AbstractDatabaseObjectAction {
         */
        public function getLabelForm() {
                // read assigned labels
-               $labelIDs = array();
+               $labelIDs = [];
                foreach ($this->labelList as $label) {
                        $labelIDs[] = $label->labelID;
                }
                
-               $assignedLabels = array();
+               $assignedLabels = [];
                // read assigned labels if editing single conversation
                if (count($this->parameters['conversationIDs']) == 1) {
                        $conversationID = current($this->parameters['conversationIDs']);
                        
                        $conditions = new PreparedStatementConditionBuilder();
-                       $conditions->add("conversationID = ?", array($conversationID));
-                       $conditions->add("labelID IN (?)", array($labelIDs));
+                       $conditions->add("conversationID = ?", [$conversationID]);
+                       $conditions->add("labelID IN (?)", [$labelIDs]);
                        
                        $sql = "SELECT  labelID
                                FROM    wcf".WCF_N."_conversation_label_to_object
                                ".$conditions;
                        $statement = WCF::getDB()->prepareStatement($sql);
                        $statement->execute($conditions->getParameters());
-                       $assignedLabels = array();
-                       while ($row = $statement->fetchArray()) {
-                               $assignedLabels[] = $row['labelID'];
-                       }
+                       $assignedLabels = $statement->fetchAll(\PDO::FETCH_COLUMN);
                }
                
-               WCF::getTPL()->assign(array(
+               WCF::getTPL()->assign([
                        'assignedLabels' => $assignedLabels,
                        'conversation' => $this->conversation,
                        'labelList' => $this->labelList
-               ));
+               ]);
                
-               return array(
+               return [
                        'actionName' => 'getLabelForm',
                        'template' => WCF::getTPL()->fetch('conversationLabelAssignment')
-               );
+               ];
        }
        
        /**
@@ -200,7 +199,7 @@ class ConversationLabelAction extends AbstractDatabaseObjectAction {
                $this->validateGetLabelForm();
                
                // validate given labels
-               $this->parameters['labelIDs'] = (isset($this->parameters['labelIDs']) && is_array($this->parameters['labelIDs'])) ? ArrayUtil::toIntegerArray($this->parameters['labelIDs']) : array();
+               $this->parameters['labelIDs'] = (isset($this->parameters['labelIDs']) && is_array($this->parameters['labelIDs'])) ? ArrayUtil::toIntegerArray($this->parameters['labelIDs']) : [];
                if (!empty($this->parameters['labelIDs'])) {
                        foreach ($this->parameters['labelIDs'] as $labelID) {
                                $isValid = false;
@@ -226,14 +225,14 @@ class ConversationLabelAction extends AbstractDatabaseObjectAction {
         */
        public function assignLabel() {
                // remove previous labels (if any)
-               $labelIDs = array();
+               $labelIDs = [];
                foreach ($this->labelList as $label) {
                        $labelIDs[] = $label->labelID;
                }
                
                $conditions = new PreparedStatementConditionBuilder();
-               $conditions->add("conversationID IN (?)", array($this->parameters['conversationIDs']));
-               $conditions->add("labelID IN (?)", array($labelIDs));
+               $conditions->add("conversationID IN (?)", [$this->parameters['conversationIDs']]);
+               $conditions->add("labelID IN (?)", [$labelIDs]);
                
                $sql = "DELETE FROM     wcf".WCF_N."_conversation_label_to_object
                        ".$conditions;
@@ -250,10 +249,10 @@ class ConversationLabelAction extends AbstractDatabaseObjectAction {
                        WCF::getDB()->beginTransaction();
                        foreach ($this->parameters['labelIDs'] as $labelID) {
                                foreach ($this->parameters['conversationIDs'] as $conversationID) {
-                                       $statement->execute(array(
+                                       $statement->execute([
                                                $labelID,
                                                $conversationID
-                                       ));
+                                       ]);
                                }
                        }
                        WCF::getDB()->commitTransaction();
@@ -263,9 +262,9 @@ class ConversationLabelAction extends AbstractDatabaseObjectAction {
                        }
                }
                
-               return array(
+               return [
                        'actionName' => 'assignLabel',
                        'labelIDs' => $this->parameters['labelIDs']
-               );
+               ];
        }
 }
index 8025671b50d451e7c3e67e1e0b54098d58ffa08e..7538a813b1b8c743b3a990ad347c8dd5eed01855 100644 (file)
@@ -6,15 +6,17 @@ use wcf\data\DatabaseObjectEditor;
  * Extends the label object with functions to create, update and delete labels.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.label
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Label
+ * 
+ * @method static      ConversationLabel       create(array $parameters = [])
+ * @method             ConversationLabel       getDecoratedObject()
+ * @mixin              ConversationLabel
  */
 class ConversationLabelEditor extends DatabaseObjectEditor {
        /**
-        * @see \wcf\data\DatabaseObjectEditor::$baseClass
+        * @inheritDoc
         */
-       protected static $baseClass = 'wcf\data\conversation\label\ConversationLabel';
+       protected static $baseClass = ConversationLabel::class;
 }
index 197941125a1cb86f35b97ec0f6a4969870b7ab7b..1a45b2b47fc247f1dd399d5776176521cedc27f6 100644 (file)
@@ -6,15 +6,18 @@ use wcf\data\DatabaseObjectList;
  * Represents a list of conversation labels.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.label
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Label
+ * 
+ * @method     ConversationLabel               current()
+ * @method     ConversationLabel[]             getObjects()
+ * @method     ConversationLabel|null          search($objectID)
+ * @property   ConversationLabel[]             $objects
  */
 class ConversationLabelList extends DatabaseObjectList {
        /**
-        * @see \wcf\data\DatabaseObjectList::$className
+        * @inheritDoc
         */
-       public $className = 'wcf\data\conversation\label\ConversationLabel';
+       public $className = ConversationLabel::class;
 }
index a90af597b767e9e49cf219165367d0681ea4249b..57a829eb70bb991085ea2010d2ec67aa36ddb52a 100644 (file)
@@ -4,8 +4,8 @@ use wcf\data\attachment\GroupedAttachmentList;
 use wcf\data\conversation\Conversation;
 use wcf\data\DatabaseObject;
 use wcf\data\IMessage;
-use wcf\system\bbcode\MessageParser;
-use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
+use wcf\data\TUserContent;
+use wcf\system\html\output\HtmlOutputProcessor;
 use wcf\system\request\LinkHandler;
 use wcf\system\WCF;
 use wcf\util\StringUtil;
@@ -14,39 +14,40 @@ use wcf\util\StringUtil;
  * Represents a conversation message.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.message
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Message
+ *
+ * @property-read      integer         $messageID
+ * @property-read      integer         $conversationID
+ * @property-read      integer|null    $userID
+ * @property-read      string          $username
+ * @property-read      string          $message
+ * @property-read      integer         $time
+ * @property-read      integer         $attachments
+ * @property-read      integer         $enableHtml
+ * @property-read      string          $ipAddress
+ * @property-read      integer         $lastEditTime
+ * @property-read      integer         $editCount
+ * @property-read      integer         $hasEmbeddedObjects
  */
 class ConversationMessage extends DatabaseObject implements IMessage {
-       /**
-        * @see \wcf\data\DatabaseObject::$databaseTableName
-        */
-       protected static $databaseTableName = 'conversation_message';
-       
-       /**
-        * @see \wcf\data\DatabaseObject::$databaseIndexName
-        */
-       protected static $databaseTableIndexName = 'messageID';
+       use TUserContent;
        
        /**
         * conversation object
-        * @var \wcf\data\conversation\Conversation
+        * @var Conversation
         */
-       protected $conversation = null;
+       protected $conversation;
        
        /**
-        * @see \wcf\data\IMessage::getFormattedMessage()
+        * @inheritDoc
         */
        public function getFormattedMessage() {
-               // assign embedded objects
-               MessageEmbeddedObjectManager::getInstance()->setActiveMessage('com.woltlab.wcf.conversation.message', $this->messageID);
+               $processor = new HtmlOutputProcessor();
+               $processor->process($this->message, 'com.woltlab.wcf.conversation.message', $this->messageID);
                
-               // parse and return message
-               MessageParser::getInstance()->setOutputType('text/html');
-               return MessageParser::getInstance()->parse($this->message, $this->enableSmilies, $this->enableHtml, $this->enableBBCodes);
+               return $processor->getHtml();
        }
        
        /**
@@ -55,25 +56,28 @@ class ConversationMessage extends DatabaseObject implements IMessage {
         * @return      string
         */
        public function getSimplifiedFormattedMessage() {
-               MessageParser::getInstance()->setOutputType('text/simplified-html');
-               return MessageParser::getInstance()->parse($this->message, $this->enableSmilies, $this->enableHtml, $this->enableBBCodes);
+               $processor = new HtmlOutputProcessor();
+               $processor->setOutputType('text/simplified-html');
+               $processor->process($this->message, 'com.woltlab.wcf.conversation.message', $this->messageID);
+               
+               return $processor->getHtml();
        }
        
        /**
         * Assigns and returns the embedded attachments.
         * 
         * @param       boolean         $ignoreCache
-        * @return      \wcf\data\attachment\GroupedAttachmentList
+        * @return      GroupedAttachmentList
         */
        public function getAttachments($ignoreCache = false) {
                if (MODULE_ATTACHMENT == 1 && ($this->attachments || $ignoreCache)) {
                        $attachmentList = new GroupedAttachmentList('com.woltlab.wcf.conversation.message');
-                       $attachmentList->getConditionBuilder()->add('attachment.objectID IN (?)', array($this->messageID));
+                       $attachmentList->getConditionBuilder()->add('attachment.objectID IN (?)', [$this->messageID]);
                        $attachmentList->readObjects();
-                       $attachmentList->setPermissions(array(
+                       $attachmentList->setPermissions([
                                'canDownload' => true,
                                'canViewPreview' => true
-                       ));
+                       ]);
                        
                        if ($ignoreCache && !count($attachmentList)) {
                                return null;
@@ -86,31 +90,37 @@ class ConversationMessage extends DatabaseObject implements IMessage {
        }
        
        /**
-        * Returns an excerpt of this message.
-        * 
-        * @param       string          $maxLength
-        * @return      string
+        * @inheritDoc
         */
        public function getExcerpt($maxLength = 255) {
                return StringUtil::truncateHTML($this->getSimplifiedFormattedMessage(), $maxLength);
        }
        
        /**
-        * Returns a text-only version of this message.
+        * Returns a version of this message optimized for use in emails.
         * 
+        * @param       string  $mimeType       Either 'text/plain' or 'text/html'
         * @return      string
         */
-       public function getMailText() {
-               MessageParser::getInstance()->setOutputType('text/simplified-html');
-               $message = MessageParser::getInstance()->parse($this->message, $this->enableSmilies, $this->enableHtml, $this->enableBBCodes);
+       public function getMailText($mimeType = 'text/plain') {
+               switch ($mimeType) {
+                       case 'text/plain':
+                               $processor = new HtmlOutputProcessor();
+                               $processor->setOutputType('text/plain');
+                               $processor->process($this->message, 'com.woltlab.wcf.conversation.message', $this->messageID);
+                               
+                               return $processor->getHtml();
+                       case 'text/html':
+                               return $this->getSimplifiedFormattedMessage();
+               }
                
-               return MessageParser::getInstance()->stripHTML($message);
+               throw new \LogicException('Unreachable');
        }
        
        /**
         * Returns the conversation of this message.
         * 
-        * @return      \wcf\data\conversation\Conversation
+        * @return      Conversation
         */
        public function getConversation() {
                if ($this->conversation === null) {
@@ -123,7 +133,7 @@ class ConversationMessage extends DatabaseObject implements IMessage {
        /**
         * Sets the conversation of this message.
         * 
-        * @param       \wcf\data\conversation\Conversation     $conversation
+        * @param       Conversation    $conversation
         */
        public function setConversation(Conversation $conversation) {
                if ($this->conversationID == $conversation->conversationID) {
@@ -141,31 +151,24 @@ class ConversationMessage extends DatabaseObject implements IMessage {
        }
        
        /**
-        * @see \wcf\data\IMessage::getMessage()
+        * @inheritDoc
         */
        public function getMessage() {
                return $this->message;
        }
        
        /**
-        * @see \wcf\data\ILinkableObject::getLink()
+        * @inheritDoc
         */
        public function getLink() {
-               return LinkHandler::getInstance()->getLink('Conversation', array(
+               return LinkHandler::getInstance()->getLink('Conversation', [
                        'object' => $this->getConversation(),
                        'messageID' => $this->messageID
-               ), '#message'.$this->messageID);
+               ], '#message'.$this->messageID);
        }
        
        /**
-        * @see \wcf\data\IMessage::getTime()
-        */
-       public function getTime() {
-               return $this->time;
-       }
-       
-       /**
-        * @see \wcf\data\ITitledObject::getTitle()
+        * @inheritDoc
         */
        public function getTitle() {
                if ($this->messageID == $this->getConversation()->firstMessageID) {
@@ -176,28 +179,14 @@ class ConversationMessage extends DatabaseObject implements IMessage {
        }
        
        /**
-        * @see \wcf\data\IMessage::getUserID()
-        */
-       public function getUserID() {
-               return $this->userID;
-       }
-       
-       /**
-        * @see \wcf\data\IMessage::getUsername()
-        */
-       public function getUsername() {
-               return $this->username;
-       }
-       
-       /**
-        * @see \wcf\data\IMessage::isVisible()
+        * @inheritDoc
         */
        public function isVisible() {
                return true;
        }
        
        /**
-        * @see \wcf\data\IMessage::__toString()
+        * @inheritDoc
         */
        public function __toString() {
                return $this->getFormattedMessage();
index 13969cb9447a11afe5c5615d43383187c5502f13..49358ca4255d1c4c520188299d5758769640fd90 100644 (file)
@@ -11,10 +11,9 @@ use wcf\data\IMessageInlineEditorAction;
 use wcf\data\IMessageQuoteAction;
 use wcf\system\attachment\AttachmentHandler;
 use wcf\system\bbcode\BBCodeHandler;
-use wcf\system\bbcode\BBCodeParser;
-use wcf\system\bbcode\PreParser;
 use wcf\system\exception\PermissionDeniedException;
 use wcf\system\exception\UserInputException;
+use wcf\system\html\input\HtmlInputProcessor;
 use wcf\system\message\censorship\Censorship;
 use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
 use wcf\system\message\quote\MessageQuoteManager;
@@ -26,41 +25,49 @@ use wcf\system\user\notification\object\ConversationMessageUserNotificationObjec
 use wcf\system\user\notification\UserNotificationHandler;
 use wcf\system\user\storage\UserStorageHandler;
 use wcf\system\WCF;
-use wcf\util\MessageUtil;
 use wcf\util\StringUtil;
 
 /**
  * Executes conversation message-related actions.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.message
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Message
+ * 
+ * @method     ConversationMessageEditor[]     getObjects()
+ * @method     ConversationMessageEditor       getSingleObject()
  */
 class ConversationMessageAction extends AbstractDatabaseObjectAction implements IAttachmentMessageQuickReplyAction, IMessageInlineEditorAction, IMessageQuoteAction {
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::$className
+        * @inheritDoc
         */
-       protected $className = 'wcf\data\conversation\message\ConversationMessageEditor';
+       protected $className = ConversationMessageEditor::class;
        
        /**
         * conversation object
-        * @var \wcf\data\conversation\Conversation
+        * @var Conversation
         */
-       public $conversation = null;
+       public $conversation;
+       
+       /**
+        * @var HtmlInputProcessor
+        */
+       public $htmlInputProcessor;
        
        /**
         * conversation message object
-        * @var \wcf\data\conversation\message\ConversationMessage
+        * @var ConversationMessage
         */
-       public $message = null;
+       public $message;
        
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::create()
+        * @inheritDoc
+        * @return      ConversationMessage
         */
        public function create() {
+               if (!isset($this->parameters['data']['enableHtml'])) $this->parameters['data']['enableHtml'] = 1;
+               
                // count attachments
                if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) {
                        $this->parameters['data']['attachments'] = count($this->parameters['attachmentHandler']);
@@ -79,12 +86,18 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                        }
                }
                
+               if (!empty($this->parameters['htmlInputProcessor'])) {
+                       /** @noinspection PhpUndefinedMethodInspection */
+                       $this->parameters['data']['message'] = $this->parameters['htmlInputProcessor']->getHtml();
+               }
+               
                // create message
+               /** @var ConversationMessage $message */
                $message = parent::create();
                $messageEditor = new ConversationMessageEditor($message);
                
                // get conversation
-               $conversation = (isset($this->parameters['converation']) ? $this->parameters['converation'] : new Conversation($message->conversationID));
+               $conversation = (isset($this->parameters['conversation']) ? $this->parameters['conversation'] : new Conversation($message->conversationID));
                $conversationEditor = new ConversationEditor($conversation);
                
                if (empty($this->parameters['isFirstPost'])) {
@@ -93,9 +106,14 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                        
                        // fire notification event
                        if (!$conversation->isDraft) {
-                               $notificationRecipients = array_diff($conversation->getParticipantIDs(true), array($message->userID)); // don't notify message author
+                               $notificationRecipients = array_diff($conversation->getParticipantIDs(true), [$message->userID]); // don't notify message author
                                if (!empty($notificationRecipients)) {
-                                       UserNotificationHandler::getInstance()->fireEvent('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', new ConversationMessageUserNotificationObject($message), $notificationRecipients);
+                                       UserNotificationHandler::getInstance()->fireEvent(
+                                               'conversationMessage',
+                                               'com.woltlab.wcf.conversation.message.notification',
+                                               new ConversationMessageUserNotificationObject($message),
+                                               $notificationRecipients
+                                       );
                                }
                        }
                        
@@ -107,7 +125,7 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                                        WHERE   participantID = ?
                                                AND conversationID = ?";
                                $statement = WCF::getDB()->prepareStatement($sql);
-                               $statement->execute(array($message->userID, $conversation->conversationID));
+                               $statement->execute([$message->userID, $conversation->conversationID]);
                                
                                $conversationEditor->updateParticipantSummary();
                                $conversationEditor->updateParticipantCount();
@@ -119,29 +137,41 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                                WHERE   conversationID = ?
                                        AND hideConversation = ?";
                        $statement = WCF::getDB()->prepareStatement($sql);
-                       $statement->execute(array(
+                       $statement->execute([
                                Conversation::STATE_DEFAULT,
                                $conversation->conversationID,
                                Conversation::STATE_HIDDEN
-                       ));
+                       ]);
                }
                
                // reset storage
                UserStorageHandler::getInstance()->reset($conversation->getParticipantIDs(), 'unreadConversationCount');
                
                // update search index
-               SearchIndexManager::getInstance()->add('com.woltlab.wcf.conversation.message', $message->messageID, $message->message, (!empty($this->parameters['isFirstPost']) ? $conversation->subject : ''), $message->time, $message->userID, $message->username);
+               SearchIndexManager::getInstance()->set(
+                       'com.woltlab.wcf.conversation.message',
+                       $message->messageID,
+                       $message->message,
+                       !empty($this->parameters['isFirstPost']) ? $conversation->subject : '',
+                       $message->time,
+                       $message->userID,
+                       $message->username
+               );
                
                // update attachments
                if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) {
+                       /** @noinspection PhpUndefinedMethodInspection */
                        $this->parameters['attachmentHandler']->updateObjectID($message->messageID);
                }
                
                // save embedded objects
-               if (MessageEmbeddedObjectManager::getInstance()->registerObjects('com.woltlab.wcf.conversation.message', $message->messageID, $message->message)) {
-                       $messageEditor->update(array(
-                               'hasEmbeddedObjects' => 1
-                       ));
+               if (!empty($this->parameters['htmlInputProcessor'])) {
+                       /** @noinspection PhpUndefinedMethodInspection */
+                       $this->parameters['htmlInputProcessor']->setObjectID($message->messageID);
+                       
+                       if (MessageEmbeddedObjectManager::getInstance()->registerObjects($this->parameters['htmlInputProcessor'])) {
+                               $messageEditor->update(['hasEmbeddedObjects' => 1]);
+                       }
                }
                
                // clear quotes
@@ -155,7 +185,7 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
        }
        
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::update()
+        * @inheritDoc
         */
        public function update() {
                // count attachments
@@ -163,31 +193,47 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                        $this->parameters['data']['attachments'] = count($this->parameters['attachmentHandler']);
                }
                
+               if (!empty($this->parameters['htmlInputProcessor'])) {
+                       /** @noinspection PhpUndefinedMethodInspection */
+                       $this->parameters['data']['message'] = $this->parameters['htmlInputProcessor']->getHtml();
+               }
+               
                parent::update();
                
                // update search index / embedded objects
                if (isset($this->parameters['data']) && isset($this->parameters['data']['message'])) {
-                       foreach ($this->objects as $message) {
+                       foreach ($this->getObjects() as $message) {
                                $conversation = $message->getConversation();
-                               SearchIndexManager::getInstance()->update('com.woltlab.wcf.conversation.message', $message->messageID, $this->parameters['data']['message'], ($conversation->firstMessageID == $message->messageID ? $conversation->subject : ''), $message->time, $message->userID, $message->username);
+                               SearchIndexManager::getInstance()->set(
+                                       'com.woltlab.wcf.conversation.message',
+                                       $message->messageID,
+                                       $this->parameters['data']['message'],
+                                       $conversation->firstMessageID == $message->messageID ? $conversation->subject : '',
+                                       $message->time,
+                                       $message->userID,
+                                       $message->username
+                               );
                                
-                               if ($message->hasEmbeddedObjects != MessageEmbeddedObjectManager::getInstance()->registerObjects('com.woltlab.wcf.conversation.message', $message->messageID, $this->parameters['data']['message'])) {
-                                       $message->update(array(
-                                               'hasEmbeddedObjects' => ($message->hasEmbeddedObjects ? 0 : 1)
-                                       ));
+                               if (!empty($this->parameters['htmlInputProcessor'])) {
+                                       /** @noinspection PhpUndefinedMethodInspection */
+                                       $this->parameters['htmlInputProcessor']->setObjectID($message->messageID);
+                                       
+                                       if ($message->hasEmbeddedObjects != MessageEmbeddedObjectManager::getInstance()->registerObjects($this->parameters['htmlInputProcessor'])) {
+                                               $message->update(['hasEmbeddedObjects' => $message->hasEmbeddedObjects ? 0 : 1]);
+                                       }
                                }
                        }
                }
        }
        
        /**
-        * @see \wcf\data\AbstractDatabaseObjectAction::delete()
+        * @inheritDoc
         */
        public function delete() {
                $count = parent::delete();
                
-               $attachmentMessageIDs = $conversationIDs = array();
-               foreach ($this->objects as $message) {
+               $attachmentMessageIDs = $conversationIDs = [];
+               foreach ($this->getObjects() as $message) {
                        if (!in_array($message->conversationID, $conversationIDs)) {
                                $conversationIDs[] = $message->conversationID;
                        }
@@ -205,7 +251,7 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                
                if (!empty($this->objectIDs)) {
                        // delete notifications
-                       UserNotificationHandler::getInstance()->deleteNotifications('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', array(), $this->objectIDs);
+                       UserNotificationHandler::getInstance()->removeNotifications('com.woltlab.wcf.conversation.message.notification', $this->objectIDs);
                        
                        // update search index
                        SearchIndexManager::getInstance()->delete('com.woltlab.wcf.conversation.message', $this->objectIDs);
@@ -226,28 +272,28 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
        }
        
        /**
-        * @see \wcf\data\IMessageQuickReply::validateQuickReply()
+        * @inheritDoc
         */
        public function validateQuickReply() {
-               QuickReplyManager::getInstance()->setAllowedBBCodes(explode(',', WCF::getSession()->getPermission('user.message.allowedBBCodes')));
-               QuickReplyManager::getInstance()->validateParameters($this, $this->parameters, 'wcf\data\conversation\Conversation');
+               QuickReplyManager::getInstance()->setDisallowedBBCodes(explode(',', WCF::getSession()->getPermission('user.message.disallowedBBCodes')));
+               QuickReplyManager::getInstance()->validateParameters($this, $this->parameters, Conversation::class);
        }
        
        /**
-        * @see \wcf\data\IMessageQuickReply::quickReply()
+        * @inheritDoc
         */
        public function quickReply() {
                return QuickReplyManager::getInstance()->createMessage(
                        $this,
                        $this->parameters,
-                       'wcf\data\conversation\ConversationAction',
+                       ConversationAction::class,
                        CONVERSATION_LIST_DEFAULT_SORT_ORDER,
                        'conversationMessageList'
                );
        }
        
        /**
-        * @see \wcf\data\IExtendedMessageQuickReplyAction::validateJumpToExtended()
+        * @inheritDoc
         */
        public function validateJumpToExtended() {
                $this->readInteger('containerID');
@@ -258,7 +304,7 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                if (!$this->conversation->conversationID) {
                        throw new UserInputException('containerID');
                }
-               else if ($this->conversation->isClosed || !Conversation::isParticipant(array($this->conversation->conversationID))) {
+               else if ($this->conversation->isClosed || !Conversation::isParticipant([$this->conversation->conversationID])) {
                        throw new PermissionDeniedException();
                }
                
@@ -276,18 +322,18 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
        }
        
        /**
-        * @see \wcf\data\IExtendedMessageQuickReplyAction::jumpToExtended()
+        * @inheritDoc
         */
        public function jumpToExtended() {
                // quick reply
                if ($this->message === null) {
                        QuickReplyManager::getInstance()->setMessage('conversation', $this->conversation->conversationID, $this->parameters['message']);
-                       $url = LinkHandler::getInstance()->getLink('ConversationMessageAdd', array('id' => $this->conversation->conversationID));
+                       $url = LinkHandler::getInstance()->getLink('ConversationMessageAdd', ['id' => $this->conversation->conversationID]);
                }
                else {
                        // editing message
                        QuickReplyManager::getInstance()->setMessage('conversationMessage', $this->message->messageID, $this->parameters['message']);
-                       $url = LinkHandler::getInstance()->getLink('ConversationMessageEdit', array('id' => $this->message->messageID));
+                       $url = LinkHandler::getInstance()->getLink('ConversationMessageEdit', ['id' => $this->message->messageID]);
                }
                
                if (!empty($this->parameters['tmpHash'])) {
@@ -295,13 +341,13 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                }
                
                // redirect
-               return array(
+               return [
                        'url' => $url
-               );
+               ];
        }
        
        /**
-        * @see \wcf\data\IMessageInlineEditorAction::validateBeginEdit()
+        * @inheritDoc
         */
        public function validateBeginEdit() {
                $this->readInteger('containerID');
@@ -312,7 +358,7 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                        throw new UserInputException('containerID');
                }
                
-               if ($this->conversation->isClosed || !Conversation::isParticipant(array($this->conversation->conversationID))) {
+               if ($this->conversation->isClosed || !Conversation::isParticipant([$this->conversation->conversationID])) {
                        throw new PermissionDeniedException();
                }
                
@@ -324,84 +370,88 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                if (!$this->message->canEdit()) {
                        throw new PermissionDeniedException();
                }
+               
+               BBCodeHandler::getInstance()->setDisallowedBBCodes(explode(',', WCF::getSession()->getPermission('user.message.disallowedBBCodes')));
        }
        
        /**
-        * @see \wcf\data\IMessageInlineEditorAction::beginEdit()
+        * @inheritDoc
         */
        public function beginEdit() {
-               BBCodeHandler::getInstance()->setAllowedBBCodes(explode(',', WCF::getSession()->getPermission('user.message.allowedBBCodes')));
-               
-               WCF::getTPL()->assign(array(
+               WCF::getTPL()->assign([
                        'defaultSmilies' => SmileyCache::getInstance()->getCategorySmilies(),
                        'message' => $this->message,
                        'permissionCanUseSmilies' => 'user.message.canUseSmilies',
                        'wysiwygSelector' => 'messageEditor'.$this->message->messageID
-               ));
+               ]);
                
                if (MODULE_ATTACHMENT) {
                        $tmpHash = StringUtil::getRandomID();
                        $attachmentHandler = new AttachmentHandler('com.woltlab.wcf.conversation.message', $this->message->messageID, $tmpHash);
                        $attachmentList = $attachmentHandler->getAttachmentList();
                                
-                       WCF::getTPL()->assign(array(
+                       WCF::getTPL()->assign([
                                'attachmentHandler' => $attachmentHandler,
                                'attachmentList' => $attachmentList->getObjects(),
                                'attachmentObjectID' => $this->message->messageID,
                                'attachmentObjectType' => 'com.woltlab.wcf.conversation.message',
                                'attachmentParentObjectID' => 0,
                                'tmpHash' => $tmpHash
-                       ));
+                       ]);
                }
                
-               return array(
+               return [
                        'actionName' => 'beginEdit',
                        'template' => WCF::getTPL()->fetch('conversationMessageInlineEditor')
-               );
+               ];
        }
        
        /**
-        * @see \wcf\data\IMessageInlineEditorAction::validateSave()
+        * @inheritDoc
         */
        public function validateSave() {
                $this->readString('message', true, 'data');
                
                if (empty($this->parameters['data']['message'])) {
-                       throw new UserInputException('message', WCF::getLanguage()->get('wcf.global.form.error.empty'));
+                       throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.global.form.error.empty'));
                }
                
                $this->validateBeginEdit();
-               $this->validateMessage($this->conversation, $this->parameters['data']['message']);
+               
+               $this->validateMessage($this->conversation, $this->getHtmlInputProcessor($this->parameters['data']['message'], $this->message->messageID));
        }
        
        /**
-        * @see \wcf\data\IMessageInlineEditorAction::save()
+        * @inheritDoc
         */
        public function save() {
-               $data = array(
-                       'message' => PreParser::getInstance()->parse(MessageUtil::stripCrap($this->parameters['data']['message']), explode(',', WCF::getSession()->getPermission('user.message.allowedBBCodes')))
-               );
+               $data = [];
+               
                if (!$this->message->getConversation()->isDraft) {
                        $data['lastEditTime'] = TIME_NOW;
                        $data['editCount'] = $this->message->editCount + 1;
                }
                // execute update action
-               $action = new ConversationMessageAction(array($this->message), 'update', array('data' => $data));
+               $action = new ConversationMessageAction([$this->message], 'update', [
+                       'data' => $data,
+                       'htmlInputProcessor' => $this->getHtmlInputProcessor()
+               ]);
                $action->executeAction();
                
                // load new message
                $this->message = new ConversationMessage($this->message->messageID);
                $this->message->getAttachments();
                
+               $attachmentList = null;
                if (MODULE_ATTACHMENT) {
                        $attachmentList = $this->message->getAttachments(true);
                        $count = 0;
                        if ($attachmentList !== null) {
-                               // set permisions
-                               $attachmentList->setPermissions(array(
+                               // set permissions
+                               $attachmentList->setPermissions([
                                        'canDownload' => true,
                                        'canViewPreview' => true
-                               ));
+                               ]);
                                
                                $count = count($attachmentList);
                        }
@@ -409,23 +459,23 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                        // update count to reflect number of attachments after edit
                        if ($count != $this->message->attachments) {
                                $messageEditor = new ConversationMessageEditor($this->message);
-                               $messageEditor->update(array('attachments' => $count));
+                               $messageEditor->update(['attachments' => $count]);
                        }
                }
                
                // load embedded objects
-               MessageEmbeddedObjectManager::getInstance()->loadObjects('com.woltlab.wcf.conversation.message', array($this->message->messageID));
+               MessageEmbeddedObjectManager::getInstance()->loadObjects('com.woltlab.wcf.conversation.message', [$this->message->messageID]);
                
-               $data = array(
+               $data = [
                        'actionName' => 'save',
                        'message' => $this->message->getFormattedMessage()
-               );
+               ];
                
                if (MODULE_ATTACHMENT) {
-                       WCF::getTPL()->assign(array(
+                       WCF::getTPL()->assign([
                                'attachmentList' => $attachmentList,
                                'objectID' => $this->message->messageID
-                       ));
+                       ]);
                        $data['attachmentList'] = WCF::getTPL()->fetch('attachments');
                }
                
@@ -433,9 +483,11 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
        }
        
        /**
-        * @see \wcf\data\IMessageQuickReply::validateContainer()
+        * @inheritDoc
         */
        public function validateContainer(DatabaseObject $conversation) {
+               /** @var Conversation $conversation */
+               
                if (!$conversation->conversationID) {
                        throw new UserInputException('objectID');
                }
@@ -449,36 +501,39 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
        }
        
        /**
-        * @see \wcf\data\IMessageQuickReplyAction::validateMessage()
+        * @inheritDoc
         */
-       public function validateMessage(DatabaseObject $container, $message) {
+       public function validateMessage(DatabaseObject $container, HtmlInputProcessor $htmlInputProcessor) {
+               $message = $htmlInputProcessor->getTextContent();
                if (mb_strlen($message) > WCF::getSession()->getPermission('user.conversation.maxLength')) {
-                       throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.tooLong', array('maxTextLength' => WCF::getSession()->getPermission('user.conversation.maxLength'))));
+                       throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.tooLong', ['maxTextLength' => WCF::getSession()->getPermission('user.conversation.maxLength')]));
                }
                
                // search for disallowed bbcodes
-               $disallowedBBCodes = BBCodeParser::getInstance()->validateBBCodes($message, explode(',', WCF::getSession()->getPermission('user.message.allowedBBCodes')));
+               $disallowedBBCodes = $htmlInputProcessor->validate();
                if (!empty($disallowedBBCodes)) {
-                       throw new UserInputException('text', WCF::getLanguage()->getDynamicVariable('wcf.message.error.disallowedBBCodes', array('disallowedBBCodes' => $disallowedBBCodes)));
+                       throw new UserInputException('text', WCF::getLanguage()->getDynamicVariable('wcf.message.error.disallowedBBCodes', ['disallowedBBCodes' => $disallowedBBCodes]));
                }
                
                // search for censored words
                if (ENABLE_CENSORSHIP) {
                        $result = Censorship::getInstance()->test($message);
                        if ($result) {
-                               throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.censoredWordsFound', array('censoredWords' => $result)));
+                               throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.censoredWordsFound', ['censoredWords' => $result]));
                        }
                }
        }
        
        /**
-        * @see \wcf\data\IMessageQuickReplyAction::getMessageList()
+        * @inheritDoc
         */
        public function getMessageList(DatabaseObject $conversation, $lastMessageTime) {
+               /** @var Conversation $conversation */
+               
                $messageList = new ViewableConversationMessageList();
                $messageList->setConversation($conversation);
-               $messageList->getConditionBuilder()->add("conversation_message.conversationID = ?", array($conversation->conversationID));
-               $messageList->getConditionBuilder()->add("conversation_message.time > ?", array($lastMessageTime));
+               $messageList->getConditionBuilder()->add("conversation_message.conversationID = ?", [$conversation->conversationID]);
+               $messageList->getConditionBuilder()->add("conversation_message.time > ?", [$lastMessageTime]);
                $messageList->sqlOrderBy = "conversation_message.time ".CONVERSATION_LIST_DEFAULT_SORT_ORDER;
                $messageList->readObjects();
                
@@ -486,42 +541,45 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
        }
        
        /**
-        * @see \wcf\data\IMessageQuickReply::getPageNo()
+        * @inheritDoc
         */
        public function getPageNo(DatabaseObject $conversation) {
+               /** @var Conversation $conversation */
+               
                $sql = "SELECT  COUNT(*) AS count
                        FROM    wcf".WCF_N."_conversation_message
                        WHERE   conversationID = ?";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array($conversation->conversationID));
+               $statement->execute([$conversation->conversationID]);
                $count = $statement->fetchArray();
                
-               return array(intval(ceil($count['count'] / CONVERSATION_MESSAGES_PER_PAGE)), $count['count']);
+               return [intval(ceil($count['count'] / CONVERSATION_MESSAGES_PER_PAGE)), $count['count']];
        }
        
        /**
-        * @see \wcf\data\IMessageQuickReply::getRedirectUrl()
+        * @inheritDoc
         */
        public function getRedirectUrl(DatabaseObject $conversation, DatabaseObject $message) {
-               return LinkHandler::getInstance()->getLink('Conversation', array(
+               /** @var ConversationMessage $message */
+               return LinkHandler::getInstance()->getLink('Conversation', [
                        'object' => $conversation,
                        'messageID' => $message->messageID
-               )).'#message'.$message->messageID;
+               ]).'#message'.$message->messageID;
        }
        
        /**
-        * @see \wcf\data\IMessageQuoteAction::validateSaveFullQuote()
+        * @inheritDoc
         */
        public function validateSaveFullQuote() {
                $this->message = $this->getSingleObject();
                
-               if (!Conversation::isParticipant(array($this->message->conversationID))) {
+               if (!Conversation::isParticipant([$this->message->conversationID])) {
                        throw new PermissionDeniedException();
                }
        }
        
        /**
-        * @see \wcf\data\IMessageQuoteAction::saveFullQuote()
+        * @inheritDoc
         */
        public function saveFullQuote() {
                $quoteID = MessageQuoteManager::getInstance()->addQuote(
@@ -533,14 +591,19 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
                );
                
                if ($quoteID === false) {
-                       $removeQuoteID = MessageQuoteManager::getInstance()->getQuoteID('com.woltlab.wcf.conversation.message', $this->message->messageID, $this->message->getExcerpt(), $this->message->getMessage());
+                       $removeQuoteID = MessageQuoteManager::getInstance()->getQuoteID(
+                               'com.woltlab.wcf.conversation.message',
+                               $this->message->messageID,
+                               $this->message->getExcerpt(),
+                               $this->message->getMessage()
+                       );
                        MessageQuoteManager::getInstance()->removeQuote($removeQuoteID);
                }
                
-               $returnValues = array(
+               $returnValues = [
                        'count' => MessageQuoteManager::getInstance()->countQuotes(),
-                       'fullQuoteMessageIDs' => MessageQuoteManager::getInstance()->getFullQuoteObjectIDs(array('com.woltlab.wcf.conversation.message'))
-               );
+                       'fullQuoteMessageIDs' => MessageQuoteManager::getInstance()->getFullQuoteObjectIDs(['com.woltlab.wcf.conversation.message'])
+               ];
                
                if ($quoteID) {
                        $returnValues['renderedQuote'] = MessageQuoteManager::getInstance()->getQuoteComponents($quoteID);
@@ -550,28 +613,34 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
        }
        
        /**
-        * @see \wcf\data\IMessageQuoteAction::validateSaveQuote()
+        * @inheritDoc
         */
        public function validateSaveQuote() {
                $this->readString('message');
                $this->readBoolean('renderQuote', true);
                $this->message = $this->getSingleObject();
                
-               if (!Conversation::isParticipant(array($this->message->conversationID))) {
+               if (!Conversation::isParticipant([$this->message->conversationID])) {
                        throw new PermissionDeniedException();
                }
        }
        
        /**
-        * @see \wcf\data\IMessageQuoteAction::saveQuote()
+        * @inheritDoc
         */
        public function saveQuote() {
-               $quoteID = MessageQuoteManager::getInstance()->addQuote('com.woltlab.wcf.conversation.message', $this->message->conversationID, $this->message->messageID, $this->parameters['message'], false);
+               $quoteID = MessageQuoteManager::getInstance()->addQuote(
+                       'com.woltlab.wcf.conversation.message',
+                       $this->message->conversationID,
+                       $this->message->messageID,
+                       $this->parameters['message'],
+                       false
+               );
                
-               $returnValues = array(
+               $returnValues = [
                        'count' => MessageQuoteManager::getInstance()->countQuotes(),
-                       'fullQuoteMessageIDs' => MessageQuoteManager::getInstance()->getFullQuoteObjectIDs(array('com.woltlab.wcf.conversation.message'))
-               );
+                       'fullQuoteMessageIDs' => MessageQuoteManager::getInstance()->getFullQuoteObjectIDs(['com.woltlab.wcf.conversation.message'])
+               ];
                
                if ($this->parameters['renderQuote']) {
                        $returnValues['renderedQuote'] = MessageQuoteManager::getInstance()->getQuoteComponents($quoteID);
@@ -581,7 +650,7 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
        }
        
        /**
-        * @see \wcf\data\IMessageQuoteAction::validateGetRenderedQuotes()
+        * @inheritDoc
         */
        public function validateGetRenderedQuotes() {
                $this->readInteger('parentObjectID');
@@ -593,20 +662,34 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
        }
        
        /**
-        * @see \wcf\data\IMessageQuoteAction::getRenderedQuotes()
+        * @inheritDoc
         */
        public function getRenderedQuotes() {
                $quotes = MessageQuoteManager::getInstance()->getQuotesByParentObjectID('com.woltlab.wcf.conversation.message', $this->conversation->conversationID);
                
-               return array(
+               return [
                        'template' => implode("\n\n", $quotes)
-               );
+               ];
        }
        
        /**
-        * @see \wcf\data\IAttachmentMessageQuickReplyAction::getAttachmentHandler()
+        * @inheritDoc
         */
        public function getAttachmentHandler(DatabaseObject $conversation) {
                return new AttachmentHandler('com.woltlab.wcf.conversation.message', 0, $this->parameters['tmpHash']);
        }
+       
+       /**
+        * @inheritDoc
+        */
+       public function getHtmlInputProcessor($message = null, $objectID = 0) {
+               if ($message === null) {
+                       return $this->htmlInputProcessor;
+               }
+               
+               $this->htmlInputProcessor = new HtmlInputProcessor();
+               $this->htmlInputProcessor->process($message, 'com.woltlab.wcf.conversation.message', $objectID);
+               
+               return $this->htmlInputProcessor;
+       }
 }
index ce8fdd8b58409579f9282a99495e4091ec7b80da..867fbb5ba2747c8809e971fad22495f429b585eb 100644 (file)
@@ -6,15 +6,17 @@ use wcf\data\DatabaseObjectEditor;
  * Extends the message object with functions to create, update and delete messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.message
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Message
+ * 
+ * @method static      ConversationMessage     create(array $parameters = [])
+ * @method             ConversationMessage     getDecoratedObject()
+ * @mixin              ConversationMessage
  */
 class ConversationMessageEditor extends DatabaseObjectEditor {
        /**
-        * @see \wcf\data\DatabaseObjectEditor::$baseClass
+        * @inheritDoc
         */
-       protected static $baseClass = 'wcf\data\conversation\message\ConversationMessage';
+       protected static $baseClass = ConversationMessage::class;
 }
index 348f409bd34cea56faddb3be935bf5af501686e0..5a4b25bc939acaf21264dce09d765204032089b7 100644 (file)
@@ -6,15 +6,18 @@ use wcf\data\DatabaseObjectList;
  * Represents a list of conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.message
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Message
+ *
+ * @method     ConversationMessage             current()
+ * @method     ConversationMessage[]           getObjects()
+ * @method     ConversationMessage|null        search($objectID)
+ * @property   ConversationMessage[]           $objects
  */
 class ConversationMessageList extends DatabaseObjectList {
        /**
-        * @see \wcf\data\DatabaseObjectList::$className
+        * @inheritDoc
         */
-       public $className = 'wcf\data\conversation\message\ConversationMessage';
+       public $className = ConversationMessage::class;
 }
index 683ef34a3b91262e40d2ccf30e211069cb3ab677..199ed6981a8802abe740fa06cc9dce5283c3a2f7 100644 (file)
@@ -9,87 +9,90 @@ use wcf\system\search\SearchResultTextParser;
  * Represents a list of search result.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.message
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Message
+ * 
+ * @property-read      string|null     $subject
  */
 class SearchResultConversationMessage extends ViewableConversationMessage implements ISearchResultObject {
        /**
         * conversation object
-        * @var \wcf\data\conversation\Conversation
+        * @var Conversation
         */
-       public $conversation = null;
+       public $conversation;
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
         * Returns the conversation object.
         * 
-        * @return      \wcf\data\conversation\Conversation
+        * @return      Conversation
         */
        public function getConversation() {
                if ($this->conversation === null) {
-                       $this->conversation = new Conversation(null, array(
+                       $this->conversation = new Conversation(null, [
                                'conversationID' => $this->conversationID,
                                'subject' => $this->subject
-                       ));
+                       ]);
                }
                
                return $this->conversation;
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\data\conversation\message\ConversationMessage::getFormattedMessage()
+        * @inheritDoc
         */
        public function getFormattedMessage() {
                return SearchResultTextParser::getInstance()->parse($this->getDecoratedObject()->getSimplifiedFormattedMessage());
        }
        
        /**
-        * @see \wcf\data\search\ISearchResultObject::getSubject()
+        * @inheritDoc
         */
        public function getSubject() {
                return $this->subject;
        }
        
        /**
-        * @see \wcf\data\search\ISearchResultObject::getLink()
+        * @inheritDoc
         */
        public function getLink($query = '') {
                if ($query) {
-                       return LinkHandler::getInstance()->getLink('Conversation', array(
+                       return LinkHandler::getInstance()->getLink('Conversation', [
                                'object' => $this->getConversation(),
                                'messageID' => $this->messageID,
                                'highlight' => urlencode($query)
-                       ), '#message'.$this->messageID);
+                       ], '#message'.$this->messageID);
                }
                
                return $this->getDecoratedObject()->getLink();
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\data\search\ISearchResultObject::getTime()
+        * @inheritDoc
         */
        public function getTime() {
                return $this->time;
        }
        
        /**
-        * @see \wcf\data\search\ISearchResultObject::getObjectTypeName()
+        * @inheritDoc
         */
        public function getObjectTypeName() {
                return 'com.woltlab.wcf.conversation.message';
        }
        
        /**
-        * @see \wcf\data\search\ISearchResultObject::getContainerTitle()
+        * @inheritDoc
         */
        public function getContainerTitle() {
                return '';
        }
        
        /**
-        * @see \wcf\data\search\ISearchResultObject::getContainerLink()
+        * @inheritDoc
         */
        public function getContainerLink() {
                return '';
index daacca02aa4911634f55636fb200ab33f0d8b744..cadc5aa41a864c6d014ebd9bdef048df9c84ce8b 100644 (file)
@@ -5,17 +5,20 @@ namespace wcf\data\conversation\message;
  * Represents a list of search results.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.message
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Message
+ *
+ * @method     SearchResultConversationMessage         current()
+ * @method     SearchResultConversationMessage[]       getObjects()
+ * @method     SearchResultConversationMessage|null    search($objectID)
+ * @property   SearchResultConversationMessage[]       $objects
  */
 class SearchResultConversationMessageList extends SimplifiedViewableConversationMessageList {
        /**
-        * @see \wcf\data\DatabaseObjectList::$decoratorClassName
+        * @inheritDoc
         */
-       public $decoratorClassName = 'wcf\data\conversation\message\SearchResultConversationMessage';
+       public $decoratorClassName = SearchResultConversationMessage::class;
        
        /**
         * Creates a new SearchResultConversationMessageList object.
index e13355cf2ae7905ff05b42f8ac2182c23389da11..a5fe51c7a9851e7a38d361e73b1852bec265db3f 100644 (file)
@@ -6,20 +6,18 @@ namespace wcf\data\conversation\message;
  * Disables the loading of attachments and embedded objects by default.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.message
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Message
  */
 class SimplifiedViewableConversationMessageList extends ViewableConversationMessageList {
        /**
-        * @see \wcf\data\conversation\message\ViewableConversationMessageList::$attachmentLoading
+        * @inheritDoc
         */
        protected $attachmentLoading = false;
        
        /**
-        * @see \wcf\data\conversation\message\ViewableConversationMessageList::$embeddedObjectLoading
+        * @inheritDoc
         */
        protected $embeddedObjectLoading = false;
 }
index 99d1051932b642e0a32689237451b6ea74d85762..3daa105afdb9c1480a1601fe769af13cce636e90 100644 (file)
@@ -1,39 +1,48 @@
 <?php
 namespace wcf\data\conversation\message;
-use wcf\data\user\User;
 use wcf\data\user\UserProfile;
 use wcf\data\DatabaseObjectDecorator;
+use wcf\data\TLegacyUserPropertyAccess;
+use wcf\system\cache\runtime\UserProfileRuntimeCache;
 
 /**
  * Represents a viewable conversation message.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.message
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Message
+ * 
+ * @method     ConversationMessage     getDecoratedObject()
+ * @mixin      ConversationMessage
  */
 class ViewableConversationMessage extends DatabaseObjectDecorator {
+       use TLegacyUserPropertyAccess;
+       
        /**
-        * @see \wcf\data\DatabaseObjectDecorator::$baseClass
+        * @inheritDoc
         */
-       protected static $baseClass = 'wcf\data\conversation\message\ConversationMessage';
+       protected static $baseClass = ConversationMessage::class;
        
        /**
         * user profile object
-        * @var \wcf\data\user\UserProfile
+        * @var UserProfile
         */
-       protected $userProfile = null;
+       protected $userProfile;
        
        /**
         * Returns the user profile object.
         * 
-        * @return      \wcf\data\user\UserProfile
+        * @return      UserProfile
         */
        public function getUserProfile() {
                if ($this->userProfile === null) {
-                       $this->userProfile = new UserProfile(new User(null, $this->getDecoratedObject()->data));
+                       if ($this->userID) {
+                               $this->userProfile = UserProfileRuntimeCache::getInstance()->getObject($this->userID);
+                       }
+                       else {
+                               $this->userProfile = UserProfile::getGuestUserProfile($this->username);
+                       }
                }
                
                return $this->userProfile;
@@ -43,11 +52,11 @@ class ViewableConversationMessage extends DatabaseObjectDecorator {
         * Returns the viewable conversation message with the given id.
         * 
         * @param       integer         $messageID
-        * @return      \wcf\data\conversation\message\ViewableConversationMessage
+        * @return      ViewableConversationMessage
         */
        public static function getViewableConversationMessage($messageID) {
                $messageList = new ViewableConversationMessageList();
-               $messageList->setObjectIDs(array($messageID));
+               $messageList->setObjectIDs([$messageID]);
                $messageList->readObjects();
                
                return $messageList->search($messageID);
index 6ac77cd75db914a64b43c681ce9fa49412ab28c6..a495af2be14599c21697ab47db0164bbc4907926 100644 (file)
@@ -3,46 +3,50 @@ namespace wcf\data\conversation\message;
 use wcf\data\attachment\GroupedAttachmentList;
 use wcf\data\conversation\Conversation;
 use wcf\data\object\type\ObjectTypeCache;
+use wcf\system\cache\runtime\UserProfileRuntimeCache;
 use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
 
 /**
  * Represents a list of viewable conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.conversation.message
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Conversation\Message
+ *
+ * @method     ViewableConversationMessage             current()
+ * @method     ViewableConversationMessage[]           getObjects()
+ * @method     ViewableConversationMessage|null        search($objectID)
+ * @property   ViewableConversationMessage[]           $objects
  */
 class ViewableConversationMessageList extends ConversationMessageList {
        /**
-        * @see \wcf\data\DatabaseObjectList::$sqlOrderBy
+        * @inheritDoc
         */
        public $sqlOrderBy = 'conversation_message.time';
        
        /**
-        * @see \wcf\data\DatabaseObjectList::$decoratorClassName
+        * @inheritDoc
         */
-       public $decoratorClassName = 'wcf\data\conversation\message\ViewableConversationMessage';
+       public $decoratorClassName = ViewableConversationMessage::class;
        
        /**
         * attachment object ids
-        * @var array<integer>
+        * @var integer[]
         */
-       public $attachmentObjectIDs = array();
+       public $attachmentObjectIDs = [];
        
        /**
         * ids of the messages with embedded objects
-        * @var array<integer>
+        * @var integer[]
         */
-       public $embeddedObjectMessageIDs = array();
+       public $embeddedObjectMessageIDs = [];
        
        /**
         * attachment list
-        * @var \wcf\data\attachment\GroupedAttachmentList
+        * @var GroupedAttachmentList
         */
-       protected $attachmentList = null;
+       protected $attachmentList;
        
        /**
         * max post time
@@ -64,28 +68,12 @@ class ViewableConversationMessageList extends ConversationMessageList {
        
        /**
         * conversation object
-        * @var \wcf\data\conversation\Conversation
+        * @var Conversation
         */
-       protected $conversation = null;
+       protected $conversation;
        
        /**
-        * Creates a new ViewableConversationMessageList object.
-        */
-       public function __construct() {
-               parent::__construct();
-               
-               $this->sqlSelects .= "user_option_value.*, user_table.*";
-               $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user user_table ON (user_table.userID = conversation_message.userID)";
-               $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user_option_value user_option_value ON (user_option_value.userID = user_table.userID)";
-               
-               // get avatars
-               if (!empty($this->sqlSelects)) $this->sqlSelects .= ',';
-               $this->sqlSelects .= "user_avatar.*";
-               $this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_user_avatar user_avatar ON (user_avatar.avatarID = user_table.avatarID)";
-       }
-       
-       /**
-        * @see \wcf\data\DatabaseObjectList::readObjects()
+        * @inheritDoc
         */
        public function readObjects() {
                if ($this->objectIDs === null) {
@@ -94,6 +82,7 @@ class ViewableConversationMessageList extends ConversationMessageList {
                
                parent::readObjects();
                
+               $userIDs = [];
                foreach ($this->objects as $message) {
                        if ($message->time > $this->maxPostTime) {
                                $this->maxPostTime = $message->time;
@@ -109,6 +98,13 @@ class ViewableConversationMessageList extends ConversationMessageList {
                        if ($message->hasEmbeddedObjects) {
                                $this->embeddedObjectMessageIDs[] = $message->messageID;
                        }
+                       if ($message->userID) {
+                               $userIDs[] = $message->userID;
+                       }
+               }
+               
+               if (!empty($userIDs)) {
+                       UserProfileRuntimeCache::getInstance()->cacheObjectIDs($userIDs);
                }
                
                if ($this->embeddedObjectLoading) {
@@ -126,7 +122,7 @@ class ViewableConversationMessageList extends ConversationMessageList {
                if (!empty($this->embeddedObjectMessageIDs)) {
                        // add message objects to attachment object cache to save SQL queries
                        ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.attachment.objectType', 'com.woltlab.wcf.conversation.message')->getProcessor()->setCachedObjects($this->objects);
-                               
+                       
                        // load embedded objects
                        MessageEmbeddedObjectManager::getInstance()->loadObjects('com.woltlab.wcf.conversation.message', $this->embeddedObjectMessageIDs);
                }
@@ -138,7 +134,7 @@ class ViewableConversationMessageList extends ConversationMessageList {
        public function readAttachments() {
                if (MODULE_ATTACHMENT == 1 && !empty($this->attachmentObjectIDs)) {
                        $this->attachmentList = new GroupedAttachmentList('com.woltlab.wcf.conversation.message');
-                       $this->attachmentList->getConditionBuilder()->add('attachment.objectID IN (?)', array($this->attachmentObjectIDs));
+                       $this->attachmentList->getConditionBuilder()->add('attachment.objectID IN (?)', [$this->attachmentObjectIDs]);
                        $this->attachmentList->readObjects();
                }
        }
@@ -155,7 +151,7 @@ class ViewableConversationMessageList extends ConversationMessageList {
        /**
         * Returns the list of attachments.
         * 
-        * @return      \wcf\data\attachment\GroupedAttachmentList
+        * @return      GroupedAttachmentList
         */
        public function getAttachmentList() {
                return $this->attachmentList;
@@ -182,7 +178,7 @@ class ViewableConversationMessageList extends ConversationMessageList {
        /**
         * Sets active conversation.
         * 
-        * @param       \wcf\data\conversation\Conversation             $conversation
+        * @param       Conversation            $conversation
         */
        public function setConversation(Conversation $conversation) {
                $this->conversation = $conversation;
index 94a286793c96aaaa1b92c0bbe110def23798d44c..72c6568a7f1a3d35b81cdecc6c4c9790c54d0e0d 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 namespace wcf\data\modification\log;
-use wcf\data\conversation\Conversation;
+use wcf\system\cache\runtime\UserProfileRuntimeCache;
 use wcf\system\log\modification\ConversationModificationLogHandler;
 use wcf\system\WCF;
 
@@ -8,34 +8,34 @@ use wcf\system\WCF;
  * Represents a list of modification logs for conversation log page.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.modification.log
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Modification\Log
+ *
+ * @method     ViewableConversationModificationLog             current()
+ * @method     ViewableConversationModificationLog[]           getObjects()
+ * @method     ViewableConversationModificationLog|null        search($objectID)
+ * @property   ViewableConversationModificationLog[]           $objects
  */
 class ConversationLogModificationLogList extends ModificationLogList {
        /**
-        * @see \wbb\data\DatabaseObjectList::__construct()
+        * @inheritDoc
         */
        public function __construct($conversationID) {
                parent::__construct();
                
                // set conditions
-               $this->getConditionBuilder()->add('modification_log.objectTypeID = ?', array(ConversationModificationLogHandler::getInstance()->getObjectType('com.woltlab.wcf.conversation.conversation')->objectTypeID));
-               $this->getConditionBuilder()->add('modification_log.objectID = ?', array($conversationID));
+               $this->getConditionBuilder()->add('modification_log.objectTypeID = ?', [ConversationModificationLogHandler::getInstance()->getObjectType('com.woltlab.wcf.conversation.conversation')->objectTypeID]);
+               $this->getConditionBuilder()->add('modification_log.objectID = ?', [$conversationID]);
        }
-               
+       
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\data\DatabaseObjectList::readObjects()
+        * @inheritDoc
         */
        public function readObjects() {
-               $sql = "SELECT          user_avatar.*,
-                                       user_table.email, user_table.enableGravatar, user_table.disableAvatar, user_table.gravatarFileExtension,
-                                       modification_log.*
-                       FROM            wcf".WCF_N."_modification_log modification_log
-                       LEFT JOIN       wcf".WCF_N."_user user_table ON (user_table.userID = modification_log.userID)
-                       LEFT JOIN       wcf".WCF_N."_user_avatar user_avatar ON (user_avatar.avatarID = user_table.avatarID)            
+               $sql = "SELECT  modification_log.*
+                       FROM    wcf".WCF_N."_modification_log modification_log
                        ".$this->getConditionBuilder()."
                        ".(!empty($this->sqlOrderBy) ? "ORDER BY ".$this->sqlOrderBy : '');
                $statement = WCF::getDB()->prepareStatement($sql, $this->sqlLimit, $this->sqlOffset);
@@ -43,16 +43,24 @@ class ConversationLogModificationLogList extends ModificationLogList {
                $this->objects = $statement->fetchObjects(($this->objectClassName ?: $this->className));
                
                // use table index as array index
-               $objects = array();
+               $objects = $userIDs = [];
                foreach ($this->objects as $object) {
                        $objectID = $object->{$this->getDatabaseTableIndexName()};
                        $objects[$objectID] = $object;
                        
                        $this->indexToObject[] = $objectID;
+                       
+                       if ($object->userID) {
+                               $userIDs[] = $object->userID;
+                       }
                }
                $this->objectIDs = $this->indexToObject;
                $this->objects = $objects;
                
+               if (!empty($userIDs)) {
+                       UserProfileRuntimeCache::getInstance()->cacheObjectIDs($userIDs);
+               }
+               
                foreach ($this->objects as &$object) {
                        $object = new ViewableConversationModificationLog($object);
                }
@@ -64,10 +72,10 @@ class ConversationLogModificationLogList extends ModificationLogList {
         * will be returned and removed from collection.
         * 
         * @param       integer         $time
-        * @return      array<\wcf\data\modification\log\ViewableConversationModificationLog>
+        * @return      ViewableConversationModificationLog[]
         */
        public function getEntriesUntil($time) {
-               $entries = array();
+               $entries = [];
                foreach ($this->objects as $index => $entry) {
                        if ($entry->time < $time) {
                                $entries[] = $entry;
index e738625af71460f8378373e5b98d4ec61fb4adfa..02607f699f037f82348c601011586f8affd8157e 100644 (file)
@@ -1,47 +1,58 @@
 <?php
 namespace wcf\data\modification\log;
-use wcf\data\user\User;
 use wcf\data\user\UserProfile;
 use wcf\data\DatabaseObjectDecorator;
+use wcf\data\TLegacyUserPropertyAccess;
+use wcf\system\cache\runtime\UserProfileRuntimeCache;
 use wcf\system\WCF;
 
 /**
  * Provides a viewable conversation modification log.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage data.modification.log
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Data\Modification\Log
+ *
+ * @method     ModificationLog         getDecoratedObject()
+ * @mixin      ModificationLog
  */
 class ViewableConversationModificationLog extends DatabaseObjectDecorator {
+       use TLegacyUserPropertyAccess;
+       
        /**
-        * @see \wcf\data\DatabaseObjectDecorator::$baseClass
+        * @inheritDoc
         */
-       protected static $baseClass = 'wcf\data\modification\log\ModificationLog';
+       protected static $baseClass = ModificationLog::class;
        
        /**
         * user profile object
-        * @var \wcf\data\user\UserProfile
+        * @var UserProfile
         */
-       protected $userProfile = null;
+       protected $userProfile;
        
        /**
         * Returns readable representation of current log entry.
+        * 
+        * @return      string
         */
        public function __toString() {
-               return WCF::getLanguage()->getDynamicVariable('wcf.conversation.log.conversation.'.$this->action, array('additionalData' => $this->additionalData));
+               return WCF::getLanguage()->getDynamicVariable('wcf.conversation.log.conversation.'.$this->action, ['additionalData' => $this->additionalData]);
        }
        
        /**
         * Returns the profile object of the user who created the modification entry.
         * 
-        * @return      \wcf\data\user\UserProfile
+        * @return      UserProfile
         */
        public function getUserProfile() {
                if ($this->userProfile === null) {
-                       $this->userProfile = new UserProfile(new User(null, $this->getDecoratedObject()->data));
+                       if ($this->userID) {
+                               $this->userProfile = UserProfileRuntimeCache::getInstance()->getObject($this->userID);
+                       }
+                       else {
+                               $this->userProfile = UserProfile::getGuestUserProfile($this->username);
+                       }
                }
                
                return $this->userProfile;
index 1cddfa4438110191d8532ddff9a5d08ad979871f..ec1cb3f800e9bcade578cad689a960d421ece44f 100644 (file)
@@ -2,13 +2,13 @@
 namespace wcf\form;
 use wcf\data\conversation\Conversation;
 use wcf\data\conversation\ConversationAction;
-use wcf\data\user\UserProfile;
-use wcf\system\breadcrumb\Breadcrumb;
+use wcf\system\cache\runtime\UserProfileRuntimeCache;
 use wcf\system\conversation\ConversationHandler;
 use wcf\system\exception\IllegalLinkException;
 use wcf\system\exception\NamedUserException;
 use wcf\system\exception\UserInputException;
 use wcf\system\message\quote\MessageQuoteManager;
+use wcf\system\page\PageLocationManager;
 use wcf\system\request\LinkHandler;
 use wcf\system\WCF;
 use wcf\util\HeaderUtil;
@@ -18,37 +18,35 @@ use wcf\util\StringUtil;
  * Shows the conversation form.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage form
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Form
  */
 class ConversationAddForm extends MessageForm {
        /**
-        * @see \wcf\page\AbstractPage::$enableTracking
+        * @inheritDoc
         */
-       public $enableTracking = true;
+       public $attachmentObjectType = 'com.woltlab.wcf.conversation.message';
        
        /**
-        * @see \wcf\form\MessageForm::$attachmentObjectType
+        * @inheritDoc
         */
-       public $attachmentObjectType = 'com.woltlab.wcf.conversation.message';
+       public $loginRequired = true;
        
        /**
-        * @see \wcf\page\AbstractPage::$loginRequired
+        * @inheritDoc
         */
-       public $loginRequired = true;
+       public $messageObjectType = 'com.woltlab.wcf.conversation.message';
        
        /**
-        * @see \wcf\page\AbstractPage::$neededModules
+        * @inheritDoc
         */
-       public $neededModules = array('MODULE_CONVERSATION');
+       public $neededModules = ['MODULE_CONVERSATION'];
        
        /**
-        * @see \wcf\page\AbstractPage::$neededPermissions
+        * @inheritDoc
         */
-       public $neededPermissions = array('user.conversation.canUseConversation');
+       public $neededPermissions = ['user.conversation.canUseConversation'];
        
        /**
         * participants (comma separated user names)
@@ -76,18 +74,18 @@ class ConversationAddForm extends MessageForm {
        
        /**
         * participants (user ids)
-        * @var array<integer>
+        * @var integer[]
         */
-       public $participantIDs = array();
+       public $participantIDs = [];
        
        /**
         * invisible participants (user ids)
-        * @var array<integer>
+        * @var integer[]
         */
-       public $invisibleParticipantIDs = array();
+       public $invisibleParticipantIDs = [];
        
        /**
-        * @see \wcf\page\IPage::readParameters()
+        * @inheritDoc
         */
        public function readParameters() {
                parent::readParameters();
@@ -101,7 +99,7 @@ class ConversationAddForm extends MessageForm {
                
                if (isset($_REQUEST['userID'])) {
                        $userID = intval($_REQUEST['userID']);
-                       $user = UserProfile::getUserProfile($userID);
+                       $user = UserProfileRuntimeCache::getInstance()->getObject($userID);
                        if ($user === null || $user->userID == WCF::getUser()->userID) {
                                throw new IllegalLinkException();
                        }
@@ -111,7 +109,7 @@ class ConversationAddForm extends MessageForm {
                                Conversation::validateParticipant($user);
                        }
                        catch (UserInputException $e) {
-                               throw new NamedUserException(WCF::getLanguage()->getDynamicVariable('wcf.conversation.participants.error.'.$e->getType(), array('errorData' => array('username' => $user->username))));
+                               throw new NamedUserException(WCF::getLanguage()->getDynamicVariable('wcf.conversation.participants.error.'.$e->getType(), ['errorData' => ['username' => $user->username]]));
                        }
                        
                        $this->participants = $user->username;
@@ -125,7 +123,7 @@ class ConversationAddForm extends MessageForm {
        }
        
        /**
-        * @see \wcf\form\IForm::readFormParameters()
+        * @inheritDoc
         */
        public function readFormParameters() {
                parent::readFormParameters();
@@ -140,7 +138,7 @@ class ConversationAddForm extends MessageForm {
        }
        
        /**
-        * @see \wcf\form\IForm::validate()
+        * @inheritDoc
         */
        public function validate() {
                if (empty($this->participants) && empty($this->invisibleParticipants) && !$this->draft) {
@@ -177,44 +175,39 @@ class ConversationAddForm extends MessageForm {
        }
        
        /**
-        * @see \wcf\form\IForm::save()
+        * @inheritDoc
         */
        public function save() {
                parent::save();
                
                // save conversation
-               $data = array_merge($this->additionalFields, array(
+               $data = array_merge($this->additionalFields, [
                        'subject' => $this->subject,
                        'time' => TIME_NOW,
                        'userID' => WCF::getUser()->userID,
                        'username' => WCF::getUser()->username,
-                       'isDraft' => ($this->draft ? 1 : 0),
+                       'isDraft' => $this->draft ? 1 : 0,
                        'participantCanInvite' => $this->participantCanInvite
-               ));
+               ]);
                if ($this->draft) {
-                       $data['draftData'] = serialize(array(
+                       $data['draftData'] = serialize([
                                'participants' => $this->participantIDs,
                                'invisibleParticipants' => $this->invisibleParticipantIDs
-                       ));
+                       ]);
                }
                
-               $conversationData = array(
+               $conversationData = [
                        'data' => $data,
                        'attachmentHandler' => $this->attachmentHandler,
-                       'messageData' => array(
-                               'message' => $this->text,
-                               'enableBBCodes' => $this->enableBBCodes,
-                               'enableHtml' => $this->enableHtml,
-                               'enableSmilies' => $this->enableSmilies,
-                               'showSignature' => $this->showSignature
-                       )
-               );
+                       'htmlInputProcessor' => $this->htmlInputProcessor,
+                       'messageData' => []
+               ];
                if (!$this->draft) {
                        $conversationData['participants'] = $this->participantIDs;
                        $conversationData['invisibleParticipants'] = $this->invisibleParticipantIDs;
                }
                
-               $this->objectAction = new ConversationAction(array(), 'create', $conversationData);
+               $this->objectAction = new ConversationAction([], 'create', $conversationData);
                $resultValues = $this->objectAction->executeAction();
                
                MessageQuoteManager::getInstance()->saved();
@@ -222,34 +215,34 @@ class ConversationAddForm extends MessageForm {
                $this->saved();
                
                // forward
-               HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Conversation', array(
+               HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Conversation', [
                        'object' => $resultValues['returnValues']
-               )));
+               ]));
                exit;
        }
        
        /**
-        * @see \wcf\page\IPage::readData()
+        * @inheritDoc
         */
        public function readData() {
                parent::readData();
                
                // add breadcrumbs
-               WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.conversation.conversations'), LinkHandler::getInstance()->getLink('ConversationList')));
+               PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.conversation.ConversationList');
        }
        
        /**
-        * @see \wcf\page\IPage::assignVariables()
+        * @inheritDoc
         */
        public function assignVariables() {
                parent::assignVariables();
                
                MessageQuoteManager::getInstance()->assignVariables();
                
-               WCF::getTPL()->assign(array(
+               WCF::getTPL()->assign([
                        'participantCanInvite' => $this->participantCanInvite,
                        'participants' => $this->participants,
                        'invisibleParticipants' => $this->invisibleParticipants
-               ));
+               ]);
        }
 }
diff --git a/files/lib/form/ConversationMessageAddForm.class.php b/files/lib/form/ConversationMessageAddForm.class.php
deleted file mode 100644 (file)
index 3f5c6cf..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-<?php
-namespace wcf\form;
-use wcf\data\conversation\message\ConversationMessage;
-use wcf\data\conversation\message\ConversationMessageAction;
-use wcf\data\conversation\message\ViewableConversationMessageList;
-use wcf\data\conversation\Conversation;
-use wcf\system\breadcrumb\Breadcrumb;
-use wcf\system\exception\IllegalLinkException;
-use wcf\system\exception\PermissionDeniedException;
-use wcf\system\message\quote\MessageQuoteManager;
-use wcf\system\message\QuickReplyManager;
-use wcf\system\request\LinkHandler;
-use wcf\system\WCF;
-use wcf\util\HeaderUtil;
-
-/**
- * Shows the conversation reply form.
- * 
- * @author     Marcel Werk
- * @copyright  2009-2012 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage form
- * @category   Community Framework
- */
-class ConversationMessageAddForm extends MessageForm {
-       /**
-        * @see \wcf\page\AbstractPage::$enableTracking
-        */
-       public $enableTracking = true;
-       
-       /**
-        * @see \wcf\form\MessageForm::$attachmentObjectType
-        */
-       public $attachmentObjectType = 'com.woltlab.wcf.conversation.message';
-       
-       /**
-        * @see \wcf\page\AbstractPage::$loginRequired
-        */
-       public $loginRequired = true;
-       
-       /**
-        * @see \wcf\page\AbstractPage::$neededModules
-        */
-       public $neededModules = array('MODULE_CONVERSATION');
-       
-       /**
-        * @see \wcf\page\AbstractPage::$neededPermissions
-        */
-       public $neededPermissions = array('user.conversation.canUseConversation');
-       
-       /**
-        * conversation id
-        * @var integer
-        */
-       public $conversationID = 0;
-       
-       /**
-        * conversation
-        * @var \wcf\data\conversation\Conversation
-        */
-       public $conversation = null;
-       
-       /**
-        * message list
-        * @var \wcf\data\conversation\message\ConversationMessageList
-        */
-       public $messageList = null;
-       
-       /**
-        * @see \wcf\form\IPage::readParameters()
-        */
-       public function readParameters() {
-               parent::readParameters();
-               
-               if (isset($_REQUEST['id'])) $this->conversationID = intval($_REQUEST['id']);
-               $this->conversation = Conversation::getUserConversation($this->conversationID, WCF::getUser()->userID);
-               if ($this->conversation === null) {
-                       throw new IllegalLinkException();
-               }
-               if (!$this->conversation->canRead() || $this->conversation->isClosed) {
-                       throw new PermissionDeniedException();
-               }
-               
-               // quotes
-               MessageQuoteManager::getInstance()->readParameters();
-       }
-       
-       /**
-        * @see \wcf\form\IForm::readFormParameters()
-        */
-       public function readFormParameters() {
-               parent::readFormParameters();
-               
-               // quotes
-               MessageQuoteManager::getInstance()->readFormParameters();
-       }
-       
-       /**
-        * @see \wcf\form\MessageForm::validateSubject()
-        */
-       protected function validateSubject() {}
-       
-       /**
-        * @see \wcf\page\IPage::readData()
-        */
-       public function readData() {
-               parent::readData();
-               
-               if (empty($_POST)) {
-                       // check for quick reply message
-                       $this->text = QuickReplyManager::getInstance()->getMessage('conversation', $this->conversation->conversationID);
-                       if (empty($this->text)) {
-                               if (MessageQuoteManager::getInstance()->getQuoteMessageID()) {
-                                       $message = new ConversationMessage(MessageQuoteManager::getInstance()->getQuoteMessageID());
-                                       if (!$message->messageID) {
-                                               throw new IllegalLinkException();
-                                       }
-                                       
-                                       if ($message->conversationID == $this->conversation->conversationID) {
-                                               $message->setConversation($this->conversation);
-                                               $this->text = MessageQuoteManager::getInstance()->renderQuote($message, $message->message);
-                                       }
-                               }
-                               
-                               if (empty($this->text)) {
-                                       // get all message ids from current conversation
-                                       $sql = "SELECT  messageID
-                                               FROM    wcf".WCF_N."_conversation_message
-                                               WHERE   conversationID = ?";
-                                       $statement = WCF::getDB()->prepareStatement($sql);
-                                       $statement->execute(array($this->conversation->conversationID));
-                                       $messageIDs = array();
-                                       while ($row = $statement->fetchArray()) {
-                                               $messageIDs[] = $row['messageID'];
-                                       }
-                                       
-                                       $renderedQuotes = MessageQuoteManager::getInstance()->getQuotesByObjectIDs('com.woltlab.wcf.conversation.message', $messageIDs);
-                                       if (!empty($renderedQuotes)) {
-                                               $this->text = implode("\n", $renderedQuotes);
-                                       }
-                               }
-                       }
-               }
-               
-               // add breadcrumbs
-               WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.conversation.conversations'), LinkHandler::getInstance()->getLink('ConversationList')));
-               WCF::getBreadcrumbs()->add($this->conversation->getBreadcrumb());
-               
-               // get message list
-               $this->messageList = new ViewableConversationMessageList();
-               $this->messageList->setConversation($this->conversation);
-               $this->messageList->sqlLimit = CONVERSATION_REPLY_SHOW_MESSAGES_MAX;
-               $this->messageList->sqlOrderBy = 'conversation_message.time DESC';
-               $this->messageList->getConditionBuilder()->add('conversation_message.conversationID = ?', array($this->conversation->conversationID));
-               $this->messageList->readObjects();
-       }
-       
-       /**
-        * @see \wcf\form\IForm::save()
-        */
-       public function save() {
-               parent::save();
-               
-               // save message
-               $data = array_merge($this->additionalFields, array(
-                       'conversationID' => $this->conversationID,
-                       'message' => $this->text,
-                       'time' => TIME_NOW,
-                       'userID' => WCF::getUser()->userID,
-                       'username' => WCF::getUser()->username,
-                       'enableBBCodes' => $this->enableBBCodes,
-                       'enableHtml' => $this->enableHtml,
-                       'enableSmilies' => $this->enableSmilies,
-                       'showSignature' => $this->showSignature
-               ));
-               
-               $messageData = array(
-                       'data' => $data,
-                       'attachmentHandler' => $this->attachmentHandler
-               );
-               
-               $this->objectAction = new ConversationMessageAction(array(), 'create', $messageData);
-               $resultValues = $this->objectAction->executeAction();
-               
-               MessageQuoteManager::getInstance()->saved();
-               
-               $this->saved();
-               
-               // forward
-               HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Conversation', array(
-                       'object' => $this->conversation,
-                       'messageID' => $resultValues['returnValues']->messageID
-               )).'#message'.$resultValues['returnValues']->messageID);
-               exit;
-       }
-       
-       /**
-        * @see \wcf\page\IPage::assignVariables()
-        */
-       public function assignVariables() {
-               parent::assignVariables();
-               
-               MessageQuoteManager::getInstance()->assignVariables();
-               
-               WCF::getTPL()->assign(array(
-                       'conversation' => $this->conversation,
-                       'conversationID' => $this->conversationID,
-                       'items' => $this->messageList->countObjects(),
-                       'messages' => $this->messageList->getObjects(),
-                       'attachmentList' => $this->messageList->getAttachmentList()
-               ));
-       }
-       
-       /**
-        * @see \wcf\page\ITrackablePage::getObjectType()
-        */
-       public function getObjectType() {
-               return 'com.woltlab.wcf.conversation';
-       }
-       
-       /**
-        * @see \wcf\page\ITrackablePage::getObjectID()
-        */
-       public function getObjectID() {
-               return $this->conversationID;
-       }
-}
diff --git a/files/lib/form/ConversationMessageEditForm.class.php b/files/lib/form/ConversationMessageEditForm.class.php
deleted file mode 100644 (file)
index 966171a..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-<?php
-namespace wcf\form;
-use wcf\data\conversation\message\ConversationMessage;
-use wcf\data\conversation\message\ConversationMessageAction;
-use wcf\data\conversation\message\ViewableConversationMessageList;
-use wcf\data\conversation\ConversationAction;
-use wcf\data\user\UserProfile;
-use wcf\system\breadcrumb\Breadcrumb;
-use wcf\system\exception\IllegalLinkException;
-use wcf\system\exception\PermissionDeniedException;
-use wcf\system\request\LinkHandler;
-use wcf\system\WCF;
-use wcf\util\HeaderUtil;
-
-/**
- * Shows the conversation message edit form.
- * 
- * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage form
- * @category   Community Framework
- */
-class ConversationMessageEditForm extends ConversationAddForm {
-       /**
-        * @see \wcf\page\AbstractPage::$templateName
-        */
-       public $templateName = 'conversationMessageEdit';
-       
-       /**
-        * message id
-        * @var integer
-        */
-       public $messageID = 0;
-       
-       /**
-        * message object
-        * @var \wcf\data\conversation\message\ConversationMessage
-        */
-       public $message = null;
-       
-       /**
-        * conversation id
-        * @var integer
-        */
-       public $conversationID = 0;
-       
-       /**
-        * conversation
-        * @var \wcf\data\conversation\Conversation
-        */
-       public $conversation = null;
-       
-       /**
-        * message list
-        * @var \wcf\data\conversation\message\ConversationMessageList
-        */
-       public $messageList = null;
-       
-       /**
-        * true if current message is first message
-        * @var boolean
-        */
-       public $isFirstMessage = false;
-       
-       /**
-        * @see \wcf\form\IPage::readParameters()
-        */
-       public function readParameters() {
-               MessageForm::readParameters();
-               
-               if (isset($_REQUEST['id'])) $this->messageID = intval($_REQUEST['id']);
-               $this->message = new ConversationMessage($this->messageID);
-               if (!$this->message->messageID) {
-                       throw new IllegalLinkException();
-               }
-               if (!$this->message->canEdit()) {
-                       throw new PermissionDeniedException();
-               }
-               // get conversation
-               $this->conversationID = $this->message->conversationID;
-               $this->conversation = $this->message->getConversation();
-               
-               if ($this->conversation->firstMessageID == $this->message->messageID) {
-                       $this->isFirstMessage = true;
-               }
-               
-               // set attachment object id
-               $this->attachmentObjectID = $this->message->messageID;
-       }
-       
-       /**
-        * @see \wcf\form\IForm::readFormParameters()
-        */
-       public function readFormParameters() {
-               parent::readFormParameters();
-               
-               if (!$this->conversation->isDraft) $this->draft = 0;
-       }
-       
-       /**
-        * @see \wcf\form\IForm::validate()
-        */
-       public function validate() {
-               if ($this->isFirstMessage && $this->conversation->isDraft) parent::validate();
-               else MessageForm::validate();
-       }
-       
-       /**
-        * @see \wcf\form\MessageForm::validateSubject()
-        */
-       protected function validateSubject() {
-               if ($this->isFirstMessage) parent::validateSubject();
-       }
-       
-       /**
-        * @see \wcf\form\IForm::save()
-        */
-       public function save() {
-               MessageForm::save();
-               
-               // save message
-               $data = array_merge($this->additionalFields, array(
-                       'message' => $this->text,
-                       'enableBBCodes' => $this->enableBBCodes,
-                       'enableHtml' => $this->enableHtml,
-                       'enableSmilies' => $this->enableSmilies,
-                       'showSignature' => $this->showSignature
-               ));
-               if ($this->conversation->isDraft && !$this->draft) {
-                       $data['time'] = TIME_NOW;
-               }
-               if (!$this->draft) {
-                       $data['lastEditTime'] = TIME_NOW;
-                       $data['editCount'] = $this->message->editCount + 1;
-               }
-               $messageData = array(
-                       'data' => $data,
-                       'attachmentHandler' => $this->attachmentHandler
-               );
-               $this->objectAction = new ConversationMessageAction(array($this->message), 'update', $messageData);
-               $this->objectAction->executeAction();
-               
-               // update conversation
-               if ($this->isFirstMessage) {
-                       $data = array(
-                               'subject' => $this->subject,
-                               'isDraft' => ($this->draft ? 1 : 0),
-                               'participantCanInvite' => $this->participantCanInvite
-                       );
-                       if ($this->draft) {
-                               $data['draftData'] = serialize(array(
-                                       'participants' => $this->participantIDs,
-                                       'invisibleParticipants' => $this->invisibleParticipantIDs
-                               ));
-                       }
-                       
-                       $conversationData = array(
-                               'data' => $data
-                       );
-                       if ($this->conversation->isDraft && !$this->draft) {
-                               $conversationData['participants'] = $this->participantIDs;
-                               $conversationData['invisibleParticipants'] = $this->invisibleParticipantIDs;
-                               
-                               $conversationData['data']['time'] = $conversationData['data']['lastPostTime'] = TIME_NOW;
-                       }
-                       
-                       $conversationAction = new ConversationAction(array($this->conversation), 'update', $conversationData);
-                       $conversationAction->executeAction();
-               }
-               $this->saved();
-               
-               // forward
-               HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Conversation', array(
-                       'object' => $this->conversation,
-                       'messageID' => $this->messageID
-               )).'#message'.$this->messageID);
-               exit;
-       }
-       
-       /**
-        * @see \wcf\page\IPage::readData()
-        */
-       public function readData() {
-               MessageForm::readData();
-               
-               if (empty($_POST)) {
-                       $this->text = $this->message->message;
-                       
-                       if ($this->isFirstMessage) {
-                               $this->participantCanInvite = $this->conversation->participantCanInvite;
-                               $this->subject = $this->conversation->subject;
-                               
-                               if ($this->conversation->isDraft && $this->conversation->draftData) {
-                                       $draftData = @unserialize($this->conversation->draftData);
-                                       if (!empty($draftData['participants'])) {
-                                               foreach (UserProfile::getUserProfiles($draftData['participants']) as $user) {
-                                                       if (!empty($this->participants)) $this->participants .= ', ';
-                                                       $this->participants .= $user->username;
-                                               }
-                                       }
-                                       if (!empty($draftData['invisibleParticipants'])) {
-                                               foreach (UserProfile::getUserProfiles($draftData['invisibleParticipants']) as $user) {
-                                                       if (!empty($this->invisibleParticipants)) $this->invisibleParticipants .= ', ';
-                                                       $this->invisibleParticipants .= $user->username;
-                                               }
-                                       }
-                               }
-                       }
-               }
-               
-               // add breadcrumbs
-               WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.conversation.conversations'), LinkHandler::getInstance()->getLink('ConversationList')));
-               WCF::getBreadcrumbs()->add($this->conversation->getBreadcrumb());
-               
-               // get message list
-               $this->messageList = new ViewableConversationMessageList();
-               $this->messageList->setConversation($this->conversation);
-               $this->messageList->sqlLimit = CONVERSATION_REPLY_SHOW_MESSAGES_MAX;
-               $this->messageList->sqlOrderBy = 'conversation_message.time DESC';
-               $this->messageList->getConditionBuilder()->add('conversation_message.conversationID = ?', array($this->message->conversationID));
-               $this->messageList->getConditionBuilder()->add("conversation_message.messageID <> ?", array($this->message->messageID));
-               $this->messageList->readObjects();
-       }
-       
-       /**
-        * @see \wcf\page\IPage::assignVariables()
-        */
-       public function assignVariables() {
-               parent::assignVariables();
-               
-               WCF::getTPL()->assign(array(
-                       'messageID' => $this->messageID,
-                       'message' => $this->message,
-                       'conversationID' => $this->conversationID,
-                       'conversation' => $this->conversation,
-                       'isFirstMessage' => $this->isFirstMessage,
-                       'items' => $this->messageList->countObjects(),
-                       'messages' => $this->messageList->getObjects(),
-                       'attachmentList' => $this->messageList->getAttachmentList()
-               ));
-       }
-       
-       /**
-        * @see \wcf\page\ITrackablePage::getObjectType()
-        */
-       public function getObjectType() {
-               return 'com.woltlab.wcf.conversation';
-       }
-       
-       /**
-        * @see \wcf\page\ITrackablePage::getObjectID()
-        */
-       public function getObjectID() {
-               return $this->conversationID;
-       }
-}
index f3d0f42362860f5728f63f58d0f51334e26335ff..46bf7f1cf2224ab8ad9240a8f554adf46ea0a5c9 100644 (file)
@@ -7,27 +7,25 @@ use wcf\system\WCF;
  * Shows most recent conversations.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage page
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Page
  */
 class ConversationFeedPage extends AbstractFeedPage {
        /**
-        * @see \wcf\page\AbstractPage::$loginRequired
+        * @inheritDoc
         */
        public $loginRequired = true;
        
        /**
-        * @see \wcf\page\IPage::readData()
+        * @inheritDoc
         */
        public function readData() {
                parent::readData();
                
                $this->items = new FeedConversationList();
-               $this->items->getConditionBuilder()->add('conversation_to_user.participantID = ?', array(WCF::getUser()->userID));
-               $this->items->getConditionBuilder()->add('conversation_to_user.hideConversation = ?', array(0));
+               $this->items->getConditionBuilder()->add('conversation_to_user.participantID = ?', [WCF::getUser()->userID]);
+               $this->items->getConditionBuilder()->add('conversation_to_user.hideConversation = ?', [0]);
                $this->items->sqlConditionJoins = "LEFT JOIN wcf".WCF_N."_conversation conversation ON (conversation.conversationID = conversation_to_user.conversationID)";
                $this->items->sqlLimit = 20;
                $this->items->readObjects();
index a35f918ae326c9087cd399e7c8a76933fca77016..efe062d2724a74febba200e39ec5af6af2648905 100644 (file)
@@ -1,63 +1,59 @@
 <?php
 namespace wcf\page;
 use wcf\data\conversation\label\ConversationLabel;
+use wcf\data\conversation\label\ConversationLabelList;
 use wcf\data\conversation\UserConversationList;
-use wcf\system\breadcrumb\Breadcrumb;
 use wcf\system\clipboard\ClipboardHandler;
 use wcf\system\exception\IllegalLinkException;
-use wcf\system\request\LinkHandler;
+use wcf\system\page\PageLocationManager;
 use wcf\system\WCF;
+use wcf\util\ArrayUtil;
 
 /**
  * Shows a list of conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2012 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage page
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Page
+ * 
+ * @property   UserConversationList    $objectList
  */
 class ConversationListPage extends SortablePage {
        /**
-        * @see \wcf\page\AbstractPage::$enableTracking
-        */
-       public $enableTracking = true;
-       
-       /**
-        * @see \wcf\page\SortablePage::$defaultSortField
+        * @inheritDoc
         */
        public $defaultSortField = CONVERSATION_LIST_DEFAULT_SORT_FIELD;
        
        /**
-        * @see \wcf\page\SortablePage::$defaultSortOrder
+        * @inheritDoc
         */
        public $defaultSortOrder = CONVERSATION_LIST_DEFAULT_SORT_ORDER;
        
        /**
-        * @see \wcf\page\SortablePage::$validSortFields
+        * @inheritDoc
         */
-       public $validSortFields = array('subject', 'time', 'username', 'lastPostTime', 'replies', 'participants');
+       public $validSortFields = ['subject', 'time', 'username', 'lastPostTime', 'replies', 'participants'];
        
        /**
-        * @see \wcf\page\MultipleLinkPage::$itemsPerPage
+        * @inheritDoc
         */
        public $itemsPerPage = CONVERSATIONS_PER_PAGE;
        
        /**
-        * @see \wcf\page\AbstractPage::$loginRequired
+        * @inheritDoc
         */
        public $loginRequired = true;
        
        /**
-        * @see \wcf\page\AbstractPage::$neededModules
+        * @inheritDoc
         */
-       public $neededModules = array('MODULE_CONVERSATION');
+       public $neededModules = ['MODULE_CONVERSATION'];
        
        /**
-        * @see \wcf\page\AbstractPage::$neededPermissions
+        * @inheritDoc
         */
-       public $neededPermissions = array('user.conversation.canUseConversation');
+       public $neededPermissions = ['user.conversation.canUseConversation'];
        
        /**
         * list filter
@@ -73,9 +69,9 @@ class ConversationListPage extends SortablePage {
        
        /**
         * label list object
-        * @var \wcf\data\conversation\label\ConversationLabelList
+        * @var ConversationLabelList
         */
-       public $labelList = null;
+       public $labelList;
        
        /**
         * number of conversations (no filter)
@@ -102,7 +98,13 @@ class ConversationListPage extends SortablePage {
        public $outboxCount = 0;
        
        /**
-        * @see \wcf\page\IPage::readParameters()
+        * participant that
+        * @var string[]
+        */
+       public $participants = [];
+       
+       /**
+        * @inheritDoc
         */
        public function readParameters() {
                parent::readParameters();
@@ -111,7 +113,11 @@ class ConversationListPage extends SortablePage {
                if (!in_array($this->filter, UserConversationList::$availableFilters)) $this->filter = '';
                
                // user settings
-               if (WCF::getUser()->conversationsPerPage) $this->itemsPerPage = WCF::getUser()->conversationsPerPage;
+               /** @noinspection PhpUndefinedFieldInspection */
+               if (WCF::getUser()->conversationsPerPage) {
+                       /** @noinspection PhpUndefinedFieldInspection */
+                       $this->itemsPerPage = WCF::getUser()->conversationsPerPage;
+               }
                
                // labels
                $this->labelList = ConversationLabel::getLabelsByUser();
@@ -130,18 +136,28 @@ class ConversationListPage extends SortablePage {
                                throw new IllegalLinkException();
                        }
                }
+               
+               if (isset($_REQUEST['participants'])) $this->participants = ArrayUtil::trim(explode(',', $_REQUEST['participants']));
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\page\MultipleLinkPage::initObjectList()
+        * @inheritDoc
         */
        protected function initObjectList() {
                $this->objectList = new UserConversationList(WCF::getUser()->userID, $this->filter, $this->labelID);
                $this->objectList->setLabelList($this->labelList);
+               
+               if (!empty($this->participants)) {
+                       $this->objectList->getConditionBuilder()->add('conversation.conversationID IN (SELECT conversationID FROM wcf'.WCF_N.'_conversation_to_user WHERE username IN (?) GROUP BY conversationID HAVING COUNT(conversationID) = ?)', [
+                               $this->participants,
+                               count($this->participants)
+                       ]);
+               }
        }
        
        /**
-        * @see \wcf\page\IPage::readData()
+        * @inheritDoc
         */
        public function readData() {
                // if sort field is `username`, `conversation.` has to prepended because `username`
@@ -158,12 +174,12 @@ class ConversationListPage extends SortablePage {
                }
                
                if ($this->filter != '') {
-                       // add breadcrumbs
-                       WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.conversation.conversations'), LinkHandler::getInstance()->getLink('ConversationList')));
+                       // `-1` = pseudo object id to have to pages with identifier `com.woltlab.wcf.conversation.ConversationList`
+                       PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.conversation.ConversationList', -1);
                }
                
                // read stats
-               if (!$this->labelID) {
+               if (!$this->labelID && empty($this->participants)) {
                        switch ($this->filter) {
                                case '':
                                        $this->conversationCount = $this->items;
@@ -183,31 +199,31 @@ class ConversationListPage extends SortablePage {
                        }
                }
                
-               if ($this->filter != '' || $this->labelID) {
+               if ($this->filter != '' || $this->labelID || !empty($this->participants)) {
                        $conversationList = new UserConversationList(WCF::getUser()->userID, '');
                        $this->conversationCount = $conversationList->countObjects();
                }
-               if ($this->filter != 'draft' || $this->labelID) {
+               if ($this->filter != 'draft' || $this->labelID || !empty($this->participants)) {
                        $conversationList = new UserConversationList(WCF::getUser()->userID, 'draft');
                        $this->draftCount = $conversationList->countObjects();
                }
-               if ($this->filter != 'hidden' || $this->labelID) {
+               if ($this->filter != 'hidden' || $this->labelID || !empty($this->participants)) {
                        $conversationList = new UserConversationList(WCF::getUser()->userID, 'hidden');
                        $this->hiddenCount = $conversationList->countObjects();
                }
-               if ($this->filter != 'outbox' || $this->labelID) {
+               if ($this->filter != 'outbox' || $this->labelID || !empty($this->participants)) {
                        $conversationList = new UserConversationList(WCF::getUser()->userID, 'outbox');
                        $this->outboxCount = $conversationList->countObjects();
                }
        }
        
        /**
-        * @see \wcf\page\IPage::assignVariables()
+        * @inheritDoc
         */
        public function assignVariables() {
                parent::assignVariables();
                
-               WCF::getTPL()->assign(array(
+               WCF::getTPL()->assign([
                        'filter' => $this->filter,
                        'hasMarkedItems' => ClipboardHandler::getInstance()->hasMarkedItems(ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.conversation.conversation')),
                        'labelID' => $this->labelID,
@@ -215,7 +231,8 @@ class ConversationListPage extends SortablePage {
                        'conversationCount' => $this->conversationCount,
                        'draftCount' => $this->draftCount,
                        'hiddenCount' => $this->hiddenCount,
-                       'outboxCount' => $this->outboxCount
-               ));
+                       'outboxCount' => $this->outboxCount,
+                       'participants' => $this->participants
+               ]);
        }
 }
index f2d15dfe773c061084183023bbc90400933aea62..1afb9b2aeb0a9e5defc605cc9289b3313190c4e8 100644 (file)
@@ -1,7 +1,9 @@
 <?php
 namespace wcf\page;
 use wcf\data\conversation\label\ConversationLabel;
+use wcf\data\conversation\label\ConversationLabelList;
 use wcf\data\conversation\message\ConversationMessage;
+use wcf\data\conversation\message\ViewableConversationMessageList;
 use wcf\data\conversation\Conversation;
 use wcf\data\conversation\ConversationAction;
 use wcf\data\conversation\ConversationParticipantList;
@@ -10,10 +12,11 @@ use wcf\data\modification\log\ConversationLogModificationLogList;
 use wcf\data\smiley\SmileyCache;
 use wcf\system\attachment\AttachmentHandler;
 use wcf\system\bbcode\BBCodeHandler;
-use wcf\system\breadcrumb\Breadcrumb;
 use wcf\system\exception\IllegalLinkException;
 use wcf\system\exception\PermissionDeniedException;
 use wcf\system\message\quote\MessageQuoteManager;
+use wcf\system\page\PageLocationManager;
+use wcf\system\page\ParentPageLocation;
 use wcf\system\request\LinkHandler;
 use wcf\system\WCF;
 use wcf\util\HeaderUtil;
@@ -23,47 +26,42 @@ use wcf\util\StringUtil;
  * Shows a conversation.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage page
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\Page
+ * 
+ * @property   ViewableConversationMessageList         $objectList
  */
 class ConversationPage extends MultipleLinkPage {
        /**
-        * @see \wcf\page\AbstractPage::$enableTracking
-        */
-       public $enableTracking = true;
-       
-       /**
-        * @see \wcf\page\MultipleLinkPage::$itemsPerPage
+        * @inheritDoc
         */
        public $itemsPerPage = CONVERSATION_MESSAGES_PER_PAGE;
        
        /**
-        * @see \wcf\page\MultipleLinkPage::$sortOrder
+        * @inheritDoc
         */
        public $sortOrder = 'ASC';
        
        /**
-        * @see \wcf\page\MultipleLinkPage::$objectListClassName
+        * @inheritDoc
         */
-       public $objectListClassName = 'wcf\data\conversation\message\ViewableConversationMessageList';
+       public $objectListClassName = ViewableConversationMessageList::class;
        
        /**
-        * @see \wcf\page\AbstractPage::$loginRequired
+        * @inheritDoc
         */
        public $loginRequired = true;
        
        /**
-        * @see \wcf\page\AbstractPage::$neededModules
+        * @inheritDoc
         */
-       public $neededModules = array('MODULE_CONVERSATION');
+       public $neededModules = ['MODULE_CONVERSATION'];
        
        /**
-        * @see \wcf\page\AbstractPage::$neededPermissions
+        * @inheritDoc
         */
-       public $neededPermissions = array('user.conversation.canUseConversation');
+       public $neededPermissions = ['user.conversation.canUseConversation'];
        
        /**
         * conversation id
@@ -73,15 +71,15 @@ class ConversationPage extends MultipleLinkPage {
        
        /**
         * viewable conversation object
-        * @var \wcf\data\conversation\ViewableConversation
+        * @var ViewableConversation
         */
-       public $conversation = null;
+       public $conversation;
        
        /**
         * conversation label list
-        * @var \wcf\data\conversation\label\ConversationLabelList
+        * @var ConversationLabelList
         */
-       public $labelList = null;
+       public $labelList;
        
        /**
         * message id
@@ -91,24 +89,24 @@ class ConversationPage extends MultipleLinkPage {
        
        /**
         * conversation message object
-        * @var \wcf\data\conversation\message\ConversationMessage
+        * @var ConversationMessage
         */
-       public $message = null;
+       public $message;
        
        /**
         * modification log list object
-        * @var \wcf\data\wcf\data\modification\log\ConversationLogModificationLogList
+        * @var ConversationLogModificationLogList
         */
-       public $modificationLogList = null;
+       public $modificationLogList;
        
        /**
         * list of participants
-        * @var \wcf\data\conversation\ConversationParticipantList
+        * @var ConversationParticipantList
         */
-       public $participantList = null;
+       public $participantList;
        
        /**
-        * @see \wcf\page\IPage::readParameters()
+        * @inheritDoc
         */
        public function readParameters() {
                parent::readParameters();
@@ -135,21 +133,25 @@ class ConversationPage extends MultipleLinkPage {
                $this->labelList = ConversationLabel::getLabelsByUser();
                $this->conversation = ViewableConversation::getViewableConversation($this->conversation, $this->labelList);
                
-               // posts per page
-               if (WCF::getUser()->conversationMessagesPerPage) $this->itemsPerPage = WCF::getUser()->conversationMessagesPerPage;
+               // messages per page
+               /** @noinspection PhpUndefinedFieldInspection */
+               if (WCF::getUser()->conversationMessagesPerPage) {
+                       /** @noinspection PhpUndefinedFieldInspection */
+                       $this->itemsPerPage = WCF::getUser()->conversationMessagesPerPage;
+               }
                
-               $this->canonicalURL = LinkHandler::getInstance()->getLink('Conversation', array(
+               $this->canonicalURL = LinkHandler::getInstance()->getLink('Conversation', [
                        'object' => $this->conversation
-               ), ($this->pageNo ? 'pageNo=' . $this->pageNo : ''));
+               ], ($this->pageNo ? 'pageNo=' . $this->pageNo : ''));
        }
        
        /**
-        * @see \wcf\page\MultipleLinkPage::initObjectList()
+        * @inheritDoc
         */
        protected function initObjectList() {
                parent::initObjectList();
                
-               $this->objectList->getConditionBuilder()->add('conversation_message.conversationID = ?', array($this->conversation->conversationID));
+               $this->objectList->getConditionBuilder()->add('conversation_message.conversationID = ?', [$this->conversation->conversationID]);
                $this->objectList->setConversation($this->conversation->getDecoratedObject());
                
                // handle jump to
@@ -159,33 +161,35 @@ class ConversationPage extends MultipleLinkPage {
        }
        
        /**
-        * @see \wcf\page\IPage::readData()
+        * @inheritDoc
         */
        public function readData() {
                parent::readData();
                
                // add breadcrumbs
-               WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.conversation.conversations'), LinkHandler::getInstance()->getLink('ConversationList')));
                if ($this->conversation->isDraft) {
-                       WCF::getBreadcrumbs()->add(new Breadcrumb(WCF::getLanguage()->get('wcf.conversation.folder.draft'), LinkHandler::getInstance()->getLink('ConversationList', array(
-                               'filter' => 'draft'
-                       ))));
+                       // `-1` = pseudo object id to have to pages with identifier `com.woltlab.wcf.conversation.ConversationList`
+                       PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.conversation.ConversationList', -1, new ParentPageLocation(
+                               WCF::getLanguage()->get('wcf.conversation.folder.draft'),
+                               LinkHandler::getInstance()->getLink('ConversationList', ['filter' => 'draft'])
+                       ));
                }
+               PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.conversation.ConversationList');
                
                // update last visit time count
                if ($this->conversation->isNew() && $this->objectList->getMaxPostTime() > $this->conversation->lastVisitTime) {
                        $visitTime = $this->objectList->getMaxPostTime();
                        if ($visitTime == $this->conversation->lastPostTime) $visitTime = TIME_NOW;
-                       $conversationAction = new ConversationAction(array($this->conversation->getDecoratedObject()), 'markAsRead', array('visitTime' => $visitTime));
+                       $conversationAction = new ConversationAction([$this->conversation->getDecoratedObject()], 'markAsRead', ['visitTime' => $visitTime]);
                        $conversationAction->executeAction();
                }
                
                // get participants
-               $this->participantList = new ConversationParticipantList($this->conversationID, WCF::getUser()->userID, ($this->conversation->userID == WCF::getUser()->userID));
+               $this->participantList = new ConversationParticipantList($this->conversationID, WCF::getUser()->userID, $this->conversation->userID == WCF::getUser()->userID);
                $this->participantList->readObjects();
                
                // init quote objects
-               $messageIDs = array();
+               $messageIDs = [];
                foreach ($this->objectList as $message) {
                        $messageIDs[] = $message->messageID;
                }
@@ -193,10 +197,10 @@ class ConversationPage extends MultipleLinkPage {
                
                // set attachment permissions
                if ($this->objectList->getAttachmentList() !== null) {
-                       $this->objectList->getAttachmentList()->setPermissions(array(
+                       $this->objectList->getAttachmentList()->setPermissions([
                                'canDownload' => true,
                                'canViewPreview' => true
-                       ));
+                       ]);
                }
                
                // get timeframe for modifications
@@ -214,7 +218,7 @@ class ConversationPage extends MultipleLinkPage {
                                                        AND time > ?
                                        ORDER BY        time";
                                $statement = WCF::getDB()->prepareStatement($sql, 1);
-                               $statement->execute(array($this->conversationID, $this->objectList->current()->time));
+                               $statement->execute([$this->conversationID, $this->objectList->current()->time]);
                                $endTime = $statement->fetchSingleColumn() - 1;
                        }       
                }
@@ -222,12 +226,12 @@ class ConversationPage extends MultipleLinkPage {
                
                // load modification log entries
                $this->modificationLogList = new ConversationLogModificationLogList($this->conversation->conversationID);
-               $this->modificationLogList->getConditionBuilder()->add("modification_log.time BETWEEN ? AND ?", array($startTime, $endTime));
+               $this->modificationLogList->getConditionBuilder()->add("modification_log.time BETWEEN ? AND ?", [$startTime, $endTime]);
                $this->modificationLogList->readObjects();
        }
        
        /**
-        * @see \wcf\page\IPage::assignVariables()
+        * @inheritDoc
         */
        public function assignVariables() {
                parent::assignVariables();
@@ -237,7 +241,7 @@ class ConversationPage extends MultipleLinkPage {
                $tmpHash = StringUtil::getRandomID();
                $attachmentHandler = new AttachmentHandler('com.woltlab.wcf.conversation.message', 0, $tmpHash, 0);
                
-               WCF::getTPL()->assign(array(
+               WCF::getTPL()->assign([
                        'attachmentHandler' => $attachmentHandler,
                        'attachmentObjectID' => 0,
                        'attachmentObjectType' => 'com.woltlab.wcf.conversation.message',
@@ -250,11 +254,10 @@ class ConversationPage extends MultipleLinkPage {
                        'conversation' => $this->conversation,
                        'conversationID' => $this->conversationID,
                        'participants' => $this->participantList->getObjects(),
-                       'defaultSmilies' => SmileyCache::getInstance()->getCategorySmilies(),
-                       'permissionCanUseSmilies' => 'user.message.canUseSmilies'
-               ));
+                       'defaultSmilies' => SmileyCache::getInstance()->getCategorySmilies()
+               ]);
                
-               BBCodeHandler::getInstance()->setAllowedBBCodes(explode(',', WCF::getSession()->getPermission('user.message.allowedBBCodes')));
+               BBCodeHandler::getInstance()->setDisallowedBBCodes(explode(',', WCF::getSession()->getPermission('user.message.disallowedBBCodes')));
        }
        
        /**
@@ -262,7 +265,7 @@ class ConversationPage extends MultipleLinkPage {
         */
        protected function goToPost() {
                $conditionBuilder = clone $this->objectList->getConditionBuilder();
-               $conditionBuilder->add('time '.($this->sortOrder == 'ASC' ? '<=' : '>=').' ?', array($this->message->time));
+               $conditionBuilder->add('time '.($this->sortOrder == 'ASC' ? '<=' : '>=').' ?', [$this->message->time]);
                
                $sql = "SELECT  COUNT(*) AS messages
                        FROM    wcf".WCF_N."_conversation_message conversation_message
@@ -284,11 +287,11 @@ class ConversationPage extends MultipleLinkPage {
                $statement = WCF::getDB()->prepareStatement($sql, 1);
                $statement->execute($this->objectList->getConditionBuilder()->getParameters());
                $row = $statement->fetchArray();
-               HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Conversation', array(
+               HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Conversation', [
                        'encodeTitle' => true,
                        'object' => $this->conversation,
                        'messageID' => $row['messageID']
-               )).'#message'.$row['messageID']);
+               ]).'#message'.$row['messageID']);
                exit;
        }
        
@@ -297,7 +300,7 @@ class ConversationPage extends MultipleLinkPage {
         */
        protected function goToFirstNewPost() {
                $conditionBuilder = clone $this->objectList->getConditionBuilder();
-               $conditionBuilder->add('time > ?', array($this->conversation->lastVisitTime));
+               $conditionBuilder->add('time > ?', [$this->conversation->lastVisitTime]);
                
                $sql = "SELECT          conversation_message.messageID
                        FROM            wcf".WCF_N."_conversation_message conversation_message
@@ -307,29 +310,15 @@ class ConversationPage extends MultipleLinkPage {
                $statement->execute($conditionBuilder->getParameters());
                $row = $statement->fetchArray();
                if ($row !== false) {
-                       HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Conversation', array(
+                       HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Conversation', [
                                'encodeTitle' => true,
                                'object' => $this->conversation,
                                'messageID' => $row['messageID']
-                       )).'#message'.$row['messageID']);
+                       ]).'#message'.$row['messageID']);
                        exit;
                }
                else {
                        $this->goToLastPost();
                }
        }
-       
-       /**
-        * @see \wcf\page\ITrackablePage::getObjectType()
-        */
-       public function getObjectType() {
-               return 'com.woltlab.wcf.conversation';
-       }
-       
-       /**
-        * @see \wcf\page\ITrackablePage::getObjectID()
-        */
-       public function getObjectID() {
-               return $this->conversationID;
-       }
 }
index f30e6e80dcf33e13bfec3d413583309f2b37a9bc..a9a44c93afcd914318f07a6dd78c38ae6f7fb525 100644 (file)
@@ -10,36 +10,39 @@ use wcf\util\ArrayUtil;
  * Attachment object type implementation for conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.attachment
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Attachment
+ * 
+ * @method     ConversationMessage     getObject($objectID)
  */
 class ConversationMessageAttachmentObjectType extends AbstractAttachmentObjectType {
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\attachment\IAttachmentObjectType::getMaxSize()
+        * @inheritDoc
         */
        public function getMaxSize() {
                return WCF::getSession()->getPermission('user.conversation.maxAttachmentSize');
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\attachment\IAttachmentObjectType::getAllowedExtensions()
+        * @inheritDoc
         */
        public function getAllowedExtensions() {
                return ArrayUtil::trim(explode("\n", WCF::getSession()->getPermission('user.conversation.allowedAttachmentExtensions')));
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\attachment\IAttachmentObjectType::getMaxCount()
+        * @inheritDoc
         */
        public function getMaxCount() {
                return WCF::getSession()->getPermission('user.conversation.maxAttachmentCount');
        }
        
        /**
-        * @see \wcf\system\attachment\IAttachmentObjectType::canDownload()
+        * @inheritDoc
         */
        public function canDownload($objectID) {
                if ($objectID) {
@@ -52,7 +55,7 @@ class ConversationMessageAttachmentObjectType extends AbstractAttachmentObjectTy
        }
        
        /**
-        * @see \wcf\system\attachment\IAttachmentObjectType::canUpload()
+        * @inheritDoc
         */
        public function canUpload($objectID, $parentObjectID = 0) {
                if (!WCF::getSession()->getPermission('user.conversation.canUploadAttachment')) {
@@ -69,7 +72,7 @@ class ConversationMessageAttachmentObjectType extends AbstractAttachmentObjectTy
        }
        
        /**
-        * @see \wcf\system\attachment\IAttachmentObjectType::canDelete()
+        * @inheritDoc
         */
        public function canDelete($objectID) {
                if ($objectID) {
@@ -81,13 +84,13 @@ class ConversationMessageAttachmentObjectType extends AbstractAttachmentObjectTy
        }
        
        /**
-        * @see \wcf\system\attachment\IAttachmentObjectType::cacheObjects()
+        * @inheritDoc
         */
        public function cacheObjects(array $objectIDs) {
                $messageList = new ConversationMessageList();
                $messageList->setObjectIDs($objectIDs);
                $messageList->readObjects();
-               $conversationIDs = array();
+               $conversationIDs = [];
                foreach ($messageList as $message) {
                        $conversationIDs[] = $message->conversationID;
                }
@@ -103,17 +106,18 @@ class ConversationMessageAttachmentObjectType extends AbstractAttachmentObjectTy
                }
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\attachment\IAttachmentObjectType::setPermissions()
+        * @inheritDoc
         */
        public function setPermissions(array $attachments) {
-               $messageIDs = array();
+               $messageIDs = [];
                foreach ($attachments as $attachment) {
                        // set default permissions
-                       $attachment->setPermissions(array(
+                       $attachment->setPermissions([
                                'canDownload' => false,
                                'canViewPreview' => false
-                       ));
+                       ]);
                        
                        if ($this->getObject($attachment->objectID) === null) {
                                $messageIDs[] = $attachment->objectID;
@@ -128,16 +132,16 @@ class ConversationMessageAttachmentObjectType extends AbstractAttachmentObjectTy
                        if (($message = $this->getObject($attachment->objectID)) !== null) {
                                if (!$message->getConversation()->canRead()) continue;
                                
-                               $attachment->setPermissions(array(
+                               $attachment->setPermissions([
                                        'canDownload' => true,
                                        'canViewPreview' => true
-                               ));
+                               ]);
                        }
                        else if ($attachment->tmpHash != '' && $attachment->userID == WCF::getUser()->userID) {
-                               $attachment->setPermissions(array(
+                               $attachment->setPermissions([
                                        'canDownload' => true,
                                        'canViewPreview' => true
-                               ));
+                               ]);
                        }
                }
        }
diff --git a/files/lib/system/cache/runtime/ConversationRuntimeCache.class.php b/files/lib/system/cache/runtime/ConversationRuntimeCache.class.php
new file mode 100644 (file)
index 0000000..f49dc30
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+namespace wcf\system\cache\runtime;
+use wcf\data\conversation\Conversation;
+use wcf\data\conversation\ConversationList;
+
+/**
+ * Runtime cache implementation for conversations.
+ *
+ * @author     Matthias Schmidt
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Cache\Runtime
+ * @since      3.0
+ * 
+ * @method     Conversation[]          getCachedObjects()
+ * @method     Conversation            getObject($objectID)
+ * @method     Conversation[]          getObjects(array $objectIDs)
+ */
+class ConversationRuntimeCache extends AbstractRuntimeCache {
+       /**
+        * @inheritDoc
+        */
+       protected $listClassName = ConversationList::class;
+}
diff --git a/files/lib/system/cache/runtime/UserConversationRuntimeCache.class.php b/files/lib/system/cache/runtime/UserConversationRuntimeCache.class.php
new file mode 100644 (file)
index 0000000..fa6d1b4
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+namespace wcf\system\cache\runtime;
+use wcf\data\conversation\Conversation;
+use wcf\data\conversation\UserConversationList;
+use wcf\system\WCF;
+
+/**
+ * Runtime cache implementation for conversation fetched using UserConversationList.
+ *
+ * @author     Matthias Schmidt
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Cache\Runtime
+ * @since      3.0
+ * 
+ * @method     Conversation[]          getCachedObjects()
+ * @method     Conversation            getObject($objectID)
+ * @method     Conversation[]          getObjects(array $objectIDs)
+ */
+class UserConversationRuntimeCache extends AbstractRuntimeCache {
+       /**
+        * @inheritDoc
+        */
+       protected $listClassName = UserConversationList::class;
+       
+       /** @noinspection PhpMissingParentCallCommonInspection */
+       /**
+        * @inheritDoc
+        */
+       protected function getObjectList() {
+               return new UserConversationList(WCF::getUser()->userID);
+       }
+}
index 53daf3e6f4784ce4fc23fceb14c00201335e61d5..b58fd3e00bdfeeb58b8f9c0d21096d4b9fdde20f 100644 (file)
@@ -1,6 +1,8 @@
 <?php
 namespace wcf\system\clipboard\action;
 use wcf\data\clipboard\action\ClipboardAction;
+use wcf\data\conversation\Conversation;
+use wcf\data\conversation\ConversationAction;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\WCF;
 
@@ -8,31 +10,29 @@ use wcf\system\WCF;
  * Prepares clipboard editor items for conversations.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.clipboard.action
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Clipboard\Action
  */
 class ConversationClipboardAction extends AbstractClipboardAction {
        /**
-        * @see \wcf\system\clipboard\action\AbstractClipboardAction::$actionClassActions
+        * @inheritDoc
         */
-       protected $actionClassActions = array('close', 'markAsRead', 'open');
+       protected $actionClassActions = ['close', 'markAsRead', 'open'];
        
        /**
         * list of conversations
-        * @var array<\wcf\data\conversation\Conversation>
+        * @var Conversation[]
         */
-       public $conversations = null;
+       public $conversations;
        
        /**
-        * @see \wcf\system\clipboard\action\AbstractClipboardAction::$supportedActions
+        * @inheritDoc
         */
-       protected $supportedActions = array('assignLabel', 'close', 'leave', 'leavePermanently', 'markAsRead', 'open', 'restore');
+       protected $supportedActions = ['assignLabel', 'close', 'leave', 'leavePermanently', 'markAsRead', 'open', 'restore'];
        
        /**
-        * @see \wcf\system\clipboard\action\IClipboardAction::execute()
+        * @inheritDoc
         */
        public function execute(array $objects, ClipboardAction $action) {
                if ($this->conversations === null) {
@@ -58,7 +58,7 @@ class ConversationClipboardAction extends AbstractClipboardAction {
                                        FROM    wcf".WCF_N."_conversation_label
                                        WHERE   userID = ?";
                                $statement = WCF::getDB()->prepareStatement($sql);
-                               $statement->execute(array(WCF::getUser()->userID));
+                               $statement->execute([WCF::getUser()->userID]);
                                $row = $statement->fetchArray();
                                if ($row['count'] == 0) {
                                        return null;
@@ -68,14 +68,14 @@ class ConversationClipboardAction extends AbstractClipboardAction {
                        break;
                        
                        case 'leave':
-                               $item->addInternalData('parameters', array('hideConversation' => 1));
+                               $item->addInternalData('parameters', ['hideConversation' => 1]);
                                $item->addParameter('actionName', 'hideConversation');
                                $item->addParameter('className', $this->getClassName());
                        break;
                        
                        case 'leavePermanently':
                                $item->addParameter('objectIDs', array_keys($this->conversations));
-                               $item->addInternalData('parameters', array('hideConversation' => 2));
+                               $item->addInternalData('parameters', ['hideConversation' => 2]);
                                $item->addParameter('actionName', 'hideConversation');
                                $item->addParameter('className', $this->getClassName());
                        break;
@@ -84,13 +84,13 @@ class ConversationClipboardAction extends AbstractClipboardAction {
                                $item->addParameter('objectIDs', array_keys($this->conversations));
                                $item->addParameter('actionName', 'markAsRead');
                                $item->addParameter('className', $this->getClassName());
-                               $item->addInternalData('confirmMessage', WCF::getLanguage()->getDynamicVariable('wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.markAsRead.confirmMessage', array(
+                               $item->addInternalData('confirmMessage', WCF::getLanguage()->getDynamicVariable('wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.markAsRead.confirmMessage', [
                                        'count' => $item->getCount()
-                               )));
+                               ]));
                        break;
                        
                        case 'restore':
-                               $item->addInternalData('parameters', array('hideConversation' => 0));
+                               $item->addInternalData('parameters', ['hideConversation' => 0]);
                                $item->addParameter('actionName', 'hideConversation');
                                $item->addParameter('className', $this->getClassName());
                        break;
@@ -100,14 +100,14 @@ class ConversationClipboardAction extends AbstractClipboardAction {
        }
        
        /**
-        * @see \wcf\system\clipboard\action\IClipboardAction::getClassName()
+        * @inheritDoc
         */
        public function getClassName() {
-               return 'wcf\data\conversation\ConversationAction';
+               return ConversationAction::class;
        }
        
        /**
-        * @see \wcf\system\clipboard\action\IClipboardAction::getTypeName()
+        * @inheritDoc
         */
        public function getTypeName() {
                return 'com.woltlab.wcf.conversation.conversation';
@@ -116,11 +116,10 @@ class ConversationClipboardAction extends AbstractClipboardAction {
        /**
         * Returns a list of conversations with user participation.
         * 
-        * @param       array<\wcf\data\conversation\Conversation>
-        * @return      array<\wcf\data\conversation\Conversation>
+        * @param       Conversation[]          $conversations
         */
        protected function validateParticipation(array $conversations) {
-               $conversationIDs = array();
+               $conversationIDs = [];
                
                // validate ownership
                foreach ($conversations as $conversation) {
@@ -132,8 +131,8 @@ class ConversationClipboardAction extends AbstractClipboardAction {
                // validate participation as non-owner
                if (!empty($conversationIDs)) {
                        $conditions = new PreparedStatementConditionBuilder();
-                       $conditions->add("conversationID IN (?)", array($conversationIDs));
-                       $conditions->add("participantID = ?", array(WCF::getUser()->userID));
+                       $conditions->add("conversationID IN (?)", [$conversationIDs]);
+                       $conditions->add("participantID = ?", [WCF::getUser()->userID]);
                        
                        $sql = "SELECT  conversationID
                                FROM    wcf".WCF_N."_conversation_to_user
@@ -163,10 +162,10 @@ class ConversationClipboardAction extends AbstractClipboardAction {
        /**
         * Validates if user may close the given conversations.
         * 
-        * @return      array<integer>
+        * @return      integer[]
         */
        protected function validateClose() {
-               $conversationIDs = array();
+               $conversationIDs = [];
                
                foreach ($this->conversations as $conversation) {
                        if (!$conversation->isClosed && $conversation->userID == WCF::getUser()->userID) {
@@ -180,18 +179,18 @@ class ConversationClipboardAction extends AbstractClipboardAction {
        /**
         * Validates conversations available for leaving.
         * 
-        * @return      array<integer>
+        * @return      integer[]
         */
        public function validateLeave() {
-               $tmpIDs = array();
+               $tmpIDs = [];
                foreach ($this->conversations as $conversation) {
                        $tmpIDs[] = $conversation->conversationID;
                }
                
                $conditions = new PreparedStatementConditionBuilder();
-               $conditions->add("conversationID IN (?)", array($tmpIDs));
-               $conditions->add("participantID = ?", array(WCF::getUser()->userID));
-               $conditions->add("hideConversation <> ?", array(1));
+               $conditions->add("conversationID IN (?)", [$tmpIDs]);
+               $conditions->add("participantID = ?", [WCF::getUser()->userID]);
+               $conditions->add("hideConversation <> ?", [1]);
                
                $sql = "SELECT  conversationID
                        FROM    wcf".WCF_N."_conversation_to_user
@@ -199,32 +198,27 @@ class ConversationClipboardAction extends AbstractClipboardAction {
                $statement = WCF::getDB()->prepareStatement($sql);
                $statement->execute($conditions->getParameters());
                
-               $conversationIDs = array();
-               while ($row = $statement->fetchArray()) {
-                       $conversationIDs[] = $row['conversationID'];
-               }
-               
-               return $conversationIDs;
+               return $statement->fetchAll(\PDO::FETCH_COLUMN);
        }
        
        /**
         * Validates conversations applicable for mark as read.
         * 
-        * @return      array<integer>
+        * @return      integer[]
         */
        public function validateMarkAsRead() {
-               $conversationIDs = array();
+               $conversationIDs = [];
                
                $conditions = new PreparedStatementConditionBuilder();
-               $conditions->add("conversationID IN (?)", array(array_keys($this->conversations)));
-               $conditions->add("participantID = ?", array(WCF::getUser()->userID));
+               $conditions->add("conversationID IN (?)", [array_keys($this->conversations)]);
+               $conditions->add("participantID = ?", [WCF::getUser()->userID]);
                
                $sql = "SELECT  conversationID, lastVisitTime
                        FROM    wcf".WCF_N."_conversation_to_user
                        ".$conditions;
                $statement = WCF::getDB()->prepareStatement($sql);
                $statement->execute($conditions->getParameters());
-               $lastVisitTime = array();
+               $lastVisitTime = [];
                while ($row = $statement->fetchArray()) {
                        $lastVisitTime[$row['conversationID']] = $row['lastVisitTime'];
                }
@@ -241,10 +235,10 @@ class ConversationClipboardAction extends AbstractClipboardAction {
        /**
         * Validates if user may open the given conversations.
         * 
-        * @return      array<integer>
+        * @return      integer[]
         */
        protected function validateOpen() {
-               $conversationIDs = array();
+               $conversationIDs = [];
                
                foreach ($this->conversations as $conversation) {
                        if ($conversation->isClosed && $conversation->userID == WCF::getUser()->userID) {
@@ -258,18 +252,18 @@ class ConversationClipboardAction extends AbstractClipboardAction {
        /**
         * Validates conversations available for restore.
         * 
-        * @return      array<integer>
+        * @return      integer[]
         */
        public function validateRestore() {
-               $tmpIDs = array();
+               $tmpIDs = [];
                foreach ($this->conversations as $conversation) {
                        $tmpIDs[] = $conversation->conversationID;
                }
                
                $conditions = new PreparedStatementConditionBuilder();
-               $conditions->add("conversationID IN (?)", array($tmpIDs));
-               $conditions->add("participantID = ?", array(WCF::getUser()->userID));
-               $conditions->add("hideConversation <> ?", array(0));
+               $conditions->add("conversationID IN (?)", [$tmpIDs]);
+               $conditions->add("participantID = ?", [WCF::getUser()->userID]);
+               $conditions->add("hideConversation <> ?", [0]);
                
                $sql = "SELECT  conversationID
                        FROM    wcf".WCF_N."_conversation_to_user
@@ -277,11 +271,6 @@ class ConversationClipboardAction extends AbstractClipboardAction {
                $statement = WCF::getDB()->prepareStatement($sql);
                $statement->execute($conditions->getParameters());
                
-               $conversationIDs = array();
-               while ($row = $statement->fetchArray()) {
-                       $conversationIDs[] = $row['conversationID'];
-               }
-               
-               return $conversationIDs;
+               return $statement->fetchAll(\PDO::FETCH_COLUMN);
        }
 }
index ddb5b42b7cfd73ec0e4e64aca95b814f14bc6936..31b08ac7671da7315115c3923277465be0e65a49 100644 (file)
@@ -9,24 +9,22 @@ use wcf\system\WCF;
  * Handles the number of conversations and unread conversations of the active user.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.conversation
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Conversation
  */
 class ConversationHandler extends SingletonFactory {
        /**
         * number of unread conversations
-        * @var array<integer>
+        * @var integer[]
         */
-       protected $unreadConversationCount = array();
+       protected $unreadConversationCount = [];
        
        /**
         * number of conversations
-        * @var array<integer>
+        * @var integer[]
         */
-       protected $conversationCount = array();
+       protected $conversationCount = [];
        
        /**
         * Returns the number of unread conversations for given user.
@@ -42,16 +40,16 @@ class ConversationHandler extends SingletonFactory {
                        $this->unreadConversationCount[$userID] = 0;
                        
                        // load storage data
-                       UserStorageHandler::getInstance()->loadStorage(array($userID));
+                       UserStorageHandler::getInstance()->loadStorage([$userID]);
                        
                        // get ids
-                       $data = UserStorageHandler::getInstance()->getStorage(array($userID), 'unreadConversationCount');
+                       $data = UserStorageHandler::getInstance()->getStorage([$userID], 'unreadConversationCount');
                        
                        // cache does not exist or is outdated
                        if ($data[$userID] === null || $skipCache) {
                                $conditionBuilder = new PreparedStatementConditionBuilder();
                                $conditionBuilder->add('conversation.conversationID = conversation_to_user.conversationID');
-                               $conditionBuilder->add('conversation_to_user.participantID = ?', array($userID));
+                               $conditionBuilder->add('conversation_to_user.participantID = ?', [$userID]);
                                $conditionBuilder->add('conversation_to_user.hideConversation = 0');
                                $conditionBuilder->add('conversation_to_user.lastVisitTime < conversation.lastPostTime');
                                
@@ -88,18 +86,18 @@ class ConversationHandler extends SingletonFactory {
                        $this->conversationCount[$userID] = 0;
                        
                        // load storage data
-                       UserStorageHandler::getInstance()->loadStorage(array($userID));
+                       UserStorageHandler::getInstance()->loadStorage([$userID]);
                        
                        // get ids
-                       $data = UserStorageHandler::getInstance()->getStorage(array($userID), 'conversationCount');
+                       $data = UserStorageHandler::getInstance()->getStorage([$userID], 'conversationCount');
                        
                        // cache does not exist or is outdated
                        if ($data[$userID] === null) {
                                $conditionBuilder1 = new PreparedStatementConditionBuilder();
-                               $conditionBuilder1->add('conversation_to_user.participantID = ?', array($userID));
+                               $conditionBuilder1->add('conversation_to_user.participantID = ?', [$userID]);
                                $conditionBuilder1->add('conversation_to_user.hideConversation IN (0,1)');
                                $conditionBuilder2 = new PreparedStatementConditionBuilder();
-                               $conditionBuilder2->add('conversation.userID = ?', array($userID));
+                               $conditionBuilder2->add('conversation.userID = ?', [$userID]);
                                $conditionBuilder2->add('conversation.isDraft = 1');
                                
                                $sql = "SELECT (SELECT  COUNT(*)
index bdc02be4d31048cafabe2059b4a8dcba63ea6e75..14a630a774f1fc6193ee2677454b0db314ce71ea 100644 (file)
@@ -1,50 +1,25 @@
 <?php
 namespace wcf\system\event\listener;
-use wcf\system\WCF;
 
 /**
- * Updates the stored username on user rename.
+ * Updates the stored username during user rename.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.event.listener
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Event\Listener
  */
-class ConversationUserActionRenameListener implements IParameterizedEventListener {
+class ConversationUserActionRenameListener extends AbstractUserActionRenameListener {
        /**
-        * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
+        * @inheritDoc
         */
-       public function execute($eventObj, $className, $eventName, array &$parameters) {
-               $objects = $eventObj->getObjects();
-               $userID = $objects[0]->userID;
-               
-               $actionParameters = $eventObj->getParameters();
-               $username = $actionParameters['data']['username'];
-               
-               WCF::getDB()->beginTransaction();
-               
-               // conversations
-               $sql = "UPDATE  wcf".WCF_N."_conversation
-                       SET     username = ?
-                       WHERE   userID = ?";
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array($username, $userID));
-               
-               $sql = "UPDATE  wcf".WCF_N."_conversation
-                       SET     lastPoster = ?
-                       WHERE   lastPosterID = ?";
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array($username, $userID));
-               
-               // conversation messages
-               $sql = "UPDATE  wcf".WCF_N."_conversation_message
-                       SET     username = ?
-                       WHERE   userID = ?";
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array($username, $userID));
-               
-               WCF::getDB()->commitTransaction();
-       }
+       protected $databaseTables = [
+               'wcf{WCF_N}_conversation',
+               'wcf{WCF_N}_conversation_message',
+               [
+                       'name' => 'wcf{WCF_N}_conversation',
+                       'userID' => 'lastPosterID',
+                       'username' => 'lastPoster'
+               ]
+       ];
 }
index e19c0555c5424d2aa483c2e0d490888ae7e64623..234ccfc5cee4df4b7d1cb8cf6e6e5fd31cc5ea2b 100644 (file)
@@ -1,70 +1,30 @@
 <?php
 namespace wcf\system\event\listener;
-use wcf\system\database\util\PreparedStatementConditionBuilder;
-use wcf\system\WCF;
 
 /**
  * Merges user conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.event.listener
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Event\Listener
  */
-class ConversationUserMergeListener implements IParameterizedEventListener {
+class ConversationUserMergeListener extends AbstractUserMergeListener {
        /**
-        * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
+        * @inheritDoc
         */
-       public function execute($eventObj, $className, $eventName, array &$parameters) {
-               $conditions = new PreparedStatementConditionBuilder();
-               $conditions->add("userID IN (?)", array($eventObj->mergedUserIDs));
-               $parameters = array_merge(array(
-                       $eventObj->destinationUserID,
-                       $eventObj->users[$eventObj->destinationUserID]->username
-               ), $conditions->getParameters());
-               
-               // conversation
-               $sql = "UPDATE  wcf".WCF_N."_conversation
-                       SET     userID = ?,
-                               username = ?
-                       ".$conditions;
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute($parameters);
-               
-               $participantConditions = new PreparedStatementConditionBuilder();
-               $participantConditions->add("lastPosterID IN (?)", array($eventObj->mergedUserIDs));
-               $sql = "UPDATE  wcf".WCF_N."_conversation
-                       SET     lastPosterID = ?,
-                               lastPoster = ?
-                       ".$participantConditions;
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute($parameters); // can still use $parameters, even though $participantConditions != $conditions
-               
-               // conversation_to_user
-               $participantConditions = new PreparedStatementConditionBuilder();
-               $participantConditions->add("participantID IN (?)", array($eventObj->mergedUserIDs));
-               $sql = "UPDATE IGNORE   wcf".WCF_N."_conversation_to_user
-                       SET             participantID = ?,
-                                       username = ?
-                       ".$participantConditions;
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute($parameters); // can still use $parameters, even though $participantConditions != $conditions
-               
-               // conversation_message
-               $sql = "UPDATE  wcf".WCF_N."_conversation_message
-                       SET     userID = ?,
-                               username = ?
-                       ".$conditions;
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute($parameters);
-               
-               // conversation_label
-               $sql = "UPDATE  wcf".WCF_N."_conversation_label
-                       SET     userID = ?
-                       ".$conditions;
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array_merge(array($eventObj->destinationUserID), $conditions->getParameters()));
-       }
+       protected $databaseTables = [
+               'wcf{WCF_N}_conversation',
+               'wcf{WCF_N}_conversation_message',
+               [
+                       'name' => 'wcf{WCF_N}_conversation_label',
+                       'username' => null
+               ],
+               [
+                       'name' => 'wcf{WCF_N}_conversation_to_user',
+                       'userID' => 'participantID',
+                       'username' => null,
+                       'ignore' => true
+               ]
+       ];
 }
index 10419ee100d73dbe4e5a552eafcf6f3944fa717e..13da950704d3b525afc3331a219e7106889d0683 100644 (file)
@@ -8,11 +8,9 @@ use wcf\data\object\type\ObjectTypeCache;
  * Imports conversation attachments.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.importer
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Importer
  */
 class ConversationAttachmentImporter extends AbstractAttachmentImporter {
        /**
@@ -24,9 +22,9 @@ class ConversationAttachmentImporter extends AbstractAttachmentImporter {
        }
        
        /**
-        * @see \wcf\system\importer\IImporter::import()
+        * @inheritDoc
         */
-       public function import($oldID, array $data, array $additionalData = array()) {
+       public function import($oldID, array $data, array $additionalData = []) {
                $data['objectID'] = ImportHandler::getInstance()->getNewID('com.woltlab.wcf.conversation.message', $data['objectID']);
                if (!$data['objectID']) return 0;
                
@@ -37,9 +35,9 @@ class ConversationAttachmentImporter extends AbstractAttachmentImporter {
                        
                        if (($newMessage = $this->fixEmbeddedAttachments($messageObj->message, $oldID, $attachmentID)) !== false) {
                                $editor = new ConversationMessageEditor($messageObj);
-                               $editor->update(array(
+                               $editor->update([
                                        'message' => $newMessage
-                               ));
+                               ]);
                        }
                }
                
index 4b407838c136dbc671158c22f527e59c97f15153..432662d4fbbaef314436ffb4aab2338b6d8c097f 100644 (file)
@@ -7,22 +7,20 @@ use wcf\data\conversation\ConversationEditor;
  * Imports conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.importer
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Importer
  */
 class ConversationImporter extends AbstractImporter {
        /**
-        * @see \wcf\system\importer\AbstractImporter::$className
+        * @inheritDoc
         */
-       protected $className = 'wcf\data\conversation\Conversation';
+       protected $className = Conversation::class;
        
        /**
-        * @see \wcf\system\importer\IImporter::import()
+        * @inheritDoc
         */
-       public function import($oldID, array $data, array $additionalData = array()) {
+       public function import($oldID, array $data, array $additionalData = []) {
                $oldUserID = $data['userID'];
                $data['userID'] = ImportHandler::getInstance()->getNewID('com.woltlab.wcf.user', $data['userID']);
                
@@ -38,14 +36,14 @@ class ConversationImporter extends AbstractImporter {
                
                // add author
                if (empty($data['isDraft'])) {
-                       ImportHandler::getInstance()->getImporter('com.woltlab.wcf.conversation.user')->import(0, array(
+                       ImportHandler::getInstance()->getImporter('com.woltlab.wcf.conversation.user')->import(0, [
                                'conversationID' => $oldID,
                                'participantID' => $oldUserID,
                                'username' => $data['username'],
                                'hideConversation' => 0,
                                'isInvisible' => 0,
                                'lastVisitTime' => $data['time']
-                       ), array('labelIDs' => array()));
+                       ], ['labelIDs' => []]);
                }
                
                return $conversation->conversationID;
index bd8c5470876b1fb74c353cff130768a44cca2e70..4310e2f3dc8295990fbfe4fc9260348cc9081f4f 100644 (file)
@@ -1,33 +1,32 @@
 <?php
 namespace wcf\system\importer;
+use wcf\data\conversation\label\ConversationLabel;
 use wcf\data\conversation\label\ConversationLabelAction;
 
 /**
  * Imports conversation labels.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.importer
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Importer
  */
 class ConversationLabelImporter extends AbstractImporter {
        /**
-        * @see \wcf\system\importer\AbstractImporter::$className
+        * @inheritDoc
         */
-       protected $className = 'wcf\data\conversation\label\ConversationLabel';
+       protected $className = ConversationLabel::class;
        
        /**
-        * @see \wcf\system\importer\IImporter::import()
+        * @inheritDoc
         */
-       public function import($oldID, array $data, array $additionalData = array()) {
+       public function import($oldID, array $data, array $additionalData = []) {
                $data['userID'] = ImportHandler::getInstance()->getNewID('com.woltlab.wcf.user', $data['userID']);
                if (!$data['userID']) return 0;
                
-               $action = new ConversationLabelAction(array(), 'create', array(
+               $action = new ConversationLabelAction([], 'create', [
                        'data' => $data
-               ));
+               ]);
                $returnValues = $action->executeAction();
                $newID = $returnValues['returnValues']->labelID;
                
index 3d53129ce301d3a05f59560a6a5b03282bed0ae6..e1ace45b9d912f8cd10990bf8e42240b52744f09 100644 (file)
@@ -7,22 +7,20 @@ use wcf\data\conversation\message\ConversationMessageEditor;
  * Imports conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.importer
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Importer
  */
 class ConversationMessageImporter extends AbstractImporter {
        /**
-        * @see \wcf\system\importer\AbstractImporter::$className
+        * @inheritDoc
         */
-       protected $className = 'wcf\data\conversation\message\ConversationMessage';
+       protected $className = ConversationMessage::class;
        
        /**
-        * @see \wcf\system\importer\IImporter::import()
+        * @inheritDoc
         */
-       public function import($oldID, array $data, array $additionalData = array()) {
+       public function import($oldID, array $data, array $additionalData = []) {
                $data['conversationID'] = ImportHandler::getInstance()->getNewID('com.woltlab.wcf.conversation', $data['conversationID']);
                if (!$data['conversationID']) return 0;
                $data['userID'] = ImportHandler::getInstance()->getNewID('com.woltlab.wcf.user', $data['userID']);
index af403a90cf5a7fb46d37bf2131827ca783d80be6..8f3daae69a1c984c985fabae5f16d4e42985d540 100644 (file)
@@ -6,17 +6,15 @@ use wcf\system\WCF;
  * Imports conversation users.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.importer
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Importer
  */
 class ConversationUserImporter extends AbstractImporter {
        /**
-        * @see \wcf\system\importer\IImporter::import()
+        * @inheritDoc
         */
-       public function import($oldID, array $data, array $additionalData = array()) {
+       public function import($oldID, array $data, array $additionalData = []) {
                $data['conversationID'] = ImportHandler::getInstance()->getNewID('com.woltlab.wcf.conversation', $data['conversationID']);
                if (!$data['conversationID']) return 0;
                $data['participantID'] = ImportHandler::getInstance()->getNewID('com.woltlab.wcf.user', $data['participantID']);
@@ -28,14 +26,14 @@ class ConversationUserImporter extends AbstractImporter {
                                                        isInvisible = IF(isInvisible AND VALUES(isInvisible),1,0),
                                                        lastVisitTime = GREATEST(lastVisitTime,VALUES(lastVisitTime))";
                $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute(array(
+               $statement->execute([
                        $data['conversationID'],
                        $data['participantID'],
                        $data['username'],
                        $data['hideConversation'],
                        $data['isInvisible'],
                        $data['lastVisitTime']
-               ));
+               ]);
                
                // save labels
                if ($data['participantID'] && !empty($additionalData['labelIDs'])) {
@@ -45,7 +43,7 @@ class ConversationUserImporter extends AbstractImporter {
                        $statement = WCF::getDB()->prepareStatement($sql);
                        foreach ($additionalData['labelIDs'] as $labelID) {
                                $labelID = ImportHandler::getInstance()->getNewID('com.woltlab.wcf.conversation.label', $labelID);
-                               if ($labelID) $statement->execute(array($labelID, $data['conversationID']));
+                               if ($labelID) $statement->execute([$labelID, $data['conversationID']]);
                        }
                }
                
index b6ed2c0a2007d508f0d3a493aa9e6072ad8e2232..0e9de623e8710d9867126ed0a58a7458d6a20259 100644 (file)
@@ -8,40 +8,43 @@ use wcf\data\user\UserList;
  * Handles conversation modification logs.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.log.modification
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Log\Modification
  */
-class ConversationModificationLogHandler extends ModificationLogHandler {
+class ConversationModificationLogHandler extends AbstractModificationLogHandler {
+       /**
+        * @inheritDoc
+        */
+       protected $objectTypeName = 'com.woltlab.wcf.conversation.conversation';
+       
        /**
         * Adds a log entry for newly added conversation participants.
         * 
-        * @param       \wcf\data\conversation\Conversation     $conversation
-        * @param       array<integer>                          $participantIDs
+        * @param       Conversation    $conversation
+        * @param       integer[]       $participantIDs
         */
        public function addParticipants(Conversation $conversation, array $participantIDs) {
-               $participants = array();
+               $participants = [];
                $userList = new UserList();
                $userList->setObjectIDs($participantIDs);
                $userList->readObjects();
                foreach ($userList as $user) {
-                       $participants[] = array(
+                       $participants[] = [
                                'userID' => $user->userID,
                                'username' => $user->username
-                       );
+                       ];
                }
                
-               $this->add($conversation, 'addParticipants', array(
+               $this->add($conversation, 'addParticipants', [
                        'participants' => $participants
-               ));
+               ]);
        }
        
        /**
         * Adds a log entry for conversation close.
         * 
-        * @param       \wcf\data\conversation\Conversation     $conversation
+        * @param       Conversation    $conversation
         */
        public function close(Conversation $conversation) {
                $this->add($conversation, 'close');
@@ -50,7 +53,7 @@ class ConversationModificationLogHandler extends ModificationLogHandler {
        /**
         * Adds a log entry for conversation open.
         * 
-        * @param       \wcf\data\conversation\Conversation     $conversation
+        * @param       Conversation    $conversation
         */
        public function open(Conversation $conversation) {
                $this->add($conversation, 'open');
@@ -59,7 +62,7 @@ class ConversationModificationLogHandler extends ModificationLogHandler {
        /**
         * Adds a log entry for conversation leave.
         * 
-        * @param       \wcf\data\conversation\Conversation     $conversation
+        * @param       Conversation    $conversation
         */
        public function leave(Conversation $conversation) {
                $this->add($conversation, 'leave');
@@ -68,35 +71,36 @@ class ConversationModificationLogHandler extends ModificationLogHandler {
        /**
         * Adds a log entry for a removed participant.
         * 
-        * @param       \wcf\data\conversation\Conversation     $conversation
-        * @param       integer                                 $userID
+        * @param       Conversation    $conversation
+        * @param       integer         $userID
         */
        public function removeParticipant(Conversation $conversation, $userID) {
                $user = new User($userID);
-               $this->add($conversation, 'removeParticipant', array(
+               $this->add($conversation, 'removeParticipant', [
                        'userID' => $userID,
                        'username' => $user->username
-               ));
+               ]);
        }
        
        /**
         * Adds a conversation modification log entry.
         * 
-        * @param       \wcf\data\conversation\Conversation     $conversation
-        * @param       string                                  $action
-        * @param       array                                   $additionalData
+        * @param       Conversation    $conversation
+        * @param       string          $action
+        * @param       array           $additionalData
         */
-       public function add(Conversation $conversation, $action, array $additionalData = array()) {
-               parent::_add('com.woltlab.wcf.conversation.conversation', $conversation->conversationID, $action, $additionalData);
+       public function add(Conversation $conversation, $action, array $additionalData = []) {
+               $this->createLog($action, $conversation->conversationID, null, $additionalData);
        }
        
        /**
         * Removes the conversation log entries of the conversations with the given
         * ids.
         * 
-        * @param       array<integer>          $objectIDs
+        * @param       integer[]       $objectIDs
+        * @deprecated  3.0, use deleteLogs()
         */
        public function remove(array $objectIDs) {
-               parent::_remove('com.woltlab.wcf.conversation.conversation', $objectIDs);
+               $this->deleteLogs($objectIDs);
        }
 }
index eddd09fd6368ee3e7354d5e615f51d2bf035715c..df7360d31056be086d7b7f7cfefda4cd7c39967a 100644 (file)
@@ -7,34 +7,32 @@ use wcf\data\conversation\ConversationList;
  * IMessageQuoteHandler implementation for conversation messages.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.message.quote
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Message\Quote
  */
 class ConversationMessageQuoteHandler extends AbstractMessageQuoteHandler {
        /**
-        * @see \wcf\system\message\quote\AbstractMessageQuoteHandler::getMessages()
+        * @inheritDoc
         */
        protected function getMessages(array $data) {
                // read messages
                $messageList = new ConversationMessageList();
-               $messageList->getConditionBuilder()->add("conversation_message.messageID IN (?)", array(array_keys($data)));
+               $messageList->setObjectIDs(array_keys($data));
                $messageList->readObjects();
                $messages = $messageList->getObjects();
                
                // read conversations
-               $conversationIDs = $validMessageIDs = array();
+               $conversationIDs = $validMessageIDs = [];
                foreach ($messages as $message) {
                        $conversationIDs[] = $message->conversationID;
                        $validMessageIDs[] = $message->messageID;
                }
                
-               $quotedMessages = array();
+               $quotedMessages = [];
                if (!empty($conversationIDs)) {
                        $conversationList = new ConversationList();
-                       $conversationList->getConditionBuilder()->add("conversation.conversationID IN (?)", array($conversationIDs));
+                       $conversationList->setObjectIDs($conversationIDs);
                        $conversationList->readObjects();
                        $conversations = $conversationList->getObjects();
                        
@@ -57,7 +55,7 @@ class ConversationMessageQuoteHandler extends AbstractMessageQuoteHandler {
                
                // check for orphaned quotes
                if (count($validMessageIDs) != count($data)) {
-                       $orphanedQuoteIDs = array();
+                       $orphanedQuoteIDs = [];
                        foreach ($data as $messageID => $quoteIDs) {
                                if (!in_array($messageID, $validMessageIDs)) {
                                        foreach (array_keys($quoteIDs) as $quoteID) {
index c291cfa6f21c7a001c62d61556b0de6dd33b459f..b78ce908da8489658a04079dcf57c23b78d4b732 100644 (file)
@@ -16,44 +16,42 @@ use wcf\system\WCF;
  * An implementation of IModerationQueueReportHandler for conversation messages.
  * 
  * @author     Alexander Ebert
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.moderation.queue
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Moderation\Queue
  */
 class ConversationMessageModerationQueueReportHandler extends AbstractModerationQueueHandler implements IModerationQueueReportHandler {
        /**
-        * @see \wcf\system\moderation\queue\AbstractModerationQueueHandler::$className
+        * @inheritDoc
         */
-       protected $className = 'wcf\data\conversation\message\ConversationMessage';
+       protected $className = ConversationMessage::class;
        
        /**
-        * @see \wcf\system\moderation\queue\AbstractModerationQueueHandler::$definitionName
+        * @inheritDoc
         */
        protected $definitionName = 'com.woltlab.wcf.moderation.report';
        
        /**
-        * @see \wcf\system\moderation\queue\AbstractModerationQueueHandler::$objectType
+        * @inheritDoc
         */
        protected $objectType = 'com.woltlab.wcf.conversation.message';
        
        /**
         * list of conversation message
-        * @var array<\wcf\data\conversation\message\ConversationMessage>
+        * @var ConversationMessage[]
         */
-       protected static $messages = array();
+       protected static $messages = [];
        
        /**
-        * @see \wcf\system\moderation\queue\AbstractModerationQueueHandler::$requiredPermission
+        * @inheritDoc
         */
        protected $requiredPermission = 'mod.conversation.canModerateConversation';
        
        /**
-        * @see \wcf\system\moderation\queue\IModerationQueueHandler::assignQueues()
+        * @inheritDoc
         */
        public function assignQueues(array $queues) {
-               $assignments = array();
+               $assignments = [];
                foreach ($queues as $queue) {
                        $assignUser = false;
                        if (WCF::getSession()->getPermission('mod.conversation.canModerateConversation')) {
@@ -67,14 +65,14 @@ class ConversationMessageModerationQueueReportHandler extends AbstractModeration
        }
        
        /**
-        * @see \wcf\system\moderation\queue\report\IModerationQueueReportHandler::canReport()
+        * @inheritDoc
         */
        public function canReport($objectID) {
                if (!$this->isValid($objectID)) {
                        return false;
                }
                
-               if (!Conversation::isParticipant(array($this->getMessage($objectID)->conversationID))) {
+               if (!Conversation::isParticipant([$this->getMessage($objectID)->conversationID])) {
                        return false;
                }
                
@@ -82,25 +80,26 @@ class ConversationMessageModerationQueueReportHandler extends AbstractModeration
        }
        
        /**
-        * @see \wcf\system\moderation\queue\IModerationQueueHandler::getContainerID()
+        * @inheritDoc
         */
        public function getContainerID($objectID) {
                return 0;
        }
        
        /**
-        * @see \wcf\system\moderation\queue\report\IModerationQueueReportHandler::getReportedContent()
+        * @inheritDoc
         */
        public function getReportedContent(ViewableModerationQueue $queue) {
-               WCF::getTPL()->assign(array(
-                       'message' => ViewableConversationMessage::getViewableConversationMessage($queue->getAffectedObject()->messageID)
-               ));
+               /** @noinspection PhpParamsInspection */
+               WCF::getTPL()->assign([
+                       'message' => new ViewableConversationMessage($queue->getAffectedObject())
+               ]);
                
                return WCF::getTPL()->fetch('moderationConversationMessage');
        }
        
        /**
-        * @see \wcf\system\moderation\queue\report\IModerationQueueReportHandler::getReportedObject()
+        * @inheritDoc
         */
        public function getReportedObject($objectID) {
                if ($this->isValid($objectID)) {
@@ -111,7 +110,7 @@ class ConversationMessageModerationQueueReportHandler extends AbstractModeration
        }
        
        /**
-        * @see \wcf\system\moderation\queue\IModerationQueueHandler::isValid()
+        * @inheritDoc
         */
        public function isValid($objectID) {
                if ($this->getMessage($objectID) === null) {
@@ -125,7 +124,7 @@ class ConversationMessageModerationQueueReportHandler extends AbstractModeration
         * Returns a conversation message object by message id or null if message id is invalid.
         * 
         * @param       integer         $objectID
-        * @return      \wcf\data\conversation\message\ConversationMessage
+        * @return      ConversationMessage
         */
        protected function getMessage($objectID) {
                if (!array_key_exists($objectID, self::$messages)) {
@@ -139,10 +138,10 @@ class ConversationMessageModerationQueueReportHandler extends AbstractModeration
        }
        
        /**
-        * @see \wcf\system\moderation\queue\IModerationQueueHandler::populate()
+        * @inheritDoc
         */
        public function populate(array $queues) {
-               $objectIDs = array();
+               $objectIDs = [];
                foreach ($queues as $object) {
                        $objectIDs[] = $object->objectID;
                }
@@ -161,7 +160,7 @@ class ConversationMessageModerationQueueReportHandler extends AbstractModeration
                }
                
                // fetch conversations
-               $conversationIDs = array();
+               $conversationIDs = [];
                foreach ($messages as $message) {
                        $conversationIDs[] = $message->conversationID;
                }
@@ -184,11 +183,11 @@ class ConversationMessageModerationQueueReportHandler extends AbstractModeration
        }
        
        /**
-        * @see \wcf\system\moderation\queue\IModerationQueueHandler::removeContent()
+        * @inheritDoc
         */
        public function removeContent(ModerationQueue $queue, $message) {
                if ($this->isValid($queue->objectID)) {
-                       $messageAction = new ConversationMessageAction(array($this->getMessage($queue->objectID)), 'delete');
+                       $messageAction = new ConversationMessageAction([$this->getMessage($queue->objectID)], 'delete');
                        $messageAction->executeAction();
                }
        }
diff --git a/files/lib/system/page/handler/ConversationListPageHandler.class.php b/files/lib/system/page/handler/ConversationListPageHandler.class.php
new file mode 100644 (file)
index 0000000..1b4fb77
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+namespace wcf\system\page\handler;
+use wcf\system\conversation\ConversationHandler;
+use wcf\system\WCF;
+
+/**
+ * Page handler implementation for the conversation list.
+ *
+ * @author     Matthias Schmidt
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Page\Handler
+ * @since      3.0
+ */
+class ConversationListPageHandler extends AbstractMenuPageHandler {
+       /** @noinspection PhpMissingParentCallCommonInspection */
+       /**
+        * @inheritDoc
+        */
+       public function getOutstandingItemCount($objectID = null) {
+               return ConversationHandler::getInstance()->getUnreadConversationCount();
+       }
+       
+       /** @noinspection PhpMissingParentCallCommonInspection */
+       /**
+        * @inheritDoc
+        */
+       public function isVisible($objectID = null) {
+               return WCF::getUser()->userID != 0;
+       }
+}
diff --git a/files/lib/system/page/handler/DefaultConversationRelatedPageHandler.class.php b/files/lib/system/page/handler/DefaultConversationRelatedPageHandler.class.php
new file mode 100644 (file)
index 0000000..e12843e
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+namespace wcf\system\page\handler;
+
+/**
+ * Default implementation of a board-related page handler.
+ * 
+ * Only use this class when you need the online location handling for a board-related page.
+ *
+ * @author     Matthias Schmidt
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Page\Handler
+ * @since      3.0
+ */
+class DefaultConversationRelatedPageHandler extends AbstractMenuPageHandler implements IOnlineLocationPageHandler {
+       use TConversationOnlineLocationPageHandler;
+}
diff --git a/files/lib/system/page/handler/TConversationOnlineLocationPageHandler.class.php b/files/lib/system/page/handler/TConversationOnlineLocationPageHandler.class.php
new file mode 100644 (file)
index 0000000..1d0eafc
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+namespace wcf\system\page\handler;
+use wcf\data\page\Page;
+use wcf\data\user\online\UserOnline;
+use wcf\system\cache\runtime\UserConversationRuntimeCache;
+use wcf\system\WCF;
+
+/**
+ * Implementation of the online location-related page handler methods for conversations.
+ * 
+ * @author     Matthias Schmidt
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Page\Handler
+ * @since      3.0
+ */
+trait TConversationOnlineLocationPageHandler {
+       use TOnlineLocationPageHandler;
+       
+       /**
+        * Returns the textual description if a user is currently online viewing this page.
+        *
+        * @see IOnlineLocationPageHandler::getOnlineLocation()
+        *
+        * @param       Page            $page           visited page
+        * @param       UserOnline      $user           user online object with request data
+        * @return      string
+        */
+       public function getOnlineLocation(Page $page, UserOnline $user) {
+               if ($user->pageObjectID === null) {
+                       return '';
+               }
+               
+               $conversation = UserConversationRuntimeCache::getInstance()->getObject($user->pageObjectID);
+               if ($conversation === null || !$conversation->canRead()) {
+                       return '';
+               }
+               
+               return WCF::getLanguage()->getDynamicVariable('wcf.page.onlineLocation.'.$page->identifier, ['conversation' => $conversation]);
+       }
+       
+       /**
+        * Prepares fetching all necessary data for the textual description if a user is currently online
+        * viewing this page.
+        *
+        * @see IOnlineLocationPageHandler::prepareOnlineLocation()
+        *
+        * @param       Page            $page           visited page
+        * @param       UserOnline      $user           user online object with request data
+        */
+       public function prepareOnlineLocation(/** @noinspection PhpUnusedParameterInspection */Page $page, UserOnline $user) {
+               if ($user->pageObjectID !== null) {
+                       UserConversationRuntimeCache::getInstance()->cacheObjectID($user->pageObjectID);
+               }
+       }
+}
index 624824321dd685d270f6d115aaa8b60818280ae2..c50ac29154db85d8533f3c703e1247d057537016 100644 (file)
@@ -1,7 +1,10 @@
 <?php
 namespace wcf\system\search;
+use wcf\data\conversation\message\SearchResultConversationMessage;
 use wcf\data\conversation\message\SearchResultConversationMessageList;
+use wcf\data\conversation\Conversation;
 use wcf\form\IForm;
+use wcf\form\SearchForm;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\WCF;
 
@@ -9,82 +12,147 @@ use wcf\system\WCF;
  * An implementation of ISearchableObjectType for searching in conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.search
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Search
  */
 class ConversationMessageSearch extends AbstractSearchableObjectType {
+       /**
+        * id of the searched conversation
+        * @var integer
+        */
+       public $conversationID = 0;
+       
+       /**
+        * searched conversation
+        * @var Conversation
+        */
+       public $conversation;
+       
        /**
         * message data cache
-        * @var array<\wcf\data\conversation\message\SearchResultConversationMessage>
+        * @var SearchResultConversationMessage[]
         */
-       public $messageCache = array();
+       public $messageCache = [];
        
        /**
-        * @see \wcf\system\search\ISearchableObjectType::cacheObjects()
+        * @inheritDoc
         */
        public function cacheObjects(array $objectIDs, array $additionalData = null) {
                $messageList = new SearchResultConversationMessageList();
-               $messageList->getConditionBuilder()->add('conversation_message.messageID IN (?)', array($objectIDs));
+               $messageList->setObjectIDs($objectIDs);
                $messageList->readObjects();
                foreach ($messageList->getObjects() as $message) {
                        $this->messageCache[$message->messageID] = $message;
                }
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\search\ISearchableObjectType::getObject()
+        * @inheritDoc
+        */
+       public function getAdditionalData() {
+               return [
+                       'conversationID' => $this->conversationID
+               ];
+       }
+       
+       /**
+        * @inheritDoc
         */
        public function getObject($objectID) {
                if (isset($this->messageCache[$objectID])) return $this->messageCache[$objectID];
                return null;
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\search\ISearchableObjectType::getJoins()
+        * @inheritDoc
         */
        public function getJoins() {
                return "JOIN wcf".WCF_N."_conversation_to_user conversation_to_user ON (conversation_to_user.participantID = ".WCF::getUser()->userID." AND conversation_to_user.conversationID = ".$this->getTableName().".conversationID)
-               LEFT JOIN wcf".WCF_N."_conversation conversation ON (conversation.conversationID = ".$this->getTableName().".conversationID)";
+                       LEFT JOIN wcf".WCF_N."_conversation conversation ON (conversation.conversationID = ".$this->getTableName().".conversationID)";
        }
        
        /**
-        * @see \wcf\system\search\ISearchableObjectType::getTableName()
+        * @inheritDoc
         */
        public function getTableName() {
                return 'wcf'.WCF_N.'_conversation_message';
        }
        
        /**
-        * @see \wcf\system\search\ISearchableObjectType::getIDFieldName()
+        * @inheritDoc
         */
        public function getIDFieldName() {
                return $this->getTableName().'.messageID';
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\search\ISearchableObjectType::getSubjectFieldName()
+        * @inheritDoc
         */
        public function getSubjectFieldName() {
                return 'conversation.subject';
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\search\ISearchableObjectType::getConditions()
+        * @inheritDoc
         */
        public function getConditions(IForm $form = null) {
                $conditionBuilder = new PreparedStatementConditionBuilder();
                $conditionBuilder->add('conversation_to_user.hideConversation IN (0,1)');
                
+               if (isset($_POST['conversationID'])) {
+                       $this->conversationID = intval($_POST['conversationID']);
+                       
+                       $conditionBuilder->add('conversation.conversationID = ?', [$this->conversationID]);
+               }
+               
                return $conditionBuilder;
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\search\ISearchableObjectType::isAccessible()
+        * @inheritDoc
         */
        public function isAccessible() {
                return (WCF::getUser()->userID ? true : false);
        }
+       
+       /** @noinspection PhpMissingParentCallCommonInspection */
+       /**
+        * @inheritDoc
+        */
+       public function getFormTemplateName() {
+               if ($this->conversation) {
+                       return 'searchConversationMessage';
+               }
+               
+               return null;
+       }
+       
+       /**
+        * @inheritDoc
+        */
+       public function show(IForm $form = null) {
+               /** @var SearchForm $form */
+               
+               // get existing values
+               if ($form !== null && isset($form->searchData['additionalData']['com.woltlab.wcf.conversation.message']['conversationID'])) {
+                       $this->conversationID = $form->searchData['additionalData']['com.woltlab.wcf.conversation.message']['conversationID'];
+                       
+                       if ($this->conversationID) {
+                               $this->conversation = Conversation::getUserConversation($this->conversationID, WCF::getUser()->userID);
+                               
+                               if ($this->conversation === null || !$this->conversation->canRead()) {
+                                       $this->conversationID = 0;
+                                       $this->conversation = null;
+                               }
+                       }
+               }
+               
+               WCF::getTPL()->assign('searchedConversation', $this->conversation);
+       }
 }
index c156bfd49b3e623ac235bf0d3e10a1eeb25a8201..957a85d12b6664573cf21a3cab4bda1fb07bcd10 100644 (file)
@@ -5,20 +5,18 @@ namespace wcf\system\stat;
  * Stat handler implementation for conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.stat
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Stat
  */
 class ConversationMessageStatDailyHandler extends AbstractStatDailyHandler {
        /**
-        * @see \wcf\system\stat\IStatDailyHandler::getData()
+        * @inheritDoc
         */
        public function getData($date) {
-               return array(
+               return [
                        'counter' => $this->getCounter($date, 'wcf'.WCF_N.'_conversation_message', 'time'),
                        'total' => $this->getTotal($date, 'wcf'.WCF_N.'_conversation_message', 'time')
-               );
+               ];
        }
 }
index 68d74b76d83b42d84c975cb43d8d104a1d06ae8c..e2f695e853e7ef6645437493fb005083e5baad7a 100644 (file)
@@ -5,20 +5,18 @@ namespace wcf\system\stat;
  * Stat handler implementation for conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.stat
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Stat
  */
 class ConversationStatDailyHandler extends AbstractStatDailyHandler {
        /**
-        * @see \wcf\system\stat\IStatDailyHandler::getData()
+        * @inheritDoc
         */
        public function getData($date) {
-               return array(
+               return [
                        'counter' => $this->getCounter($date, 'wcf'.WCF_N.'_conversation', 'time'),
                        'total' => $this->getTotal($date, 'wcf'.WCF_N.'_conversation', 'time')
-               );
+               ];
        }
 }
index 6fee83d4aa809ff938b65a7cc376cb321c4197ca..c9b7120c7b9e562c3ec04401f6ecc4002b44534f 100644 (file)
@@ -1,91 +1,98 @@
 <?php
 namespace wcf\system\user\notification\event;
+use wcf\system\email\Email;
 use wcf\system\request\LinkHandler;
-use wcf\system\user\notification\event\AbstractUserNotificationEvent;
+use wcf\system\user\notification\object\ConversationMessageUserNotificationObject;
 
 /**
  * User notification event for conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.user.notification.event
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\User\Notification\Event
+ * 
+ * @method     ConversationMessageUserNotificationObject       getUserNotificationObject()
  */
 class ConversationMessageUserNotificationEvent extends AbstractUserNotificationEvent {
        /**
-        * @see \wcf\system\user\notification\event\AbstractUserNotificationEvent::$stackable
+        * @inheritDoc
         */
        protected $stackable = true;
        
        /**
-        * @see \wcf\system\user\notification\event\IUserNotificationEvent::getMessage()
+        * @inheritDoc
         */
        public function getTitle() {
                $count = count($this->getAuthors());
                if ($count > 1) {
-                       return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.message.title.stacked', array('count' => $count));
+                       return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.message.title.stacked', ['count' => $count]);
                }
                
                return $this->getLanguage()->get('wcf.user.notification.conversation.message.title');
        }
        
        /**
-        * @see \wcf\system\user\notification\event\IUserNotificationEvent::getMessage()
+        * @inheritDoc
         */
        public function getMessage() {
                $authors = array_values($this->getAuthors());
                $count = count($authors);
                
                if ($count > 1) {
-                       return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.message.message.stacked', array(
+                       return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.message.message.stacked', [
                                'author' => $this->author,
                                'authors' => $authors,
                                'count' => $count,
                                'message' => $this->userNotificationObject,
                                'others' => $count - 1
-                       ));
+                       ]);
                }
                
-               return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.message.message', array(
+               return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.message.message', [
                        'author' => $this->author,
                        'message' => $this->userNotificationObject
-               ));
+               ]);
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\user\notification\event\IUserNotificationEvent::getEmailMessage()
+        * @inheritDoc
         */
        public function getEmailMessage($notificationType = 'instant') {
-               return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.message.mail', array(
-                       'message' => $this->userNotificationObject,
-                       'author' => $this->author,
-                       'notificationType' => $notificationType
-               ));
+               $messageID = '<com.woltlab.wcf.conversation.notification/'.$this->getUserNotificationObject()->getConversation()->conversationID.'@'.Email::getHost().'>';
+               
+               return [
+                       'template' => 'email_notification_conversationMessage',
+                       'application' => 'wcf',
+                       'in-reply-to' => [$messageID],
+                       'references' => [$messageID]
+               ];
        }
        
        /**
-        * @see \wcf\system\user\notification\event\IUserNotificationEvent::getLink()
+        * @inheritDoc
         */
        public function getLink() {
-               return LinkHandler::getInstance()->getLink('Conversation', array(
-                       'object' => $this->userNotificationObject->getConversation(),
-                       'messageID' => $this->userNotificationObject->messageID
-               ), '#message'.$this->userNotificationObject->messageID);
+               return LinkHandler::getInstance()->getLink('Conversation', [
+                       'object' => $this->getUserNotificationObject()->getConversation(),
+                       'messageID' => $this->getUserNotificationObject()->messageID
+               ], '#message'.$this->getUserNotificationObject()->messageID);
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\user\notification\event\IUserNotificationEvent::getEventHash()
+        * @inheritDoc
         */
        public function getEventHash() {
-               return sha1($this->eventID . '-' . $this->userNotificationObject->conversationID);
+               return sha1($this->eventID . '-' . $this->getUserNotificationObject()->conversationID);
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\user\notification\event\IUserNotificationEvent::checkAccess()
+        * @inheritDoc
         */
        public function checkAccess() {
-               return $this->userNotificationObject->getConversation()->canRead();
+               return $this->getUserNotificationObject()->getConversation()->canRead();
        }
 }
index b1a08547b43b672abfc7fe21aeaef1b79e4587c6..008d42d191d6bc6841ad2492d732677b14cdc13a 100644 (file)
@@ -1,58 +1,60 @@
 <?php
 namespace wcf\system\user\notification\event;
 use wcf\system\request\LinkHandler;
-use wcf\system\user\notification\event\AbstractUserNotificationEvent;
+use wcf\system\user\notification\object\ConversationUserNotificationObject;
 
 /**
  * User notification event for conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.user.notification.event
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\User\Notification\Event
+ * 
+ * @method     ConversationUserNotificationObject      getUserNotificationObject()
  */
 class ConversationUserNotificationEvent extends AbstractUserNotificationEvent {
        /**
-        * @see \wcf\system\user\notification\event\IUserNotificationEvent::getMessage()
+        * @inheritDoc
         */
        public function getTitle() {
                return $this->getLanguage()->get('wcf.user.notification.conversation.title');
        }
        
        /**
-        * @see \wcf\system\user\notification\event\IUserNotificationEvent::getMessage()
+        * @inheritDoc
         */
        public function getMessage() {
-               return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.message', array(
+               return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.message', [
                        'author' => $this->author,
                        'conversation' => $this->userNotificationObject
-               ));
+               ]);
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\user\notification\event\IUserNotificationEvent::getEmailMessage()
+        * @inheritDoc
         */
        public function getEmailMessage($notificationType = 'instant') {
-               return $this->getLanguage()->getDynamicVariable('wcf.user.notification.conversation.mail', array(
-                       'conversation' => $this->userNotificationObject,
-                       'author' => $this->author,
-                       'notificationType' => $notificationType
-               ));
+               return [
+                       'message-id' => 'com.woltlab.wcf.conversation.notification/'.$this->getUserNotificationObject()->conversationID,
+                       'template' => 'email_notification_conversation',
+                       'application' => 'wcf'
+               ];
        }
        
        /**
-        * @see \wcf\system\user\notification\event\IUserNotificationEvent::getLink()
+        * @inheritDoc
         */
        public function getLink() {
-               return LinkHandler::getInstance()->getLink('Conversation', array('object' => $this->userNotificationObject));
+               return LinkHandler::getInstance()->getLink('Conversation', ['object' => $this->userNotificationObject]);
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\user\notification\event\IUserNotificationEvent::checkAccess()
+        * @inheritDoc
         */
        public function checkAccess() {
-               return $this->userNotificationObject->canRead();
+               return $this->getUserNotificationObject()->canRead();
        }
 }
index 101c693d85aabde04612789a36692cf9112c790e..14afdb1b9ccbdf079b7561fc2c8c139fb5ef11ba 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\system\user\notification\object;
+use wcf\data\conversation\message\ConversationMessage;
 use wcf\data\DatabaseObjectDecorator;
 use wcf\system\request\LinkHandler;
 
@@ -7,44 +8,45 @@ use wcf\system\request\LinkHandler;
  * Notification object for conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.user.notification.object
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\User\Notification\Object
+ *
+ * @method     ConversationMessage     getDecoratedObject()
+ * @mixin      ConversationMessage
  */
 class ConversationMessageUserNotificationObject extends DatabaseObjectDecorator implements IStackableUserNotificationObject {
        /**
-        * @see \wcf\data\DatabaseObjectDecorator::$baseClass
+        * @inheritDoc
         */
-       protected static $baseClass = 'wcf\data\conversation\message\ConversationMessage';
+       protected static $baseClass = ConversationMessage::class;
        
        /**
-        * @see \wcf\system\user\notification\object\IUserNotificationObject::getTitle()
+        * @inheritDoc
         */
        public function getTitle() {
                return $this->getConversation()->subject;
        }
        
        /**
-        * @see \wcf\system\user\notification\object\IUserNotificationObject::getURL()
+        * @inheritDoc
         */
        public function getURL() {
-               return LinkHandler::getInstance()->getLink('Conversation', array(
+               return LinkHandler::getInstance()->getLink('Conversation', [
                        'object' => $this->getConversation(),
                        'messageID' => $this->messageID
-               )).'#message'.$this->messageID;
+               ]).'#message'.$this->messageID;
        }
        
        /**
-        * @see \wcf\system\user\notification\object\IUserNotificationObject::getAuthorID()
+        * @inheritDoc
         */
        public function getAuthorID() {
                return $this->userID;
        }
        
        /**
-        * @see \wcf\system\user\notification\object\IStackableUserNotificationObject::getRelatedObjectID()
+        * @inheritDoc
         */
        public function getRelatedObjectID() {
                return $this->conversationID;
index 7127b2d0ad465b0c430b44ab603c78d2331ccd98..f9986b4a9315aaa39b80ad3d336ab5dddfd56a08 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\system\user\notification\object;
+use wcf\data\conversation\Conversation;
 use wcf\data\DatabaseObjectDecorator;
 use wcf\system\request\LinkHandler;
 
@@ -7,36 +8,37 @@ use wcf\system\request\LinkHandler;
  * Notification object for conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.user.notification.object
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\User\Notification\Object
+ * 
+ * @method     Conversation    getDecoratedObject()
+ * @mixin      Conversation
  */
 class ConversationUserNotificationObject extends DatabaseObjectDecorator implements IUserNotificationObject {
        /**
-        * @see \wcf\data\DatabaseObjectDecorator::$baseClass
+        * @inheritDoc
         */
-       protected static $baseClass = 'wcf\data\conversation\Conversation';
+       protected static $baseClass = Conversation::class;
        
        /**
-        * @see \wcf\system\user\notification\object\IUserNotificationObject::getTitle()
+        * @inheritDoc
         */
        public function getTitle() {
                return $this->subject;
        }
        
        /**
-        * @see \wcf\system\user\notification\object\IUserNotificationObject::getURL()
+        * @inheritDoc
         */
        public function getURL() {
-               return LinkHandler::getInstance()->getLink('Conversation', array(
+               return LinkHandler::getInstance()->getLink('Conversation', [
                        'object' => $this->getDecoratedObject()
-               ));
+               ]);
        }
        
        /**
-        * @see \wcf\system\user\notification\object\IUserNotificationObject::getAuthorID()
+        * @inheritDoc
         */
        public function getAuthorID() {
                return $this->userID;
index 3f48c91376869740a149a4f36d65464abb5d5de3..c5d388e5dcf179530808d89505d6b738524f58cd 100644 (file)
@@ -1,29 +1,30 @@
 <?php
 namespace wcf\system\user\notification\object\type;
+use wcf\data\conversation\message\ConversationMessage;
+use wcf\data\conversation\message\ConversationMessageList;
+use wcf\system\user\notification\object\ConversationMessageUserNotificationObject;
 
 /**
  * Represents a conversation message notification object type.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.user.notification.object.type
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\User\Notification\Object\Type
  */
 class ConversationMessageNotificationObjectType extends AbstractUserNotificationObjectType {
        /**
-        * @see \wcf\system\user\notification\object\type\AbstractUserNotificationObjectType::$decoratorClassName
+        * @inheritDoc
         */
-       protected static $decoratorClassName = 'wcf\system\user\notification\object\ConversationMessageUserNotificationObject';
+       protected static $decoratorClassName = ConversationMessageUserNotificationObject::class;
        
        /**
-        * @see \wcf\system\user\notification\object\type\AbstractUserNotificationObjectType::$objectClassName
+        * @inheritDoc
         */
-       protected static $objectClassName = 'wcf\data\conversation\message\ConversationMessage';
+       protected static $objectClassName = ConversationMessage::class;
        
        /**
-        * @see \wcf\system\user\notification\object\type\AbstractUserNotificationObjectType::$objectListClassName
+        * @inheritDoc
         */
-       protected static $objectListClassName = 'wcf\data\conversation\message\ConversationMessageList';
+       protected static $objectListClassName = ConversationMessageList::class;
 }
index fe64fe992b9144e0478a5c2f66953d15dc65b3ea..605c9ad35a3228da30658fcc6e50cfc71703b47a 100644 (file)
@@ -1,36 +1,37 @@
 <?php
 namespace wcf\system\user\notification\object\type;
 use wcf\data\conversation\Conversation;
+use wcf\data\conversation\ConversationList;
+use wcf\system\user\notification\object\ConversationUserNotificationObject;
 use wcf\system\WCF;
 
 /**
  * Represents a conversation notification object type.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.user.notification.object.type
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\User\Notification\Object\Type
  */
 class ConversationNotificationObjectType extends AbstractUserNotificationObjectType {
        /**
-        * @see \wcf\system\user\notification\object\type\AbstractUserNotificationObjectType::$decoratorClassName
+        * @inheritDoc
         */
-       protected static $decoratorClassName = 'wcf\system\user\notification\object\ConversationUserNotificationObject';
+       protected static $decoratorClassName = ConversationUserNotificationObject::class;
        
        /**
-        * @see \wcf\system\user\notification\object\type\AbstractUserNotificationObjectType::$objectClassName
+        * @inheritDoc
         */
-       protected static $objectClassName = 'wcf\data\conversation\Conversation';
+       protected static $objectClassName = Conversation::class;
        
        /**
-        * @see \wcf\system\user\notification\object\type\AbstractUserNotificationObjectType::$objectListClassName
+        * @inheritDoc
         */
-       protected static $objectListClassName = 'wcf\data\conversation\ConversationList';
+       protected static $objectListClassName = ConversationList::class;
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\user\notification\object\type\IUserNotificationObjectType::getObjectsByIDs()
+        * @inheritDoc
         */
        public function getObjectsByIDs(array $objectIDs) {
                $objects = Conversation::getUserConversations($objectIDs, WCF::getUser()->userID);
@@ -45,10 +46,10 @@ class ConversationNotificationObjectType extends AbstractUserNotificationObjectT
                                // '__unknownNotificationObject' tells the notification API
                                // that the object does not exist anymore so that the related
                                // notification can be deleted automatically
-                               $objects[$objectID] = new static::$decoratorClassName(new static::$objectClassName(null, array(
+                               $objects[$objectID] = new static::$decoratorClassName(new static::$objectClassName(null, [
                                        '__unknownNotificationObject' => true,
                                        'conversationID' => $objectID
-                               )));
+                               ]));
                        }
                }
                
diff --git a/files/lib/system/user/online/location/ConversationLocation.class.php b/files/lib/system/user/online/location/ConversationLocation.class.php
deleted file mode 100644 (file)
index deff877..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-namespace wcf\system\user\online\location;
-use wcf\data\conversation\Conversation;
-use wcf\data\user\online\UserOnline;
-use wcf\system\database\util\PreparedStatementConditionBuilder;
-use wcf\system\WCF;
-
-/**
- * Implementation of IUserOnlineLocation for the conversation page location.
- * 
- * @author     Marcel Werk
- * @copyright  2001-2016 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf.conversation
- * @subpackage system.user.online.location
- * @category   Community Framework
- */
-class ConversationLocation implements IUserOnlineLocation {
-       /**
-        * conversation ids
-        * @var array<integer>
-        */
-       protected $conversationIDs = array();
-       
-       /**
-        * list of conversations
-        * @var array<\wcf\data\conversation\Conversation>
-        */
-       protected $conversations = null;
-       
-       /**
-        * @see \wcf\system\user\online\location\IUserOnlineLocation::cache()
-        */
-       public function cache(UserOnline $user) {
-               if ($user->objectID) $this->conversationIDs[] = $user->objectID;
-       }
-       
-       /**
-        * @see \wcf\system\user\online\location\IUserOnlineLocation::get()
-        */
-       public function get(UserOnline $user, $languageVariable = '') {
-               if ($this->conversations === null) {
-                       $this->readConversations();
-               }
-               
-               if (!isset($this->conversations[$user->objectID])) {
-                       return '';
-               }
-               
-               return WCF::getLanguage()->getDynamicVariable($languageVariable, array('conversation' => $this->conversations[$user->objectID]));
-       }
-       
-       /**
-        * Loads the conversations.
-        */
-       protected function readConversations() {
-               $this->conversations = array();
-               
-               if (!WCF::getUser()->userID) return;
-               if (empty($this->conversationIDs)) return;
-               $this->conversationIDs = array_unique($this->conversationIDs);
-               
-               $conditionBuilder = new PreparedStatementConditionBuilder();
-               $conditionBuilder->add('conversation_to_user.participantID = ?', array(WCF::getUser()->userID));
-               $conditionBuilder->add('conversation_to_user.conversationID IN (?)', array($this->conversationIDs));
-               $conditionBuilder->add('conversation_to_user.hideConversation <> ?', array(Conversation::STATE_LEFT));
-               
-               $sql = "SELECT          conversation.*
-                       FROM            wcf".WCF_N."_conversation_to_user conversation_to_user
-                       LEFT JOIN       wcf".WCF_N."_conversation conversation
-                       ON              (conversation.conversationID = conversation_to_user.conversationID)
-                       ".$conditionBuilder;
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute($conditionBuilder->getParameters());
-               while ($conversation = $statement->fetchObject('\wcf\data\conversation\Conversation')) {
-                       $this->conversations[$conversation->conversationID] = $conversation;
-               }
-       }
-}
index da4f169eb75077d7751425f8641cef01228d980c..7a8e730e7d21fbd86a46cad8a8d267bccdcf644d 100644 (file)
@@ -3,6 +3,7 @@ namespace wcf\system\worker;
 use wcf\data\conversation\message\ConversationMessageEditor;
 use wcf\data\conversation\message\ConversationMessageList;
 use wcf\data\object\type\ObjectTypeCache;
+use wcf\system\html\input\HtmlInputProcessor;
 use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
 use wcf\system\search\SearchIndexManager;
 use wcf\system\WCF;
@@ -11,20 +12,26 @@ use wcf\system\WCF;
  * Worker implementation for updating conversation messages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf
- * @subpackage system.worker
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Worker
+ * 
+ * @method     ConversationMessageList         getObjectList()
  */
 class ConversationMessageRebuildDataWorker extends AbstractRebuildDataWorker {
        /**
-        * @see \wcf\system\worker\AbstractWorker::$limit
+        * @inheritDoc
         */
        protected $limit = 500;
        
        /**
-        * @see \wcf\system\worker\IWorker::countObjects()
+        * @var HtmlInputProcessor
+        */
+       protected $htmlInputProcessor;
+       
+       /** @noinspection PhpMissingParentCallCommonInspection */
+       /**
+        * @inheritDoc
         */
        public function countObjects() {
                if ($this->count === null) {
@@ -38,8 +45,9 @@ class ConversationMessageRebuildDataWorker extends AbstractRebuildDataWorker {
                }
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\worker\AbstractRebuildDataWorker::initObjectList
+        * @inheritDoc
         */
        protected function initObjectList() {
                $this->objectList = new ConversationMessageList();
@@ -49,10 +57,10 @@ class ConversationMessageRebuildDataWorker extends AbstractRebuildDataWorker {
        }
        
        /**
-        * @see \wcf\system\worker\IWorker::execute()
+        * @inheritDoc
         */
        public function execute() {
-               $this->objectList->getConditionBuilder()->add('conversation_message.messageID BETWEEN ? AND ?', array($this->limit * $this->loopCount + 1, $this->limit * $this->loopCount + $this->limit));
+               $this->objectList->getConditionBuilder()->add('conversation_message.messageID BETWEEN ? AND ?', [$this->limit * $this->loopCount + 1, $this->limit * $this->loopCount + $this->limit]);
                
                parent::execute();
                
@@ -70,20 +78,53 @@ class ConversationMessageRebuildDataWorker extends AbstractRebuildDataWorker {
                $attachmentStatement = WCF::getDB()->prepareStatement($sql);
                
                foreach ($this->objectList as $message) {
-                       SearchIndexManager::getInstance()->add('com.woltlab.wcf.conversation.message', $message->messageID, $message->message, ($message->subject ?: ''), $message->time, $message->userID, $message->username);
+                       SearchIndexManager::getInstance()->set(
+                               'com.woltlab.wcf.conversation.message',
+                               $message->messageID,
+                               $message->message, 
+                               $message->subject ?: '',
+                               $message->time,
+                               $message->userID,
+                               $message->username
+                       );
                        
                        $editor = new ConversationMessageEditor($message);
-                       $data = array();
+                       $data = [];
                        
                        // count attachments
-                       $attachmentStatement->execute(array($attachmentObjectType->objectTypeID, $message->messageID));
+                       $attachmentStatement->execute([$attachmentObjectType->objectTypeID, $message->messageID]);
                        $row = $attachmentStatement->fetchSingleRow();
                        $data['attachments'] = $row['attachments'];
                        
-                       // update embedded objects
-                       $data['hasEmbeddedObjects'] = (MessageEmbeddedObjectManager::getInstance()->registerObjects('com.woltlab.wcf.conversation.message', $message->messageID, $message->message) ? 1 : 0);
+                       // update message
+                       if (!$message->enableHtml) {
+                               $this->getHtmlInputProcessor()->process($message->message, 'com.woltlab.wcf.conversation.message', $message->messageID, true);
+                               $data['message'] = $this->getHtmlInputProcessor()->getHtml();
+                               $data['enableHtml'] = 1;
+                       }
+                       else {
+                               $this->getHtmlInputProcessor()->processEmbeddedContent($message->message, 'com.woltlab.wcf.conversation.message', $message->messageID);
+                       }
+                       
+                       if (MessageEmbeddedObjectManager::getInstance()->registerObjects($this->getHtmlInputProcessor())) {
+                               $data['hasEmbeddedObjects'] = 1;
+                       }
+                       else {
+                               $data['hasEmbeddedObjects'] = 0;
+                       }
                        
                        $editor->update($data);
                }
        }
+       
+       /**
+        * @return      HtmlInputProcessor
+        */
+       protected function getHtmlInputProcessor() {
+               if ($this->htmlInputProcessor === null) {
+                       $this->htmlInputProcessor = new HtmlInputProcessor();
+               }
+               
+               return $this->htmlInputProcessor;
+       }
 }
index 0faf3ce0d30910a5ca3dcbb130b62e6210b2d374..44791eb1704f151898dfb457dfbdeaf655a8e62e 100644 (file)
@@ -10,20 +10,21 @@ use wcf\system\WCF;
  * Worker implementation for updating conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package    com.woltlab.wcf
- * @subpackage system.worker
- * @category   Community Framework
+ * @package    WoltLabSuite\Core\System\Worker
+ * 
+ * @method     ConversationList        getObjectList()
  */
 class ConversationRebuildDataWorker extends AbstractRebuildDataWorker {
        /**
-        * @see \wcf\system\worker\AbstractWorker::$limit
+        * @inheritDoc
         */
        protected $limit = 100;
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\worker\IWorker::countObjects()
+        * @inheritDoc
         */
        public function countObjects() {
                if ($this->count === null) {
@@ -37,8 +38,9 @@ class ConversationRebuildDataWorker extends AbstractRebuildDataWorker {
                }
        }
        
+       /** @noinspection PhpMissingParentCallCommonInspection */
        /**
-        * @see \wcf\system\worker\AbstractRebuildDataWorker::initObjectList
+        * @inheritDoc
         */
        protected function initObjectList() {
                $this->objectList = new ConversationList();
@@ -46,10 +48,10 @@ class ConversationRebuildDataWorker extends AbstractRebuildDataWorker {
        }
        
        /**
-        * @see \wcf\system\worker\IWorker::execute()
+        * @inheritDoc
         */
        public function execute() {
-               $this->objectList->getConditionBuilder()->add('conversation.conversationID BETWEEN ? AND ?', array($this->limit * $this->loopCount + 1, $this->limit * $this->loopCount + $this->limit));
+               $this->objectList->getConditionBuilder()->add('conversation.conversationID BETWEEN ? AND ?', [$this->limit * $this->loopCount + 1, $this->limit * $this->loopCount + $this->limit]);
                
                parent::execute();
                
@@ -92,7 +94,7 @@ class ConversationRebuildDataWorker extends AbstractRebuildDataWorker {
                                AND participantID IS NOT NULL";
                $existingParticipantStatement = WCF::getDB()->prepareStatement($sql, 5);
                
-               $obsoleteConversations = array();
+               $obsoleteConversations = [];
                foreach ($this->objectList as $conversation) {
                        $editor = new ConversationEditor($conversation);
                        
@@ -102,7 +104,7 @@ class ConversationRebuildDataWorker extends AbstractRebuildDataWorker {
                                if (!$conversation->userID) $obsolete = true;
                        }
                        else {
-                               $existingParticipantStatement->execute(array($conversation->conversationID));
+                               $existingParticipantStatement->execute([$conversation->conversationID]);
                                $row = $existingParticipantStatement->fetchSingleRow();
                                if (!$row['participants']) $obsolete = true;
                        }
@@ -112,10 +114,10 @@ class ConversationRebuildDataWorker extends AbstractRebuildDataWorker {
                        }
                        
                        // update data
-                       $data = array();
+                       $data = [];
                        
                        // get first post
-                       $firstMessageStatement->execute(array($conversation->conversationID));
+                       $firstMessageStatement->execute([$conversation->conversationID]);
                        if (($row = $firstMessageStatement->fetchSingleRow()) !== false) {
                                $data['firstMessageID'] = $row['messageID'];
                                $data['lastPostTime'] = $data['time'] = $row['time'];
@@ -124,7 +126,7 @@ class ConversationRebuildDataWorker extends AbstractRebuildDataWorker {
                        }
                        
                        // get last post
-                       $lastMessageStatement->execute(array($conversation->conversationID));
+                       $lastMessageStatement->execute([$conversation->conversationID]);
                        if (($row = $lastMessageStatement->fetchSingleRow()) !== false) {
                                $data['lastPostTime'] = $row['time'];
                                $data['lastPosterID'] = $row['userID'];
@@ -132,19 +134,19 @@ class ConversationRebuildDataWorker extends AbstractRebuildDataWorker {
                        }
                        
                        // get stats
-                       $statsStatement->execute(array($conversation->conversationID));
+                       $statsStatement->execute([$conversation->conversationID]);
                        $row = $statsStatement->fetchSingleRow();
                        $data['replies'] = ($row['messages'] ? $row['messages'] - 1 : 0);
                        $data['attachments'] = ($row['attachments'] ?: 0);
                        
                        // get number of participants
-                       $participantCounterStatement->execute(array($conversation->conversationID, Conversation::STATE_LEFT, $conversation->userID, 0));
+                       $participantCounterStatement->execute([$conversation->conversationID, Conversation::STATE_LEFT, $conversation->userID, 0]);
                        $row = $participantCounterStatement->fetchSingleRow();
                        $data['participants'] = $row['participants'];
                        
                        // get participant summary
-                       $participantStatement->execute(array($conversation->conversationID, $conversation->userID, 0));
-                       $users = array();
+                       $participantStatement->execute([$conversation->conversationID, $conversation->userID, 0]);
+                       $users = [];
                        while ($row = $participantStatement->fetchArray()) {
                                $users[] = $row;
                        }
diff --git a/files/style/conversation.less b/files/style/conversation.less
deleted file mode 100644 (file)
index cec8aee..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-#conversationLabelFilter {
-       margin-bottom: @wcfGapMedium;
-}
-
-.conversationLabelList {
-       margin-bottom: @wcfGapMedium;
-       
-       li:not(:last-child) {
-               margin-bottom: @wcfGapTiny;
-       }
-       
-       &~small {
-               display: block;
-       }
-}
-
-#unreadConversations .dropdownMenu > li {
-       h3 {
-               max-width: 250px;
-               overflow: hidden;
-               text-overflow: ellipsis;
-       }
-}
-
-.conversationParticipantList {
-       > li {
-               .inlineDataList {
-                       font-size: @wcfSmallFontSize;
-               }
-               
-               &.conversationLeft > div {
-                       > a > img,
-                       > span > img {
-                               .grayscale;
-                       }
-               }
-       }
-}
-
-.conversationLeft .userLink,
-.conversationLeft.userLink,
-.conversationLeft p > span {
-       text-decoration: line-through;
-}
-
-.sidebar fieldset.conversationQuota {
-       > div {
-               text-align: center;
-       }
-}
-
-.conversationUsageBar {
-       background-color: @wcfColor;
-       border-radius: 5px;
-       height: 20px;
-       padding: 4px;
-       
-       .boxShadowNative(~"inset 0 1px 5px rgba(0, 0, 0, .5), 0 1px 0 rgba(255, 255, 255, .5)");
-       
-       > span {
-               border-radius: 3px;
-               color: transparent;
-               display: block;
-               height: 100%;
-               
-               .boxShadowNative(~"inset 0 1px 0 rgba(255, 255, 255, .5)");
-               .linearGradient(rgba(165, 223, 65, 1), rgba(165, 223, 65, 1), rgba(76, 169, 22, 1));
-       }
-       
-       &.yellow > span {
-               .linearGradient(rgba(254, 207, 35, 1), rgba(254, 207, 35, 1), rgba(253, 146, 21, 1));
-       }
-       
-       &.red > span {
-               .linearGradient(rgba(240, 163, 163, 1), rgba(240, 163, 163, 1), rgba(244, 35, 35, 1));
-       }
-}
-
-.conversationFolderList > li > a > span {
-       float: right;
-}
-
-@media only screen and (max-width: 800px) {
-       .conversationList {
-               thead {
-                       display: none;
-               }
-               
-               tbody {
-                       .columnMark,
-                       .columnReplies,
-                       .columnParticipants,
-                       .columnLastPost,
-                       .conversationParticipantSummary,
-                       .columnSubject .statusDisplay {
-                               display: none;
-                       }
-               }
-       }
-}
-
-@media only screen and (max-width: 1239px) {
-       .conversationList {
-               thead .columnParticipants,
-               tbody .columnParticipants {
-                       display: none;
-               }
-       }
-}
\ No newline at end of file
diff --git a/files/style/conversation.scss b/files/style/conversation.scss
new file mode 100644 (file)
index 0000000..32e1fd5
--- /dev/null
@@ -0,0 +1,64 @@
+/* list of participants */
+.conversationParticipantList {
+       > li {
+               &.conversationLeft > div {
+                       > a > img,
+                       > span > img {
+                               @extend .grayscale;
+                       }
+               }
+       }
+}
+
+/* participant left status */
+.conversationLeft .userLink,
+.conversationLeft.userLink,
+.conversationLeft p > span {
+       text-decoration: line-through;
+}
+
+/* quota usage display */
+.sidebar .box.conversationQuota .boxContent {
+       text-align: center;
+}
+.conversationUsageBar {
+       background-color: rgba(165, 223, 65, 1);
+       height: 5px;
+       
+       > span {
+               background-color: rgba(76, 169, 22, 1);
+               color: transparent;
+               display: block;
+               height: 100%;
+       }
+       
+       &.yellow {
+               background-color: rgba(254, 207, 35, 1);
+               
+               > span {
+                       background-color: rgba(253, 146, 21, 1);
+               }
+       }
+       
+       &.red {
+               background-color: rgba(255, 205, 210, 1);
+               
+               > span {
+                       background-color: rgba(244, 67, 54, 1);
+               }
+       }
+}
+
+.conversationItem {
+       .conversationInfo {
+               display: flex;
+       }
+       
+       .conversationParticipant {
+               flex: 1 1 auto;
+       }
+       .conversationLastPostTime {
+               flex: 0 0 auto;
+               margin-left: 10px;
+       }
+}
index dcf2b0f22ef668ad845fd09c747676f6b927d6d6..01fc72fca4183292af0bdd1e0b214863d79ce149 100644 (file)
@@ -43,10 +43,7 @@ CREATE TABLE wcf1_conversation_message (
        message MEDIUMTEXT NOT NULL,
        time INT(10) NOT NULL DEFAULT 0,
        attachments SMALLINT(5) NOT NULL DEFAULT 0,
-       enableSmilies TINYINT(1) NOT NULL DEFAULT 1,
        enableHtml TINYINT(1) NOT NULL DEFAULT 0,
-       enableBBCodes TINYINT(1) NOT NULL DEFAULT 1,
-       showSignature TINYINT(1) NOT NULL DEFAULT 1,
        ipAddress VARCHAR(39) NOT NULL DEFAULT '',
        lastEditTime INT(10) NOT NULL DEFAULT 0,
        editCount MEDIUMINT(7) NOT NULL DEFAULT 0,
index ceb0182b273a13a4adba13040445a3f95b6ef8e5..8644de6b89980f88f88b04187bdec6a8324c8b7a 100644 (file)
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.leave"><![CDATA[Ausblenden ({#$count})]]></item>
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.leavePermanently"><![CDATA[Verlassen ({#$count})]]></item>
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.markAsRead"><![CDATA[Als gelesen markieren ({#$count})]]></item>
-               <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.markAsRead.confirmMessage"><![CDATA[Wollen Sie die {if $count == 1}markierte Konversation{else}markierten Konversationen{/if} wirklich als gelesen markieren?]]></item>
+               <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.markAsRead.confirmMessage"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Willst du{else}Wollen Sie{/if} die {if $count == 1}markierte Konversation{else}markierten Konversationen{/if} wirklich als gelesen markieren?]]></item>
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.open"><![CDATA[Öffnen ({#$count})]]></item>
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.restore"><![CDATA[Als aktiv markieren ({#$count})]]></item>
-               <item name="wcf.clipboard.label.com.woltlab.wcf.conversation.conversation.marked"><![CDATA[{if $count == 1}Eine Konversation{else}{#$count} Konversationen{/if} markiert]]></item>
+               <item name="wcf.clipboard.label.com.woltlab.wcf.conversation.conversation.marked"><![CDATA[{if $count == 1}Eine Konversation{else}{#$count} Konversationen{/if}]]></item>
        </category>
        
        <category name="wcf.conversation">
@@ -64,6 +64,7 @@
                <item name="wcf.conversation.button.add"><![CDATA[Konversation starten]]></item>
                <item name="wcf.conversation.button.saveAsDraft"><![CDATA[Entwurf speichern]]></item>
                <item name="wcf.conversation.conversations"><![CDATA[Konversationen]]></item>
+               <item name="wcf.conversation.filter.participants"><![CDATA[Filter nach Teilnehmern]]></item>
                <item name="wcf.conversation.folders"><![CDATA[Ordner]]></item>
                <item name="wcf.conversation.folder.draft"><![CDATA[Entwürfe]]></item>
                <item name="wcf.conversation.folder.hidden"><![CDATA[Ausgeblendet]]></item>
                <item name="wcf.conversation.hideConversation.leave"><![CDATA[Ausblenden]]></item>
                <item name="wcf.conversation.hideConversation.leave.description"><![CDATA[Die Konversation wird bis zu einer neuen Antwort nicht mehr als aktive Konversation gelistet.]]></item>
                <item name="wcf.conversation.hideConversation.leavePermanently"><![CDATA[Verlassen]]></item>
-               <item name="wcf.conversation.hideConversation.leavePermanently.description"><![CDATA[Die Konversation wird verlassen und Sie werden nicht länger als aktiver Teilnehmer gelistet.]]></item>
+               <item name="wcf.conversation.hideConversation.leavePermanently.description"><![CDATA[Die Konversation wird verlassen und {if LANGUAGE_USE_INFORMAL_VARIANT}di wirst{else}Sie werden{/if} nicht länger als aktiver Teilnehmer gelistet.]]></item>
                <item name="wcf.conversation.hideConversation.restore"><![CDATA[Als aktiv markieren]]></item>
                <item name="wcf.conversation.information"><![CDATA[Informationen]]></item>
                <item name="wcf.conversation.invisible"><![CDATA[unsichtbar]]></item>
                <item name="wcf.conversation.invisibleParticipants"><![CDATA[Unsichtbare Teilnehmer]]></item>
-               <item name="wcf.conversation.invisibleParticipants.description"><![CDATA[Unsichtbare Teilnehmer sind für andere Teilnehmer nicht sichtbar. Mehrere Teilnehmer können mit Komma getrennt angegeben werden.]]></item>
+               <item name="wcf.conversation.invisibleParticipants.description"><![CDATA[Unsichtbare Teilnehmer sind für andere Teilnehmer nicht sichtbar.]]></item>
                <item name="wcf.conversation.lastPostTime"><![CDATA[Letzte Antwort]]></item>
-               <item name="wcf.conversation.lastVisitTime"><![CDATA[Letzter Aufruf]]></item>
+               <item name="wcf.conversation.lastVisitTime"><![CDATA[Konversation gelesen]]></item>
                <item name="wcf.conversation.leave.title"><![CDATA[Teilnahme verwalten]]></item>
-               <item name="wcf.conversation.markAllAsRead.confirmMessage"><![CDATA[Wollen Sie wirklich alle Konversationen als gelesen markieren?]]></item>
+               <item name="wcf.conversation.markAllAsRead.confirmMessage"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Willst du{else}Wollen Sie{/if} wirklich alle Konversationen als gelesen markieren?]]></item>
                <item name="wcf.conversation.message"><![CDATA[Nachricht]]></item>
-               <item name="wcf.conversation.message.add"><![CDATA[Neue Antwort erstellen]]></item>
-               <item name="wcf.conversation.message.add.previousPosts"><![CDATA[{if $items == 1}Vorherige Nachricht{else}Vorherige Nachrichten{/if}]]></item>
                <item name="wcf.conversation.message.button.add"><![CDATA[Antworten]]></item>
                <item name="wcf.conversation.message.edit"><![CDATA[Nachricht bearbeiten]]></item>
                <item name="wcf.conversation.noConversations"><![CDATA[Es wurden keine Konversationen gefunden.]]></item>
                <item name="wcf.conversation.noMoreItems"><![CDATA[Keine aktuellen Konversationen]]></item>
                <item name="wcf.conversation.participantCanInvite"><![CDATA[Teilnehmer können weitere Teilnehmer hinzufügen]]></item>
                <item name="wcf.conversation.participants"><![CDATA[Teilnehmer]]></item>
-               <item name="wcf.conversation.participants.description"><![CDATA[Mehrere Teilnehmer können mit Komma getrennt angegeben werden.]]></item>
+               <item name="wcf.conversation.participants.description"><![CDATA[]]></item>
                <item name="wcf.conversation.participants.error.mailboxIsFull"><![CDATA[{$errorData[username]} hat das zulässige Limit für Konversationen bereits erreicht und kann an keinen neuen Konversationen teilnehmen.]]></item>
                <item name="wcf.conversation.participants.error.notFound"><![CDATA[Der Benutzername {$errorData[username]} konnte nicht gefunden werden.]]></item>
-               <item name="wcf.conversation.participants.error.isAuthor"><![CDATA[Sie sind bereits Teilnehmer dieser Konversation.]]></item>
+               <item name="wcf.conversation.participants.error.isAuthor"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du bist{else}Sie sind{/if} bereits Teilnehmer dieser Konversation.]]></item>
                <item name="wcf.conversation.participants.error.duplicate"><![CDATA[{$errorData[username]} ist bereits Teilnehmer dieser Konversation.]]></item>
                <item name="wcf.conversation.participants.error.canNotUseConversation"><![CDATA[{$errorData[username]} besitzt nicht die notwendigen Berechtigungen, um an einer Konversation teilnehmen zu dürfen.]]></item>
                <item name="wcf.conversation.participants.error.doesNotAcceptConversation"><![CDATA[{$errorData[username]} möchte nicht an Konversationen teilnehmen.]]></item>
-               <item name="wcf.conversation.participants.error.ignoresYou"><![CDATA[{$errorData[username]} hat Sie blockiert.]]></item>
-               <item name="wcf.conversation.participants.error.tooManyParticipants"><![CDATA[Sie haben zu viele Teilnehmer angegeben. Das Maximum liegt bei {#$__wcf->getSession()->getPermission('user.conversation.maxParticipants')} Teilnehmern.]]></item>
-               <item name="wcf.conversation.participants.error.invisibleParticipantsNoPermission"><![CDATA[Sie haben keine Berechtigung, unsichtbare Teilnehmer hinzuzufügen.]]></item>
-               <item name="wcf.conversation.participants.error.participantCanInviteNoPermission"><![CDATA[Sie haben keine Berechtigung, Teilnehmern das Hinzufügen weiterer Teilnehmer zu erlauben.]]></item>
+               <item name="wcf.conversation.participants.error.ignoresYou"><![CDATA[{$errorData[username]} hat {if LANGUAGE_USE_INFORMAL_VARIANT}dich{else}Sie{/if} blockiert.]]></item>
+               <item name="wcf.conversation.participants.error.tooManyParticipants"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du hast{else}Sie haben{/if} zu viele Teilnehmer angegeben. Das Maximum liegt bei {#$__wcf->getSession()->getPermission('user.conversation.maxParticipants')} Teilnehmern.]]></item>
+               <item name="wcf.conversation.participants.error.invisibleParticipantsNoPermission"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du hast{else}Sie haben{/if} keine Berechtigung, unsichtbare Teilnehmer hinzuzufügen.]]></item>
+               <item name="wcf.conversation.participants.error.participantCanInviteNoPermission"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du hast{else}Sie haben{/if} keine Berechtigung, Teilnehmern das Hinzufügen weiterer Teilnehmer zu erlauben.]]></item>
                <item name="wcf.conversation.participants.removeParticipant"><![CDATA[Teilnehmer entfernen]]></item>
-               <item name="wcf.conversation.participants.removeParticipant.confirmMessage"><![CDATA[Wollen Sie {$participant->username} wirklich aus dieser Konversation entfernen?]]></item>
+               <item name="wcf.conversation.participants.removeParticipant.confirmMessage"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Willst du{else}Wollen Sie{/if} <span class="confirmationObject">{$participant->username}</span> wirklich aus dieser Konversation entfernen?]]></item>
                <item name="wcf.conversation.quota"><![CDATA[Speicherplatz]]></item>
                <item name="wcf.conversation.quota.description"><![CDATA[{#$conversationCount/$maxConversationCount*100}% belegt ({#$conversationCount} von {#$maxConversationCount})]]></item>
                <item name="wcf.conversation.replies"><![CDATA[Antworten]]></item>
+               <item name="wcf.conversation.reply"><![CDATA[Auf diese Konversation antworten…]]></item>
                <item name="wcf.conversation.showAll"><![CDATA[Alle Konversationen anzeigen]]></item>
-               <item name="wcf.conversation.ownPosts"><![CDATA[Diese Konversation enthält Nachrichten von Ihnen.]]></item>
+               <item name="wcf.conversation.ownPosts"><![CDATA[Diese Konversation enthält Nachrichten von {if LANGUAGE_USE_INFORMAL_VARIANT}dir{else}Ihnen{/if}.]]></item>
                <item name="wcf.conversation.gotoLastPost"><![CDATA[Zur letzten Nachricht springen]]></item>
                <item name="wcf.conversation.searchConversations"><![CDATA[Konversationen durchsuchen]]></item>
+               <item name="wcf.conversation.searchConversation"><![CDATA[Aktuelle Konversation durchsuchen]]></item>
+               <item name="wcf.conversation.searchedConversation"><![CDATA[Nur Konversation <a href="{link controller='Conversation' object=$searchedConversation}{/link}">{$searchedConversation->getTitle()}</a> durchsuchen]]></item>
                <item name="wcf.conversation.participants.other"><![CDATA[und {if $conversation->participants - $participantSummaryCount == 1}ein weiterer{else}{#$conversation->participants-$participantSummaryCount} weitere{/if}]]></item>
                <item name="wcf.conversation.attachments"><![CDATA[Diese Konversation enthält {if $conversation->attachments == 1}einen Dateianhang{else}{#$conversation->attachments} Dateianhänge{/if}.]]></item>
-               <item name="wcf.conversation.error.mailboxIsFull"><![CDATA[Sie haben das zulässige Limit für Konversationen bereits erreicht und können keine neuen Konversationen starten.]]></item>
+               <item name="wcf.conversation.error.mailboxIsFull"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du hast{else}Sie haben{/if} das zulässige Limit für Konversationen bereits erreicht und können keine neuen Konversationen starten.]]></item>
                <item name="wcf.conversation.markAllAsRead"><![CDATA[Alle Konversationen als gelesen markieren]]></item>
                <item name="wcf.conversation.message.editNote"><![CDATA[{$message->username} hat diese Nachricht {#$message->editCount} mal editiert, zuletzt: {@$message->lastEditTime|time}.]]></item>
-               <item name="wcf.conversation.noParticipantsWarning"><![CDATA[Sie sind dabei, auf eine Konversation ohne weitere Teilnehmer zu antworten. Alle anderen Teilnehmer haben diese Konversation verlassen. Niemand wird Ihre Nachricht lesen!]]></item>
+               <item name="wcf.conversation.noParticipantsWarning"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du bist{else}Sie sind{/if} dabei, auf eine Konversation ohne weitere Teilnehmer zu antworten. Alle anderen Teilnehmer haben diese Konversation verlassen. Niemand wird {if LANGUAGE_USE_INFORMAL_VARIANT}deine{else}Ihre{/if} Nachricht lesen!]]></item>
                <item name="wcf.conversation.message.permalink"><![CDATA[Permalink zur {#$startIndex}. Nachricht]]></item>
                <item name="wcf.conversation.markAsRead.doubleClick"><![CDATA[Konversation durch Doppelklick als gelesen markieren]]></item>
        </category>
                <item name="wcf.conversation.label.management.addLabel"><![CDATA[Label hinzufügen]]></item>
                <item name="wcf.conversation.label.management.addLabel.success"><![CDATA[Label wurde hinzugefügt]]></item>
                <item name="wcf.conversation.label.management.deleteLabel"><![CDATA[Label löschen]]></item>
-               <item name="wcf.conversation.label.management.deleteLabel.confirmMessage"><![CDATA[Wollen Sie das Label „#labelName#“ wirklich löschen?]]></item>
-               <item name="wcf.conversation.label.management.edit.description"><![CDATA[Klicken Sie ein Label an, um dieses zu bearbeiten oder zu löschen.]]></item>
+               <item name="wcf.conversation.label.management.deleteLabel.confirmMessage"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Willst du{else}Wollen Sie{/if} das Label <span class="confirmationObject">#labelName#</span> wirklich löschen?]]></item>
+               <item name="wcf.conversation.label.management.edit.description"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Klicke{else}Klicken Sie{/if} ein Label an, um dieses zu bearbeiten oder zu löschen.]]></item>
                <item name="wcf.conversation.label.management.editLabel"><![CDATA[Label „#labelName#“ bearbeiten]]></item>
                <item name="wcf.conversation.label.management.existingLabels"><![CDATA[Vorhandene Labels]]></item>
                <item name="wcf.conversation.label.placeholder"><![CDATA[Label]]></item>
        </category>
        
        <category name="wcf.page">
-               <item name="wcf.page.category.com.woltlab.wcf.conversation"><![CDATA[Konversationen]]></item>
-               <item name="wcf.page.com.woltlab.wcf.conversation.ConversationAddForm"><![CDATA[Neue Konversation starten]]></item>
-               <item name="wcf.page.com.woltlab.wcf.conversation.ConversationMessageAddForm"><![CDATA[Neue Konversationsantwort erstellen]]></item>
-               <item name="wcf.page.com.woltlab.wcf.conversation.ConversationMessageEditForm"><![CDATA[Konversationsnachricht bearbeiten]]></item>
-               <item name="wcf.page.com.woltlab.wcf.conversation.ConversationListPage"><![CDATA[Konversationen]]></item>
-               <item name="wcf.page.com.woltlab.wcf.conversation.ConversationPage"><![CDATA[Konversation]]></item>
+               <item name="wcf.page.onlineLocation.com.woltlab.wcf.conversation.Conversation"><![CDATA[Konversation <a href="{link controller='Conversation' object=$conversation}{/link}" class="conversationLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject}</a>]]></item>
        </category>
        
        <category name="wcf.search">
+               <item name="wcf.search.type.com.woltlab.wcf.conversation"><![CDATA[Diese Konversation]]></item>
                <item name="wcf.search.type.com.woltlab.wcf.conversation.message"><![CDATA[Konversationen]]></item>
                <item name="wcf.search.object.com.woltlab.wcf.conversation.message"><![CDATA[Konversation]]></item>
        </category>
                <item name="wcf.user.notification.conversation.message.message.stacked"><![CDATA[{if $count < 4}{@$authors[0]->getAnchorTag()}{if $count == 2} und {else}, {/if}{@$authors[1]->getAnchorTag()}{if $count == 3} und {@$authors[2]->getAnchorTag()}{/if}{else}{@$authors[0]->getAnchorTag()} und {#$count} weitere{/if} haben auf die Konversation <a href="{link controller='Conversation' object=$message->getConversation()}{/link}">{$message->getConversation()->getTitle()}</a> geantwortet.]]></item>
                <item name="wcf.user.notification.conversation.message.title"><![CDATA[Neue Antwort auf Konversation]]></item>
                <item name="wcf.user.notification.conversation.message.title.stacked"><![CDATA[{#$count} Teilnehmer haben auf eine Konversation geantwortet]]></item>
-               <item name="wcf.user.notification.conversation.message.mail"><![CDATA[{@$author->username} hat auf die Konversation "{@$message->getTitle()}" geantwortet:
-{if $notificationType == 'instant'}
----------------------------------
-{@$message->getMailText()} 
----------------------------------
-{/if}{link controller='Conversation' object=$message->getConversation() isEmail=true}messageID={@$message->messageID}{/link}#message{@$message->messageID}]]></item>
+               <item name="wcf.user.notification.conversation.message.mail.plaintext"><![CDATA[{@$authorList} {if $count == 1 && !$guestTimesTriggered}hat{else}haben{/if} auf die Konversation „{$event->getUserNotificationObject()->getConversation()->subject}“ [URL:{link controller='Conversation' object=$event->getUserNotificationObject()->getConversation() isEmail=true}{/link}] geantwortet{if $count == 1 && !$guestTimesTriggered}:{else}.{/if}]]></item>
+               <item name="wcf.user.notification.conversation.message.mail.html"><![CDATA[<p>{@$authorList} {if $count == 1 && !$guestTimesTriggered}hat{else}haben{/if} auf die Konversation <a href="{link controller='Conversation' object=$event->getUserNotificationObject()->getConversation() isEmail=true}{/link}">{$event->getUserNotificationObject()->getConversation()->subject}</a> geantwortet:</p>]]></item>
                <item name="wcf.user.notification.conversation.message"><![CDATA[{@$author->getAnchorTag()} hat die Konversation <a href="{link controller='Conversation' object=$conversation}{/link}">{$conversation->subject}</a> gestartet.]]></item>
                <item name="wcf.user.notification.conversation.title"><![CDATA[Neue Konversation]]></item>
-               <item name="wcf.user.notification.conversation.mail"><![CDATA[{@$author->username} hat die Konversation "{@$conversation->subject}" gestartet:
-{if $notificationType == 'instant'}
----------------------------------
-{@$conversation->getFirstMessage()->getMailText()} 
----------------------------------
-{/if}{link controller='Conversation' object=$conversation isEmail=true}{/link}]]></item>
+               <item name="wcf.user.notification.conversation.mail.plaintext"><![CDATA[{@$event->getAuthor()->username} [URL:{link controller='User' object=$event->getAuthor() isEmail=true}{/link}] hat die Konversation „{@$event->getUserNotificationObject()->subject}“ [URL:{link controller='Conversation' object=$event->getUserNotificationObject() isEmail=true}{/link}] gestartet:]]></item>
+               <item name="wcf.user.notification.conversation.mail.html"><![CDATA[<p><a href="{link controller='User' object=$event->getAuthor() isEmail=true}{/link}">{$event->getAuthor()->username}</a> hat die Konversation <a href="{link controller='Conversation' object=$event->getUserNotificationObject() isEmail=true}{/link}">{$event->getUserNotificationObject()->subject}</a> gestartet:</p>]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation"><![CDATA[Konversationen]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation.notification.conversation"><![CDATA[Neue Konversation]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation.message.notification.conversationMessage"><![CDATA[Antwort auf bestehende Konversation]]></item>
                <item name="wcf.user.option.conversationsPerPage"><![CDATA[Konversationen pro Seite]]></item>
                <item name="wcf.user.option.canSendConversation"><![CDATA[Kann Konversationen schreiben]]></item>
        </category>
-       
-       <category name="wcf.user.usersOnline">
-               <item name="wcf.user.usersOnline.location.ConversationAddForm"><![CDATA[Erstellt eine neue Konversation]]></item>
-               <item name="wcf.user.usersOnline.location.ConversationListPage"><![CDATA[Betrachtet die Liste seiner Konversationen]]></item>
-               <item name="wcf.user.usersOnline.location.ConversationMessageAddForm"><![CDATA[Schreibt eine Antwort auf die Konversation <a href="{link controller='Conversation' object=$conversation}{/link}" class="conversationLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject}</a>]]></item>
-               <item name="wcf.user.usersOnline.location.ConversationMessageEditForm"><![CDATA[Bearbeitet eine Nachricht in der Konversation <a href="{link controller='Conversation' object=$conversation}{/link}" class="conversationLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject}</a>]]></item>
-               <item name="wcf.user.usersOnline.location.ConversationPage"><![CDATA[Liest die Konversation <a href="{link controller='Conversation' object=$conversation}{/link}" class="conversationLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject}</a>]]></item>
-       </category>
 </language>
index 4e653b7323562d8a911e81e1f66a945e151e7d6b..4a095fe518a4d7c13b4c4e5b470dc60edbbd5fda 100644 (file)
@@ -59,7 +59,7 @@
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.markAsRead.confirmMessage"><![CDATA[Do you really want to mark the marked conversation{if $count != 1}s{/if} as read?]]></item>
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.open"><![CDATA[Open ({#$count})]]></item>
                <item name="wcf.clipboard.item.com.woltlab.wcf.conversation.conversation.restore"><![CDATA[Mark as Active ({#$count})]]></item>
-               <item name="wcf.clipboard.label.com.woltlab.wcf.conversation.conversation.marked"><![CDATA[{if $count == 1}One Conversation{else}{#$count} Conversations{/if} Marked]]></item>
+               <item name="wcf.clipboard.label.com.woltlab.wcf.conversation.conversation.marked"><![CDATA[{if $count == 1}One Conversation{else}{#$count} Conversations{/if}]]></item>
        </category>
        
        <category name="wcf.conversation">
@@ -67,6 +67,7 @@
                <item name="wcf.conversation.button.add"><![CDATA[New Conversation]]></item>
                <item name="wcf.conversation.button.saveAsDraft"><![CDATA[Save Draft]]></item>
                <item name="wcf.conversation.conversations"><![CDATA[Conversations]]></item>
+               <item name="wcf.conversation.filter.participants"><![CDATA[Filter by Participants]]></item>
                <item name="wcf.conversation.folders"><![CDATA[Folders]]></item>
                <item name="wcf.conversation.folder.draft"><![CDATA[Drafts]]></item>
                <item name="wcf.conversation.folder.hidden"><![CDATA[Hidden]]></item>
                <item name="wcf.conversation.information"><![CDATA[Details]]></item>
                <item name="wcf.conversation.invisible"><![CDATA[invisible]]></item>
                <item name="wcf.conversation.invisibleParticipants"><![CDATA[Invisible Participants]]></item>
-               <item name="wcf.conversation.invisibleParticipants.description"><![CDATA[Invisible participants remain invisible to other participants until they write a message. Separate multiple participants with a comma.]]></item>
+               <item name="wcf.conversation.invisibleParticipants.description"><![CDATA[Invisible participants remain invisible to other participants until they write a message.]]></item>
                <item name="wcf.conversation.lastPostTime"><![CDATA[Last Reply]]></item>
-               <item name="wcf.conversation.lastVisitTime"><![CDATA[Last Visited]]></item>
+               <item name="wcf.conversation.lastVisitTime"><![CDATA[Conversation Read]]></item>
                <item name="wcf.conversation.leave.title"><![CDATA[Manage Participation]]></item>
                <item name="wcf.conversation.markAllAsRead.confirmMessage"><![CDATA[Do you really want to mark all conversations as read?]]></item>
                <item name="wcf.conversation.message"><![CDATA[Message]]></item>
-               <item name="wcf.conversation.message.add"><![CDATA[Reply]]></item>
-               <item name="wcf.conversation.message.add.previousPosts"><![CDATA[Previous message{if $items != 1}s{/if}]]></item>
                <item name="wcf.conversation.message.button.add"><![CDATA[Reply]]></item>
                <item name="wcf.conversation.message.edit"><![CDATA[Edit Message]]></item>
                <item name="wcf.conversation.noConversations"><![CDATA[There are not any conversations at the moment.]]></item>
                <item name="wcf.conversation.noMoreItems"><![CDATA[You have no recent conversations.]]></item>
                <item name="wcf.conversation.participantCanInvite"><![CDATA[Participants can add new participants]]></item>
                <item name="wcf.conversation.participants"><![CDATA[Participants]]></item>
-               <item name="wcf.conversation.participants.description"><![CDATA[Separate multiple participants with a comma.]]></item>
+               <item name="wcf.conversation.participants.description"><![CDATA[]]></item>
                <item name="wcf.conversation.participants.error.mailboxIsFull"><![CDATA[{$errorData[username]} is already participating in too many conversations and cannot be added.]]></item>
                <item name="wcf.conversation.participants.error.notFound"><![CDATA[The username “{$errorData[username]}” does not exist.]]></item>
                <item name="wcf.conversation.participants.error.isAuthor"><![CDATA[You are already a participant of this conversation.]]></item>
                <item name="wcf.conversation.participants.error.invisibleParticipantsNoPermission"><![CDATA[You do not have the permission to add invisible participants.]]></item>
                <item name="wcf.conversation.participants.error.participantCanInviteNoPermission"><![CDATA[You do not have the permission to allow participants to add new participants.]]></item>
                <item name="wcf.conversation.participants.removeParticipant"><![CDATA[Remove Participant]]></item>
-               <item name="wcf.conversation.participants.removeParticipant.confirmMessage"><![CDATA[Do you really want to remove “{$participant->username}” from this conversation?]]></item>
+               <item name="wcf.conversation.participants.removeParticipant.confirmMessage"><![CDATA[Do you really want to remove <span class="confirmationObject">{$participant->username}</span> from this conversation?]]></item>
                <item name="wcf.conversation.quota"><![CDATA[Quota]]></item>
                <item name="wcf.conversation.quota.description"><![CDATA[{#$conversationCount/$maxConversationCount*100}% used ({#$conversationCount} of {#$maxConversationCount})]]></item>
                <item name="wcf.conversation.replies"><![CDATA[Replies]]></item>
+               <item name="wcf.conversation.reply"><![CDATA[Reply to this conversation…]]></item>
                <item name="wcf.conversation.showAll"><![CDATA[Display All Conversations]]></item>
                <item name="wcf.conversation.ownPosts"><![CDATA[Conversation contains your own messages]]></item>
-               <item name="wcf.conversation.gotoLastPost"><![CDATA[Jump to Last Message]]></item>
+               <item name="wcf.conversation.gotoLastPost"><![CDATA[Go to Last Message]]></item>
                <item name="wcf.conversation.searchConversations"><![CDATA[Search Conversations]]></item>
+               <item name="wcf.conversation.searchConversation"><![CDATA[Search This Conversation Only]]></item>
+               <item name="wcf.conversation.searchedConversation"><![CDATA[Only search conversation <a href="{link controller='Conversation' object=$searchedConversation}{/link}">{$searchedConversation->getTitle()}</a>]]></item>
                <item name="wcf.conversation.participants.other"><![CDATA[and {if $conversation->participants - $participantSummaryCount == 1}one other{else}{#$conversation->participants-$participantSummaryCount} others{/if}]]></item>
                <item name="wcf.conversation.attachments"><![CDATA[Conversation contains {#$conversation->attachments} attachment{if $conversation->attachments != 1}s{/if}]]></item>
                <item name="wcf.conversation.error.mailboxIsFull"><![CDATA[You have reached your maximum conversations limit and cannot start new conversations.]]></item>
                <item name="wcf.conversation.label.management.addLabel"><![CDATA[Add Label]]></item>
                <item name="wcf.conversation.label.management.addLabel.success"><![CDATA[Label was added]]></item>
                <item name="wcf.conversation.label.management.deleteLabel"><![CDATA[Delete Label]]></item>
-               <item name="wcf.conversation.label.management.deleteLabel.confirmMessage"><![CDATA[Do you really want to delete the label “#labelName#”?]]></item>
+               <item name="wcf.conversation.label.management.deleteLabel.confirmMessage"><![CDATA[Do you really want to delete the label <span class="confirmationObject">#labelName#</span>?]]></item>
                <item name="wcf.conversation.label.management.edit.description"><![CDATA[Click on a label to edit or delete it.]]></item>
                <item name="wcf.conversation.label.management.editLabel"><![CDATA[Edit Label “#labelName#”]]></item>
                <item name="wcf.conversation.label.management.existingLabels"><![CDATA[Existing Labels]]></item>
        </category>
        
        <category name="wcf.page">
-               <item name="wcf.page.category.com.woltlab.wcf.conversation"><![CDATA[Conversations]]></item>
-               <item name="wcf.page.com.woltlab.wcf.conversation.ConversationAddForm"><![CDATA[New Conversation]]></item>
-               <item name="wcf.page.com.woltlab.wcf.conversation.ConversationMessageAddForm"><![CDATA[Reply to Conversation]]></item>
-               <item name="wcf.page.com.woltlab.wcf.conversation.ConversationMessageEditForm"><![CDATA[Edit Conversation Message]]></item>
-               <item name="wcf.page.com.woltlab.wcf.conversation.ConversationListPage"><![CDATA[Conversations]]></item>
-               <item name="wcf.page.com.woltlab.wcf.conversation.ConversationPage"><![CDATA[Conversation]]></item>
+               <item name="wcf.page.onlineLocation.com.woltlab.wcf.conversation.Conversation"><![CDATA[Conversation <a href="{link controller='Conversation' object=$conversation}{/link}" class="conversationLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject}</a>]]></item>
        </category>
        
        <category name="wcf.search">
+               <item name="wcf.search.type.com.woltlab.wcf.conversation"><![CDATA[This Conversation]]></item>
                <item name="wcf.search.type.com.woltlab.wcf.conversation.message"><![CDATA[Conversations]]></item>
                <item name="wcf.search.object.com.woltlab.wcf.conversation.message"><![CDATA[Conversation]]></item>
        </category>
 {@$message->getMailText()} 
 ---------------------------------
 {/if}{link controller='Conversation' object=$message->getConversation() isEmail=true}messageID={@$message->messageID}{/link}#message{@$message->messageID}]]></item>
+               <item name="wcf.user.notification.conversation.message.mail.plaintext"><![CDATA[{@$authorList} replied to the conversation “{$event->getUserNotificationObject()->getConversation()->subject}” [URL:{link controller='Conversation' object=$event->getUserNotificationObject()->getConversation() isEmail=true}{/link}]{if $count == 1 && !$guestTimesTriggered}:{else}.{/if}]]></item>
+               <item name="wcf.user.notification.conversation.message.mail.html"><![CDATA[<p>{@$authorList} replied to the conversation <a href="{link controller='Conversation' object=$event->getUserNotificationObject()->getConversation() isEmail=true}{/link}">{$event->getUserNotificationObject()->getConversation()->subject}</a>:</p>]]></item>
                <item name="wcf.user.notification.conversation.message"><![CDATA[{@$author->getAnchorTag()} started the conversation <a href="{link controller='Conversation' object=$conversation}{/link}">{$conversation->subject}</a>.]]></item>
                <item name="wcf.user.notification.conversation.title"><![CDATA[New Conversation]]></item>
-               <item name="wcf.user.notification.conversation.mail"><![CDATA[{@$author->username} started the conversation "{@$conversation->subject}":
-{if $notificationType == 'instant'}
----------------------------------
-{@$conversation->getFirstMessage()->getMailText()} 
----------------------------------
-{/if}{link controller='Conversation' object=$conversation isEmail=true}{/link}]]></item>
+               <item name="wcf.user.notification.conversation.mail.plaintext"><![CDATA[{@$event->getAuthor()->username} [URL:{link controller='User' object=$event->getAuthor() isEmail=true}{/link}] started the conversation “{@$event->getUserNotificationObject()->subject}” [URL:{link controller='Conversation' object=$event->getUserNotificationObject() isEmail=true}{/link}]:]]></item>
+               <item name="wcf.user.notification.conversation.mail.html"><![CDATA[<p><a href="{link controller='User' object=$event->getAuthor() isEmail=true}{/link}">{$event->getAuthor()->username}</a> started the conversation <a href="{link controller='Conversation' object=$event->getUserNotificationObject() isEmail=true}{/link}">{$event->getUserNotificationObject()->subject}</a>:</p>]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation"><![CDATA[Conversations]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation.notification.conversation"><![CDATA[Notify me of new conversations]]></item>
                <item name="wcf.user.notification.com.woltlab.wcf.conversation.message.notification.conversationMessage"><![CDATA[Notify me of new replies in conversations]]></item>
                <item name="wcf.user.option.conversationsPerPage"><![CDATA[Conversations per Page]]></item>
                <item name="wcf.user.option.canSendConversation"><![CDATA[Can Add Me to Conversations]]></item>
        </category>
-       
-       <category name="wcf.user.usersOnline">
-               <item name="wcf.user.usersOnline.location.ConversationAddForm"><![CDATA[Creating a conversation]]></item>
-               <item name="wcf.user.usersOnline.location.ConversationListPage"><![CDATA[Viewing list of conversations]]></item>
-               <item name="wcf.user.usersOnline.location.ConversationMessageAddForm"><![CDATA[Writing a reply to conversation <a href="{link controller='Conversation' object=$conversation}{/link}" class="conversationLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject}</a>]]></item>
-               <item name="wcf.user.usersOnline.location.ConversationMessageEditForm"><![CDATA[Editing message in conversation <a href="{link controller='Conversation' object=$conversation}{/link}" class="conversationLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject}</a>]]></item>
-               <item name="wcf.user.usersOnline.location.ConversationPage"><![CDATA[Reading conversation <a href="{link controller='Conversation' object=$conversation}{/link}" class="conversationLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject}</a>]]></item>
-       </category>
 </language>
index a37b38ec39bf6e360be3ef63650a36f3dcfad39d..9b0ff4353bdb138c5875b876be043d1bf8925daf 100644 (file)
                </type>
                <!-- /Modification Log -->
                
-               <!-- user online locations -->
-               <type>
-                       <name>com.woltlab.wcf.conversation.ConversationListPage</name>
-                       <definitionname>com.woltlab.wcf.user.online.location</definitionname>
-                       <controller>wcf\page\ConversationListPage</controller>
-                       <languagevariable>wcf.user.usersOnline.location.ConversationListPage</languagevariable>
-               </type>
-               <type>
-                       <name>com.woltlab.wcf.conversation.ConversationAddForm</name>
-                       <definitionname>com.woltlab.wcf.user.online.location</definitionname>
-                       <controller>wcf\form\ConversationAddForm</controller>
-                       <languagevariable>wcf.user.usersOnline.location.ConversationAddForm</languagevariable>
-               </type>
-               <type>
-                       <name>com.woltlab.wcf.conversation.ConversationPage</name>
-                       <definitionname>com.woltlab.wcf.user.online.location</definitionname>
-                       <classname>wcf\system\user\online\location\ConversationLocation</classname>
-                       <controller>wcf\page\ConversationPage</controller>
-                       <languagevariable>wcf.user.usersOnline.location.ConversationPage</languagevariable>
-               </type>
-               <type>
-                       <name>com.woltlab.wcf.conversation.ConversationMessageAddForm</name>
-                       <definitionname>com.woltlab.wcf.user.online.location</definitionname>
-                       <classname>wcf\system\user\online\location\ConversationLocation</classname>
-                       <controller>wcf\form\ConversationMessageAddForm</controller>
-                       <languagevariable>wcf.user.usersOnline.location.ConversationMessageAddForm</languagevariable>
-               </type>
-               <type>
-                       <name>com.woltlab.wcf.conversation.ConversationMessageEditForm</name>
-                       <definitionname>com.woltlab.wcf.user.online.location</definitionname>
-                       <classname>wcf\system\user\online\location\ConversationLocation</classname>
-                       <controller>wcf\form\ConversationMessageEditForm</controller>
-                       <languagevariable>wcf.user.usersOnline.location.ConversationMessageEditForm</languagevariable>
-               </type>
-               <!-- /user online locations -->
-               
                <!-- importers -->
                <type>
                        <name>com.woltlab.wcf.conversation</name>
                        <definitionname>com.woltlab.wcf.importer</definitionname>
-                       <classname><![CDATA[wcf\system\importer\ConversationImporter]]></classname>
+                       <classname>wcf\system\importer\ConversationImporter</classname>
                </type>
                <type>
                        <name>com.woltlab.wcf.conversation.label</name>
                        <definitionname>com.woltlab.wcf.importer</definitionname>
-                       <classname><![CDATA[wcf\system\importer\ConversationLabelImporter]]></classname>
+                       <classname>wcf\system\importer\ConversationLabelImporter</classname>
                </type>
                <type>
                        <name>com.woltlab.wcf.conversation.message</name>
                        <definitionname>com.woltlab.wcf.importer</definitionname>
-                       <classname><![CDATA[wcf\system\importer\ConversationMessageImporter]]></classname>
+                       <classname>wcf\system\importer\ConversationMessageImporter</classname>
                </type>
                <type>
                        <name>com.woltlab.wcf.conversation.user</name>
                        <definitionname>com.woltlab.wcf.importer</definitionname>
-                       <classname><![CDATA[wcf\system\importer\ConversationUserImporter]]></classname>
+                       <classname>wcf\system\importer\ConversationUserImporter</classname>
                </type>
                <type>
                        <name>com.woltlab.wcf.conversation.attachment</name>
                        <definitionname>com.woltlab.wcf.importer</definitionname>
-                       <classname><![CDATA[wcf\system\importer\ConversationAttachmentImporter]]></classname>
+                       <classname>wcf\system\importer\ConversationAttachmentImporter</classname>
                </type>
                <!-- /importers -->
                
                <type>
                        <name>com.woltlab.wcf.conversation</name>
                        <definitionname>com.woltlab.wcf.rebuildData</definitionname>
-                       <classname><![CDATA[wcf\system\worker\ConversationRebuildDataWorker]]></classname>
+                       <classname>wcf\system\worker\ConversationRebuildDataWorker</classname>
                </type>
                <type>
                        <name>com.woltlab.wcf.conversation.message</name>
                        <definitionname>com.woltlab.wcf.rebuildData</definitionname>
-                       <classname><![CDATA[wcf\system\worker\ConversationMessageRebuildDataWorker]]></classname>
+                       <classname>wcf\system\worker\ConversationMessageRebuildDataWorker</classname>
                        <nicevalue>-5</nicevalue>
                </type>
                <!-- /rebuild data workers -->
                
-               <!-- pages -->
-               <type>
-                       <name>com.woltlab.wcf.conversation.ConversationAddForm</name>
-                       <definitionname>com.woltlab.wcf.page</definitionname>
-                       <classname><![CDATA[wcf\form\ConversationAddForm]]></classname>
-                       <options>module_conversation</options>
-                       <categoryname>com.woltlab.wcf.conversation</categoryname>
-               </type>
-               <type>
-                       <name>com.woltlab.wcf.conversation.ConversationMessageAddForm</name>
-                       <definitionname>com.woltlab.wcf.page</definitionname>
-                       <classname><![CDATA[wcf\form\ConversationMessageAddForm]]></classname>
-                       <options>module_conversation</options>
-                       <categoryname>com.woltlab.wcf.conversation</categoryname>
-               </type>
-               <type>
-                       <name>com.woltlab.wcf.conversation.ConversationMessageEditForm</name>
-                       <definitionname>com.woltlab.wcf.page</definitionname>
-                       <classname><![CDATA[wcf\form\ConversationMessageEditForm]]></classname>
-                       <options>module_conversation</options>
-                       <categoryname>com.woltlab.wcf.conversation</categoryname>
-               </type>
-               <type>
-                       <name>com.woltlab.wcf.conversation.ConversationListPage</name>
-                       <definitionname>com.woltlab.wcf.page</definitionname>
-                       <classname><![CDATA[wcf\page\ConversationListPage]]></classname>
-                       <options>module_conversation</options>
-                       <categoryname>com.woltlab.wcf.conversation</categoryname>
-               </type>
-               <type>
-                       <name>com.woltlab.wcf.conversation.ConversationPage</name>
-                       <definitionname>com.woltlab.wcf.page</definitionname>
-                       <classname><![CDATA[wcf\page\ConversationPage]]></classname>
-                       <options>module_conversation</options>
-                       <categoryname>com.woltlab.wcf.conversation</categoryname>
-               </type>
-               <!-- /pages -->
-               
                <!-- stat handlers -->
                <type>
                        <name>com.woltlab.wcf.conversation</name>
                        <definitionname>com.woltlab.wcf.statDailyHandler</definitionname>
-                       <classname><![CDATA[wcf\system\stat\ConversationStatDailyHandler]]></classname>
+                       <classname>wcf\system\stat\ConversationStatDailyHandler</classname>
                        <categoryname>com.woltlab.wcf.conversation</categoryname>
                </type>
                <type>
                        <name>com.woltlab.wcf.conversation.message</name>
                        <definitionname>com.woltlab.wcf.statDailyHandler</definitionname>
-                       <classname><![CDATA[wcf\system\stat\ConversationMessageStatDailyHandler]]></classname>
+                       <classname>wcf\system\stat\ConversationMessageStatDailyHandler</classname>
                        <categoryname>com.woltlab.wcf.conversation</categoryname>
                </type>
                <!-- /stat handlers -->
index 507134dc4b7c4e1bb05b7ff02387864074518e44..02e57c565244a8e1ac545c65e032425b7566e573 100644 (file)
                                <categoryname>message.conversation</categoryname>
                                <optiontype>select</optiontype>
                                <defaultvalue>lastPostTime</defaultvalue>
-                               <selectoptions><![CDATA[subject:wcf.global.subject
-lastPostTime:wcf.conversation.lastPostTime]]></selectoptions>
+                               <selectoptions>subject:wcf.global.subject
+lastPostTime:wcf.conversation.lastPostTime</selectoptions>
                        </option>
                        <option name="conversation_list_default_sort_order">
                                <categoryname>message.conversation</categoryname>
                                <optiontype>select</optiontype>
                                <defaultvalue>DESC</defaultvalue>
-                               <selectoptions><![CDATA[ASC:wcf.global.sortOrder.ascending
-DESC:wcf.global.sortOrder.descending]]></selectoptions>
+                               <selectoptions>ASC:wcf.global.sortOrder.ascending
+DESC:wcf.global.sortOrder.descending</selectoptions>
                        </option>
                </options>
        </import>
index fa1516e84991f8079412dff2387248e4d5105ad7..0044dac429ab415e85fd565f3801b4a7d63499fe 100644 (file)
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <package name="com.woltlab.wcf.conversation" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/package.xsd">
        <packageinformation>
-               <packagename>User Conversation System</packagename>
-               <packagedescription>Private conversations between multiple users.</packagedescription>
-               <version>2.1.6</version>
-               <date>2016-06-01</date>
+               <packagename>WoltLab Suite Core: Conversations</packagename>
+               <packagedescription>Private conversations between multiple users</packagedescription>
+               <version>3.0.0 Beta 2</version>
+               <date>2016-10-03</date>
        </packageinformation>
        
        <authorinformation>
        </authorinformation>
        
        <requiredpackages>
-               <requiredpackage minversion="2.1.11">com.woltlab.wcf</requiredpackage>
+               <requiredpackage minversion="3.0.0 Beta 2">com.woltlab.wcf</requiredpackage>
        </requiredpackages>
        
        <excludedpackages>
-               <excludedpackage version="2.2.0 Alpha 1">com.woltlab.wcf</excludedpackage>
+               <excludedpackage version="3.1.0 Alpha 1">com.woltlab.wcf</excludedpackage>
        </excludedpackages>
        
        <instructions type="install">
-               <instruction type="file">files.tar</instruction>
-               <instruction type="userGroupOption">userGroupOption.xml</instruction>
-               <instruction type="sql">install.sql</instruction>
-               <instruction type="template">templates.tar</instruction>
-               <instruction type="option">option.xml</instruction>
-               <instruction type="templateListener">templateListener.xml</instruction>
-               <instruction type="language">language/*.xml</instruction>
-               <instruction type="objectType">objectType.xml</instruction>
-               <instruction type="clipboardAction">clipboardAction.xml</instruction>
-               <instruction type="coreObject">coreObject.xml</instruction>
-               <instruction type="userNotificationEvent">userNotificationEvent.xml</instruction>
-               <instruction type="userOption">userOption.xml</instruction>
-               <instruction type="eventListener">eventListener.xml</instruction>
-               <instruction type="script">acp/install_com.woltlab.wcf.conversation_2.0.0.php</instruction>
+               <instruction type="file" />
+               <instruction type="userGroupOption" />
+               <instruction type="sql" />
+               <instruction type="template" />
+               <instruction type="option" />
+               <instruction type="templateListener" />
+               <instruction type="language" />
+               <instruction type="objectType" />
+               <instruction type="clipboardAction" />
+               <instruction type="coreObject" />
+               <instruction type="userNotificationEvent" />
+               <instruction type="userOption" />
+               <instruction type="eventListener" />
+               <instruction type="script">acp/install_com.woltlab.wcf.conversation.php</instruction>
+               <instruction type="page" />
        </instructions>
        
-       <instructions type="update" fromversion="2.0.10">
-               <instruction type="file" run="standalone">files.tar</instruction>
-               <instruction type="template" run="standalone">templates.tar</instruction>
-               
-               <instruction type="language" run="standalone">language/*.xml</instruction>
-               
-               <instruction type="sql" run="standalone">update1_210.sql</instruction>
-               <instruction type="sql" run="standalone">update2_210.sql</instruction>
-               <instruction type="sql" run="standalone">update3_210.sql</instruction>
-               
-               <instruction type="clipboardAction">clipboardAction.xml</instruction>
-               <instruction type="eventListener">eventListener_update210.xml</instruction>
-               <instruction type="objectType">objectType.xml</instruction>
-               <instruction type="option">option.xml</instruction>
-               <instruction type="userGroupOption">userGroupOption.xml</instruction>
-               <instruction type="userOption">userOption.xml</instruction>
-       </instructions>
-       
-       <instructions type="update" fromversion="2.1.5">
+       <instructions type="update" fromversion="3.0.0 Beta 1">
                <instruction type="file">files_update.tar</instruction>
                <instruction type="template">templates_update.tar</instruction>
                
-               <instruction type="language">language/*.xml</instruction>
+               <instruction type="language" />
        </instructions>
 </package>
diff --git a/page.xml b/page.xml
new file mode 100644 (file)
index 0000000..ecfcf5e
--- /dev/null
+++ b/page.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/maelstrom/page.xsd">
+       <import>
+               <page identifier="com.woltlab.wcf.conversation.ConversationList">
+                       <controller>wcf\page\ConversationListPage</controller>
+                       <handler>wcf\system\page\handler\ConversationListPageHandler</handler>
+                       <name language="de">Konversationenliste</name>
+                       <name language="en">Conversation List</name>
+                       <pageType>system</pageType>
+                       
+                       <content language="en">
+                               <title>Conversations</title>
+                       </content>
+                       <content language="de">
+                               <title>Konversationen</title>
+                       </content>
+               </page>
+               <page identifier="com.woltlab.wcf.conversation.Conversation">
+                       <controller>wcf\page\ConversationPage</controller>
+                       <handler>wcf\system\page\handler\DefaultConversationRelatedPageHandler</handler>
+                       <name language="de">Konversation</name>
+                       <name language="en">Conversation</name>
+                       <pageType>system</pageType>
+                       <requireObjectID>1</requireObjectID>
+                       <hasFixedParent>1</hasFixedParent>
+                       <parent>com.woltlab.wcf.conversation.ConversationList</parent>
+               </page>
+               <page identifier="com.woltlab.wcf.conversation.ConversationAdd">
+                       <controller>wcf\form\ConversationAddForm</controller>
+                       <name language="de">Konversation starten</name>
+                       <name language="en">New Conversation</name>
+                       <pageType>system</pageType>
+                       <hasFixedParent>1</hasFixedParent>
+                       <parent>com.woltlab.wcf.conversation.ConversationList</parent>
+                       
+                       <content language="en">
+                               <title>New Conversation</title>
+                       </content>
+                       <content language="de">
+                               <title>Konversation starten</title>
+                       </content>
+               </page>
+       </import>
+</data>
index 4764803f9f03d753bd1723a866e9b6e3e8406c3d..48e741367f8d9cf4a708667dcff1d82b801e82f6 100644 (file)
@@ -3,7 +3,7 @@
        <import>
                <templatelistener name="userPanel">
                        <environment>user</environment>
-                       <templatename>userPanel</templatename>
+                       <templatename>pageHeaderUser</templatename>
                        <eventname>menuItems</eventname>
                        <templatecode><![CDATA[{include file='__userPanelConversationDropdown'}]]></templatecode>
                </templatelistener>
                
                <templatelistener name="searchAreaConversationSettings">
                        <environment>user</environment>
-                       <templatename>searchArea</templatename>
+                       <templatename>pageHeaderSearch</templatename>
                        <eventname>settings</eventname>
                        <templatecode><![CDATA[{include file='__searchAreaConversationSettings'}]]></templatecode>
                </templatelistener>
+               
+               <templatelistener name="userProfileStartConversation">
+                       <environment>user</environment>
+                       <templatename>user</templatename>
+                       <eventname>menuInteraction</eventname>
+                       <templatecode><![CDATA[{include file='__userProfileStartConversation'}]]></templatecode>
+               </templatelistener>
+               
+               <templatelistener name="mobileMenuConversation">
+                       <environment>user</environment>
+                       <templatename>pageMenuMobile</templatename>
+                       <eventname>userMenuItems</eventname>
+                       <templatecode><![CDATA[{include file='__mobileMenuConversation'}]]></templatecode>
+               </templatelistener>
        </import>
-</data>
\ No newline at end of file
+       
+       <delete>
+               <templatelistener name="searchAreaConversationSettings">
+                       <environment>user</environment>
+                       <templatename>searchArea</templatename>
+                       <eventname>settings</eventname>
+                       <templatecode><![CDATA[{include file='__searchAreaConversationSettings'}]]></templatecode>
+               </templatelistener>
+       </delete>
+</data>
diff --git a/templates/__mobileMenuConversation.tpl b/templates/__mobileMenuConversation.tpl
new file mode 100644 (file)
index 0000000..98c9302
--- /dev/null
@@ -0,0 +1,7 @@
+<li class="menuOverlayItem" data-more="com.woltlab.wcf.conversation">
+       <a href="{link controller='ConversationList'}{/link}" class="menuOverlayItemLink menuOverlayItemBadge box24" data-badge-identifier="unreadConversations">
+               <span class="icon icon24 fa-comments"></span>
+               <span class="menuOverlayItemTitle">{lang}wcf.conversation.conversations{/lang}</span>
+               {if $__wcf->getConversationHandler()->getUnreadConversationCount()}<span class="badge badgeUpdate">{#$__wcf->getConversationHandler()->getUnreadConversationCount()}</span>{/if}
+       </a>
+</li>
index b5566292d92581a1cb9cc115ee893c98df4dc0be..532987ad9eb02fc410f1cabce1461dd1bdfa8c80 100644 (file)
@@ -1,5 +1,8 @@
 {if $__searchAreaInitialized|empty && $templateName|substr:0:12 == 'conversation'}
-       {capture assign='__searchInputPlaceholder'}{lang}wcf.conversation.searchConversations{/lang}{/capture}
-       {capture assign='__searchHiddenInputFields'}<input type="hidden" name="types[]" value="com.woltlab.wcf.conversation.message" />{/capture}
-       {assign var='__searchAreaInitialized' value=true}
-{/if}
\ No newline at end of file
+       {assign var='__searchObjectTypeName' value='com.woltlab.wcf.conversation.message'}
+       
+       {if $__wcf->getActivePage()->identifier == 'com.woltlab.wcf.conversation.Conversation'}
+               {capture assign='__searchTypeLabel'}{lang}wcf.search.type.com.woltlab.wcf.conversation{/lang}{/capture}
+               {capture assign='__searchTypesScoped'}<li><a href="#" data-extended-link="{link controller='Search'}types[]=com.woltlab.wcf.conversation.message{/link}" data-object-type="com.woltlab.wcf.conversation.message" data-parameters='{ "conversationID": {@$conversation->conversationID} }'>{lang}wcf.search.type.com.woltlab.wcf.conversation{/lang}</a></li>{/capture}
+       {/if}
+{/if}
index 9f6d949eff9654e92e034dfe5740eaeed30b67f7..d4649421fb764f559b65536299c36cb17ffbc413 100644 (file)
@@ -1,3 +1,3 @@
 {if MODULE_CONVERSATION && $__wcf->user->userID && $__wcf->session->getPermission('user.conversation.canUseConversation') && $user->userID != $__wcf->user->userID}
-       <li><a class="jsTooltip" href="{link controller='ConversationAdd'}userID={@$user->userID}{/link}" title="{lang}wcf.conversation.button.add{/lang}"><span class="icon icon16 icon-comments"></span> <span class="invisible">{lang}wcf.conversation.button.add{/lang}</span></a></li>
+       <li><a class="jsTooltip" href="{link controller='ConversationAdd'}userID={@$user->userID}{/link}" title="{lang}wcf.conversation.button.add{/lang}"><span class="icon icon16 fa-comments"></span> <span class="invisible">{lang}wcf.conversation.button.add{/lang}</span></a></li>
 {/if}
\ No newline at end of file
index cd0146c1aa642c5004a2755c5562613b861d472f..10b9f0a9dbc6fd1a11334f08f64b75c68deeb48d 100644 (file)
@@ -1,10 +1,9 @@
 {if MODULE_CONVERSATION && $__wcf->user->userID && $__wcf->session->getPermission('user.conversation.canUseConversation')}
        <li id="unreadConversations" data-count="{#$__wcf->getConversationHandler()->getUnreadConversationCount()}">
-               <a href="{link controller='ConversationList'}{/link}"><span class="icon icon16 icon-comments"></span> <span>{lang}wcf.conversation.conversations{/lang}</span> {if $__wcf->getConversationHandler()->getUnreadConversationCount()}<span class="badge badgeInverse">{#$__wcf->getConversationHandler()->getUnreadConversationCount()}</span>{/if}</a>
+               <a class="jsTooltip" href="{link controller='ConversationList'}{/link}" title="{lang}wcf.conversation.conversations{/lang}"><span class="icon icon32 fa-comments"></span> <span>{lang}wcf.conversation.conversations{/lang}</span> {if $__wcf->getConversationHandler()->getUnreadConversationCount()}<span class="badge badgeUpdate">{#$__wcf->getConversationHandler()->getUnreadConversationCount()}</span>{/if}</a>
                {if !OFFLINE || $__wcf->session->getPermission('admin.general.canViewPageDuringOfflineMode')}
                        <script data-relocate="true" src="{@$__wcf->getPath()}js/WCF.Conversation{if !ENABLE_DEBUG_MODE}.min{/if}.js?v={@LAST_UPDATE_TIME}"></script>
                        <script data-relocate="true">
-                               //<![CDATA[
                                $(function() {
                                        new WCF.User.Panel.Conversation({
                                                markAllAsReadConfirmMessage: '{lang}wcf.conversation.markAllAsRead.confirmMessage{/lang}',
@@ -15,7 +14,6 @@
                                                title: '{lang}wcf.conversation.conversations{/lang}'
                                        });
                                });
-                               //]]>
                        </script>
                {/if}
        </li>
diff --git a/templates/__userProfileStartConversation.tpl b/templates/__userProfileStartConversation.tpl
new file mode 100644 (file)
index 0000000..41741fc
--- /dev/null
@@ -0,0 +1 @@
+{if MODULE_CONVERSATION && $__wcf->user->userID && $__wcf->session->getPermission('user.conversation.canUseConversation') && $user->userID != $__wcf->user->userID}<li><a href="{link controller='ConversationAdd'}userID={@$user->userID}{/link}">{lang}wcf.conversation.button.add{/lang}</a></li>{/if}
index 27ca5827088a97da12336b9d5bf3d72e47799242..1413606de979c5ca14c58bd219bf8e7251cd4d0b 100644 (file)
@@ -1 +1 @@
-{if MODULE_CONVERSATION && $__wcf->user->userID && $__wcf->session->getPermission('user.conversation.canUseConversation') && $user->userID != $__wcf->user->userID}<li><a class="button jsTooltip" href="{link controller='ConversationAdd'}userID={@$user->userID}{/link}" title="{lang}wcf.conversation.button.add{/lang}"><span class="icon icon16 icon-comments"></span> <span class="invisible">{lang}wcf.conversation.button.add{/lang}</span></a></li>{/if}
\ No newline at end of file
+{if MODULE_CONVERSATION && $__wcf->user->userID && $__wcf->session->getPermission('user.conversation.canUseConversation') && $user->userID != $__wcf->user->userID}<li><a class="button jsTooltip" href="{link controller='ConversationAdd'}userID={@$user->userID}{/link}" title="{lang}wcf.conversation.button.add{/lang}"><span class="icon icon16 fa-comments"></span> <span class="invisible">{lang}wcf.conversation.button.add{/lang}</span></a></li>{/if}
\ No newline at end of file
index 968a47b78abd8781a83fd0d84cee7baab2a215a9..7f2d9071f7ce4e3f2185a745eaafd4ef76c9c943 100644 (file)
-{include file='documentHeader'}
+{capture assign='pageTitle'}{$conversation->subject} {if $pageNo > 1} - {lang}wcf.page.pageNo{/lang}{/if}{/capture}
 
-<head>
-       <title>{$conversation->subject} {if $pageNo > 1}- {lang}wcf.page.pageNo{/lang} {/if} - {PAGE_TITLE|language}</title>
-       
-       {include file='headInclude'}
-       
-       <script data-relocate="true" src="{@$__wcf->getPath()}js/WCF.Conversation{if !ENABLE_DEBUG_MODE}.min{/if}.js?v={@LAST_UPDATE_TIME}"></script>
-       <script data-relocate="true">
-               //<![CDATA[
-               $(function() {
-                       WCF.Language.addObject({
-                               'wcf.conversation.edit.addParticipants': '{lang}wcf.conversation.edit.addParticipants{/lang}',
-                               'wcf.conversation.edit.assignLabel': '{lang}wcf.conversation.edit.assignLabel{/lang}',
-                               'wcf.conversation.edit.close': '{lang}wcf.conversation.edit.close{/lang}',
-                               'wcf.conversation.edit.leave': '{lang}wcf.conversation.edit.leave{/lang}',
-                               'wcf.conversation.edit.open': '{lang}wcf.conversation.edit.open{/lang}',
-                               'wcf.conversation.leave.title': '{lang}wcf.conversation.leave.title{/lang}',
-                               'wcf.global.state.closed': '{lang}wcf.global.state.closed{/lang}',
-                               'wcf.message.bbcode.code.copy': '{lang}wcf.message.bbcode.code.copy{/lang}',
-                               'wcf.message.error.editorAlreadyInUse': '{lang}wcf.message.error.editorAlreadyInUse{/lang}',
-                               'wcf.moderation.report.reportContent': '{lang}wcf.moderation.report.reportContent{/lang}',
-                               'wcf.moderation.report.success': '{lang}wcf.moderation.report.success{/lang}',
-                               'wcf.conversation.label.assignLabels': '{lang}wcf.conversation.label.assignLabels{/lang}'
-                       });
+{capture assign='contentHeader'}
+       <header class="contentHeader">
+               <div class="contentHeaderIcon">
+                       {@$conversation->getUserProfile()->getAvatar()->getImageTag(64)}
+               </div>
+               
+               <div class="contentHeaderTitle">
+                       <h1 class="contentTitle">{$conversation->subject}</h1>
                        
-                       var $availableLabels = [ {implode from=$labelList item=label}{ cssClassName: '{if $label->cssClassName}{@$label->cssClassName}{/if}', labelID: {@$label->labelID}, label: '{$label->label}' }{/implode} ];
-                       var $editorHandler = new WCF.Conversation.EditorHandlerConversation($availableLabels);
-                       var $inlineEditor = new WCF.Conversation.InlineEditor('.conversation');
-                       $inlineEditor.setEditorHandler($editorHandler);
-                       
-                       {assign var=__supportPaste value=true}
-                       {if $conversation->isClosed}{assign var=__supportPaste value=false}{/if}
-                       {include file='__messageQuoteManager' wysiwygSelector='text' supportPaste=$__supportPaste}
-                       
-                       new WCF.Conversation.Message.InlineEditor({@$conversation->conversationID}, $quoteManager);
-                       new WCF.Conversation.Message.QuoteHandler($quoteManager);
-                       {if !$conversation->isClosed}new WCF.Conversation.QuickReply($quoteManager);{/if}
-                       
-                       {if $__wcf->session->getPermission('user.profile.canReportContent')}
-                               new WCF.Moderation.Report.Content('com.woltlab.wcf.conversation.message', '.jsReportConversationMessage');
-                       {/if}
-                       new WCF.Conversation.RemoveParticipant({@$conversation->conversationID});
-                       new WCF.Message.BBCode.CodeViewer();
-               });
-               //]]>
-       </script>
-</head>
-
-<body id="tpl{$templateName|ucfirst}" data-template="{$templateName}" data-application="{$templateNameApplication}">
+                       <ul class="inlineList contentHeaderMetaData">
+                               {hascontent}
+                                       <li>
+                                               <span class="icon icon16 fa-tags"></span>
+                                               <ul class="labelList">
+                                                       {content}
+                                                               {foreach from=$conversation->getAssignedLabels() item=label}
+                                                                       <li><span class="label badge{if $label->cssClassName} {$label->cssClassName}{/if}">{lang}{$label->label}{/lang}</span></li>
+                                                               {/foreach}
+                                                       {/content}
+                                               </ul>
+                                       </li>
+                               {/hascontent}
+                               
+                               <li>
+                                       <span class="icon icon16 fa-user"></span>
+                                       {if $conversation->userID}
+                                               <a href="{link controller='User' object=$conversation->getUserProfile()->getDecoratedObject()}{/link}" class="userLink" data-user-id="{@$conversation->userID}">{$conversation->username}</a>
+                                       {else}
+                                               {$conversation->username}
+                                       {/if}
+                               </li>
+                               
+                               <li>
+                                       <span class="icon icon16 fa-clock-o"></span>
+                                       {@$conversation->time|time}
+                               </li>
+                               
+                               {if $conversation->isClosed}
+                                       <li>
+                                               <span class="icon icon16 fa-lock jsIconLock"></span>
+                                               {lang}wcf.global.state.closed{/lang}
+                                       </li>
+                               {/if}
+                       </ul>
+               </div>
+               
+               <nav class="contentHeaderNavigation">
+                       <ul class="conversation jsConversationInlineEditorContainer" data-conversation-id="{@$conversation->conversationID}" data-label-ids="[ {implode from=$conversation->getAssignedLabels() item=label}{@$label->labelID}{/implode} ]" data-is-closed="{@$conversation->isClosed}" data-can-close-conversation="{if $conversation->userID == $__wcf->getUser()->userID}1{else}0{/if}" data-can-add-participants="{if $conversation->canAddParticipants()}1{else}0{/if}">
+                               <li class="jsOnly"><a href="#" class="button jsConversationInlineEditor"><span class="icon icon16 fa-pencil"></span> <span>{lang}wcf.global.button.edit{/lang}</span></a></li>
+                               {if !$conversation->isClosed}<li class="jsOnly"><a href="#" title="{lang}wcf.conversation.message.add{/lang}" class="button buttonPrimary jsQuickReply"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.conversation.message.button.add{/lang}</span></a></li>{/if}
+                               {event name='contentHeaderNavigation'}
+                       </ul>
+               </nav>
+       </header>
+{/capture}
 
 {include file='header'}
 
-<header class="boxHeadline marginTop conversationHeadline labeledHeadline">
-       <h1><a href="{link controller='Conversation' object=$conversation}{/link}">{$conversation->subject}</a>{if $conversation->isClosed} <span class="icon icon16 icon-lock jsTooltip jsIconLock" title="{lang}wcf.global.state.closed{/lang}"></span>{/if}</h1>
-       
-       {hascontent}
-               <ul class="labelList">
-                       {content}
-                               {foreach from=$conversation->getAssignedLabels() item=label}
-                                       <li><span class="label badge{if $label->cssClassName} {$label->cssClassName}{/if}">{lang}{$label->label}{/lang}</span></li>
-                               {/foreach}
-                       {/content}
-               </ul>
-       {/hascontent}
-       
-       {event name='headlineData'}
-</header>
-
-{include file='userNotice'}
-
 {if !$conversation->isDraft}
-       <div class="container containerPadding marginTop">
-               <fieldset>
-                       <legend>{lang}wcf.conversation.participants{/lang}</legend>
-                       
-                       <ul class="containerBoxList tripleColumned conversationParticipantList">
-                               {foreach from=$participants item=participant}
-                                       <li class="jsParticipant{if !$participant->userID || $participant->hideConversation == 2} conversationLeft{/if}">
-                                               <div class="box24">
-                                                       {if $participant->userID}<a href="{link controller='User' object=$participant}{/link}" class="framed">{@$participant->getAvatar()->getImageTag(24)}</a>{else}<span class="framed">{@$participant->getAvatar()->getImageTag(24)}</span>{/if}
-                                                       <div>
-                                                               <p>
-                                                                       {if $participant->userID}<a href="{link controller='User' object=$participant}{/link}" class="userLink" data-user-id="{@$participant->userID}">{$participant->username}</a>{else}<span>{$participant->username}</span>{/if}
-                                                                       {if $participant->isInvisible}<small>({lang}wcf.conversation.invisible{/lang})</small>{/if}
-                                                                       {if $participant->userID && ($conversation->userID == $__wcf->getUser()->userID) && ($participant->userID != $__wcf->getUser()->userID) && $participant->hideConversation != 2}
-                                                                               <a href="#" class="jsDeleteButton jsTooltip jsOnly" title="{lang}wcf.conversation.participants.removeParticipant{/lang}" data-confirm-message="{lang}wcf.conversation.participants.removeParticipant.confirmMessage{/lang}" data-object-id="{@$participant->userID}"><span class="icon icon16 icon-remove"></span></a>
-                                                                       {/if}
-                                                               </p>
-                                                               <dl class="plain inlineDataList">
-                                                                       <dt>{lang}wcf.conversation.lastVisitTime{/lang}</dt>
-                                                                       <dd>{if $participant->lastVisitTime}{@$participant->lastVisitTime|time}{else}-{/if}</dd>
-                                                               </dl>
-                                                       </div>
+       <section class="section">
+               <h2 class="sectionTitle">{lang}wcf.conversation.participants{/lang}</h2>
+               
+               <ul class="containerBoxList tripleColumned conversationParticipantList">
+                       {foreach from=$participants item=participant}
+                               <li class="jsParticipant{if !$participant->userID || $participant->hideConversation == 2} conversationLeft{/if}">
+                                       <div class="box24">
+                                               {if $participant->userID}<a href="{link controller='User' object=$participant}{/link}">{@$participant->getAvatar()->getImageTag(24)}</a>{else}<span>{@$participant->getAvatar()->getImageTag(24)}</span>{/if}
+                                               <div>
+                                                       <p>
+                                                               {if $participant->userID}<a href="{link controller='User' object=$participant}{/link}" class="userLink" data-user-id="{@$participant->userID}">{$participant->username}</a>{else}<span>{$participant->username}</span>{/if}
+                                                               {if $participant->isInvisible}<small>({lang}wcf.conversation.invisible{/lang})</small>{/if}
+                                                               {if $participant->userID && ($conversation->userID == $__wcf->getUser()->userID) && ($participant->userID != $__wcf->getUser()->userID) && $participant->hideConversation != 2}
+                                                                       <a href="#" class="jsDeleteButton jsTooltip jsOnly" title="{lang}wcf.conversation.participants.removeParticipant{/lang}" data-confirm-message-html="{lang __encode=true}wcf.conversation.participants.removeParticipant.confirmMessage{/lang}" data-object-id="{@$participant->userID}"><span class="icon icon16 fa-times"></span></a>
+                                                               {/if}
+                                                       </p>
+                                                       <dl class="plain inlineDataList small">
+                                                               <dt>{lang}wcf.conversation.lastVisitTime{/lang}</dt>
+                                                               <dd>{if $participant->lastVisitTime}{@$participant->lastVisitTime|time}{else}-{/if}</dd>
+                                                       </dl>
                                                </div>
-                                       </li>
-                               {/foreach}
-                       </ul>
-               </fieldset>
-       </div>
+                                       </div>
+                               </li>
+                       {/foreach}
+               </ul>
+       </section>
 {/if}
 
-<div class="contentNavigation">
-       {pages print=true assign=pagesLinks controller='Conversation' object=$conversation link="pageNo=%d"}
-       
-       <nav>
-               <ul class="conversation jsConversationInlineEditorContainer" data-conversation-id="{@$conversation->conversationID}" data-label-ids="[ {implode from=$conversation->getAssignedLabels() item=label}{@$label->labelID}{/implode} ]" data-is-closed="{@$conversation->isClosed}" data-can-close-conversation="{if $conversation->userID == $__wcf->getUser()->userID}1{else}0{/if}" data-can-add-participants="{if $conversation->canAddParticipants()}1{else}0{/if}">
-                       <li class="jsOnly"><a href="#" class="button jsConversationInlineEditor"><span class="icon icon16 icon-pencil"></span> <span>{lang}wcf.global.button.edit{/lang}</span></a></li>
-                       {if !$conversation->isClosed}<li><a href="{link controller='ConversationMessageAdd' id=$conversationID}{/link}" title="{lang}wcf.conversation.message.add{/lang}" class="button buttonPrimary jsQuickReply"><span class="icon icon16 icon-plus"></span> <span>{lang}wcf.conversation.message.button.add{/lang}</span></a></li>{/if}
-                       {event name='contentNavigationButtonsTop'}
-               </ul>
-       </nav>
-</div>
+{hascontent}
+       <div class="paginationTop">
+               {content}{pages print=true assign=pagesLinks controller='Conversation' object=$conversation link="pageNo=%d"}{/content}
+       </div>
+{/hascontent}
 
-<div class="marginTop">
+<div class="section">
        <ul class="messageList">
                {include file='conversationMessageList'}
+               {hascontent}
+                       <li class="messageListPagination">
+                               {content}{@$pagesLinks}{/content}
+                       </li>
+               {/hascontent}
                {if !$conversation->isClosed}{include file='conversationQuickReply'}{/if}
        </ul>
 </div>
 
-<div class="contentNavigation">
-       {@$pagesLinks}
-       
-       {hascontent}
-               <nav>
-                       <ul>
-                               {content}
-                                       {if !$conversation->isClosed}<li><a href="{link controller='ConversationMessageAdd' id=$conversationID}{/link}" title="{lang}wcf.conversation.message.add{/lang}" class="button buttonPrimary jsQuickReply"><span class="icon icon16 icon-plus"></span> <span>{lang}wcf.conversation.message.button.add{/lang}</span></a></li>{/if}
-                                       {event name='contentNavigationButtonsBottom'}
-                               {/content}
-                       </ul>
-               </nav>
-       {/hascontent}
-</div>
+{if !ENABLE_DEBUG_MODE}<script src="{@$__wcf->getPath()}js/WoltLabSuite.Core.Conversation.min.js?v={@LAST_UPDATE_TIME}"></script>{/if}
+<script data-relocate="true" src="{@$__wcf->getPath()}js/WCF.Conversation{if !ENABLE_DEBUG_MODE}.min{/if}.js?v={@LAST_UPDATE_TIME}"></script>
+<script data-relocate="true">
+       $(function() {
+               WCF.Language.addObject({
+                       'wcf.conversation.edit.addParticipants': '{lang}wcf.conversation.edit.addParticipants{/lang}',
+                       'wcf.conversation.edit.assignLabel': '{lang}wcf.conversation.edit.assignLabel{/lang}',
+                       'wcf.conversation.edit.close': '{lang}wcf.conversation.edit.close{/lang}',
+                       'wcf.conversation.edit.leave': '{lang}wcf.conversation.edit.leave{/lang}',
+                       'wcf.conversation.edit.open': '{lang}wcf.conversation.edit.open{/lang}',
+                       'wcf.conversation.leave.title': '{lang}wcf.conversation.leave.title{/lang}',
+                       'wcf.global.state.closed': '{lang}wcf.global.state.closed{/lang}',
+                       'wcf.message.bbcode.code.copy': '{lang}wcf.message.bbcode.code.copy{/lang}',
+                       'wcf.message.error.editorAlreadyInUse': '{lang}wcf.message.error.editorAlreadyInUse{/lang}',
+                       'wcf.moderation.report.reportContent': '{lang}wcf.moderation.report.reportContent{/lang}',
+                       'wcf.moderation.report.success': '{lang}wcf.moderation.report.success{/lang}',
+                       'wcf.conversation.label.assignLabels': '{lang}wcf.conversation.label.assignLabels{/lang}'
+               });
+               
+               var $availableLabels = [ {implode from=$labelList item=label}{ cssClassName: '{if $label->cssClassName}{@$label->cssClassName}{/if}', labelID: {@$label->labelID}, label: '{$label->label}' }{/implode} ];
+               var $editorHandler = new WCF.Conversation.EditorHandlerConversation($availableLabels);
+               var $inlineEditor = new WCF.Conversation.InlineEditor('.conversation');
+               $inlineEditor.setEditorHandler($editorHandler);
+               
+               {assign var=__supportPaste value=true}
+               {if $conversation->isClosed}{assign var=__supportPaste value=false}{/if}
+               {include file='__messageQuoteManager' wysiwygSelector='text' supportPaste=$__supportPaste}
+               
+               new WCF.Conversation.Message.InlineEditor({@$conversation->conversationID}, $quoteManager);
+               new WCF.Conversation.Message.QuoteHandler($quoteManager);
+               {* if !$conversation->isClosed}new WCF.Conversation.QuickReply($quoteManager);{/if *}
+               
+               {if $__wcf->session->getPermission('user.profile.canReportContent')}
+               new WCF.Moderation.Report.Content('com.woltlab.wcf.conversation.message', '.jsReportConversationMessage');
+               {/if}
+               new WCF.Conversation.RemoveParticipant({@$conversation->conversationID});
+               new WCF.Message.BBCode.CodeViewer();
+       });
+</script>
 
 {include file='footer'}
-
-</body>
-</html>
index 478478081b186c1038485051d1b17eef2d7325ef..66258ab103b7805a2f6dd6cafd6f394551165efd 100644 (file)
@@ -1,93 +1,61 @@
-{include file='documentHeader'}
-
-<head>
-       <title>{lang}wcf.conversation.add{/lang} - {PAGE_TITLE|language}</title>
-       
-       {include file='headInclude'}
-       
-       <script data-relocate="true">
-               //<![CDATA[
-               $(function() {
-                       new WCF.Search.User('#participants', null, false, [ ], true);
-                       new WCF.Search.User('#invisibleParticipants', null, false, [ ], true);
-                       
-                       WCF.Message.Submit.registerButton('text', $('#messageContainer > .formSubmit > input[type=submit]'));
-                       new WCF.Message.FormGuard();
-                       
-                       WCF.System.Dependency.Manager.register('Redactor_text', function() { new WCF.Message.UserMention('text'); });
-                       
-                       {include file='__messageQuoteManager' wysiwygSelector='text' supportPaste=true}
-               });
-               //]]>
-       </script>
-</head>
-
-<body id="tpl{$templateName|ucfirst}" data-template="{$templateName}" data-application="{$templateNameApplication}">
 {include file='header'}
 
-<header class="boxHeadline">
-       <h1>{lang}wcf.conversation.add{/lang}</h1>
-</header>
-
-{include file='userNotice'}
-
 {include file='formError'}
 
 <form id="messageContainer" class="jsFormGuard" method="post" action="{link controller='ConversationAdd'}{/link}">
-       <div class="container containerPadding marginTop">
-               <fieldset>
-                       <legend>{lang}wcf.conversation.information{/lang}</legend>
-                       
-                       <dl{if $errorField == 'subject'} class="formError"{/if}>
-                               <dt><label for="subject">{lang}wcf.global.subject{/lang}</label></dt>
-                               <dd>
-                                       <input type="text" id="subject" name="subject" value="{$subject}" required="required" maxlength="255" class="long" />
-                                       {if $errorField == 'subject'}
-                                               <small class="innerError">
-                                                       {if $errorType == 'empty'}
-                                                               {lang}wcf.global.form.error.empty{/lang}
-                                                       {elseif $errorType == 'censoredWordsFound'}
-                                                               {lang}wcf.message.error.censoredWordsFound{/lang}
-                                                       {else}
-                                                               {lang}wcf.conversation.subject.error.{@$errorType}{/lang}
-                                                       {/if}
-                                               </small>
-                                       {/if}
-                               </dd>
-                       </dl>
-                       
-                       {event name='informationFields'}
-               </fieldset>
+       <section class="section">
+               <h2 class="sectionTitle">{lang}wcf.conversation.information{/lang}</h2>
                
-               <fieldset>
-                       <legend>{lang}wcf.conversation.participants{/lang}</legend>
-                       
-                       <dl{if $errorField == 'participants'} class="formError"{/if}>
-                               <dt><label for="participants">{lang}wcf.conversation.participants{/lang}</label></dt>
-                               <dd>
-                                       <textarea id="participants" name="participants" class="long" cols="40" rows="2">{$participants}</textarea>
-                                       {if $errorField == 'participants'}
-                                               <small class="innerError">
-                                                       {if $errorType == 'empty'}
-                                                               {lang}wcf.global.form.error.empty{/lang}
-                                                       {elseif $errorType|is_array}
-                                                               {foreach from=$errorType item='errorData'}
-                                                                       {lang}wcf.conversation.participants.error.{@$errorData.type}{/lang}
-                                                               {/foreach}
-                                                       {else}
-                                                               {lang}wcf.conversation.participants.error.{@$errorType}{/lang}
-                                                       {/if}
-                                               </small>
-                                       {/if}
-                                       <small>{lang}wcf.conversation.participants.description{/lang}</small>
-                               </dd>
-                       </dl>
-                       
-                       {if $__wcf->session->getPermission('user.conversation.canAddInvisibleParticipants')}
+               <dl{if $errorField == 'subject'} class="formError"{/if}>
+                       <dt><label for="subject">{lang}wcf.global.subject{/lang}</label></dt>
+                       <dd>
+                               <input type="text" id="subject" name="subject" value="{$subject}" required maxlength="255" class="long">
+                               {if $errorField == 'subject'}
+                                       <small class="innerError">
+                                               {if $errorType == 'empty'}
+                                                       {lang}wcf.global.form.error.empty{/lang}
+                                               {elseif $errorType == 'censoredWordsFound'}
+                                                       {lang}wcf.message.error.censoredWordsFound{/lang}
+                                               {else}
+                                                       {lang}wcf.conversation.subject.error.{@$errorType}{/lang}
+                                               {/if}
+                                       </small>
+                               {/if}
+                       </dd>
+               </dl>
+               
+               {event name='informationFields'}
+       </section>
+       
+       <section class="section">
+               <h2 class="sectionTitle">{lang}wcf.conversation.participants{/lang}</h2>
+               
+               <dl{if $errorField == 'participants'} class="formError"{/if}>
+                       <dt><label for="participants">{lang}wcf.conversation.participants{/lang}</label></dt>
+                       <dd>
+                               <input type="text" id="participants" name="participants" class="long" value="{$participants}">
+                               {if $errorField == 'participants'}
+                                       <small class="innerError">
+                                               {if $errorType == 'empty'}
+                                                       {lang}wcf.global.form.error.empty{/lang}
+                                               {elseif $errorType|is_array}
+                                                       {foreach from=$errorType item='errorData'}
+                                                               {lang}wcf.conversation.participants.error.{@$errorData.type}{/lang}
+                                                       {/foreach}
+                                               {else}
+                                                       {lang}wcf.conversation.participants.error.{@$errorType}{/lang}
+                                               {/if}
+                                       </small>
+                               {/if}
+                               <small>{lang}wcf.conversation.participants.description{/lang}</small>
+                       </dd>
+               </dl>
+               
+               {if $__wcf->session->getPermission('user.conversation.canAddInvisibleParticipants')}
                        <dl{if $errorField == 'invisibleParticipants'} class="formError"{/if}>
                                <dt><label for="invisibleParticipants">{lang}wcf.conversation.invisibleParticipants{/lang}</label></dt>
                                <dd>
-                                       <textarea id="invisibleParticipants" name="invisibleParticipants" class="long" cols="40" rows="2">{$invisibleParticipants}</textarea>
+                                       <input type="text" id="invisibleParticipants" name="invisibleParticipants" class="long" value="{$invisibleParticipants}">
                                        {if $errorField == 'invisibleParticipants'}
                                                <small class="innerError">
                                                        {if $errorType == 'empty'}
                                        <small>{lang}wcf.conversation.invisibleParticipants.description{/lang}</small>
                                </dd>
                        </dl>
-                       {/if}
-                       
-                       {if $__wcf->session->getPermission('user.conversation.canSetCanInvite')}
+               {/if}
+               
+               {if $__wcf->session->getPermission('user.conversation.canSetCanInvite')}
                        <dl>
                                <dt></dt>
                                <dd>
-                                       <label><input type="checkbox" name="participantCanInvite" id="participantCanInvite" value="1"{if $participantCanInvite} checked="checked"{/if} /> {lang}wcf.conversation.participantCanInvite{/lang}</label>
-                               </dd>
-                       </dl>
-                       {/if}
-                       
-                       {event name='participantFields'}
-               </fieldset>
-                       
-               <fieldset>
-                       <legend>{lang}wcf.conversation.message{/lang}</legend>
-                       
-                       <dl class="wide{if $errorField == 'text'} formError{/if}">
-                               <dt><label for="text">{lang}wcf.conversation.message{/lang}</label></dt>
-                               <dd>
-                                       <textarea id="text" name="text" rows="20" cols="40" data-autosave="com.woltlab.wcf.conversation.conversationAdd" data-autosave-prompt="true">{$text}</textarea>
-                                       {if $errorField == 'text'}
-                                               <small class="innerError">
-                                                       {if $errorType == 'empty'}
-                                                               {lang}wcf.global.form.error.empty{/lang}
-                                                       {elseif $errorType == 'tooLong'}
-                                                               {lang}wcf.message.error.tooLong{/lang}
-                                                       {elseif $errorType == 'censoredWordsFound'}
-                                                               {lang}wcf.message.error.censoredWordsFound{/lang}
-                                                       {elseif $errorType == 'disallowedBBCodes'}
-                                                               {lang}wcf.message.error.disallowedBBCodes{/lang}
-                                                       {else}
-                                                               {lang}wcf.conversation.message.error.{@$errorType}{/lang}
-                                                       {/if}
-                                               </small>
-                                       {/if}
+                                       <label><input type="checkbox" name="participantCanInvite" id="participantCanInvite" value="1"{if $participantCanInvite} checked{/if}> {lang}wcf.conversation.participantCanInvite{/lang}</label>
                                </dd>
                        </dl>
-                       
-                       {event name='messageFields'}
-               </fieldset>
+               {/if}
                
-               {include file='messageFormTabs' wysiwygContainerID='text'}
+               {event name='participantFields'}
+       </section>
                
-               {event name='fieldsets'}
-       </div>
+       <section class="section">
+               <h2 class="sectionTitle">{lang}wcf.conversation.message{/lang}</h2>
+               
+               <dl class="wide{if $errorField == 'text'} formError{/if}">
+                       <dt><label for="text">{lang}wcf.conversation.message{/lang}</label></dt>
+                       <dd>
+                               <textarea id="text" name="text" class="wysiwygTextarea"
+                                         data-autosave="com.woltlab.wcf.conversation.conversationAdd"
+                                         data-autosave-prompt="true"
+                                         data-support-mention="true"
+                               >{$text}</textarea>
+                               {if $errorField == 'text'}
+                                       <small class="innerError">
+                                               {if $errorType == 'empty'}
+                                                       {lang}wcf.global.form.error.empty{/lang}
+                                               {elseif $errorType == 'tooLong'}
+                                                       {lang}wcf.message.error.tooLong{/lang}
+                                               {elseif $errorType == 'censoredWordsFound'}
+                                                       {lang}wcf.message.error.censoredWordsFound{/lang}
+                                               {elseif $errorType == 'disallowedBBCodes'}
+                                                       {lang}wcf.message.error.disallowedBBCodes{/lang}
+                                               {else}
+                                                       {lang}wcf.conversation.message.error.{@$errorType}{/lang}
+                                               {/if}
+                                       </small>
+                               {/if}
+                       </dd>
+               </dl>
+               
+               {event name='messageFields'}
+       </section>
+       
+       {include file='messageFormTabs' wysiwygContainerID='text'}
+       
+       {event name='sections'}
        
        <div class="formSubmit">
-               <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
+               <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
                <button name="draft" accesskey="d" value="1">{lang}wcf.conversation.button.saveAsDraft{/lang}</button>
-               {include file='messageFormPreviewButton'}
+               {include file='messageFormPreviewButton' previewMessageObjectType='com.woltlab.wcf.conversation.message' previewMessageObjectID=0}
                {@SECURITY_TOKEN_INPUT_TAG}
        </div>
 </form>
 
-{include file='footer'}
-{include file='wysiwyg'}
+<script data-relocate="true">
+       require(['WoltLabSuite/Core/Ui/ItemList/User'], function(UiItemListUser) {
+               UiItemListUser.init('participants', {
+                       maxItems: {@$__wcf->getSession()->getPermission('user.conversation.maxParticipants')}
+               });
+               
+               UiItemListUser.init('invisibleParticipants', {
+                       maxItems: {@$__wcf->getSession()->getPermission('user.conversation.maxParticipants')}
+               });
+       });
+       
+       $(function() {
+               WCF.Message.Submit.registerButton('text', $('#messageContainer > .formSubmit > input[type=submit]'));
+               new WCF.Message.FormGuard();
+               
+               {include file='__messageQuoteManager' wysiwygSelector='text' supportPaste=true}
+       });
+</script>
 
-</body>
-</html>
\ No newline at end of file
+{include file='wysiwyg'}
+{include file='footer'}
index 7113213acf3ead01fc2f773a48aef1a3fa034258..3dd779352c53e7635a0b0db877cf5cddb0a9d423 100644 (file)
@@ -1,14 +1,10 @@
-<fieldset>
-       <legend>{lang}wcf.conversation.edit.addParticipants{/lang}</legend>
-       
-       <dl class="jsAddParticipants">
-               <dt><label for="participantsInput">{lang}wcf.conversation.participants{/lang}</label></dt>
-               <dd>
-                       <textarea id="participantsInput" name="participants" class="long" cols="40" rows="2"></textarea>
-                       <small>{lang}wcf.conversation.participants.description{/lang}</small>
-               </dd>
-       </dl>
-</fieldset>
+<dl class="jsAddParticipants">
+       <dt><label for="participantsInput">{lang}wcf.conversation.participants{/lang}</label></dt>
+       <dd>
+               <textarea id="participantsInput" name="participants" class="long" cols="40" rows="2"></textarea>
+               <small>{lang}wcf.conversation.participants.description{/lang}</small>
+       </dd>
+</dl>
 
 <div class="formSubmit">
        <button id="addParticipants" class="buttonPrimary">{lang}wcf.global.button.submit{/lang}</button>
index c78d8f355bab4a7a507f66e87600479871d59588..f231a2d00adf6404de5e25c2b74770360673a667 100644 (file)
@@ -1,17 +1,17 @@
-<fieldset>
-       <legend>{lang}wcf.conversation.label.assignLabels{/lang}</legend>
+<section class="section">
+       <h2 class="sectionTitle">{lang}wcf.conversation.label.assignLabels{/lang}</h2>
        
        <ul>
                {foreach from=$labelList item=label}
                        <li>
                                <label>
-                                       <input type="checkbox"{if $label->labelID|in_array:$assignedLabels} checked="checked"{/if} data-label-id="{@$label->labelID}" />
+                                       <input type="checkbox"{if $label->labelID|in_array:$assignedLabels} checked{/if} data-label-id="{@$label->labelID}">
                                        <span class="badge label{if $label->cssClassName} {@$label->cssClassName}{/if}">{$label->label}</span>
                                </label>
                        </li>
                {/foreach}
        </ul>
-</fieldset>
+</section>
 
 <div class="formSubmit">
        <button class="buttonPrimary" id="assignLabels">{lang}wcf.global.button.save{/lang}</button>
index 69475cfef18ddae4ba64fbe5eb06b9b7b1151ee4..7ef21e749bd6de63a360ddb3d32baad9bd9cccfd 100644 (file)
@@ -1,25 +1,25 @@
 {hascontent}
-       <fieldset>
-               <legend>{lang}wcf.conversation.label.management.existingLabels{/lang}</legend>
-       </fieldset>
-       
-       <ul class="conversationLabelList">
-               {content}
-                       {foreach from=$labelList item=label}
-                               <li><a class="badge label{if $label->cssClassName} {@$label->cssClassName}{/if}" data-label-id="{@$label->labelID}" data-css-class-name="{if $label->cssClassName}{@$label->cssClassName}{else}none{/if}">{$label->label}</a></li>
-                       {/foreach}
-               {/content}
-       </ul>
-       
-       <small>{lang}wcf.conversation.label.management.edit.description{/lang}</small>
+       <section class="section">
+               <header class="sectionHeader">
+                       <h2 class="sectionTitle">{lang}wcf.conversation.label.management.existingLabels{/lang}</h2>
+                       <p class="sectionDescription">{lang}wcf.conversation.label.management.edit.description{/lang}</p>
+               </header>
+               <ul class="conversationLabelList">
+                       {content}
+                               {foreach from=$labelList item=label}
+                                       <li><a class="badge label{if $label->cssClassName} {@$label->cssClassName}{/if}" data-label-id="{@$label->labelID}" data-css-class-name="{if $label->cssClassName}{@$label->cssClassName}{else}none{/if}">{$label->label}</a></li>
+                               {/foreach}
+                       {/content}
+               </ul>
+       </section>
 {/hascontent}
 
-<fieldset id="conversationLabelManagementForm">
-       <legend>{lang}wcf.conversation.label.management.addLabel{/lang}</legend>
+<section class="section" id="conversationLabelManagementForm">
+       <h2 class="sectionTitle">{lang}wcf.conversation.label.management.addLabel{/lang}</h2>
        
        <dl>
                <dt><label for="labelName">{lang}wcf.conversation.label.labelName{/lang}</label></dt>
-               <dd><input type="text" id="labelName" class="long" /></dd>
+               <dd><input type="text" id="labelName" class="long"></dd>
        </dl>
        <dl>
                <dt>{lang}wcf.conversation.label.cssClassName{/lang}</dt>
@@ -27,7 +27,7 @@
                        <ul id="labelManagementList">
                                {foreach from=$cssClassNames item=cssClassName}
                                        <li><label>
-                                               <input type="radio" name="cssClassName" value="{@$cssClassName}"{if $cssClassName == 'none'} checked="checked"{/if} />
+                                               <input type="radio" name="cssClassName" value="{@$cssClassName}"{if $cssClassName == 'none'} checked{/if}>
                                                <span class="badge label{if $cssClassName != 'none'} {@$cssClassName}{/if}">{lang}wcf.conversation.label.placeholder{/lang}</span>
                                        </label></li>
                                {/foreach}
@@ -40,4 +40,4 @@
                <button id="editLabel" style="display: none;" class="buttonPrimary">{lang}wcf.global.button.save{/lang}</button>
                <button id="deleteLabel" style="display: none;">{lang}wcf.conversation.label.management.deleteLabel{/lang}</button>
        </div>
-</fieldset>
\ No newline at end of file
+</section>
\ No newline at end of file
index 480dfa09a79a1f37c4aa767577d0ca3ee5f9bf41..00eb2568c7bf4660308d4303ceaffced435fbdb9 100644 (file)
@@ -1,24 +1,24 @@
-<fieldset>
-       <legend>{lang}wcf.conversation.hideConversation{/lang}</legend>
+<section class="section">
+       <h2 class="sectionTitle">{lang}wcf.conversation.hideConversation{/lang}</h2>
        
        <dl class="wide">
                {if $hideConversation == 1}
                        <dd>
-                               <label><input type="radio" name="hideConversation" value="0" /> {lang}wcf.conversation.hideConversation.restore{/lang}</label>
+                               <label><input type="radio" name="hideConversation" value="0"> {lang}wcf.conversation.hideConversation.restore{/lang}</label>
                        </dd>
                {/if}
                {if $hideConversation != 1}
                        <dd>
-                               <label><input type="radio" name="hideConversation" value="1" /> {lang}wcf.conversation.hideConversation.leave{/lang}</label>
+                               <label><input type="radio" name="hideConversation" value="1"> {lang}wcf.conversation.hideConversation.leave{/lang}</label>
                                <small>{lang}wcf.conversation.hideConversation.leave.description{/lang}</small>
                        </dd>
                {/if}
                <dd>
-                       <label><input type="radio" name="hideConversation" value="2" /> {lang}wcf.conversation.hideConversation.leavePermanently{/lang}</label>
+                       <label><input type="radio" name="hideConversation" value="2"> {lang}wcf.conversation.hideConversation.leavePermanently{/lang}</label>
                        <small>{lang}wcf.conversation.hideConversation.leavePermanently.description{/lang}</small>
                </dd>
        </dl>
-</fieldset>
+</section>
 
 <div class="formSubmit">
        <button id="hideConversation" class="buttonPrimary">{lang}wcf.global.button.submit{/lang}</button>
index 4df3ecd1fd9b6d15e4c4f0f31938ba9f74651752..cddc08ff1d57d71f55a717f871bab9c932b3c8c2 100644 (file)
-{include file='documentHeader'}
+{capture assign='pageTitle'}{if $filter}{lang}wcf.conversation.folder.{$filter}{/lang}{else}{$__wcf->getActivePage()->getTitle()}{/if}{if $pageNo > 1} - {lang}wcf.page.pageNo{/lang}{/if}{/capture}
 
-<head>
-       <title>{lang}wcf.conversation.conversations{/lang} {if $pageNo > 1}- {lang}wcf.page.pageNo{/lang} {/if}- {PAGE_TITLE|language}</title>
-       
-       {include file='headInclude'}
-       
-       <link rel="alternate" type="application/rss+xml" title="{lang}wcf.global.button.rss{/lang}" href="{link controller='ConversationFeed' appendSession=false}at={@$__wcf->getUser()->userID}-{@$__wcf->getUser()->accessToken}{/link}" />
-       <script data-relocate="true" src="{@$__wcf->getPath()}js/WCF.Conversation{if !ENABLE_DEBUG_MODE}.min{/if}.js?v={@LAST_UPDATE_TIME}"></script>
-       <script data-relocate="true">
-               //<![CDATA[
-               $(function() {
-                       WCF.Language.addObject({
-                               'wcf.conversation.edit.addParticipants': '{lang}wcf.conversation.edit.addParticipants{/lang}',
-                               'wcf.conversation.edit.assignLabel': '{lang}wcf.conversation.edit.assignLabel{/lang}',
-                               'wcf.conversation.edit.close': '{lang}wcf.conversation.edit.close{/lang}',
-                               'wcf.conversation.edit.leave': '{lang}wcf.conversation.edit.leave{/lang}',
-                               'wcf.conversation.edit.open': '{lang}wcf.conversation.edit.open{/lang}',
-                               'wcf.conversation.label.management': '{lang}wcf.conversation.label.management{/lang}',
-                               'wcf.conversation.label.management.addLabel.success': '{lang}wcf.conversation.label.management.addLabel.success{/lang}',
-                               'wcf.conversation.label.management.deleteLabel.confirmMessage': '{lang}wcf.conversation.label.management.deleteLabel.confirmMessage{/lang}',
-                               'wcf.conversation.label.management.editLabel': '{lang}wcf.conversation.label.management.editLabel{/lang}',
-                               'wcf.conversation.label.placeholder': '{lang}wcf.conversation.label.placeholder{/lang}',
-                               'wcf.conversation.leave.title': '{lang}wcf.conversation.leave.title{/lang}',
-                               'wcf.global.state.closed': '{lang}wcf.global.state.closed{/lang}',
-                               'wcf.conversation.label.assignLabels': '{lang}wcf.conversation.label.assignLabels{/lang}'
-                       });
-                       
-                       WCF.Clipboard.init('wcf\\page\\ConversationListPage', {@$hasMarkedItems}, { });
-                       
-                       var $editorHandler = new WCF.Conversation.EditorHandler();
-                       var $inlineEditor = new WCF.Conversation.InlineEditor('.conversation');
-                       $inlineEditor.setEditorHandler($editorHandler, 'list');
-                       
-                       new WCF.Conversation.Clipboard($editorHandler);
-                       new WCF.Conversation.Label.Manager('{link controller='ConversationList' encode=false}{if $filter}filter={@$filter}{/if}&sortField={$sortField}&sortOrder={$sortOrder}&pageNo={@$pageNo}{/link}');
-                       new WCF.Conversation.Preview();
-                       new WCF.Conversation.MarkAsRead();
-                       new WCF.Conversation.MarkAllAsRead();
-                       
-                       // mobile safari hover workaround
-                       if ($(window).width() <= 800) {
-                               $('.sidebar').addClass('mobileSidebar').hover(function() { });
-                       }
-               });
-               //]]>
-       </script>
-</head>
-
-<body id="tpl{$templateName|ucfirst}" data-template="{$templateName}" data-application="{$templateNameApplication}">
-
-{capture assign='sidebar'}
-       <fieldset>
-               <legend>{lang}wcf.conversation.folders{/lang}</legend>
+{capture assign='contentHeader'}
+       <header class="contentHeader">
+               <div class="contentHeaderTitle">
+                       <h1 class="contentTitle">{if $filter}{lang}wcf.conversation.folder.{$filter}{/lang}{else}{$__wcf->getActivePage()->getTitle()}{/if}</h1>
+               </div>
                
-               <nav>
-                       <ul class="conversationFolderList">
-                               <li{if $filter == ''} class="active"{/if}><a href="{link controller='ConversationList'}{/link}">{lang}wcf.conversation.conversations{/lang}{if $conversationCount} <span class="badge">{#$conversationCount}</span>{/if}</a></li>
-                               <li{if $filter == 'draft'} class="active"{/if}><a href="{link controller='ConversationList'}filter=draft{/link}">{lang}wcf.conversation.folder.draft{/lang}{if $draftCount} <span class="badge">{#$draftCount}</span>{/if}</a></li>
-                               <li{if $filter == 'outbox'} class="active"{/if}><a href="{link controller='ConversationList'}filter=outbox{/link}">{lang}wcf.conversation.folder.outbox{/lang}{if $outboxCount} <span class="badge">{#$outboxCount}</span>{/if}</a></li>
-                               <li{if $filter == 'hidden'} class="active"{/if}><a href="{link controller='ConversationList'}filter=hidden{/link}">{lang}wcf.conversation.folder.hidden{/lang}{if $hiddenCount} <span class="badge">{#$hiddenCount}</span>{/if}</a></li>
+               <nav class="contentHeaderNavigation">
+                       <ul>
+                               <li><a href="{link controller='ConversationAdd'}{/link}" title="{lang}wcf.conversation.add{/lang}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.conversation.button.add{/lang}</span></a></li>
+                               {event name='contentHeaderNavigation'}
                        </ul>
                </nav>
-       </fieldset>
+       </header>
+{/capture}
+
+{capture assign='headContent'}
+       <link rel="alternate" type="application/rss+xml" title="{lang}wcf.global.button.rss{/lang}" href="{link controller='ConversationFeed'}at={@$__wcf->getUser()->userID}-{@$__wcf->getUser()->accessToken}{/link}">
+{/capture}
+
+{capture assign='sidebarRight'}
+       <section class="box">
+               <h2 class="boxTitle">{lang}wcf.conversation.folders{/lang}</h2>
+               
+               <div class="boxContent">
+                       <nav>
+                               <ol class="boxMenu">
+                                       <li{if $filter == ''} class="active"{/if}>
+                                               <a class="boxMenuLink" href="{link controller='ConversationList'}{/link}"><span class="boxMenuLinkTitle">{lang}wcf.conversation.conversations{/lang}</span>{if $conversationCount} <span class="badge">{#$conversationCount}</span>{/if}</a>
+                                       </li>
+                                       <li{if $filter == 'draft'} class="active"{/if}>
+                                               <a class="boxMenuLink" href="{link controller='ConversationList'}filter=draft{/link}"><span class="boxMenuLinkTitle">{lang}wcf.conversation.folder.draft{/lang}</span>{if $draftCount} <span class="badge">{#$draftCount}</span>{/if}</a>
+                                       </li>
+                                       <li{if $filter == 'outbox'} class="active"{/if}>
+                                               <a class="boxMenuLink" href="{link controller='ConversationList'}filter=outbox{/link}"><span class="boxMenuLinkTitle">{lang}wcf.conversation.folder.outbox{/lang}</span>{if $outboxCount} <span class="badge">{#$outboxCount}</span>{/if}</a>
+                                       </li>
+                                       <li{if $filter == 'hidden'} class="active"{/if}>
+                                               <a class="boxMenuLink" href="{link controller='ConversationList'}filter=hidden{/link}"><span class="boxMenuLinkTitle">{lang}wcf.conversation.folder.hidden{/lang}</span>{if $hiddenCount} <span class="badge">{#$hiddenCount}</span>{/if}</a>
+                                       </li>
+                               </ol>
+                       </nav>
+               </div>
+       </section>
        
-       <fieldset class="jsOnly">
-               <legend>{lang}wcf.conversation.label{/lang}</legend>
+       <section class="box">
+               <h2 class="boxTitle">{lang}wcf.conversation.filter.participants{/lang}</h2>
                
-               <div id="conversationLabelFilter" class="dropdown">
-                       <div class="dropdownToggle" data-toggle="conversationLabelFilter">
-                               {if $labelID}
-                                       {foreach from=$labelList item=label}
-                                               {if $label->labelID == $labelID}
-                                                       <span class="badge label{if $label->cssClassName} {@$label->cssClassName}{/if}">{$label->label}</span>
-                                               {/if}
-                                       {/foreach}
-                               {else}
-                                       <span class="badge">{lang}wcf.conversation.label.filter{/lang}</span>
-                               {/if}
-                       </div>
-                       
-                       <div class="dropdownMenu">
-                               <ul class="scrollableDropdownMenu">
-                                       {foreach from=$labelList item=label}
-                                               <li><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}{/if}&sortField={$sortField}&sortOrder={$sortOrder}&pageNo={@$pageNo}&labelID={@$label->labelID}{/link}"><span class="badge label{if $label->cssClassName} {@$label->cssClassName}{/if}" data-css-class-name="{if $label->cssClassName}{@$label->cssClassName}{/if}" data-label-id="{@$label->labelID}">{$label->label}</span></a></li>
-                                       {/foreach}
-                               </ul>
-                               <ul>
-                                       <li class="dropdownDivider"{if !$labelList|count} style="display: none;"{/if}></li>
-                                       <li><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}{/if}&sortField={$sortField}&sortOrder={$sortOrder}&pageNo={@$pageNo}{/link}"><span class="badge label">{lang}wcf.conversation.label.disableFilter{/lang}</span></a></li>
-                               </ul>
+               <div class="boxContent">
+                       <form action="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}sortField={$sortField}&sortOrder={$sortOrder}&pageNo={@$pageNo}{/link}" method="post">
+                               <dl>
+                                       <dt></dt>
+                                       <dd><label><textarea id="participants" name="participants" class="long">{implode from=$participants item=participant glue=','}{$participant}{/implode}</textarea></label></dd>
+                               </dl>
+                               
+                               <div class="formSubmit">
+                                       <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
+                                       {@SECURITY_TOKEN_INPUT_TAG}
+                               </div>
+                       </form>
+               </div>
+       </section>
+       
+       <section class="box jsOnly">
+               <h2 class="boxTitle">{lang}wcf.conversation.label{/lang}</h2>
+               
+               <div class="boxContent">
+                       <div id="conversationLabelFilter" class="dropdown">
+                               <div class="dropdownToggle" data-toggle="conversationLabelFilter">
+                                       {if $labelID}
+                                               {foreach from=$labelList item=label}
+                                                       {if $label->labelID == $labelID}
+                                                               <span class="badge label{if $label->cssClassName} {@$label->cssClassName}{/if}">{$label->label}</span>
+                                                       {/if}
+                                               {/foreach}
+                                       {else}
+                                               <span class="badge">{lang}wcf.conversation.label.filter{/lang}</span>
+                                       {/if}
+                               </div>
+                               
+                               <div class="dropdownMenu">
+                                       <ul class="scrollableDropdownMenu">
+                                               {foreach from=$labelList item=label}
+                                                       <li><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}sortField={$sortField}&sortOrder={$sortOrder}&pageNo={@$pageNo}&labelID={@$label->labelID}{/link}"><span class="badge label{if $label->cssClassName} {@$label->cssClassName}{/if}" data-css-class-name="{if $label->cssClassName}{@$label->cssClassName}{/if}" data-label-id="{@$label->labelID}">{$label->label}</span></a></li>
+                                               {/foreach}
+                                       </ul>
+                                       <ul>
+                                               <li class="dropdownDivider"{if !$labelList|count} style="display: none;"{/if}></li>
+                                               <li><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}sortField={$sortField}&sortOrder={$sortOrder}&pageNo={@$pageNo}{/link}"><span class="badge label">{lang}wcf.conversation.label.disableFilter{/lang}</span></a></li>
+                                       </ul>
+                               </div>
                        </div>
                </div>
                
-               <button id="manageLabel">{lang}wcf.conversation.label.management{/lang}</button>
-       </fieldset>
+               <div class="boxContent">
+                       <button id="manageLabel">{lang}wcf.conversation.label.management{/lang}</button>
+               </div>
+       </section>
        
        {event name='beforeQuotaBox'}
        
-       <fieldset class="conversationQuota">
-               <legend>{lang}wcf.conversation.quota{/lang}</legend>
+       <section class="box conversationQuota">
+               <h2 class="boxTitle">{lang}wcf.conversation.quota{/lang}</h2>
                
-               <div>
+               <div class="boxContent">
                        {assign var='conversationCount' value=$__wcf->getConversationHandler()->getConversationCount()}
                        {assign var='maxConversationCount' value=$__wcf->session->getPermission('user.conversation.maxConversations')}
                        <p class="conversationUsageBar{if $conversationCount/$maxConversationCount >= 1.0} red{elseif $conversationCount/$maxConversationCount > 0.9} yellow{/if}">
                        </p>
                        <p><small>{lang}wcf.conversation.quota.description{/lang}</small></p>
                </div>
-       </fieldset>
+       </section>
        
        {event name='boxes'}
 {/capture}
 
 {capture assign='headerNavigation'}
-       <li><a rel="alternate" href="{link controller='ConversationFeed' appendSession=false}at={@$__wcf->getUser()->userID}-{@$__wcf->getUser()->accessToken}{/link}" title="{lang}wcf.global.button.rss{/lang}" class="jsTooltip"><span class="icon icon16 icon-rss"></span> <span class="invisible">{lang}wcf.global.button.rss{/lang}</span></a></li>
-       <li class="jsOnly"><a href="#" title="{lang}wcf.conversation.markAllAsRead{/lang}" class="markAllAsReadButton jsTooltip"><span class="icon icon16 icon-ok"></span> <span class="invisible">{lang}wcf.conversation.markAllAsRead{/lang}</span></a></li>
+       <li><a rel="alternate" href="{link controller='ConversationFeed'}at={@$__wcf->getUser()->userID}-{@$__wcf->getUser()->accessToken}{/link}" title="{lang}wcf.global.button.rss{/lang}" class="jsTooltip"><span class="icon icon16 fa-rss"></span> <span class="invisible">{lang}wcf.global.button.rss{/lang}</span></a></li>
+       <li class="jsOnly"><a href="#" title="{lang}wcf.conversation.markAllAsRead{/lang}" class="markAllAsReadButton jsTooltip"><span class="icon icon16 fa-check"></span> <span class="invisible">{lang}wcf.conversation.markAllAsRead{/lang}</span></a></li>
 {/capture}
 
-{include file='header' sidebarOrientation='left'}
+{include file='header'}
 
-<header class="boxHeadline">
-       <h1>{if $filter}{lang}wcf.conversation.folder.{$filter}{/lang}{else}{lang}wcf.conversation.conversations{/lang}{/if}</h1>
-</header>
-
-{include file='userNotice'}
-
-<div class="contentNavigation">
-       {assign var='labelIDParameter' value=''}
-       {if $labelID}{assign var='labelIDParameter' value="&labelID=$labelID"}{/if}
-       {pages print=true assign=pagesLinks controller='ConversationList' link="filter=$filter&pageNo=%d&sortField=$sortField&sortOrder=$sortOrder$labelIDParameter"}
-       
-       <nav>
-               <ul>
-                       <li><a href="{link controller='ConversationAdd'}{/link}" title="{lang}wcf.conversation.add{/lang}" class="button"><span class="icon icon16 icon-asterisk"></span> <span>{lang}wcf.conversation.button.add{/lang}</span></a></li>
-                       {event name='contentNavigationButtonsTop'}
-               </ul>
-       </nav>
-</div>
+{hascontent}
+       <div class="paginationTop">
+               {content}
+                       {assign var='participantsParameter' value=''}
+                       {if $participants}{capture assign='participantsParameter'}&participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}{/capture}{/if}
+                       {assign var='labelIDParameter' value=''}
+                       {if $labelID}{assign var='labelIDParameter' value="&labelID=$labelID"}{/if}
+                       {pages print=true assign=pagesLinks controller='ConversationList' link="filter=$filter$participantsParameter&pageNo=%d&sortField=$sortField&sortOrder=$sortOrder$labelIDParameter"}
+               {/content}
+       </div>
+{/hascontent}
 
 {if !$items}
        <p class="info">{lang}wcf.conversation.noConversations{/lang}</p>
 {else}
-       <div class="marginTop tabularBox tabularBoxTitle messageGroupList conversationList jsClipboardContainer" data-type="com.woltlab.wcf.conversation.conversation">
-               <header>
-                       <h2>{lang}wcf.conversation.conversations{/lang} <span class="badge badgeInverse">{#$items}</span></h2>
-               </header>
-               
-               <table class="table">
-                       <thead>
-                               <tr>
-                                       <th class="columnMark jsOnly"><label><input type="checkbox" class="jsClipboardMarkAll" /></label></th>
-                                       <th colspan="2" class="columnTitle columnSubject{if $sortField == 'subject'} active {@$sortOrder}{/if}"><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}pageNo={@$pageNo}&sortField=subject&sortOrder={if $sortField == 'subject' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">{lang}wcf.global.subject{/lang}</a></th>
-                                       <th class="columnDigits columnReplies{if $sortField == 'replies'} active {@$sortOrder}{/if}"><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}pageNo={@$pageNo}&sortField=replies&sortOrder={if $sortField == 'replies' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">{lang}wcf.conversation.replies{/lang}</a></th>
-                                       <th class="columnDigits columnParticipants{if $sortField == 'participants'} active {@$sortOrder}{/if}"><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}pageNo={@$pageNo}&sortField=participants&sortOrder={if $sortField == 'participants' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">{lang}wcf.conversation.participants{/lang}</a></th>
-                                       <th class="columnText columnLastPost{if $sortField == 'lastPostTime'} active {@$sortOrder}{/if}"><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}pageNo={@$pageNo}&sortField=lastPostTime&sortOrder={if $sortField == 'lastPostTime' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">{lang}wcf.conversation.lastPostTime{/lang}</a></th>
+       <div class="section tabularBox messageGroupList conversationList jsClipboardContainer" data-type="com.woltlab.wcf.conversation.conversation">
+               <ol class="tabularList">
+                       <li class="tabularListRow tabularListRowHead">
+                               <ol class="tabularListColumns">
+                                       <li class="columnMark jsOnly"><label><input type="checkbox" class="jsClipboardMarkAll"></label></li>
+                                       <li class="columnSubject{if $sortField === 'subject'} active {@$sortOrder}{/if}"><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}pageNo={@$pageNo}&sortField=subject&sortOrder={if $sortField == 'subject' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">{lang}wcf.global.subject{/lang}</a></li>
+                                       <li class="columnStats{if $sortField == 'replies'} active {@$sortOrder}{/if}"><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}pageNo={@$pageNo}&sortField=replies&sortOrder={if $sortField == 'replies' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">{lang}wcf.conversation.replies{/lang}</a></li>
+                                       <li class="columnLastPost{if $sortField === 'lastPostTime'} active {@$sortOrder}{/if}"><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}pageNo={@$pageNo}&sortField=lastPostTime&sortOrder={if $sortField == 'lastPostTime' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{if $labelID}&labelID={@$labelID}{/if}{/link}">{lang}wcf.conversation.lastPostTime{/lang}</a></li>
                                        
                                        {event name='columnHeads'}
-                               </tr>
-                       </thead>
+                               </ol>
+                       </li>
                        
-                       <tbody>
-                               {foreach from=$objects item=conversation}
-                                       <tr class="conversation jsClipboardObject{if $conversation->isNew()} new{/if}" data-conversation-id="{@$conversation->conversationID}" data-label-ids="[ {implode from=$conversation->getAssignedLabels() item=label}{@$label->labelID}{/implode} ]" data-is-closed="{@$conversation->isClosed}" data-can-close-conversation="{if $conversation->userID == $__wcf->getUser()->userID}1{else}0{/if}" data-can-add-participants="{if $conversation->canAddParticipants()}1{else}0{/if}">
-                                               <td class="columnMark jsOnly">
-                                                       <label><input type="checkbox" class="jsClipboardItem" data-object-id="{@$conversation->conversationID}" /></label>
-                                               </td>
-                                               <td class="columnIcon columnAvatar">
+                       {foreach from=$objects item=conversation}
+                               <li class="tabularListRow">
+                                       <ol class="tabularListColumns messageGroup conversation jsClipboardObject{if $conversation->isNew()} new{/if}" data-conversation-id="{@$conversation->conversationID}" data-label-ids="[ {implode from=$conversation->getAssignedLabels() item=label}{@$label->labelID}{/implode} ]" data-is-closed="{@$conversation->isClosed}" data-can-close-conversation="{if $conversation->userID == $__wcf->getUser()->userID}1{else}0{/if}" data-can-add-participants="{if $conversation->canAddParticipants()}1{else}0{/if}">
+                                               <li class="columnMark jsOnly">
+                                                       <label><input type="checkbox" class="jsClipboardItem" data-object-id="{@$conversation->conversationID}"></label>
+                                               </li>
+                                               <li class="columnIcon columnAvatar">
                                                        {if $conversation->getUserProfile()->getAvatar()}
                                                                <div>
-                                                                       <p class="framed"{if $conversation->isNew()} title="{lang}wcf.conversation.markAsRead.doubleClick{/lang}"{/if}>{@$conversation->getUserProfile()->getAvatar()->getImageTag(32)}</p>
+                                                                       <p{if $conversation->isNew()} title="{lang}wcf.conversation.markAsRead.doubleClick{/lang}"{/if}>{@$conversation->getUserProfile()->getAvatar()->getImageTag(48)}</p>
                                                                        
                                                                        {if $conversation->ownPosts && $conversation->userID != $__wcf->user->userID}
                                                                                {if $__wcf->getUserProfileHandler()->getAvatar()}
-                                                                                       <small class="framed myAvatar" title="{lang}wcf.conversation.ownPosts{/lang}">{@$__wcf->getUserProfileHandler()->getAvatar()->getImageTag(16)}</small>
+                                                                                       <small class="myAvatar jsTooltip" title="{lang}wcf.conversation.ownPosts{/lang}">{@$__wcf->getUserProfileHandler()->getAvatar()->getImageTag(24)}</small>
                                                                                {/if}
                                                                        {/if}
                                                                </div>
                                                        {/if}
-                                               </td>
-                                               <td class="columnText columnSubject">
+                                               </li>
+                                               <li class="columnSubject">
                                                        {hascontent}
                                                                <ul class="labelList">
                                                                        {content}
                                                                                {foreach from=$conversation->getAssignedLabels() item=label}
-                                                                                       <li><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}{/if}&sortField={$sortField}&sortOrder={$sortOrder}&pageNo={@$pageNo}&labelID={@$label->labelID}{/link}" class="badge label{if $label->cssClassName} {@$label->cssClassName}{/if}">{$label->label}</a></li>
+                                                                                       <li><a href="{link controller='ConversationList'}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}sortField={$sortField}&sortOrder={$sortOrder}&pageNo={@$pageNo}&labelID={@$label->labelID}{/link}" class="badge label{if $label->cssClassName} {@$label->cssClassName}{/if}">{$label->label}</a></li>
                                                                                {/foreach}
                                                                        {/content}
                                                                </ul>
                                                        {/hascontent}
                                                                
                                                        <h3>
-                                                               <a href="{if $conversation->isNew()}{link controller='Conversation' object=$conversation}action=firstNew{/link}{else}{link controller='Conversation' object=$conversation}{/link}{/if}" class="conversationLink messageGroupLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject|tableWordwrap}</a>
+                                                               <a href="{if $conversation->isNew()}{link controller='Conversation' object=$conversation}action=firstNew{/link}{else}{link controller='Conversation' object=$conversation}{/link}{/if}" class="conversationLink messageGroupLink" data-conversation-id="{@$conversation->conversationID}">{$conversation->subject}</a>
+                                                               {if $conversation->replies}
+                                                                       <span class="badge messageGroupCounterMobile">{@$conversation->replies|shortUnit}</span>
+                                                               {/if}
                                                        </h3>
                                                        
                                                        <aside class="statusDisplay">
                                                                {smallpages pages=$conversation->getPages() controller='Conversation' object=$conversation link='pageNo=%d'}
                                                                <ul class="statusIcons">
-                                                                       {if $conversation->isClosed}<li><span class="icon icon16 icon-lock jsIconLock jsTooltip" title="{lang}wcf.global.state.closed{/lang}"></span></li>{/if}
-                                                                       {if $conversation->attachments}<li><span class="icon icon16 icon-paper-clip jsIconAttachment jsTooltip" title="{lang}wcf.conversation.attachments{/lang}"></span></li>{/if}
+                                                                       {if $conversation->isClosed}<li><span class="icon icon16 fa-lock jsIconLock jsTooltip" title="{lang}wcf.global.state.closed{/lang}"></span></li>{/if}
+                                                                       {if $conversation->attachments}<li><span class="icon icon16 fa-paperclip jsIconAttachment jsTooltip" title="{lang}wcf.conversation.attachments{/lang}"></span></li>{/if}
                                                                </ul>
                                                        </aside>
                                                        
-                                                       <ul class="messageGroupInfo mobileOptimization">
+                                                       <ul class="inlineList dotSeparated small messageGroupInfo">
                                                                <li class="messageGroupAuthor">{if $conversation->userID}<a href="{link controller='User' object=$conversation->getUserProfile()->getDecoratedObject()}{/link}" class="userLink" data-user-id="{@$conversation->userID}">{$conversation->username}</a>{else}{$conversation->username}{/if}</li>
                                                                <li class="messageGroupTime">{@$conversation->time|time}</li>
-                                                               <li class="messageGroupLastPoster">{if $conversation->lastPosterID}<a href="{link controller='User' object=$conversation->getLastPosterProfile()->getDecoratedObject()}{/link}" class="userLink" data-user-id="{@$conversation->getLastPosterProfile()->userID}">{$conversation->lastPoster}</a>{else}{$conversation->lastPoster}{/if}</li>
-                                                               <li class="messageGroupLastPostTime">{@$conversation->lastPostTime|time}</li>
                                                                <li class="messageGroupEditLink jsOnly"><a class="jsConversationInlineEditor">{lang}wcf.global.button.edit{/lang}</a></li>
                                                                {event name='messageGroupInfo'}
                                                        </ul>
                                                        
+                                                       <ul class="messageGroupInfoMobile">
+                                                               <li class="messageGroupAuthorMobile">{$conversation->username}</li>
+                                                               <li class="messageGroupLastPostTimeMobile">{@$conversation->lastPostTime|time}</li>
+                                                       </ul>
+                                                       
                                                        {if $conversation->getParticipantSummary()|count}
                                                                <small class="conversationParticipantSummary">
                                                                        {assign var='participantSummaryCount' value=$conversation->getParticipantSummary()|count}
                                                        {/if}
                                                        
                                                        {event name='conversationData'}
-                                               </td>
-                                               <td class="columnDigits columnReplies">{#$conversation->replies}</td>
-                                               <td class="columnDigits columnParticipants">{#$conversation->participants}</td>
-                                               <td class="columnText columnLastPost">
+                                               </li>
+                                               <li class="columnStats">
+                                                       <dl class="plain statsDataList">
+                                                               <dt>{lang}wcf.conversation.replies{/lang}</dt>
+                                                               <dd>{@$conversation->replies|shortUnit}</dd>
+                                                       </dl>
+                                                       <dl class="plain statsDataList">
+                                                               <dt>{lang}wcf.conversation.participants{/lang}</dt>
+                                                               <dd>{@$conversation->participants|shortUnit}</dd>
+                                                       </dl>
+                                                       
+                                                       <div class="messageGroupListStatsSimple">{@$conversation->replies|shortUnit}</div>
+                                               </li>
+                                               <li class="columnLastPost">
                                                        {if $conversation->replies != 0}
-                                                               <div class="box24">
-                                                                       <a href="{link controller='Conversation' object=$conversation}action=lastPost{/link}" class="framed jsTooltip" title="{lang}wcf.conversation.gotoLastPost{/lang}">{@$conversation->getLastPosterProfile()->getAvatar()->getImageTag(24)}</a>
+                                                               <div class="box32">
+                                                                       <a href="{link controller='Conversation' object=$conversation}action=lastPost{/link}" class="jsTooltip" title="{lang}wcf.conversation.gotoLastPost{/lang}">{@$conversation->getLastPosterProfile()->getAvatar()->getImageTag(32)}</a>
                                                                        
                                                                        <div>
                                                                                <p>
                                                                        </div>
                                                                </div>
                                                        {/if}
-                                               </td>
+                                               </li>
                                                
                                                {event name='columns'}
-                                       </tr>
-                               {/foreach}
-                       </tbody>
-               </table>
+                                       </ol>
+                               </li>
+                       {/foreach}
+               </ol>
        </div>
 {/if}
 
-<div class="contentNavigation">
-       {@$pagesLinks}
+<footer class="contentFooter">
+       {hascontent}
+               <div class="paginationBottom">
+                       {content}{@$pagesLinks}{/content}
+               </div>
+       {/hascontent}
        
-       <nav>
+       <nav class="contentFooterNavigation">
                <ul>
-                       <li><a href="{link controller='ConversationAdd'}{/link}" title="{lang}wcf.conversation.add{/lang}" class="button"><span class="icon icon16 icon-asterisk"></span> <span>{lang}wcf.conversation.button.add{/lang}</span></a></li>
-                       {event name='contentNavigationButtonsTop'}
+                       <li><a href="{link controller='ConversationAdd'}{/link}" title="{lang}wcf.conversation.add{/lang}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.conversation.button.add{/lang}</span></a></li>
+                       {event name='contentFooterNavigation'}
                </ul>
        </nav>
-       
-       <nav class="jsClipboardEditor" data-types="[ 'com.woltlab.wcf.conversation.conversation' ]"></nav>
-</div>
+</footer>
 
-{include file='footer'}
+<script data-relocate="true" src="{@$__wcf->getPath()}js/WCF.Conversation{if !ENABLE_DEBUG_MODE}.min{/if}.js?v={@LAST_UPDATE_TIME}"></script>
+<script data-relocate="true">
+       require(['Language', 'WoltLabSuite/Core/Ui/ItemList/User'], function(Language, UiItemListUser) {
+               Language.addObject({
+                       'wcf.conversation.edit.addParticipants': '{lang}wcf.conversation.edit.addParticipants{/lang}',
+                       'wcf.conversation.edit.assignLabel': '{lang}wcf.conversation.edit.assignLabel{/lang}',
+                       'wcf.conversation.edit.close': '{lang}wcf.conversation.edit.close{/lang}',
+                       'wcf.conversation.edit.leave': '{lang}wcf.conversation.edit.leave{/lang}',
+                       'wcf.conversation.edit.open': '{lang}wcf.conversation.edit.open{/lang}',
+                       'wcf.conversation.label.management': '{lang}wcf.conversation.label.management{/lang}',
+                       'wcf.conversation.label.management.addLabel.success': '{lang}wcf.conversation.label.management.addLabel.success{/lang}',
+                       'wcf.conversation.label.management.deleteLabel.confirmMessage': '{lang}wcf.conversation.label.management.deleteLabel.confirmMessage{/lang}',
+                       'wcf.conversation.label.management.editLabel': '{lang}wcf.conversation.label.management.editLabel{/lang}',
+                       'wcf.conversation.label.placeholder': '{lang}wcf.conversation.label.placeholder{/lang}',
+                       'wcf.conversation.leave.title': '{lang}wcf.conversation.leave.title{/lang}',
+                       'wcf.global.state.closed': '{lang}wcf.global.state.closed{/lang}',
+                       'wcf.conversation.label.assignLabels': '{lang}wcf.conversation.label.assignLabels{/lang}'
+               });
+               
+               WCF.Clipboard.init('wcf\\page\\ConversationListPage', {@$hasMarkedItems}, { });
+               
+               var $editorHandler = new WCF.Conversation.EditorHandler();
+               var $inlineEditor = new WCF.Conversation.InlineEditor('.conversation');
+               $inlineEditor.setEditorHandler($editorHandler, 'list');
+               
+               new WCF.Conversation.Clipboard($editorHandler);
+               new WCF.Conversation.Label.Manager('{link controller='ConversationList' encode=false}{if $filter}filter={@$filter}&{/if}{if !$participants|empty}participants={implode from=$participants item=participant}{$participant|rawurlencode}{/implode}&{/if}sortField={$sortField}&sortOrder={$sortOrder}&pageNo={@$pageNo}{/link}');
+               new WCF.Conversation.Preview();
+               new WCF.Conversation.MarkAsRead();
+               new WCF.Conversation.MarkAllAsRead();
+               
+               // mobile safari hover workaround
+               if ($(window).width() <= 800) {
+                       $('.sidebar').addClass('mobileSidebar').hover(function() { });
+               }
+               
+               UiItemListUser.init('participants', {
+                       excludedSearchValues: ['{$__wcf->user->username|encodeJS}']
+               });
+       });
+</script>
 
-</body>
-</html>
+{include file='footer'}
index 5d9b1158f8aa239117a2270a241e00919750ad2a..0badff9226944a43589c68640c7b5b64da5f3123 100644 (file)
@@ -1,17 +1,37 @@
 {foreach from=$conversations item=conversation}
        <li class="conversationItem{if $conversation->lastVisitTime < $conversation->lastPostTime} conversationItemUnread interactiveDropdownItemOutstanding{/if}" data-link="{link controller='Conversation' object=$conversation}action=firstNew{/link}" data-object-id="{@$conversation->conversationID}" data-is-read="{if $conversation->lastVisitTime < $conversation->lastPostTime}false{else}true{/if}">
-               <div class="box32">
-                       <div class="framed">
-                               {if $conversation->lastPosterID}
-                                       {@$conversation->getLastPosterProfile()->getAvatar()->getImageTag(32)}
+               <div class="box48">
+                       <div>
+                               {if $conversation->userID == $__wcf->user->userID}
+                                       {if $conversation->participants > 1}
+                                               <span class="icon icon48 fa-users"></span>
+                                       {else}
+                                               {@$conversation->getOtherParticipantProfile()->getAvatar()->getImageTag(48)}
+                                       {/if}   
                                {else}
-                                       {@$conversation->getUserProfile()->getAvatar()->getImageTag(32)}
+                                       {@$conversation->getUserProfile()->getAvatar()->getImageTag(48)}
                                {/if}
                        </div>
                        <div>
                                <h3><a href="{link controller='Conversation' object=$conversation}action=firstNew{/link}">{$conversation->subject}</a></h3>
-                               <small>{if $conversation->lastPosterID}<a href="{link controller='User' id=$conversation->lastPosterID title=$conversation->lastPoster}{/link}">{$conversation->lastPoster}</a>{else}{$conversation->username}{/if} - {@$conversation->lastPostTime|time}</small>
+                               <small class="conversationInfo">
+                                       <span class="conversationParticipant">
+                                               {if $conversation->userID == $__wcf->user->userID}
+                                                       {if $conversation->participants > 1}
+                                                               {assign var='participantSummaryCount' value=$conversation->getParticipantSummary()|count}
+                                                               {implode from=$conversation->getParticipantSummary() item=participant}<a href="{link controller='User' object=$participant}{/link}" class="userLink{if $participant->hideConversation == 2} conversationLeft{/if}" data-user-id="{@$participant->userID}">{$participant->username}</a>{/implode}
+                                                               {if $participantSummaryCount < $conversation->participants}{lang}wcf.conversation.participants.other{/lang}{/if}
+                                                       {else}
+                                                               {if $conversation->getOtherParticipantProfile()->userID}<a href="{link controller='User' id=$conversation->getOtherParticipantProfile()->userID title=$conversation->getOtherParticipantProfile()->username}{/link}">{$conversation->getOtherParticipantProfile()->username}</a>{else}{$conversation->getOtherParticipantProfile()->username}{/if}
+                                                       {/if}
+                                               {else}
+                                                       {if $conversation->userID}<a href="{link controller='User' id=$conversation->userID title=$conversation->username}{/link}">{$conversation->username}</a>{else}{$conversation->username}{/if}
+                                               {/if}
+                                       </span>
+                                       
+                                       <span class="conversationLastPostTime">{@$conversation->lastPostTime|time}</span>
+                               </small>
                        </div>
                </div>
        </li>
-{/foreach}
\ No newline at end of file
+{/foreach}
diff --git a/templates/conversationMessageAdd.tpl b/templates/conversationMessageAdd.tpl
deleted file mode 100644 (file)
index 7f5d5fc..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-{include file='documentHeader'}
-
-<head>
-       <title>{lang}wcf.conversation.message.add{/lang} - {$conversation->subject} - {PAGE_TITLE|language}</title>
-       
-       {include file='headInclude'}
-       
-       <script data-relocate="true" src="{@$__wcf->getPath()}js/WCF.Conversation{if !ENABLE_DEBUG_MODE}.min{/if}.js?v={@LAST_UPDATE_TIME}"></script>
-       <script data-relocate="true">
-               //<![CDATA[
-               $(function() {
-                       WCF.Language.addObject({
-                               'wcf.message.bbcode.code.copy': '{lang}wcf.message.bbcode.code.copy{/lang}'
-                       });
-                       
-                       {include file='__messageQuoteManager' wysiwygSelector='text' supportPaste=true}
-                       new WCF.Conversation.Message.QuoteHandler($quoteManager);
-                       
-                       WCF.Message.Submit.registerButton('text', $('#messageContainer > .formSubmit > input[type=submit]'));
-                       new WCF.Message.FormGuard();
-                       new WCF.Message.BBCode.CodeViewer();
-                       
-                       WCF.System.Dependency.Manager.register('CKEditor', function() { new WCF.Message.UserMention('text'); });
-               });
-               //]]>
-       </script>
-</head>
-
-<body id="tpl{$templateName|ucfirst}" data-template="{$templateName}" data-application="{$templateNameApplication}">
-{include file='header'}
-
-<header class="boxHeadline">
-       <h1>{lang}wcf.conversation.message.add{/lang}</h1>
-</header>
-
-{include file='userNotice'}
-
-{if !$conversation->isDraft && !$conversation->hasOtherParticipants()}
-       <p class="warning">{lang}wcf.conversation.noParticipantsWarning{/lang}</p>
-{/if}
-
-{include file='formError'}
-
-<form id="messageContainer" class="jsFormGuard" method="post" action="{link controller='ConversationMessageAdd' id=$conversationID}{/link}">
-       <div class="container containerPadding marginTop">
-               <fieldset>
-                       <legend>{lang}wcf.conversation.message{/lang}</legend>
-                       
-                       <dl class="wide{if $errorField == 'text'} formError{/if}">
-                               <dt><label for="text">{lang}wcf.conversation.message{/lang}</label></dt>
-                               <dd>
-                                       <textarea id="text" name="text" rows="20" cols="40" data-autosave="com.woltlab.wcf.conversation.messageAdd-{@$conversation->conversationID}">{$text}</textarea>
-                                       {if $errorField == 'text'}
-                                               <small class="innerError">
-                                                       {if $errorType == 'empty'}
-                                                               {lang}wcf.global.form.error.empty{/lang}
-                                                       {elseif $errorType == 'tooLong'}
-                                                               {lang}wcf.message.error.tooLong{/lang}
-                                                       {elseif $errorType == 'censoredWordsFound'}
-                                                               {lang}wcf.message.error.censoredWordsFound{/lang}
-                                                       {elseif $errorType == 'disallowedBBCodes'}
-                                                               {lang}wcf.message.error.disallowedBBCodes{/lang}
-                                                       {else}
-                                                               {lang}wcf.conversation.message.error.{@$errorType}{/lang}
-                                                       {/if}
-                                               </small>
-                                       {/if}
-                               </dd>
-                       </dl>
-                       
-                       {event name='messageFields'}
-               </fieldset>
-               
-               {include file='messageFormTabs' wysiwygContainerID='text'}
-               
-               {event name='fieldsets'}
-       </div>
-       
-       <div class="formSubmit">
-               <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
-               {include file='messageFormPreviewButton'}
-               {@SECURITY_TOKEN_INPUT_TAG}
-       </div>
-</form>
-
-<header class="boxHeadline boxSubHeadline">
-       <h2>{lang}wcf.conversation.message.add.previousPosts{/lang}{if $items != 1} <span class="badge">{#$items}</span>{/if}</h2>
-</header>
-
-<div>
-       <ul class="messageList">
-               {foreach from=$messages item=message}
-                       {assign var='objectID' value=$message->messageID}
-                       
-                       <li class="marginTop">
-                               <article class="message messageReduced{if $message->getUserProfile()->userOnlineGroupID} userOnlineGroupMarking{@$message->getUserProfile()->userOnlineGroupID}{/if}" data-object-id="{@$message->messageID}">
-                                       <div>
-                                               <section class="messageContent">
-                                                       <div>
-                                                               <header class="messageHeader">
-                                                                       <div class="box32">
-                                                                               <a href="{link controller='User' object=$message->getUserProfile()}{/link}" class="framed">{@$message->getUserProfile()->getAvatar()->getImageTag(32)}</a>
-                                                                               
-                                                                               <div class="messageHeadline">
-                                                                                       <p>
-                                                                                               <span class="username"><a href="{link controller='User' object=$message->getUserProfile()}{/link}" class="userLink" data-user-id="{@$message->userID}">{$message->username}</a></span>
-                                                                                               <a href="{link controller='Conversation' object=$conversation}messageID={@$message->messageID}{/link}#message{@$message->messageID}" class="permalink">{@$message->time|time}</a>
-                                                                                       </p>
-                                                                               </div>
-                                                                       </div>
-                                                               </header>
-                                                               
-                                                               <div class="messageBody">
-                                                                       <div>
-                                                                               <div class="messageText">
-                                                                                       {@$message->getFormattedMessage()}
-                                                                               </div>
-                                                                       </div>
-                                                                       
-                                                                       {include file='attachments'}
-                                                                       
-                                                                       <footer class="messageOptions">
-                                                                               <nav class="jsMobileNavigation buttonGroupNavigation">
-                                                                                       <ul class="smallButtons buttonGroup"><li class="toTopLink"><a href="{$__wcf->getAnchor('top')}" title="{lang}wcf.global.scrollUp{/lang}" class="button jsTooltip"><span class="icon icon16 icon-arrow-up"></span> <span class="invisible">{lang}wcf.global.scrollUp{/lang}</span></a></li></ul>
-                                                                               </nav>
-                                                                       </footer>
-                                                               </div>
-                                                       </div>
-                                               </section>
-                                       </div>
-                               </article>
-                       </li>
-               {/foreach}
-       </ul>
-</div>
-
-{include file='footer'}
-{include file='wysiwyg'}
-
-</body>
-</html>
\ No newline at end of file
diff --git a/templates/conversationMessageEdit.tpl b/templates/conversationMessageEdit.tpl
deleted file mode 100644 (file)
index e5e94dd..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-{include file='documentHeader'}
-
-<head>
-       <title>{lang}wcf.conversation.message.edit{/lang} - {$conversation->subject} - {PAGE_TITLE|language}</title>
-       
-       {include file='headInclude'}
-       
-       <script data-relocate="true">
-               //<![CDATA[
-               $(function() {
-                       WCF.Language.addObject({
-                               'wcf.message.bbcode.code.copy': '{lang}wcf.message.bbcode.code.copy{/lang}'
-                       });
-                       
-                       {if $isFirstMessage && $conversation->isDraft}
-                               new WCF.Search.User('#participants', null, false, [ ], true);
-                               new WCF.Search.User('#invisibleParticipants', null, false, [ ], true);
-                       {/if}
-                       
-                       WCF.Message.Submit.registerButton('text', $('#messageContainer > .formSubmit > input[type=submit]'));
-                       new WCF.Message.FormGuard();
-                       new WCF.Message.BBCode.CodeViewer();
-                       
-                       WCF.System.Dependency.Manager.register('CKEditor', function() { new WCF.Message.UserMention('text'); });
-               });
-               //]]>
-       </script>
-</head>
-
-<body id="tpl{$templateName|ucfirst}" data-template="{$templateName}" data-application="{$templateNameApplication}">
-{include file='header'}
-
-<header class="boxHeadline">
-       <h1>{lang}wcf.conversation.message.edit{/lang}</h1>
-</header>
-
-{include file='userNotice'}
-
-{include file='formError'}
-
-<form id="messageContainer" class="jsFormGuard" method="post" action="{link controller='ConversationMessageEdit' id=$messageID}{/link}">
-       <div class="container containerPadding marginTop">
-               {if $isFirstMessage}
-                       <fieldset>
-                               <legend>{lang}wcf.conversation.information{/lang}</legend>
-                               
-                               <dl{if $errorField == 'subject'} class="formError"{/if}>
-                                       <dt><label for="subject">{lang}wcf.global.subject{/lang}</label></dt>
-                                       <dd>
-                                               <input type="text" id="subject" name="subject" value="{$subject}" required="required" maxlength="255" class="long" />
-                                               {if $errorField == 'subject'}
-                                                       <small class="innerError">
-                                                               {if $errorType == 'empty'}
-                                                                       {lang}wcf.global.form.error.empty{/lang}
-                                                               {else}
-                                                                       {lang}wcf.conversation.subject.error.{@$errorType}{/lang}
-                                                               {/if}
-                                                       </small>
-                                               {/if}
-                                       </dd>
-                               </dl>
-                               
-                               {event name='informationFields'}
-                       </fieldset>
-                       
-                       <fieldset>
-                               <legend>{lang}wcf.conversation.participants{/lang}</legend>
-                               
-                               {if $conversation->isDraft}
-                                       <dl{if $errorField == 'participants'} class="formError"{/if}>
-                                               <dt><label for="participants">{lang}wcf.conversation.participants{/lang}</label></dt>
-                                               <dd>
-                                                       <textarea id="participants" name="participants" class="long" cols="40" rows="2">{$participants}</textarea>
-                                                       {if $errorField == 'participants'}
-                                                               <small class="innerError">
-                                                                       {if $errorType == 'empty'}
-                                                                               {lang}wcf.global.form.error.empty{/lang}
-                                                                       {elseif $errorType|is_array}
-                                                                               {foreach from=$errorType item='errorData'}
-                                                                                       {lang}wcf.conversation.participants.error.{@$errorData.type}{/lang}
-                                                                               {/foreach}
-                                                                       {else}
-                                                                               {lang}wcf.conversation.participants.error.{@$errorType}{/lang}
-                                                                       {/if}
-                                                               </small>
-                                                       {/if}
-                                                       <small>{lang}wcf.conversation.participants.description{/lang}</small>
-                                               </dd>
-                                       </dl>
-                                       
-                                       <dl{if $errorField == 'invisibleParticipants'} class="formError"{/if}>
-                                               <dt><label for="invisibleParticipants">{lang}wcf.conversation.invisibleParticipants{/lang}</label></dt>
-                                               <dd>
-                                                       <textarea id="invisibleParticipants" name="invisibleParticipants" class="long" cols="40" rows="2">{$invisibleParticipants}</textarea>
-                                                       {if $errorField == 'invisibleParticipants'}
-                                                               <small class="innerError">
-                                                                       {if $errorType == 'empty'}
-                                                                               {lang}wcf.global.form.error.empty{/lang}
-                                                                       {elseif $errorType|is_array}
-                                                                               {foreach from=$errorType item='errorData'}
-                                                                                       {lang}wcf.conversation.participants.error.{@$errorData.type}{/lang}
-                                                                               {/foreach}
-                                                                       {else}
-                                                                               {lang}wcf.conversation.participants.error.{@$errorType}{/lang}
-                                                                       {/if}
-                                                               </small>
-                                                       {/if}
-                                                       <small>{lang}wcf.conversation.invisibleParticipants.description{/lang}</small>
-                                               </dd>
-                                       </dl>
-                               {/if}
-                               
-                               <dl>
-                                       <dt></dt>
-                                       <dd>
-                                               <label><input type="checkbox" name="participantCanInvite" id="participantCanInvite" value="1"{if $participantCanInvite} checked="checked"{/if} /> {lang}wcf.conversation.participantCanInvite{/lang}</label>
-                                       </dd>
-                               </dl>
-                               
-                               {event name='participantFields'}
-                       </fieldset>
-               {/if}
-               
-               <fieldset>
-                       <legend>{lang}wcf.conversation.message{/lang}</legend>
-                       
-                       <dl class="wide{if $errorField == 'text'} formError{/if}">
-                               <dt><label for="text">{lang}wcf.conversation.message{/lang}</label></dt>
-                               <dd>
-                                       <textarea id="text" name="text" rows="20" cols="40" data-autosave="com.woltlab.wcf.conversation.messageEdit-{@$message->messageID}">{$text}</textarea>
-                                       {if $errorField == 'text'}
-                                               <small class="innerError">
-                                                       {if $errorType == 'empty'}
-                                                               {lang}wcf.global.form.error.empty{/lang}
-                                                       {elseif $errorType == 'tooLong'}
-                                                               {lang}wcf.message.error.tooLong{/lang}
-                                                       {elseif $errorType == 'censoredWordsFound'}
-                                                               {lang}wcf.message.error.censoredWordsFound{/lang}
-                                                       {elseif $errorType == 'disallowedBBCodes'}
-                                                               {lang}wcf.message.error.disallowedBBCodes{/lang}
-                                                       {else}
-                                                               {lang}wcf.conversation.message.error.{@$errorType}{/lang}
-                                                       {/if}
-                                               </small>
-                                       {/if}
-                               </dd>
-                       </dl>
-                       
-                       {event name='messageFields'}
-               </fieldset>
-               
-               {include file='messageFormTabs' wysiwygContainerID='text'}
-               
-               {event name='fieldsets'}
-       </div>
-       
-       <div class="formSubmit">
-               <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
-               {if $isFirstMessage && $conversation->isDraft}<button name="draft" accesskey="d" value="1">{lang}wcf.conversation.button.saveAsDraft{/lang}</button>{/if}
-               {include file='messageFormPreviewButton'}
-               {@SECURITY_TOKEN_INPUT_TAG}
-       </div>
-</form>
-
-{if $messages|count}
-       <header class="boxHeadline boxSubHeadline">
-               <h2>{lang}wcf.conversation.message.add.previousPosts{/lang}</h2>
-       </header>
-       
-       <div>
-               <ul class="messageList">
-                       {foreach from=$messages item=message}
-                               {assign var='objectID' value=$message->messageID}
-                               
-                               <li class="marginTop">
-                                       <article class="message messageReduced{if $message->getUserProfile()->userOnlineGroupID} userOnlineGroupMarking{@$message->getUserProfile()->userOnlineGroupID}{/if}">
-                                               <div>
-                                                       <section class="messageContent">
-                                                               <div>
-                                                                       <header class="messageHeader">
-                                                                               <div class="box32">
-                                                                                       <a href="{link controller='User' object=$message->getUserProfile()}{/link}" class="framed">{@$message->getUserProfile()->getAvatar()->getImageTag(32)}</a>
-                                                                                       
-                                                                                       <div class="messageHeadline">
-                                                                                               <p>
-                                                                                                       <span class="username"><a href="{link controller='User' object=$message->getUserProfile()}{/link}" class="userLink" data-user-id="{@$message->userID}">{$message->username}</a></span>
-                                                                                                       <a href="{link controller='Conversation' object=$conversation}messageID={@$message->messageID}{/link}#message{@$message->messageID}" class="permalink">{@$message->time|time}</a>
-                                                                                               </p>
-                                                                                       </div>
-                                                                               </div>
-                                                                       </header>
-                                                                       
-                                                                       <div class="messageBody">
-                                                                               <div>
-                                                                                       <div class="messageText">
-                                                                                               {@$message->getFormattedMessage()}
-                                                                                       </div>
-                                                                               </div>
-                                                                               
-                                                                               {include file='attachments'}
-                                                                               
-                                                                               <footer class="messageOptions">
-                                                                                       <nav class="jsMobileNavigation buttonGroupNavigation">
-                                                                                               <ul class="smallButtons buttonGroup"><li class="toTopLink"><a href="{$__wcf->getAnchor('top')}" title="{lang}wcf.global.scrollUp{/lang}" class="button jsTooltip"><span class="icon icon16 icon-arrow-up"></span> <span class="invisible">{lang}wcf.global.scrollUp{/lang}</span></a></li></ul>
-                                                                                       </nav>
-                                                                               </footer>
-                                                                       </div>
-                                                               </div>
-                                                       </section>
-                                               </div>
-                                       </article>
-                               </li>
-                       {/foreach}
-               </ul>
-       </div>
-{/if}
-
-{include file='footer'}
-{include file='wysiwyg'}
-
-</body>
-</html>
index de9e28a086b434bf66fd16e1fba1455216774643..8fb04564065a1f203b4cf3624893ca956a969742 100644 (file)
@@ -1,20 +1,24 @@
+{capture assign='wysiwygSelector'}messageEditor{@$message->messageID}{/capture}
 <div class="messageInlineEditor">
-       <textarea id="messageEditor{@$message->messageID}" rows="20" cols="40" data-autosave="com.woltlab.wcf.conversation.messageEdit-{@$message->messageID}">{$message->message}</textarea>
+       <textarea id="{$wysiwygSelector}" class="wysiwygTextarea"
+                 data-autosave="com.woltlab.wcf.conversation.messageEdit-{@$message->messageID}"
+                 data-support-mention="true"
+       >{$message->message}</textarea>
        {capture assign=wysiwygContainerID}messageEditor{@$message->messageID}{/capture}
        {include file='messageFormTabsInline' inConversationInlineEdit=true wysiwygContainerID=$wysiwygContainerID}
        
        <div class="formSubmit">
                <button class="buttonPrimary" data-type="save">{lang}wcf.global.button.submit{/lang}</button>
-               <button data-type="extended">{lang}wcf.message.button.extendedEdit{/lang}</button>
+               
+               {include file='messageFormPreviewButton' previewMessageFieldID=$wysiwygSelector previewButtonID=$wysiwygSelector|concat:'_PreviewButton' previewMessageObjectType='com.woltlab.wcf.conversation.message' previewMessageObjectID=$message->messageID}
+               
                <button data-type="cancel">{lang}wcf.global.button.cancel{/lang}</button>
        </div>
        
        {include file='wysiwyg' wysiwygEnableUpload=true}
        <script data-relocate="true">
-               //<![CDATA[
                $(function() {
                        WCF.System.Dependency.Manager.register('Redactor_messageEditor{@$message->messageID}', function() { new WCF.Message.UserMention('messageEditor{@$message->messageID}'); });
                });
-               //]]>
        </script>
 </div>
index 178f1a40ae0ce97c85c65f5c9c73284976545bc6..3b4a799bf79d426ed842a0c6ef939b95fa982f12 100644 (file)
@@ -6,70 +6,75 @@
        {assign var='objectID' value=$message->messageID}
        {assign var='userProfile' value=$message->getUserProfile()}
        
-       <li id="message{@$message->messageID}" class="marginTop{if MESSAGE_SIDEBAR_ENABLE_MESSAGE_GROUP_STARTER_ICON && $conversation->userID == $message->userID} messageGroupStarter{/if}">
-               <article class="message messageSidebarOrientation{@$__wcf->getStyleHandler()->getStyle()->getVariable('messageSidebarOrientation')|ucfirst} dividers jsMessage{if $userProfile->userOnlineGroupID} userOnlineGroupMarking{@$userProfile->userOnlineGroupID}{/if}" data-can-edit="{if $message->canEdit()}1{else}0{/if}" data-object-id="{@$message->messageID}">
-                       <div>
-                               {include file='messageSidebar'}
-                               
-                               <section class="messageContent">
-                                       <div>
-                                               <header class="messageHeader">
-                                                       <ul class="messageQuickOptions">
-                                                               <li><a href="{link controller='Conversation' object=$conversation}messageID={@$message->messageID}{/link}#message{@$message->messageID}" class="badge jsTooltip" title="{lang}wcf.conversation.message.permalink{/lang}">{#$startIndex}</a></li>
-                                                       </ul>
-                                                       
-                                                       <div class="messageHeadline">
-                                                               <p><a href="{link controller='Conversation' object=$conversation}messageID={@$message->messageID}{/link}#message{@$message->messageID}" class="permalink">{@$message->time|time}</a></p>
-                                                       </div>
+       <li id="message{@$message->messageID}" class="anchorFixedHeader{if $conversation->userID == $message->userID} messageGroupStarter{/if}">
+               <article class="message messageSidebarOrientation{@$__wcf->getStyleHandler()->getStyle()->getVariable('messageSidebarOrientation')|ucfirst} jsMessage{if $userProfile->userOnlineGroupID} userOnlineGroupMarking{@$userProfile->userOnlineGroupID}{/if}" data-can-edit="{if $message->canEdit()}1{else}0{/if}" data-object-id="{@$message->messageID}">
+                       {include file='messageSidebar'}
+                       
+                       <div class="messageContent">
+                               <header class="messageHeader">
+                                       <div class="messageHeaderBox">
+                                               <ul class="messageHeaderMetaData">
+                                                       <li><a href="{link controller='Conversation' object=$conversation}messageID={@$message->messageID}{/link}#message{@$message->messageID}" class="permalink messagePublicationTime">{@$message->time|time}</a></li>
                                                        
+                                                       {event name='messageHeaderMetaData'}
+                                               </ul>
+                                               
+                                               <ul class="messageStatus">
                                                        {if $conversation->isNewMessage($message->getDecoratedObject())}
-                                                               <p class="newMessageBadge">{lang}wcf.message.new{/lang}</p>
+                                                               <li><span class="badge label newMessageBadge">{lang}wcf.message.new{/lang}</span></li>
                                                        {/if}
                                                        
-                                                       {event name='messageHeader'}
-                                               </header>
+                                                       {event name='messageStatus'}
+                                               </ul>
+                                       </div>
+                                       
+                                       <ul class="messageQuickOptions">
+                                               <li><a href="{link controller='Conversation' object=$conversation}messageID={@$message->messageID}{/link}#message{@$message->messageID}" class="jsTooltip" title="{lang}wcf.conversation.message.permalink{/lang}">#{#$startIndex}</a></li>
                                                
-                                               <div class="messageBody">
-                                                       <div>
-                                                               <div class="messageText">
-                                                                       {@$message->getFormattedMessage()}
-                                                                       
-                                                                       {event name='messageText'}
-                                                               </div>
-                                                       </div>
-                                                       
-                                                       {include file='attachments'}
-                                                       
-                                                       {if $message->showSignature && $message->getUserProfile()->showSignature()}
-                                                               <div class="messageSignature">
-                                                                       <div>{@$message->getUserProfile()->getSignature()}</div>
-                                                               </div>
-                                                       {/if}
-                                                       
-                                                       {event name='messageBody'}
-                                                       
-                                                       <div class="messageFooter">
-                                                               {if $message->editCount}
-                                                                       <p class="messageFooterNote">{lang}wcf.conversation.message.editNote{/lang}</p>
-                                                               {/if}
-                                                               
-                                                               {event name='messageFooterNotes'}
-                                                       </div>
-                                                       
-                                                       <footer class="messageOptions">
-                                                               <nav class="jsMobileNavigation buttonGroupNavigation">
-                                                                       <ul class="smallButtons buttonGroup">
-                                                                               {if $message->canEdit()}<li><a href="{link controller='ConversationMessageEdit' id=$message->messageID}{/link}" title="{lang}wcf.conversation.message.edit{/lang}" class="button{if !$conversation->isDraft || $message->messageID != $conversation->firstMessageID} jsMessageEditButton{/if}"><span class="icon icon16 icon-pencil"></span> <span>{lang}wcf.global.button.edit{/lang}</span></a></li>{/if}
-                                                                               <li class="jsQuoteMessage" data-object-id="{@$message->messageID}" data-is-quoted="{if $__quoteFullQuote|isset && $message->messageID|in_array:$__quoteFullQuote}1{else}0{/if}"><a rel="nofollow" href="{link controller='ConversationMessageAdd' id=$conversation->conversationID quoteMessageID=$message->messageID}{/link}" title="{lang}wcf.message.quote.quoteMessage{/lang}" class="button jsTooltip{if $__quoteFullQuote|isset && $message->messageID|in_array:$__quoteFullQuote} active{/if}"><span class="icon icon16 icon-quote-left"></span> <span class="invisible">{lang}wcf.message.quote.quoteMessage{/lang}</span></a></li>
-                                                                               {if $message->userID != $__wcf->getUser()->userID && $__wcf->session->getPermission('user.profile.canReportContent')}<li class="jsReportConversationMessage jsOnly" data-object-id="{@$message->messageID}"><a href="#" title="{lang}wcf.moderation.report.reportContent{/lang}" class="button jsTooltip"><span class="icon icon16 icon-warning-sign"></span> <span class="invisible">{lang}wcf.moderation.report.reportContent{/lang}</span></a></li>{/if}
-                                                                               {event name='messageOptions'}
-                                                                               <li class="toTopLink"><a href="{$__wcf->getAnchor('top')}" title="{lang}wcf.global.scrollUp{/lang}" class="button jsTooltip"><span class="icon icon16 icon-arrow-up"></span> <span class="invisible">{lang}wcf.global.scrollUp{/lang}</span></a></li>
-                                                                       </ul>
-                                                               </nav>
-                                                       </footer>
+                                               {event name='messageQuickOptions'}
+                                       </ul>
+                                       
+                                       {event name='messageHeader'}
+                               </header>
+                               
+                               <div class="messageBody">
+                                       {event name='beforeMessageText'}
+                                       
+                                       <div class="messageText">
+                                               {@$message->getFormattedMessage()}
+                                       </div>
+                                       
+                                       {event name='afterMessageText'}
+                               </div>
+                               
+                               <footer class="messageFooter">
+                                       {include file='attachments'}
+                                       
+                                       {if $message->showSignature && $message->getUserProfile()->showSignature()}
+                                               <div class="messageSignature">
+                                                       <div>{@$message->getUserProfile()->getSignature()}</div>
                                                </div>
+                                       {/if}
+                                       
+                                       {event name='messageFooter'}
+                                       
+                                       <div class="messageFooterNotes">
+                                               {if $message->editCount}
+                                                       <p class="messageFooterNote">{lang}wcf.conversation.message.editNote{/lang}</p>
+                                               {/if}
+                                               
+                                               {event name='messageFooterNotes'}
+                                       </div>
+                                       
+                                       <div class="messageFooterGroup">
+                                               <ul class="messageFooterButtons buttonList smallButtons jsMobileNavigation">
+                                                       {if $message->canEdit()}<li class="jsOnly"><a href="#" title="{lang}wcf.conversation.message.edit{/lang}" class="button{if !$conversation->isDraft || $message->messageID != $conversation->firstMessageID} jsMessageEditButton{/if}"><span class="icon icon16 fa-pencil"></span> <span>{lang}wcf.global.button.edit{/lang}</span></a></li>{/if}
+                                                       <li class="jsQuoteMessage" data-object-id="{@$message->messageID}" data-is-quoted="{if $__quoteFullQuote|isset && $message->messageID|in_array:$__quoteFullQuote}1{else}0{/if}"><a rel="nofollow" href="{link controller='ConversationMessageAdd' id=$conversation->conversationID quoteMessageID=$message->messageID}{/link}" title="{lang}wcf.message.quote.quoteMessage{/lang}" class="button jsTooltip{if $__quoteFullQuote|isset && $message->messageID|in_array:$__quoteFullQuote} active{/if}"><span class="icon icon16 fa-quote-left"></span> <span class="invisible">{lang}wcf.message.quote.quoteMessage{/lang}</span></a></li>
+                                                       {if $message->userID != $__wcf->getUser()->userID && $__wcf->session->getPermission('user.profile.canReportContent')}<li class="jsReportConversationMessage jsOnly" data-object-id="{@$message->messageID}"><a href="#" title="{lang}wcf.moderation.report.reportContent{/lang}" class="button jsTooltip"><span class="icon icon16 fa-exclamation-triangle"></span> <span class="invisible">{lang}wcf.moderation.report.reportContent{/lang}</span></a></li>{/if}
+                                                       {event name='messageFooterButtons'}
+                                               </ul>
                                        </div>
-                               </section>
+                               </footer>
                        </div>
                </article>
        </li>
index 750cb3207a0f24ee31b6455ac2e6cd6b7f2fc743..7b57a9bd994f5ba8d174f8f09b63806834707199 100644 (file)
@@ -1,21 +1,24 @@
 {if $modificationLogList|isset}
        {assign var=__modificationLogEntries value=$modificationLogList->getEntriesUntil($__modificationLogTime)}
        {foreach from=$__modificationLogEntries item=modificationLogEntry}
-               <li class="marginTop jsModificationLogEntry">
-                       <article class="message messageCollapsed">
-                               <div class="messageHeader">
-                                       <div class="box24">
-                                               <a href="{link controller='User' object=$modificationLogEntry->getUserProfile()}{/link}" class="framed">{@$modificationLogEntry->getUserProfile()->getAvatar()->getImageTag(24)}</a>
-                                               
-                                               <div>
-                                                       <h1><a href="{link controller='User' object=$modificationLogEntry->getUserProfile()}{/link}" class="userLink" data-user-id="{@$modificationLogEntry->userID}">{$modificationLogEntry->username}</a>
-                                                               -
-                                                               {@$modificationLogEntry->time|time}</h1>
-                                                       <small>{@$modificationLogEntry}</small>
+               <li class="jsModificationLogEntry">
+                       <article class="message messageReduced">
+                               <div class="messageContent">
+                                       <div class="messageHeader">
+                                               <div class="box32 messageHeaderWrapper">
+                                                       <a href="{link controller='User' object=$modificationLogEntry->getUserProfile()}{/link}">{@$modificationLogEntry->getUserProfile()->getAvatar()->getImageTag(32)}</a>
+                                                       
+                                                       <div class="messageHeaderBox">
+                                                               <h2 class="messageTitle">
+                                                                       <a href="{link controller='User' object=$modificationLogEntry->getUserProfile()}{/link}" class="userLink username" data-user-id="{@$modificationLogEntry->userID}">{$modificationLogEntry->username}</a>
+                                                                       <small class="separatorLeft">{@$modificationLogEntry->time|time}</small>
+                                                               </h2>
+                                                               <div>{@$modificationLogEntry}</div>
+                                                       </div>
                                                </div>
                                        </div>
                                </div>
                        </article>
                </li>
        {/foreach}
-{/if}
\ No newline at end of file
+{/if}
index 3d7f25dd00b484b77ea4992068a374d9c62ea467..d43a06eb4a71c4adf0a61507a441ab10501bbf18 100644 (file)
@@ -1,14 +1,14 @@
 <div class="box48">
        {if $message->getUserProfile()->getAvatar()}
-               <a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}" class="framed">{@$message->getUserProfile()->getAvatar()->getImageTag(48)}</a>
+               <a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}">{@$message->getUserProfile()->getAvatar()->getImageTag(48)}</a>
        {/if}
 
        <div>
                <div class="containerHeadline">
-                       <h3><a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}">{$message->username}</a> <small>- {@$message->time|time}</small></h3> 
+                       <h3><a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}">{$message->username}</a> <small class="separatorLeft">{@$message->time|time}</small></h3>
                </div>
                
-               <div>{@$message->getExcerpt()|nl2br}</div>
+               <div>{@$message->getExcerpt()|nl2br:false}</div>
                
                {event name='previewData'}
        </div>
index e4d6115c445138856d5c0a86cb2b4841ea9ceb33..c51fe1e78e41da28e1c006fc2ee7e9e84fe0f4a7 100644 (file)
@@ -1,38 +1,37 @@
-<li id="messageQuickReply" class="marginTop jsOnly{if $conversation->userID == $__wcf->getUser()->userID} messageGroupStarter{/if}" style="display: none;" data-conversation-id="{@$conversation->conversationID}" data-last-post-time="{@$conversation->lastPostTime}" data-page-no="{@$pageNo}">
-       <article class="message messageSidebarOrientation{@$__wcf->getStyleHandler()->getStyle()->getVariable('messageSidebarOrientation')|ucfirst} dividers{if $__wcf->getUserProfileHandler()->userOnlineGroupID} userOnlineGroupMarking{@$__wcf->getUserProfileHandler()->userOnlineGroupID}{/if}">
-               <div>
-                       {include file='messageSidebar' userProfile=$__wcf->getUserProfileHandler()}
+<li id="messageQuickReply" class="jsOnly{if $conversation->userID == $__wcf->getUser()->userID} messageGroupStarter{/if}{if $pageNo < $pages} messageQuickReplyCollapsed{/if}" data-object-id="{@$conversation->conversationID}" data-last-post-time="{@$conversation->lastPostTime}" data-page-no="{@$pageNo}">
+       <article class="message messageSidebarOrientation{@$__wcf->getStyleHandler()->getStyle()->getVariable('messageSidebarOrientation')|ucfirst}{if $__wcf->getUserProfileHandler()->userOnlineGroupID} userOnlineGroupMarking{@$__wcf->getUserProfileHandler()->userOnlineGroupID}{/if}">
+               {include file='messageSidebar' userProfile=$__wcf->getUserProfileHandler()->getUserProfile()}
+               
+               <div class="messageContent messageQuickReplyContent"{if $pageNo < $pages} data-placeholder="{lang}wcf.conversation.reply{/lang}"{/if}>
+                       <div class="messageBody">
+                               {if !$conversation->isDraft && !$conversation->hasOtherParticipants()}
+                                       <p class="warning" style="margin-bottom: 14px">{lang}wcf.conversation.noParticipantsWarning{/lang}</p>
+                               {/if}
+                               
+                               <textarea id="text" name="text" class="wysiwygTextarea"
+                                         data-autosave="com.woltlab.wcf.conversation.messageAdd-{@$conversation->conversationID}"
+                                         data-support-mention="true"
+                               ></textarea>
+                               {include file='messageFormTabsInline' inConversationQuickReply=true}
+                       </div>
                        
-                       <section class="messageContent messageQuickReplyContent">
-                               <div>
-                                       <header class="messageHeader">
-                                       </header>
-                                       
-                                       <div class="messageBody">
-                                               {if !$conversation->isDraft && !$conversation->hasOtherParticipants()}
-                                                       <p class="warning" style="margin-bottom: 14px">{lang}wcf.conversation.noParticipantsWarning{/lang}</p>
-                                               {/if}
-                                               
-                                               <textarea id="text" name="text" rows="20" cols="40" data-autosave="com.woltlab.wcf.conversation.messageAdd-{@$conversation->conversationID}" style="width: 100%"></textarea>
-                                               {include file='messageFormTabsInline' inConversationQuickReply=true}
-                                       </div>
-                                       
-                                       <div class="formSubmit">
-                                               <button class="buttonPrimary" data-type="save" accesskey="s">{lang}wcf.global.button.submit{/lang}</button>
-                                               <button data-type="extended">{lang}wcf.message.button.extendedReply{/lang}</button>
-                                               <button data-type="cancel">{lang}wcf.global.button.cancel{/lang}</button>
-                                       </div>
+                       <footer class="messageFooter">
+                               <div class="formSubmit">
+                                       <button class="buttonPrimary" data-type="save" accesskey="s">{lang}wcf.global.button.submit{/lang}</button>
+                                       {include file='messageFormPreviewButton' previewMessageObjectType='com.woltlab.wcf.conversation.message' previewMessageObjectID=0}
                                </div>
-                       </section>
+                       </footer>
                </div>
        </article>
        
        <script data-relocate="true">
-               //<![CDATA[
-               $(function() {
-                       WCF.System.Dependency.Manager.register('Redactor_text', function() { new WCF.Message.UserMention('text'); });
+               require(['WoltLabSuite/Core/Ui/Message/Reply'], function(UiMessageReply) {
+                       new UiMessageReply({
+                               ajax: {
+                                       className: 'wcf\\data\\conversation\\message\\ConversationMessageAction'
+                               }
+                       });
                });
-               //]]>
        </script>
        {include file='wysiwyg'}
 </li>
\ No newline at end of file
diff --git a/templates/email_notification_conversation.tpl b/templates/email_notification_conversation.tpl
new file mode 100644 (file)
index 0000000..159e60f
--- /dev/null
@@ -0,0 +1,37 @@
+{if $mimeType === 'text/plain'}
+{lang}wcf.user.notification.conversation.mail.plaintext{/lang}
+
+{@$event->getUserNotificationObject()->getFirstMessage()->getMailText($mimeType)} {* this line ends with a space *}
+{else}
+       {lang}wcf.user.notification.conversation.mail.html{/lang}
+       {assign var='user' value=$event->getAuthor()}
+       {assign var='conversation' value=$event->getUserNotificationObject()}
+       {assign var='message' value=$conversation->getFirstMessage()}
+       
+       {if $notificationType == 'instant'}{assign var='avatarSize' value=128}
+       {else}{assign var='avatarSize' value=64}{/if}
+       {capture assign='messageContent'}
+       <table cellpadding="0" cellspacing="0" border="0">
+               <tr>
+                       <td><a href="{link controller='User' object=$user isEmail=true}{/link}" title="{$message->username}">{@$user->getAvatar()->getImageTag($avatarSize)}</a></td>
+                       <td class="boxContent">
+                               <div class="containerHeadline">
+                                       <h3>
+                                               {if $message->userID}
+                                                       <a href="{link controller='User' object=$user isEmail=true}{/link}">{$message->username}</a>
+                                               {else}
+                                                       {$message->username}
+                                               {/if}
+                                               &#xb7;
+                                               <small>{$message->time|plainTime}</small>
+                                       </h3>
+                               </div>
+                               <div>
+                                       {@$message->getMailText($mimeType)}
+                               </div>
+                       </td>
+               </tr>
+       </table>
+       {/capture}
+       {include file='email_paddingHelper' block=true class='box'|concat:$avatarSize content=$messageContent sandbox=true}
+{/if}
diff --git a/templates/email_notification_conversationMessage.tpl b/templates/email_notification_conversationMessage.tpl
new file mode 100644 (file)
index 0000000..41cf23c
--- /dev/null
@@ -0,0 +1,40 @@
+{assign var='count' value=$event->getAuthors()|count}{assign var='guestTimesTriggered' value=$event->getNotification()->guestTimesTriggered}{assign var='authors' value=$event->getAuthors()|array_values}
+{if $mimeType === 'text/plain'}
+{capture assign='authorList'}{lang}wcf.user.notification.mail.authorList.plaintext{/lang}{/capture}
+{lang}wcf.user.notification.conversation.message.mail.plaintext{/lang}{if $count == 1 && !$guestTimesTriggered}
+
+{@$event->getUserNotificationObject()->getMailText($mimeType)}{/if} {* this line ends with a space *}
+{else}
+       {capture assign='authorList'}{lang}wcf.user.notification.mail.authorList.html{/lang}{/capture}
+       {lang}wcf.user.notification.conversation.message.mail.html{/lang}
+       {assign var='user' value=$event->getAuthor()}
+       {assign var='message' value=$event->getUserNotificationObject()}
+       {assign var='conversation' value=$message->getConversation()}
+       
+       {if $notificationType == 'instant'}{assign var='avatarSize' value=128}
+       {else}{assign var='avatarSize' value=64}{/if}
+       {capture assign='messageContent'}
+       <table cellpadding="0" cellspacing="0" border="0">
+               <tr>
+                       <td><a href="{link controller='User' object=$user isEmail=true}{/link}" title="{$message->username}">{@$user->getAvatar()->getImageTag($avatarSize)}</a></td>
+                       <td class="boxContent">
+                               <div class="containerHeadline">
+                                       <h3>
+                                               {if $message->userID}
+                                                       <a href="{link controller='User' object=$user isEmail=true}{/link}">{$message->username}</a>
+                                               {else}
+                                                       {$message->username}
+                                               {/if}
+                                               &#xb7;
+                                               <small>{$message->time|plainTime}</small>
+                                       </h3>
+                               </div>
+                               <div>
+                                       {@$message->getMailText($mimeType)}
+                               </div>
+                       </td>
+               </tr>
+       </table>
+       {/capture}
+       {include file='email_paddingHelper' block=true class='box'|concat:$avatarSize content=$messageContent sandbox=true}
+{/if}
index d6cf43ccd74bfb344b3fa9710482d129b54af7c1..8a0baa61dd334f4e2f6539b0c5be41270eb4a361 100644 (file)
@@ -1,33 +1,36 @@
 <article class="message messageReduced">
-       <div>
-               <section class="messageContent">
-                       <div>
-                               <header class="messageHeader">
-                                       <div class="box32">
-                                               {if $message->userID}
-                                                       <a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}" class="framed">{@$message->getUserProfile()->getAvatar()->getImageTag(32)}</a>
-                                               {else}
-                                                       <span class="framed">{@$message->getUserProfile()->getAvatar()->getImageTag(32)}</span>
-                                               {/if}
-                                               
-                                               <div class="messageHeadline">
-                                                       <h1>{if $message->getConversation()->canRead()}<a href="{@$message->getLink()}">{$message->getTitle()}</a>{else}{$message->getTitle()}{/if}</h1>
-                                                       <p>
-                                                               <span class="username">{if $message->userID}<a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}">{$message->getUsername()}</a>{else}{$message->getUsername()}{/if}</span>
-                                                               {@$message->getTime()|time}
-                                                       </p>
-                                               </div>
-                                       </div>
-                               </header>
+       <div class="messageContent">
+               <header class="messageHeader">
+                       <div class="box32 messageHeaderWrapper">
+                               {if $message->userID}
+                                       <a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}">{@$message->getUserProfile()->getAvatar()->getImageTag(32)}</a>
+                               {else}
+                                       <span>{@$message->getUserProfile()->getAvatar()->getImageTag(32)}</span>
+                               {/if}
                                
-                               <div class="messageBody">
-                                       <div>
-                                               <div class="messageText">
-                                                       {@$message->getFormattedMessage()}
-                                               </div>
-                                       </div>
+                               <div class="messageHeaderBox">
+                                       <h2 class="messageTitle">{if $message->getConversation()->canRead()}<a href="{@$message->getLink()}">{$message->getTitle()}</a>{else}{$message->getTitle()}{/if}</h2>
+                                       
+                                       <ul class="messageHeaderMetaData">
+                                               <li>{if $message->userID}<a href="{link controller='User' object=$message->getUserProfile()->getDecoratedObject()}{/link}" class="username">{$message->getUsername()}</a>{else}<span class="username">{$message->getUsername()}</span>{/if}</li>
+                                               <li><span class="messagePublicationTime">{@$message->getTime()|time}</span></li>
+                                               
+                                               {event name='messageHeaderMetaData'}
+                                       </ul>
                                </div>
                        </div>
-               </section>
+                       
+                       {event name='messageHeader'}
+               </header>
+               
+               <div class="messageBody">
+                       {event name='beforeMessageText'}
+                       
+                       <div class="messageText">
+                               {@$message->getFormattedMessage()}
+                       </div>
+                       
+                       {event name='afterMessageText'}
+               </div>
        </div>
 </article>
\ No newline at end of file
diff --git a/templates/searchConversationMessage.tpl b/templates/searchConversationMessage.tpl
new file mode 100644 (file)
index 0000000..34eef4f
--- /dev/null
@@ -0,0 +1,4 @@
+<dl>
+       <dt></dt>
+       <dd><label><input type="checkbox" name="conversationID" value="{@$searchedConversation->conversationID}" checked> {lang}wcf.conversation.searchedConversation{/lang}</label></dd>
+</dl>
diff --git a/update1_210.sql b/update1_210.sql
deleted file mode 100644 (file)
index 4447a60..0000000
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE wcf1_conversation_message ADD lastEditTime INT(10) NOT NULL DEFAULT 0;
diff --git a/update2_210.sql b/update2_210.sql
deleted file mode 100644 (file)
index 0cde8a4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE wcf1_conversation_message ADD editCount MEDIUMINT(7) NOT NULL DEFAULT 0;
diff --git a/update3_210.sql b/update3_210.sql
deleted file mode 100644 (file)
index b40c128..0000000
+++ /dev/null
@@ -1 +0,0 @@
-ALTER TABLE wcf1_conversation_message ADD hasEmbeddedObjects TINYINT(1) NOT NULL DEFAULT 0;
index c7480202704ff9b4f133ebff11fb7812c14150f0..0b2e4ce55f92e6cca0867f21c8c0e829b1fb6bde 100644 (file)
                        <option name="user.conversation.allowedAttachmentExtensions">
                                <categoryname>user.conversation</categoryname>
                                <optiontype>textarea</optiontype>
-                               <defaultvalue><![CDATA[gif
+                               <defaultvalue>gif
 jpg
 jpeg
 png
 bmp
 zip
 txt
-pdf]]></defaultvalue>
+pdf</defaultvalue>
                                <options>module_attachment</options>
-                               <wildcard><![CDATA[*]]></wildcard>
+                               <wildcard>*</wildcard>
                                <usersonly>1</usersonly>
                        </option>
                        <option name="user.conversation.maxAttachmentCount">
index 9ad7eb38f69282efb63c44c4e637af429eb29c22..405924934c666dfa0c099053bbb688652210ae5a 100644 (file)
@@ -6,9 +6,9 @@
                                <categoryname>settings.privacy.messaging</categoryname>
                                <optiontype>select</optiontype>
                                <editable>3</editable>
-                               <selectoptions><![CDATA[0:wcf.user.access.registered
+                               <selectoptions>0:wcf.user.access.registered
 1:wcf.user.access.following
-2:wcf.user.access.nobody]]></selectoptions>
+2:wcf.user.access.nobody</selectoptions>
                                <defaultvalue>0</defaultvalue>
                                <options>module_conversation</options>
                        </option>
                                <optiontype>select</optiontype>
                                <editable>3</editable>
                                <defaultvalue>0</defaultvalue>
-                               <selectoptions><![CDATA[0:wcf.global.defaultValue
+                               <selectoptions>0:wcf.global.defaultValue
 5
 10
 20
 30
-40]]></selectoptions>
+40</selectoptions>
                                <options>module_conversation</options>
                        </option>
                        <option name="conversationMessagesPerPage">
                                <optiontype>select</optiontype>
                                <editable>3</editable>
                                <defaultvalue>0</defaultvalue>
-                               <selectoptions><![CDATA[0:wcf.global.defaultValue
+                               <selectoptions>0:wcf.global.defaultValue
 5
 10
 20
 30
-40]]></selectoptions>
+40</selectoptions>
                                <options>module_conversation</options>
                        </option>
                </options>