Bläddra i källkod

#42 - messages module

Alex Trofimov 12 år sedan
förälder
incheckning
e296f05c54

+ 1 - 1
inc/classes/BxDolTemplate.php

@@ -1914,7 +1914,7 @@ class BxDolTemplate extends BxDol implements iBxDolSingleton {
     }
     function displayErrorOccured ($sMsg = '') {
         header("HTTP/1.0 500 Internal Server Error");
-        $this->displayMsg($sMsg ? $sMsg : _t('_Error Occured'));
+        $this->displayMsg($sMsg ? $sMsg : _t('_error occured'));
     }
     function displayPageNotFound ($sMsg = '') {
         header("HTTP/1.0 404 Not Found");

+ 3 - 8
modules/base/text/classes/BxBaseModTextModule.php

@@ -198,7 +198,7 @@ class BxBaseModTextModule extends BxDolModule
 
 		bx_import('BxDolCmts');
 		$oCmts = BxDolCmts::getObjectInstance($this->_oConfig->CNF['OBJECT_COMMENTS'], $iContentId);
-		if(!$oCmts->isEnabled())
+		if (!$oCmts || !$oCmts->isEnabled())
 			return false;
         return $oCmts->getCommentsBlock(0, 0, false);
     }
@@ -216,12 +216,7 @@ class BxBaseModTextModule extends BxDolModule
         if (!$aContentInfo)
             return false;
 
-        $oProfile = BxDolProfile::getInstance($aContentInfo[$this->_oConfig->CNF['FIELD_AUTHOR']]);
-        if (!$oProfile) {
-            bx_import('BxDolProfileUndefined');
-            $oProfile = BxDolProfileUndefined::getInstance();
-        }
-        return $this->_oTemplate->entryAuthor ($aContentInfo, $oProfile);
+        return $this->_oTemplate->entryAuthor ($aContentInfo);
     }
 
     /**
@@ -313,7 +308,7 @@ class BxBaseModTextModule extends BxDolModule
         $oCmts = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $aEvent['object_id']);
 
         $aComments = array(); 
-		if($oCmts->isEnabled())
+		if($oCmts && $oCmts->isEnabled())
 			$aComments = array(
 				'system' => $CNF['OBJECT_COMMENTS'],
 				'object_id' => $aContentInfo[$CNF['FIELD_ID']],

+ 18 - 8
modules/base/text/classes/BxBaseModTextTemplate.php

@@ -16,7 +16,7 @@ bx_import('BxDolModuleTemplate');
  */
 class BxBaseModTextTemplate extends BxDolModuleTemplate 
 {
-    protected static $MODULE;
+    protected $MODULE;
 
     /**
      * Constructor
@@ -30,7 +30,7 @@ class BxBaseModTextTemplate extends BxDolModuleTemplate
 
     function unit ($aData, $isCheckPrivateContent = true, $sTemplateName = 'unit.html') 
     {
-        $oModule = BxDolModule::getInstance(self::$MODULE);
+        $oModule = BxDolModule::getInstance($this->MODULE);
         $CNF = &$oModule->_oConfig->CNF;
 
         if ($isCheckPrivateContent && CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $oModule->checkAllowedView($aData))) {
@@ -106,7 +106,7 @@ class BxBaseModTextTemplate extends BxDolModuleTemplate
 
     function entryText ($aData, $sTemplateName = 'entry-text.html') 
     {
-        $oModule = BxDolModule::getInstance(self::$MODULE);
+        $oModule = BxDolModule::getInstance($this->MODULE);
         $CNF = &$oModule->_oConfig->CNF;
 
         $aVars = $aData;
@@ -116,23 +116,33 @@ class BxBaseModTextTemplate extends BxDolModuleTemplate
         return $this->parseHtmlByName($sTemplateName, $aVars);
     }
 
-    function entryAuthor ($aData, $oProfile, $sTemplateName = 'author.html') 
+    function entryAuthor ($aData, $sTemplateName = 'author.html') 
     {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        $oProfile = BxDolProfile::getInstance($aData[$CNF['FIELD_AUTHOR']]);
+        if (!$oProfile) {
+            bx_import('BxDolProfileUndefined');
+            $oProfile = BxDolProfileUndefined::getInstance();
+        }
         if (!$oProfile)
             return '';
 
-        $oModule = BxDolModule::getInstance(self::$MODULE);
-        $CNF = &$oModule->_oConfig->CNF;
-
         $aVars = array (
             'author_url' => $oProfile->getUrl(),
             'author_thumb_url' => $oProfile->getThumb(),
             'author_title' => $oProfile->getDisplayName(),
-            'entry_posting_date' =>  bx_time_js($aData[$CNF['FIELD_ADDED']], BX_FORMAT_DATE),
+            'author_desc' => $this->getAuthorDesc($aData),
         );
         return $this->parseHtmlByName($sTemplateName, $aVars);
     }
 
+    function getAuthorDesc ($aData) 
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        return bx_time_js($aData[$oModule->_oConfig->CNF['FIELD_ADDED']], BX_FORMAT_DATE);
+    }
 }
 
 /** @} */ 

+ 31 - 0
modules/boonex/messages/classes/BxMsgAlertsResponse.php

@@ -0,0 +1,31 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Messages Messages
+ * @ingroup     DolphinModules
+ *
+ * @{
+ */
+
+/**
+ * alerts handler
+ */
+class BxMsgAlertsResponse extends BxDolAlertsResponse 
+{
+    public function response($oAlert) 
+    {
+        if ('bx_messages' == $oAlert->sUnit) {
+
+            switch ($oAlert->sAction) {
+                case 'commentPost':
+                    BxDolService::call('bx_messages', 'trigger_comment_post', array($oAlert->iObject, $oAlert->iSender));
+                    break;
+            }
+
+        }
+    }
+}
+
+/** @} */

+ 14 - 0
modules/boonex/messages/classes/BxMsgCmts.php

@@ -21,6 +21,7 @@ class BxMsgCmts extends BxTemplCmts
         if (!parent::isEnabled ())
             return false;
 
+        bx_import('BxDolModule');
         $oModule = BxDolModule::getInstance('bx_messages');
         if (!($aContentInfo = $oModule->_oDb->getContentInfoById((int)$this->getId())))
             return false;
@@ -31,6 +32,19 @@ class BxMsgCmts extends BxTemplCmts
 
         return true;
     }
+
+    public function isRemoveAllowed ($aCmt, $isPerformAction = false)
+    {
+    	if (isAdmin())
+    		return true;
+
+        return false;
+    }
+
+    public function msgErrRemoveAllowed ()
+    {
+        return _t('_sys_txt_access_denied');
+    }
 }
 
 /** @} */

+ 1 - 0
modules/boonex/messages/classes/BxMsgConfig.php

@@ -41,6 +41,7 @@ class BxMsgConfig extends BxBaseModTextConfig
             'URI_VIEW_ENTRY' => 'view-message',
             'URI_HOME' => 'messages',
             'URI_AUTHOR_ENTRIES' => 'messages',
+            'URI_ADD_ENTRY' => 'compose-message',
 
             // some params
             'PARAM_CHARS_SUMMARY' => '',

+ 5 - 0
modules/boonex/messages/classes/BxMsgDb.php

@@ -39,6 +39,11 @@ class BxMsgDb extends BxBaseModTextDb
         return $this->query($sQuery);
     }
 
+    public function updateLastCommentTimeProfile($iConversationId, $iProfileId, $iTimestamp)
+    {
+        $sQuery = $this->prepare("UPDATE `" . $this->getPrefix() . "conversations` SET `last_reply_profile_id` = ?, `last_reply_timestamp` = ? WHERE `id` = ?", $iProfileId, $iTimestamp, $iConversationId);
+        return $this->query($sQuery);
+    }
 }
 
 /** @} */ 

+ 2 - 0
modules/boonex/messages/classes/BxMsgFormEntry.php

@@ -29,6 +29,8 @@ class BxMsgFormEntry extends BxBaseModTextFormEntry
 
     public function insert ($aValsToAdd = array(), $isIgnore = false) 
     {
+        $aValsToAdd['last_reply_timestamp'] = time();
+        $aValsToAdd['last_reply_profile_id'] = bx_get_logged_profile_id();
         $iContentId = parent::insert ($aValsToAdd, $isIgnore);
         if (!$iContentId)
             return 0;

+ 69 - 0
modules/boonex/messages/classes/BxMsgGrid.php

@@ -13,9 +13,78 @@ bx_import('BxTemplGrid');
 
 class BxMsgGrid extends BxTemplGrid 
 {
+    protected static $MODULE;
+
     public function __construct ($aOptions, $oTemplate = false) 
     {
+        self::$MODULE = 'bx_messages';
         parent::__construct ($aOptions, $oTemplate);
+        $this->_sDefaultSortingOrder = 'DESC';
+    }
+
+    public function performActionCompose() 
+    {
+        $oModule = BxDolModule::getInstance(self::$MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        bx_import('BxDolPermalinks');
+        $sUrl = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_ADD_ENTRY']);
+
+        header('Location:' . $sUrl);
+    }
+
+    protected function _getActionAdd ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array()) 
+    {
+        $oModule = BxDolModule::getInstance(self::$MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        bx_import('BxDolPermalinks');
+        $sUrl = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_ADD_ENTRY']);
+
+        $a['attr']['onclick'] = "document.location='$sUrl'";
+        unset($a['attr']['bx_grid_action_independent']);
+
+        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getCellPreview ($mixedValue, $sKey, $aField, $aRow) 
+    {
+        $oModule = BxDolModule::getInstance(self::$MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        bx_import('BxDolPermalinks');
+        $sUrl = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aRow[$CNF['FIELD_ID']]);
+
+        $s = strmaxtextlen($aRow['text'], 100);
+        $s = '<a href="' . $sUrl . '">' . $s . '</a>';
+        if ($aRow['comments'] - $aRow['read_comments'] > 0)
+            $s = '<b>' . $s . '</b>';
+        return parent::_getCellDefault ($s, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellLastReplyTimestamp ($mixedValue, $sKey, $aField, $aRow) 
+    {
+        $s = bx_time_js($mixedValue, BX_FORMAT_DATE);
+        if ($aRow['comments'] - $aRow['read_comments'] > 0)
+            $s = '<b>' . $s . '</b>';
+        return parent::_getCellDefault ($s, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellCollaborators ($mixedValue, $sKey, $aField, $aRow)
+    {
+        $oModule = BxDolModule::getInstance(self::$MODULE);
+        $s = $oModule->_oTemplate->entryCollaborators ($aRow);
+        return parent::_getCellDefault ($s, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellComments ($mixedValue, $sKey, $aField, $aRow) 
+    {
+        if ($aRow['comments'] - $aRow['read_comments'] > 0)
+            $mixedValue = _t('_bx_msg_x_new_messages', 1 + $mixedValue, $aRow['comments'] - $aRow['read_comments']);
+        else
+            $mixedValue = 1 + $mixedValue;
+
+        return parent::_getCellDefault ($mixedValue, $sKey, $aField, $aRow);
     }
 }
 

+ 61 - 10
modules/boonex/messages/classes/BxMsgModule.php

@@ -27,13 +27,52 @@ class BxMsgModule extends BxBaseModTextModule
         parent::__construct($aModule);
     }
 
+    public function sortCollaborators ($aCollaborators, $iProfileIdLastComment, $iProfileIdAuthor, $iProfileIdCurrent = 0) 
+    {
+        if (!$iProfileIdCurrent)
+            $iProfileIdCurrent = bx_get_logged_profile_id();
+
+        $aMoveUp = array($iProfileIdCurrent, $iProfileIdLastComment, $iProfileIdAuthor);
+
+        asort($aCollaborators, SORT_NUMERIC);
+
+        foreach ($aMoveUp as $iProfileId) {
+            if (!isset($aCollaborators[$iProfileId]))
+                continue;
+
+            $a = array($iProfileId => $aCollaborators[$iProfileId]);
+            unset($aCollaborators[$iProfileId]);
+            $aCollaborators = $a + $aCollaborators;
+        }
+
+        return $aCollaborators;
+    }
+
+    public function setModuleSubmenu () 
+    {
+        bx_import('BxDolMenu');
+        $oMenuSubmenu = BxDolMenu::getObjectInstance('sys_site_submenu');
+        if ($oMenuSubmenu) 
+            $oMenuSubmenu->setObjectSubmenu($this->_oConfig->CNF['OBJECT_MENU_SUBMENU'], array (
+                'title' => 'Messages',
+                'link' => 'javascript:void(0);',
+                'icon' => '',
+            ));
+    }
+
     /**
      * Display messages in folder
      */
     public function actionFolder ($iFolderId) 
     {
+        $this->setModuleSubmenu ();
+
         bx_import('BxDolGrid');
         $oGrid = BxDolGrid::getObjectInstance('bx_messages');
+        if (!$oGrid){
+            $this->_oTemplate->displayErrorOccured();
+            exit;
+        }
 
         // TODO: incorporate markers into custom class, so replace will work in search and so on
         $oGrid->addMarkers(array(
@@ -41,11 +80,6 @@ class BxMsgModule extends BxBaseModTextModule
             'profile_id' => bx_get_logged_profile_id(),
         ));
 
-        if (!$oGrid) {
-            $this->_oTemplate->displayPageNotFound();
-            exit;
-        }
-
         // TODO: refactor below
         $oTemplate = BxDolTemplate::getInstance();
         $oTemplate->setPageNameIndex (BX_PAGE_DEFAULT);
@@ -67,6 +101,26 @@ class BxMsgModule extends BxBaseModTextModule
         echo(json_encode($a));
     }
 
+    /**
+     * Update last comment time and author
+     */
+    public function serviceTriggerCommentPost ($iContentId, $iProfileId, $iTimestamp = 0) 
+    {
+        if (!(int)$iContentId)
+            return false;
+        $aContentInfo = $this->_oDb->getContentInfoById((int)$iContentId);
+        if (!$aContentInfo)
+            return false;
+   
+        if (!$iTimestamp)
+            $iTimestamp = time();
+
+        if ($iProfileId == bx_get_logged_profile_id())
+            $this->_oDb->updateReadComments($iProfileId, $aContentInfo[$this->_oConfig->CNF['FIELD_ID']], $aContentInfo[$this->_oConfig->CNF['FIELD_COMMENTS']]);
+
+        return $this->_oDb->updateLastCommentTimeProfile((int)$iContentId, (int)$iProfileId, $iTimestamp);
+    }
+
     /**
      * Entry collaborators block
      */
@@ -79,11 +133,8 @@ class BxMsgModule extends BxBaseModTextModule
         $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
         if (!$aContentInfo)
             return false;
-
-        $aCollaborators = $this->_oDb->getCollaborators($iContentId);
-        //unset($aCollaborators[$aContentInfo[$this->_oConfig->CNF['FIELD_AUTHOR']]]);
-    
-        return $this->_oTemplate->entryCollaborators ($aContentInfo, $aCollaborators);
+   
+        return $this->_oTemplate->entryCollaborators ($aContentInfo, 5, 'right');
     }
 
     /**

+ 2 - 0
modules/boonex/messages/classes/BxMsgPageEntry.php

@@ -24,6 +24,8 @@ class BxMsgPageEntry extends BxBaseModTextPageEntry
         $CNF = &$this->_oModule->_oConfig->CNF;
 
         $this->_oModule->_oDb->updateReadComments(bx_get_logged_profile_id(), $this->_aContentInfo[$CNF['FIELD_ID']], $this->_aContentInfo[$CNF['FIELD_COMMENTS']]);
+
+        $this->_oModule->setModuleSubmenu ();
     }
 }
 

+ 63 - 8
modules/boonex/messages/classes/BxMsgTemplate.php

@@ -21,40 +21,95 @@ class BxMsgTemplate extends BxBaseModTextTemplate
      */
     function __construct(&$oConfig, &$oDb) 
     {
-        self::$MODULE = 'bx_messages';
+        $this->MODULE = 'bx_messages';
         parent::__construct($oConfig, $oDb);
     }
 
-    public function entryCollaborators ($aContentInfo, $aCollaborators)
+    public function entryCollaborators ($aContentInfo, $iMaxVisible = 2, $sFloat = 'left')
     {
-        $oModule = BxDolModule::getInstance(self::$MODULE);
+        $oModule = BxDolModule::getInstance($this->MODULE);
         $CNF = &$oModule->_oConfig->CNF;
 
         bx_import('BxDolProfile');
     
+        $aCollaborators = $this->_oDb->getCollaborators($aContentInfo[$CNF['FIELD_ID']]);
+        //unset($aCollaborators[$aContentInfo[$CNF['FIELD_AUTHOR']]]);
+
+        // sort collaborators: first - current user, second - last replier, third - author, all others sorted by max number of posts
+        $aCollaborators = $oModule->sortCollaborators($aCollaborators, $aContentInfo['last_reply_profile_id'], $aContentInfo[$CNF['FIELD_AUTHOR']]);
+        $iCollaboratorsNum = count($aCollaborators);
+
+        // prepare template variables
+        $aVarsPopup = array (
+            'bx_repeat:collaborators' => array(),
+            'bx_if:collaborators_more' => array(
+                'condition' => false,
+                'content' => array(),
+            ),
+        );
         $aVars = array (
             'bx_repeat:collaborators' => array(),
+            'bx_if:collaborators_more' => array(
+                'condition' => $iCollaboratorsNum > $iMaxVisible,
+                'content' => array(
+                    'popup' => '',
+                    'title_more' => _t('_bx_msg_more', $iCollaboratorsNum - $iMaxVisible),
+                    'float' => $sFloat,
+                    'id' => $this->MODULE . '-popup-' . $aContentInfo[$CNF['FIELD_ID']],
+                ),
+            ),
         );
+        $i = 0;
         foreach ($aCollaborators as $iProfileId => $iReadComments) {
             $oProfile = BxDolProfile::getInstance($iProfileId);
             if (!$oProfile)
                 continue;
-            $aVars['bx_repeat:collaborators'][] = array (
+
+            $aCollaborator = array (
+                'id' => $oProfile->id(),
                 'url' => $oProfile->getUrl(),
                 'thumb_url' => $oProfile->getThumb(),
                 'title' => $oProfile->getDisplayName(),
-                'unread_messages_title_attr' =>  bx_html_attribute( _t('_bx_msg_unread_messages', $aContentInfo['comments'] - $iReadComments)),
-                'bx_if:unread_messages' => array (
-                    'condition' => ($aContentInfo['comments'] - $iReadComments) > 0,
+                'title_attr' =>  $oProfile->getDisplayName(),
+                'float' => $sFloat,
+                'bx_if:last_replier' => array (
+                    'condition' => ($aContentInfo['last_reply_profile_id'] == $iProfileId),
+                    'content' => array (
+                        'id' => $oProfile->id(),
+                    ),
+                ),
+                'bx_if:author'  => array (
+                    'condition' => $aContentInfo[$CNF['FIELD_AUTHOR']] == $iProfileId,
                     'content' => array (
-                        'unread_messages' =>  $aContentInfo['comments'] - $iReadComments,
+                        'id' => $oProfile->id(),
                     ),
                 ),
             );
+
+            if ($i < $iMaxVisible)
+                $aVars['bx_repeat:collaborators'][] = $aCollaborator;
+            if ($i >= $iMaxVisible)
+                $aVarsPopup['bx_repeat:collaborators'][] = $aCollaborator;
+
+            ++$i;
+        }
+
+        if ($aVarsPopup['bx_repeat:collaborators']) {
+            bx_import('BxTemplFunctions');
+            $aVars['bx_if:collaborators_more']['content']['popup'] = BxTemplFunctions::getInstance()->transBox('', '<div class="bx-def-padding">' . $this->parseHtmlByName('collaborators.html', $aVarsPopup) . '</div>');
         }
 
         return $this->parseHtmlByName('collaborators.html', $aVars);
     }
+
+    function getAuthorDesc ($aData) 
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        if ($aData['last_reply_timestamp'] == $aData[$oModule->_oConfig->CNF['FIELD_ADDED']])
+            return bx_time_js($aData[$oModule->_oConfig->CNF['FIELD_ADDED']], BX_FORMAT_DATE);
+        
+        return _t('_bx_msg_author_desc', bx_time_js($aData[$oModule->_oConfig->CNF['FIELD_ADDED']], BX_FORMAT_DATE), bx_time_js($aData['last_reply_timestamp'], BX_FORMAT_DATE));
+    }
 }
 
 /** @} */ 

+ 25 - 8
modules/boonex/messages/install/langs/en.xml

@@ -61,14 +61,26 @@
     <string name="_bx_msg_menu_title_view_entry"><![CDATA[View message]]></string>
     <string name="_bx_msg_menu_title_submenu"><![CDATA[Messages Submenu]]></string>
     <string name="_bx_msg_menu_set_title_submenu"><![CDATA[Messages Submenu]]></string>
-    <string name="_bx_msg_menu_item_title_system_delete_entry"><![CDATA[Delete message]]></string>
-    <string name="_bx_msg_menu_item_title_delete_entry"><![CDATA[Delete message]]></string>
-    <string name="_bx_msg_menu_item_title_system_entries_inbox"><![CDATA[Inbox]]></string>
-    <string name="_bx_msg_menu_item_title_entries_inbox"><![CDATA[Inbox]]></string>
-    <string name="_bx_msg_menu_item_title_system_entries_sent"><![CDATA[Sent]]></string>
-    <string name="_bx_msg_menu_item_title_entries_sent"><![CDATA[Sent]]></string>
     <string name="_bx_msg_menu_title_entries_my"><![CDATA[My messages action menu]]></string>
     <string name="_bx_msg_menu_set_title_entries_my"><![CDATA[My messages menu]]></string>
+    <string name="_bx_msg_menu_title_folders_more"><![CDATA[More folders]]></string>
+    <string name="_bx_msg_menu_set_title_submenu"><![CDATA[More folders]]></string>
+
+
+    <string name="_bx_msg_menu_item_title_system_delete_entry"><![CDATA[Delete message]]></string>
+    <string name="_bx_msg_menu_item_title_delete_entry"><![CDATA[Delete message]]></string>
+    <string name="_bx_msg_menu_item_title_system_folder_inbox"><![CDATA[Inbox]]></string>
+    <string name="_bx_msg_menu_item_title_folder_inbox"><![CDATA[Inbox]]></string>
+    <string name="_bx_msg_menu_item_title_system_folder_sent"><![CDATA[Sent]]></string>
+    <string name="_bx_msg_menu_item_title_folder_sent"><![CDATA[Sent]]></string>
+    <string name="_bx_msg_menu_item_title_system_folder_drafts"><![CDATA[Drafts]]></string>
+    <string name="_bx_msg_menu_item_title_folder_drafts"><![CDATA[Drafts]]></string>
+    <string name="_bx_msg_menu_item_title_system_folder_spam"><![CDATA[Spam]]></string>
+    <string name="_bx_msg_menu_item_title_folder_spam"><![CDATA[Spam]]></string>
+    <string name="_bx_msg_menu_item_title_system_folder_trash"><![CDATA[Trash]]></string>
+    <string name="_bx_msg_menu_item_title_folder_trash"><![CDATA[Trash]]></string>
+    <string name="_bx_msg_menu_item_title_system_folder_more"><![CDATA[More]]></string>
+    <string name="_bx_msg_menu_item_title_folder_more"><![CDATA[More]]></string>
 
     <string name="_bx_msg_txt_sample_single"><![CDATA[message]]></string>
 
@@ -78,14 +90,19 @@
     <string name="_bx_msg_folder_spam"><![CDATA[Spam]]></string>
     <string name="_bx_msg_folder_trash"><![CDATA[Trash]]></string>
 
-    <string name="_bx_msg_field_author"><![CDATA[Author]]></string>
+    <string name="_bx_msg_field_comments"><![CDATA[Messages]]></string>
+    <string name="_bx_msg_field_updated"><![CDATA[Updated]]></string>
     <string name="_bx_msg_field_preview"><![CDATA[Preview]]></string>
     <string name="_bx_msg_field_collaborators"><![CDATA[Collaborators]]></string>
-    <string name="_bx_msg_field_unread_comments"><![CDATA[Unread]]></string>
 
     <string name="_bx_msg_grid_action_delete"><![CDATA[Delete]]></string>
     <string name="_bx_msg_grid_action_compose"><![CDATA[Compose]]></string>
 
     <string name="_bx_msg_unread_messages"><![CDATA[{0} unread messages]]></string>
+    <string name="_bx_msg_last_replier"><![CDATA[last replier, {0}]]></string>
+    <string name="_bx_msg_more"><![CDATA[{0} more]]></string>
+
+    <string name="_bx_msg_author_desc"><![CDATA[{0} (updated {1})]]></string>
+    <string name="_bx_msg_x_new_messages"><![CDATA[<b>{0} ({1} new)</b>]]></string>
 
 </resources>

+ 5 - 1
modules/boonex/messages/install/sql/disable.sql

@@ -23,7 +23,7 @@ DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_messages' OR `object` IN('bx
 -- MENU
 DELETE FROM `sys_objects_menu` WHERE `module` = 'bx_messages';
 DELETE FROM `sys_menu_sets` WHERE `module` = 'bx_messages';
-DELETE FROM `sys_menu_items` WHERE `module` = 'bx_messages' OR `set_name` IN('bx_messages_view', 'bx_messages_submenu', 'bx_messages_my');
+DELETE FROM `sys_menu_items` WHERE `module` = 'bx_messages' OR `set_name` IN('bx_messages_view', 'bx_messages_submenu', 'bx_messages_my', 'bx_messages_menu_folders_more');
 
 -- GRID
 DELETE FROM `sys_objects_grid` WHERE `object` LIKE 'bx_messages%';
@@ -40,3 +40,7 @@ DELETE FROM `sys_objects_cmts` WHERE `Name` = 'bx_messages';
 -- VIEWS
 DELETE FROM `sys_objects_view` WHERE `Name` = 'bx_messages';
 
+-- ALERTS
+SET @iHandler := (SELECT `id` FROM `sys_alerts_handlers` WHERE `name` = 'bx_messages' LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `handler_id` = @iHandler;
+DELETE FROM `sys_alerts_handlers` WHERE `id` = @iHandler;

+ 31 - 7
modules/boonex/messages/install/sql/enable.sql

@@ -104,21 +104,35 @@ INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES
 ('bx_messages_submenu', 'bx_messages', '_bx_msg_menu_set_title_submenu', 0);
 
 INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
-('bx_messages_submenu', 'bx_messages', 'messages-inbox', '_bx_msg_menu_item_title_system_entries_inbox', '_bx_msg_menu_item_title_entries_inbox', 'page.php?i=messages-inbox', '', '', '', '', 2147483647, 1, 1, 1),
-('bx_messages_submenu', 'bx_messages', 'messages-sent', '_bx_msg_menu_item_title_system_entries_sent', '_bx_msg_menu_item_title_entries_sent', 'page.php?i=messages-sent', '', '', '', '', 2147483647, 1, 1, 2);
+('bx_messages_submenu', 'bx_messages', 'messages-folder-inbox', '_bx_msg_menu_item_title_system_folder_inbox', '_bx_msg_menu_item_title_folder_inbox', 'modules/?r=messages/folder/1', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_messages_submenu', 'bx_messages', 'messages-folder-sent', '_bx_msg_menu_item_title_system_folder_sent', '_bx_msg_menu_item_title_folder_sent', 'modules/?r=messages/folder/2', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_messages_submenu', 'bx_messages', 'messages-folder-more', '_bx_msg_menu_item_title_system_folder_more', '_bx_msg_menu_item_title_folder_more', 'javascript:void(0);', 'bx_menu_popup(''bx_messages_menu_folders_more'', this);', '', '', '', 2147483647, 1, 1, 3);
+
+-- MENU: more folders
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_messages_menu_folders_more', '_bx_msg_menu_title_folders_more', 'bx_messages_menu_folders_more', 'bx_messages', 4, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_messages_menu_folders_more', 'bx_messages', '_bx_msg_menu_set_title_folders_more', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_messages_menu_folders_more', 'bx_messages', 'messages-drafts', '_bx_msg_menu_item_title_system_folder_drafts', '_bx_msg_menu_item_title_folder_drafts', 'modules/?r=messages/folder/3', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_messages_menu_folders_more', 'bx_messages', 'messages-spam', '_bx_msg_menu_item_title_system_folder_spam', '_bx_msg_menu_item_title_folder_spam', 'modules/?r=messages/folder/4', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_messages_menu_folders_more', 'bx_messages', 'messages-trash', '_bx_msg_menu_item_title_system_folder_trash', '_bx_msg_menu_item_title_folder_trash', 'modules/?r=messages/folder/5', '', '', '', '', 2147483647, 1, 1, 3);
 
 
 -- GRID
 
 INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_mode`, `sorting_fields`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
-('bx_messages', 'Sql', 'SELECT `c`.`id`, `c`.`author`, `c`.`text`, `c`.`comments`, `f`.`read_comments` FROM `bx_messages_conversations` AS `c` INNER JOIN `bx_messages_conv2folder` AS `f` ON (`c`.`id` = `f`.`conv_id` AND `f`.`folder_id` = {folder_id} AND `f`.`collaborator` = {profile_id})', 'bx_messages_conversations', 'id', '', '', 10, NULL, 'start', '', 'text', 'auto', '', 64, 'BxMsgGrid', 'modules/boonex/messages/classes/BxMsgGrid.php');
+('bx_messages', 'Sql', 'SELECT `c`.`id`, `c`.`author`, `c`.`text`, `c`.`added`, `c`.`comments`, `f`.`read_comments`, `last_reply_timestamp`, `last_reply_profile_id` FROM `bx_messages_conversations` AS `c` INNER JOIN `bx_messages_conv2folder` AS `f` ON (`c`.`id` = `f`.`conv_id` AND `f`.`folder_id` = {folder_id} AND `f`.`collaborator` = {profile_id})', 'bx_messages_conversations', 'id', 'last_reply_timestamp', '', 10, NULL, 'start', '', 'text', 'auto', 'comments,last_reply_timestamp', 64, 'BxMsgGrid', 'modules/boonex/messages/classes/BxMsgGrid.php');
 
 INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `params`, `order`) VALUES
 ('bx_messages', 'checkbox', '_sys_select', '2%', '', 1),
-('bx_messages', 'author', '_bx_msg_field_author', '5%', '', 2),
-('bx_messages', 'preview', '_bx_msg_field_preview', '70%', '', 3),
-('bx_messages', 'collaborators', '_bx_msg_field_collaborators', '20%', '', 4),
-('bx_messages', 'unread_comments', '_bx_msg_field_unread_comments', '3%', '', 5);
+('bx_messages', 'collaborators', '_bx_msg_field_collaborators', '25%', '', 2),
+('bx_messages', 'preview', '_bx_msg_field_preview', '50%', '', 3),
+('bx_messages', 'comments', '_bx_msg_field_comments', '10%', '', 4),
+('bx_messages', 'last_reply_timestamp', '_bx_msg_field_updated', '13%', '', 5);
 
 INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `confirm`, `order`) VALUES
 ('bx_messages', 'bulk', 'delete', '_bx_msg_grid_action_delete', '', 1, 1),
@@ -181,3 +195,13 @@ INSERT INTO `sys_objects_cmts` (`Name`, `Table`, `CharsPostMin`, `CharsPostMax`,
 INSERT INTO `sys_objects_view` (`name`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
 ('bx_messages', 'bx_messages_views_track', '86400', '1', 'bx_messages_conversations', 'id', 'views', '', '');
 
+-- ALERTS
+
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `eval`) VALUES 
+('bx_messages', 'BxMsgAlertsResponse', 'modules/boonex/messages/classes/BxMsgAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('bx_messages', 'commentPost', @iHandler),
+('bx_messages', 'commentRemoved', @iHandler);
+

+ 4 - 1
modules/boonex/messages/install/sql/install.sql

@@ -9,7 +9,10 @@ CREATE TABLE IF NOT EXISTS `bx_messages_conversations` (
   `text` text NOT NULL,
   `views` int(11) NOT NULL default '0',
   `comments` int(11) NOT NULL default '0',
-  PRIMARY KEY (`id`)
+  `last_reply_timestamp` int(11) NOT NULL,
+  `last_reply_profile_id` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `last_reply_timestamp` (`last_reply_timestamp`)
 );
 
 CREATE TABLE IF NOT EXISTS `bx_messages_conv2folder` (

+ 2 - 2
modules/boonex/messages/template/author.html

@@ -1,5 +1,5 @@
 
-<div class="bx-notes-author bx-def-unit">
-    <a href="__author_url__"><img class="bx-def-thumb bx-def-thumb-size" src="__author_thumb_url__" /></a><div class="bx-def-unit-info bx-def-thumb-size-max-height bx-def-padding-left"><a href="__author_url__">__author_title__</a><br /><span class="bx-def-font-grayed bx-def-font-small">__entry_posting_date__</span></div>
+<div class="bx-msg-author bx-def-unit">
+    <a href="__author_url__"><img class="bx-def-thumb bx-def-thumb-size" src="__author_thumb_url__" /></a><div class="bx-def-unit-info bx-def-thumb-size-max-height bx-def-padding-left"><a href="__author_url__">__author_title__</a><br /><span class="bx-def-font-grayed bx-def-font-small">__author_desc__</span></div>
 </div>
 

+ 22 - 8
modules/boonex/messages/template/collaborators.html

@@ -1,8 +1,22 @@
-<bx_repeat:collaborators>
-    <div class="bx-msg-collaborator bx-def-unit bx-def-margin-sec-left bx-def-margin-sec-bottom">
-        <a href="__url__" title="__unread_messages_title_attr__"><img class="bx-def-thumb bx-def-thumb-size" src="__thumb_url__" /></a>
-        <bx_if:unread_messages>
-            <div class="bx-def-unit-alert bg-col-blue2-dark">__unread_messages__</div>
-        </bx_if:unread_messages>
-    </div>
-</bx_repeat:collaborators>
+<div class="bx-msg-collaborators bx-clearfix">
+
+    <bx_repeat:collaborators>
+        <div class="bx-msg-collaborator bx-def-unit bx-def-margin-sec-__float__-auto" style="float:__float__;">
+            <a href="__url__" title="__title_attr__"><img class="bx-def-thumb bx-def-thumb-size" src="__thumb_url__" /></a>
+            <bx_if:last_replier>
+                <div class="bx-def-unit-alert bg-col-blue2-dark" style="left:0; right:auto;"><i class="sys-icon comments"></i></div>
+            </bx_if:last_replier>
+            <bx_if:author>
+                <div class="bx-def-unit-alert bg-col-blue2-dark"><i class="sys-icon user"></i></div>
+            </bx_if:author>
+        </div>
+    </bx_repeat:collaborators>
+
+    <bx_if:collaborators_more>
+        <div class="bx-msg-collaborator bx-def-unit bx-def-thumb-size bx-def-margin-sec-__float__-auto" style="float:__float__;">
+            <a href="javascript:void(0);" onclick="$('#__id__').dolPopup({pointer:{el:$(this)}})">__title_more__</a>            
+        </div>
+        <div id="__id__" style="display:none;">__popup__</div>
+    </bx_if:collaborators_more>
+
+</div>

+ 1 - 0
modules/boonex/messages/template/css/main.css

@@ -2,6 +2,7 @@
 
 .bx-msg-collaborator {
     float:right;
+    white-space:nowrap;
 }
 
 /* unit */

+ 1 - 0
modules/boonex/notes/classes/BxNotesConfig.php

@@ -41,6 +41,7 @@ class BxNotesConfig extends BxBaseModTextConfig
             'URI_VIEW_ENTRY' => 'view-note',
             'URI_HOME' => 'notes-home',
             'URI_AUTHOR_ENTRIES' => 'notes-author',
+            'URI_ADD_ENTRY' => 'create-note',
 
             // some params
             'PARAM_CHARS_SUMMARY' => 'bx_notes_summary_chars',

+ 1 - 1
modules/boonex/notes/classes/BxNotesTemplate.php

@@ -21,7 +21,7 @@ class BxNotesTemplate extends BxBaseModTextTemplate
      */
     function __construct(&$oConfig, &$oDb) 
     {
-        self::$MODULE = 'bx_notes';
+        $this->MODULE = 'bx_notes';
         parent::__construct($oConfig, $oDb);
     }
 }

+ 1 - 1
modules/boonex/notes/template/author.html

@@ -1,5 +1,5 @@
 
 <div class="bx-notes-author bx-def-unit">
-    <a href="__author_url__"><img class="bx-def-thumb bx-def-thumb-size" src="__author_thumb_url__" /></a><div class="bx-def-unit-info bx-def-thumb-size-max-height bx-def-padding-left"><a href="__author_url__">__author_title__</a><br /><span class="bx-def-font-grayed bx-def-font-small">__entry_posting_date__</span></div>
+    <a href="__author_url__"><img class="bx-def-thumb bx-def-thumb-size" src="__author_thumb_url__" /></a><div class="bx-def-unit-info bx-def-thumb-size-max-height bx-def-padding-left"><a href="__author_url__">__author_title__</a><br /><span class="bx-def-font-grayed bx-def-font-small">__author_desc__</span></div>
 </div>
 

+ 12 - 4
template/css/default.less

@@ -102,6 +102,12 @@
         .margin-left(0);
     }
 }
+.bx-def-margin-sec-right-auto {
+    .margin-left(@bx-margin-sec);
+    &:last-child {
+        .margin-left(0);
+    }
+}
 
 .bx-def-margin-thd {
     .margin(@bx-margin-thd);
@@ -389,6 +395,7 @@ h3,
 .bx-def-thumb-size {
     .width(@bx-size-thumb);
     .height(@bx-size-thumb);
+    .line-height(@bx-size-thumb);
 }
 .bx-def-thumb-size-max-height {
     .max-height(@bx-size-thumb);
@@ -414,6 +421,7 @@ h3,
 
 .bx-def-unit {
     position:relative;
+    white-space:nowrap;
 }
 .bx-def-unit .bx-def-unit-info,
 .bx-def-unit img {
@@ -432,10 +440,10 @@ h3,
     position:absolute;
     right:0;
     bottom:0;
-    .min-width(@bx-font-size-small + 3);
-    .height(@bx-font-size-small + 3);
-    .line-height(@bx-font-size-small + 5);
-    .radius(15px);
+    .min-width(@bx-font-size-small + 5);
+    .height(@bx-font-size-small + 5);
+    .line-height(@bx-font-size-small + 6);
+    .radius(@bx-font-size-small);
     .border (1px, solid, #fff);
     .font-size(@bx-font-size-small);
     text-align:center;

+ 1 - 1
template/scripts/BxBaseGrid.php

@@ -481,7 +481,7 @@ class BxBaseGrid extends BxDolGrid {
             return '';
         $sRet = '';
         foreach ($this->_aOptions[$sActionsType] as $sKey => $a) 
-{
+        {
             $sFunc = '_getAction' . $this->_genMethodName($sKey);
             if (!method_exists($this, $sFunc))
                 $sFunc = empty($a) ? '_getActionDivider' : '_getActionDefault';

+ 4 - 1
template/scripts/BxBaseMenuSubmenu.php

@@ -48,10 +48,13 @@ class BxBaseMenuSubmenu extends BxTemplMenu
         if (!$this->_sObjectSubmenu && $aMenuItemSelected['submenu_object'])
             $this->_sObjectSubmenu = $aMenuItemSelected['submenu_object'];
 
+        bx_import('BxDolPermalinks');
+        $oPermalinks = BxDolPermalinks::getInstance();
+
         $aVars = array (
             'object' => $this->_sObject,
             'title' => $aMenuItemSelected['title'],
-            'link' => $aMenuItemSelected['link'],
+            'link' => $oPermalinks->permalink($aMenuItemSelected['link']),
             'icon' => $aMenuItemSelected['icon'],
         );