Просмотр исходного кода

Ticket #3583 - Timeline: Dynamic browsing and Core changes.

AntonLV 4 лет назад
Родитель
Сommit
19d2045d3c

+ 8 - 0
modules/base/notifications/classes/BxBaseModNotificationsDb.php

@@ -190,6 +190,14 @@ class BxBaseModNotificationsDb extends BxBaseModGeneralDb
 
         if(!empty($aParams))
             switch($aParams['type']) {
+                case 'by_type':
+                    $aMethod['params'][1] = array(
+                        'type' => $aParams['value']
+                    );
+
+                    $sWhereClause = "AND `type`=:type";
+                    break;
+
                 case 'by_group_key_type':
                     $aMethod['name'] = 'getAllWithKey';
                     $aMethod['params'][1] = 'type';

+ 0 - 1
modules/boonex/russian/data/langs/bx_timeline/ru.xml

@@ -43,7 +43,6 @@
     <string name="_bx_timeline_option_enable_cache_item"><![CDATA[Включить кэш элемента]]></string>
     <string name="_bx_timeline_option_cache_item_engine"><![CDATA[Механизм кэширования элемента (отличный от FileHtml может потребовать дополнительную настройку сервера)]]></string>
     <string name="_bx_timeline_option_cache_item_lifetime"><![CDATA[Время жизни кэша элемента]]></string>
-    <string name="_bx_timeline_option_enable_cache_list"><![CDATA[Включить кэш хроники]]></string>
     <string name="_bx_timeline_option_enable_editor_toolbar"><![CDATA[Включить панель инструментов в форме создания сообщения]]></string>
     <string name="_bx_timeline_option_limit_attach_links"><![CDATA[Ограничить число присоединенных линок (0 - без ограничений)]]></string>
 

+ 2 - 14
modules/boonex/timeline/classes/BxTimelineConfig.php

@@ -24,8 +24,6 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
     protected $_bCacheItem;
     protected $_sCacheItemEngine;
     protected $_iCacheItemLifetime;
-    protected $_bCacheList;
-    protected $_aCacheListExceptions;
 
     protected $_bInfScroll;
     protected $_iInfScrollAutoPreloads;
@@ -214,6 +212,8 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
             'page_item_brief' => $this->_sName . '_item_brief',
 
             'menu_view' => $this->_sName . '_menu_view',
+            'menu_feeds' => $this->_sName . '_menu_feeds',
+            'menu_set_feeds' => $this->_sName . '_menu_feeds',
             'menu_item_manage' => $this->_sName . '_menu_item_manage',
             'menu_item_actions' => $this->_sName . '_menu_item_actions',
             'menu_item_actions_all' => $this->_sName . '_menu_item_actions_all',
@@ -353,8 +353,6 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
         $this->_bCacheItem = getParam($sOptionPrefix . 'enable_cache_item') == 'on';
         $this->_sCacheItemEngine = getParam($sOptionPrefix . 'cache_item_engine');
         $this->_iCacheItemLifetime = (int)getParam($sOptionPrefix . 'cache_item_lifetime');
-        $this->_bCacheList = getParam($sOptionPrefix . 'enable_cache_list') == 'on';
-        $this->_aCacheListExceptions = array(BX_TIMELINE_TYPE_HOT);
 
         $this->_aPerPage = array(
             'default' => (int)getParam($sOptionPrefix . 'events_per_page'),
@@ -519,16 +517,6 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
         return $this->_bCacheItem;
     }
 
-    public function isCacheList()
-    {
-        return $this->_bCacheList;
-    }
-
-    public function isCacheListException($sType)
-    {
-        return in_array($sType, $this->_aCacheListExceptions);
-    }
-
     public function getCacheItemEngine()
     {
         return $this->_sCacheItemEngine;

+ 65 - 75
modules/boonex/timeline/classes/BxTimelineDb.php

@@ -11,8 +11,6 @@
 
 class BxTimelineDb extends BxBaseModNotificationsDb
 {
-    protected $_sTableCache;
-
     protected $_sTableEvent2User;
     protected $_sTableRepostsTrack;
     protected $_sTableHotTrack;
@@ -29,8 +27,6 @@ class BxTimelineDb extends BxBaseModNotificationsDb
 
         $CNF = &$this->_oConfig->CNF;
 
-        $this->_sTableCache = $this->_sPrefix . 'cache';
-
         $this->_sTableEvent2User = $this->_sPrefix . 'events2users';
         $this->_sTableRepostsTrack = $this->_sPrefix . 'reposts_track';
         $this->_sTableHotTrack = $this->_sPrefix . 'hot_track';
@@ -465,77 +461,6 @@ class BxTimelineDb extends BxBaseModNotificationsDb
         return (int)$this->query("REPLACE INTO `" . $this->_sTableHotTrack . "` SET " . $this->arrayToSQL($aTrack)) > 0;
     }
 
-    public function insertCache($aParamsSet)
-    {
-        if(empty($aParamsSet))
-            return false;
-
-        $iRet = (int)$this->query("REPLACE INTO `{$this->_sTableCache}` SET " . $this->arrayToSQL($aParamsSet)) > 0;
-        $this->setReadOnlyMode(true);
-        return $iRet;
-    }
-
-    public function deleteCache($aParamsWhere)
-    {
-        if(empty($aParamsWhere))
-            return false;
-
-        return (int)$this->query("DELETE FROM `{$this->_sTableCache}` WHERE " . $this->arrayToSQL($aParamsWhere, ' AND ')) > 0;
-    }
-
-    public function clearCache()
-    {
-        return (int)$this->query("DELETE FROM `{$this->_sTableCache}` WHERE 1") > 0;
-    }
-
-    public function getCache($aParams)
-    {
-        $CNF = &$this->_oConfig->CNF;
-
-    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
-        
-        $sFieldsClause = '*';
-        $sWhereClause = $sLimitClause = '';
-
-        if(isset($aParams['start']) && !empty($aParams['per_page']))
-            $sLimitClause = $aParams['start'] . ", " . $aParams['per_page'];
-
-        switch($aParams['browse']) {
-            case 'list': // by type + owner profile (context) + viewer profile
-                $aMethod['name'] = 'getAllWithKey';
-                $aMethod['params'][1] = 'event_id';
-                $aMethod['params'][2] = array(
-                    'type' => $aParams['type'],
-                    'context_id' => $aParams['context_id'],
-                    'profile_id' => $aParams['profile_id']
-                );
-
-                //--- Apply custom check depending on Type
-                switch($aParams['type']) {
-                    case BX_BASE_MOD_NTFS_TYPE_PUBLIC:
-                        $aMethod['params'][2]['context_id'] = 0;
-                        break;
-
-                    case BX_TIMELINE_TYPE_CHANNELS:
-                    case BX_TIMELINE_TYPE_FEED:
-                    case BX_TIMELINE_TYPE_OWNER_AND_CONNECTIONS:
-                        $aMethod['params'][2]['context_id'] = $aParams['profile_id'];
-                        break;
-                }
-
-                $sWhereClause .= " AND `type`=:type AND `context_id`=:context_id  AND `profile_id`=:profile_id";
-                break;
-        }
-
-        $sLimitClause = $sLimitClause ? "LIMIT " . $sLimitClause : "";
-
-        $aMethod['params'][0] = "SELECT " . $sFieldsClause . " 
-        FROM `{$this->_sTableCache}` 
-        WHERE 1" . $sWhereClause . " ORDER BY `important` DESC, `date` DESC " . $sLimitClause;
-
-        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
-    }
-
     public function getEvents($aParams)
     {
         bx_alert($this->_oConfig->getName(), 'get_events_before', 0, 0, array(
@@ -976,6 +901,33 @@ class BxTimelineDb extends BxBaseModNotificationsDb
                 //--- Select Promoted posts.
                 $mixedWhereSubclause['p4'] = "`{$this->_sTable}`.`promoted` <> '0'";
                 break;
+
+            //--- Feed: Profile Connections to contexts from Selected module
+            default:
+                if(empty($aParams['owner_id']))
+                    break;
+
+                $mixedJoinClause = [];
+                $mixedWhereSubclause = [];
+
+                $oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('conn_subscriptions'));
+
+                //--- Join System posts received by following channels.
+                $aQueryParts = $oConnection->getConnectedContentAsSQLPartsExt($this->_sPrefix . 'events', 'owner_id', $aParams['owner_id']);
+                $aJoin1 = $aQueryParts['join'];
+
+                $mixedJoinClause['p1'] = "INNER JOIN `sys_profiles` AS `p` ON `" . $this->_sTable ."`.`owner_id`=`p`.`id` AND `p`.`type`='" . $aParams['type'] . "'";
+                $mixedJoinClause['p1'] .= " LEFT JOIN `" . $aJoin1['table'] . "` AS `" . $aJoin1['table_alias'] . "` ON " . $aJoin1['condition'];
+
+                $mixedWhereSubclause['p1'] = "NOT ISNULL(`" . $aJoin1['table_alias'] . "`.`content`)";
+
+                //--- Exclude Own (Direct) posts on timelines of following members.
+                //--- Note. Disabled for now.
+                //$mixedWhereSubclause['p1'] = $this->prepareAsString(" AND IF(`{$this->_sTable}`.`system`='0', `{$this->_sTable}`.`object_id` <> ?, 1)", $aParams['owner_id']);
+
+                //--- Select Promoted posts.
+                $mixedWhereSubclause['p2'] = "`" . $this->_sTable . "`.`promoted` <> '0'";
+                break;
         }
 
         $aAlertParams = $aParams;
@@ -1019,6 +971,44 @@ class BxTimelineDb extends BxBaseModNotificationsDb
 
         return array($mixedJoinClause, $mixedWhereClause);
     }
+
+    public function getMenuItemMaxOrder($sSetName)
+    {
+        return $this->getOne("SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`=:set_name LIMIT 1", [
+            'set_name' => $sSetName
+        ]);
+    }
+
+    public function getMenuItemId($sSetName, $sName)
+    {
+        return (int)$this->getOne("SELECT `id` FROM `sys_menu_items` WHERE `set_name`=:set_name AND `name`=:name LIMIT 1", [
+            'set_name' => $sSetName,
+            'name' => $sName
+        ]);
+    }
+
+    public function insertMenuItem($sSetName, $sModule, $sName, $sTitle, $iOrder)
+    {
+        return $this->query("INSERT INTO `sys_menu_items` SET " . $this->arrayToSQL([
+            'set_name' => $sSetName, 
+            'module' => $sModule, 
+            'name' => $sName, 
+            'title_system' => $sTitle,
+            'title' => $sTitle,
+            'link' => 'javascript:void(0)', 
+            'onclick' => "javascript:{js_object_view}.changeFeed(this, '" . $sModule . "')", 
+            'target' => '_self',
+            'order' => $iOrder
+        ]));
+    }
+    
+    public function deleteMenuItem($sSetName, $sName)
+    {
+        return $this->query("DELETE FROM `sys_menu_items` WHERE `set_name`=:set_name AND `name`=:name LIMIT 1", [
+            'set_name' => $sSetName,
+            'name' => $sName
+        ]);
+    }
 }
 
 /** @} */

+ 44 - 0
modules/boonex/timeline/classes/BxTimelineMenuFeeds.php

@@ -0,0 +1,44 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Timeline Timeline
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxTimelineMenuFeeds extends BxTemplMenuCustom
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_timeline';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct($aObject, $this->_oModule->_oTemplate);
+    }
+
+    public function setBrowseParams($aParams = [])
+    {
+        $aMarkers = array();
+        foreach($aParams as $sKey => $mixedValue)
+            if(!is_array($mixedValue))
+                $aMarkers[$sKey] = $mixedValue;
+
+        $this->addMarkers($aMarkers);
+        $this->addMarkers(array(
+            'js_object_view' => $this->_oModule->_oConfig->getJsObjectView($aParams)
+        ));
+    }
+
+    protected function _getMenuItemItemDivider($aItem)
+    {
+        return $this->_oModule->_oTemplate->parseHtmlByName('menu_item_divider.html', []);
+    }
+}
+
+/** @} */

+ 109 - 35
modules/boonex/timeline/classes/BxTimelineModule.php

@@ -25,6 +25,8 @@ bx_import('BxBaseModNotificationsModule');
  */
 define('BX_TIMELINE_SLTMODE_ABSOLUTE', 21);
 
+define('BX_TIMELINE_NAME_VIEWS_DB', 'views_db'); //--- Dynamic browsing feeds.
+
 define('BX_TIMELINE_TYPE_ITEM', 'view_item');
 define('BX_TIMELINE_TYPE_OWNER_AND_CONNECTIONS', 'owner_and_connections');
 define('BX_TIMELINE_TYPE_CHANNELS', 'channels'); //--- Followed channels only.
@@ -188,8 +190,6 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
         if(!$this->_oDb->updateEvent(array('pinned' => $aEvent['pinned']), array('id' => $iId)))
             return echoJson(array('code' => 3));
 
-        $this->_oDb->deleteCache(array('context_id' => $this->_iOwnerId)); //--- Delete cache for context
-
         echoJson(array(
             'code' => 0, 
             'id' => $iId, 
@@ -215,9 +215,6 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
     	if(!$this->_oDb->updateEvent(array('sticked' => $aEvent['sticked']), array('id' => $iId)))
             return echoJson(array('code' => 3));
 
-        $this->_oDb->deleteCache(array('context_id' => 0)); //--- Delete cache for Public feed
-        $this->_oDb->deleteCache(array('context_id' => $this->_iOwnerId)); //--- Delete cache for context
-
         bx_audit(
             $iId, 
             $this->getName(), 
@@ -249,9 +246,6 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
         if(!$this->_oDb->updateEvent(array('promoted' => $aEvent['promoted']), array('id' => $iId)))
             return echoJson(array('code' => 2));
 
-        $this->_oDb->deleteCache(array('context_id' => 0)); //--- Delete cache for Public feed
-        $this->_oDb->deleteCache(array('context_id' => $this->_iOwnerId)); //--- Delete cache for context
-
         bx_alert($this->_oConfig->getObject('alert'), $sAction . 'd', $iId, (int)$this->getUserId(), array(
             'owner_id' => $aEvent['owner_id'],
             'object_id' => $aEvent['object_id'],
@@ -291,9 +285,6 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
         if(!$this->getConnectionMuteObject()->addConnection($this->_iProfileId, $iAuthor))
             return echoJson(array('code' => 2));
 
-        $this->_oDb->deleteCache(array('context_id' => 0)); //--- Delete cache for Public feed
-        $this->_oDb->deleteCache(array('context_id' => $this->_iOwnerId)); //--- Delete cache for context
-
         bx_alert($this->_oConfig->getObject('alert'), 'muted', $iAuthor, $this->_iProfileId, array(
             'owner_id' => $aEvent['owner_id'],
             'object_id' => $aEvent['object_id'],
@@ -320,8 +311,6 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
         if(!$this->deleteEvent($aEvent))
             return echoJson(array('code' => 3));
 
-        $this->_oDb->deleteCache(array('event_id' => $iId));
-
         echoJson(array(
             'code' => 0, 
             'id' => $aEvent['id'], 
@@ -412,8 +401,8 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
     {
         $aParams = $this->_prepareParamsGet();
 
-        $sConten = $this->_oTemplate->getViewBlock($aParams);
-        if(empty($sConten))
+        $sContent = $this->_oTemplate->getViewBlock($aParams);
+        if(empty($sContent))
             return echoJson(array());
 
         if(!empty($aParams['type']))
@@ -421,10 +410,30 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
 
         echoJson(array(
             'code' => 0, 
-            'content' => $sConten,
+            'content' => $sContent,
         ));
     }
 
+    function actionGetViewFilters()
+    {
+        $aParams = $this->_prepareParamsGet();
+
+        $sContent = $this->_oTemplate->getViewFilters($aParams);
+        if(empty($sContent))
+            return echoJson([]);
+
+        echoJson([
+            'code' => 0,
+            'popup' => [
+                'html' => $sContent,
+                'options' => [
+                    'closeOnOuterClick' => true,
+                    'removeOnClose' => false,
+                ]
+            ],
+        ]);
+    }
+
     function actionGetPost()
     {
         $aParams = $this->_prepareParamsGet();
@@ -743,6 +752,44 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
         ));
     }
 
+    public function serviceFeedsMenuAdd($mixedModule = false)
+    {
+        $sSetName = $this->_oConfig->getObject('menu_set_feeds');
+
+        $iOrder = $this->_oDb->getMenuItemMaxOrder($sSetName);
+
+        $aModules = !empty($mixedModule) ? [$this->_oDb->getModuleByName($mixedModule)] : bx_srv('system', 'get_modules_by_type', ['context']);
+        foreach($aModules as $aModule) {
+            $sModuleName = $aModule['name'];
+            $sModuleUri = $aModule['uri'];
+            if($sModuleName == 'system' && $sModuleUri == 'system')
+                continue;
+
+            $iMenuItem = $this->_oDb->getMenuItemId($sSetName, $sModuleUri);
+            if(!empty($iMenuItem))
+                continue;
+
+            $sTitleKey = '_' . $sModuleName;
+            if(strcmp($sTitleKey, _t($sTitleKey)) == 0)
+                $sTitleKey = $aModule['title'];
+
+            $this->_oDb->insertMenuItem($sSetName, $sModuleName, $sModuleUri, $sTitleKey, ++$iOrder);
+        }
+
+        return true;
+    }
+
+    public function serviceFeedsMenuDelete($mixedModule = false)
+    {
+        $sSetName = $this->_oConfig->getObject('menu_set_feeds');
+
+        $aModules = !empty($mixedModule) ? [$this->_oDb->getModuleByName($mixedModule)] : bx_srv('system', 'get_modules_by_type', ['context']);
+        foreach($aModules as $aModule)
+            $this->_oDb->deleteMenuItem($sSetName, $aModule['uri']);
+
+        return true;
+    }
+
     /**
      * @page service Service Calls
      * @section bx_timeline Timeline
@@ -1633,7 +1680,7 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
 
         return $this->_serviceGetBlockViewByType(array(
             'view' => BX_TIMELINE_VIEW_TIMELINE, 
-            'type' => BX_TIMELINE_TYPE_OWNER_AND_CONNECTIONS, 
+            'type' => BX_TIMELINE_TYPE_FEED, 
             'owner_id' => $iProfileId, 
             'start' => $iStart, 
             'per_page' => $iPerPage, 
@@ -1674,7 +1721,7 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
 
         return $this->_serviceGetBlockViewByType(array(
             'view' => BX_TIMELINE_VIEW_OUTLINE, 
-            'type' => BX_TIMELINE_TYPE_OWNER_AND_CONNECTIONS,
+            'type' => BX_TIMELINE_TYPE_FEED,
             'owner_id' => $iProfileId, 
             'start' => $iStart, 
             'per_page' => $iPerPage, 
@@ -1708,6 +1755,50 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
     	return $this->_serviceGetBlockViewByType($aParams);
     }
 
+    public function serviceGetBlockMenuDb($aParams = array())
+    {
+        $aParams = $this->_prepareParams(array_merge($aParams, [
+            'name' => BX_TIMELINE_NAME_VIEWS_DB,
+            'view' => BX_TIMELINE_VIEW_TIMELINE,
+            'type' => BX_TIMELINE_TYPE_FEED,
+            'owner_id' => $this->getProfileId()
+        ]));
+
+        if(($sType = $this->_oConfig->getUserChoice('type')) !== false)
+            $aParams['type'] = $sType;
+
+        $sMenu = $this->_oConfig->getObject('menu_feeds');
+        $oMenu = BxDolMenu::getObjectInstance($sMenu);
+
+        $sSelectedModule = $this->getName();
+        $sSelectedName = $aParams['type'];
+        if(($aModule = $this->_oDb->getModuleByName($aParams['type']))) {
+            $sSelectedModule = $aModule['name'];
+            $sSelectedName = $aModule['uri'];
+        }
+
+        $oMenu->setSelected($sSelectedModule, $sSelectedName);
+        $oMenu->setBrowseParams($aParams);
+        return $oMenu->getCode();
+    }
+
+    public function serviceGetBlockViewsDb($aParams = [])
+    {
+        $aParams = $this->_prepareParams(array_merge($aParams, [
+            'name' => BX_TIMELINE_NAME_VIEWS_DB,
+            'view' => BX_TIMELINE_VIEW_TIMELINE,
+            'type' => BX_TIMELINE_TYPE_FEED,
+            'owner_id' => $this->getProfileId()
+        ]));
+
+        if(($sType = $this->_oConfig->getUserChoice('type')) !== false)
+            $aParams['type'] = $sType;
+
+        $this->_iOwnerId = $aParams['owner_id'];
+
+        return $this->_oTemplate->getViewsDbBlock($aParams);
+    }
+
     /**
      * @page service Service Calls
      * @section bx_timeline Timeline
@@ -2809,8 +2900,6 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
         if(!$this->deleteEvent($aEvent))
             return _t('_bx_timeline_txt_err_cannot_perform_action');
 
-        $this->_oDb->deleteCache(array('event_id' => $iContentId));
-
         return '';
     }
 
@@ -3177,7 +3266,6 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
             $this->_saveMedia($CNF['FIELD_FILE'], $iId, $aFileIds, $iUserId);
 
             $this->getCacheItemObject()->removeAllByPrefix($this->_oConfig->getPrefix('cache_item') . $iId);
-            $this->_oDb->deleteCache(array('event_id' => $iId));
 
             return array(
                 'id' => $iId
@@ -3810,10 +3898,6 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
             $iSenderId = $iObjectAuthorId = (int)$aEvent['object_id'];
         }
 
-        //--- Delete feed cached
-        $this->_oDb->deleteCache(array('context_id' => 0)); //--- Delete cache for Public feed
-        $this->_oDb->deleteCache(array('context_id' => $aEvent[$CNF['FIELD_OWNER_ID']])); //--- Delete cache for old context
-
         //--- Event -> Post/Defer for Alerts Engine ---//
         $sAction = ($aEvent[$CNF['FIELD_STATUS']] == BX_TIMELINE_STATUS_AWAITING ? 'defer' : 'post') . '_' . $sPostType;
         bx_alert($this->_oConfig->getObject('alert'), $sAction, $iContentId, $iSenderId, array(
@@ -3826,15 +3910,8 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
 
     public function onPublished($iContentId)
     {
-        $CNF = &$this->_oConfig->CNF;
-
-        $aEvent = $this->_oDb->getEvents(array('browse' => 'id', 'value' => $iContentId));
-
         //--- Clear Item cache
         $this->getCacheItemObject()->removeAllByPrefix($this->_oConfig->getPrefix('cache_item') . $iContentId);
-        
-        //--- Clear Feed cache
-        $this->_oDb->deleteCache(array('context_id' => $aEvent[$CNF['FIELD_OWNER_ID']]));
 
         $this->onPost($iContentId);
     }
@@ -3949,9 +4026,6 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
         //--- Delete associated meta.
         $oMetatags = BxDolMetatags::getObjectInstance($this->_oConfig->getObject('metatags'));
         $oMetatags->onDeleteContent($aEvent[$CNF['FIELD_ID']]);
-
-        //--- Delete feed cache.
-        $this->_oDb->deleteCache(array('event_id' => $aEvent[$CNF['FIELD_ID']]));
         
         //--- Delete item cache.
         $sCacheItemKey = $this->_oConfig->getCacheItemKey($aEvent[$CNF['FIELD_ID']]);

+ 33 - 23
modules/boonex/timeline/classes/BxTimelineResponse.php

@@ -104,24 +104,14 @@ class BxTimelineResponse extends BxBaseModNotificationsResponse
 
                 $this->_oModule->_oDb->updateEvent($aParamsSet, array('id' => $aEvent[$CNF['FIELD_ID']]));
 
-                //--- Delete feed cached
-                $this->_oModule->_oDb->deleteCache(array('context_id' => 0)); //--- Delete cache for Public feed
-                $this->_oModule->_oDb->deleteCache(array('context_id' => $aEvent[$CNF['FIELD_OWNER_ID']])); //--- Delete cache for old context
-                if(isset($aParamsSet['owner_id']))
-                    $this->_oModule->_oDb->deleteCache(array('context_id' => $aParamsSet['owner_id'])); //--- Delete cache for new context
-
                 //--- Delete item cache.
                 $oCacheItem = $this->_oModule->getCacheItemObject();
                 $oCacheItem->delData($this->_oModule->_oConfig->getCacheItemKey($aEvent['id']));
 
+                //--- Delete item cache for repost.
                 $aReposts = $this->_oModule->_oDb->getReposts($aEvent[$CNF['FIELD_ID']]);
-                foreach($aReposts as $aRepost) {
-                    //--- Delete cache for reposter context
-                    $this->_oModule->_oDb->deleteCache(array('context_id' => $aRepost['author_id']));
-
-                    //--- Delete item cache for repost.
+                foreach($aReposts as $aRepost)
                     $oCacheItem->delData($this->_oModule->_oConfig->getCacheItemKey($aRepost['event_id']));
-                }
                 break;
 
             case BX_BASE_MOD_NTFS_HANDLER_TYPE_DELETE:
@@ -130,15 +120,12 @@ class BxTimelineResponse extends BxBaseModNotificationsResponse
                     foreach($aEvents as $aEvent)
                         $this->_oModule->deleteEvent($aEvent);
 
-                    if(isset($oAlert->aExtras['delete_with_content']) && $oAlert->aExtras['delete_with_content']) {
-                        $aEvents = $this->_oModule->_oDb->getEvents(array('browse' => 'common_by_object', 'value' => $oAlert->iObject));
-                        foreach($aEvents as $aEvent)
-                            $this->_oModule->deleteEvent($aEvent);
-                    }
+                    if(!isset($oAlert->aExtras['delete_with_content']) || !$oAlert->aExtras['delete_with_content']) 
+                        break;
 
-                    //--- Delete cached
-                    $this->_oModule->_oDb->deleteCache(array('context_id' => $oAlert->iObject));
-                    $this->_oModule->_oDb->deleteCache(array('profile_id' => $oAlert->iObject));
+                    $aEvents = $this->_oModule->_oDb->getEvents(array('browse' => 'common_by_object', 'value' => $oAlert->iObject));
+                    foreach($aEvents as $aEvent)
+                        $this->_oModule->deleteEvent($aEvent);
                     break;
                 }
 
@@ -174,6 +161,32 @@ class BxTimelineResponse extends BxBaseModNotificationsResponse
         $this->_clearCache();
     }
 
+    protected function _processSystemEnable($oAlert)
+    {
+        $aModuleConfig = $oAlert->aExtras['config'];
+        if(empty($aModuleConfig) || !is_array($aModuleConfig))
+            return false;
+
+        $sName = $aModuleConfig['name'];
+        if(!bx_srv_ii('system', 'is_module_context', [$sName]))
+            return false;
+
+        return $this->_oModule->serviceFeedsMenuAdd($sName);
+    }
+
+    protected function _processSystemDisable($oAlert)
+    {
+        $aModuleConfig = $oAlert->aExtras['config'];
+        if(empty($aModuleConfig) || !is_array($aModuleConfig))
+            return false;
+
+        $sName = $aModuleConfig['name'];
+        if(!bx_srv_ii('system', 'is_module_context', [$sName]))
+            return false;
+
+        return $this->_oModule->serviceFeedsMenuDelete($sName);
+    }
+
     protected function _processAccountConfirm($oAlert)
     {
         $this->_clearCache();
@@ -208,9 +221,6 @@ class BxTimelineResponse extends BxBaseModNotificationsResponse
     {
         //--- Clear item cache.
         $this->_oModule->getCacheItemObject()->removeAllByPrefix($this->_oModule->_oConfig->getPrefix('cache_item'));
-
-        //--- Clear feed cache.
-        $this->_oModule->_oDb->clearCache();
     }
 
     protected function _processBxTimelineVideosMp4Transcoded($oAlert)

+ 109 - 107
modules/boonex/timeline/classes/BxTimelineTemplate.php

@@ -198,6 +198,110 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
         );
     }
 
+    public function getViewsDbBlock($aParams)
+    {
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+
+        $sJsObject = $this->_oConfig->getJsObjectView($aParams);
+        $sJsContent = $this->getJsCodeView([
+            'sObjName' => $sJsObject,
+            'sName' => $aParams['name'],
+            'sView' => $aParams['view'],
+            'sType' => $aParams['type'],
+            'sVideosAutoplay' => $this->_oConfig->getVideosAutoplay(),
+            'oRequestParams' => $aParams
+        ], [
+            'wrap' => true,
+            'mask_markers' => ['object' => $sJsObject]
+        ]);
+
+        return array(
+            'content' => $this->parseHtmlByName('block_views_db.html', array(
+                'style_prefix' => $sStylePrefix,
+                'html_id' => $this->_oConfig->getHtmlIdView('views', $aParams, array('with_type' => false)),
+                'html_id_content' => $this->_oConfig->getHtmlIdView('views_content', $aParams, array('with_type' => false)),
+                'content' => $this->getViewBlock(array_merge($aParams, ['name' => ''])),
+                'js_content' => $sJsContent
+            )),
+            'buttons' => [
+                ['title' => _t('_bx_timeline_txt_filters'), 'href' => 'javascript:void(0)', 'onclick' => 'javascript:' . $sJsObject . '.changeFeedFilters(this)']
+            ]
+        );
+    }
+
+    public function getViewFilters($aParams)
+    {
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+        $sJsObject = $this->_oConfig->getJsObjectView($aParams);
+
+        $aHandlers = $this->_oDb->getHandlers(['type' => 'by_type', 'value' => 'insert']);       
+
+        $aModules = [];
+        foreach($aHandlers as $aHandler) {
+            $sModule = $aHandler['alert_unit'];
+            if(isset($aModules[$sModule]))
+                continue;
+
+            $aModule = $this->_oDb->getModuleByName($sModule);
+            if(empty($aModule) || !is_array($aModule))
+                continue;
+
+            $sTitleKey = '_' . $sModule;
+            $sTitleValue = _t($sTitleKey);
+            if(strcmp($sTitleKey, $sTitleValue) == 0)
+                $sTitleValue = $aModule['title'];
+
+            $aModules[$sModule] = [
+                'key' => $aHandler['alert_unit'],
+                'value' => $sTitleValue
+            ];
+        }
+
+        uasort($aModules, function($aV1, $aV2) {
+            return strcmp($aV1['value'], $aV2['value']);
+        });
+
+        $aForm = [
+            'inputs' => [
+                'by_module' => [
+                    'name' => 'by_module',
+                    'type' => 'radio_set',
+                    'caption' => _t('_bx_timeline_form_filters_input_by_modules'),
+                    'values' => [
+                        ['key' => 'all', 'value' => _t('_bx_timeline_form_filters_input_by_modules_all')],
+                        ['key' => 'selected', 'value' => _t('_bx_timeline_form_filters_input_by_modules_selected')]
+                    ],
+                    'value' => 'all',
+                    'attrs' => ['onchange' => $sJsObject . '.onFilterByModuleChange(this)'],
+                    'dv_thd' => 1
+                ],
+                'modules' => [
+                    'name' => 'modules',
+                    'type' => 'checkbox_set',
+                    'values' => array_values($aModules),
+                    'tr_attrs' => ['class' => 'modules', 'style' => 'display:none']
+                ],
+                'apply' => [
+                    'name' => 'apply',
+                    'type' => 'button',
+                    'value' => _t('_bx_timeline_form_filters_input_do_apply'),
+                    'attrs' => ['onclick' => $sJsObject . '.onFilterApply(this)']
+                ]
+            ]
+        ];
+        $oForm = new BxTemplFormView($aForm);
+        
+
+        $sViewFiltersPopupId = $this->_oConfig->getHtmlIdView('filters_popup', $aParams);
+        $sViewFiltersPopupContent = $this->parseHtmlByName('block_view_filters.html', array(
+            'style_prefix' => $sStylePrefix,
+            'js_object' => $sJsObject,
+            'content' => $oForm->genRows()
+    	));
+
+    	return BxTemplFunctions::getInstance()->transBox($sViewFiltersPopupId, $sViewFiltersPopupContent, true);
+    }
+
     public function getViewBlock($aParams)
     {
         $oModule = $this->getModule();
@@ -254,7 +358,7 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
             'js_content' => &$sJsContent
         ));
 
-        return $sLiveUpdateCode . $this->parseHtmlByName('block_view.html', array(
+        return $this->parseHtmlByName('block_view.html', array(
             'style_prefix' => $this->_oConfig->getPrefix('style'),
             'html_id' => $this->_oConfig->getHtmlIdView('main', $aParams),
             'view' => $aParams['view'],
@@ -266,6 +370,7 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
             'load_more' =>  $sLoadMore,
             'show_more' => $this->_getShowMore($aParams),
             'view_image_popup' => $this->_getImagePopup($aParams),
+            'live_update_code' => $sLiveUpdateCode,
             'js_content' => $sJsContent
         ));
     }
@@ -486,16 +591,8 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
         $oPrivacy = BxDolPrivacy::getObjectInstance($this->_oConfig->getObject('privacy_view'));
         if($oPrivacy) {
             $oPrivacy->setTableFieldAuthor($this->_oConfig->isSystem($aEvent['type'], $aEvent['action']) ? 'owner_id' : 'object_id');
-            if(!$oPrivacy->check($iEventId)) {
-                if($this->_oConfig->isCacheList())
-                    $this->_oDb->deleteCache(array(
-                        'type' => $aBrowseParams['type'], 
-                        'profile_id' => bx_get_logged_profile_id(),
-                        'event_id' => $iEventId
-                    ));
-
+            if(!$oPrivacy->check($iEventId))
                 return '';
-            }
         }
 
         $aResult = $this->getDataCached($aEvent, $aBrowseParams);
@@ -524,9 +621,6 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
         if(isset($aEvent[$sKey]) && $aEvent[$sKey] !== CHECK_ACTION_RESULT_ALLOWED) 
             return '';
 
-        if($this->_oConfig->isCacheList())
-            $this->_cacheEvent(bx_get_logged_profile_id(), $aEvent, $aBrowseParams);
-
         $sType = !empty($aResult['content_type']) ? $aResult['content_type'] : BX_TIMELINE_PARSE_TYPE_DEFAULT;
         self::$_aMemoryCacheItems[$sMemoryCacheItemsKey] = $this->_getPost($sType, $aEvent, $aBrowseParams);
         self::$_aMemoryCacheItemsData[$sMemoryCacheItemsKey] = $aEvent;
@@ -555,8 +649,7 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
 
         //--- Before: Check for Next
         $aParamsDb['per_page'] += 1;
-
-        $aEvents = $this->_getPosts($aParamsDb);
+        $aEvents = $this->_oDb->getEvents($aParamsDb);
 
         //--- After: Check for Previous
         if($bPrevious) {
@@ -1440,97 +1533,6 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
         ));
     }
 
-    protected function _cacheEvent($iProfileId, &$aEvent, &$aParams)
-    {
-        $CNF = &$this->_oConfig->CNF;
-
-        $aParamsSet = array(
-            'type' => $aParams['type'],
-            'context_id' => is_array($aEvent[$CNF['FIELD_OWNER_ID']]) ? array_shift($aEvent[$CNF['FIELD_OWNER_ID']]) : $aEvent[$CNF['FIELD_OWNER_ID']],  
-            'profile_id' => $iProfileId, 
-            'event_id' => $aEvent[$CNF['FIELD_ID']], 
-            'date' => $aEvent[$CNF['FIELD_ADDED']]
-        );
-
-        //--- Process Context ID value.
-        if($aParams['type'] == BX_BASE_MOD_NTFS_TYPE_PUBLIC)
-            $aParamsSet['context_id'] = 0;
-        else if(in_array($aParams['type'], array(BX_TIMELINE_TYPE_FEED, BX_TIMELINE_TYPE_CHANNELS, BX_TIMELINE_TYPE_OWNER_AND_CONNECTIONS)))
-            $aParamsSet['context_id'] = $iProfileId;
-
-        //--- Process 'important' flag.
-        if($aParams['type'] == BX_BASE_MOD_NTFS_TYPE_OWNER && (int)$aEvent['pinned'] > 0) 
-            $aParamsSet['important'] = 1;
-        else if(in_array($aParams['type'], array(BX_BASE_MOD_NTFS_TYPE_PUBLIC, BX_BASE_MOD_NTFS_TYPE_CONNECTIONS, BX_TIMELINE_TYPE_FEED, BX_TIMELINE_TYPE_CHANNELS, BX_TIMELINE_TYPE_OWNER_AND_CONNECTIONS)) && (int)$aEvent['sticked'] > 0)
-            $aParamsSet['important'] = 1;
-
-        return $this->_oDb->insertCache($aParamsSet);
-    }
-
-    protected function _cacheEvents($aParams)
-    {
-        $CNF = &$this->_oConfig->CNF;
-
-        $iPerPage = (int)$aParams['per_page'];
-        $aParamsCopy = $aParams;
-
-        $aIds = array();
-        while(count($aIds) < $iPerPage) {
-            $aEvents = $this->_oDb->getEvents($aParamsCopy);
-            if(empty($aEvents))
-                break;
-
-            foreach($aEvents as $aEvent) {
-                if($this->getPost($aEvent, $aParamsCopy) == '')
-                    continue;
-
-                $aIds[] = $aEvent[$CNF['FIELD_ID']];
-                if(count($aIds) == $iPerPage)
-                    break 2;
-            }
-
-            $aParamsCopy['start'] += $iPerPage;
-        }
-
-        return $aIds;
-    }
-
-    protected function _getCachedEvents($iProfileId, &$aParams)
-    {
-        return $this->_oDb->getCache(array(
-            'browse' => $aParams['browse'], 
-            'type' => $aParams['type'], 
-            'context_id' => $aParams['owner_id'], 
-            'profile_id' => $iProfileId, 
-            'start' => $aParams['start'], 
-            'per_page' => $aParams['per_page']
-        ));
-    }
-
-    protected function _getPosts($aParams)
-    {
-        $CNF = &$this->_oConfig->CNF;
-
-        if(!$this->_oConfig->isCacheList() || $this->_oConfig->isCacheListException($aParams['type']))
-            return $this->_oDb->getEvents($aParams);
-
-        $iPerPage = (int)$aParams['per_page'];
-        $iProfileId = (int)bx_get_logged_profile_id(); 
-
-        /*
-         * Get cached data.
-         */
-        $aCache = $this->_getCachedEvents($iProfileId, $aParams);
-        if(!empty($aCache) && is_array($aCache) && count($aCache) == $iPerPage)
-            return $this->_oDb->getEvents(array('browse' => 'ids', 'type' => $aParams['type'], 'ids' => array_keys($aCache)));
-
-        /*
-         * Cache data.
-         */
-        $aIds = $this->_cacheEvents($aParams);
-        return $this->_oDb->getEvents(array('browse' => 'ids', 'type' => $aParams['type'], 'ids' => $aIds));
-    }
-
     protected function _getPost($sType, $aEvent, $aBrowseParams = array())
     {
         $CNF = &$this->_oConfig->CNF;
@@ -2793,7 +2795,7 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
                 return (int)$aEvent[$CNF['FIELD_ID']];
 
         $aParams['start'] += $aParams['per_page'];
-        $aEvents = $this->_getPosts($aParams);
+        $aEvents = $this->_oDb->getEvents($aParams);
         if(!empty($aEvents) && is_array($aEvents))
             return $this->_getFirst($aEvents, $aParams);
 

+ 10 - 2
modules/boonex/timeline/install/installer.php

@@ -21,9 +21,12 @@ class BxTimelineInstaller extends BxBaseModNotificationsInstaller
     public function enable($aParams)
     {
         $aResult = parent::enable($aParams);
-        if($aResult['result'])
+        if($aResult['result']) {
             $this->updateParamAET(true);
 
+            $this->updateFeedsMenu();
+        }
+
         return $aResult;
     }
 
@@ -32,7 +35,7 @@ class BxTimelineInstaller extends BxBaseModNotificationsInstaller
         $aResult = parent::disable($aParams);
         if($aResult['result'])
             $this->updateParamAET(false);
-        
+
         return $aResult;
     }
 
@@ -58,6 +61,11 @@ class BxTimelineInstaller extends BxBaseModNotificationsInstaller
 
         return setParam($sAetParam, $sAetParamValue);
     }
+
+    protected function updateFeedsMenu()
+    {
+        return bx_srv_ii($this->_aConfig['name'], 'feeds_menu_add');
+    }
 }
 
 /** @} */

+ 16 - 2
modules/boonex/timeline/install/langs/en.xml

@@ -43,7 +43,6 @@
     <string name="_bx_timeline_option_enable_cache_item"><![CDATA[Enable item cache]]></string>
     <string name="_bx_timeline_option_cache_item_engine"><![CDATA[Item cache engine (other than File option may require custom server setup)]]></string>
     <string name="_bx_timeline_option_cache_item_lifetime"><![CDATA[Item cache lifetime]]></string>
-    <string name="_bx_timeline_option_enable_cache_list"><![CDATA[Enable feed cache]]></string>
     <string name="_bx_timeline_option_enable_editor_toolbar"><![CDATA[Enable post form editor toolbar]]></string>
     <string name="_bx_timeline_option_limit_attach_links"><![CDATA[Limit number of attached links (0 - no limit)]]></string>
 
@@ -109,6 +108,11 @@
     <string name="_bx_timeline_form_repost_to_input_sys_do_cancel"><![CDATA[Cancel]]></string>
     <string name="_bx_timeline_form_repost_to_input_do_cancel"><![CDATA[Cancel]]></string>
 
+    <string name="_bx_timeline_form_filters_input_by_modules"><![CDATA[Content:]]></string>
+    <string name="_bx_timeline_form_filters_input_by_modules_all"><![CDATA[All]]></string>
+    <string name="_bx_timeline_form_filters_input_by_modules_selected"><![CDATA[Selected]]></string>
+    <string name="_bx_timeline_form_filters_input_do_apply"><![CDATA[Apply]]></string>
+
     <string name="_bx_timeline_privacy_view"><![CDATA[View event]]></string>
 
     <string name="_bx_timeline_acl_action_post"><![CDATA[Post]]></string>
@@ -168,6 +172,10 @@
     <string name="_bx_timeline_page_block_title_view_hot"><![CDATA[Hot Feed]]></string>
     <string name="_bx_timeline_page_block_title_system_view_hot_outline"><![CDATA[Hot Feed (Outline)]]></string>
     <string name="_bx_timeline_page_block_title_view_hot_outline"><![CDATA[Hot Feed]]></string>
+    <string name="_bx_timeline_page_block_title_system_menu_db"><![CDATA[Dynamic Browsing: Menu]]></string>
+    <string name="_bx_timeline_page_block_title_menu_db"><![CDATA[Feeds]]></string>
+    <string name="_bx_timeline_page_block_title_system_views_db"><![CDATA[Dynamic Browsing: Views]]></string>
+    <string name="_bx_timeline_page_block_title_views_db"><![CDATA[Feed]]></string>
     <string name="_bx_timeline_page_block_title_browse_cmts"><![CDATA[Feeds' Comments]]></string>
 
     <string name="_bx_timeline_page_title_sys_manage"><![CDATA[Manage]]></string>
@@ -193,6 +201,10 @@
     <string name="_bx_timeline_menu_item_title_system_hot"><![CDATA[Hot]]></string>
     <string name="_bx_timeline_menu_item_title_hot"><![CDATA[Hot]]></string>
 
+    <string name="_bx_timeline_menu_title_feeds"><![CDATA[Feeds]]></string>
+    <string name="_bx_timeline_menu_set_title_feeds"><![CDATA[Feeds]]></string>
+    <string name="_bx_timeline_menu_item_title_system_divider"><![CDATA[Divider]]></string>
+
     <string name="_bx_timeline_menu_item_view_all"><![CDATA[All posts]]></string>
     <string name="_bx_timeline_menu_item_view_owner"><![CDATA[Posts by {0}]]></string>
     <string name="_bx_timeline_menu_item_view_other"><![CDATA[Posts by others]]></string>
@@ -266,7 +278,7 @@
     <string name="_bx_timeline_menu_item_title_system_add_file_simple"><![CDATA[Add File (Simple)]]></string>
     <string name="_bx_timeline_menu_item_title_system_add_file_html5"><![CDATA[Add File (HTML5)]]></string>
 
-  <string name="_bx_timeline_menu_item_title_add_video"><![CDATA[Add Video]]></string>
+    <string name="_bx_timeline_menu_item_title_add_video"><![CDATA[Add Video]]></string>
     <string name="_bx_timeline_menu_item_title_system_add_video_record"><![CDATA[Record Video]]></string>
     <string name="_bx_timeline_menu_item_title_add_video_record"><![CDATA[Record Video]]></string>
     <string name="_bx_timeline_menu_item_title_system_timeline"><![CDATA[Timeline]]></string>
@@ -279,6 +291,7 @@
     <string name="_bx_timeline_menu_item_title_system_manage_my_timeline"><![CDATA[Timeline]]></string>
     <string name="_bx_timeline_menu_item_title_manage_my_timeline"><![CDATA[Timeline]]></string>
 
+    <!-- Grids -->
     <string name="_bx_timeline_grid_column_title_adm_active"><![CDATA[Active]]></string>
     <string name="_bx_timeline_grid_column_title_adm_description"><![CDATA[Event]]></string>
     <string name="_bx_timeline_grid_column_title_adm_added"><![CDATA[Added]]></string>
@@ -344,6 +357,7 @@
     <string name="_bx_timeline_txt_some_text_here"><![CDATA[Share your thoughts, location, photos or video]]></string>
     <string name="_bx_timeline_txt_show"><![CDATA[Show]]></string>
     <string name="_bx_timeline_txt_new_content"><![CDATA[New content]]></string>
+    <string name="_bx_timeline_txt_filters"><![CDATA[Filters]]></string>
 
     <string name="_bx_timeline_txt_do_repost"><![CDATA[Repost]]></string>
     <string name="_bx_timeline_txt_reposted"><![CDATA[Reposted {0}'s {1}.]]></string>

+ 1 - 1
modules/boonex/timeline/install/sql/disable.sql

@@ -11,7 +11,7 @@ DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_timeline' OR `object` IN('bx
 -- MENU
 DELETE FROM `sys_objects_menu` WHERE `module` = 'bx_timeline';
 DELETE FROM `sys_menu_sets` WHERE `module` = 'bx_timeline';
-DELETE FROM `sys_menu_items` WHERE `module` = 'bx_timeline' OR `set_name` IN('bx_timeline_menu_view', 'bx_timeline_menu_item_share', 'bx_timeline_menu_item_manage', 'bx_timeline_menu_item_actions', 'bx_timeline_menu_item_actions', 'bx_timeline_menu_item_counters', 'bx_timeline_menu_item_meta', 'bx_timeline_menu_post_attachments');
+DELETE FROM `sys_menu_items` WHERE `module` = 'bx_timeline' OR `set_name` IN('bx_timeline_menu_view', 'bx_timeline_menu_feeds', 'bx_timeline_menu_item_share', 'bx_timeline_menu_item_manage', 'bx_timeline_menu_item_actions', 'bx_timeline_menu_item_actions', 'bx_timeline_menu_item_counters', 'bx_timeline_menu_item_meta', 'bx_timeline_menu_post_attachments');
 
 
 -- SETTINGS

+ 23 - 4
modules/boonex/timeline/install/sql/enable.sql

@@ -85,13 +85,18 @@ SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = '' A
 INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `tabs`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
 ('', 0, 'bx_timeline', '_bx_timeline_page_block_title_system_views_timeline', '_bx_timeline_page_block_title_views_timeline', 11, 1, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:24:"get_block_views_timeline";}', 0, 1, 1, @iPBOrderHome + 1),
 ('', 0, 'bx_timeline', '_bx_timeline_page_block_title_system_views_outline', '_bx_timeline_page_block_title_views_outline', 11, 1, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:23:"get_block_views_outline";}', 0, 1, 1, @iPBOrderHome + 2),
+
 ('', 0, 'bx_timeline', '_bx_timeline_page_block_title_system_view_home', '_bx_timeline_page_block_title_view_home', 0, 0, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:19:"get_block_view_home";}', 0, 1, 1, @iBlockOrder + 3),
 ('', 0, 'bx_timeline', '_bx_timeline_page_block_title_system_view_home_outline', '_bx_timeline_page_block_title_view_home_outline', 0, 0, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:27:"get_block_view_home_outline";}', 0, 1, 1, @iBlockOrder + 4),
+
 ('', 0, 'bx_timeline', '_bx_timeline_page_block_title_system_view_account', '_bx_timeline_page_block_title_view_account', 0, 0, 2147483644, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:22:"get_block_view_account";}', 0, 1, 1, @iBlockOrder + 5),
-('', 0, 'bx_timeline', '_bx_timeline_page_block_title_system_view_account_outline', '_bx_timeline_page_block_title_view_account_outline', 0, 0, 2147483644, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:30:"get_block_view_account_outline";}', 0, 1, 1, @iBlockOrder + 6);
+('', 0, 'bx_timeline', '_bx_timeline_page_block_title_system_view_account_outline', '_bx_timeline_page_block_title_view_account_outline', 0, 0, 2147483644, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:30:"get_block_view_account_outline";}', 0, 1, 1, @iBlockOrder + 6),
 
+('', 0, 'bx_timeline', '_bx_timeline_page_block_title_system_menu_db', '_bx_timeline_page_block_title_menu_db', 11, 0, 2147483644, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:17:"get_block_menu_db";}', 0, 1, 1, @iBlockOrder + 7),
+('', 0, 'bx_timeline', '_bx_timeline_page_block_title_system_views_db', '_bx_timeline_page_block_title_views_db', 11, 0, 2147483644, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:18:"get_block_views_db";}', 0, 1, 1, @iBlockOrder + 8);
 
--- MENU: Feeds
+
+-- MENU: View
 INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
 ('bx_timeline_menu_view', '_bx_timeline_menu_title_view', 'bx_timeline_menu_view', 'bx_timeline', 15, 0, 1, 'BxTimelineMenuView', 'modules/boonex/timeline/classes/BxTimelineMenuView.php');
 
@@ -104,6 +109,19 @@ INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `titl
 ('bx_timeline_menu_view', 'bx_timeline', 'channels', '_bx_timeline_menu_item_title_system_channels', '_bx_timeline_menu_item_title_channels', 'javascript:void(0)', 'javascript:{js_object_view}.changeView(this, ''channels'')', '_self', '', '', 2147483647, 0, 0, 3),
 ('bx_timeline_menu_view', 'bx_timeline', 'hot', '_bx_timeline_menu_item_title_system_hot', '_bx_timeline_menu_item_title_hot', 'javascript:void(0)', 'javascript:{js_object_view}.changeView(this, ''hot'')', '_self', '', '', 2147483647, 1, 0, 4);
 
+-- MENU: Feeds
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_timeline_menu_feeds', '_bx_timeline_menu_title_feeds', 'bx_timeline_menu_feeds', 'bx_timeline', 20, 0, 1, 'BxTimelineMenuFeeds', 'modules/boonex/timeline/classes/BxTimelineMenuFeeds.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_timeline_menu_feeds', 'bx_timeline', '_bx_timeline_menu_set_title_feeds', 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_timeline_menu_feeds', 'bx_timeline', 'feed', '_bx_timeline_menu_item_title_system_feed', '_bx_timeline_menu_item_title_feed', 'javascript:void(0)', 'javascript:{js_object_view}.changeFeed(this, ''feed'')', '_self', '', '', 2147483647, 1, 0, 1),
+('bx_timeline_menu_feeds', 'bx_timeline', 'public', '_bx_timeline_menu_item_title_system_public', '_bx_timeline_menu_item_title_public', 'javascript:void(0)', 'javascript:{js_object_view}.changeFeed(this, ''public'')', '_self', '', '', 2147483647, 1, 0, 2),
+('bx_timeline_menu_feeds', 'bx_timeline', 'hot', '_bx_timeline_menu_item_title_system_hot', '_bx_timeline_menu_item_title_hot', 'javascript:void(0)', 'javascript:{js_object_view}.changeFeed(this, ''hot'')', '_self', '', '', 2147483647, 1, 0, 3),
+('bx_timeline_menu_feeds', 'bx_timeline', 'divider', '_bx_timeline_menu_item_title_system_divider', '', '', '', '', '', '', 2147483647, 1, 1, 4);
+
 -- MENU: Item Share (Repost, Send to Friend, etc)
 INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
 ('bx_timeline_menu_item_share', '_bx_timeline_menu_title_item_share', 'bx_timeline_menu_item_share', 'bx_timeline', 6, 0, 1, 'BxTimelineMenuItemShare', 'modules/boonex/timeline/classes/BxTimelineMenuItemShare.php');
@@ -303,8 +321,7 @@ SET @iCategId = LAST_INSERT_ID();
 INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
 ('bx_timeline_enable_cache_item', 'on', @iCategId, '_bx_timeline_option_enable_cache_item', 'checkbox', '', '', '', '', 1),
 ('bx_timeline_cache_item_engine', 'File', @iCategId, '_bx_timeline_option_cache_item_engine', 'select', '', '', '', 'File,Memcache,APC,XCache', 2),
-('bx_timeline_cache_item_lifetime', '604800', @iCategId, '_bx_timeline_option_cache_item_lifetime', 'digit', '', '', '', '', 3),
-('bx_timeline_enable_cache_list', 'on', @iCategId, '_bx_timeline_option_enable_cache_list', 'checkbox', '', '', '', '', 4);
+('bx_timeline_cache_item_lifetime', '604800', @iCategId, '_bx_timeline_option_cache_item_lifetime', 'digit', '', '', '', '', 3);
 
 -- Category: Post form
 INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
@@ -432,6 +449,8 @@ SET @iHandler := LAST_INSERT_ID();
 
 INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
 ('system', 'clear_cache', @iHandler),
+('system', 'enable', @iHandler),
+('system', 'disable', @iHandler),
 
 ('account', 'confirm', @iHandler),
 ('account', 'unconfirm', @iHandler),

+ 0 - 10
modules/boonex/timeline/install/sql/install.sql

@@ -61,16 +61,6 @@ INSERT INTO `bx_timeline_handlers`(`group`, `type`, `alert_unit`, `alert_action`
 ('comment', 'update', 'comment', 'edited', ''),
 ('comment', 'delete', 'comment', 'deleted', '');
 
-CREATE TABLE IF NOT EXISTS `bx_timeline_cache` (
-  `type` varchar(32) NOT NULL default '',
-  `context_id` int(11) NOT NULL default '0',
-  `profile_id` int(11) NOT NULL default '0',
-  `event_id` int(11) NOT NULL default '0',
-  `date` int(11) NOT NULL default '0',
-  `important` tinyint(4) NOT NULL default '0',
-  PRIMARY KEY `item` (`type`, `context_id`, `profile_id`, `event_id`)
-);
-
 -- TABLE: mute
 CREATE TABLE IF NOT EXISTS `bx_timeline_mute` (
   `id` int(11) NOT NULL AUTO_INCREMENT,

+ 1 - 1
modules/boonex/timeline/install/sql/uninstall.sql

@@ -1,6 +1,6 @@
 SET @sName = 'bx_timeline';
 
-DROP TABLE IF EXISTS `bx_timeline_events`, `bx_timeline_handlers`, `bx_timeline_cache`;
+DROP TABLE IF EXISTS `bx_timeline_events`, `bx_timeline_handlers`;
 
 DROP TABLE IF EXISTS `bx_timeline_mute`;
 

+ 1 - 1
modules/boonex/timeline/js/post.js

@@ -336,7 +336,7 @@ BxTimelinePost.prototype._onGetPost = function(oData)
     var fContinue = function(oData) {
         if(!$.trim(oData.item).length) 
             return;
-
+console.log(oData); return;
         var aTypes = Array.isArray(oData.type) ? oData.type : new Array(oData.type);
         aTypes.forEach(function(sType) {
             oData['type'] = sType;

+ 137 - 0
modules/boonex/timeline/js/view.js

@@ -42,6 +42,8 @@ function BxTimelineView(oOptions) {
 
     this._bLiveUpdatePaused = false;
 
+    this._oFiltersPopupOptions = {};
+
     if(typeof window.glBxTimelineVapPlayers === 'undefined')
         window.glBxTimelineVapPlayers = [];
 
@@ -399,6 +401,141 @@ BxTimelineView.prototype.reload = function(oSource)
     });
 };
 
+BxTimelineView.prototype.changeFeed = function(oLink, sType, oRequestParams)
+{
+    var $this = this;
+    var oViews = $(this._getHtmlId('views_content', this._oRequestParams, {with_type: false})); 
+    var oViewActive = oViews.children(':visible');
+
+    if(this._sVideosAutoplay != 'off')
+        this.pauseVideos(oViewActive);
+
+    var sFilters = this._getHtmlId('filters_popup', jQuery.extend({}, this._oRequestParams, {name: ''}));
+    if($(sFilters).length)
+        $(sFilters).remove();
+
+    this._oRequestParams.type = sType;
+    oRequestParams = jQuery.extend({}, this._oRequestParams, {
+        name: '',
+        start: 0
+    }, oRequestParams);
+
+    var oData = this._getDefaultData(oLink);
+    oData = jQuery.extend({}, oData, oRequestParams);
+
+    var sView = $this._getHtmlId('main', oRequestParams);
+
+    var oTab = $(oLink);
+    var sTabActive = 'bx-menu-tab-active';
+    oTab.parents('ul:first').find('li.' + sTabActive).removeClass(sTabActive);
+    oTab.parents('li:first').addClass(sTabActive);
+
+    this.loadingIn(oLink, true);
+
+    jQuery.get (
+        this._sActionsUrl + 'get_view',
+        oData,
+        function(oResponse) {
+            if(oLink)
+                $this.loadingIn(oLink, false);
+
+            if(!oResponse.content)
+                return;
+
+            oViewActive.hide('fast', function() {
+                oViews.html('').append(oResponse.content).find(sView).bxProcessHtml();
+            });
+        },
+        'json'
+    );
+};
+
+BxTimelineView.prototype.changeFeedFilters = function(oLink, oRequestParams)
+{
+    var $this = this;
+
+    oRequestParams = jQuery.extend({}, this._oRequestParams, {
+        name: '',
+        start: 0
+    }, oRequestParams);
+
+    var sFilters = this._getHtmlId('filters_popup', oRequestParams);
+    if($(sFilters).length)
+        return $(sFilters).dolPopup(this._oFiltersPopupOptions);
+
+    var oData = this._getDefaultData(oLink);
+    if(oRequestParams != undefined)
+        oData = jQuery.extend({}, oData, oRequestParams);
+
+    this.loadingIn(oLink, true);
+
+    jQuery.get (
+        this._sActionsUrl + 'get_view_filters',
+        oData,
+        function(oResponse) {
+            if(oLink)
+                $this.loadingIn(oLink, false);
+
+            if(oResponse && oResponse.popup != undefined) {
+                $this._oFiltersPopupOptions = jQuery.extend({}, oResponse.popup.options, {
+                    pointer: { 
+                        el: $(oLink),
+                        align: 'right'
+                    }
+                });
+
+                oResponse.popup.options = $this._oFiltersPopupOptions;
+            }
+
+            processJsonData(oResponse);
+        },
+        'json'
+    );
+};
+
+BxTimelineView.prototype.onFilterByModuleChange = function(oSource)
+{
+    var oModules = $(oSource).parents('.bx-form-element-wrapper:first').siblings('.modules');
+    oModules.find("input[name='modules[]']:checked").removeAttr('checked');
+    oModules.bx_anim($(oSource).val() == 'selected' ? 'show' : 'hide');
+};
+
+BxTimelineView.prototype.onFilterApply = function(oSource)
+{
+    var $this = this;
+    var sView = this._getHtmlId('main', this._oRequestParams); 
+    var oFilters = $(oSource).parents('.bx-tl-view-filters:first');
+
+    this._oRequestParams.start = 0;
+    this._oRequestParams.modules = [];
+    if(oFilters.find("input[name='by_module']:checked").val() == 'selected')
+        oFilters.find("input[name='modules[]']:checked").each(function() {
+            $this._oRequestParams.modules.push($(this).val());
+        });
+
+    var oData = this._getDefaultData(oSource);
+
+    this.loadingIn(oSource, true);
+
+    jQuery.get (
+        this._sActionsUrl + 'get_view',
+        oData,
+        function(oResponse) {
+            if(oSource)
+                $this.loadingIn(oSource, false);
+
+            if(!oResponse.content)
+                return;
+
+            $('.bx-popup-applied:visible').dolPopupHide();
+
+            $(sView).replaceWith(oResponse.content);
+            $(sView).bxProcessHtml();
+        },
+        'json'
+    );
+};
+
 BxTimelineView.prototype.changeView = function(oLink, sType, oRequestParams)
 {
     var $this = this;

+ 1 - 0
modules/boonex/timeline/template/block_view.html

@@ -11,5 +11,6 @@
     </div>
     __show_more__
     __view_image_popup__
+    __live_update_code__
     __js_content__
 </div>

+ 3 - 0
modules/boonex/timeline/template/block_view_filters.html

@@ -0,0 +1,3 @@
+<div class="__style_prefix__-view-filters">
+    <div class="__style_prefix__-view-filters-cnt bx-def-padding">__content__</div>
+</div>

+ 4 - 0
modules/boonex/timeline/template/block_views_db.html

@@ -0,0 +1,4 @@
+<div id="__html_id__" class="__style_prefix__-views __style_prefix__-views-db">
+    <div id="__html_id_content__" class="__style_prefix__-v-cnt">__content__</div>
+</div>
+__js_content__

+ 25 - 0
modules/boonex/timeline/template/css/view.css

@@ -1,5 +1,17 @@
 /*--- General section ---*/
 
+/*--- Dynamic Browsing: Menu ---*/
+.bx-menu-object-bx_timeline_menu_feeds .bx-menu-item > span {
+    display: block;
+    padding: 0;
+}
+.bx-menu-object-bx_timeline_menu_feeds .bx-menu-item > span > a {
+    display: block;
+    padding: 0.25rem 0.5rem;
+}
+.bx-menu-object-bx_timeline_menu_feeds .bx-menu-tab-active {
+    background-color: rgba(235, 240, 245, 0.8);
+}
 
 /*--- Views Block Style ---*/
 .bx-tl-views {
@@ -67,6 +79,19 @@ div.bx-tl-items-wrapper {
 	position: relative;
 }
 
+/*--- Filters Style ---*/
+div.bx-tl-view-filters {
+    min-width: 14rem;
+    max-width: 20rem;
+}
+div.bx-tl-view-filters div.bx-form-section-wrapper:first-child {
+    margin-top: 0;
+}
+div.bx-tl-view-filters div.bx-form-section-content {
+    padding-top: 0;
+    padding-bottom: 0;
+}
+
 /*--- Back Style ---*/
 
 

+ 1 - 0
modules/boonex/timeline/template/menu_item_divider.html

@@ -0,0 +1 @@
+<div class="bx-def-hr bx-def-margin-sec-topbottom"></div>

+ 11 - 0
template/css/forms.css

@@ -237,6 +237,17 @@
     height:auto;
 }
 
+.bx-form-value .bx-form-input-radio_set,
+.bx-form-value .bx-form-input-checkbox_set {
+    line-height: 1.25;
+}
+
+.bx-form-value .bx-form-input-radio_set label,
+.bx-form-value .bx-form-input-checkbox_set label {
+    padding-left: 0.25rem;
+}
+
+
 .bx-form-input-textarea {
     padding:0.5rem;
     height:150px;

+ 2 - 1
template/scripts/BxBaseFormView.php

@@ -1815,11 +1815,12 @@ BLAH;
 
         // generate options
         $sDivider = isset($aInput['dv']) ? $aInput['dv'] : $this->_sDivider;
+        $iDividerThreshold = !empty($aInput['dv_thd']) ? (int)$aInput['dv_thd'] : 3;
 
         $sOptions = '';
 
         if (isset($aInput['values']) && is_array($aInput['values'])) {
-            if (count($aInput['values']) > 3 && $sDivider == $this->_sDivider)
+            if (count($aInput['values']) > $iDividerThreshold && $sDivider == $this->_sDivider)
                 $sDivider = $this->_sDividerAlt;
             
             // generate complex input using simple standard inputs

+ 45 - 3
template/scripts/BxBaseServices.php

@@ -398,6 +398,48 @@ class BxBaseServices extends BxDol implements iBxDolProfileService
         return !empty($aModule) && is_array($aModule) && (int)$aModule['enabled'] != 0;
     }
 
+    /**
+     * Checks whether a module is a 'Content' module or not.
+     * 
+     * @param string $mixedModule - module name or an instance of Module class.
+     * @return boolean result of operation.
+     */
+    public function serviceIsModuleContent($mixedModule)
+    {
+        if(is_string($mixedModule))
+            $mixedModule = BxDolModule::getInstance($mixedModule);
+
+        return $mixedModule instanceof BxDolModule && $mixedModule instanceof iBxDolContentInfoService && !($mixedModule instanceof iBxDolProfileService);
+    }
+
+    /**
+     * Checks whether a module is a 'Context' module or not.
+     * 
+     * @param string $mixedModule - module name or an instance of Module class.
+     * @return boolean result of operation.
+     */
+    public function serviceIsModuleContext($mixedModule)
+    {
+        if(is_string($mixedModule))
+            $mixedModule = BxDolModule::getInstance($mixedModule);
+
+        return $mixedModule instanceof BxDolModule && $mixedModule instanceof iBxDolProfileService;
+    }
+
+    /**
+     * Checks whether a module is a 'Profile' module or not.
+     * 
+     * @param string $mixedModule - module name or an instance of Module class.
+     * @return boolean result of operation.
+     */
+    public function serviceIsModuleProfile($mixedModule)
+    {
+        if(is_string($mixedModule))
+            $mixedModule = BxDolModule::getInstance($mixedModule);
+
+        return $mixedModule instanceof BxDolModule && $mixedModule instanceof iBxDolProfileService && $mixedModule->serviceActAsProfile();
+    }
+
     /**
      * Get modules by type. Available types are 'content', 'context', 'profile'.
      * 
@@ -414,13 +456,13 @@ class BxBaseServices extends BxDol implements iBxDolProfileService
             if(!$oModule)
                 continue;
 
-            if($sType == 'content' && (!($oModule instanceof iBxDolContentInfoService) || $oModule instanceof iBxDolProfileService))
+            if($sType == 'content' && !$this->serviceIsModuleContent($oModule))
                 continue;
 
-            if($sType == 'context' && !($oModule instanceof iBxDolProfileService))
+            if($sType == 'context' && !$this->serviceIsModuleContext($oModule))
                 continue;
 
-            if($sType == 'profile' && (!($oModule instanceof iBxDolProfileService) || !$oModule->serviceActAsProfile()))
+            if($sType == 'profile' && !$this->serviceIsModuleProfile($oModule))
                 continue;
 
             $aResults[] = $aModule;