AntonLV 9 лет назад
Родитель
Сommit
dee57bf8ea
51 измененных файлов с 6965 добавлено и 76 удалено
  1. 0 7
      modules/boonex/albums/updates/9.0.2_9.0.3/install/sql/install.sql
  2. 1 9
      modules/boonex/convos/updates/9.0.2_9.0.3/install/sql/install.sql
  3. 0 8
      modules/boonex/events/updates/9.0.1_9.0.2/install/sql/install.sql
  4. 1 8
      modules/boonex/forum/updates/9.0.1_9.0.2/install/sql/install.sql
  5. 0 8
      modules/boonex/groups/updates/9.0.2_9.0.3/install/sql/install.sql
  6. 0 7
      modules/boonex/market/updates/9.0.3_9.0.4/install/sql/install.sql
  7. 1 9
      modules/boonex/organizations/updates/9.0.2_9.0.3/install/sql/install.sql
  8. 1 9
      modules/boonex/persons/updates/9.0.2_9.0.3/install/sql/install.sql
  9. 0 8
      modules/boonex/posts/updates/9.0.2_9.0.3/install/sql/install.sql
  10. 2 2
      modules/boonex/timeline/install/config.php
  11. 0 1
      modules/boonex/timeline/install/sql/enable.sql
  12. 59 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/install/config.php
  13. 84 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/install/installer.php
  14. 56 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/install/langs/en.xml
  15. 104 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/install/sql/enable.sql
  16. 20 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/install/sql/install.sql
  17. 276 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineConfig.php
  18. 469 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineDb.php
  19. 142 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineMenuItemActions.php
  20. 83 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineMenuItemManage.php
  21. 123 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineMenuItemShare.php
  22. 1355 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineModule.php
  23. 66 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineSearchResult.php
  24. 1202 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineTemplate.php
  25. 134 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/config.php
  26. 63 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/installer.php
  27. 167 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/langs/en.xml
  28. 60 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/sql/disable.sql
  29. 245 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/sql/enable.sql
  30. 336 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/sql/install.sql
  31. 49 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/sql/uninstall.sql
  32. 249 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/js/main.js
  33. 257 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/js/post.js
  34. 86 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/js/repost.js
  35. 384 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/js/view.js
  36. 18 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/attach_link_item.html
  37. 9 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/block_item.html
  38. 12 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/block_view.html
  39. 76 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/css/post.css
  40. 48 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/css/repost.css
  41. 246 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/css/view-media-desktop.css
  42. 19 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/css/view-media-tablet.css
  43. 301 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/css/view.css
  44. 3 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/divider.html
  45. 41 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/item_outline.html
  46. 45 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/item_timeline.html
  47. 9 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/repost_by_list.html
  48. 1 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/repost_counter.html
  49. 7 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/repost_element_block.html
  50. 47 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/type_post.html
  51. 8 0
      modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/type_repost.html

+ 0 - 7
modules/boonex/albums/updates/9.0.2_9.0.3/install/sql/install.sql

@@ -1,15 +1,8 @@
-SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
-
 -- TABLE
 ALTER TABLE `bx_albums_files` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
 ALTER TABLE `bx_albums_photos_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
 
 
--- STORAGES & TRANSCODERS
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_albums_files';
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_albums_photos_resized';
-
-
 -- VIEWS
 UPDATE `sys_objects_view` SET `trigger_field_author`='author' WHERE `name`='bx_albums_media';
 

+ 1 - 9
modules/boonex/convos/updates/9.0.2_9.0.3/install/sql/install.sql

@@ -1,11 +1,3 @@
-SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
-
-
 -- TABLE
 ALTER TABLE `bx_convos_files` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
-ALTER TABLE `bx_convos_photos_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
-
-
--- STORAGES & TRANSCODERS
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_convos_files';
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_convos_photos_resized';
+ALTER TABLE `bx_convos_photos_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;

+ 0 - 8
modules/boonex/events/updates/9.0.1_9.0.2/install/sql/install.sql

@@ -1,16 +1,8 @@
-SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
-
-
 -- TABLE
 ALTER TABLE `bx_events_pics` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
 ALTER TABLE `bx_events_pics_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
 
 
--- STORAGES & TRANSCODERS
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_events_pics';
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_events_pics_resized';
-
-
 -- FORMS
 DELETE FROM `sys_form_displays` WHERE `display_name`='bx_event_invite';
 INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 

+ 1 - 8
modules/boonex/forum/updates/9.0.1_9.0.2/install/sql/install.sql

@@ -1,13 +1,6 @@
 SET @sName = 'bx_forum';
-SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
 
 
 -- TABLE
 ALTER TABLE `bx_forum_files` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
-ALTER TABLE `bx_forum_photos_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
-
-
--- STORAGES & TRANSCODERS
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_forum_files';
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_forum_files_cmts';
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_forum_photos_resized';
+ALTER TABLE `bx_forum_photos_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;

+ 0 - 8
modules/boonex/groups/updates/9.0.2_9.0.3/install/sql/install.sql

@@ -1,16 +1,8 @@
-SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
-
-
 -- TABLE
 ALTER TABLE `bx_groups_pics` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
 ALTER TABLE `bx_groups_pics_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
 
 
--- STORAGES & TRANSCODERS
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_groups_pics';
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_groups_pics_resized';
-
-
 -- FORMS
 DELETE FROM `sys_form_displays` WHERE `display_name` IN ('bx_group_invite');
 INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 

+ 0 - 7
modules/boonex/market/updates/9.0.3_9.0.4/install/sql/install.sql

@@ -1,6 +1,3 @@
-SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
-
-
 -- TABLE
 ALTER TABLE `bx_market_files` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
 ALTER TABLE `bx_market_photos` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
@@ -8,10 +5,6 @@ ALTER TABLE `bx_market_photos_resized` CHANGE `remote_id` `remote_id` VARCHAR(12
 
 
 -- STORAGES & TRANSCODERS
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_market_files';
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_market_photos';
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_market_photos_resized';
-
 DELETE FROM `sys_objects_transcoder` WHERE `object` IN ('bx_market_icon', 'bx_market_thumb');
 INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`) VALUES 
 ('bx_market_icon', 'bx_market_photos_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_market_photos";}', 'no', '1', '2592000', '0'),

+ 1 - 9
modules/boonex/organizations/updates/9.0.2_9.0.3/install/sql/install.sql

@@ -1,11 +1,3 @@
-SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
-
-
 -- TABLE
 ALTER TABLE `bx_organizations_pics` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
-ALTER TABLE `bx_organizations_pics_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
-
-
--- STORAGES & TRANSCODERS
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_organizations_pics';
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_organizations_pics_resized';
+ALTER TABLE `bx_organizations_pics_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;

+ 1 - 9
modules/boonex/persons/updates/9.0.2_9.0.3/install/sql/install.sql

@@ -1,11 +1,3 @@
-SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
-
-
 -- TABLE
 ALTER TABLE `bx_persons_pictures` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
-ALTER TABLE `bx_persons_pictures_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
-
-
--- STORAGES & TRANSCODERS
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_persons_pictures';
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_persons_pictures_resized';
+ALTER TABLE `bx_persons_pictures_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;

+ 0 - 8
modules/boonex/posts/updates/9.0.2_9.0.3/install/sql/install.sql

@@ -1,16 +1,8 @@
-SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
-
-
 -- TABLE
 ALTER TABLE `bx_posts_files` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
 ALTER TABLE `bx_posts_photos_resized` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
 
 
--- STORAGES & TRANSCODERS
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_posts_files';
-UPDATE `sys_objects_storage` SET `engine`=@sStorageEngine WHERE `object`='bx_posts_photos_resized';
-
-
 -- VIEWS
 UPDATE `sys_objects_view` SET `trigger_field_author`='author' WHERE `name`='bx_posts';
 

+ 2 - 2
modules/boonex/timeline/install/config.php

@@ -17,12 +17,12 @@ $aConfig = array(
     'name' => 'bx_timeline',
     'title' => 'Timeline',
     'note' => 'Timeline module.',
-    'version' => '9.0.3.DEV',
+    'version' => '9.0.3',
     'vendor' => 'BoonEx',
 	'help_url' => 'http://feed.boonex.com/?section={module_name}',
 
     'compatible_with' => array(
-        '9.0.x'
+        '9.0.0-B4'
     ),
 
     /**

+ 0 - 1
modules/boonex/timeline/install/sql/enable.sql

@@ -74,7 +74,6 @@ INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES
 ('bx_timeline_menu_item_actions', 'bx_timeline', '_bx_timeline_menu_set_title_item_actions', 0);
 
 INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
-('bx_timeline_menu_item_actions', 'bx_timeline', 'item-view', '_bx_timeline_menu_item_title_system_item_view', '', 'javascript:void(0)', '', '', '', '', '', 0, 2147483647, 1, 0, 0, 0),
 ('bx_timeline_menu_item_actions', 'bx_timeline', 'item-comment', '_bx_timeline_menu_item_title_system_item_comment', '_bx_timeline_menu_item_title_item_comment', 'javascript:void(0)', 'javascript:{comment_onclick}', '_self', 'comment', 'a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:27:"get_menu_item_addon_comment";s:6:"params";a:3:{i:0;s:16:"{comment_system}";i:1;s:16:"{comment_object}";i:2;s:6:"{view}";}}', '', 0, 2147483647, 1, 0, 1, 1),
 ('bx_timeline_menu_item_actions', 'bx_timeline', 'item-vote', '_bx_timeline_menu_item_title_system_item_vote', '', 'javascript:void(0)', '', '', '', '', '', 0, 2147483647, 1, 0, 0, 2),
 ('bx_timeline_menu_item_actions', 'bx_timeline', 'item-share', '_bx_timeline_menu_item_title_system_item_share', '', 'javascript:void(0)', 'bx_menu_popup(''bx_timeline_menu_item_share'', this, {''id'':''bx_timeline_menu_item_share_{content_id}''}, {content_id:{content_id}});', '', 'share-alt', '', 'bx_timeline_menu_item_share', 1, 2147483647, 1, 0, 0, 3),

+ 59 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/install/config.php

@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Timeline',
+    'version_from' => '9.0.2',
+	'version_to' => '9.0.3',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '9.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/timeline/updates/update_9.0.2_9.0.3/',
+	'home_uri' => 'timeline_update_902_903',
+
+	'module_dir' => 'boonex/timeline/',
+	'module_uri' => 'timeline',
+
+    'db_prefix' => 'bx_timeline_',
+    'class_prefix' => 'BxTimeline',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+		'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+		'clear_db_cache' => 1,
+    ),
+
+	/**
+     * Category for language keys.
+     */
+    'language_category' => 'Timeline',
+
+	/**
+     * Files Section
+     */
+    'delete_files' => array(
+		'js/share.js',
+		'template/css/share.css',
+		'template/item.html',
+		'template/share_by_list.html',
+		'template/share_counter.html',
+		'template/share_element_block.html',
+		'template/type_share.html',
+	),
+);

+ 84 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/install/installer.php

@@ -0,0 +1,84 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxTimelineUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+	{
+        parent::__construct($aConfig);
+    }
+
+	public function actionExecuteSql($sOperation)
+    {
+    	if($sOperation == 'install') {
+			if(!$this->oDb->isFieldExists('bx_timeline_events', 'views'))
+        		$this->oDb->query("ALTER TABLE `bx_timeline_events` ADD `views` int(11) unsigned NOT NULL default '0' AFTER `description`");
+
+			if($this->oDb->isFieldExists('bx_timeline_events', 'shares'))
+        		$this->oDb->query("ALTER TABLE `bx_timeline_events` CHANGE `shares` `reposts` INT( 11 ) UNSIGNED NOT NULL DEFAULT '0'");
+
+			if($this->isTableExists('bx_timeline_shares_track') && !$this->isTableExists('bx_timeline_reposts_track'))
+				$this->oDb->query("RENAME TABLE `bx_timeline_shares_track` TO `bx_timeline_reposts_track`");
+
+			$bRepostsTrack = $this->isTableExists('bx_timeline_reposts_track');
+			if($bRepostsTrack && $this->oDb->isFieldExists('bx_timeline_reposts_track', 'shared_id'))
+        		$this->oDb->query("ALTER TABLE `bx_timeline_reposts_track` CHANGE `shared_id` `reposted_id` INT( 11 ) NOT NULL DEFAULT '0'");
+
+			if($bRepostsTrack && $this->oDb->isIndexExists('bx_timeline_reposts_track', 'share'))
+				$this->oDb->query("ALTER TABLE `bx_timeline_reposts_track` DROP INDEX `share`");
+
+			if($bRepostsTrack && !$this->oDb->isIndexExists('bx_timeline_reposts_track', 'repost'))
+				$this->oDb->query("ALTER TABLE `bx_timeline_reposts_track` ADD INDEX `repost` (`reposted_id` , `author_nip`)");
+		}
+
+    	return parent::actionExecuteSql($sOperation);
+    }
+
+	public function update($aParams)
+    {
+		$aResult = parent::update($aParams);
+		if(!$aResult['result'])
+			return $aResult;
+
+		$aModule = $this->oDb->getModuleByUri($this->_aConfig['module_uri']);
+		if(!empty($aModule) && is_array($aModule) && (int)$aModule['enabled'] == 1)
+			$this->updateParamAET(true);
+
+		return $aResult;
+	}
+
+	protected function isTableExists($sTable)
+    {
+        $aTableNames = $this->oDb->listTables();
+        foreach($aTableNames as $iKey => $sTableName)
+            $aTableNames[$iKey] = strtoupper($sTableName);
+
+        return in_array(strtoupper($sTable), $aTableNames);
+    }
+
+	protected function updateParamAET($bAdd)
+    {
+        $sAetDivider = ',';
+        $sAetName = 'bx_timeline_send';
+
+        $sAetParam = 'sys_email_attachable_email_templates';
+        $sAetParamValue = getParam($sAetParam);
+
+        if($bAdd)
+            $sAetParamValue = trim($sAetParamValue . $sAetDivider . $sAetName, $sAetDivider);
+        else {
+            $aAet = explode($sAetDivider, $sAetParamValue);
+
+            $mixedKey = array_search($sAetName, $aAet);
+            if($mixedKey !== false) {
+                unset($aAet[$mixedKey]);
+                $sAetParamValue = implode($sAetDivider, $aAet);
+            }
+        }
+
+        return setParam($sAetParam, $sAetParamValue);
+    }
+}

+ 56 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/install/langs/en.xml

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_timeline_acl_action_repost"><![CDATA[Repost]]></string_add>
+	<string_add name="_bx_timeline_acl_action_send"><![CDATA[Send]]></string_add>
+	<string_add name="_bx_timeline_page_title_sys_view_home"><![CDATA[Home page Timeline]]></string_add>
+	<string_add name="_bx_timeline_page_title_view_home"><![CDATA[Timeline]]></string_add>
+	<string_add name="_bx_timeline_page_block_title_view_outline"><![CDATA[Outline]]></string_add>
+	<string_add name="_bx_timeline_page_block_title_post_profile"><![CDATA[Post to Timeline]]></string_add>
+	<string_add name="_bx_timeline_page_block_title_view_profile"><![CDATA[Timeline]]></string_add>
+	<string_add name="_bx_timeline_page_block_title_view_profile_outline"><![CDATA[Outline]]></string_add>
+	<string_add name="_bx_timeline_page_block_title_view_account_outline"><![CDATA[Subscriptions Outline]]></string_add>
+	<string_add name="_bx_timeline_page_block_title_post_home"><![CDATA[Post to Timeline]]></string_add>
+	<string_add name="_bx_timeline_page_block_title_view_home_outline"><![CDATA[Outline]]></string_add>
+	<string_add name="_bx_timeline_menu_title_item_share"><![CDATA[Share Item]]></string_add>
+	<string_add name="_bx_timeline_menu_set_title_item_share"><![CDATA[Share Item]]></string_add>
+	<string_add name="_bx_timeline_menu_item_title_system_item_repost"><![CDATA[Repost]]></string_add>
+	<string_add name="_bx_timeline_menu_item_title_item_repost"><![CDATA[Repost]]></string_add>
+	<string_add name="_bx_timeline_menu_item_title_system_item_send"><![CDATA[Send]]></string_add>
+	<string_add name="_bx_timeline_menu_item_title_item_send"><![CDATA[Send to Friend]]></string_add>
+	<string_add name="_bx_timeline_menu_item_title_system_item_view"><![CDATA[View]]></string_add>
+	<string_add name="_bx_timeline_alert_module_timeline_common_repost"><![CDATA[Timeline (repost)]]></string_add>
+	<string_add name="_bx_timeline_txt_added_sample"><![CDATA[added {0}]]></string_add>
+	<string_add name="_bx_timeline_txt_user_reposted_sample"><![CDATA[{0} reposted {1}'s {2}]]></string_add>
+	<string_add name="_bx_timeline_txt_sample_with_article"><![CDATA[a post]]></string_add>
+	<string_add name="_bx_timeline_txt_today"><![CDATA[Today]]></string_add>
+	<string_add name="_bx_timeline_txt_do_repost"><![CDATA[Repost]]></string_add>
+	<string_add name="_bx_timeline_txt_reposted"><![CDATA[Reposted {0}'s {1}.]]></string_add>
+	<string_add name="_bx_timeline_txt_reposted_by"><![CDATA[Reposted by]]></string_add>
+	<string_add name="_bx_timeline_txt_err_cannot_repost"><![CDATA[Cannot repost. Please report.]]></string_add>
+	<string_add name="_bx_timeline_txt_err_already_reposted"><![CDATA[You already reposted the item.]]></string_add>
+	<string_add name="_bx_timeline_txt_msg_success_repost"><![CDATA[The item was successfully reposted.]]></string_add>
+	<string_add name="_bx_timeline_txt_object_reposted"><![CDATA[<a class="bx-ntfs-content-profile" href="{owner_link}">{owner_name}</a> reposted a {entry_sample} <a href="{entry_url}">{entry_caption}</a>]]></string_add>
+	<string_add name="_bx_timeline_et_txt_name_send"><![CDATA[Send to Friend.]]></string_add>
+	<string_add name="_bx_timeline_et_txt_subject_send"><![CDATA[It may be interesting for you.]]></string_add>
+	<string_add name="_bx_timeline_et_txt_body_send"><![CDATA[
+<p>Hello.</p>
+<p>Take a look at <a href="{ViewLink}">this post</a>, it may be interesting for you.</p>]]></string_add>
+
+	<string_upd name="_bx_timeline_page_title_sys_view"><![CDATA[Profile Timeline]]></string_upd>
+	<string_upd name="_bx_timeline_page_block_title_view_home"><![CDATA[Timeline]]></string_upd>
+	<string_upd name="_bx_timeline_menu_item_title_system_item_share"><![CDATA[Share]]></string_upd>
+
+	<string_del name="_bx_timeline_acl_action_share"><![CDATA[Repost]]></string_del>
+	<string_del name="_bx_timeline_page_block_title_post_profile_persons"><![CDATA[Post to Timeline]]></string_del>
+	<string_del name="_bx_timeline_page_block_title_post_profile_organizations"><![CDATA[Post to Timeline]]></string_del>
+	<string_del name="_bx_timeline_page_block_title_view_profile_persons"><![CDATA[Timeline]]></string_del>
+	<string_del name="_bx_timeline_page_block_title_view_profile_organizations"><![CDATA[Timeline]]></string_del>
+	<string_del name="_bx_timeline_alert_module_timeline_common_share"><![CDATA[Timeline (repost)]]></string_del>
+	<string_del name="_bx_timeline_txt_user_shared_sample"><![CDATA[{0} reposted {1}'s {2}]]></string_del>
+	<string_del name="_bx_timeline_txt_do_share"><![CDATA[Repost]]></string_del>
+	<string_del name="_bx_timeline_txt_shared"><![CDATA[Reposted {0}'s {1}.]]></string_del>
+	<string_del name="_bx_timeline_txt_shared_by"><![CDATA[Reposted by]]></string_del>
+	<string_del name="_bx_timeline_txt_err_cannot_share"><![CDATA[Cannot repost. Please report.]]></string_del>
+	<string_del name="_bx_timeline_txt_err_already_shared"><![CDATA[You already reposted the item.]]></string_del>
+	<string_del name="_bx_timeline_txt_msg_success_share"><![CDATA[]]></string_del>
+</resources>

+ 104 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/install/sql/enable.sql

@@ -0,0 +1,104 @@
+-- PAGE
+DELETE FROM `sys_objects_page` WHERE `object`='bx_timeline_view_home';
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_timeline_view_home', '_bx_timeline_page_title_sys_view_home', '_bx_timeline_page_title_view_home', 'bx_timeline', 5, 2147483647, 1, 'timeline-view-home', 'page.php?i=timeline-view-home', '', '', '', 0, 1, 0, '', '');
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_timeline_view' AND `title` IN ('_bx_timeline_page_block_title_view_outline');
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_timeline_view', 1, 'bx_timeline', '_bx_timeline_page_block_title_view_outline', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:22:"get_block_view_outline";}', 0, 0, 3);
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_timeline_view_home' AND `title` IN ('_bx_timeline_page_block_title_post_home', '_bx_timeline_page_block_title_view_home', '_bx_timeline_page_block_title_view_home_outline');
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_timeline_view_home', 1, 'bx_timeline', '_bx_timeline_page_block_title_post_home', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:19:"get_block_post_home";}', 0, 0, 1),
+('bx_timeline_view_home', 1, 'bx_timeline', '_bx_timeline_page_block_title_view_home', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:19:"get_block_view_home";}', 0, 0, 2),
+('bx_timeline_view_home', 1, 'bx_timeline', '_bx_timeline_page_block_title_view_home_outline', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:27:"get_block_view_home_outline";}', 0, 0, 3);
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='sys_dashboard' AND `title` IN ('_bx_timeline_page_block_title_view_account_outline');
+SET @iPBCellDashboard = 1;
+SET @iPBOrderDashboard = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_pages_blocks` WHERE `object` = 'sys_dashboard' AND `cell_id` = @iPBCellDashboard LIMIT 1);
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('sys_dashboard', @iPBCellDashboard, 'bx_timeline', '_bx_timeline_page_block_title_view_account_outline', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:30:"get_block_view_account_outline";}', 0, 1, @iPBOrderDashboard + 1);
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='sys_home' AND `title` IN ('_bx_timeline_page_block_title_post_home', '_bx_timeline_page_block_title_view_home_outline');
+SET @iPBCellHome = 1;
+SET @iPBOrderHome = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_pages_blocks` WHERE `object` = 'sys_home' AND `cell_id` = @iPBCellHome ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('sys_home', @iPBCellHome, 'bx_timeline', '_bx_timeline_page_block_title_post_home', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:19:"get_block_post_home";}', 0, 1, @iPBOrderHome + 1),
+('sys_home', @iPBCellHome, 'bx_timeline', '_bx_timeline_page_block_title_view_home_outline', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:27:"get_block_view_home_outline";}', 0, 1, @iPBOrderHome + 2);
+
+
+UPDATE `sys_pages_blocks` SET `title`='_bx_timeline_page_block_title_post_profile' WHERE `title`='_bx_timeline_page_block_title_post_profile_persons';
+UPDATE `sys_pages_blocks` SET `title`='_bx_timeline_page_block_title_view_profile' WHERE `title`='_bx_timeline_page_block_title_view_profile_persons';
+
+SET @iPBCellProfile = 2;
+SET @iPBCellGroup = 4;
+
+DELETE FROM `sys_pages_blocks` WHERE `title` IN ('_bx_timeline_page_block_title_view_profile_outline');
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_timeline', '_bx_timeline_page_block_title_view_profile_outline', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:30:"get_block_view_profile_outline";s:6:"params";a:1:{i:0;s:6:"{type}";}}', 0, 0, 0),
+('trigger_page_group_view_entry', @iPBCellGroup, 'bx_timeline', '_bx_timeline_page_block_title_view_profile_outline', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:22:"get_block_view_profile_outline";s:6:"params";a:1:{i:0;s:6:"{type}";}}', 0, 0, 0);
+
+
+-- MENU
+DELETE FROM `sys_objects_menu` WHERE `object`='bx_timeline_menu_item_share';
+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');
+
+DELETE FROM `sys_menu_sets` WHERE `set_name`='bx_timeline_menu_item_share';
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_timeline_menu_item_share', 'bx_timeline', '_bx_timeline_menu_set_title_item_share', 0);
+
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_timeline_menu_item_share';
+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_item_share', 'bx_timeline', 'item-repost', '_bx_timeline_menu_item_title_system_item_repost', '_bx_timeline_menu_item_title_item_repost', 'javascript:void(0)', 'javascript:{js_onclick_repost}', '_self', 'repeat', '', 2147483647, 1, 0, 1),
+('bx_timeline_menu_item_share', 'bx_timeline', 'item-send', '_bx_timeline_menu_item_title_system_item_send', '_bx_timeline_menu_item_title_item_send', 'page.php?i=start-convo&et={et_send}', '', '_self', 'envelope', '', 2147483647, 1, 0, 2);
+
+UPDATE `sys_menu_items` SET `onclick`='javascript:{js_object_view}.pinPost(this, {content_id}, 1)' WHERE `set_name`='bx_timeline_menu_item_manage' AND `name`='item-pin';
+UPDATE `sys_menu_items` SET `onclick`='javascript:{js_object_view}.pinPost(this, {content_id}, 0)' WHERE `set_name`='bx_timeline_menu_item_manage' AND `name`='item-unpin';
+
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_timeline_menu_item_actions' AND `name` IN ('item-view');
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_timeline_menu_item_actions', 'bx_timeline', 'item-view', '_bx_timeline_menu_item_title_system_item_view', '', 'javascript:void(0)', '', '', '', '', '', 0, 2147483647, 1, 0, 0, 0);
+
+UPDATE `sys_menu_items` SET `addon`='a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:27:"get_menu_item_addon_comment";s:6:"params";a:3:{i:0;s:16:"{comment_system}";i:1;s:16:"{comment_object}";i:2;s:6:"{view}";}}' WHERE `set_name`='bx_timeline_menu_item_actions' AND `name`='item-comment';
+UPDATE `sys_menu_items` SET `onclick`='bx_menu_popup(''bx_timeline_menu_item_share'', this, {''id'':''bx_timeline_menu_item_share_{content_id}''}, {content_id:{content_id}});', `icon`='share-alt', `submenu_object`='bx_timeline_menu_item_share', `submenu_popup`='1' WHERE `set_name`='bx_timeline_menu_item_actions' AND `name`='item-share';
+
+
+-- ACL
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+UPDATE `sys_acl_actions` SET `Name`='repost', `Title`='_bx_timeline_acl_action_repost' WHERE `Module`='bx_timeline' AND `Name`='share';
+
+SET @iIdActionSend = (SELECT `ID` FROM `sys_acl_actions` WHERE `Module`='bx_timeline' AND `Name`='send' LIMIT 1);
+DELETE FROM `sys_acl_actions` WHERE `ID`=@iIdActionSend;
+DELETE FROM `sys_acl_matrix` WHERE `IDAction`=@iIdActionSend;
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_timeline', 'send', NULL, '_bx_timeline_acl_action_send', '', 1, 3);
+SET @iIdActionSend = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+(@iStandard, @iIdActionSend),
+(@iModerator, @iIdActionSend),
+(@iAdministrator, @iIdActionSend),
+(@iPremium, @iIdActionSend);
+
+
+-- VIEWS
+DELETE FROM `sys_objects_view` WHERE `name`='bx_timeline';
+INSERT INTO `sys_objects_view` (`name`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_timeline', 'bx_timeline_views_track', '86400', '1', 'bx_timeline_events', 'id', 'object_id', 'views', '', '');
+
+
+-- EMAIL TEMPLATES
+DELETE FROM `sys_email_templates` WHERE `Name`='bx_timeline_send';
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES 
+('bx_timeline', '_bx_timeline_et_txt_name_send', 'bx_timeline_send', '_bx_timeline_et_txt_subject_send', '_bx_timeline_et_txt_body_send');

+ 20 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/install/sql/install.sql

@@ -0,0 +1,20 @@
+SET @sName = 'bx_timeline';
+
+
+-- TABLES
+UPDATE `bx_timeline_events` SET `type`='timeline_common_repost' WHERE `type`='timeline_common_share';
+
+UPDATE `bx_timeline_handlers` SET `group`='common_repost', `alert_unit`='timeline_common_repost' WHERE `group`='common_share' AND `alert_unit`='timeline_common_share';
+
+ALTER TABLE `bx_timeline_photos` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
+ALTER TABLE `bx_timeline_photos_processed` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
+ALTER TABLE `bx_timeline_videos` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
+ALTER TABLE `bx_timeline_videos_processed` CHANGE `remote_id` `remote_id` VARCHAR(128) NOT NULL;
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_views_track` (
+  `object_id` int(11) NOT NULL default '0',
+  `viewer_id` int(11) NOT NULL default '0',
+  `viewer_nip` int(11) unsigned NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;

+ 276 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineConfig.php

@@ -0,0 +1,276 @@
+<?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
+ *
+ * @{
+ */
+
+bx_import('BxDolPrivacy');
+
+class BxTimelineConfig extends BxBaseModNotificationsConfig
+{
+    protected $_bAllowDelete;
+
+    protected $_iRssLength;
+    protected $_iCharsDisplayMax;
+
+    protected $_sStorageObject;
+    protected $_sTranscoderObjectPreview;
+    protected $_sTranscoderObjectView;
+    protected $_aPhotoUploaders;
+    protected $_aVideoUploaders;
+
+    protected $_sMenuItemManage;
+    protected $_sMenuItemActions;
+
+    protected $_aRepostDefaults;
+
+    protected $_iTimelineVisibilityThreshold;
+    protected $_aPregPatterns;
+
+    /**
+     * Constructor
+     */
+    public function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->CNF = array (
+            'ICON' => 'clock-o col-green1',
+        
+	        // database fields
+        	'FIELD_ID' => 'id',
+        	'FIELD_LOCATION_PREFIX' => 'location',
+
+        	// objects
+            'OBJECT_COMMENTS' => $this->_sName,
+        	'OBJECT_VIEWS' => $this->_sName,
+        	'OBJECT_VOTES' => $this->_sName,
+        	'OBJECT_REPORTS' => $this->_sName,
+
+        	// some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_timeline_txt_sample',
+        		'txt_sample_single_ext' => '_bx_timeline_txt_sample_ext',
+            	'txt_sample_comment_single' => '_bx_timeline_txt_sample_comment_single',
+        		'txt_sample_vote_single' => '_bx_timeline_txt_sample_vote_single',
+            ),
+        );
+
+        $this->_aPrefixes = array(
+        	'style' => 'bx-tl',
+        	'language' => '_bx_timeline',
+        	'option' => 'bx_timeline_',
+        	'common_post' => 'timeline_common_'
+        );
+
+        $this->_aObjects = array_merge($this->_aObjects, array(
+        	'comment' => $this->CNF['OBJECT_COMMENTS'],
+        	'view' => $this->CNF['OBJECT_VIEWS'],
+        	'vote' => $this->CNF['OBJECT_VOTES'],
+        	'report' => $this->CNF['OBJECT_REPORTS'],
+        	'metatags' => $this->_sName,
+
+        	'storage_photos' => $this->_sName . '_photos',
+        	'storage_videos' => $this->_sName . '_videos',
+        	'transcoder_photos_preview' => $this->_sName . '_photos_preview',
+        	'transcoder_photos_view' => $this->_sName . '_photos_view',
+        	'transcoder_videos_poster' => $this->_sName . '_videos_poster',
+        	'transcoder_videos_mp4' => $this->_sName . '_videos_mp4',
+        	'transcoder_videos_webm' => $this->_sName . '_videos_webm',
+
+        	'menu_item_manage' => $this->_sName . '_menu_item_manage',
+        	'menu_item_actions' => $this->_sName . '_menu_item_actions',
+        	'menu_post_attachments' => $this->_sName . '_menu_post_attachments',
+
+        	'form_post' => $this->_sName . '_post',
+        	'form_attach_link' => $this->_sName . '_attach_link',
+        	'form_display_post_add' => $this->_sName . '_post_add',
+        	'form_display_attach_link_add' => $this->_sName . '_attach_link_add'
+        ));
+
+        $this->_aHandlerDescriptor = array('module_name' => '', 'module_method' => '', 'module_class' => '', 'groupable' => '', 'group_by' => '');
+        $this->_sHandlersMethod = 'get_timeline_data';
+
+        $this->_aPhotoUploaders = array($this->_sName . '_simple_photo');
+        $this->_aVideoUploaders = array($this->_sName . '_simple_video');
+
+        $this->_bJsMode = false;
+        $this->_aJsClasses = array(
+            'main' => 'BxTimelineMain',
+            'view' => 'BxTimelineView',
+            'post' => 'BxTimelinePost',
+            'repost' => 'BxTimelineRepost'
+        );
+        $this->_aJsObjects = array(
+            'view' => 'oTimelineView',
+            'post' => 'oTimelinePost',
+            'repost' => 'oTimelineRepost'
+        );
+
+        $sHp = str_replace('_', '-', $this->_sName);
+        $sHpT = BX_TIMELINE_VIEW_TIMELINE;
+        $sHpO = BX_TIMELINE_VIEW_OUTLINE;
+        $this->_aHtmlIds = array(
+        	'view' => array(
+                'main_' . $sHpT => $sHp . '-' . $sHpT,
+        		'item_' . $sHpT => $sHp . '-item-' . $sHpT . '-',
+                'photo_popup_' . $sHpT => $sHp . '-photo-popup-' . $sHpT,
+
+        		'main_' . $sHpO => $sHp . '-' . $sHpO,
+        		'item_' . $sHpO => $sHp . '-item-' . $sHpO . '-',
+                'photo_popup_' . $sHpO => $sHp . '-photo-popup-' . $sHpO,
+
+        		'main_item' => $sHp . '-item',
+				'menu_popup' => $sHp . '-menu-popup-',
+            ),
+            'post' => array(
+                'attach_link_popup' =>  $sHp . '-attach-link-popup',
+                'attach_link_form_field' => $sHp . '-attach-link-form_field',
+                'attach_link_item' => $sHp . '-attach-link-item-',
+
+            	'main_' . $sHpT => $sHp . '-' . $sHpT,
+            	'main_' . $sHpO => $sHp . '-' . $sHpO,
+            ),
+            'repost' => array(
+                'main' => $sHp . '-repost-',
+                'counter' => $sHp . '-repost-counter-',
+                'by_popup' => $sHp . '-repost-by-',
+            )
+        );
+
+        $this->_aRepostDefaults = array(
+            'show_do_repost_as_button' => false,
+            'show_do_repost_as_button_small' => false,
+            'show_do_repost_icon' => true,
+            'show_do_repost_label' => false,
+            'show_counter' => true
+        );
+
+        $this->_iTimelineVisibilityThreshold = 0;
+
+        $this->_aPregPatterns = array(
+            "meta_title" => "/<title>(.*)<\/title>/",
+            "meta_description" => "/<meta[\s]+[^>]*?name[\s]?=[\s\"\']+description[\s\"\']+content[\s]?=[\s\"\']+(.*?)[\"\']+.*?>/",
+        	"url" => "/(([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?/"
+        );
+    }
+
+    public function init(&$oDb)
+    {
+    	parent::init($oDb);
+
+    	$sOptionPrefix = $this->getPrefix('option');
+        $this->_bAllowDelete = getParam($sOptionPrefix . 'enable_delete') == 'on';
+
+        $this->_aPerPage = array(
+    		'default' => (int)getParam($sOptionPrefix . 'events_per_page'),
+        	'profile' => (int)getParam($sOptionPrefix . 'events_per_page_profile'),
+        	'account' => (int)getParam($sOptionPrefix . 'events_per_page_account'),
+        	'home' => (int)getParam($sOptionPrefix . 'events_per_page_home')
+    	);
+
+        $this->_iRssLength = (int)getParam($sOptionPrefix . 'rss_length');
+        $this->_iCharsDisplayMax = (int)getParam($sOptionPrefix . 'chars_display_max');
+    }
+
+    public function isAllowDelete()
+    {
+        return $this->_bAllowDelete;
+    }
+
+    public function getUploaders($sType)
+    {
+        $aResult = array();
+
+        switch($sType) {
+            case 'photo':
+                $aResult = $this->_aPhotoUploaders;
+                break;
+			case 'video':
+                $aResult = $this->_aVideoUploaders;
+                break;
+        }
+
+        return $aResult;
+    }
+
+    public function getRssLength()
+    {
+        return $this->_iRssLength;
+    }
+
+    public function getCharsDisplayMax()
+    {
+        return $this->_iCharsDisplayMax;
+    }
+
+    public function getRepostDefaults()
+    {
+        return $this->_aRepostDefaults;
+    }
+
+    public function getPregPattern($sType)
+    {
+        return $this->_aPregPatterns[$sType];
+    }
+
+    /**
+     * Ancillary functions
+     */
+    public function getViewUrl($iOwnerId)
+    {
+        return BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=timeline-view&id=' . $iOwnerId);
+    }
+
+    public function getHomeViewUrl()
+    {
+        return BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=timeline-view-home');
+    }
+
+    public function getItemViewUrl(&$aEvent)
+    {
+        return BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=timeline-item&id=' . $aEvent['id']);
+    }
+
+    public function isSystem($sType, $sAction)
+    {
+        $sPrefix = $this->getPrefix('common_post');
+        return strpos($sType, $sPrefix) === false && !empty($sAction);
+    }
+    public function getSystemData(&$aEvent)
+    {
+		$sHandler = $aEvent['type'] . '_' . $aEvent['action'];
+        if(!$this->isHandler($sHandler))
+            return false;
+
+        $aHandler = $this->getHandlers($sHandler);
+        if(empty($aHandler['module_name']) || empty($aHandler['module_class']) || empty($aHandler['module_method']))
+        	return false; 
+
+		return BxDolService::call($aHandler['module_name'], $aHandler['module_method'], array($aEvent), $aHandler['module_class']);
+    }
+    public function getSystemDataByDescriptor($sType, $sAction, $iObjectId)
+    {
+    	$aDescriptor = array(
+    		'type' => $sType, 
+    		'action' => $sAction,
+    		'object_id' => $iObjectId
+    	);
+    	return $this->getSystemData($aDescriptor);
+    }
+
+    public function isEqualUrls($sUrl1, $sUrl2)
+    {
+        $sUrl1 = trim($sUrl1, "/");
+        $sUrl2 = trim($sUrl2, "/");
+
+        return strncmp($sUrl1, $sUrl2, strlen($sUrl1)) === 0;
+    }
+}
+
+/** @} */

+ 469 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineDb.php

@@ -0,0 +1,469 @@
+<?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 BxTimelineDb extends BxBaseModNotificationsDb
+{
+    protected $_sTablesRepostTrack;
+
+    protected $_aTablesMedia;
+    protected $_aTablesMedia2Events;
+
+    /*
+     * Constructor.
+     */
+    function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+        $this->_sTableRepostsTrack = $this->_sPrefix . 'reposts_track';
+
+        $this->_aTablesMedia = array(
+        	BX_TIMELINE_MEDIA_PHOTO => $this->_sPrefix . 'photos',
+        	BX_TIMELINE_MEDIA_VIDEO => $this->_sPrefix . 'videos' 
+        );
+        $this->_aTablesMedia2Events = array(
+        	BX_TIMELINE_MEDIA_PHOTO => $this->_sPrefix . 'photos2events',
+        	BX_TIMELINE_MEDIA_VIDEO => $this->_sPrefix . 'videos2events'
+        );
+    }
+
+    public function deleteModuleEvents($aData)
+    {
+    	foreach($aData['handlers'] as $aHandler) {
+    		//Delete system events.
+            $this->deleteEvent(array('type' => $aHandler['alert_unit'], 'action' => $aHandler['alert_action']));
+
+            //Delete reposted events.
+    		$aEvents = $this->getEvents(array('browse' => 'reposted_by_descriptor', 'type' => $aHandler['alert_unit'], 'action' => $aHandler['alert_action']));
+			foreach($aEvents as $aEvent) {
+				$aContent = unserialize($aEvent['content']);
+				if(isset($aContent['type']) && $aContent['type'] == $aHandler['alert_unit'] && isset($aContent['action']) && $aContent['action'] == $aHandler['alert_action'])
+					$this->deleteEvent(array('id' => (int)$aEvent['id']));
+			}
+    	}
+    }
+
+	public function activateModuleEvents($aData, $bActivate = true)
+    {
+    	$iActivate = $bActivate ? 1 : 0;
+
+    	foreach($aData['handlers'] as $aHandler) {
+    		//Activate (deactivate) system events.
+            $this->updateEvent(array('active' => $iActivate), array('type' => $aHandler['alert_unit'], 'action' => $aHandler['alert_action']));
+
+			//Activate (deactivate) reposted events.
+			$aEvents = $this->getEvents(array('browse' => 'reposted_by_descriptor', 'type' => $aHandler['alert_unit'], 'action' => $aHandler['alert_action']));
+			foreach($aEvents as $aEvent) {
+				$aContent = unserialize($aEvent['content']);
+				if(isset($aContent['type']) && $aContent['type'] == $aHandler['alert_unit'] && isset($aContent['action']) && $aContent['action'] == $aHandler['alert_action'])
+					$this->updateEvent(array('active' => $iActivate), array('id' => (int)$aEvent['id']));
+			}
+    	}
+    }
+
+    public function getMaxDuration($aParams)
+    {
+        $aParams['browse'] = 'last';
+        if(isset($aParams['timeline']))
+            unset($aParams['timeline']);
+
+        $aEvent = $this->getEvents($aParams);
+        if(empty($aEvent) || !is_array($aEvent))
+            return 0;
+
+        $iNowYear = date('Y', time());
+        return (int)$aEvent['year'] < $iNowYear ? (int)$aEvent['year'] : 0;
+    }
+
+    //--- Repost related methods ---//
+    public function insertRepostTrack($iEventId, $iAuthorId, $sAuthorIp, $iRepostedId)
+    {
+        $iNow = time();
+        $iAuthorNip = ip2long($sAuthorIp);
+        $sQuery = $this->prepare("INSERT INTO `{$this->_sTableRepostsTrack}` SET `event_id` = ?, `author_id` = ?, `author_nip` = ?, `reposted_id` = ?, `date` = ?", $iEventId, $iAuthorId, $iAuthorNip, $iRepostedId, $iNow);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function deleteRepostTrack($iEventId)
+    {
+        $sQuery = $this->prepare("DELETE FROM `{$this->_sTableRepostsTrack}` WHERE `event_id` = ?", $iEventId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function updateRepostCounter($iId, $iCounter, $iIncrement = 1)
+    {
+        return (int)$this->updateEvent(array('reposts' => (int)$iCounter + $iIncrement), array('id' => $iId)) > 0;
+    }
+
+    public function getReposted($sType, $sAction, $iObjectId)
+    {
+    	$bSystem = $this->_oConfig->isSystem($sType, $sAction);
+
+        if($bSystem)
+            $aParams = array('browse' => 'descriptor', 'type' => $sType, 'action' => $sAction, 'object_id' => $iObjectId);
+        else
+            $aParams = array('browse' => 'id', 'value' => $iObjectId);
+
+		$aReposted = $this->getEvents($aParams);
+		if($bSystem && (empty($aReposted) || !is_array($aReposted))) {
+			$iOwnerId = 0;
+			$iDate = 0;
+			$iHidden = 1;
+
+			$mixedResult = $this->_oConfig->getSystemDataByDescriptor($sType, $sAction, $iObjectId);
+			if(is_array($mixedResult)) {
+				$iOwnerId = !empty($mixedResult['owner_id']) ? (int)$mixedResult['owner_id'] : 0;
+				$iDate = !empty($mixedResult['date']) ? (int)$mixedResult['date'] : 0;
+				if(!empty($iOwnerId) && !empty($iDate))
+					$iHidden = 0;
+			}
+
+			$iId = $this->insertEvent(array(
+				'owner_id' => $iOwnerId,
+				'type' => $sType,
+				'action' => $sAction,
+				'object_id' => $iObjectId,
+				'object_privacy_view' => $this->_oConfig->getPrivacyViewDefault('object'),
+				'content' => '',
+				'title' => '',
+				'description' => '',
+				'date' => $iDate,
+				'hidden' => $iHidden
+			));
+
+			$aReposted = $this->getEvents(array('browse' => 'id', 'value' => $iId));
+		}
+
+        return $aReposted;
+    }
+
+    function getRepostedBy($iRepostedId)
+    {
+        $sQuery = $this->prepare("SELECT `author_id` FROM `{$this->_sTableRepostsTrack}` WHERE `reposted_id`=?", $iRepostedId);
+        return $this->getColumn($sQuery);
+    }
+
+    function isReposted($iRepostedId, $iOwnerId, $iAuthorId)
+    {
+    	$sQuery = $this->prepare("SELECT 
+    			`te`.`id`
+    		FROM `{$this->_sTableRepostsTrack}` AS `tst` 
+    		LEFT JOIN `{$this->_sTable}` AS `te` ON `tst`.`event_id`=`te`.`id` 
+    		WHERE `tst`.`author_id`=? AND `tst`.`reposted_id`=? AND `te`.`owner_id`=?", $iAuthorId, $iRepostedId, $iOwnerId);
+
+    	return (int)$this->getOne($sQuery) > 0;
+    }
+
+    //--- Photo uploader related methods ---//
+    public function saveMedia($sType, $iEventId, $iItemId)
+    {
+    	$sTable = $this->_aTablesMedia2Events[$sType];
+
+        $sQuery = $this->prepare("INSERT INTO `" . $sTable . "` SET `event_id`=?, `media_id`=?", $iEventId, $iItemId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function deleteMedia($sType, $iEventId)
+    {
+    	$sTable = $this->_aTablesMedia2Events[$sType];
+
+        $sQuery = $this->prepare("DELETE FROM `" . $sTable . "` WHERE `event_id` = ?", $iEventId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function getMedia($sType, $iEventId, $iOffset = 0)
+    {
+    	$sTableMedia = $this->_aTablesMedia[$sType];
+    	$sTableMedia2Events = $this->_aTablesMedia2Events[$sType];
+
+        $sLimitAddon = '';
+        if($iOffset != 0)
+            $sLimitAddon = $this->prepareAsString(" OFFSET ?", $iOffset);
+
+        $sQuery = $this->prepare("SELECT
+                 `tme`.`media_id` AS `id`
+            FROM `" . $sTableMedia2Events . "` AS `tme`
+            LEFT JOIN `" . $sTableMedia . "` AS `tm` ON `tme`.`media_id`=`tm`.`id`
+            WHERE `tme`.`event_id`=?" . $sLimitAddon, $iEventId);
+
+        return $this->getColumn($sQuery);
+    }
+
+    //--- Link attach related methods ---//
+    public function getUnusedLinks($iUserId, $iLinkId = 0)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+        $aMethod['params'][1] = array(
+			'profile_id' => $iUserId
+		);
+
+        $sWhereAddon = '';
+        if(!empty($iLinkId)) {
+            $aMethod['name'] = 'getRow';
+            $aMethod['params'][1]['id'] = $iLinkId;
+
+            $sWhereAddon = " AND `tl`.`id`=:id";
+        }
+
+        $aMethod['params'][0] = "SELECT
+                `tl`.`id` AS `id`,
+                `tl`.`profile_id` AS `profile_id`,
+                `tl`.`media_id` AS `media_id`,
+                `tl`.`url` AS `url`,
+                `tl`.`title` AS `title`,
+                `tl`.`text` AS `text`,
+                `tl`.`added` AS `added`
+            FROM `" . $this->_sPrefix . "links` AS `tl`
+            LEFT JOIN `" . $this->_sPrefix . "links2events` AS `tle` ON `tl`.`id`=`tle`.`link_id`
+            WHERE `tl`.`profile_id`=:profile_id AND ISNULL(`tle`.`event_id`)" . $sWhereAddon . "
+            ORDER BY `tl`.`added` DESC";
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);;
+    }
+
+    public function deleteUnusedLinks($iUserId, $iLinkId = 0)
+    {
+    	$aBindings = array(
+    		'profile_id' => $iUserId
+    	);
+
+        $sWhereAddon = '';
+        if(!empty($iLinkId)) {
+        	$aBindings['id'] = $iLinkId;
+
+            $sWhereAddon = " AND `id`=:id";
+        }
+
+        return $this->query("DELETE FROM `" . $this->_sPrefix . "links` WHERE `profile_id`=:profile_id" . $sWhereAddon, $aBindings);
+    }
+
+    public function saveLink($iEventId, $iLinkId)
+    {
+        $sQuery = $this->prepare("INSERT INTO `" . $this->_sPrefix . "links2events` SET `event_id`=?, `link_id`=?", $iEventId, $iLinkId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function deleteLinks($iEventId)
+    {
+        $sQuery = $this->prepare("DELETE FROM `tl`, `tle` USING `" . $this->_sPrefix . "links` AS `tl` LEFT JOIN `" . $this->_sPrefix . "links2events` AS `tle` ON `tl`.`id`=`tle`.`link_id` WHERE `tle`.`event_id` = ?", $iEventId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function getLinks($iEventId)
+    {
+        $sQuery = $this->prepare("SELECT
+                `tl`.`id` AS `id`,
+                `tl`.`profile_id` AS `profile_id`,
+                `tl`.`media_id` AS `media_id`,
+                `tl`.`url` AS `url`,
+                `tl`.`title` AS `title`,
+                `tl`.`text` AS `text`,
+                `tl`.`added` AS `added`
+            FROM `" . $this->_sPrefix . "links` AS `tl`
+            LEFT JOIN `" . $this->_sPrefix . "links2events` AS `tle` ON `tl`.`id`=`tle`.`link_id`
+            WHERE `tle`.`event_id`=?", $iEventId);
+
+        return $this->getAll($sQuery);
+    }
+
+    protected function _getFilterAddon($iOwnerId, $sFilter)
+    {
+        switch($sFilter) {
+            case BX_TIMELINE_FILTER_OWNER:
+                $sFilterAddon = $this->prepareAsString(" AND `{$this->_sTable}`.`action`='' AND `{$this->_sTable}`.`object_id`=? ", $iOwnerId);
+                break;
+            case BX_TIMELINE_FILTER_OTHER:
+                $sFilterAddon = $this->prepareAsString(" AND `{$this->_sTable}`.`action`='' AND `{$this->_sTable}`.`object_id`<>? ", $iOwnerId);
+                break;
+            case BX_TIMELINE_FILTER_ALL:
+            default:
+                $sFilterAddon = "";
+        }
+        return $sFilterAddon;
+    }
+
+    protected function _getSqlPartsEvents($aParams)
+    {
+    	$sMethod = 'getAll';
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        switch($aParams['browse']) {
+        	case 'owner_id':
+        		$sWhereClause = $this->prepareAsString("AND `{$this->_sTable}`.`owner_id`=? ", $aParams['value']);
+        		break;
+
+        	case 'common_by_object':
+        		$sCommonPostPrefix = $this->_oConfig->getPrefix('common_post');
+        		$sWhereClause = $this->prepareAsString("AND SUBSTRING(`{$this->_sTable}`.`type`, 1, " . strlen($sCommonPostPrefix) . ")='" . $sCommonPostPrefix . "' AND `{$this->_sTable}`.`object_id`=? ", $aParams['value']);
+        		break;
+
+            case 'descriptor':
+                $sMethod = 'getRow';
+                $sWhereClause = "";
+
+                if(isset($aParams['type']))
+                	$sWhereClause .= $this->prepareAsString("AND `{$this->_sTable}`.`type`=? ", $aParams['type']);
+				if(isset($aParams['action']))
+					$sWhereClause .= $this->prepareAsString("AND `{$this->_sTable}`.`action`=? ", $aParams['action']);
+				if(isset($aParams['object_id']))
+					$sWhereClause .= $this->prepareAsString("AND `{$this->_sTable}`.`object_id`=? ", $aParams['object_id']);
+
+				$sLimitClause = "LIMIT 1";
+                break;
+
+            case 'reposted_by_descriptor':
+            	$sWhereClause = "";
+
+            	if(isset($aParams['type']))
+                	$sWhereClause .= "AND `{$this->_sTable}`.`content` LIKE " . $this->escape('%' . $aParams['type'] . '%');
+
+                if(isset($aParams['action']))
+                	$sWhereClause .= "AND `{$this->_sTable}`.`content` LIKE " . $this->escape('%' . $aParams['action'] . '%');
+                break;
+
+            default:
+            	list($sMethod, $sSelectClause, $sJoinClause, $sWhereClause, $sOrderClause, $sLimitClause) = parent::_getSqlPartsEvents($aParams);
+        }
+
+		$sSelectClause .= "DAYOFYEAR(FROM_UNIXTIME(`{$this->_sTable}`.`date`)) AS `days`, DAYOFYEAR(NOW()) AS `today`, ROUND((UNIX_TIMESTAMP() - `{$this->_sTable}`.`date`)/86400) AS `ago_days`, YEAR(FROM_UNIXTIME(`{$this->_sTable}`.`date`)) AS `year`, ";
+		if($aParams['browse'] == 'list')
+			$sOrderClause = "ORDER BY `{$this->_sTable}`.`pinned` DESC, `{$this->_sTable}`.`date` DESC";
+
+        return array($sMethod, $sSelectClause, $sJoinClause, $sWhereClause, $sOrderClause, $sLimitClause);
+    }
+
+    protected function _getSqlPartsEventsList($aParams)
+    {
+    	$sJoinClause = "";
+    	$sWhereClause = "AND `{$this->_sTable}`.`hidden`='0' ";
+
+		if(isset($aParams['active']))
+        	$sWhereClause .= $this->prepareAsString("AND `{$this->_sTable}`.`active`=? ", (int)$aParams['active']);
+
+		//--- Apply filter
+        if(isset($aParams['filter']))
+        	$sWhereClause .= $this->_getFilterAddon($aParams['owner_id'], $aParams['filter']);
+
+		//--- Apply timeline
+        if(isset($aParams['timeline']) && !empty($aParams['timeline'])) {
+        	$iYear = (int)$aParams['timeline'];
+            $sWhereClause .= $this->prepareAsString("AND `date`<=? ", mktime(23, 59, 59, 12, 31, $iYear));
+		}
+
+		//--- Apply modules or handlers filter
+        $sWhereModuleFilter = '';
+        if(!empty($aParams['modules']) && is_array($aParams['modules']))
+        	$sWhereModuleFilter = "AND `" . $this->_sTable . "`.`type` IN (" . $this->implode_escape($aParams['modules']) . ") ";
+
+		if($sWhereModuleFilter == '') {
+        	$aHidden = $this->_oConfig->getHandlersHidden();
+			$sWhereModuleFilter = !empty($aHidden) && is_array($aHidden) ? "AND `" . $this->_sTableHandlers . "`.`id` NOT IN (" . $this->implode_escape($aHidden) . ") " : "";
+		}
+
+		if($sWhereModuleFilter != '')
+			$sWhereClause .= $sWhereModuleFilter;
+
+		//--- Apply privacy filter
+		$oPrivacy = BxDolPrivacy::getObjectInstance($this->_oConfig->getObject('privacy_view'));
+		$aQueryParts = $oPrivacy->getContentByGroupAsSQLPart(BX_DOL_PG_ALL);
+		$sWhereClause .= $aQueryParts['where'] . " ";
+
+		//--- Check type
+		switch($aParams['type']) {
+			case BX_BASE_MOD_NTFS_TYPE_OWNER:
+				if(empty($aParams['owner_id']))
+					break;
+
+				$sWhereClause .= $this->prepareAsString("AND `{$this->_sTable}`.`owner_id`=? ", $aParams['owner_id']);
+				break;
+
+			case BX_BASE_MOD_NTFS_TYPE_CONNECTIONS:
+				if(empty($aParams['owner_id']))
+					break;
+
+				$oConnection = BxDolConnection::getObjectInstance($this->_oConfig->getObject('conn_subscriptions'));
+
+				$aQueryParts = $oConnection->getConnectedContentAsSQLParts($this->_sPrefix . "events", 'owner_id', $aParams['owner_id']);
+				$sJoinClause .= ' ' . $aQueryParts['join'];
+
+				$iUserId = bx_get_logged_profile_id();
+				$sCommonPostPrefix = $this->_oConfig->getPrefix('common_post');
+
+				$sWhereClause .= $this->prepareAsString("AND IF(SUBSTRING(`{$this->_sTable}`.`type`, 1, " . strlen($sCommonPostPrefix) . ") = '" . $sCommonPostPrefix . "', `{$this->_sTable}`.`object_id` <> ?, 1) ", $iUserId);
+				break;
+
+			case BX_BASE_MOD_NTFS_TYPE_PUBLIC:
+				$sCommonPostPrefix = $this->_oConfig->getPrefix('common_post');
+				$sWhereClause .= $this->prepareAsString("AND (SUBSTRING(`{$this->_sTable}`.`type`, 1, " . strlen($sCommonPostPrefix) . ") <> '" . $sCommonPostPrefix . "' OR `{$this->_sTable}`.`owner_id`=?) ", 0);
+				break;
+		}
+
+		return array($sJoinClause, $sWhereClause);
+    }
+
+    function updateSimilarObject($iId, &$oAlert, $sDuration = 'day')
+    {
+        $sType = $oAlert->sUnit;
+        $sAction = $oAlert->sAction;
+
+        //Check handler
+        $aHandler = $this->_oConfig->getHandlers($sType . '_' . $sAction);
+        if(empty($aHandler) || !is_array($aHandler) || (int)$aHandler['groupable'] != 1)
+            return false;
+
+        //Check content's extra values
+        if(isset($aHandler['group_by']) && !empty($aHandler['group_by']) && (!isset($oAlert->aExtras[$aHandler['group_by']]) || empty($oAlert->aExtras[$aHandler['group_by']])))
+            return false;
+
+		$aBindings = array(
+			'object_id' => $oAlert->iObject,
+			'id' => $iId,
+			'owner_id' => $oAlert->iSender,
+			'type' => $sType,
+			'action' => $sAction
+		);
+
+        $sWhereClause = "";
+        switch($sDuration) {
+            case 'day':
+                $aBindings['day_start'] = mktime(0, 0, 0, date('m'), date('d'), date('Y'));
+                $aBindings['day_end'] = mktime(23, 59, 59, date('m'), date('d'), date('Y'));
+
+                $sWhereClause .= "AND `date`>:day_start AND `date`<:day_end ";
+                break;
+        }
+
+        if(isset($aHandler['group_by'])) {
+        	$aBindings['content'] = '%' . $oAlert->aExtras[$aHandler['group_by']] . '%';
+
+            $sWhereClause .= "AND `content` LIKE :content ";
+        }
+
+        $sSql = "UPDATE `{$this->_sTable}`
+            SET
+                `object_id`=CONCAT(`object_id`, ',:object_id'),
+                `title`='',
+                `description`='',
+                `date`=UNIX_TIMESTAMP()
+            WHERE
+                `id`<>:id AND
+                `owner_id`=:owner_id AND
+                `type`=:type AND
+                `action`=:action " . $sWhereClause;
+        $mixedResult = $this->query($sSql, $aBindings);
+
+        if((int)$mixedResult > 0)
+            $this->deleteEvent(array('id' => $iId));
+
+        return $mixedResult;
+    }
+}
+
+/** @} */

+ 142 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineMenuItemActions.php

@@ -0,0 +1,142 @@
+<?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
+ *
+ * @{
+ */
+
+/**
+ * 'Item' menu.
+ */
+class BxTimelineMenuItemActions extends BxTemplMenuCustom
+{
+    protected $_aEvent;
+    protected $_oModule;
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+
+        $this->_oModule = BxDolModule::getInstance('bx_timeline');
+    }
+
+    public function setEvent($sView, $aEvent)
+    {
+        if(empty($aEvent) || !is_array($aEvent))
+            return;
+
+        $this->_aEvent = $aEvent;
+
+        $iCommentsObject = 0;
+        $sCommentsSystem = $sCommentsOnclick = '';
+        if(isset($aEvent['comments']) && is_array($aEvent['comments']) && isset($aEvent['comments']['system'])) {
+            $sCommentsSystem = $aEvent['comments']['system'];
+            $iCommentsObject = $aEvent['comments']['object_id'];
+            $sCommentsOnclick = $this->_oModule->_oConfig->getJsObject('view') . ".commentItem(this, '" . $sCommentsSystem . "', " . $iCommentsObject . ")";
+        }
+
+        $this->addMarkers(array(
+        	'js_object_view' => $this->_oModule->_oConfig->getJsObject('view'),
+
+            'view' => $sView,
+            'content_id' => $aEvent['id'],
+
+            'comment_system' => $sCommentsSystem,
+            'comment_object' => $iCommentsObject,
+            'comment_onclick' => $sCommentsOnclick,
+        ));
+    }
+
+    public function isVisible()
+    {
+    	if(!isset($this->_aObject['menu_items']))
+			$this->_aObject['menu_items'] = $this->_oQuery->getMenuItems();
+
+    	$bVisible = false;
+    	foreach ($this->_aObject['menu_items'] as $a) {
+    		if((isset($a['active']) && !$a['active']) || (isset($a['visible_for_levels']) && !$this->_isVisible($a)))
+				continue;
+			
+			$bVisible = true;
+			break;
+    	}
+
+    	return $bVisible;
+    }
+
+    protected function _getMenuItemItemView($aItem)
+    {
+        if(!isset($this->_aEvent['views']) || !is_array($this->_aEvent['views']) || !isset($this->_aEvent['views']['system'])) 
+        	return false;
+
+		$sViewsSystem = $this->_aEvent['views']['system'];
+		$iViewsObject = $this->_aEvent['views']['object_id'];
+    	return $this->_oModule->getViewObject($sViewsSystem, $iViewsObject)->getElementInline(array('dynamic_mode' => $this->_bDynamicMode));
+    }
+
+    protected function _getMenuItemItemVote($aItem)
+    {
+        if(!isset($this->_aEvent['votes']) || !is_array($this->_aEvent['votes']) || !isset($this->_aEvent['votes']['system'])) 
+        	return false;
+
+		$sVotesSystem = $this->_aEvent['votes']['system'];
+		$iVotesObject = $this->_aEvent['votes']['object_id'];
+    	return $this->_oModule->getVoteObject($sVotesSystem, $iVotesObject)->getElementInline(array('dynamic_mode' => $this->_bDynamicMode));
+    }
+
+	protected function _getMenuItemItemReport($aItem)
+    {
+        if(!isset($this->_aEvent['reports']) || !is_array($this->_aEvent['reports']) || !isset($this->_aEvent['reports']['system'])) 
+        	return false;
+
+		$sReportsSystem = $this->_aEvent['reports']['system'];
+		$iReportsObject = $this->_aEvent['reports']['object_id'];
+    	return $this->_oModule->getReportObject($sReportsSystem, $iReportsObject)->getElementInline(array('dynamic_mode' => $this->_bDynamicMode));
+    }
+
+    /**
+     * Check if menu items is visible.
+     * @param $a menu item array
+     * @return boolean
+     */
+    protected function _isVisible ($a)
+    {
+        if(!parent::_isVisible($a) || empty($this->_aEvent))
+            return false;
+
+        $sCheckFuncName = '';
+        $aCheckFuncParams = array($this->_aEvent);
+        switch ($a['name']) {
+            case 'item-view':
+                $sCheckFuncName = 'isAllowedViewCounter';
+                break;
+
+            case 'item-comment':
+                $sCheckFuncName = 'isAllowedComment';
+                break;
+
+            case 'item-vote':
+                $sCheckFuncName = 'isAllowedVote';
+                break;
+
+			case 'item-report':
+                $sCheckFuncName = 'isAllowedReport';
+                break;
+
+            case 'item-more':
+            	$sCheckFuncName = 'isAllowedMore';
+            	break;
+        }
+
+        if(!$sCheckFuncName || !method_exists($this->_oModule, $sCheckFuncName))
+            return true;
+
+        return call_user_func_array(array($this->_oModule, $sCheckFuncName), $aCheckFuncParams) === true;
+    }
+}
+
+/** @} */

+ 83 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineMenuItemManage.php

@@ -0,0 +1,83 @@
+<?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
+ *
+ * @{
+ */
+
+/**
+ * 'Item' menu.
+ */
+class BxTimelineMenuItemManage extends BxTemplMenu
+{
+    protected $_oModule;
+
+	protected $_iEvent;
+	protected $_aEvent;
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+
+        $this->_oModule = BxDolModule::getInstance('bx_timeline');
+
+        if(bx_get('content_id') !== false)
+            $this->setEventId((int)bx_get('content_id'));
+    }
+
+    public function setEventId($iEventId)
+    {
+    	$this->_iEvent = $iEventId;
+    	$this->_aEvent = $this->_oModule->_oDb->getEvents(array('browse' => 'id', 'value' => $this->_iEvent));
+
+    	$this->addMarkers(array(
+            'js_object_view' => $this->_oModule->_oConfig->getJsObject('view'),
+
+        	'content_id' => $this->_iEvent,
+        ));
+    }
+
+    /**
+     * Check if menu items is visible.
+     * @param $a menu item array
+     * @return boolean
+     */
+    protected function _isVisible ($a)
+    {
+        if(!parent::_isVisible($a))
+            return false;
+
+		if(empty($this->_aEvent) || !is_array($this->_aEvent))
+			return false;
+
+        $sCheckFuncName = '';
+        $aCheckFuncParams = array();
+        switch ($a['name']) {
+        	case 'item-pin':
+                $sCheckFuncName = 'isAllowedPin';
+				$aCheckFuncParams = array($this->_aEvent);
+                break;
+
+			case 'item-unpin':
+                $sCheckFuncName = 'isAllowedUnpin';
+				$aCheckFuncParams = array($this->_aEvent);
+                break;
+
+            case 'item-delete':
+                $sCheckFuncName = 'isAllowedDelete';
+				$aCheckFuncParams = array($this->_aEvent);
+                break;
+        }
+
+        if(!$sCheckFuncName || !method_exists($this->_oModule, $sCheckFuncName))
+            return true;
+
+        return call_user_func_array(array($this->_oModule, $sCheckFuncName), $aCheckFuncParams) === true;
+    }
+}
+
+/** @} */

+ 123 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineMenuItemShare.php

@@ -0,0 +1,123 @@
+<?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
+ *
+ * @{
+ */
+
+/**
+ * 'Item' menu.
+ */
+class BxTimelineMenuItemShare extends BxTemplMenu
+{
+    protected $_oModule;
+
+	protected $_iEvent;
+	protected $_aEvent;
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+
+        $this->_oModule = BxDolModule::getInstance('bx_timeline');
+
+        if(bx_get('content_id') !== false)
+        	$this->setEventId((int)bx_get('content_id'));
+    }
+
+    public function setEventId($iEventId)
+    {
+    	$this->_iEvent = $iEventId;
+    	$this->_aEvent = $this->_oModule->_oDb->getEvents(array('browse' => 'id', 'value' => $this->_iEvent));
+
+        $sRepostOnclick = $sEtSend = '';
+        if(!empty($this->_aEvent) && is_array($this->_aEvent)) {
+            $sType = $this->_aEvent['type'];
+            $sAction = $this->_aEvent['action'];
+
+            $this->_aEvent['url'] = $this->_oModule->_oConfig->getItemViewUrl($this->_aEvent);
+            if($this->_oModule->_oConfig->isSystem($sType, $sAction)) {
+                $aResult = $this->_oModule->_oConfig->getSystemData($this->_aEvent);
+                if(!empty($aResult['url']))
+                    $this->_aEvent['url'] = $aResult['url'];
+            }
+
+            //--- Repost item
+            $iOwnerId = $this->_oModule->getUserId(); //--- in whose timeline the content will be reposted
+            $iObjectId = $this->_oModule->_oConfig->isSystem($sType, $sAction) ? $this->_aEvent['object_id'] : $this->_aEvent['id'];
+            $sRepostOnclick = $this->_oModule->serviceGetRepostJsClick($iOwnerId, $sType, $sAction, $iObjectId);
+
+            //--- Send item
+    	    $sAetSend = urlencode(base64_encode(serialize(array(
+    	        'name' => 'bx_timeline_send',
+    	        'params' => array(
+    	            'ViewLink' => $this->_aEvent['url']
+    	        )
+    	    )))); 
+        }
+
+    	$this->addMarkers(array(
+        	'js_object_view' => $this->_oModule->_oConfig->getJsObject('view'),
+
+        	'content_id' => $this->_iEvent,
+    	    'content_url' => $this->_aEvent['url'],
+
+    	    'js_onclick_repost' => $sRepostOnclick,
+    		'et_send' => $sAetSend
+    	));
+    }
+
+    public function getMenuItems ()
+    {
+        $aItems = parent::getMenuItems();
+
+        $oSocial = BxDolMenu::getObjectInstance('sys_social_sharing');
+        $oSocial->addMarkers(array(
+            'id' => $this->_iEvent,
+        	'module' => $this->_oModule->_oConfig->getName(),
+        	'url' => $this->_aEvent['url'],
+        	'title' => $this->_aEvent['title'],
+        ));
+
+        return array_merge($aItems, $oSocial->getMenuItems());
+    }
+
+    /**
+     * Check if menu items is visible.
+     * @param $a menu item array
+     * @return boolean
+     */
+    protected function _isVisible ($a)
+    {
+        if(!parent::_isVisible($a))
+            return false;
+
+		if(empty($this->_aEvent) || !is_array($this->_aEvent))
+			return false;
+
+        $sCheckFuncName = '';
+        $aCheckFuncParams = array();
+        switch ($a['name']) {
+        	case 'item-repost':
+                $sCheckFuncName = 'isAllowedRepost';
+				$aCheckFuncParams = array($this->_aEvent);
+                break;
+
+			case 'item-send':
+                $sCheckFuncName = 'isAllowedSend';
+				$aCheckFuncParams = array($this->_aEvent);
+                break;
+        }
+
+        if(!$sCheckFuncName || !method_exists($this->_oModule, $sCheckFuncName))
+            return true;
+
+        return call_user_func_array(array($this->_oModule, $sCheckFuncName), $aCheckFuncParams) === true;
+    }
+}
+
+/** @} */

+ 1355 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineModule.php

@@ -0,0 +1,1355 @@
+<?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
+ *
+ * @{
+ */
+
+bx_import('BxDolAcl');
+bx_import('BxBaseModNotificationsModule');
+
+define('BX_TIMELINE_TYPE_ITEM', 'view_item');
+define('BX_TIMELINE_TYPE_DEFAULT', BX_BASE_MOD_NTFS_TYPE_OWNER);
+
+define('BX_TIMELINE_VIEW_TIMELINE', 'timeline');
+define('BX_TIMELINE_VIEW_OUTLINE', 'outline');
+define('BX_TIMELINE_VIEW_DEFAULT', BX_TIMELINE_VIEW_OUTLINE);
+
+define('BX_TIMELINE_FILTER_ALL', 'all');
+define('BX_TIMELINE_FILTER_OWNER', 'owner');
+define('BX_TIMELINE_FILTER_OTHER', 'other');
+
+define('BX_TIMELINE_PARSE_TYPE_POST', 'post');
+define('BX_TIMELINE_PARSE_TYPE_REPOST', 'repost');
+define('BX_TIMELINE_PARSE_TYPE_DEFAULT', BX_TIMELINE_PARSE_TYPE_POST);
+
+define('BX_TIMELINE_MEDIA_PHOTO', 'photo');
+define('BX_TIMELINE_MEDIA_VIDEO', 'video');
+
+class BxTimelineModule extends BxBaseModNotificationsModule
+{
+    protected $_sJsPostObject;
+    protected $_sJsViewObject;
+    protected $_aPostElements;
+    protected $_sJsOutlineObject;
+
+    protected $_sDividerTemplate;
+    protected $_sBalloonTemplate;
+    protected $_sCmtPostTemplate;
+    protected $_sCmtViewTemplate;
+    protected $_sCmtTemplate;
+
+    /**
+     * Constructor
+     */
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    /**
+     * ACTION METHODS
+     */
+    public function actionPost()
+    {
+        $sType = bx_process_input($_POST['type']);
+        $sMethod = 'getForm' . ucfirst($sType);
+        if(!method_exists($this, $sMethod)) {
+            echoJson(array());
+            return;
+        }
+
+        $this->_iOwnerId = bx_process_input(bx_get('owner_id'), BX_DATA_INT);
+
+        $mixedAllowed = $this->isAllowedPost(true);
+        if($mixedAllowed !== true) {
+            echoJson(array('msg' => strip_tags($mixedAllowed)));
+            return;
+        }
+
+        $aResult = $this->$sMethod();
+        echoJson($aResult);
+    }
+
+	function actionPin()
+    {
+        $this->_iOwnerId = bx_process_input(bx_get('owner_id'), BX_DATA_INT);
+
+        $iId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        $aEvent = $this->_oDb->getEvents(array('browse' => 'id', 'value' => $iId));
+
+        $mixedAllowed = $this->{'isAllowed' . ((int)$aEvent['pinned'] == 0 ? 'Pin' : 'Unpin')}($aEvent, true);
+        if($mixedAllowed !== true)
+            return echoJson(array('code' => 1, 'msg' => strip_tags($mixedAllowed)));
+
+		$aEvent['pinned'] = (int)$aEvent['pinned'] == 0 ? time() : 0;
+        if(!$this->_oDb->updateEvent(array('pinned' => $aEvent['pinned']), array('id' => $iId)))
+        	return echoJson(array('code' => 2));
+
+		echoJson(array(
+			'code' => 0, 
+			'id' => $iId, 
+			'eval' => $this->_oConfig->getJsObject('view') . '.onPinPost(oData)'
+		));
+    }
+
+    function actionDelete()
+    {
+        $this->_iOwnerId = bx_process_input(bx_get('owner_id'), BX_DATA_INT);
+
+        $aEvent = $this->_oDb->getEvents(array('browse' => 'id', 'value' => bx_process_input(bx_get('id'), BX_DATA_INT)));
+
+        $mixedAllowed = $this->isAllowedDelete($aEvent, true);
+        if($mixedAllowed !== true)
+            return echoJson(array('code' => 1, 'msg' => strip_tags($mixedAllowed)));
+
+        if(!$this->deleteEvent($aEvent))
+            return echoJson(array('code' => 2));
+
+        echoJson(array(
+        	'code' => 0, 
+        	'id' => $aEvent['id'], 
+        	'eval' => $this->_oConfig->getJsObject('view') . '.onDeletePost(oData)'
+        ));
+    }
+
+    public function actionRepost()
+    {
+    	$iAuthorId = $this->getUserId();
+
+        $iOwnerId = bx_process_input(bx_get('owner_id'), BX_DATA_INT);
+        $aContent = array(
+            'type' => bx_process_input(bx_get('type'), BX_DATA_TEXT),
+            'action' => bx_process_input(bx_get('action'), BX_DATA_TEXT),
+            'object_id' => bx_process_input(bx_get('object_id'), BX_DATA_INT),
+        );
+
+        $aReposted = $this->_oDb->getReposted($aContent['type'], $aContent['action'], $aContent['object_id']);
+        if(empty($aReposted) || !is_array($aReposted)) {
+            echoJson(array('code' => 1, 'msg' => _t('_bx_timeline_txt_err_cannot_repost')));
+            return;
+        }
+
+        $mixedAllowed = $this->isAllowedRepost($aReposted, true);
+        if($mixedAllowed !== true) {
+            echoJson(array('code' => 2, 'msg' => strip_tags($mixedAllowed)));
+            return;
+        }
+
+        $bReposted = $this->_oDb->isReposted($aReposted['id'], $iOwnerId, $iAuthorId);
+		if($bReposted) {
+        	echoJson(array('code' => 3, 'msg' => _t('_bx_timeline_txt_err_already_reposted')));
+            return;
+        }
+
+        $iId = $this->_oDb->insertEvent(array(
+            'owner_id' => $iOwnerId,
+            'type' => $this->_oConfig->getPrefix('common_post') . 'repost',
+            'action' => '',
+            'object_id' => $iAuthorId,
+            'object_privacy_view' => $this->_oConfig->getPrivacyViewDefault('object'),
+            'content' => serialize($aContent),
+            'title' => '',
+            'description' => ''
+        ));
+
+        if(empty($iId)) {
+	        echoJson(array('code' => 4, 'msg' => _t('_bx_timeline_txt_err_cannot_repost')));        
+	        return;
+        }
+
+        $this->onRepost($iId, $aReposted);
+
+        $aReposted = $this->_oDb->getReposted($aContent['type'], $aContent['action'], $aContent['object_id']);
+		$sCounter = $this->_oTemplate->getRepostCounter($aReposted);
+
+		echoJson(array(
+			'code' => 0, 
+			'msg' => _t('_bx_timeline_txt_msg_success_repost'), 
+			'count' => $aReposted['reposts'], 
+			'counter' => $sCounter,
+			'disabled' => !$bReposted
+		));
+    }
+
+    function actionGetPost()
+    {
+        $sView = bx_process_input(bx_get('view'));
+        $this->_iOwnerId = bx_process_input(bx_get('owner_id'), BX_DATA_INT);
+
+        $aEvent = $this->_oDb->getEvents(array('browse' => 'id', 'value' => bx_process_input(bx_get('id'), BX_DATA_INT)));
+        if(empty($aEvent) || !is_array($aEvent))
+            return echoJson(array());
+
+        echoJson(array(
+            'id' => $aEvent['id'],
+            'view' => $sView,
+        	'item' => $this->_oTemplate->getPost($aEvent, array(
+        		'view' => $sView, 
+        		'type' => 'owner', 
+        		'owner_id' => $this->_iOwnerId, 
+        		'dynamic_mode' => true
+            )),
+            'eval' => $this->_oConfig->getJsObject('post') . "._onGetPost(oData)"
+        ));
+    }
+
+    function actionGetPosts()
+    {
+        $aParams = $this->_prepareParamsGet();
+        list($sItems, $sLoadMore, $sBack, $sEmpty) = $this->_oTemplate->getPosts($aParams);
+
+        echoJson(array(
+        	'view' => $aParams['view'],
+        	'items' => $sItems, 
+        	'load_more' => $sLoadMore, 
+        	'back' => $sBack,
+            'empty' => $sEmpty,
+        	'eval' => $this->_oConfig->getJsObject('view') . "._onGetPosts(oData)"
+        ));
+    }
+
+    public function actionGetPostForm($sType)
+    {
+        $this->_iOwnerId = bx_process_input(bx_get('owner_id'), BX_DATA_INT);
+
+        $sMethod = 'getForm' . ucfirst($sType);
+        if(!method_exists($this, $sMethod)) {
+            echoJson(array());
+            return;
+        }
+        $aResult = $this->$sMethod();
+
+        echoJson($aResult);
+    }
+
+    public function actionGetComments()
+    {
+        $this->_iOwnerId = bx_process_input(bx_get('owner_id'), BX_DATA_INT);
+
+        $sSystem = bx_process_input(bx_get('system'), BX_DATA_TEXT);
+        $iId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        $sComments = $this->_oTemplate->getComments($sSystem, $iId);
+
+        echoJson(array('content' => $sComments));
+    }
+
+    public function actionAddAttachLink()
+    {
+        $aResult = $this->getFormAttachLink();
+
+        echoJson($aResult);
+    }
+
+    public function actionDeleteAttachLink()
+    {
+    	$iUserId = $this->getUserId();
+        $iLinkId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if(empty($iLinkId)) {
+            echoJson(array());
+            return;
+        }
+
+        $aLink = $this->_oDb->getUnusedLinks($iUserId, $iLinkId);
+    	if(empty($aLink) || !is_array($aLink)) {
+            echoJson(array());
+            return;
+        }
+
+		if(!empty($aLink['media_id']))
+			BxDolStorage::getObjectInstance($this->_oConfig->getObject('storage_photos'))->deleteFile($aLink['media_id']);
+
+        $aResult = array();
+        if($this->_oDb->deleteUnusedLinks($iUserId, $iLinkId))
+            $aResult = array('code' => 0);
+        else
+            $aResult = array('code' => 1, 'msg' => _t('_bx_timeline_form_post_input_link_err_delete'));
+
+        echoJson($aResult);
+    }
+
+    public function actionGetAttachLinkForm()
+    {
+        echo $this->_oTemplate->getAttachLinkForm();
+    }
+
+    public function actionGetRepostedBy()
+    {
+        $iRepostedId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+        echo $this->_oTemplate->getRepostedBy($iRepostedId);
+    }
+
+    function actionRss()
+    {
+        $aArgs = func_get_args();
+
+        $sType = array_shift($aArgs);
+        $iOwnerId = 0;
+
+        switch($sType) {
+            case BX_BASE_MOD_NTFS_TYPE_OWNER:
+                $iOwnerId = array_shift($aArgs);
+                list($sUserName) = $this->getUserInfo($iOwnerId);
+
+                $sRssCaption = _t('_bx_timeline_txt_rss_caption', $sUserName);
+                $sRssLink = $this->_oConfig->getViewUrl($iOwnerId);
+                break;
+
+            case BX_BASE_MOD_NTFS_TYPE_PUBLIC:
+                $sRssCaption = _t('_bx_timeline_page_title_view_home');
+                $sRssLink = $this->_oConfig->getHomeViewUrl();
+                break;
+        }
+        
+
+        $aParams = $this->_prepareParams($sType, $iOwnerId, 0, $this->_oConfig->getRssLength(), '', array(), 0);
+        $aEvents = $this->_oDb->getEvents($aParams);
+
+        $aRssData = array();
+        foreach($aEvents as $aEvent) {
+            if(empty($aEvent['title'])) continue;
+
+            $aRssData[$aEvent['id']] = array(
+               'UnitID' => $aEvent['id'],
+               'UnitTitle' => $aEvent['title'],
+               'UnitLink' => $this->_oConfig->getItemViewUrl($aEvent),
+               'UnitDesc' => $aEvent['description'],
+               'UnitDateTimeUTS' => $aEvent['date'],
+            );
+        }
+
+        $oRss = new BxDolRssFactory();
+
+        header('Content-Type: application/xml; charset=utf-8');
+        echo $oRss->GenRssByData($aRssData, $sRssCaption, $sRssLink);
+    }
+
+    /**
+     * SERVICE METHODS
+     * 
+     * Get Post block for a separate page.
+     */
+    public function serviceGetBlockPost($iProfileId = 0)
+    {
+    	if(empty($iProfileId) && bx_get('profile_id') !== false)
+			$iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+
+		if(empty($iProfileId) && isLogged())
+			$iProfileId = bx_get_logged_profile_id();
+
+        if(!$iProfileId)
+            return array();
+
+        return $this->_getBlockPost($iProfileId);
+    }
+
+    public function serviceGetBlockPostProfile($sProfileModule = 'bx_persons', $iProfileContentId = 0)
+    {
+        if(empty($sProfileModule))
+    		return array();
+
+    	if(empty($iProfileContentId) && bx_get('id') !== false)
+    		$iProfileContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+		$oProfile = BxDolProfile::getInstanceByContentAndType($iProfileContentId, $sProfileModule);
+		if(empty($oProfile))
+			return array();
+
+		return $this->_getBlockPost($oProfile->id());
+    }
+
+    public function serviceGetBlockPostHome()
+    {
+        $iProfileId = 0;
+        return $this->_getBlockPost($iProfileId);
+    }
+
+    /*
+     * Get View block for a separate page. Will return a block with "Empty" message if nothing found.
+     */
+    public function serviceGetBlockView($iProfileId = 0)
+    {
+    	return $this->_serviceGetBlockView($iProfileId, BX_TIMELINE_VIEW_TIMELINE);
+    }
+
+    public function serviceGetBlockViewOutline($iProfileId = 0)
+    {
+        return $this->_serviceGetBlockView($iProfileId, BX_TIMELINE_VIEW_OUTLINE);
+    }
+
+    public function serviceGetBlockViewProfile($sProfileModule = 'bx_persons', $iProfileContentId = 0, $iStart = -1, $iPerPage = -1, $sFilter = '', $aModules = array(), $iTimeline = -1)
+    {
+        $sView = BX_TIMELINE_VIEW_TIMELINE;
+
+        return $this->_serviceGetBlockViewProfile($sProfileModule, $iProfileContentId, $sView, $iStart, $iPerPage, $sFilter, $aModules, $iTimeline);
+    }
+
+	public function serviceGetBlockViewProfileOutline($sProfileModule = 'bx_persons', $iProfileContentId = 0, $iStart = -1, $iPerPage = -1, $sFilter = '', $aModules = array(), $iTimeline = -1)
+    {
+        $sView = BX_TIMELINE_VIEW_OUTLINE;
+
+        return $this->_serviceGetBlockViewProfile($sProfileModule, $iProfileContentId, $sView, $iStart, $iPerPage, $sFilter, $aModules, $iTimeline);
+    }
+
+    public function serviceGetBlockViewHome($iProfileId = 0, $iStart = -1, $iPerPage = -1, $iTimeline = -1, $sFilter = '', $aModules = array())
+    {
+        return $this->_serviceGetBlockViewHome($iProfileId, BX_TIMELINE_VIEW_TIMELINE, $iStart, $iPerPage, $this->_oConfig->getPerPage('home'), $iTimeline, $sFilter, $aModules);
+    }
+
+	public function serviceGetBlockViewHomeOutline($iProfileId = 0, $iStart = -1, $iPerPage = -1, $iTimeline = -1, $sFilter = '', $aModules = array())
+    {
+        return $this->_serviceGetBlockViewHome($iProfileId, BX_TIMELINE_VIEW_OUTLINE, $iStart, $iPerPage, $this->_oConfig->getPerPage('home'), $iTimeline, $sFilter, $aModules);
+    }
+
+    public function serviceGetBlockViewAccount($iProfileId = 0, $iStart = -1, $iPerPage = -1, $iTimeline = -1, $sFilter = '', $aModules = array())
+    {
+        return $this->_serviceGetBlockViewByType($iProfileId, BX_TIMELINE_VIEW_TIMELINE, BX_BASE_MOD_NTFS_TYPE_CONNECTIONS, $iStart, $iPerPage, $this->_oConfig->getPerPage('account'), $iTimeline, $sFilter, $aModules);
+    }
+
+    public function serviceGetBlockViewAccountOutline($iProfileId = 0, $iStart = -1, $iPerPage = -1, $iTimeline = -1, $sFilter = '', $aModules = array())
+    {
+        return $this->_serviceGetBlockViewByType($iProfileId, BX_TIMELINE_VIEW_OUTLINE, BX_BASE_MOD_NTFS_TYPE_CONNECTIONS, $iStart, $iPerPage, $this->_oConfig->getPerPage('account'), $iTimeline, $sFilter, $aModules);
+    }
+
+    public function serviceGetBlockItem()
+    {
+        $iItemId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if(!$iItemId)
+            return array();
+
+        return array('content' => $this->_oTemplate->getItemBlock($iItemId));
+    }
+
+	/**
+     * Data for Notifications module
+     */
+    public function serviceGetNotificationsData()
+    {
+    	$sModule = $this->_aModule['name'];
+
+        return array(
+            'handlers' => array(
+                array('group' => $sModule . '_object', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'post_common', 'module_name' => $sModule, 'module_method' => 'get_notifications_post', 'module_class' => 'Module'),
+                array('group' => $sModule . '_object', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'delete'),
+                array('group' => $sModule . '_repost', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'repost', 'module_name' => $sModule, 'module_method' => 'get_notifications_repost', 'module_class' => 'Module'),
+                array('group' => $sModule . '_repost', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'delete_repost'),
+                array('group' => $sModule . '_comment', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'commentPost', 'module_name' => $sModule, 'module_method' => 'get_notifications_comment', 'module_class' => 'Module'),
+                array('group' => $sModule . '_comment', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'commentRemoved'),
+                array('group' => $sModule . '_vote', 'type' => 'insert', 'alert_unit' => $sModule, 'alert_action' => 'doVote', 'module_name' => $sModule, 'module_method' => 'get_notifications_vote', 'module_class' => 'Module'),
+				array('group' => $sModule . '_vote', 'type' => 'delete', 'alert_unit' => $sModule, 'alert_action' => 'undoVote'),
+            ),
+            'alerts' => array(
+                array('unit' => $sModule, 'action' => 'post_common'),
+                array('unit' => $sModule, 'action' => 'delete'),
+                array('unit' => $sModule, 'action' => 'repost'),
+                array('unit' => $sModule, 'action' => 'delete_repost'),
+                array('unit' => $sModule, 'action' => 'commentPost'),
+                array('unit' => $sModule, 'action' => 'commentRemoved'),
+                array('unit' => $sModule, 'action' => 'doVote'),
+                array('unit' => $sModule, 'action' => 'undoVote'),
+            )
+        );
+    }
+
+    public function serviceGetNotificationsRepost($aEvent)
+    {
+        $aResult = $this->serviceGetNotificationsPost($aEvent);
+        $aResult['lang_key'] = '_bx_timeline_txt_object_reposted';
+
+        return $aResult;
+    }
+
+    public function serviceGetNotificationsPost($aEvent)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$iContent = (int)$aEvent['object_id'];
+		$aContent = $this->_oDb->getEvents(array('browse' => 'id', 'value' => $iContent));
+        if(empty($aContent) || !is_array($aContent))
+            return array();
+
+        $sEntryCaption = !empty($aContent['title']) ? $aContent['title'] : strmaxtextlen($aContent['description'], 20, '...');
+
+		return array(
+			'entry_sample' => $CNF['T']['txt_sample_single_ext'],
+			'entry_url' => $this->_oConfig->getItemViewUrl($aContent),
+			'entry_caption' => $sEntryCaption,
+			'entry_author' => $aContent['owner_id'],
+			'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+		);
+    }
+
+    public function serviceGetNotificationsComment($aEvent)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$iContent = (int)$aEvent['object_id'];
+    	$aContent = $this->_oDb->getEvents(array('browse' => 'id', 'value' => $iContent));
+        if(empty($aContent) || !is_array($aContent))
+            return array();
+
+		$oComment = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS'], $iContent);
+        if(!$oComment || !$oComment->isEnabled())
+            return array();
+
+        $sEntryCaption = !empty($aContent['title']) ? $aContent['title'] : strmaxtextlen($aContent['description'], 20, '...');
+
+		return array(
+			'entry_sample' => $CNF['T']['txt_sample_single'],
+			'entry_url' => $this->_oConfig->getItemViewUrl($aContent),
+			'entry_caption' => $sEntryCaption,
+			'entry_author' => $aContent['owner_id'],
+			'subentry_sample' => $CNF['T']['txt_sample_comment_single'],
+			'subentry_url' => $oComment->getViewUrl((int)$aEvent['subobject_id']),
+			'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+		);
+    }
+
+    public function serviceGetNotificationsVote($aEvent)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+    	$iContent = (int)$aEvent['object_id'];
+    	$aContent = $this->_oDb->getEvents(array('browse' => 'id', 'value' => $iContent));
+        if(empty($aContent) || !is_array($aContent))
+            return array();
+
+		$oVote = BxDolVote::getObjectInstance($CNF['OBJECT_VOTES'], $iContent);
+        if(!$oVote || !$oVote->isEnabled())
+            return array();
+
+        $sEntryCaption = !empty($aContent['title']) ? $aContent['title'] : strmaxtextlen($aContent['description'], 20, '...');
+
+		return array(
+			'entry_sample' => $CNF['T']['txt_sample_single'],
+			'entry_url' => $this->_oConfig->getItemViewUrl($aContent),
+			'entry_caption' => $sEntryCaption,
+			'entry_author' => $aContent['owner_id'],
+			'subentry_sample' => $CNF['T']['txt_sample_vote_single'],
+			'lang_key' => '', //may be empty or not specified. In this case the default one from Notification module will be used.
+		);
+    }
+
+    public function serviceGetRepostElementBlock($iOwnerId, $sType, $sAction, $iObjectId, $aParams = array())
+    {
+    	if(!$this->isEnabled())
+    		return '';
+
+        $aParams = array_merge($this->_oConfig->getRepostDefaults(), $aParams);
+        return $this->_oTemplate->getRepostElement($iOwnerId, $sType, $sAction, $iObjectId, $aParams);
+    }
+
+    public function serviceGetRepostCounter($sType, $sAction, $iObjectId)
+    {
+    	if(!$this->isEnabled())
+    		return '';
+
+		$aReposted = $this->_oDb->getReposted($sType, $sAction, $iObjectId);
+
+        return $this->_oTemplate->getRepostCounter($aReposted);
+    }
+
+    public function serviceGetRepostJsScript()
+    {
+    	if(!$this->isEnabled())
+    		return '';
+
+        return $this->_oTemplate->getRepostJsScript();
+    }
+
+    public function serviceGetRepostJsClick($iOwnerId, $sType, $sAction, $iObjectId)
+    {
+    	if(!$this->isEnabled())
+    		return '';
+
+        return $this->_oTemplate->getRepostJsClick($iOwnerId, $sType, $sAction, $iObjectId);
+    }
+
+    public function serviceGetMenuItemAddonComment($sSystem, $iObjectId)
+    {
+        if(empty($sSystem) || empty($iObjectId))
+            return '';
+
+        $oCmts = $this->getCmtsObject($sSystem, $iObjectId);
+        if($oCmts === false)
+            return '';
+
+        $iCounter = (int)$oCmts->getCommentsCount();
+        return  $this->_oTemplate->parseHtmlByName('bx_a.html', array(
+            'href' => 'javascript:void(0)',
+            'title' => _t('_bx_timeline_menu_item_title_item_comment'),
+            'bx_repeat:attrs' => array(
+                array('key' => 'onclick', 'value' => "javascript:" . $this->_oConfig->getJsObject('view') . ".commentItem(this, '" . $sSystem . "', " . $iObjectId . ")")
+            ),
+            'content' => $iCounter > 0 ? $iCounter : ''
+        ));
+    }
+
+    public function serviceGetSettingsCheckerHelper()
+    {
+        bx_import('FormCheckerHelper', $this->_aModule);
+        return 'BxTimelineFormCheckerHelper';
+    }
+
+    /*
+     * COMMON METHODS
+     */
+    public function deleteEvent($aEvent)
+    {
+    	if(empty($aEvent) || !is_array($aEvent) || !$this->_oDb->deleteEvent(array('id' => (int)$aEvent['id'])))
+            return false;
+
+        $this->onDelete($aEvent);
+        return true;
+    }
+
+    public function getFormAttachLink()
+    {
+        $iUserId = $this->getUserId();
+
+        $oForm = BxDolForm::getObjectInstance($this->_oConfig->getObject('form_attach_link'), $this->_oConfig->getObject('form_display_attach_link_add'), $this->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'add_attach_link/';
+        $oForm->aInputs['url']['checker']['params']['preg'] = $this->_oConfig->getPregPattern('url');
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $sLink = $oForm->getCleanValue('url');
+
+            $aMatches = array();
+            preg_match($this->_oConfig->getPregPattern('url'), $sLink, $aMatches);
+            $sLink = (empty($aMatches[2]) ? 'http://' : '') . $aMatches[0];
+
+            $aSiteInfo = bx_get_site_info($sLink, array(
+                'thumbnailUrl' => array('tag' => 'link', 'content_attr' => 'href'),
+                'OGImage' => array('name_attr' => 'property', 'name' => 'og:image'),
+            ));
+
+            $sTitle = !empty($aSiteInfo['title']) ? $aSiteInfo['title'] : _t('_Empty');
+            $sDescription = !empty($aSiteInfo['description']) ? $aSiteInfo['description'] : _t('_Empty');
+
+            $sMediaUrl = '';
+            if(!empty($aSiteInfo['thumbnailUrl']))
+            	$sMediaUrl = $aSiteInfo['thumbnailUrl'];
+            else if(!empty($aSiteInfo['OGImage']))
+            	$sMediaUrl = $aSiteInfo['OGImage'];
+
+			$iMediaId = 0;
+			$oStorage = null;
+            if(!empty($sMediaUrl)) {
+            	$oStorage = BxDolStorage::getObjectInstance($this->_oConfig->getObject('storage_' . BX_TIMELINE_MEDIA_PHOTO . 's'));
+
+            	$iMediaId = $oStorage->storeFileFromUrl($sMediaUrl, true, $iUserId);
+            }
+
+            $iId = (int)$oForm->insert(array('profile_id' => $iUserId, 'media_id' => $iMediaId, 'url' => $sLink, 'title' => $sTitle, 'text' => $sDescription, 'added' => time()));
+            if(!empty($iId)) {
+            	if(!empty($oStorage) && !empty($iMediaId))
+            		$oStorage->afterUploadCleanup($iMediaId, $iUserId);
+
+                return array('item' => $this->_oTemplate->getAttachLinkItem($iUserId, $iId));
+            }
+
+            return array('msg' => _t('_bx_timeline_txt_err_cannot_perform_action'));
+        }
+
+        return array('form' => $oForm->getCode(), 'form_id' => $oForm->id);
+    }
+
+    public function getFormPost()
+    {
+        $iUserId = $this->getUserId();
+
+        $oForm = BxDolForm::getObjectInstance($this->_oConfig->getObject('form_post'), $this->_oConfig->getObject('form_display_post_add'), $this->_oTemplate);
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            list($sUserName) = $this->getUserInfo($iUserId);
+
+            $sType = $oForm->getCleanValue('type');
+            $sType = $this->_oConfig->getPrefix('common_post') . $sType;
+            BxDolForm::setSubmittedValue('type', $sType, $oForm->aFormAttrs['method']);
+
+            $aContent = array();
+
+            //--- Process Text ---//
+            $sText = $oForm->getCleanValue('text');
+            $sText = $this->_prepareTextForSave($sText);
+            $bText = !empty($sText);
+            unset($oForm->aInputs['text']);
+
+            if($bText)
+            	$aContent['text'] = $sText;
+
+            //--- Process Link ---//
+            $aLinkIds = $oForm->getCleanValue('link');
+            $bLinkIds = !empty($aLinkIds) && is_array($aLinkIds);
+
+            //--- Process Media ---//
+            $aPhotoIds = $oForm->getCleanValue(BX_TIMELINE_MEDIA_PHOTO);
+            $bPhotoIds = !empty($aPhotoIds) && is_array($aPhotoIds);
+
+            $aVideoIds = $oForm->getCleanValue(BX_TIMELINE_MEDIA_VIDEO);
+            $bVideoIds = !empty($aVideoIds) && is_array($aVideoIds);
+
+            if(!$bText && !$bLinkIds && !$bPhotoIds && !$bVideoIds)
+            	return array('msg' => _t('_bx_timeline_txt_err_empty_post'));
+
+            $sTitle = _t('_bx_timeline_txt_user_added_sample', $sUserName, _t('_bx_timeline_txt_sample'));
+            $sDescription = $bText ? $sText : '';
+
+            $iId = $oForm->insert(array(
+                'object_id' => $iUserId,
+                'object_privacy_view' => $this->_oConfig->getPrivacyViewDefault('object'),
+                'content' => serialize($aContent),
+                'title' => $sTitle,
+                'description' => $sDescription,
+                'date' => time()
+            ));
+
+            if(!empty($iId)) {
+            	$oMetatags = BxDolMetatags::getObjectInstance($this->_oConfig->getObject('metatags'));
+            	if($bText)
+ 					$oMetatags->keywordsAdd($iId, $sText);
+ 				$oMetatags->locationsAddFromForm($iId, $this->_oConfig->CNF['FIELD_LOCATION_PREFIX']);
+
+				//--- Process Link ---//
+                if($bLinkIds)
+                    foreach($aLinkIds as $iLinkId)
+                        $this->_oDb->saveLink($iId, $iLinkId);
+
+				//--- Process Media ---//
+				if($bPhotoIds) 
+					$this->_saveMedia(BX_TIMELINE_MEDIA_PHOTO, $iId, $aPhotoIds);
+
+				if($bVideoIds)
+					$this->_saveMedia(BX_TIMELINE_MEDIA_VIDEO, $iId, $aVideoIds);
+
+                $this->onPost($iId);
+
+                return array('id' => $iId);
+            }
+
+            return array('msg' => _t('_bx_timeline_txt_err_cannot_perform_action'));
+        }
+
+        return array('form' => $oForm->getCode(), 'form_id' => $oForm->id);
+    }
+
+    public function getCmtsObject($sSystem, $iId)
+    {
+        if(empty($sSystem) || (int)$iId == 0)
+            return false;
+
+        $oCmts = BxDolCmts::getObjectInstance($sSystem, $iId, true, $this->_oTemplate);
+        if(!$oCmts || !$oCmts->isEnabled())
+            return false;
+
+        return $oCmts;
+    }
+
+    public function getViewObject($sSystem, $iId)
+    {
+        if(empty($sSystem) || (int)$iId == 0)
+            return false;
+
+        $oView = BxDolView::getObjectInstance($sSystem, $iId, true, $this->_oTemplate);
+        if(!$oView || !$oView->isEnabled())
+            return false;
+
+        return $oView;
+    }
+
+    public function getVoteObject($sSystem, $iId)
+    {
+        if(empty($sSystem) || (int)$iId == 0)
+            return false;
+
+        $oVote = BxDolVote::getObjectInstance($sSystem, $iId, true, $this->_oTemplate);
+        if(!$oVote || !$oVote->isEnabled())
+            return false;
+
+        return $oVote;
+    }
+
+	public function getReportObject($sSystem, $iId)
+    {
+        if(empty($sSystem) || (int)$iId == 0)
+            return false;
+
+        $oReport = BxDolReport::getObjectInstance($sSystem, $iId, true, $this->_oTemplate);
+        if(!$oReport || !$oReport->isEnabled())
+            return false;
+
+        return $oReport;
+    }
+
+    public function getAttachmentsMenuObject()
+    {
+        $oMenu = BxDolMenu::getObjectInstance($this->_oConfig->getObject('menu_post_attachments'), $this->_oTemplate);
+        $oMenu->addMarkers(array(
+            'js_object' => $this->_oConfig->getJsObject('post'),
+        ));
+
+        return $oMenu;
+    }
+
+    public function getManageMenuObject()
+    {
+        return BxDolMenu::getObjectInstance($this->_oConfig->getObject('menu_item_manage'), $this->_oTemplate);
+    }
+
+    //--- Check permissions methods ---//
+    public function isAllowedPost($bPerform = false)
+    {
+        if(isAdmin())
+            return true;
+
+        $iUserId = $this->getUserId();
+        $aCheckResult = checkActionModule($iUserId, 'post', $this->getName(), $bPerform);
+
+        $oProfileOwner = BxDolProfile::getInstance($this->_iOwnerId);
+        if($oProfileOwner !== false)
+            bx_alert($oProfileOwner->getModule(), $this->_oConfig->getUri() . '_post', $oProfileOwner->id(), $iUserId, array('check_result' => &$aCheckResult));
+
+        return $aCheckResult[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED ? $aCheckResult[CHECK_ACTION_MESSAGE] : true;
+    }
+
+    public function isAllowedDelete($aEvent, $bPerform = false)
+    {
+        if(!isLogged())
+            return false;
+
+        if(isAdmin())
+            return true;
+
+        $iUserId = (int)$this->getUserId();
+        if((int)$aEvent['owner_id'] == $iUserId && $this->_oConfig->isAllowDelete())
+           return true;
+
+        $aCheckResult = checkActionModule($iUserId, 'delete', $this->getName(), $bPerform);
+
+        $oProfileOwner = BxDolProfile::getInstance((int)$aEvent['owner_id']);
+        if($oProfileOwner !== false)
+            bx_alert($oProfileOwner->getModule(), $this->_oConfig->getUri() . '_delete', $oProfileOwner->id(), $iUserId, array('check_result' => &$aCheckResult));
+
+        return $aCheckResult[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED ? $aCheckResult[CHECK_ACTION_MESSAGE] : true;
+    }
+
+    public function isAllowedComment($aEvent, $bPerform = false)
+    {
+        $mixedComments = $this->getCommentsData($aEvent['comments']);
+        if($mixedComments === false)
+            return false;
+
+        list($sSystem, $iObjectId) = $mixedComments;
+        $oCmts = $this->getCmtsObject($sSystem, $iObjectId);
+        $oCmts->addCssJs();
+
+        $bResult = true;
+
+        $oProfileOwner = BxDolProfile::getInstance($aEvent['owner_id']);
+        if($oProfileOwner !== false)
+            bx_alert($oProfileOwner->getModule(), $this->_oConfig->getUri() . '_comment', $oProfileOwner->id(), (int)$this->getUserId(), array('result' => &$bResult));
+
+        return $bResult;
+    }
+
+    public function isAllowedViewCounter($aEvent, $bPerform = false)
+    {
+        $mixedViews = $this->getViewsData($aEvent['views']);
+        if($mixedViews === false)
+            return false;
+
+        list($sSystem, $iObjectId) = $mixedViews;
+        $oView = $this->getViewObject($sSystem, $iObjectId);
+
+        $bResult = true;
+
+        $oProfileOwner = BxDolProfile::getInstance($aEvent['owner_id']);
+        if($oProfileOwner !== false)
+            bx_alert($oProfileOwner->getModule(), $this->_oConfig->getUri() . '_view_counter', $oProfileOwner->id(), (int)$this->getUserId(), array('result' => &$bResult));
+
+        return $bResult;
+    }
+
+    public function isAllowedVote($aEvent, $bPerform = false)
+    {
+        $mixedVotes = $this->getVotesData($aEvent['votes']);
+        if($mixedVotes === false)
+            return false;
+
+        list($sSystem, $iObjectId) = $mixedVotes;
+        $oVote = $this->getVoteObject($sSystem, $iObjectId);
+        $oVote->addCssJs();
+
+        $bResult = true;
+
+        $oProfileOwner = BxDolProfile::getInstance($aEvent['owner_id']);
+        if($oProfileOwner !== false)
+            bx_alert($oProfileOwner->getModule(), $this->_oConfig->getUri() . '_vote', $oProfileOwner->id(), (int)$this->getUserId(), array('result' => &$bResult));
+
+        return $bResult;
+    }
+
+    public function isAllowedReport($aEvent, $bPerform = false)
+    {
+        $mixedReports = $this->getReportsData($aEvent['reports']);
+        if($mixedReports === false)
+            return false;
+
+        list($sSystem, $iObjectId) = $mixedReports;
+        $oReport = $this->getReportObject($sSystem, $iObjectId);
+        $oReport->addCssJs();
+
+        $bResult = true;
+
+        $oProfileOwner = BxDolProfile::getInstance($aEvent['owner_id']);
+        if($oProfileOwner !== false)
+            bx_alert($oProfileOwner->getModule(), $this->_oConfig->getUri() . '_report', $oProfileOwner->id(), (int)$this->getUserId(), array('result' => &$bResult));
+
+        return $bResult;
+    }
+
+    public function isAllowedRepost($aEvent, $bPerform = false)
+    {
+        if(isAdmin())
+            return true;
+
+        $iUserId = (int)$this->getUserId();
+        if($iUserId == 0)
+            return false;
+
+        $aCheckResult = checkActionModule($iUserId, 'repost', $this->getName(), $bPerform);
+
+        $oProfileOwner = BxDolProfile::getInstance($aEvent['owner_id']);
+        if($oProfileOwner !== false)
+            bx_alert($oProfileOwner->getModule(), $this->_oConfig->getUri() . '_repost', $oProfileOwner->id(), $iUserId, array('check_result' => &$aCheckResult));
+
+        return $aCheckResult[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED ? $aCheckResult[CHECK_ACTION_MESSAGE] : true;
+    }
+
+    public function isAllowedSend($aEvent, $bPerform = false)
+    {
+        if(isAdmin())
+            return true;
+
+        $iUserId = (int)$this->getUserId();
+        if($iUserId == 0)
+            return false;
+
+        $aCheckResult = checkActionModule($iUserId, 'send', $this->getName(), $bPerform);
+
+        $oProfileOwner = BxDolProfile::getInstance($aEvent['owner_id']);
+        if($oProfileOwner !== false)
+            bx_alert($oProfileOwner->getModule(), $this->_oConfig->getUri() . '_send', $oProfileOwner->id(), $iUserId, array('check_result' => &$aCheckResult));
+
+        return $aCheckResult[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED ? $aCheckResult[CHECK_ACTION_MESSAGE] : true;
+    }
+
+	public function isAllowedPin($aEvent, $bPerform = false)
+    {
+    	if((int)$aEvent['pinned'] != 0)
+    		return false;
+
+        return $this->_isAllowedPin($aEvent, $bPerform);
+    }
+
+	public function isAllowedUnpin($aEvent, $bPerform = false)
+    {
+    	if((int)$aEvent['pinned'] == 0)
+    		return false;
+
+        return $this->_isAllowedPin($aEvent, $bPerform);
+    }
+
+    public function isAllowedMore($aEvent, $bPerform = false)
+    {
+    	$oMoreMenu = $this->getManageMenuObject();
+    	$oMoreMenu->setEventId($aEvent['id']);
+    	return $oMoreMenu->isVisible();
+    }
+
+    public function onPost($iId)
+    {
+        $aEvent = $this->_oDb->getEvents(array('browse' => 'id', 'value' => $iId));
+
+        if($this->_oConfig->isSystem($aEvent['type'], $aEvent['action'])) {
+            $sPostType = 'system';
+            $iSenderId = $aEvent['owner_id'];
+        } else {
+            $sPostType = 'common';
+            $iSenderId = $aEvent['object_id'];
+        }
+
+        //--- Event -> Post for Alerts Engine ---//
+        $oAlert = new BxDolAlerts($this->_oConfig->getObject('alert'), 'post_' . $sPostType, $iId, $iSenderId, array(
+        	'object_author_id' => $aEvent['owner_id']
+        ));
+        $oAlert->alert();
+        //--- Event -> Post for Alerts Engine ---//
+    }
+
+    public function onRepost($iId, $aReposted = array())
+    {
+        $aEvent = $this->_oDb->getEvents(array('browse' => 'id', 'value' => $iId));
+
+        if(empty($aReposted)) {
+            $aContent = unserialize($aEvent['content']);
+
+            $aReposted = $this->_oDb->getReposted($aContent['type'], $aContent['action'], $aContent['object_id']);
+            if(empty($aReposted) || !is_array($aReposted))
+                return;
+        }
+
+        $iUserId = $this->getUserId();
+        $this->_oDb->insertRepostTrack($aEvent['id'], $iUserId, $this->getUserIp(), $aReposted['id']);
+        $this->_oDb->updateRepostCounter($aReposted['id'], $aReposted['reposts']);
+
+        //--- Timeline -> Update for Alerts Engine ---//
+        $oAlert = new BxDolAlerts($this->_oConfig->getObject('alert'), 'repost', $aReposted['id'], $iUserId, array(
+        	'repost_id' => $iId,
+        	'object_author_id' => $aReposted['owner_id'],
+        ));
+        $oAlert->alert();
+        //--- Timeline -> Update for Alerts Engine ---//
+    }
+
+    public function onDelete($aEvent)
+    {
+        $iUserId = $this->getUserId();
+    	$sCommonPostPrefix = $this->_oConfig->getPrefix('common_post');
+
+    	//--- Delete attached photos, videos and links when common event was deleted.
+    	if($aEvent['type'] == $sCommonPostPrefix . BX_TIMELINE_PARSE_TYPE_POST) {
+    		$this->_deleteMedia(BX_TIMELINE_MEDIA_PHOTO, $aEvent['id']);
+    		$this->_deleteMedia(BX_TIMELINE_MEDIA_VIDEO, $aEvent['id']);
+
+	        $this->_deleteLinks($aEvent['id']);
+    	}
+
+    	//--- Update parent event when repost event was deleted.
+    	$bRepost = $aEvent['type'] == $sCommonPostPrefix . BX_TIMELINE_PARSE_TYPE_REPOST;
+        if($bRepost) {
+            $this->_oDb->deleteRepostTrack($aEvent['id']);
+
+            $aContent = unserialize($aEvent['content']);
+            $aReposted = $this->_oDb->getReposted($aContent['type'], $aContent['action'], $aContent['object_id']);
+            if(!empty($aReposted) && is_array($aReposted))
+                $this->_oDb->updateRepostCounter($aReposted['id'], $aReposted['reposts'], -1);
+        }
+
+        //--- Find and delete repost events when parent event was deleted.
+        $bSystem = $this->_oConfig->isSystem($aEvent['type'], $aEvent['action']);
+	    $aRepostEvents = $this->_oDb->getEvents(array('browse' => 'reposted_by_descriptor', 'type' => $aEvent['type']));
+		foreach($aRepostEvents as $aRepostEvent) {
+			$aContent = unserialize($aRepostEvent['content']);
+			if(isset($aContent['type']) && $aContent['type'] == $aEvent['type'] && isset($aContent['object_id']) && (($bSystem && (int)$aContent['object_id'] == (int)$aEvent['object_id']) || (!$bSystem  && (int)$aContent['object_id'] == (int)$aEvent['id'])) && (int)$this->_oDb->deleteEvent(array('id' => (int)$aRepostEvent['id'])) > 0) {
+                $oAlert = new BxDolAlerts($this->_oConfig->getObject('alert'), 'delete_repost', $aEvent['id'], $iUserId, array(
+                    'repost_id' => $aRepostEvent['id'],
+                ));
+                $oAlert->alert();
+            }
+		}
+
+		//--- Delete associated meta.
+        $oMetatags = BxDolMetatags::getObjectInstance($this->_oConfig->getObject('metatags'));
+        $oMetatags->onDeleteContent($aEvent['id']);
+
+        //--- Event -> Delete for Alerts Engine ---//
+        if($bRepost)
+            $oAlert = new BxDolAlerts($this->_oConfig->getObject('alert'), 'delete_repost', $aReposted['id'], $iUserId, array(
+                'repost_id' => $aEvent['id'],
+            ));
+        else
+            $oAlert = new BxDolAlerts($this->_oConfig->getObject('alert'), 'delete', $aEvent['id'], $iUserId);
+        $oAlert->alert();
+        //--- Event -> Delete for Alerts Engine ---//
+    }
+
+    public function getViewsData(&$aViews)
+    {
+        if(empty($aViews) || !is_array($aViews))
+            return false;
+
+        $sSystem = isset($aViews['system']) ? $aViews['system'] : '';
+        $iObjectId = isset($aViews['object_id']) ? (int)$aViews['object_id'] : 0;
+        $iCount = isset($aViews['count']) ? (int)$aViews['count'] : 0;
+        if($sSystem == '' || $iObjectId == 0)
+            return false;
+
+        return array($sSystem, $iObjectId, $iCount);
+    }
+
+    public function getVotesData(&$aVotes)
+    {
+        if(empty($aVotes) || !is_array($aVotes))
+            return false;
+
+        $sSystem = isset($aVotes['system']) ? $aVotes['system'] : '';
+        $iObjectId = isset($aVotes['object_id']) ? (int)$aVotes['object_id'] : 0;
+        $iCount = isset($aVotes['count']) ? (int)$aVotes['count'] : 0;
+        if($sSystem == '' || $iObjectId == 0)
+            return false;
+
+        return array($sSystem, $iObjectId, $iCount);
+    }
+
+    public function getReportsData(&$aReports)
+    {
+        if(empty($aReports) || !is_array($aReports))
+            return false;
+
+        $sSystem = isset($aReports['system']) ? $aReports['system'] : '';
+        $iObjectId = isset($aReports['object_id']) ? (int)$aReports['object_id'] : 0;
+        $iCount = isset($aReports['count']) ? (int)$aReports['count'] : 0;
+        if($sSystem == '' || $iObjectId == 0)
+            return false;
+
+        return array($sSystem, $iObjectId, $iCount);
+    }
+
+    public function getCommentsData(&$aComments)
+    {
+        if(empty($aComments) || !is_array($aComments))
+            return false;
+
+        $sSystem = isset($aComments['system']) ? $aComments['system'] : '';
+        $iObjectId = isset($aComments['object_id']) ? (int)$aComments['object_id'] : 0;
+        $iCount = isset($aComments['count']) ? (int)$aComments['count'] : 0;
+        if($sSystem == '' || $iObjectId == 0 || ($iCount == 0 && !isLogged()))
+            return false;
+
+        return array($sSystem, $iObjectId, $iCount);
+    }
+
+    /**
+     * Protected Methods 
+     */
+    protected function _serviceGetBlockView($iProfileId = 0, $sView = BX_TIMELINE_VIEW_DEFAULT)
+    {
+        if(empty($iProfileId) && bx_get('profile_id') !== false)
+			$iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+
+		if(empty($iProfileId) && isLogged())
+			$iProfileId = bx_get_logged_profile_id();
+
+        $aBlock = $this->_getBlockView($iProfileId, $sView);
+        if(!empty($aBlock))
+            return $aBlock;
+
+        return array('content' => MsgBox(_t('_bx_timeline_txt_msg_no_results')));
+    }
+
+    protected function _serviceGetBlockViewProfile($sProfileModule = 'bx_persons', $iProfileContentId = 0, $sView = BX_TIMELINE_VIEW_DEFAULT, $iStart = -1, $iPerPage = -1, $sFilter = '', $aModules = array(), $iTimeline = -1)
+    {
+    	if(empty($sProfileModule))
+    		return array();
+
+    	if(empty($iProfileContentId) && bx_get('id') !== false)
+    		$iProfileContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+		$oProfile = BxDolProfile::getInstanceByContentAndType($iProfileContentId, $sProfileModule);
+		if(empty($oProfile))
+			return array();
+
+        return $this->_getBlockView($oProfile->id(), $sView, $iStart, $iPerPage, $sFilter, $aModules, $iTimeline);
+    }
+
+    protected function _serviceGetBlockViewHome($iProfileId = 0, $sView = BX_TIMELINE_VIEW_DEFAULT, $iStart = -1, $iPerPage = -1, $iPerPageDefault = -1,  $iTimeline = -1, $sFilter = '', $aModules = array())
+    {
+        $sRssUrl = BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'rss/' . BX_BASE_MOD_NTFS_TYPE_PUBLIC . '/';
+        BxDolTemplate::getInstance()->addPageRssLink(_t('_bx_timeline_page_title_view_home'), $sRssUrl);
+
+        return $this->_serviceGetBlockViewByType($iProfileId, $sView, BX_BASE_MOD_NTFS_TYPE_PUBLIC, $iStart, $iPerPage, $this->_oConfig->getPerPage('home'), $iTimeline, $sFilter, $aModules);
+    } 
+
+    protected function _serviceGetBlockViewByType($iProfileId = 0, $sView = BX_TIMELINE_VIEW_DEFAULT, $sType = BX_TIMELINE_TYPE_DEFAULT, $iStart = -1, $iPerPage = -1, $iPerPageDefault = -1,  $iTimeline = -1, $sFilter = '', $aModules = array())
+    {
+        $aParams = $this->_prepareParams($sType, $iProfileId, $iStart, $iPerPage, $sFilter, $aModules, $iTimeline);
+
+        $aParams['view'] = $sView;
+        $aParams['per_page'] = (int)$iPerPage > 0 ? $iPerPage : ((int)$iPerPageDefault > 0 ? $iPerPageDefault : $this->_oConfig->getPerPage());
+
+        $this->_iOwnerId = $aParams['owner_id'];
+
+        $sContent = $this->_oTemplate->getViewBlock($aParams);
+        return array('content' => $sContent);
+    }
+
+    protected function _getBlockPost($iProfileId)
+    {
+        $this->_iOwnerId = $iProfileId;
+
+        if($this->isAllowedPost() !== true)
+            return array();
+
+		$sContent = $this->_oTemplate->getPostBlock($this->_iOwnerId);
+        return array('content' => $sContent);
+    }
+
+    protected function _getBlockView($iProfileId, $sView = BX_TIMELINE_VIEW_DEFAULT, $iStart = -1, $iPerPage = -1, $sFilter = '', $aModules = array(), $iTimeline = -1)
+    {
+        if(!$iProfileId)
+			return array();
+
+        $aParams = $this->_prepareParams(BX_BASE_MOD_NTFS_TYPE_OWNER, $iProfileId, $iStart, $iPerPage, $sFilter, $aModules, $iTimeline);
+
+        $aParams['view'] = $sView;
+        $aParams['per_page'] = (int)$iPerPage > 0 ? $iPerPage : $this->_oConfig->getPerPage('profile');
+
+        $this->_iOwnerId = $aParams['owner_id'];
+        list($sUserName, $sUserUrl) = $this->getUserInfo($aParams['owner_id']);
+
+        $sRssUrl = BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'rss/' . BX_BASE_MOD_NTFS_TYPE_OWNER . '/' . $iProfileId . '/';
+        $sJsObject = $this->_oConfig->getJsObject('view');
+        $aMenu = array(
+            array('id' => $sView . '-view-all', 'name' => $sView . '-view-all', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:' . $sJsObject . '.changeFilter(this)', 'target' => '_self', 'title' => _t('_bx_timeline_menu_item_view_all'), 'active' => 1),
+            array('id' => $sView . '-view-owner', 'name' => $sView . '-view-owner', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:' . $sJsObject . '.changeFilter(this)', 'target' => '_self', 'title' => _t('_bx_timeline_menu_item_view_owner', $sUserName)),
+            array('id' => $sView . '-view-other', 'name' => $sView . '-view-other', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:' . $sJsObject . '.changeFilter(this)', 'target' => '_self', 'title' => _t('_bx_timeline_menu_item_view_other')),
+            array('id' => $sView . '-get-rss', 'name' => $sView . '-get-rss', 'class' => '', 'link' => $sRssUrl, 'target' => '_blank', 'title' => _t('_bx_timeline_menu_item_get_rss')),
+        );
+
+        $sContent = '';
+        $oProfileOwner = BxDolProfile::getInstance($this->_iOwnerId);
+        bx_alert($oProfileOwner->getModule(), $this->_oConfig->getUri() . '_view', $this->_iOwnerId, $this->getUserId(), array('override_content' => &$sContent, 'params' => &$aParams, 'menu' => &$aMenu));
+
+        $oMenu = new BxTemplMenuInteractive(array('template' => 'menu_interactive_vertical.html', 'menu_id'=> $sView . '-view-all', 'menu_items' => $aMenu));
+        $oMenu->setSelected('', $sView . '-view-all');
+
+        if (!$sContent)
+            $sContent = $this->_oTemplate->getViewBlock($aParams);
+
+        BxDolTemplate::getInstance()->addPageRssLink(_t('_bx_timeline_page_title_view'), $sRssUrl);
+
+        return array('content' => $sContent, 'menu' => $oMenu);
+    }
+
+	protected function _isAllowedPin($aEvent, $bPerform = false)
+    {
+        if(isAdmin())
+            return true;
+
+        $iUserId = (int)$this->getUserId();
+        if($iUserId == 0)
+            return false;
+
+		if((int)$aEvent['owner_id'] == $iUserId)
+           return true;
+
+        $aCheckResult = checkActionModule($iUserId, 'pin', $this->getName(), $bPerform);
+
+        $oProfileOwner = BxDolProfile::getInstance($aEvent['owner_id']);
+        if($oProfileOwner !== false)
+            bx_alert($oProfileOwner->getModule(), $this->_oConfig->getUri() . '_pin', $oProfileOwner->id(), $iUserId, array('check_result' => &$aCheckResult));
+
+        return $aCheckResult[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED ? $aCheckResult[CHECK_ACTION_MESSAGE] : true;
+    }
+
+	protected function _deleteLinks($iId)
+    {
+	    $aLinks = $this->_oDb->getLinks($iId);
+	    if(empty($aLinks) || !is_array($aLinks))
+	    	return;
+
+		$oStorage = BxDolStorage::getObjectInstance($this->_oConfig->getObject('storage_photos'));
+		foreach($aLinks as $aLink)
+			if(!empty($aLink['media_id']))
+				$oStorage->deleteFile($aLink['media_id']);
+
+		$this->_oDb->deleteLinks($iId);
+    }
+
+    protected function _saveMedia($sType, $iId, $aItemIds)
+    {
+    	if(empty($aItemIds) || !is_array($aItemIds))
+    		return; 
+
+    	$iUserId = $this->getUserId();
+
+		$oStorage = BxDolStorage::getObjectInstance($this->_oConfig->getObject('storage_' . strtolower($sType) . 's'));
+		foreach($aItemIds as $iItemId)
+        	if($this->_oDb->saveMedia($sType, $iId, $iItemId))
+            	$oStorage->afterUploadCleanup($iItemId, $iUserId);
+    }
+
+    protected function _deleteMedia($sType, $iId)
+    {
+	    $aItems = $this->_oDb->getMedia($sType, $iId);
+	    if(empty($aItems) || !is_array($aItems))
+	    	return;
+
+		$oStorage = BxDolStorage::getObjectInstance($this->_oConfig->getObject('storage_' . strtolower($sType) . 's'));
+		foreach($aItems as $iItemId)
+			$oStorage->deleteFile($iItemId);
+
+		$this->_oDb->deleteMedia($sType, $iId);
+    }
+
+    protected function _prepareParams($sType, $iOwnerId, $iStart, $iPerPage, $sFilter, $aModules, $iTimeline)
+    {
+        return array(
+            'view' => BX_TIMELINE_VIEW_DEFAULT,
+
+            'browse' => 'list',
+            'type' => !empty($sType) ? $sType : BX_TIMELINE_TYPE_DEFAULT,
+            'owner_id' => (int)$iOwnerId != 0 ? $iOwnerId : $this->getUserId(),
+            'filter' => !empty($sFilter) ? $sFilter : BX_TIMELINE_FILTER_ALL,
+            'modules' => is_array($aModules) && !empty($aModules) ? $aModules : array(),
+            'timeline' => (int)$iTimeline > 0 ? $iTimeline : 0,
+            'active' => 1,
+            'hidden' => 0,
+
+            'start' => (int)$iStart > 0 ? $iStart : 0,
+            'per_page' => (int)$iPerPage > 0 ? $iPerPage : $this->_oConfig->getPerPage(),
+        );
+    }
+
+    protected function _prepareParamsGet()
+    {
+        $aParams = array(
+            'browse' => 'list',
+            'dynamic_mode' => true,
+        );
+
+        $aParams['view'] = bx_get('view');
+        $aParams['view'] = $aParams['view'] !== false ? bx_process_input($aParams['view'], BX_DATA_TEXT) : BX_TIMELINE_VIEW_DEFAULT;
+
+        $aParams['type'] = bx_get('type');
+        $aParams['type'] = $aParams['type'] !== false ? bx_process_input($aParams['type'], BX_DATA_TEXT) : BX_TIMELINE_TYPE_DEFAULT;
+
+        $aParams['owner_id'] = bx_get('owner_id');
+        $aParams['owner_id'] = $aParams['owner_id'] !== false ? bx_process_input($aParams['owner_id'], BX_DATA_INT) : $this->getUserId();
+
+        $aParams['start'] = bx_get('start');
+        $aParams['start'] = $aParams['start'] !== false ? bx_process_input($aParams['start'], BX_DATA_INT) : 0;
+
+        $aParams['per_page'] = bx_get('per_page');
+        $aParams['per_page'] = $aParams['per_page'] !== false ? bx_process_input($aParams['per_page'], BX_DATA_INT) : $this->_oConfig->getPerPage();
+
+        $aParams['filter'] = bx_get('filter');
+        $aParams['filter'] = $aParams['filter'] !== false ? bx_process_input($aParams['filter'], BX_DATA_TEXT) : BX_TIMELINE_FILTER_ALL;
+
+        $aParams['modules'] = bx_get('modules');
+        $aParams['modules'] = $aParams['modules'] !== false ? bx_process_input($aParams['modules'], BX_DATA_TEXT) : array();
+
+        $aParams['timeline'] = bx_get('timeline');
+        $aParams['timeline'] = $aParams['timeline'] !== false ? bx_process_input($aParams['timeline'], BX_DATA_INT) : 0;
+
+        $aParams['active'] = 1;
+        $aParams['hidden'] = 0;
+
+        return $aParams;
+    }
+
+    protected function _prepareTextForSave($s)
+    {
+        return bx_process_input($s, BX_DATA_TEXT_MULTILINE);
+    }
+}
+
+/** @} */

+ 66 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineSearchResult.php

@@ -0,0 +1,66 @@
+<?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 BxTimelineSearchResult extends BxBaseModNotificationsSearchResult
+{
+    function __construct($sMode = '', $aParams = array())
+    {
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_timeline',
+            'module_name' => 'bx_timeline',
+            'title' => _t('_bx_timeline_page_title_browse'),
+            'table' => 'bx_timeline_events',
+            'ownFields' => array('id', 'owner_id', 'type', 'action', 'object_id', 'object_privacy_view', 'content', 'title', 'description', 'rate', 'votes', 'comments', 'reports', 'reposts', 'date', 'active', 'hidden', 'pinned'),
+            'searchFields' => array('description'),
+            'restriction' => array(
+        		'internal' => array('value' => 'timeline_common_post', 'field' => 'type', 'operator' => '='),
+        		'active' => array('value' => '1', 'field' => 'active', 'operator' => '='),
+            ),
+            'paginate' => array('perPage' => getParam('bx_timeline_events_per_page'), 'start' => 0),
+            'sorting' => 'last',
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_timeline_filter';
+        $this->oModule = $this->getMain();
+
+        switch ($sMode) {
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_timeline');
+                $this->aCurrent['paginate']['perPage'] = 3;
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+
+        }
+
+        $this->setProcessPrivateContent(false);
+    }
+
+    function getAlterOrder()
+    {
+        $aSql = array();
+        switch ($this->aCurrent['sorting']) {
+            case 'last':
+                $aSql['order'] = ' ORDER BY `bx_timeline_events`.`date` DESC';
+                break;
+        }
+        return $aSql;
+    }
+}
+
+/** @} */

+ 1202 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/classes/BxTimelineTemplate.php

@@ -0,0 +1,1202 @@
+<?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 BxTimelineTemplate extends BxBaseModNotificationsTemplate
+{
+    protected $_bShowTimelineDividers;
+
+    function __construct(&$oConfig, &$oDb)
+    {
+        parent::__construct($oConfig, $oDb);
+
+        $this->_bShowTimelineDividers = false;
+    }
+
+    public function getCssJs()
+    {
+    	parent::getCssJs();
+
+        $this->addCss(array(
+        	BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'flickity/|flickity.css',
+            'jquery-ui/jquery-ui.css',
+            'post.css',
+            'repost.css',
+        ));
+        $this->addJs(array(
+            'jquery-ui/jquery-ui.custom.min.js',
+            'jquery.form.min.js',
+            'jquery.ba-resize.min.js',
+        	'autosize.min.js',
+            'masonry.pkgd.min.js',
+            'modernizr.js',
+        	'flickity/flickity.pkgd.min.js',
+            'post.js',
+            'repost.js',
+        ));
+    }
+
+    public function getPostBlock($iOwnerId)
+    {
+        $aForm = $this->getModule()->getFormPost();
+
+        return $this->parseHtmlByName('block_post.html', array (
+            'style_prefix' => $this->_oConfig->getPrefix('style'),
+            'js_object' => $this->_oConfig->getJsObject('post'),
+            'js_content' => $this->getJsCode('post', array(
+            	'oRequestParams' => array('owner_id' => $iOwnerId)
+        	)),
+            'form' => $aForm['form']
+        ));
+    }
+
+    public function getViewBlock($aParams)
+    {
+        list($sContent, $sLoadMore, $sBack, $sEmpty) = $this->getPosts($aParams);
+
+        return $this->parseHtmlByName('block_view.html', array(
+            'style_prefix' => $this->_oConfig->getPrefix('style'),
+        	'html_id' => $this->_oConfig->getHtmlIds('view', 'main_' . $aParams['view']),
+            'view' => $aParams['view'],
+            'back' => $sBack,
+            'empty' => $sEmpty, 
+            'content' => $sContent,
+            'load_more' =>  $sLoadMore,
+        	'view_image_popup' => $this->_getImagePopup($aParams),
+            'js_content' => $this->getJsCode('view', array(
+            	'oRequestParams' => array(
+	                'type' => $aParams['type'],
+	                'owner_id' => $aParams['owner_id'],
+	                'start' => $aParams['start'],
+	                'per_page' => $aParams['per_page'],
+	                'filter' => $aParams['filter'],
+	                'modules' => $aParams['modules'],
+	                'timeline' => $aParams['timeline'],
+        		)
+            )) . $this->getJsCode('repost')
+        ));
+    }
+
+    public function getItemBlock($iId)
+    {
+        $aEvent = $this->_oDb->getEvents(array('browse' => 'id', 'value' => $iId));
+        if(empty($aEvent))
+            return '';
+
+        $aParams = array(
+        	'view' => BX_TIMELINE_VIEW_DEFAULT, 
+        	'type' => BX_TIMELINE_TYPE_ITEM
+        );
+        $sContent = $this->getPost($aEvent, $aParams);
+
+        $oModule = $this->getModule();
+        if($oModule->isAllowedViewCounter($aEvent) !== true)
+            return '';
+
+        if(!$this->_oConfig->isSystem($aEvent['type'], $aEvent['action'])) {
+            $mixedViews = $oModule->getViewsData($aEvent['views']);
+            if($mixedViews !== false) {
+                list($sSystem, $iObjectId) = $mixedViews;
+                $oModule->getViewObject($sSystem, $iObjectId)->doView();
+            }
+        }
+
+        return $this->parseHtmlByName('block_item.html', array(
+            'style_prefix' => $this->_oConfig->getPrefix('style'),
+        	'html_id' => $this->_oConfig->getHtmlIds('view', 'main_item'),
+        	'content' => $sContent,
+        	'view_image_popup' => $this->_getImagePopup($aParams),
+            'js_content' => $this->getJsCode('view')
+        ));
+    }
+
+    public function getPost(&$aEvent, $aBrowseParams = array())
+    {
+        $aResult = $this->_oConfig->isSystem($aEvent['type'], $aEvent['action']) ? $this->_getSystemData($aEvent) : $this->_getCommonData($aEvent);
+        if(empty($aResult) || empty($aResult['owner_id']) || empty($aResult['content']))
+            return '';
+
+        list($sUserName) = $this->getModule()->getUserInfo($aResult['owner_id']);
+
+        $sSample = !empty($aResult['sample']) ? $aResult['sample'] : '_bx_timeline_txt_sample';
+        if(empty($aEvent['title']) || empty($aEvent['description'])) {
+            $sTitle = !empty($aResult['title']) ? $aResult['title'] : _t('_bx_timeline_txt_user_added_sample', $sUserName, _t($sSample));
+
+            $sDescription = !empty($aResult['description']) ? $aResult['description'] : '';
+            if($sDescription == '' && !empty($aResult['content']['text']))
+                $sDescription = $aResult['content']['text'];
+
+            $this->_oDb->updateEvent(array(
+                'title' => bx_process_input(strip_tags($sTitle)),
+                'description' => bx_process_input(strip_tags($sDescription))
+            ), array('id' => $aEvent['id']));
+        }
+
+        $aEvent['object_owner_id'] = $aResult['owner_id'];
+        $aEvent['icon'] = !empty($aResult['icon']) ? $aResult['icon'] : '';
+        $aEvent['sample'] = $sSample;
+        $aEvent['sample_action'] = !empty($aResult['sample_action']) ? $aResult['sample_action'] : '_bx_timeline_txt_added_sample';
+        $aEvent['content'] = $aResult['content'];
+        $aEvent['views'] = $aResult['views'];
+        $aEvent['votes'] = $aResult['votes'];
+        $aEvent['reports'] = $aResult['reports'];
+        $aEvent['comments'] = $aResult['comments'];
+
+        $sType = !empty($aResult['content_type']) ? $aResult['content_type'] : BX_TIMELINE_PARSE_TYPE_DEFAULT;
+        return $this->_getPost($sType, $aEvent, $aBrowseParams);
+    }
+
+    public function getPosts($aParams)
+    {
+        $bViewTimeline = $aParams['view'] == BX_TIMELINE_VIEW_TIMELINE;
+
+        $iStart = $aParams['start'];
+        $iPerPage = $aParams['per_page'];
+
+        $aParamsDb = $aParams;
+
+        //--- Check for Previous
+        $iDays = -1;
+        $bPrevious = false;
+        if($iStart - 1 >= 0) {
+            $aParamsDb['start'] -= 1;
+            $aParamsDb['per_page'] += 1;
+            $bPrevious = true;
+        }
+
+        //--- Check for Next
+        $aParamsDb['per_page'] += 1;
+        $aEvents = $this->_oDb->getEvents($aParamsDb);
+
+        //--- Check for Previous
+        if($bPrevious) {
+            $aEvent = array_shift($aEvents);
+            $iDays = (int)$aEvent['days'];
+        }
+
+        //--- Check for Next
+        $bNext = false;
+        if(count($aEvents) > $iPerPage) {
+            $aEvent = array_pop($aEvents);
+            $bNext = true;
+        }
+
+        $iEvents = count($aEvents);
+        $sContent = '';
+        if($bViewTimeline && $iEvents <= 0)
+        	$sContent .= $this->getDividerToday();
+
+        $bFirst = true;
+        foreach($aEvents as $aEvent) {
+            $sEvent = $this->getPost($aEvent, $aParams);
+            $bEvent = !empty($sEvent);
+            if(!$bEvent)
+                continue;
+
+            if($bViewTimeline && $bFirst) {
+                $sContent .= $this->getDividerToday($aEvent);
+                $bFirst = false;
+            }
+
+            $sContent .= $bViewTimeline && $bEvent ? $this->getDivider($iDays, $aEvent) : '';
+            $sContent .= $sEvent;
+        }
+
+        $sBack = $this->getBack($aParams);
+        $sLoadMore = $this->getLoadMore($aParams, $bNext, $iEvents > 0);
+        $sEmpty = $this->getEmpty($iEvents <= 0);
+        return array($sContent, $sLoadMore, $sBack, $sEmpty);
+    }
+
+    public function getEmpty($bVisible)
+    {
+        return $this->parseHtmlByName('empty.html', array(
+            'style_prefix' => $this->_oConfig->getPrefix('style'),
+            'visible' => $bVisible ? 'block' : 'none',
+            'content' => MsgBox(_t('_bx_timeline_txt_msg_no_results'))
+        ));
+    }
+
+    public function getDivider(&$iDays, &$aEvent)
+    {
+        if(!$this->_bShowTimelineDividers || $iDays == $aEvent['days'])
+            return '';
+
+        $iDays = $aEvent['days'];
+        $iDaysAgo = (int)$aEvent['ago_days'];
+        if($aEvent['today'] == $aEvent['days'] || (($aEvent['today'] - $aEvent['days']) == 1 && $iDaysAgo == 0))
+            return '';
+
+        return $this->parseHtmlByName('divider.html', array(
+        	'style_prefix' => $this->_oConfig->getPrefix('style'),
+            'type' => 'common',
+            'bx_if:show_hidden' => array(
+                'condition' => false,
+                'content' => array()
+            ),
+            'content' => bx_time_js($aEvent['date'])
+        ));
+    }
+
+    public function getDividerToday($aEvent = array())
+    {
+        if(!$this->_bShowTimelineDividers)
+            return '';
+
+    	$bToday = !empty($aEvent) && ($aEvent['today'] == $aEvent['days'] || (($aEvent['today'] - $aEvent['days']) == 1 && (int)$aEvent['ago_days'] == 0));
+
+        return $this->parseHtmlByName('divider.html', array(
+        	'style_prefix' => $this->_oConfig->getPrefix('style'),
+            'type' => 'today',
+        	'bx_if:show_hidden' => array(
+                'condition' => !$bToday,
+                'content' => array()
+            ),
+            'content' => _t('_bx_timeline_txt_today')
+        ));
+    }
+
+    public function getBack($aParams)
+    {
+        $iYearSel = (int)$aParams['timeline'];
+        if($iYearSel == 0)
+            return '';
+
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+        $sJsObject = $this->_oConfig->getJsObject('view');
+
+        $iYearNow = date('Y', time());
+        return $this->parseHtmlByName('back.html', array(
+            'style_prefix' => $sStylePrefix,
+            'href' => 'javascript:void(0)',
+            'title' => _t('_bx_timeline_txt_jump_to_n_year', $iYearNow),
+            'bx_repeat:attrs' => array(
+                array('key' => 'onclick', 'value' => 'javascript:' . $sJsObject . '.changeTimeline(this, 0)')
+            ),
+            'content' => _t('_bx_timeline_txt_jump_to_recent')
+        ));
+    }
+
+    public function getLoadMore($aParams, $bEnabled, $bVisible = true)
+    {
+        $iStart = $aParams['start'];
+        $iPerPage = $aParams['per_page'];
+        $iYearSel = (int)$aParams['timeline'];
+        $iYearMin = $this->_oDb->getMaxDuration($aParams);
+
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+        $sJsObject = $this->_oConfig->getJsObject('view');
+
+        $sYears = '';
+        if(!empty($iYearMin)) {
+            $iYearMax = date('Y', time()) - 1;
+            for($i = $iYearMax; $i >= $iYearMin; $i--)
+                $sYears .= ($i != $iYearSel ? $this->parseHtmlByName('bx_a.html', array(
+                    'href' => 'javascript:void(0)',
+                    'title' => _t('_bx_timeline_txt_jump_to_n_year', $i),
+                    'bx_repeat:attrs' => array(
+                        array('key' => 'onclick', 'value' => 'javascript:' . $sJsObject . '.changeTimeline(this, ' . $i . ')')
+                    ),
+                    'content' => $i
+                )) : $i) . ', ';
+
+            $sYears = substr($sYears, 0, -2);
+        }
+
+        $aTmplVars = array(
+            'style_prefix' => $sStylePrefix,
+            'visible' => ($aParams['view'] == BX_TIMELINE_VIEW_TIMELINE && $bVisible) || ($aParams['view'] == BX_TIMELINE_VIEW_OUTLINE && $bEnabled && $bVisible) ? 'block' : 'none',
+            'bx_if:is_disabled' => array(
+                'condition' => !$bEnabled,
+                'content' => array()
+            ),
+            'bx_if:show_on_click' => array(
+                'condition' => $bEnabled,
+                'content' => array(
+                    'on_click' => 'javascript:' . $sJsObject . '.changePage(this, ' . ($iStart + $iPerPage) . ', ' . $iPerPage . ')'
+                )
+            ),
+            'bx_if:show_jump_to' => array(
+                'condition' => !empty($sYears),
+                'content' => array(
+                    'style_prefix' => $sStylePrefix,
+                    'years' => $sYears
+                )
+            )
+        );
+        return $this->parseHtmlByName('load_more.html', $aTmplVars);
+    }
+
+    public function getComments($sSystem, $iId)
+    {
+        $oModule = $this->getModule();
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+
+        $oCmts = $oModule->getCmtsObject($sSystem, $iId);
+        if($oCmts === false)
+            return '';
+
+        $aComments = $oCmts->getCommentsBlock(0, 0, false);
+        return $this->parseHtmlByName('comments.html', array(
+            'style_prefix' => $sStylePrefix,
+            'id' => $iId,
+            'content' => $aComments['content']
+        ));
+    }
+
+    public function getRepostElement($iOwnerId, $sType, $sAction, $iObjectId, $aParams = array())
+    {
+        $aReposted = $this->_oDb->getReposted($sType, $sAction, $iObjectId);
+        if(empty($aReposted) || !is_array($aReposted))
+            return '';
+
+		$oModule = $this->getModule();
+		$bDisabled = $oModule->isAllowedRepost($aReposted) !== true || $this->_oDb->isReposted($aReposted['id'], $iOwnerId, $oModule->getUserId());
+		if($bDisabled && (int)$aReposted['reposts'] == 0)
+            return '';
+
+		$sStylePrefix = $this->_oConfig->getPrefix('style');
+        $sStylePrefixRepost = $sStylePrefix . '-repost-';
+
+        $bShowDoRepostAsButtonSmall = isset($aParams['show_do_repost_as_button_small']) && $aParams['show_do_repost_as_button_small'] == true;
+        $bShowDoRepostAsButton = !$bShowDoRepostAsButtonSmall && isset($aParams['show_do_repost_as_button']) && $aParams['show_do_repost_as_button'] == true;
+
+        $bShowDoRepostIcon = isset($aParams['show_do_repost_icon']) && $aParams['show_do_repost_icon'] == true;
+        $bShowDoRepostLabel = isset($aParams['show_do_repost_label']) && $aParams['show_do_repost_label'] == true;
+        $bShowCounter = isset($aParams['show_counter']) && $aParams['show_counter'] === true;
+
+        //--- Do repost link ---//
+		$sClass = $sStylePrefixRepost . 'do-repost';
+		if($bShowDoRepostAsButton)
+			$sClass .= ' bx-btn';
+		else if($bShowDoRepostAsButtonSmall)
+			$sClass .= ' bx-btn bx-btn-small';
+
+		$sOnClick = '';
+		if(!$bDisabled) {
+			$sCommonPrefix = $this->_oConfig->getPrefix('common_post');
+			if(str_replace($sCommonPrefix, '', $sType) == BX_TIMELINE_PARSE_TYPE_REPOST) {
+				$aRepostedData = $this->_getCommonData($aReposted);
+	
+	            $sOnClick = $this->_getRepostJsClick($iOwnerId, $aRepostedData['content']['type'], $aRepostedData['content']['action'], $aRepostedData['content']['object_id']);
+			}
+			else
+				$sOnClick = $this->_getRepostJsClick($iOwnerId, $sType, $sAction, $iObjectId);
+		}
+		else
+			$sClass .= $bShowDoRepostAsButton || $bShowDoRepostAsButtonSmall ? ' bx-btn-disabled' : ' ' . $sStylePrefixRepost . 'disabled';
+
+		$aOnClickAttrs = array();
+		if(!empty($sClass))
+			$aOnClickAttrs[] = array('key' => 'class', 'value' => $sClass);
+		if(!empty($sOnClick))
+			$aOnClickAttrs[] = array('key' => 'onclick', 'value' => $sOnClick);
+
+		$sDoRepost = '';
+        if($bShowDoRepostIcon)
+            $sDoRepost .= $this->parseHtmlByName('bx_icon.html', array('name' => 'repeat'));
+
+        if($bShowDoRepostLabel)
+            $sDoRepost .= ($sDoRepost != '' ? ' ' : '') . _t('_bx_timeline_txt_do_repost');
+
+        return $this->parseHtmlByName('repost_element_block.html', array(
+            'style_prefix' => $sStylePrefix,
+            'html_id' => $this->_oConfig->getHtmlIds('repost', 'main') . $aReposted['id'],
+            'class' => ($bShowDoRepostAsButton ? $sStylePrefixRepost . 'button' : '') . ($bShowDoRepostAsButtonSmall ? $sStylePrefixRepost . 'button-small' : ''),
+            'count' => $aReposted['reposts'],
+            'do_repost' => $this->parseHtmlByName('bx_a.html', array(
+	            'href' => 'javascript:void(0)',
+	            'title' => _t('_bx_timeline_txt_do_repost'),
+	            'bx_repeat:attrs' => $aOnClickAttrs,
+	            'content' => $sDoRepost
+	        )),
+            'bx_if:show_counter' => array(
+                'condition' => $bShowCounter,
+                'content' => array(
+                    'style_prefix' => $sStylePrefix,
+        			'bx_if:show_hidden' => array(
+        				'condition' => (int)$aReposted['reposts'] == 0,
+        				'content' => array()
+        			),
+                    'counter' => $this->getRepostCounter($aReposted, $aParams)
+                )
+            ),
+            'script' => $this->getRepostJsScript()
+        ));
+    }
+
+    public function getRepostCounter($aEvent, $aParams = array())
+    {
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+        $sJsObject = $this->_oConfig->getJsObject('repost');
+
+        $bShowDoRepostAsButtonSmall = isset($aParams['show_do_repost_as_button_small']) && $aParams['show_do_repost_as_button_small'] == true;
+        $bShowDoRepostAsButton = !$bShowDoRepostAsButtonSmall && isset($aParams['show_do_repost_as_button']) && $aParams['show_do_repost_as_button'] == true;
+
+        $sClass = $sStylePrefix . '-repost-counter';
+        if($bShowDoRepostAsButtonSmall)
+            $sClass .= ' bx-btn-small-height';
+        if($bShowDoRepostAsButton)
+            $sClass .= ' bx-btn-height';
+
+        return $this->parseHtmlByName('repost_counter.html', array(
+            'href' => 'javascript:void(0)',
+            'title' => _t('_bx_timeline_txt_reposted_by'),
+            'bx_repeat:attrs' => array(
+                array('key' => 'id', 'value' => $this->_oConfig->getHtmlIds('repost', 'counter') . $aEvent['id']),
+                array('key' => 'class', 'value' => $sClass),
+                array('key' => 'onclick', 'value' => 'javascript:' . $sJsObject . '.toggleByPopup(this, ' . $aEvent['id'] . ')')
+            ),
+            'content' => !empty($aEvent['reposts']) && (int)$aEvent['reposts'] > 0 ? $aEvent['reposts'] : ''
+        ));
+    }
+
+    public function getRepostedBy($iId)
+    {
+        $aTmplUsers = array();
+        $oModule = $this->getModule();
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+
+        $aUserIds = $this->_oDb->getRepostedBy($iId);
+        foreach($aUserIds as $iUserId) {
+            list($sUserName, $sUserUrl, $sUserIcon, $sUserUnit) = $oModule->getUserInfo($iUserId);
+            $aTmplUsers[] = array(
+                'style_prefix' => $sStylePrefix,
+                'user_unit' => $sUserUnit
+            );
+        }
+
+        if(empty($aTmplUsers))
+            $aTmplUsers = MsgBox(_t('_Empty'));
+
+        return $this->parseHtmlByName('repost_by_list.html', array(
+            'style_prefix' => $sStylePrefix,
+            'bx_repeat:list' => $aTmplUsers
+        ));
+    }
+
+    public function getRepostJsScript()
+    {
+        $this->addCss(array('repost.css'));
+        $this->addJs(array('main.js', 'repost.js'));
+
+        return $this->getJsCode('repost');
+    }
+
+    public function getRepostJsClick($iOwnerId, $sType, $sAction, $iObjectId)
+    {
+        $aReposted = $this->_oDb->getReposted($sType, $sAction, $iObjectId);
+        if(empty($aReposted) || !is_array($aReposted))
+            return '';
+
+        $sResult = '';
+        $sCommonPrefix = $this->_oConfig->getPrefix('common_post');
+        if(str_replace($sCommonPrefix, '', $sType) == BX_TIMELINE_PARSE_TYPE_REPOST) {
+            $aRepostedData = $this->_getCommonData($aReposted);
+
+            $sResult = $this->_getRepostJsClick($iOwnerId, $aRepostedData['content']['type'], $aRepostedData['content']['action'], $aRepostedData['content']['object_id']);
+        }
+        else
+            $sResult = $this->_getRepostJsClick($iOwnerId, $sType, $sAction, $iObjectId);
+
+        return $sResult;
+    }
+
+    public function getAttachLinkForm()
+    {
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+        $sJsObject = $this->_oConfig->getJsObject('post');
+
+        $aForm = $this->getModule()->getFormAttachLink();
+
+        return $this->parseHtmlByName('attach_link_form.html', array(
+            'style_prefix' => $sStylePrefix,
+            'js_object' => $sJsObject,
+            'form_id' => $aForm['form_id'],
+            'form' => $aForm['form'],
+        ));
+    }
+
+    public function getAttachLinkField($iUserId)
+    {
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+
+        $aLinks = $this->_oDb->getUnusedLinks($iUserId);
+
+        $sLinks = '';
+        foreach($aLinks as $aLink)
+            $sLinks .= $this->getAttachLinkItem($iUserId, $aLink);
+
+        return $this->parsePageByName('attach_link_form_field.html', array(
+            'html_id' => $this->_oConfig->getHtmlIds('post', 'attach_link_form_field'),
+            'style_prefix' => $sStylePrefix,
+            'links' => $sLinks
+        ));
+    }
+
+    public function getAttachLinkItem($iUserId, $mixedLink)
+    {
+        $aLink = is_array($mixedLink) ? $mixedLink : $this->_oDb->getUnusedLinks($iUserId, (int)$mixedLink);
+        if(empty($aLink) || !is_array($aLink))
+            return '';
+
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+        $sJsObject = $this->_oConfig->getJsObject('post');
+        $sLinkIdPrefix = $this->_oConfig->getHtmlIds('post', 'attach_link_item');
+
+        $bTmplVarsEmbed = false;
+        $aTmplVarsEmbed = array();
+        $sEmbedlyKey = $this->_oDb->getParam('sys_embedly_api_key');
+        $sEmbedlyPattern = $this->_oDb->getParam('sys_embedly_api_pattern');
+        if(!empty($sEmbedlyKey) && !empty($sEmbedlyPattern) && preg_match($sEmbedlyPattern, $aLink['url'])) {
+            $bTmplVarsEmbed = true;
+            $aTmplVarsEmbed = array(
+                'style_prefix' => $sStylePrefix,
+            	'embed' => $this->parsePageByName('bx_a.html', array(
+            		'href' => $aLink['url'],
+            		'title' => bx_html_attribute($aLink['title']),
+            		'bx_repeat:attrs' => array(
+                        array('key' => 'class', 'value' => 'bx-link-embed')
+                    ),
+            		'content' => $aLink['title'],
+            	))
+            );
+        }
+        else {
+            $aLinkAttrs = array();
+            if(!$this->_oConfig->isEqualUrls(BX_DOL_URL_ROOT, $aLink['url'])) {
+                $aLinkAttrs[] = array('key' => 'target', 'value' => '_blank');
+    
+                if($this->_oDb->getParam('sys_add_nofollow') == 'on')
+            	    $aLinkAttrs[] = array('key' => 'rel', 'value' => 'nofollow');
+            }
+
+            $sThumbnail = "";
+            if((int)$aLink['media_id'] != 0)
+                $sThumbnail = BxDolTranscoderImage::getObjectInstance($this->_oConfig->getObject('transcoder_photos_preview'))->getFileUrl($aLink['media_id']);
+
+            $aTmplVarsEmbed = array(
+                'style_prefix' => $sStylePrefix,
+            	'bx_if:show_thumbnail' => array(
+            		'condition' => !empty($sThumbnail),
+            		'content' => array(
+            			'style_prefix' => $sStylePrefix,
+            			'thumbnail' => $sThumbnail
+            		)
+            	),
+    			'url' => $aLink['url'],
+            	'link' => $this->parsePageByName('bx_a.html', array(
+            		'href' => $aLink['url'],
+            		'title' => bx_html_attribute($aLink['title']),
+            		'bx_repeat:attrs' => $aLinkAttrs,
+            		'content' => $aLink['title'],
+            	))
+            );
+        }
+
+        return $this->parsePageByName('attach_link_item.html', array(
+            'html_id' => $sLinkIdPrefix . $aLink['id'],
+            'style_prefix' => $sStylePrefix,
+            'js_object' => $sJsObject,
+            'id' => $aLink['id'],
+        	'bx_if:show_embed_outer' => array(
+        		'condition' => $bTmplVarsEmbed,
+        		'content' => $aTmplVarsEmbed
+        	),
+        	'bx_if:show_embed_inner' => array(
+        		'condition' => !$bTmplVarsEmbed,
+        		'content' => $aTmplVarsEmbed
+            ),
+        ));
+    }
+
+    protected function _getPost($sType, $aEvent, $aBrowseParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oModule = $this->getModule();
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+        $sJsObject = $this->_oConfig->getJsObject('view');
+
+        list($sAuthorName, $sAuthorUrl, $sAuthorIcon) = $oModule->getUserInfo($aEvent['object_owner_id']);
+        $bAuthorIcon = !empty($sAuthorIcon);
+
+        $aTmplVarsMenuItemActions = $this->_getTmplVarsMenuItemActions($aEvent, $aBrowseParams);
+
+        $aTmplVarsTimelineOwner = array();
+        if(isset($aBrowseParams['type']) && $aBrowseParams['type'] == BX_BASE_MOD_NTFS_TYPE_CONNECTIONS)
+            $aTmplVarsTimelineOwner = $this->_getTmplVarsTimelineOwner($aEvent);
+
+        $bBrowseItem = isset($aBrowseParams['type']) && $aBrowseParams['type'] == BX_TIMELINE_TYPE_ITEM;
+        $bViewTimeline = isset($aBrowseParams['view']) && $aBrowseParams['view'] == BX_TIMELINE_VIEW_TIMELINE;
+
+        $oMetatags = BxDolMetatags::getObjectInstance($this->_oConfig->getObject('metatags'));
+ 		$sLocation = $oMetatags->locationsString($aEvent['id']);
+ 
+        $aTmplVars = array (
+            'style_prefix' => $sStylePrefix,
+            'js_object' => $sJsObject,
+        	'html_id' => $this->_oConfig->getHtmlIds('view', 'item_' . $aBrowseParams['view']) . $aEvent['id'],
+            'class' => $bBrowseItem || $bViewTimeline ? 'bx-tl-view-sizer' : 'bx-tl-grid-sizer',
+        	'class_content' => $bBrowseItem ? 'bx-def-color-bg-block' : 'bx-def-color-bg-box',
+            'id' => $aEvent['id'],
+            'bx_if:show_owner_icon' => array(
+                'condition' => $bAuthorIcon,
+                'content' => array(
+                    'owner_icon' => $sAuthorIcon
+                )
+            ),
+            'bx_if:show_owner_icon_empty' => array(
+                'condition' => !$bAuthorIcon,
+                'content' => array()
+            ),
+            'item_icon' => !empty($aEvent['icon']) ? $aEvent['icon'] : $CNF['ICON'],
+            'item_owner_url' => $sAuthorUrl,
+            'item_owner_title' => bx_html_attribute($sAuthorName),
+            'item_owner_name' => $sAuthorName,
+            'item_owner_action' => _t($aEvent['sample_action'], _t($aEvent['sample'])),
+            'bx_if:show_timeline_owner' => array(
+                'condition' => !empty($aTmplVarsTimelineOwner),
+                'content' => $aTmplVarsTimelineOwner
+            ),
+            'item_view_url' => $this->_oConfig->getItemViewUrl($aEvent),
+            'item_date' => bx_time_js($aEvent['date']),
+            'bx_if:show_pinned' => array(
+            	'condition' => (int)$aEvent['pinned'] != 0,
+            	'content' => array(
+            		'style_prefix' => $sStylePrefix,
+            	)
+            ),
+            'content' => is_string($aEvent['content']) ? $aEvent['content'] : $this->_getContent($sType, $aEvent, $aBrowseParams),
+            'bx_if:show_location' => array(
+            	'condition' => !empty($sLocation),
+            	'content' => array(
+            		'style_prefix' => $sStylePrefix,
+            		'location' => $sLocation
+            	)
+            ),
+            'bx_if:show_menu_item_actions' => array(
+                'condition' => !empty($aTmplVarsMenuItemActions),
+                'content' => $aTmplVarsMenuItemActions
+            ),
+            'comments' => $bBrowseItem ? $this->_getComments($aEvent['comments']) : '',
+        );
+
+        return $this->parseHtmlByName('item_' . $aBrowseParams['view'] . '.html', $aTmplVars);
+    }
+
+    protected function _getContent($sType, $aEvent, $aBrowseParams = array())
+    {
+        $sMethod = '_getTmplVarsContent' . ucfirst($sType);
+        if(!method_exists($this, $sMethod))
+            return '';
+
+		$aTmplVars = $this->$sMethod($aEvent, $aBrowseParams);
+		return $this->parseHtmlByName('type_' . $sType . '.html', $aTmplVars);
+    }
+
+    protected function _getComments($aComments)
+    {
+        $mixedComments = $this->getModule()->getCommentsData($aComments);
+        if($mixedComments === false)
+            return '';
+
+        list($sSystem, $iObjectId, $iCount) = $mixedComments;
+        return $this->getComments($sSystem, $iObjectId);
+    }
+
+    protected function _getImagePopup($aParams)
+    {
+        $sViewImagePopupId = $this->_oConfig->getHtmlIds('view', 'photo_popup_' . $aParams['view']);
+        $sViewImagePopupContent = $this->parseHtmlByName('popup_image.html', array(
+    		'image_url' => ''
+    	));
+
+    	return BxTemplFunctions::getInstance()->transBox($sViewImagePopupId, $sViewImagePopupContent, true);
+    }
+
+    protected function _getRepostJsClick($iOwnerId, $sType, $sAction, $iObjectId)
+    {
+        $sJsObject = $this->_oConfig->getJsObject('repost');
+        $sFormat = "%s.repostItem(this, %d, '%s', '%s', %d);";
+
+        $iOwnerId = !empty($iOwnerId) ? (int)$iOwnerId : $this->getModule()->getUserId(); //--- in whose timeline the content will be reposted
+        return sprintf($sFormat, $sJsObject, $iOwnerId, $sType, $sAction, (int)$iObjectId);
+    }
+
+    protected function _getTmplVarsMenuItemActions(&$aEvent, $aBrowseParams = array())
+    {
+        $oMenu = BxDolMenu::getObjectInstance($this->_oConfig->getObject('menu_item_actions'));
+        $oMenu->setEvent($aBrowseParams['view'], $aEvent);
+        $oMenu->setDynamicMode(isset($aBrowseParams['dynamic_mode']) && $aBrowseParams['dynamic_mode'] === true);
+
+        $sMenu = $oMenu->getCode();
+        if(empty($sMenu))
+            return array();
+
+        return array(
+            'style_prefix' => $this->_oConfig->getPrefix('style'),
+            'js_object' => $this->_oConfig->getJsObject('view'),
+            'menu_item_actions' => $sMenu
+        );
+    }
+
+    protected function _getTmplVarsTimelineOwner(&$aEvent)
+    {
+        $oModule = $this->getModule();
+
+        $aTmplVarsTimelineOwner = array();
+        if((int)$aEvent['owner_id'] != (int)$aEvent['object_owner_id']) {
+            list($sTimelineAuthorName, $sTimelineAuthorUrl) = $oModule->getUserInfo($aEvent['owner_id']);
+
+            $aTmplVarsTimelineOwner = array(
+            	'style_prefix' => $this->_oConfig->getPrefix('style'),
+                'owner_url' => $sTimelineAuthorUrl,
+                'owner_username' => $sTimelineAuthorName,
+            );
+        }
+
+        return $aTmplVarsTimelineOwner;
+    }
+
+    protected function _getTmplVarsContentPost($aEvent, $aBrowseParams = array())
+    {
+    	$aContent = &$aEvent['content'];
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+        $sJsObject = $this->_oConfig->getJsObject('view');
+
+        $bBrowseItem = isset($aBrowseParams['type']) && $aBrowseParams['type'] == BX_TIMELINE_TYPE_ITEM;
+
+        //--- Process Raw ---//
+        $sRaw = isset($aContent['raw']) ? $aContent['raw'] : '';
+
+        //--- Process Text ---//
+        $sUrl = isset($aContent['url']) ? bx_html_attribute($aContent['url']) : '';
+        $sTitle = $sTitleAttr = '';
+        if(isset($aContent['title'])) {
+            $sTitle = bx_process_output($aContent['title']);
+            $sTitleAttr = bx_html_attribute($aContent['title']);
+        }
+
+        if(!empty($sUrl) && !empty($sTitle))
+            $sTitle = $this->parseHtmlByName('bx_a.html', array(
+                'href' => $sUrl,
+                'title' => $sTitleAttr,
+                'bx_repeat:attrs' => array(
+                    array('key' => 'class', 'value' => $sStylePrefix . '-title')
+                ),
+                'content' => $sTitle
+            ));
+
+        $sText = isset($aContent['text']) ? $aContent['text'] : '';
+        $sTextMore = '';
+
+        if($bBrowseItem)
+        	 $sText = strip_tags($sText, '<br><br/><p>');
+        else {
+        	$sText = strip_tags($sText);
+
+        	$iMaxLength = $this->_oConfig->getCharsDisplayMax();
+        	if(strlen($sText) > $iMaxLength) {
+            	$iLength = strpos($sText, ' ', $iMaxLength);
+
+            	$sTextMore = trim(substr($sText, $iLength));
+            	$sText = trim(substr($sText, 0, $iLength));
+        	}
+
+            $sTextMore = nl2br($sTextMore);
+            $sText = nl2br($sText);
+        }
+
+        $sText = $this->_prepareTextForOutput($sText, $aEvent['id']);
+        $sTextMore = $this->_prepareTextForOutput($sTextMore, $aEvent['id']);
+
+        //--- Process Links ---//
+        $bAddNofollow = $this->_oDb->getParam('sys_add_nofollow') == 'on';
+
+        $aTmplVarsLinks = array();
+        if(!empty($aContent['links']))
+            foreach($aContent['links'] as $aLink) {
+                $bTmplVarsEmbed = false;
+                $aTmplVarsEmbed = array();
+                $sEmbedlyKey = $this->_oDb->getParam('sys_embedly_api_key');
+                $sEmbedlyPattern = $this->_oDb->getParam('sys_embedly_api_pattern');
+                if(!empty($sEmbedlyKey) && !empty($sEmbedlyPattern) && preg_match($sEmbedlyPattern, $aLink['url'])) {
+                    $bTmplVarsEmbed = true;
+                    $aTmplVarsEmbed = array(
+                        'style_prefix' => $sStylePrefix,
+                    	'embed' => $this->parsePageByName('bx_a.html', array(
+                    		'href' => $aLink['url'],
+                    		'title' => bx_html_attribute($aLink['title']),
+                    		'bx_repeat:attrs' => array(
+                                array('key' => 'class', 'value' => 'bx-link-embed')
+                            ),
+                    		'content' => $aLink['title'],
+                    	))
+                    );
+                }
+                else {
+                    $aLinkAttrs = array();
+                    if(!$this->_oConfig->isEqualUrls(BX_DOL_URL_ROOT, $aLink['url'])) {
+                        $aLinkAttrs[] = array('key' => 'target', 'value' => '_blank');
+    
+                        if($bAddNofollow)
+                    	    $aLinkAttrs[] = array('key' => 'rel', 'value' => 'nofollow');
+                    }
+
+                    $aTmplVarsEmbed = array(
+                        'bx_if:show_thumbnail' => array(
+                    		'condition' => !empty($aLink['thumbnail']),
+                    		'content' => array(
+                    			'style_prefix' => $sStylePrefix,
+                    			'thumbnail' => $aLink['thumbnail']
+                    		)
+                    	),
+                    	'link' => $this->parsePageByName('bx_a.html', array(
+    		        		'href' => $aLink['url'],
+    		        		'title' => $aLink['title'],
+    		        		'bx_repeat:attrs' => $aLinkAttrs,
+    		        		'content' => $aLink['title'],
+    		        	)),
+                        'bx_if:show_text' => array(
+                            'condition' => !empty($aLink['text']),
+                            'content' => array(
+                                'style_prefix' => $sStylePrefix,
+                                'text' => $aLink['text']
+                            )
+                        )
+                    );
+                }
+
+                $aTmplVarsLinks[] = array(
+                    'style_prefix' => $sStylePrefix,
+                    'bx_if:show_embed_outer' => array(
+                		'condition' => $bTmplVarsEmbed,
+                		'content' => $aTmplVarsEmbed
+                	),
+                	'bx_if:show_embed_inner' => array(
+                		'condition' => !$bTmplVarsEmbed,
+                		'content' => $aTmplVarsEmbed
+                    )
+                );
+            }
+
+        //--- Process Photos ---//
+        $aTmplVarsImages = array();
+        if(!empty($aContent['images'])) {
+            foreach($aContent['images'] as $aImage) {
+                $sImage = '';
+                if(!empty($aImage['src']))
+                    $sImage = $this->parseHtmlByName('bx_img.html', array(
+                        'src' => $bBrowseItem && !empty($aImage['src_orig']) ? $aImage['src_orig'] : $aImage['src'],
+                        'bx_repeat:attrs' => array(
+                            array('key' => 'class', 'value' => $sStylePrefix . '-item-img')
+                        )
+                    ));
+
+                if(!empty($sImage) && (isset($aImage['url']) || isset($aImage['onclick']))) {
+                    $aAttrs = array();
+                    if(isset($aImage['onclick']))
+                        $aAttrs[] = array('key' => 'onclick', 'value' => $aImage['onclick']);
+
+                    $sImage = $this->parseHtmlByName('bx_a.html', array(
+                        'href' => isset($aImage['url']) ? $aImage['url'] : 'javascript:void(0)',
+                        'title' => '',
+                        'bx_repeat:attrs' => $aAttrs,
+                        'content' => $sImage
+                    ));
+                }
+
+                $aTmplVarsImages[] = array(
+                    'style_prefix' => $sStylePrefix,
+                    'image' => $sImage
+                );
+            }
+        }
+
+    	//--- Process Videos ---//
+        $aTmplVarsVideos = array();
+        if(!empty($aContent['videos']))
+            foreach($aContent['videos'] as $aVideo) {
+                $aTmplVarsVideos[] = array(
+                    'style_prefix' => $sStylePrefix,
+                	'video' => BxTemplFunctions::getInstance()->videoPlayer($aVideo['src_poster'], $aVideo['src_mp4'], $aVideo['src_webm']) 
+                );
+            }
+
+        return array(
+            'style_prefix' => $sStylePrefix,
+            'bx_if:show_title' => array(
+                'condition' => !empty($sTitle),
+                'content' => array(
+                    'style_prefix' => $sStylePrefix,
+                    'title' => $sTitle,
+                )
+            ),
+            'bx_if:show_content' => array(
+                'condition' => !empty($sText),
+                'content' => array(
+                    'style_prefix' => $sStylePrefix,
+                    'item_content' => $sText,
+                    'bx_if:show_more' => array(
+                        'condition' => !empty($sTextMore),
+                        'content' => array(
+                            'style_prefix' => $sStylePrefix,
+                            'js_object' => $sJsObject,
+                            'item_content_more' => $sTextMore
+                        )
+                    ),
+                )
+            ),
+            'bx_if:show_content_raw' => array(
+                'condition' => !empty($sRaw),
+                'content' => array(
+                    'item_content_raw' => $sRaw
+                )
+            ),
+            'bx_if:show_links' => array(
+                'condition' => !empty($aTmplVarsLinks),
+                'content' => array(
+                    'style_prefix' => $sStylePrefix,
+                    'bx_repeat:links' => $aTmplVarsLinks
+                )
+            ),
+            'bx_if:show_images' => array(
+                'condition' => !empty($aTmplVarsImages),
+                'content' => array(
+                    'style_prefix' => $sStylePrefix,
+                    'bx_repeat:images' => $aTmplVarsImages
+                )
+            ),
+            'bx_if:show_videos' => array(
+                'condition' => !empty($aTmplVarsVideos),
+                'content' => array(
+                    'style_prefix' => $sStylePrefix,
+                    'bx_repeat:videos' => $aTmplVarsVideos
+                )
+            )
+        );
+    }
+
+    protected function _getTmplVarsContentRepost($aEvent, $aBrowseParams = array())
+    {
+    	$aContent = &$aEvent['content'];
+        $sStylePrefix = $this->_oConfig->getPrefix('style');
+
+        $sOwnerLink = $this->parseHtmlByName('bx_a.html', array(
+            'href' => $aContent['owner_url'],
+            'title' => '',
+            'bx_repeat:attrs' => array(),
+            'content' => $aContent['owner_name']
+        ));
+
+        $sSample = _t($aContent['sample']);
+        $sSampleLink = empty($aContent['url']) ? $sSample : $this->parseHtmlByName('bx_a.html', array(
+            'href' => $aContent['url'],
+            'title' => '',
+            'bx_repeat:attrs' => array(),
+            'content' => $sSample
+        ));
+
+        $sTitle = _t('_bx_timeline_txt_reposted', $sOwnerLink, $sSampleLink);
+        $sText = $this->_getContent($aContent['parse_type'], $aEvent);
+
+        return array(
+            'bx_if:show_title' => array(
+                'condition' => !empty($sTitle),
+                'content' => array(
+                    'style_prefix' => $sStylePrefix,
+                    'title' => $sTitle,
+                )
+            ),
+            'bx_if:show_content' => array(
+                'condition' => !empty($sText),
+                'content' => array(
+                    'style_prefix' => $sStylePrefix,
+                    'content' => $sText,
+                )
+            )
+        );
+    }
+
+    protected function _getSystemData(&$aEvent)
+    {
+        $mixedResult = $this->_oConfig->getSystemData($aEvent);
+		if($mixedResult !== false)
+			return $mixedResult;
+
+		$sMethod = 'display' . bx_gen_method_name($aEvent['type'] . '_' . $aEvent['action']);
+		if(!method_exists($this, $sMethod))
+        	return '';
+
+		return $this->$sMethod($aEvent);
+    }
+
+    protected function _getCommonData(&$aEvent)
+    {
+        $CNF = $this->_oConfig->CNF;
+
+        $oModule = $this->getModule();
+        $sJsObject = $this->_oConfig->getJsObject('view');
+        $sPrefix = $this->_oConfig->getPrefix('common_post');
+        $sType = str_replace($sPrefix, '', $aEvent['type']);
+
+        $aResult = array(
+            'owner_id' => $aEvent['object_id'],
+            'icon' => $CNF['ICON'],
+        	'sample' => '_bx_timeline_txt_sample_with_article',
+            'sample_wo_article' => '_bx_timeline_txt_sample',
+        	'sample_action' => '_bx_timeline_txt_added_sample',
+            'content_type' => $sType,
+            'content' => array(
+                'sample' => '_bx_timeline_txt_sample_with_article',
+        		'sample_wo_article' => '_bx_timeline_txt_sample',
+        		'sample_action' => '_bx_timeline_txt_added_sample',
+                'url' => $this->_oConfig->getItemViewUrl($aEvent)
+            ), //a string to display or array to parse default template before displaying.
+            'views' => '',
+            'votes' => '',
+            'reports' => '',
+            'comments' => '',
+            'title' => '', //may be empty.
+            'description' => '' //may be empty.
+        );
+
+        switch($sType) {
+            case BX_TIMELINE_PARSE_TYPE_POST:
+                if(!empty($aEvent['content']))
+                    $aResult['content'] = array_merge($aResult['content'], unserialize($aEvent['content']));
+
+                $aLinks = $this->_oDb->getLinks($aEvent['id']);
+                if(!empty($aLinks) && is_array($aLinks))
+                	$oTranscoder = BxDolTranscoderImage::getObjectInstance($this->_oConfig->getObject('transcoder_photos_preview'));
+
+                    foreach($aLinks as $aLink)
+                        $aResult['content']['links'][] = array(
+                            'url' => $aLink['url'],
+                            'title' => $aLink['title'],
+                            'text' => $aLink['text'],
+                        	'thumbnail' => (int)$aLink['media_id'] != 0 ? $oTranscoder->getFileUrl($aLink['media_id']) : ''
+                        );
+
+                $aPhotos = $this->_oDb->getMedia(BX_TIMELINE_MEDIA_PHOTO, $aEvent['id']);
+                if(!empty($aPhotos) && is_array($aPhotos)) {
+                    $oStorage = BxDolStorage::getObjectInstance($this->_oConfig->getObject('storage_photos'));
+
+                    $oTranscoder = BxDolTranscoderImage::getObjectInstance($this->_oConfig->getObject('transcoder_photos_view'));
+
+                    foreach($aPhotos as $iPhotoId) {
+                        $sPhotoSrcOrig = $oStorage->getFileUrlById($iPhotoId);
+
+                        $aResult['content']['images'][] = array(
+                            'src' => $oTranscoder->getFileUrl($iPhotoId),
+                            'src_orig' => $sPhotoSrcOrig,
+                            'title' => '',
+                            'onclick' => $sJsObject . '.showPhoto(this, \'' . $sPhotoSrcOrig . '\')'
+                        );
+                    }
+                }
+
+                $aVideos = $this->_oDb->getMedia(BX_TIMELINE_MEDIA_VIDEO, $aEvent['id']);
+                if(!empty($aVideos) && is_array($aVideos)) {
+                    $oTranscoderPoster = BxDolTranscoderVideo::getObjectInstance($this->_oConfig->getObject('transcoder_videos_poster'));
+                    $oTranscoderMp4 = BxDolTranscoderVideo::getObjectInstance($this->_oConfig->getObject('transcoder_videos_mp4'));
+                    $oTranscoderWebm = BxDolTranscoderVideo::getObjectInstance($this->_oConfig->getObject('transcoder_videos_webm'));
+
+                    foreach($aVideos as $iVideoId) {
+                        $aResult['content']['videos'][] = array(
+                            'src_poster' => $oTranscoderPoster->getFileUrl($iVideoId),
+                        	'src_mp4' => $oTranscoderMp4->getFileUrl($iVideoId),
+                        	'src_webm' => $oTranscoderWebm->getFileUrl($iVideoId),
+                        );
+                    }
+                }
+                break;
+
+            case BX_TIMELINE_PARSE_TYPE_REPOST:
+                if(empty($aEvent['content']))
+                    return array();
+
+                $aContent = unserialize($aEvent['content']);
+
+                if(!$this->_oConfig->isSystem($aContent['type'] , $aContent['action'])) {
+                    $aReposted = $this->_oDb->getEvents(array('browse' => 'id', 'value' => $aContent['object_id']));
+                    $aReposted = $this->_getCommonData($aReposted);
+                } 
+                else
+                	$aReposted = $this->_getSystemData($aContent);
+
+				if(empty($aReposted) || !is_array($aReposted))
+					return array();
+
+                $aResult['content'] = array_merge($aContent, $aReposted['content']);
+                $aResult['content']['parse_type'] = !empty($aReposted['content_type']) ? $aReposted['content_type'] : BX_TIMELINE_PARSE_TYPE_DEFAULT;
+                $aResult['content']['owner_id'] = $aReposted['owner_id'];
+                list($aResult['content']['owner_name'], $aResult['content']['owner_url']) = $oModule->getUserInfo($aReposted['owner_id']);
+
+                if(!empty($aReposted['sample']))
+                    $aResult['content']['sample'] = $aReposted['sample'];
+                if(!empty($aReposted['sample_wo_article']))
+                    $aResult['content']['sample'] = $aReposted['sample_wo_article'];
+
+                list($sUserName) = $oModule->getUserInfo($aEvent['object_id']);
+                $aResult['title'] = _t('_bx_timeline_txt_user_reposted_sample', $sUserName, $aResult['content']['owner_name'], _t($aResult['content']['sample']));
+                $aResult['description'] = '';
+                break;
+        }
+
+        $sSystem = $this->_oConfig->getObject('view');
+        if($oModule->getViewObject($sSystem, $aEvent['id']) !== false)
+            $aResult['views'] = array(
+                'system' => $sSystem,
+                'object_id' => $aEvent['id'],
+                'count' => $aEvent['views']
+            );
+
+        $sSystem = $this->_oConfig->getObject('vote');
+        if($oModule->getVoteObject($sSystem, $aEvent['id']) !== false)
+            $aResult['votes'] = array(
+                'system' => $sSystem,
+                'object_id' => $aEvent['id'],
+                'count' => $aEvent['votes']
+            );
+
+		$sSystem = $this->_oConfig->getObject('report');
+        if($oModule->getReportObject($sSystem, $aEvent['id']) !== false)
+            $aResult['reports'] = array(
+                'system' => $sSystem,
+                'object_id' => $aEvent['id'],
+                'count' => $aEvent['reports']
+            );
+
+        $sSystem = $this->_oConfig->getObject('comment');
+        if($oModule->getCmtsObject($sSystem, $aEvent['id']) !== false)
+            $aResult['comments'] = array(
+                'system' => $sSystem,
+                'object_id' => $aEvent['id'],
+                'count' => $aEvent['comments']
+            );
+
+        return $aResult;
+    }
+
+    protected function _prepareTextForOutput($s, $iEventId = 0)
+    {
+    	$s = bx_process_output($s, BX_DATA_HTML);
+        $s = bx_linkify_html($s, 'class="' . BX_DOL_LINK_CLASS . '"');
+
+        $oMetatags = BxDolMetatags::getObjectInstance($this->_oConfig->getObject('metatags'));
+		$s = $oMetatags->keywordsParse($iEventId, $s);
+
+        return $s;
+    }
+}
+
+/** @} */

+ 134 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/config.php

@@ -0,0 +1,134 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Timeline Timeline
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_timeline',
+    'title' => 'Timeline',
+    'note' => 'Timeline module.',
+    'version' => '9.0.3',
+    'vendor' => 'BoonEx',
+	'help_url' => 'http://feed.boonex.com/?section={module_name}',
+
+    'compatible_with' => array(
+        '9.0.0-B4'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/timeline/',
+    'home_uri' => 'timeline',
+
+    'db_prefix' => 'bx_timeline_',
+    'class_prefix' => 'BxTimeline',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Timeline',
+
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+        'trigger_page_profile_view_entry',
+        'trigger_page_group_view_entry',
+    ),
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu',
+    	'trigger_group_view_submenu',
+    ),
+
+    /**
+     * Storages.
+     */
+    'storages' => array(
+    	'bx_timeline_photos',
+    	'bx_timeline_videos'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+    	'bx_timeline_photos_preview',
+    	'bx_timeline_photos_view',
+    	'bx_timeline_videos_poster',
+    	'bx_timeline_videos_mp4',
+    	'bx_timeline_videos_webm'
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_storages' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations_for_all' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+    	'process_page_triggers' => 1,
+		'process_menu_triggers' => 1,
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'update_relations_for_all' => 1,
+    	'update_relations' => 1,
+    	'unregister_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Relations Section
+     */
+    'relation_handlers' => array(
+    	'on_install' => '',
+    	'on_uninstall' => 'delete_module_events',
+	    'on_enable' => 'add_handlers',
+	    'on_disable' => 'delete_handlers',
+    ),
+    'relations' => array(
+    	'bx_notifications'
+    )
+);
+
+/** @} */

+ 63 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/installer.php

@@ -0,0 +1,63 @@
+<?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
+ *
+ * @{
+ */
+
+bx_import('BxBaseModNotificationsInstaller');
+
+class BxTimelineInstaller extends BxBaseModNotificationsInstaller
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+
+    public function enable($aParams)
+    {
+        $aResult = parent::enable($aParams);
+        if($aResult['result'])
+            $this->updateParamAET(true);
+
+        return $aResult;
+    }
+
+    public function disable($aParams)
+    {
+        $aResult = parent::disable($aParams);
+        if($aResult['result'])
+            $this->updateParamAET(false);
+        
+        return $aResult;
+    }
+
+    protected function updateParamAET($bAdd)
+    {
+        $sAetDivider = ',';
+        $sAetName = 'bx_timeline_send';
+
+        $sAetParam = 'sys_email_attachable_email_templates';
+        $sAetParamValue = getParam($sAetParam);
+
+        if($bAdd)
+            $sAetParamValue = trim($sAetParamValue . $sAetDivider . $sAetName, $sAetDivider);
+        else {
+            $aAet = explode($sAetDivider, $sAetParamValue);
+
+            $mixedKey = array_search($sAetName, $aAet);
+            if($mixedKey !== false) {
+                unset($aAet[$mixedKey]);
+                $sAetParamValue = implode($sAetDivider, $aAet);
+            }
+        }
+
+        return setParam($sAetParam, $sAetParamValue);
+    }
+}
+
+/** @} */

+ 167 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/langs/en.xml

@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+	<string name="_bx_timeline"><![CDATA[Timeline]]></string>
+	<string name="_bx_timeline_cmts"><![CDATA[Timelines' Comments]]></string>
+
+	<string name="_bx_timeline_option_enable_delete"><![CDATA[Allow Timeline owner to remove items]]></string>
+	<string name="_bx_timeline_option_events_per_page_profile"><![CDATA[Number of events are displayed on Profile page]]></string>
+	<string name="_bx_timeline_option_events_per_page_account"><![CDATA[Number of events are displayed on Account page]]></string>
+	<string name="_bx_timeline_option_events_per_page_home"><![CDATA[Number of events are displayed on Home page]]></string>
+	<string name="_bx_timeline_option_events_per_page"><![CDATA[Number of events per page]]></string>
+	<string name="_bx_timeline_option_rss_length"><![CDATA[The length of RSS feed]]></string>
+	<string name="_bx_timeline_option_events_hide"><![CDATA[Show events in Timeline]]></string>
+	<string name="_bx_timeline_option_chars_display_max"><![CDATA[Max number of displayed character in text post]]></string>
+	<string name="_bx_timeline_option_err_chars_display_max"><![CDATA[Enter the number which should be greater then 150.]]></string>
+
+	<string name="_bx_timeline_form_post"><![CDATA[Post]]></string>
+	<string name="_bx_timeline_form_post_display_add"><![CDATA[Write Post]]></string>
+	<string name="_bx_timeline_form_post_input_sys_owner_id"><![CDATA[Owner ID]]></string>
+	<string name="_bx_timeline_form_post_input_sys_action"><![CDATA[Action]]></string>
+	<string name="_bx_timeline_form_post_input_sys_type"><![CDATA[Type]]></string>
+	<string name="_bx_timeline_form_post_input_sys_text"><![CDATA[Content]]></string>
+	<string name="_bx_timeline_form_post_input_text"><![CDATA[]]></string>
+	<string name="_bx_timeline_form_post_input_sys_link"><![CDATA[Link]]></string>
+	<string name="_bx_timeline_form_post_input_link_alt"><![CDATA[Add Link]]></string>
+	<string name="_bx_timeline_form_post_input_link_err_delete"><![CDATA[Cannot remove the link. Please report.]]></string>
+	<string name="_bx_timeline_form_post_input_sys_photo"><![CDATA[Photo]]></string>
+	<string name="_bx_timeline_form_post_input_photo"><![CDATA[]]></string>
+	<string name="_bx_timeline_form_post_input_photo_alt"><![CDATA[Add Photo]]></string>
+	<string name="_bx_timeline_form_post_input_sys_video"><![CDATA[Video]]></string>
+	<string name="_bx_timeline_form_post_input_video"><![CDATA[]]></string>
+	<string name="_bx_timeline_form_post_input_video_alt"><![CDATA[Add Video]]></string>
+	<string name="_bx_timeline_form_post_input_sys_attachments"><![CDATA[Attachments]]></string>
+	<string name="_bx_timeline_form_post_input_sys_do_submit"><![CDATA[Post]]></string>
+	<string name="_bx_timeline_form_post_input_do_submit"><![CDATA[Post]]></string>
+
+	<string name="_bx_timeline_form_attach_link"><![CDATA[Attach Link]]></string>
+	<string name="_bx_timeline_form_attach_link_display_add"><![CDATA[Attach Link]]></string>
+	<string name="_bx_timeline_form_attach_link_input_sys_url"><![CDATA[Url]]></string>
+	<string name="_bx_timeline_form_attach_link_input_url"><![CDATA[Add Link]]></string>
+	<string name="_bx_timeline_form_attach_link_input_url_err"><![CDATA[Correct Link is essential. Please, fill in this field.]]></string>
+	<string name="_bx_timeline_form_attach_link_input_sys_do_submit"><![CDATA[Add]]></string>
+	<string name="_bx_timeline_form_attach_link_input_do_submit"><![CDATA[Add]]></string>
+	<string name="_bx_timeline_form_attach_link_input_do_cancel"><![CDATA[Close]]></string>
+
+	<string name="_bx_timeline_privacy_view"><![CDATA[View event]]></string>
+
+	<string name="_bx_timeline_acl_action_post"><![CDATA[Post]]></string>
+	<string name="_bx_timeline_acl_action_delete"><![CDATA[Delete]]></string>
+	<string name="_bx_timeline_acl_action_vote"><![CDATA[Vote]]></string>
+	<string name="_bx_timeline_acl_action_repost"><![CDATA[Repost]]></string>
+	<string name="_bx_timeline_acl_action_send"><![CDATA[Send]]></string>
+	<string name="_bx_timeline_acl_action_pin"><![CDATA[Pin]]></string>
+
+	<string name="_bx_timeline_page_title_sys_view"><![CDATA[Profile Timeline]]></string>
+	<string name="_bx_timeline_page_title_view"><![CDATA[Timeline]]></string>
+	<string name="_bx_timeline_page_title_sys_view_home"><![CDATA[Home page Timeline]]></string>
+    <string name="_bx_timeline_page_title_view_home"><![CDATA[Timeline]]></string>
+	<string name="_bx_timeline_page_title_sys_item"><![CDATA[Timeline Item]]></string>
+	<string name="_bx_timeline_page_title_item"><![CDATA[Timeline Item]]></string>
+	<string name="_bx_timeline_page_title_sys_account"><![CDATA[Timeline]]></string>
+	<string name="_bx_timeline_page_title_account"><![CDATA[Timeline]]></string>
+	<string name="_bx_timeline_page_block_title_post"><![CDATA[Post to Timeline]]></string>
+	<string name="_bx_timeline_page_block_title_view"><![CDATA[Timeline]]></string>
+	<string name="_bx_timeline_page_block_title_view_outline"><![CDATA[Outline]]></string>
+	<string name="_bx_timeline_page_block_title_post_profile"><![CDATA[Post to Timeline]]></string>
+	<string name="_bx_timeline_page_block_title_view_profile"><![CDATA[Timeline]]></string>	
+	<string name="_bx_timeline_page_block_title_view_profile_outline"><![CDATA[Outline]]></string>
+	<string name="_bx_timeline_page_block_title_item"><![CDATA[Item]]></string>
+	<string name="_bx_timeline_page_block_title_view_account"><![CDATA[Subscriptions Timeline]]></string>
+	<string name="_bx_timeline_page_block_title_view_account_outline"><![CDATA[Subscriptions Outline]]></string>
+	<string name="_bx_timeline_page_block_title_post_home"><![CDATA[Post to Timeline]]></string>
+	<string name="_bx_timeline_page_block_title_view_home"><![CDATA[Timeline]]></string>
+	<string name="_bx_timeline_page_block_title_view_home_outline"><![CDATA[Outline]]></string>
+	<string name="_bx_timeline_page_block_title_browse_cmts"><![CDATA[Timelines' Comments]]></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>
+    <string name="_bx_timeline_menu_item_get_rss"><![CDATA[RSS]]></string>
+
+    <string name="_bx_timeline_menu_title_item_share"><![CDATA[Share Item]]></string>
+    <string name="_bx_timeline_menu_set_title_item_share"><![CDATA[Share Item]]></string>
+    <string name="_bx_timeline_menu_item_title_system_item_repost"><![CDATA[Repost]]></string>
+    <string name="_bx_timeline_menu_item_title_item_repost"><![CDATA[Repost]]></string>
+    <string name="_bx_timeline_menu_item_title_system_item_send"><![CDATA[Send]]></string>
+    <string name="_bx_timeline_menu_item_title_item_send"><![CDATA[Send to Friend]]></string>
+    
+    <string name="_bx_timeline_menu_title_item_manage"><![CDATA[Manage Item]]></string>
+    <string name="_bx_timeline_menu_set_title_item_manage"><![CDATA[Manage Item]]></string>
+	<string name="_bx_timeline_menu_item_title_system_item_pin"><![CDATA[Pin]]></string>
+    <string name="_bx_timeline_menu_item_title_item_pin"><![CDATA[Pin]]></string>
+    <string name="_bx_timeline_menu_item_title_system_item_unpin"><![CDATA[Unpin]]></string>
+    <string name="_bx_timeline_menu_item_title_item_unpin"><![CDATA[Unpin]]></string>
+    <string name="_bx_timeline_menu_item_title_system_item_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_timeline_menu_item_title_item_delete"><![CDATA[Delete]]></string>
+
+	<string name="_bx_timeline_menu_title_item_actions"><![CDATA[Item Actions]]></string>
+    <string name="_bx_timeline_menu_set_title_item_actions"><![CDATA[Item Actions]]></string>
+    <string name="_bx_timeline_menu_item_title_system_item_comment"><![CDATA[Comment]]></string>
+    <string name="_bx_timeline_menu_item_title_item_comment"><![CDATA[Comment]]></string>
+    <string name="_bx_timeline_menu_item_title_system_item_view"><![CDATA[View]]></string>
+    <string name="_bx_timeline_menu_item_title_system_item_vote"><![CDATA[Vote]]></string>
+    <string name="_bx_timeline_menu_item_title_system_item_share"><![CDATA[Share]]></string>
+    <string name="_bx_timeline_menu_item_title_system_item_report"><![CDATA[Report]]></string>
+    <string name="_bx_timeline_menu_item_title_system_item_more"><![CDATA[More]]></string>
+
+	<string name="_bx_timeline_menu_title_post_attachments"><![CDATA[Form Attachments]]></string>
+    <string name="_bx_timeline_menu_set_title_post_attachments"><![CDATA[Form Attachments]]></string>
+    <string name="_bx_timeline_menu_item_title_system_add_link"><![CDATA[Add Link]]></string>
+    <string name="_bx_timeline_menu_item_title_add_link"><![CDATA[Add Link]]></string>
+    <string name="_bx_timeline_menu_item_title_system_add_photo"><![CDATA[Add Photo]]></string>
+    <string name="_bx_timeline_menu_item_title_add_photo"><![CDATA[Add Photo]]></string>
+    <string name="_bx_timeline_menu_item_title_system_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_timeline"><![CDATA[Timeline]]></string>
+    <string name="_bx_timeline_menu_item_title_timeline"><![CDATA[Timeline]]></string>
+    
+    <string name="_bx_timeline_menu_item_title_system_create_entry"><![CDATA[Update Status]]></string>
+    <string name="_bx_timeline_menu_item_title_create_entry"><![CDATA[Update Status]]></string>
+
+	<string name="_bx_timeline_menu_item_title_system_view_timeline_view"><![CDATA[Timeline]]></string>
+	<string name="_bx_timeline_menu_item_title_view_timeline_view"><![CDATA[Timeline]]></string>
+
+	<string name="_bx_timeline_alert_module_timeline_common_post"><![CDATA[Timeline (post)]]></string>
+	<string name="_bx_timeline_alert_module_timeline_common_repost"><![CDATA[Timeline (repost)]]></string>
+	<string name="_bx_timeline_alert_action_added"><![CDATA[add]]></string>
+
+	<string name="_bx_timeline_txt_msg_no_results"><![CDATA[Empty]]></string>
+	<string name="_bx_timeline_txt_err_cannot_perform_action"><![CDATA[Cannot perform action. Please report.]]></string>
+	<string name="_bx_timeline_txt_err_empty_post"><![CDATA[The post is empty.]]></string>
+
+	<string name="_bx_timeline_txt_load_more"><![CDATA[Load More]]></string>
+	<string name="_bx_timeline_txt_or_jump_to"><![CDATA[... or jump to:]]></string>
+	<string name="_bx_timeline_txt_jump_to_n_year"><![CDATA[Jump to {0} year]]></string>
+	<string name="_bx_timeline_txt_jump_to_recent"><![CDATA[Jump to recent posts]]></string>
+	<string name="_bx_timeline_txt_pinned"><![CDATA[Pinned post]]></string>
+
+	<string name="_bx_timeline_txt_rss_caption"><![CDATA[{0}'s timeline]]></string>
+	<string name="_bx_timeline_txt_added_sample"><![CDATA[added {0}]]></string>
+	<string name="_bx_timeline_txt_user_added_sample"><![CDATA[{0} added {1}]]></string>
+	<string name="_bx_timeline_txt_user_reposted_sample"><![CDATA[{0} reposted {1}'s {2}]]></string>
+	<string name="_bx_timeline_txt_sample"><![CDATA[post]]></string>
+	<string name="_bx_timeline_txt_sample_with_article"><![CDATA[a post]]></string>
+	<string name="_bx_timeline_txt_sample_ext"><![CDATA[timeline post]]></string>
+	<string name="_bx_timeline_txt_sample_comment_single"><![CDATA[timeline post's comment]]></string>
+    <string name="_bx_timeline_txt_sample_vote_single"><![CDATA[timeline post's vote]]></string>
+    <string name="_bx_timeline_txt_today"><![CDATA[Today]]></string>
+
+	<string name="_bx_timeline_txt_do_repost"><![CDATA[Repost]]></string>
+	<string name="_bx_timeline_txt_reposted"><![CDATA[Reposted {0}'s {1}.]]></string>
+	<string name="_bx_timeline_txt_reposted_by"><![CDATA[Reposted by]]></string>
+	<string name="_bx_timeline_txt_err_cannot_repost"><![CDATA[Cannot repost. Please report.]]></string>
+	<string name="_bx_timeline_txt_err_already_reposted"><![CDATA[You already reposted the item.]]></string>
+	<string name="_bx_timeline_txt_msg_success_repost"><![CDATA[The item was successfully reposted.]]></string>
+	<string name="_bx_timeline_txt_object_reposted"><![CDATA[<a class="bx-ntfs-content-profile" href="{owner_link}">{owner_name}</a> reposted a {entry_sample} <a href="{entry_url}">{entry_caption}</a>]]></string>
+
+    <!-- EMAIL TEMPLATES -->
+    <string name="_bx_timeline_et_txt_name_send"><![CDATA[Send to Friend.]]></string>
+    <string name="_bx_timeline_et_txt_subject_send"><![CDATA[It may be interesting for you.]]></string>
+    <string name="_bx_timeline_et_txt_body_send"><![CDATA[
+<p>Hello.</p>
+<p>Take a look at <a href="{ViewLink}">this post</a>, it may be interesting for you.</p>]]></string>
+
+	<string name="_bx_ntfs_alert_action_post_common"><![CDATA[add post]]></string>
+</resources>

+ 60 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/sql/disable.sql

@@ -0,0 +1,60 @@
+-- PAGES & BLOCKS
+DELETE FROM `sys_objects_page` WHERE `module` = 'bx_timeline';
+DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_timeline';
+
+
+-- 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';
+
+
+-- SETTINGS
+SET @iTypeId = (SELECT `ID` FROM `sys_options_types` WHERE `name` = 'bx_timeline' LIMIT 1);
+SET @iCategId = (SELECT `ID` FROM `sys_options_categories` WHERE `type_id` = @iTypeId LIMIT 1);
+DELETE FROM `sys_options` WHERE `category_id` = @iCategId;
+DELETE FROM `sys_options_categories` WHERE `type_id` = @iTypeId;
+DELETE FROM `sys_options_types` WHERE `id` = @iTypeId;
+
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` WHERE `module` = 'bx_timeline';
+
+
+-- ACL
+DELETE `sys_acl_actions`, `sys_acl_matrix` FROM `sys_acl_actions`, `sys_acl_matrix` WHERE `sys_acl_matrix`.`IDAction` = `sys_acl_actions`.`ID` AND `sys_acl_actions`.`Module` = 'bx_timeline';
+DELETE FROM `sys_acl_actions` WHERE `Module` = 'bx_timeline';
+
+
+-- ALERTS
+SET @iHandlerId = (SELECT `id` FROM `sys_alerts_handlers` WHERE `name` = 'bx_timeline' LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `handler_id` = @iHandlerId;
+DELETE FROM `sys_alerts_handlers` WHERE `id` = @iHandlerId LIMIT 1;
+
+
+-- COMMENTS
+DELETE FROM `sys_objects_cmts` WHERE `Name` = 'bx_timeline' LIMIT 1;
+
+
+-- VIEWS
+DELETE FROM `sys_objects_view` WHERE `name` = 'bx_timeline' LIMIT 1;
+
+
+-- VOTES
+DELETE FROM `sys_objects_vote` WHERE `Name` = 'bx_timeline' LIMIT 1;
+
+
+-- REPORTS
+DELETE FROM `sys_objects_report` WHERE `Name` = 'bx_timeline' LIMIT 1;
+
+
+-- SEARCH
+DELETE FROM `sys_objects_search` WHERE `ObjectName` IN ('bx_timeline', 'bx_timeline_cmts');
+
+
+-- METATAGS
+DELETE FROM `sys_objects_metatags` WHERE `object` = 'bx_timeline';
+
+
+-- EMAIL TEMPLATES
+DELETE FROM `sys_email_templates` WHERE `Module` = 'bx_timeline';

+ 245 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/sql/enable.sql

@@ -0,0 +1,245 @@
+-- PAGES & BLOCKS
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_timeline_view', '_bx_timeline_page_title_sys_view', '_bx_timeline_page_title_view', 'bx_timeline', 5, 2147483647, 1, 'timeline-view', 'page.php?i=timeline-view', '', '', '', 0, 1, 0, 'BxTimelinePageView', 'modules/boonex/timeline/classes/BxTimelinePageView.php'),
+('bx_timeline_view_home', '_bx_timeline_page_title_sys_view_home', '_bx_timeline_page_title_view_home', 'bx_timeline', 5, 2147483647, 1, 'timeline-view-home', 'page.php?i=timeline-view-home', '', '', '', 0, 1, 0, '', ''),
+('bx_timeline_item', '_bx_timeline_page_title_sys_item', '_bx_timeline_page_title_item', 'bx_timeline', 5, 2147483647, 1, 'timeline-item', 'page.php?i=timeline-item', '', '', '', 0, 1, 0, '', '');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_timeline_view', 1, 'bx_timeline', '_bx_timeline_page_block_title_post', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:14:"get_block_post";}', 0, 0, 1),
+('bx_timeline_view', 1, 'bx_timeline', '_bx_timeline_page_block_title_view', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:14:"get_block_view";}', 0, 0, 2),
+('bx_timeline_view', 1, 'bx_timeline', '_bx_timeline_page_block_title_view_outline', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:22:"get_block_view_outline";}', 0, 0, 3),
+
+('bx_timeline_view_home', 1, 'bx_timeline', '_bx_timeline_page_block_title_post_home', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:19:"get_block_post_home";}', 0, 0, 1),
+('bx_timeline_view_home', 1, 'bx_timeline', '_bx_timeline_page_block_title_view_home', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:19:"get_block_view_home";}', 0, 0, 2),
+('bx_timeline_view_home', 1, 'bx_timeline', '_bx_timeline_page_block_title_view_home_outline', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:27:"get_block_view_home_outline";}', 0, 0, 3),
+
+('bx_timeline_item', 1, 'bx_timeline', '_bx_timeline_page_block_title_item', 0, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:14:"get_block_item";}', 0, 0, 1);
+
+-- PAGES: add page block on dashboard
+SET @iPBCellDashboard = 1;
+SET @iPBOrderDashboard = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_pages_blocks` WHERE `object` = 'sys_dashboard' AND `cell_id` = @iPBCellDashboard LIMIT 1);
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('sys_dashboard', @iPBCellDashboard, 'bx_timeline', '_bx_timeline_page_block_title_view_account', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:22:"get_block_view_account";}', 0, 1, @iPBOrderDashboard + 1),
+('sys_dashboard', @iPBCellDashboard, 'bx_timeline', '_bx_timeline_page_block_title_view_account_outline', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:30:"get_block_view_account_outline";}', 0, 1, @iPBOrderDashboard + 2);
+
+-- PAGES: add page block on home
+SET @iPBCellHome = 1;
+SET @iPBOrderHome = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_pages_blocks` WHERE `object` = 'sys_home' AND `cell_id` = @iPBCellHome ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('sys_home', @iPBCellHome, 'bx_timeline', '_bx_timeline_page_block_title_post_home', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:19:"get_block_post_home";}', 0, 1, @iPBOrderHome + 1),
+('sys_home', @iPBCellHome, 'bx_timeline', '_bx_timeline_page_block_title_view_home', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:19:"get_block_view_home";}', 0, 1, @iPBOrderHome + 2),
+('sys_home', @iPBCellHome, 'bx_timeline', '_bx_timeline_page_block_title_view_home_outline', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:27:"get_block_view_home_outline";}', 0, 1, @iPBOrderHome + 3);
+
+-- PAGES: add page block to profiles modules (trigger* page objects are processed separately upon modules enable/disable)
+SET @iPBCellProfile = 2;
+SET @iPBCellGroup = 4;
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_timeline', '_bx_timeline_page_block_title_post_profile', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:22:"get_block_post_profile";s:6:"params";a:1:{i:0;s:6:"{type}";}}', 0, 0, 0),
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_timeline', '_bx_timeline_page_block_title_view_profile', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:22:"get_block_view_profile";s:6:"params";a:1:{i:0;s:6:"{type}";}}', 0, 0, 0),
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_timeline', '_bx_timeline_page_block_title_view_profile_outline', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:30:"get_block_view_profile_outline";s:6:"params";a:1:{i:0;s:6:"{type}";}}', 0, 0, 0),
+
+('trigger_page_group_view_entry', @iPBCellGroup, 'bx_timeline', '_bx_timeline_page_block_title_post_profile', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:22:"get_block_post_profile";s:6:"params";a:1:{i:0;s:6:"{type}";}}', 0, 0, 0),
+('trigger_page_group_view_entry', @iPBCellGroup, 'bx_timeline', '_bx_timeline_page_block_title_view_profile', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:22:"get_block_view_profile";s:6:"params";a:1:{i:0;s:6:"{type}";}}', 0, 0, 0),
+('trigger_page_group_view_entry', @iPBCellGroup, 'bx_timeline', '_bx_timeline_page_block_title_view_profile_outline', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:22:"get_block_view_profile_outline";s:6:"params";a:1:{i:0;s:6:"{type}";}}', 0, 0, 0);
+
+
+-- 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');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_timeline_menu_item_share', 'bx_timeline', '_bx_timeline_menu_set_title_item_share', 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_item_share', 'bx_timeline', 'item-repost', '_bx_timeline_menu_item_title_system_item_repost', '_bx_timeline_menu_item_title_item_repost', 'javascript:void(0)', 'javascript:{js_onclick_repost}', '_self', 'repeat', '', 2147483647, 1, 0, 1),
+('bx_timeline_menu_item_share', 'bx_timeline', 'item-send', '_bx_timeline_menu_item_title_system_item_send', '_bx_timeline_menu_item_title_item_send', 'page.php?i=start-convo&et={et_send}', '', '_self', 'envelope', '', 2147483647, 1, 0, 2);
+
+-- MENU: Item Manage (Pin, Delete, 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_manage', '_bx_timeline_menu_title_item_manage', 'bx_timeline_menu_item_manage', 'bx_timeline', 6, 0, 1, 'BxTimelineMenuItemManage', 'modules/boonex/timeline/classes/BxTimelineMenuItemManage.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_timeline_menu_item_manage', 'bx_timeline', '_bx_timeline_menu_set_title_item_manage', 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_item_manage', 'bx_timeline', 'item-pin', '_bx_timeline_menu_item_title_system_item_pin', '_bx_timeline_menu_item_title_item_pin', 'javascript:void(0)', 'javascript:{js_object_view}.pinPost(this, {content_id}, 1)', '_self', 'thumb-tack', '', 2147483647, 1, 0, 0),
+('bx_timeline_menu_item_manage', 'bx_timeline', 'item-unpin', '_bx_timeline_menu_item_title_system_item_unpin', '_bx_timeline_menu_item_title_item_unpin', 'javascript:void(0)', 'javascript:{js_object_view}.pinPost(this, {content_id}, 0)', '_self', 'thumb-tack', '', 2147483647, 1, 0, 1),
+('bx_timeline_menu_item_manage', 'bx_timeline', 'item-delete', '_bx_timeline_menu_item_title_system_item_delete', '_bx_timeline_menu_item_title_item_delete', 'javascript:void(0)', 'javascript:{js_object_view}.deletePost(this, {content_id})', '_self', 'remove', '', 2147483647, 1, 0, 2);
+
+-- MENU: Item Actions (Comment, Vote, Share, Report, 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_actions', '_bx_timeline_menu_title_item_actions', 'bx_timeline_menu_item_actions', 'bx_timeline', 15, 0, 1, 'BxTimelineMenuItemActions', 'modules/boonex/timeline/classes/BxTimelineMenuItemActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_timeline_menu_item_actions', 'bx_timeline', '_bx_timeline_menu_set_title_item_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_timeline_menu_item_actions', 'bx_timeline', 'item-comment', '_bx_timeline_menu_item_title_system_item_comment', '_bx_timeline_menu_item_title_item_comment', 'javascript:void(0)', 'javascript:{comment_onclick}', '_self', 'comment', 'a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:27:"get_menu_item_addon_comment";s:6:"params";a:3:{i:0;s:16:"{comment_system}";i:1;s:16:"{comment_object}";i:2;s:6:"{view}";}}', '', 0, 2147483647, 1, 0, 1, 1),
+('bx_timeline_menu_item_actions', 'bx_timeline', 'item-vote', '_bx_timeline_menu_item_title_system_item_vote', '', 'javascript:void(0)', '', '', '', '', '', 0, 2147483647, 1, 0, 0, 2),
+('bx_timeline_menu_item_actions', 'bx_timeline', 'item-share', '_bx_timeline_menu_item_title_system_item_share', '', 'javascript:void(0)', 'bx_menu_popup(''bx_timeline_menu_item_share'', this, {''id'':''bx_timeline_menu_item_share_{content_id}''}, {content_id:{content_id}});', '', 'share-alt', '', 'bx_timeline_menu_item_share', 1, 2147483647, 1, 0, 0, 3),
+('bx_timeline_menu_item_actions', 'bx_timeline', 'item-report', '_bx_timeline_menu_item_title_system_item_report', '', 'javascript:void(0)', '', '', '', '', '', 0, 2147483647, 1, 0, 0, 4),
+('bx_timeline_menu_item_actions', 'bx_timeline', 'item-more', '_bx_timeline_menu_item_title_system_item_more', '', 'javascript:void(0)', 'bx_menu_popup(''bx_timeline_menu_item_manage'', this, {''id'':''bx_timeline_menu_item_manage_{content_id}''}, {content_id:{content_id}});', '', 'ellipsis-h', '', 'bx_timeline_menu_item_manage', 1, 2147483647, 1, 0, 0, 5);
+
+-- MENU: Post form attachments (Link, Photo, Video)
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_timeline_menu_post_attachments', '_bx_timeline_menu_title_post_attachments', 'bx_timeline_menu_post_attachments', 'bx_timeline', 9, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_timeline_menu_post_attachments', 'bx_timeline', '_bx_timeline_menu_set_title_post_attachments', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_timeline_menu_post_attachments', 'bx_timeline', 'add-link', '_bx_timeline_menu_item_title_system_add_link', '_bx_timeline_menu_item_title_add_link', 'javascript:void(0)', 'javascript:{js_object}.showAttachLink(this);', '_self', 'link', '', '', 2147483647, 1, 0, 1, 1),
+('bx_timeline_menu_post_attachments', 'bx_timeline', 'add-photo', '_bx_timeline_menu_item_title_system_add_photo', '_bx_timeline_menu_item_title_add_photo', 'javascript:void(0)', 'javascript:{js_object_uploader_photo}.showUploaderForm();', '_self', 'camera', '', '', 2147483647, 1, 0, 1, 2),
+('bx_timeline_menu_post_attachments', 'bx_timeline', 'add-video', '_bx_timeline_menu_item_title_system_add_video', '_bx_timeline_menu_item_title_add_video', 'javascript:void(0)', 'javascript:{js_object_uploader_video}.showUploaderForm();', '_self', 'video-camera', '', '', 2147483647, 1, 0, 1, 3);
+
+-- MENU: add to "add content" menu
+SET @iAddMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_add_content_links' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+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 
+('sys_add_content_links', 'bx_timeline', 'create-post', '_bx_timeline_menu_item_title_system_create_entry', '_bx_timeline_menu_item_title_create_entry', 'page.php?i=timeline-view', '', '', 'clock-o col-green1', '', 2147483647, 1, 1, IFNULL(@iAddMenuOrder, 0) + 1);
+
+-- MENU: add menu item to profiles modules (trigger* menu sets are processed separately upon modules enable/disable)
+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 
+('trigger_profile_view_submenu', 'bx_timeline', 'timeline-view', '_bx_timeline_menu_item_title_system_view_timeline_view', '_bx_timeline_menu_item_title_view_timeline_view', 'page.php?i=timeline-view&profile_id={profile_id}', '', '', 'clock-o col-green1', '', 2147483647, 1, 0, 0),
+('trigger_group_view_submenu', 'bx_timeline', 'timeline-view', '_bx_timeline_menu_item_title_system_view_timeline_view', '_bx_timeline_menu_item_title_view_timeline_view', 'page.php?i=timeline-view&profile_id={profile_id}', '', '', 'clock-o col-green1', '', 2147483647, 1, 0, 0);
+
+
+-- SETTINGS
+SET @iTypeOrder = (SELECT MAX(`order`) FROM `sys_options_types` WHERE `group` = 'modules');
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('modules', 'bx_timeline', '_bx_timeline', 'bx_timeline@modules/boonex/timeline/|std-icon.svg', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_timeline', '_bx_timeline', 1);
+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_delete', 'on', @iCategId, '_bx_timeline_option_enable_delete', 'checkbox', '', '', '', '', 1),
+('bx_timeline_events_per_page_profile', '10', @iCategId, '_bx_timeline_option_events_per_page_profile', 'digit', '', '', '', '', 2),
+('bx_timeline_events_per_page_account', '20', @iCategId, '_bx_timeline_option_events_per_page_account', 'digit', '', '', '', '', 3),
+('bx_timeline_events_per_page_home', '20', @iCategId, '_bx_timeline_option_events_per_page_home', 'digit', '', '', '', '', 4),
+('bx_timeline_events_per_page', '20', @iCategId, '_bx_timeline_option_events_per_page', 'digit', '', '', '', '', 5),
+('bx_timeline_rss_length', '5', @iCategId, '_bx_timeline_option_rss_length', 'digit', '', '', '', '', 6),
+('bx_timeline_events_hide', '', @iCategId, '_bx_timeline_option_events_hide', 'rlist', '', '', '', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:21:"get_actions_checklist";}', 7),
+('bx_timeline_chars_display_max', '300', @iCategId, '_bx_timeline_option_chars_display_max', 'digit', 'GreaterThan', 'a:1:{s:3:"min";i:150;}', '_bx_timeline_option_err_chars_display_max', '', 8);
+
+
+-- PRIVACY 
+INSERT INTO `sys_objects_privacy` (`object`, `module`, `action`, `title`, `default_group`, `table`, `table_field_id`, `table_field_author`, `override_class_name`, `override_class_file`) VALUES
+('bx_timeline_privacy_view', 'bx_timeline', 'view', '_bx_timeline_privacy_view', '3', 'bx_timeline_events', 'id', 'owner_id', 'BxTimelinePrivacy', 'modules/boonex/timeline/classes/BxTimelinePrivacy.php');
+
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_timeline', 'post', NULL, '_bx_timeline_acl_action_post', '', 1, 3);
+SET @iIdActionPost = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_timeline', 'delete', NULL, '_bx_timeline_acl_action_delete', '', 1, 3);
+SET @iIdActionDelete = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_timeline', 'vote', NULL, '_bx_timeline_acl_action_vote', '', 1, 0);
+SET @iIdActionVote = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_timeline', 'repost', NULL, '_bx_timeline_acl_action_repost', '', 1, 3);
+SET @iIdActionRepost = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_timeline', 'send', NULL, '_bx_timeline_acl_action_send', '', 1, 3);
+SET @iIdActionSend = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_timeline', 'pin', NULL, '_bx_timeline_acl_action_pin', '', 1, 3);
+SET @iIdActionPin = LAST_INSERT_ID();
+
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+
+-- post
+(@iStandard, @iIdActionPost),
+(@iModerator, @iIdActionPost),
+(@iAdministrator, @iIdActionPost),
+(@iPremium, @iIdActionPost),
+
+-- delete
+(@iModerator, @iIdActionDelete),
+(@iAdministrator, @iIdActionDelete),
+
+-- vote
+(@iStandard, @iIdActionVote),
+(@iModerator, @iIdActionVote),
+(@iAdministrator, @iIdActionVote),
+(@iPremium, @iIdActionVote),
+
+-- repost
+(@iStandard, @iIdActionRepost),
+(@iModerator, @iIdActionRepost),
+(@iAdministrator, @iIdActionRepost),
+(@iPremium, @iIdActionRepost),
+
+-- send
+(@iStandard, @iIdActionSend),
+(@iModerator, @iIdActionSend),
+(@iAdministrator, @iIdActionSend),
+(@iPremium, @iIdActionSend),
+
+-- pin
+(@iModerator, @iIdActionPin),
+(@iAdministrator, @iIdActionPin);
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers`(`name`, `class`, `file`, `service_call`) VALUES 
+('bx_timeline', 'BxTimelineResponse', 'modules/boonex/timeline/classes/BxTimelineResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('profile', 'delete', @iHandler);
+
+
+-- COMMENTS
+INSERT INTO `sys_objects_cmts` (`Name`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Nl2br`, `PerView`, `PerViewReplies`, `BrowseType`, `IsBrowseSwitch`, `PostFormPosition`, `NumberOfLevels`, `IsDisplaySwitch`, `IsRatable`, `ViewingThreshold`, `IsOn`, `RootStylePrefix`, `BaseUrl`, `ObjectVote`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('bx_timeline', 'bx_timeline_comments', 1, 5000, 1000, 1, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=timeline-item&id={object_id}', '', 'bx_timeline_events', 'id', 'object_id', 'title', 'comments', 'BxTimelineCmts', 'modules/boonex/timeline/classes/BxTimelineCmts.php');
+
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_timeline', 'bx_timeline_views_track', '86400', '1', 'bx_timeline_events', 'id', 'object_id', 'views', '', '');
+
+
+-- VOTES
+INSERT INTO `sys_objects_vote`(`Name`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_timeline', 'bx_timeline_votes', 'bx_timeline_votes_track', '604800', '1', '1', '0', '1', 'bx_timeline_events', 'id', 'object_id', 'rate', 'votes', 'BxTimelineVote', 'modules/boonex/timeline/classes/BxTimelineVote.php');
+
+
+-- REPORTS
+INSERT INTO `sys_objects_report` (`name`, `table_main`, `table_track`, `is_on`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_timeline', 'bx_timeline_reports', 'bx_timeline_reports_track', '1', 'page.php?i=timeline-item&id={object_id}', 'bx_timeline_events', 'id', 'owner_id', 'reports',  'BxTimelineReport', 'modules/boonex/timeline/classes/BxTimelineReport.php');
+
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_timeline', '_bx_timeline', @iSearchOrder + 1, 'BxTimelineSearchResult', 'modules/boonex/timeline/classes/BxTimelineSearchResult.php'),
+('bx_timeline_cmts', '_bx_timeline_cmts', @iSearchOrder + 2, 'BxTimelineCmtsSearchResult', 'modules/boonex/timeline/classes/BxTimelineCmtsSearchResult.php');
+
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_timeline', 'bx_timeline_meta_keywords', 'bx_timeline_meta_locations', '', '', '');
+
+
+-- EMAIL TEMPLATES
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES 
+('bx_timeline', '_bx_timeline_et_txt_name_send', 'bx_timeline_send', '_bx_timeline_et_txt_subject_send', '_bx_timeline_et_txt_body_send');

+ 336 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/sql/install.sql

@@ -0,0 +1,336 @@
+SET @sName = 'bx_timeline';
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+-- TABLES
+CREATE TABLE IF NOT EXISTS `bx_timeline_events` (
+  `id` int(11) NOT NULL auto_increment,
+  `owner_id` int(11) unsigned NOT NULL default '0',
+  `type` varchar(255) NOT NULL,
+  `action` varchar(255) NOT NULL,
+  `object_id` text NOT NULL,
+  `object_privacy_view` int(11) NOT NULL default '3',
+  `content` text NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `description` text NOT NULL,
+  `views` int(11) unsigned NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) unsigned NOT NULL default '0',
+  `comments` int(11) unsigned NOT NULL default '0',
+  `reports` int(11) unsigned NOT NULL default '0',
+  `reposts` int(11) unsigned NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  `active` tinyint(4) NOT NULL default '1',
+  `hidden` tinyint(4) NOT NULL default '0',
+  `pinned` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `owner_id` (`owner_id`),
+  FULLTEXT KEY `search_fields` (`description`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_handlers` (
+  `id` int(11) NOT NULL auto_increment,
+  `group` varchar(64) NOT NULL default '',
+  `type` enum('insert','update','delete') NOT NULL DEFAULT 'insert',
+  `alert_unit` varchar(64) NOT NULL default '',
+  `alert_action` varchar(64) NOT NULL default '',
+  `content` text NOT NULL,
+  `privacy` varchar(64) NOT NULL default '',
+  PRIMARY KEY  (`id`),
+  UNIQUE `handler` (`group`, `type`),
+  UNIQUE `alert` (`alert_unit`, `alert_action`)
+);
+
+INSERT INTO `bx_timeline_handlers`(`group`, `type`, `alert_unit`, `alert_action`, `content`) VALUES
+('common_post', 'insert', 'timeline_common_post', '', ''),
+('common_repost', 'insert', 'timeline_common_repost', '', ''),
+('profile', 'delete', 'profile', 'delete', '');
+
+-- TABLES: STORAGES, TRANSCODERS, UPLOADERS
+CREATE TABLE IF NOT EXISTS `bx_timeline_photos` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` int(11) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_photos_processed` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` int(11) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_photos2events` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `event_id` int(11) NOT NULL DEFAULT '0',
+  `media_id` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `media` (`event_id`, `media_id`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_videos` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` int(11) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_videos_processed` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` int(11) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_videos2events` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `event_id` int(11) NOT NULL DEFAULT '0',
+  `media_id` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `media` (`event_id`, `media_id`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+-- TABLES: LINKS
+CREATE TABLE IF NOT EXISTS `bx_timeline_links` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `media_id` int(11) NOT NULL DEFAULT '0',
+  `url` varchar(255) NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `text` text NOT NULL,
+  `added` int(11) NOT NULL,
+  PRIMARY KEY (`id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_links2events` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `event_id` int(11) NOT NULL DEFAULT '0',
+  `link_id` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `link` (`event_id`, `link_id`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+-- TABLES: REPOSTS
+CREATE TABLE IF NOT EXISTS `bx_timeline_reposts_track` (
+  `event_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `reposted_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  UNIQUE KEY `event_id` (`event_id`),
+  KEY `repost` (`reposted_id`, `author_nip`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+-- TABLES: COMMENTS
+CREATE TABLE IF NOT EXISTS `bx_timeline_comments` (
+  `cmt_id` int(11) NOT NULL AUTO_INCREMENT,
+  `cmt_parent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_vparent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_object_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_author_id` int(10) unsigned NOT NULL DEFAULT '0',
+  `cmt_level` int(11) NOT NULL DEFAULT '0',
+  `cmt_text` text NOT NULL,
+  `cmt_time` int(11) unsigned NOT NULL DEFAULT '0',
+  `cmt_replies` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+-- TABLE: views
+CREATE TABLE IF NOT EXISTS `bx_timeline_views_track` (
+  `object_id` int(11) NOT NULL default '0',
+  `viewer_id` int(11) NOT NULL default '0',
+  `viewer_nip` int(11) unsigned NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- TABLES: VOTES
+CREATE TABLE IF NOT EXISTS `bx_timeline_votes` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_votes_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+-- TABLE: metas
+CREATE TABLE IF NOT EXISTS `bx_timeline_meta_keywords` (
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_meta_locations` (
+  `object_id` int(10) unsigned NOT NULL,
+  `lat` double NOT NULL,
+  `lng` double NOT NULL,
+  `country` varchar(2) NOT NULL,
+  `state` varchar(255) NOT NULL,
+  `city` varchar(255) NOT NULL,
+  `zip` varchar(255) NOT NULL,
+  `street` varchar(255) NOT NULL,
+  `street_number` varchar(255) NOT NULL,
+  PRIMARY KEY (`object_id`),
+  KEY `country_state_city` (`country`,`state`(8),`city`(8))
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- TABLE: reports
+CREATE TABLE IF NOT EXISTS `bx_timeline_reports` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_reports_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `type` varchar(32) NOT NULL default '',
+  `text` text NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+
+-- STORAGES, TRANSCODERS, UPLOADERS
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_timeline_simple_photo', 1, 'BxTimelineUploaderSimplePhoto', 'modules/boonex/timeline/classes/BxTimelineUploaderSimplePhoto.php'),
+('bx_timeline_simple_video', 1, 'BxTimelineUploaderSimpleVideo', 'modules/boonex/timeline/classes/BxTimelineUploaderSimpleVideo.php');
+
+INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `cache_control`, `levels`, `table_files`, `ext_mode`, `ext_allow`, `ext_deny`, `quota_size`, `current_size`, `quota_number`, `current_number`, `max_file_size`, `ts`) VALUES
+('bx_timeline_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_timeline_photos', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
+('bx_timeline_photos_processed', @sStorageEngine, '', 360, 2592000, 3, 'bx_timeline_photos_processed', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
+
+('bx_timeline_videos', @sStorageEngine, '', 360, 2592000, 3, 'bx_timeline_videos', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,divx,xvid,3gp,webm,jpg', '', 0, 0, 0, 0, 0, 0),
+('bx_timeline_videos_processed', @sStorageEngine, '', 360, 2592000, 3, 'bx_timeline_videos_processed', 'allow-deny', 'avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,divx,xvid,3gp,webm,jpg', '', 0, 0, 0, 0, 0, 0);
+
+INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`, `override_class_name`, `override_class_file`) VALUES
+('bx_timeline_photos_preview', 'bx_timeline_photos_processed', 'Storage', 'a:1:{s:6:"object";s:18:"bx_timeline_photos";}', 'no', '1', '2592000', '0', '', ''),
+('bx_timeline_photos_view', 'bx_timeline_photos_processed', 'Storage', 'a:1:{s:6:"object";s:18:"bx_timeline_photos";}', 'no', '1', '2592000', '0', '', ''),
+
+('bx_timeline_videos_poster', 'bx_timeline_videos_processed', 'Storage', 'a:1:{s:6:"object";s:18:"bx_timeline_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+('bx_timeline_videos_mp4', 'bx_timeline_videos_processed', 'Storage', 'a:1:{s:6:"object";s:18:"bx_timeline_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+('bx_timeline_videos_webm', 'bx_timeline_videos_processed', 'Storage', 'a:1:{s:6:"object";s:18:"bx_timeline_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', '');
+
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES
+('bx_timeline_photos_preview', 'Resize', 'a:3:{s:1:"w";s:3:"100";s:1:"h";s:3:"100";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_timeline_photos_view', 'Resize', 'a:3:{s:1:"w";s:3:"318";s:1:"h";s:3:"318";s:13:"square_resize";s:1:"1";}', '0'),
+
+('bx_timeline_videos_poster', 'Poster', 'a:2:{s:1:"h";s:3:"318";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_timeline_videos_mp4', 'Mp4', 'a:2:{s:1:"h";s:3:"318";s:10:"force_type";s:3:"mp4";}', 0),
+('bx_timeline_videos_webm', 'Webm', 'a:2:{s:1:"h";s:3:"318";s:10:"force_type";s:4:"webm";}', 0);
+
+
+-- Forms -> Post
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_timeline_post', @sName, '_bx_timeline_form_post', '', '', 'do_submit', 'bx_timeline_events', 'id', '', '', '', 0, 1, 'BxTimelineFormPost', 'modules/boonex/timeline/classes/BxTimelineFormPost.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_timeline_post_add', @sName, 'bx_timeline_post', '_bx_timeline_form_post_display_add', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_timeline_post', @sName, 'type', 'post', '', 0, 'hidden', '_bx_timeline_form_post_input_sys_type', '', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_timeline_post', @sName, 'action', '', '', 0, 'hidden', '_bx_timeline_form_post_input_sys_action', '', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_timeline_post', @sName, 'owner_id', '0', '', 0, 'hidden', '_bx_timeline_form_post_input_sys_owner_id', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_timeline_post', @sName, 'text', '', '', 0, 'textarea', '_bx_timeline_form_post_input_sys_text', '_bx_timeline_form_post_input_text', '', 0, 0, 0, 'a:1:{s:12:"autocomplete";s:3:"off";}', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_timeline_post', @sName, 'location', '', '', 0, 'location', '_sys_form_input_sys_location', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_timeline_post', @sName, 'link', '', '', 0, 'custom', '_bx_timeline_form_post_input_sys_link', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_timeline_post', @sName, 'photo', 'a:1:{i:0;s:24:"bx_timeline_simple_photo";}', 'a:1:{s:24:"bx_timeline_simple_photo";s:26:"_sys_uploader_simple_title";}', 0, 'files', '_bx_timeline_form_post_input_sys_photo', '_bx_timeline_form_post_input_photo', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_timeline_post', @sName, 'video', 'a:1:{i:0;s:24:"bx_timeline_simple_video";}', 'a:1:{s:24:"bx_timeline_simple_video";s:26:"_sys_uploader_simple_title";}', 0, 'files', '_bx_timeline_form_post_input_sys_video', '_bx_timeline_form_post_input_video', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_timeline_post', @sName, 'attachments', '', '', 0, 'custom', '_bx_timeline_form_post_input_sys_attachments', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_timeline_post', @sName, 'do_submit', '_bx_timeline_form_post_input_do_submit', '', 0, 'submit', '_bx_timeline_form_post_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_timeline_post_add', 'type', 2147483647, 1, 1),
+('bx_timeline_post_add', 'action', 2147483647, 1, 2),
+('bx_timeline_post_add', 'owner_id', 2147483647, 1, 3),
+('bx_timeline_post_add', 'text', 2147483647, 1, 4),
+('bx_timeline_post_add', 'location', 2147483647, 1, 5),
+('bx_timeline_post_add', 'link', 2147483647, 1, 6),
+('bx_timeline_post_add', 'photo', 2147483647, 1, 7),
+('bx_timeline_post_add', 'video', 2147483647, 1, 8),
+('bx_timeline_post_add', 'attachments', 2147483647, 1, 9),
+('bx_timeline_post_add', 'do_submit', 2147483647, 1, 10);
+
+-- Forms -> Attach link
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_timeline_attach_link', @sName, '_bx_timeline_form_attach_link', '', '', 'do_submit', 'bx_timeline_links', 'id', '', '', '', 0, 1, '', '');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_timeline_attach_link_add', @sName, 'bx_timeline_attach_link', '_bx_timeline_form_attach_link_display_add', 0);
+
+INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
+('bx_timeline_attach_link', @sName, 'url', '', '', 0, 'text', '_bx_timeline_form_attach_link_input_sys_url', '_bx_timeline_form_attach_link_input_url', '', 0, 0, 0, '', '', '', 'Preg', 'a:1:{s:4:"preg";s:0:"";}', '_bx_timeline_form_attach_link_input_url_err', '', '', 0, 0),
+('bx_timeline_attach_link', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_timeline_attach_link', @sName, 'do_submit', '_bx_timeline_form_attach_link_input_do_submit', '', 0, 'submit', '_bx_timeline_form_attach_link_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_timeline_attach_link', @sName, 'do_cancel', '_bx_timeline_form_attach_link_input_do_cancel', '', 0, 'button', '_bx_timeline_form_attach_link_input_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_timeline_attach_link_add', 'url', 2147483647, 1, 1),
+('bx_timeline_attach_link_add', 'controls', 2147483647, 1, 2),
+('bx_timeline_attach_link_add', 'do_submit', 2147483647, 1, 3),
+('bx_timeline_attach_link_add', 'do_cancel', 2147483647, 1, 4);
+
+
+-- STUDIO PAGE & WIDGET
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_timeline', '_bx_timeline', '_bx_timeline', 'bx_timeline@modules/boonex/timeline/|std-icon.svg');
+SET @iPageId = LAST_INSERT_ID();
+
+SET @iParentPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name` = 'home');
+SET @iParentPageOrder = (SELECT MAX(`order`) FROM `sys_std_pages_widgets` WHERE `page_id` = @iParentPageId);
+INSERT INTO `sys_std_widgets` (`page_id`, `module`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_timeline', '{url_studio}module.php?name=bx_timeline', '', 'bx_timeline@modules/boonex/timeline/|std-icon.svg', '_bx_timeline', '', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_actions";s:6:"params";a:0:{}s:5:"class";s:18:"TemplStudioModules";}');
+INSERT INTO `sys_std_pages_widgets` (`page_id`, `widget_id`, `order`) VALUES
+(@iParentPageId, LAST_INSERT_ID(), IF(ISNULL(@iParentPageOrder), 1, @iParentPageOrder + 1));

+ 49 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/install/sql/uninstall.sql

@@ -0,0 +1,49 @@
+SET @sName = 'bx_timeline';
+
+DROP TABLE IF EXISTS `bx_timeline_events`;
+DROP TABLE IF EXISTS `bx_timeline_handlers`;
+
+DROP TABLE IF EXISTS `bx_timeline_photos`;
+DROP TABLE IF EXISTS `bx_timeline_photos_processed`;
+DROP TABLE IF EXISTS `bx_timeline_photos2events`;
+
+DROP TABLE IF EXISTS `bx_timeline_videos`;
+DROP TABLE IF EXISTS `bx_timeline_videos_processed`;
+DROP TABLE IF EXISTS `bx_timeline_videos2events`;
+
+DROP TABLE IF EXISTS `bx_timeline_links`;
+DROP TABLE IF EXISTS `bx_timeline_links2events`;
+
+DROP TABLE IF EXISTS `bx_timeline_reposts_track`;
+
+DROP TABLE IF EXISTS `bx_timeline_comments`;
+
+DROP TABLE IF EXISTS `bx_timeline_views_track`;
+
+DROP TABLE IF EXISTS `bx_timeline_votes`;
+DROP TABLE IF EXISTS `bx_timeline_votes_track`;
+
+DROP TABLE IF EXISTS `bx_timeline_meta_keywords`;
+DROP TABLE IF EXISTS `bx_timeline_meta_locations`;
+
+DROP TABLE IF EXISTS `bx_timeline_reports`;
+DROP TABLE IF EXISTS `bx_timeline_reports_track`;
+
+
+-- STORAGES, TRANSCODERS, UPLOADERS
+DELETE FROM `sys_objects_uploader` WHERE `object` LIKE 'bx_timeline%';
+DELETE FROM `sys_objects_storage` WHERE `object`  LIKE 'bx_timeline%';
+DELETE FROM `sys_objects_transcoder` WHERE `object`  LIKE 'bx_timeline%';
+DELETE FROM `sys_transcoder_filters` WHERE `transcoder_object` LIKE 'bx_timeline%';
+
+
+-- Forms All
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN  (SELECT `display_name` FROM `sys_form_displays` WHERE `module` = @sName);
+DELETE FROM `sys_form_inputs` WHERE `module` = @sName;
+DELETE FROM `sys_form_displays` WHERE `module` = @sName;
+DELETE FROM `sys_objects_form` WHERE `module` = @sName;
+
+-- STUDIO PAGE & WIDGET
+DELETE FROM `tp`, `tw`, `tpw`
+USING `sys_std_pages` AS `tp`, `sys_std_widgets` AS `tw`, `sys_std_pages_widgets` AS `tpw`
+WHERE `tp`.`id` = `tw`.`page_id` AND `tw`.`id` = `tpw`.`widget_id` AND `tp`.`name` = @sName;

+ 249 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/js/main.js

@@ -0,0 +1,249 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Timeline Timeline
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxTimelineMain() {
+	this.sIdPost = '#bx-timeline-post';
+
+	this.sIdView = '#bx-timeline-';
+	this.sIdViewTimeline = '#bx-timeline-timeline';
+	this.sIdViewOutline = '#bx-timeline-outline';
+	this.sIdItem = '#bx-timeline-item-';
+	this.sIdItemTimeline = '#bx-timeline-item-timeline-';
+	this.sIdItemOutline = '#bx-timeline-item-outline-';
+
+	this.sSP = 'bx-tl';
+	this.sClassView = this.sSP + '-view';
+	this.sClassMasonry = this.sSP + '-masonry';
+	this.sClassItems = this.sSP + '-items';
+	this.sClassItem = this.sSP + '-item';
+	this.sClassDividerToday = this.sSP + '-divider-today';
+	this.sClassItemComments = this.sSP + '-item-comments-holder';
+	this.sClassItemImages = this.sSP + '-item-images';
+	this.sClassItemImage = this.sSP + '-item-image';
+
+	this.oViewTimeline = null;
+	this.bViewTimeline = false;
+
+	this.oViewOutline = null;
+	this.bViewOutline = false;
+}
+
+BxTimelineMain.prototype.isMasonry = function() {
+	return $(this.sIdViewOutline + ' .' + this.sClassItems).hasClass(this.sClassMasonry);
+};
+
+BxTimelineMain.prototype.isMasonryEmpty = function() {
+	return $(this.sIdViewOutline + ' .' + this.sClassItems + ' .' + this.sClassItem).length == 0;
+};
+
+BxTimelineMain.prototype.initMasonry = function(onComplete) {
+	var $this = this;
+	var oHolder = $(this.sIdViewOutline + ' .' + this.sClassItems);
+
+	var oItems = oHolder.find('.' + this.sClassItem);
+	if(oItems.length == 0) 
+		return;
+
+	oItems.resize(function(){
+		$this.reloadMasonry();
+	});
+
+	oHolder.addClass(this.sClassMasonry).masonry({
+	  itemSelector: '.' + this.sClassItem,
+	  columnWidth: '.' + this.sSP + '-grid-sizer'
+	}).masonry('once', 'layoutComplete', function() {
+		if(typeof onComplete === 'function')
+			onComplete(oItems);
+	});
+};
+
+BxTimelineMain.prototype.destroyMasonry = function() {
+	$(this.sIdViewOutline + ' .' + this.sClassItems).removeClass(this.sClassMasonry).masonry('destroy');
+};
+
+BxTimelineMain.prototype.appendMasonry = function(oItems, onComplete) {
+	var $this = this;
+	var oItems = $(oItems);
+	oItems.resize(function(){
+		$this.reloadMasonry();
+	}).find('iframe').load(function() {
+		$this.reloadMasonry();
+	}).find('img.' + this.sSP + '-item-image').load(function() {
+		$this.reloadMasonry();
+	});
+
+	var oHolder = $(this.sIdViewOutline + ' .' + this.sClassItems).masonry('layout').append(oItems);
+	if(!this.isMasonry())
+		this.initMasonry(onComplete);
+	else
+		oHolder.masonry('appended', oItems).masonry('layout').masonry('once', 'layoutComplete', function() {
+			if(typeof onComplete === 'function')
+				onComplete(oItems);
+		});
+};
+
+BxTimelineMain.prototype.prependMasonry = function(oItems, onComplete) {
+	var $this = this;
+	var oItems = $(oItems);
+	oItems.resize(function(){
+		$this.reloadMasonry();
+	}).find('iframe').load(function() {
+		$this.reloadMasonry();
+	}).find('img.' + this.sSP + '-item-image').load(function() {
+		$this.reloadMasonry();
+	});
+
+	var oHolder = $(this.sIdViewOutline + ' .' + this.sClassItems).masonry('layout').prepend(oItems);
+	if(!this.isMasonry())
+		this.initMasonry(onComplete);
+	else
+		oHolder.masonry('prepended', oItems).masonry('layout').masonry('once', 'layoutComplete', function() {
+			if(typeof onComplete === 'function')
+				onComplete(oItems);
+		});
+};
+
+BxTimelineMain.prototype.removeMasonry = function(oItems, onRemove) {
+	var $this = this;
+	var oItems = $(oItems);
+
+	var oHolder = $(this.sIdViewOutline + ' .' + this.sClassItems);
+	if(typeof onRemove === 'function')
+		oHolder.masonry('once', 'removeComplete', onRemove);
+
+	oHolder.masonry('remove', oItems).masonry('layout');
+};
+
+BxTimelineMain.prototype.reloadMasonry = function() {
+	$(this.sIdViewOutline + ' .' + this.sClassItems).masonry('reloadItems').masonry('layout');
+};
+
+BxTimelineMain.prototype.initFlickity = function() {
+	var $this = this;
+
+	$('.' + this.sClassItem + ' .' + this.sClassItemImages).each(function() {
+		if($(this).find('.' + $this.sClassItemImage).length <= 1)
+			return;
+
+		$(this).flickity({
+			cellSelector: 'div.' + $this.sClassItemImage,
+			cellAlign: 'left',
+			pageDots: false,
+			imagesLoaded: true
+		});
+	});
+};
+
+BxTimelineMain.prototype.processResult = function(oData) {
+	var $this = this;
+
+	if(oData && oData.msg != undefined && oData.msg.length != 0)
+    	alert(oData.msg);
+
+	if(oData && oData.message != undefined && oData.message.length != 0)
+    	alert(oData.message);
+
+    if(oData && oData.reload != undefined && parseInt(oData.reload) == 1)
+    	document.location = document.location;
+
+    if(oData && oData.popup != undefined) {
+    	var oPopup = null;
+    	var oOptions = {
+            fog: {
+				color: '#fff',
+				opacity: .7
+            },
+            closeOnOuterClick: false
+        };
+
+    	if(typeof(oData.popup) == 'object') {
+    		oOptions = $.extend({}, oOptions, oData.popup.options);
+    		oPopup = $(oData.popup.html);
+    	}
+    	else 
+    		oPopup = $(oData.popup);
+
+    	$('#' + oPopup.attr('id')).remove();
+        oPopup.hide().prependTo('body').bxTime().dolPopup(oOptions);
+    }
+
+    if (oData && oData.eval != undefined)
+        eval(oData.eval);
+};
+
+BxTimelineMain.prototype.loadingInButton = function(e, bShow) {
+	if($(e).length)
+		bx_loading_btn($(e), bShow);
+	else
+		bx_loading($('body'), bShow);	
+};
+
+BxTimelineMain.prototype.loadingInItem = function(e, bShow) {
+	var oParent = $('body');
+	if($(e).length)
+		oParent = !$(e).hasClass(this.sClassItem) ? $(e).parents('.' + this.sClassItem + ':first') : $(e);
+
+	bx_loading(oParent, bShow);
+};
+
+BxTimelineMain.prototype.loadingInBlock = function(e, bShow) {
+	var oParent = $(e).length ? $(e).parents('.bx-db-container:first') : $('body'); 
+	bx_loading(oParent, bShow);
+};
+
+BxTimelineMain.prototype.loadingInPopup = function(e, bShow) {
+	var oParent = $(e).length ? $(e).parents('.bx-popup-content:first') : $('body'); 
+	bx_loading(oParent, bShow);
+};
+
+BxTimelineMain.prototype.loadingIn = function(e, bShow) {
+	var oElement = $(e);
+	var bElement = oElement.length > 0;
+
+	if(bElement && oElement.hasClass('bx-btn'))
+		this.loadingInButton(e, bShow);
+	else if(bElement && (oElement.hasClass(this.sClassItem) || oElement.parents('.' + this.sClassItem + ':first').length > 0))
+		this.loadingInItem(e, bShow);
+	else if(bElement && oElement.parents('.bx-popup-content:first').length > 0)
+		this.loadingInPopup(e, bShow);
+	else if(bElement && oElement.parents('.bx-db-container:first').length > 0)
+		this.loadingInBlock(e, bShow);
+	else 
+		bx_loading($('body'), bShow);
+};
+
+BxTimelineMain.prototype._loading = function(e, bShow) {
+	var oParent = $(e).length ? $(e) : $('body'); 
+	bx_loading(oParent, bShow);
+};
+
+BxTimelineMain.prototype._getView = function(oView) {
+	oView = $(oView);
+	if(!oView.hasClass(this.sClassView))
+		oView = oView.parents('.bx-db-container:first').find('.' + this.sClassView + ':first');
+
+	if(oView.hasClass(this.sClassView + '-timeline'))
+		return 'timeline';
+
+	if(oView.hasClass(this.sClassView + '-outline'))
+		return 'outline';
+
+	return '';
+};
+
+BxTimelineMain.prototype._getDefaultData = function(oElement) {
+	var oDate = new Date();
+	var sView = oElement != undefined ? this._getView(oElement) : '';
+
+    return jQuery.extend({}, this._oRequestParams[sView.length > 0 ? sView : 'general'], {
+    	view: sView,
+		_t:oDate.getTime()
+    });
+};

+ 257 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/js/post.js

@@ -0,0 +1,257 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Timeline Timeline
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxTimelinePost(oOptions) {
+	this._sActionsUri = oOptions.sActionUri;
+    this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjName = oOptions.sObjName == undefined ? 'oTimelinePost' : oOptions.sObjName;
+    this._iOwnerId = oOptions.iOwnerId == undefined ? 0 : parseInt(oOptions.iOwnerId);
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'slide' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this._aHtmlIds = oOptions.aHtmlIds == undefined ? {} : oOptions.aHtmlIds;
+    this._oRequestParams = oOptions.oRequestParams == undefined ? {} : oOptions.oRequestParams;
+
+    var $this = this;
+    $(document).ready(function () {
+    	$($this.sIdPost + ' form').each(function() {
+    		var sId = $(this).attr('id');
+    		$this.initFormPost(sId);
+    	});
+	});
+}
+
+BxTimelinePost.prototype = new BxTimelineMain();
+
+BxTimelinePost.prototype.initFormPost = function(sFormId)
+{
+	var $this = this;
+	var oForm = $('#' + sFormId);
+
+	autosize(oForm.find('textarea'));
+	oForm.ajaxForm({
+        dataType: "json",
+        beforeSubmit: function (formData, jqForm, options) {
+        	window[$this._sObjName].beforeFormPostSubmit(oForm);
+        },
+        success: function (oData) {
+        	window[$this._sObjName].afterFormPostSubmit(oForm, oData);
+        }
+    });
+};
+
+BxTimelinePost.prototype.beforeFormPostSubmit = function(oForm)
+{
+	this.loadingInButton($(oForm).children().find(':submit'), true);
+};
+
+BxTimelinePost.prototype.afterFormPostSubmit = function (oForm, oData)
+{
+	this.loadingInButton($(oForm).children().find(':submit'), false);
+
+	if(oData && oData.msg != undefined)
+        alert(oData.msg);
+
+	if(oData && oData.id != undefined) {
+		var iId = parseInt(oData.id);
+        if(iId <= 0) 
+        	return;
+
+        if($('#' + this._aHtmlIds['main_timeline']).length)
+        	this._getPost(oForm, iId, 'timeline');
+
+        if($('#' + this._aHtmlIds['main_outline']).length)
+        	this._getPost(oForm, iId, 'outline');
+
+        this._getForm(oForm, $(oForm).find("input[name = 'type']").val());
+
+        return;
+	}
+
+	if(oData && oData.form != undefined && oData.form_id != undefined) {
+		$('#' + oData.form_id).replaceWith(oData.form);
+		this.initFormPost(oData.form_id);
+
+		return;
+	}
+};
+
+BxTimelinePost.prototype.initFormAttachLink = function(sFormId)
+{
+	var $this = this;
+	var oForm = $('#' + sFormId);
+
+	oForm.ajaxForm({
+        dataType: "json",
+        clearForm: true,
+        beforeSubmit: function (formData, jqForm, options) {
+        	window[$this._sObjName].beforeFormAttachLinkSubmit(oForm);
+        },
+        success: function (oData) {
+        	window[$this._sObjName].afterFormAttachLinkSubmit(oForm, oData);
+        }
+    });
+};
+
+BxTimelinePost.prototype.beforeFormAttachLinkSubmit = function(oForm)
+{
+	this.loadingInButton($(oForm).children().find(':submit'), true);
+};
+
+BxTimelinePost.prototype.afterFormAttachLinkSubmit = function (oForm, oData)
+{
+	oForm = $(oForm);
+	this.loadingInButton(oForm.find(':submit'), false);
+
+	if(oData && oData.msg != undefined)
+        alert(oData.msg);
+
+	if(oData && oData.item != undefined) {
+		$('#' + this._aHtmlIds['attach_link_popup']).dolPopupHide({onHide: function() {
+			oForm.find('.bx-form-warn').hide();
+		}});
+
+		if(!$.trim(oData.item).length)
+			return;
+
+		var oItem = $(oData.item).hide();
+		$('#' + this._aHtmlIds['attach_link_form_field']).prepend(oItem).find('#' + oItem.attr('id')).bx_anim('show', this._sAnimationEffect, this._sAnimationSpeed, function() {
+			$(this).find('a.bx-link-embed').dolEmbedly();
+		});
+
+        return;
+	}
+
+	if(oData && oData.form != undefined && oData.form_id != undefined) {
+		$('#' + oData.form_id).replaceWith(oData.form);
+		this.initFormAttachLink(oData.form_id);
+
+		return;
+	}
+};
+
+BxTimelinePost.prototype.deleteAttachLink = function(oLink, iId) {
+	var $this = this;
+    var oData = this._getDefaultData();
+    oData['id'] = iId;
+
+    var oAttachLink = $('#' + this._aHtmlIds['attach_link_item'] + iId);
+    bx_loading(oAttachLink, true);
+    
+    jQuery.post (
+        this._sActionsUrl + 'delete_attach_link/',
+        oData,
+        function(oData) {
+        	bx_loading(oAttachLink, false);
+
+        	if(oData && oData.msg != undefined)
+                alert(oData.msg);
+
+        	if(oData && oData.code != undefined && oData.code == 0) {
+        		oAttachLink.bx_anim('hide', $this._sAnimationEffect, $this._sAnimationSpeed, function() {
+        			$(this).remove;
+        		});
+        	}
+        },
+        'json'
+    );
+
+	return false;
+};
+
+BxTimelinePost.prototype.showAttachLink = function(oLink) {
+	var oData = this._getDefaultData();    
+
+    $(window).dolPopupAjax({
+		id: {value: this._aHtmlIds['attach_link_popup'], force: true},
+		url: bx_append_url_params(this._sActionsUri + 'get_attach_link_form/', oData),
+		closeOnOuterClick: false
+	});
+
+	return false;
+};
+
+BxTimelinePost.prototype._getForm = function(oElement, sType) {
+    var $this = this;
+    var oData = this._getDefaultData();
+
+    jQuery.post (
+	    this._sActionsUrl + 'get_post_form/' + sType + '/',
+	    oData,
+	    function(oData) {
+            if(oData && oData.form != undefined && oData.form_id != undefined) {
+                $('#' + oData.form_id).replaceWith(oData.form);
+                $this.initFormPost(oData.form_id);
+            }
+	    },
+	    'json'
+	);
+};
+
+BxTimelinePost.prototype._getPost = function(oElement, iId, sView) {
+    var $this = this;
+    var oData = this._getDefaultData();
+    oData['id'] = iId;
+    oData['view'] = sView;
+
+    var oElementView = $('#' + this._aHtmlIds['main_' + sView]);
+    this.loadingInBlock(oElementView, true);
+
+    jQuery.post (
+        this._sActionsUrl + 'get_post/',
+        oData,
+        function(oData) {
+        	$this.loadingInBlock(oElementView, false);
+
+        	$this.processResult(oData);
+        },
+        'json'
+    );
+};
+
+BxTimelinePost.prototype._onGetPost = function(oData) {
+	if(!$.trim(oData.item).length) 
+		return;
+
+	var oView = $('#' + this._aHtmlIds['main_' + oData.view]);
+
+	var oLoadMore = oView.find('.' + this.sSP + '-load-more');
+	if(!oLoadMore.is(':visible'))
+		oLoadMore.show();
+
+	var oEmpty = oView.find('.' + this.sSP + '-empty');
+	if(oEmpty.is(':visible'))
+		oEmpty.hide();
+
+	var oContent = $(oData.item).bxTime();
+	switch(oData.view) {
+		case 'timeline':
+			var oItem = null;
+			var oItems = $('#' + this._aHtmlIds['main_timeline'] + ' ' + '.' + this.sClassItems);
+			var oDivider  = oItems.find('.' + this.sClassDividerToday);
+			var bDivider = oDivider.length > 0;
+
+			if(bDivider && !oDivider.is(':visible'))
+				oDivider.show();
+
+			oContent.hide();
+
+			oItem = bDivider ? oDivider.after(oContent).next('.' + this.sClassItem + ':hidden') : oContent.prependTo(oItems);
+			oItem.bx_anim('show', this._sAnimationEffect, this._iAnimationSpeed, function() {
+				$(this).find('a.bx-link-embed').dolEmbedly();
+			});
+			break;
+
+		case 'outline':
+			this.prependMasonry(oContent, function(oItems) {
+				$(oItems).find('a.bx-link-embed').dolEmbedly();
+			});
+			break;
+	}
+};

+ 86 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/js/repost.js

@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Timeline Timeline
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxTimelineRepost(oOptions) {
+	this._sActionsUri = oOptions.sActionUri;
+    this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjName = oOptions.sObjName == undefined ? 'oTimelineRepost' : oOptions.sObjName;
+    this._iOwnerId = oOptions.iOwnerId == undefined ? 0 : oOptions.iOwnerId;
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'slide' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this._aHtmlIds = oOptions.aHtmlIds == undefined ? {} : oOptions.aHtmlIds;
+    this._oRequestParams = oOptions.oRequestParams == undefined ? {} : oOptions.oRequestParams;
+}
+
+BxTimelineRepost.prototype = new BxTimelineMain();
+
+BxTimelineRepost.prototype.repostItem = function(oLink, iOwnerId, sType, sAction, iId) {
+	var $this = this;
+	var oDate = new Date();
+	var oParams = {
+		owner_id: iOwnerId,
+		type: sType,
+		action: sAction,
+		object_id: iId,
+		_t: oDate.getTime()	
+	};
+
+	this.loadingIn(oLink, true);
+
+	jQuery.post(
+        this._sActionsUrl + 'repost/',
+        oParams,
+        function(oData) {
+        	$this.loadingIn(oLink, false);
+
+        	var oPopup = $(oLink).parents('.bx-popup-applied:visible:first');
+        	if(oPopup.length >0)
+        		oPopup.dolPopupHide();
+
+        	var oCounter = $this._getCounter(oLink);
+        	var bCounter = oCounter && oCounter.length > 0;
+        	
+        	if(oData && oData.msg != undefined && oData.msg.length > 0 && !bCounter)
+                alert(oData.msg);
+        	
+        	if(oData && oData.counter != undefined && bCounter) {
+        		var oCounterHolder = oCounter.parents('.' + $this.sSP + '-repost-counter-holder:first');
+
+        		oCounter.replaceWith(oData.counter);
+        		oCounterHolder.bx_anim(oData.count > 0 ? 'show' : 'hide');
+        	}
+
+        	if(oData && oData.disabled)
+    			$(oLink).removeAttr('onclick').addClass($(oLink).hasClass('bx-btn') ? 'bx-btn-disabled' : $this.sSP + '-repost-disabled');
+        },
+        'json'
+    );
+};
+
+BxTimelineRepost.prototype.toggleByPopup = function(oLink, iId) {
+    var oData = this._getDefaultData();
+    oData['id'] = iId;
+
+	$(oLink).dolPopupAjax({
+		id: this._aHtmlIds['by_popup'] + iId, 
+		url: bx_append_url_params(this._sActionsUri + 'get_reposted_by/', oData)
+	});
+
+	return false;
+};
+
+BxTimelineRepost.prototype._getCounter = function(oElement) {
+	var sSPRepost = this.sSP + '-repost';
+
+	if($(oElement).hasClass(sSPRepost))
+		return $(oElement).find('.' + sSPRepost + '-counter');
+	else 
+		return $(oElement).parents('.' + sSPRepost + ':first').find('.' + sSPRepost + '-counter');
+};

+ 384 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/js/view.js

@@ -0,0 +1,384 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Timeline Timeline
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxTimelineView(oOptions) {
+	this._sActionsUri = oOptions.sActionUri;
+    this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjName = oOptions.sObjName == undefined ? 'oTimelineView' : oOptions.sObjName;
+    this._iOwnerId = oOptions.iOwnerId == undefined ? 0 : oOptions.iOwnerId;
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'slide' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this._aHtmlIds = oOptions.aHtmlIds == undefined ? {} : oOptions.aHtmlIds;
+    this._oRequestParams = {
+    	timeline: null,
+    	outline: null,
+    	general: oOptions.oRequestParams == undefined ? {} : oOptions.oRequestParams
+    };
+
+    this._fOutsideOffset = 0.8;
+
+    var $this = this;
+    $(document).ready(function() {
+    	$this.init();
+    });
+}
+
+BxTimelineView.prototype = new BxTimelineMain();
+
+BxTimelineView.prototype.init = function() {
+	var $this = this;
+
+	this.oViewTimeline = $('#' + this._aHtmlIds['main_timeline']);
+	this.bViewTimeline = this.oViewTimeline.length > 0;
+
+	this.oViewOutline = $('#' + this._aHtmlIds['main_outline']);
+	this.bViewOutline = this.oViewOutline.length > 0;	
+
+	if(this.bViewTimeline) {
+		this._oRequestParams['timeline'] = jQuery.extend({}, this._oRequestParams['general']);
+
+		var oItems = this.oViewTimeline.find('.' + this.sClassItem);
+
+		//--- Hide timeline Events which are outside the viewport
+		this.hideEvents(oItems, this._fOutsideOffset);
+
+		//on scolling, show/animate timeline Events when enter the viewport
+		$(window).on('scroll', function() {
+			if(!window.requestAnimationFrame) 
+				setTimeout(function() {
+					$this.showEvents(oItems, $this._fOutsideOffset);
+				}, 100);
+			else
+				window.requestAnimationFrame(function() {
+					$this.showEvents(oItems, $this._fOutsideOffset);
+				});
+		});
+	}
+
+	if(this.bViewOutline) {
+		this._oRequestParams['outline'] = jQuery.extend({}, this._oRequestParams['general']);
+
+    	this.initMasonry();
+
+    	this.oViewOutline.find('.' + this.sClassItem).resize(function() {
+    		$this.reloadMasonry();
+    	});
+    	this.oViewOutline.find('img.' + this.sClassItemImage).load(function() {
+    		$this.reloadMasonry();
+    	});
+	}
+
+	this.initFlickity();
+};
+
+BxTimelineView.prototype.hideEvents = function(oEvents, fOffset) {
+	oEvents.each(function() {
+		( $(this).offset().top > $(window).scrollTop() + $(window).height() * fOffset ) && $(this).find('.bx-tl-item-type, .bx-tl-item-cnt').addClass('is-hidden');
+	});
+};
+
+BxTimelineView.prototype.showEvents = function(oEvents, fOffset) {
+	oEvents.each(function() {
+		( $(this).offset().top <= $(window).scrollTop() + $(window).height() * fOffset && $(this).find('.bx-tl-item-type').hasClass('is-hidden') ) && $(this).find('.bx-tl-item-type, .bx-tl-item-cnt').removeClass('is-hidden').addClass('bounce-in');
+	});
+};
+
+BxTimelineView.prototype.changePage = function(oLink, iStart, iPerPage) {
+	var $this = this;
+	var sView = this._getView(oLink);
+
+	this.loadingInButton(oLink, true);
+
+	this._oRequestParams[sView].start = iStart;
+    this._oRequestParams[sView].per_page = iPerPage;
+    this._getPosts(oLink, function(oData) {
+    	$this.loadingInButton(oLink, false);
+
+    	var oView = null;
+    	var sItems = $.trim(oData.items);
+    	switch(sView) {
+    		case 'timeline':
+    			oView = $this.oViewTimeline;
+    			oView.find('.' + $this.sClassItems).append($(sItems).hide()).find('.' + $this.sClassItem + ':hidden').bx_anim('show', $this._sAnimationEffect, $this._iAnimationSpeed, function() {
+					$(this).bxTime();
+			    });
+    			break;
+
+    		case 'outline':
+    			oView = $this.oViewOutline;
+    			$this.appendMasonry($(sItems).bxTime());
+    			break;
+    	}
+
+    	if(oView && oData && oData.load_more != undefined)
+    		oView.find('.' + $this.sSP + '-load-more-holder').html($.trim(oData.load_more));
+
+    	if(oView && oData && oData.back != undefined)
+    		oView.find('.' + $this.sSP + '-back-holder').html($.trim(oData.back));
+
+    	if(oData && oData.empty != undefined)
+			oView.find('.' + $this.sSP + '-empty-holder').html($.trim(oData.empty));
+    });
+};
+
+BxTimelineView.prototype.changeFilter = function(oLink) {
+	var sView = this._getView(oLink);
+
+    var sId = $(oLink).attr('id');
+    sId = sId.substr(sId.lastIndexOf('-') + 1, sId.length);
+
+    this.loadingInBlock(oLink, true);
+
+    this._oRequestParams[sView].start = 0;
+    this._oRequestParams[sView].filter = sId;
+    this._getPosts(oLink);
+};
+
+BxTimelineView.prototype.changeTimeline = function(oLink, iYear) {
+	var sView = this._getView(oLink);
+
+	this.loadingInBlock(oLink, true);
+
+	this._oRequestParams[sView].start = 0;
+    this._oRequestParams[sView].timeline = iYear;
+	this._getPosts(oLink);
+	
+	console.log(this._oRequestParams);
+};
+
+BxTimelineView.prototype.showMoreContent = function(oLink) {
+	var sView = this._getView(oLink);
+
+	$(oLink).parent('span').next('span').show().prev('span').remove();
+
+	switch(sView) {
+		case 'timeline':
+			break;
+	
+		case 'outline':
+			this.reloadMasonry();
+			break;
+	}	
+};
+
+BxTimelineView.prototype.showPhoto = function(oLink, sUrl) {
+	var sView = this._getView(oLink);
+
+	$('#' + this._aHtmlIds['photo_popup_' + sView]).dolPopupImage(sUrl, $(oLink).parent());
+};
+
+BxTimelineView.prototype.commentItem = function(oLink, sSystem, iId) {
+	var $this = this;
+    var oData = this._getDefaultData(oLink);
+    oData['system'] = sSystem;
+    oData['id'] = iId;
+
+    var oComments = $(oLink).parents('.' + this.sClassItem + ':first').find('.' + this.sClassItemComments);
+    if(oComments.children().length > 0) {
+    	oComments.bx_anim('toggle', this._sAnimationEffect, this._iAnimationSpeed);
+    	return;
+    }
+
+    if(oLink)
+    	this.loadingInItem(oLink, true);
+
+    jQuery.get (
+        this._sActionsUrl + 'get_comments',
+        oData,
+        function(oData) {
+        	if(oLink)
+        		$this.loadingInItem(oLink, false);
+
+        	if(!oData.content)
+        		return;
+
+        	oComments.html($(oData.content).hide()).children(':hidden').bxTime().bx_anim('show', $this._sAnimationEffect, $this._iAnimationSpeed);
+        },
+        'json'
+    );
+};
+
+BxTimelineView.prototype.pinPost = function(oLink, iId, iWay) {
+	var $this = this;
+    var oData = this._getDefaultData();
+    oData['id'] = iId;
+
+    $(oLink).parents('.bx-popup-applied:first:visible').dolPopupHide({
+		onHide: function(oPopup) {
+			$(oPopup).remove();
+		}
+	});
+
+    if(this.bViewTimeline)
+    	this.loadingInItem($(this.sIdItemTimeline + iId), true);
+
+    if(this.bViewOutline)
+    	this.loadingInItem($(this.sIdItemOutline + iId), true);
+
+    $.post(
+        this._sActionsUrl + 'pin/',
+        oData,
+        function(oData) {
+        	$this.processResult(oData);
+        },
+        'json'
+    );
+};
+
+BxTimelineView.prototype.onPinPost = function(oData) {
+	var $this = this;
+
+	//--- Pin on Timeline (if available)
+	if(this.bViewTimeline) {
+		var sItemTimeline = this.sIdItemTimeline + oData.id;
+
+		this._oRequestParams['timeline'].start = 0;
+        this._getPosts(this.oViewTimeline, function(oData) {
+        	$(sItemTimeline).bx_anim('hide', $this._sAnimationEffect, $this._iAnimationSpeed, function() {
+    	        $(this).remove();
+
+    	        $this.processResult(oData);
+        	});
+        });
+	}
+
+	//--- Pin on Outline (if available)
+	if(this.bViewOutline) {
+		var sItemOutline = this.sIdItemOutline + oData.id;
+
+		this._oRequestParams['outline'].start = 0;
+        this._getPosts(this.oViewOutline, function(oData) {
+        	$this.removeMasonry(sItemOutline, function() {
+        		$this.processResult(oData);
+    		});
+        });
+	}
+};
+
+BxTimelineView.prototype.deletePost = function(oLink, iId) {
+    var $this = this;
+    var oData = this._getDefaultData();
+    oData['id'] = iId;
+
+    $(oLink).parents('.bx-popup-applied:first:visible').dolPopupHide();
+
+    if(this.bViewTimeline)
+    	this.loadingInItem($(this.sIdItemTimeline + iId), true);
+
+    if(this.bViewOutline)
+    	this.loadingInItem($(this.sIdItemOutline + iId), true);
+
+    $.post(
+        this._sActionsUrl + 'delete/',
+        oData,
+        function(oData) {
+        	$this.processResult(oData);
+        },
+        'json'
+    );
+};
+
+BxTimelineView.prototype.onDeletePost = function(oData) {
+	var $this = this;
+
+	//--- Delete from Timeline (if available)
+	if(this.bViewTimeline) {
+		$(this.sIdItemTimeline + oData.id).bx_anim('hide', this._sAnimationEffect, this._iAnimationSpeed, function() {
+	        $(this).remove();
+
+	        if($this.oViewTimeline.find('.' + $this.sClassItem).length == 0) {
+	        	$this.oViewTimeline.find('.' + $this.sClassDividerToday).hide();
+	        	$this.oViewTimeline.find('.' + $this.sSP + '-load-more').hide();
+	        	$this.oViewTimeline.find('.' + $this.sSP + '-empty').show();
+	        }
+	    });
+	}
+
+	//--- Delete from Outline (if available)
+	if(this.bViewOutline) {
+		$(this.sIdItemOutline + oData.id).bx_anim('hide', this._sAnimationEffect, this._iAnimationSpeed, function() {
+	        $(this).remove();
+
+	        if($this.oViewOutline.find('.' + $this.sClassItem).length == 0) {
+	        	$this.destroyMasonry();
+
+	        	$this.oViewOutline.find('.' + $this.sSP + '-load-more').hide();
+	        	$this.oViewOutline.find('.' + $this.sSP + '-empty').show();
+	        } 
+	        else
+	        	$this.reloadMasonry();
+	    });
+	}
+};
+
+BxTimelineView.prototype._getPosts = function(oElement, onComplete) {
+	var $this = this;
+	var oData = this._getDefaultData(oElement);
+
+	jQuery.get(
+        this._sActionsUrl + 'get_posts/',
+        oData,
+        function(oData) {
+        	if(typeof onComplete === 'function')
+        		return onComplete(oData);
+
+        	$this.loadingInBlock(oElement, false);
+
+        	$this.processResult(oData);
+        },
+        'json'
+    );
+};
+
+BxTimelineView.prototype._onGetPosts = function(oData) {
+	var $this = this;
+	var oView = $('#' + this._aHtmlIds['main_' + oData.view]);
+
+	var onComplete = function() {
+		if(oData && oData.load_more != undefined)
+			oView.find('.' + $this.sSP + '-load-more-holder').html($.trim(oData.load_more));
+
+		if(oData && oData.back != undefined)
+			oView.find('.' + $this.sSP + '-back-holder').html($.trim(oData.back));
+
+		if(oData && oData.empty != undefined)
+			oView.find('.' + $this.sSP + '-empty-holder').html($.trim(oData.empty));
+	};
+
+	if(oData && oData.items != undefined) {
+		var sItems = $.trim(oData.items);
+
+		switch(oData.view) {
+			case 'timeline':
+				oView.find('.' + this.sClassItems).bx_anim('hide', this._sAnimationEffect, this._iAnimationSpeed, function() {
+					$(this).html(sItems).show().bxTime();
+
+					onComplete();
+			    });
+				break;
+
+			case 'outline':
+				oView.find('.' + this.sClassItems).bx_anim('hide', this._sAnimationEffect, this._iAnimationSpeed, function() {
+			        $(this).html(sItems).show().bxTime();
+
+			        if($this.isMasonry())
+			        	$this.destroyMasonry();
+
+			        if(!$this.isMasonryEmpty())
+			        	$this.initMasonry();
+
+			        onComplete();
+			    });
+				break;
+		}
+	}
+
+	
+};

+ 18 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/attach_link_item.html

@@ -0,0 +1,18 @@
+<div id="__html_id__" class="__style_prefix__-al-item bx-def-margin-sec-top">
+    <bx_if:show_embed_outer>
+       <div class="__style_prefix__-ali-embed">__embed__</div>
+    </bx_if:show_embed_outer>
+    <bx_if:show_embed_inner>
+		<bx_if:show_thumbnail>
+			<div class="__style_prefix__-ali-thumbnail">
+				<img src="__thumbnail__" />
+			</div>
+		</bx_if:show_thumbnail>
+		<div class="__style_prefix__-ali-title">__link__</div>
+		<div class="__style_prefix__-ali-url bx-def-font-grayed">__url__</div>
+    </bx_if:show_embed_inner>
+	<div class="__style_prefix__-ali-actions bx-def-margin-sec-top bx-clearfix">
+		<a class="bx-btn bx-btn-small" href="javascript:void(0)" onclick="javascript:__js_object__.deleteAttachLink(this, __id__)"><bx_text:_Delete /></a>
+		<input type="hidden" name="link[]" value="__id__" />
+	</div>
+</div>

+ 9 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/block_item.html

@@ -0,0 +1,9 @@
+<div id="__html_id__" class="__style_prefix__-view __style_prefix__-view-item bx-def-bc-margin">
+	<div class="__style_prefix__-cnt">
+        <div class="__style_prefix__-items-wrapper">
+            <div class="__style_prefix__-items bx-def-margin-sec-leftright-neg">__content__</div>
+        </div>
+	</div>
+	__view_image_popup__
+    __js_content__
+</div>

+ 12 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/block_view.html

@@ -0,0 +1,12 @@
+<div id="__html_id__" class="__style_prefix__-view __style_prefix__-view-__view__ bx-def-bc-margin">
+	<div class="__style_prefix__-cnt">
+        <div class="__style_prefix__-back-holder">__back__</div>
+        <div class="__style_prefix__-empty-holder">__empty__</div>
+        <div class="__style_prefix__-items-wrapper">
+            <div class="__style_prefix__-items bx-def-margin-sec-leftright-neg">__content__</div>
+        </div>
+		<div class="__style_prefix__-load-more-holder">__load_more__</div>
+	</div>
+	__view_image_popup__
+    __js_content__
+</div>

+ 76 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/css/post.css

@@ -0,0 +1,76 @@
+div.bx-tl-post {
+    position: relative;
+}
+div.bx-tl-post-cnt {
+    position: relative;
+    display: block;
+}
+
+/*--- Post Form Styles ---*/
+div#bx-timeline-post textarea.bx-form-input-textarea {
+	height: 36px;
+    height: 2.2rem;
+}
+
+div#bx-timeline-post div#bx-form-element-link,
+div#bx-timeline-post div#bx-form-element-photo,
+div#bx-timeline-post div#bx-form-element-video,
+div#bx-timeline-post .bx-form-input-files-uploaders {
+	margin-top: 0px;
+}
+div#bx-timeline-post div#bx-form-element-attachments {
+	position: absolute;
+	z-index: 1;
+
+	right: 0px;
+}
+div.bx-tl-uploader-file {
+	position: relative;
+	float: left;
+}
+div.bx-tl-uploader-file-preview {
+	overflow: hidden;
+}
+div.bx-tl-uploader-file-preview,
+div.bx-tl-uploader-file-preview img {
+	width: 100px;
+	width: 6.25rem;
+	height: 100px;
+	height: 6.25rem;
+}
+div.bx-tl-uploader-file-preview img {
+	background-position: center center;
+	background-repeat: no-repeat;
+}
+
+
+/*--- Attach Link Form Styles ---*/
+div.bx-tl-attach-link-form {
+	width: 460px;
+	width: 28.75rem;
+}
+
+
+/*--- Attach Link Form Field Styles ---*/
+div.bx-tl-attach-link-form-field {}
+div.bx-tl-al-item {
+	position: relative;
+	display: inline-block;
+	vertical-align: top;
+
+	width: 25%;
+
+	overflow: hidden;
+}
+div.bx-tl-ali-thumbnail img {
+	width: 100px;
+	height: 100px;
+}
+div.bx-tl-ali-embed iframe {
+    width: 100%;
+	height: auto;
+}
+div.bx-tl-ali-actions .bx-btn {
+	display: inline-block;
+	float: none;
+}

+ 48 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/css/repost.css

@@ -0,0 +1,48 @@
+/*--- Reposted By ---*/
+div.bx-tl-by-list {}
+div.bx-tl-by-list-cnt {
+	max-height: 200px;
+	max-height: 12.5rem;
+	min-width: 220px;
+	min-width: 13.75rem;
+	overflow: auto;
+}
+div.bx-tl-by-list div.bx-base-pofile-unit {
+	float: none;
+	margin-right: 0px;
+	margin-bottom: 0px;
+}
+
+/*--- Repost Element Styles ---*/
+.bx-tl-repost .bx-tl-repost-element-holder .bx-tl-repost-do-repost.bx-tl-repost-disabled,
+.bx-tl-repost .bx-tl-repost-element-holder .bx-tl-repost-do-repost.bx-tl-repost-disabled .sys-icon {
+	color: #ddd;
+}
+.bx-tl-repost .bx-tl-repost-counter-holder {
+	margin-left: 5px;
+	margin-left: 0.3125rem;
+}
+.bx-tl-repost-button .bx-tl-repost-element-holder,
+.bx-tl-repost-button .bx-tl-repost-counter-holder {
+	line-height: 36px;
+	line-height: 2.25rem;
+}
+.bx-tl-repost.bx-tl-repost-button .bx-tl-repost-counter-holder {
+	margin-left: 10px;
+	margin-left: 0.625rem;
+}
+.bx-tl-repost-button-small .bx-tl-repost-element-holder,
+.bx-tl-repost-button-small .bx-tl-repost-counter-holder {
+	line-height: 24px;
+	line-height: 1.6rem;
+}
+.bx-tl-repost-button .bx-tl-repost-counter-holder,
+.bx-tl-repost-button-small .bx-tl-repost-counter-holder {
+	font-size: 1.5rem;
+}
+
+div.bx-tl-repost div.bx-tl-repost-element-holder,
+div.bx-tl-repost div.bx-tl-repost-counter-holder {
+	position: relative;
+	float: left;
+}

+ 246 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/css/view-media-desktop.css

@@ -0,0 +1,246 @@
+@media (min-width: 1024px) {
+	/*--- View Block Style ---*/
+	.bx-tl-grid-sizer {
+		width: 33.3%;
+	}
+
+	.bx-layout-column-wide .bx-tl-grid-sizer,
+	.bx-layout-column-half .bx-tl-grid-sizer {
+		width: 50%;
+	}
+
+	.bx-layout-column-thin .bx-tl-grid-sizer {
+		width: 100%;
+	}
+
+	/*--- Timeline Item Style ---*/
+	div.bx-tl-view-timeline div.bx-tl-item-cnt {
+	    position: relative;
+	
+	    margin: 0px 0px 0px 56px;
+	    margin: 0px 0px 0px 3.5rem;
+	}
+	.bx-layout-column-fullwidth div.bx-tl-view-timeline div.bx-tl-items::before {
+        left: 50%;
+        margin-left: -2px;
+        margin-left: -0.125rem;
+	} 
+	.bx-layout-column-fullwidth div.bx-tl-view-timeline div.bx-tl-item div.bx-tl-item-type {
+        left: 50%;
+        margin-left: -20px;
+        margin-left: -1.25rem;
+	} 
+	.bx-layout-column-fullwidth div.bx-tl-view-timeline div.bx-tl-item div.bx-tl-item-cnt {
+        width: 45%;
+	}
+    .bx-layout-column-fullwidth div.bx-tl-view-timeline div.bx-tl-item:nth-child(2n + 1) div.bx-tl-item-cnt {
+        margin: 0px 56px 0px 0p;
+        margin: 0px 3.5rem 0px 0px;
+    }
+	.bx-layout-column-fullwidth div.bx-tl-view-timeline div.bx-tl-item:nth-child(2n) div.bx-tl-item-cnt {
+		float: right;
+
+        margin: 0px 0px 0px 56px;
+        margin: 0px 0px 0px 3.5rem;
+	}
+
+	/*--- Animation ---*/
+	.mdrnzr_cssanimations div.bx-tl-view-timeline .bx-tl-item-type.is-hidden {
+	    visibility: hidden;
+	}
+	.mdrnzr_cssanimations div.bx-tl-view-timeline .bx-tl-item-type.bounce-in {
+		visibility: visible;
+		-webkit-animation: cd-bounce-1 0.6s;
+		-moz-animation: cd-bounce-1 0.6s;
+		animation: cd-bounce-1 0.6s;
+	}
+	.mdrnzr_cssanimations div.bx-tl-view-timeline .bx-tl-item-cnt.is-hidden {
+	    visibility: hidden;
+	}
+	.mdrnzr_cssanimations div.bx-tl-view-timeline .bx-tl-item-cnt.bounce-in {
+		visibility: visible;
+		-webkit-animation: cd-bounce-2 0.6s;
+		-moz-animation: cd-bounce-2 0.6s;
+		animation: cd-bounce-2 0.6s;
+	}
+	/* inverse bounce effect on even content blocks */
+	.mdrnzr_cssanimations .bx-layout-column-fullwidth div.bx-tl-view-timeline .bx-tl-item:nth-child(even) .bx-tl-item-cnt.bounce-in {
+		-webkit-animation: cd-bounce-2-inverse 0.6s;
+		-moz-animation: cd-bounce-2-inverse 0.6s;
+		animation: cd-bounce-2-inverse 0.6s;
+	}
+}
+
+/*--- Animation ---*/
+@-webkit-keyframes cd-bounce-1 {
+  0% {
+    opacity: 0;
+    -webkit-transform: scale(0.5);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: scale(1.2);
+  }
+
+  100% {
+    -webkit-transform: scale(1);
+  }
+}
+@-moz-keyframes cd-bounce-1 {
+  0% {
+    opacity: 0;
+    -moz-transform: scale(0.5);
+  }
+
+  60% {
+    opacity: 1;
+    -moz-transform: scale(1.2);
+  }
+
+  100% {
+    -moz-transform: scale(1);
+  }
+}
+@keyframes cd-bounce-1 {
+  0% {
+    opacity: 0;
+    -webkit-transform: scale(0.5);
+    -moz-transform: scale(0.5);
+    -ms-transform: scale(0.5);
+    -o-transform: scale(0.5);
+    transform: scale(0.5);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: scale(1.2);
+    -moz-transform: scale(1.2);
+    -ms-transform: scale(1.2);
+    -o-transform: scale(1.2);
+    transform: scale(1.2);
+  }
+
+  100% {
+    -webkit-transform: scale(1);
+    -moz-transform: scale(1);
+    -ms-transform: scale(1);
+    -o-transform: scale(1);
+    transform: scale(1);
+  }
+}
+
+@-webkit-keyframes cd-bounce-2 {
+  0% {
+    opacity: 0;
+    -webkit-transform: translateX(-100px);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: translateX(20px);
+  }
+
+  100% {
+    -webkit-transform: translateX(0);
+  }
+}
+@-moz-keyframes cd-bounce-2 {
+  0% {
+    opacity: 0;
+    -moz-transform: translateX(-100px);
+  }
+
+  60% {
+    opacity: 1;
+    -moz-transform: translateX(20px);
+  }
+
+  100% {
+    -moz-transform: translateX(0);
+  }
+}
+@keyframes cd-bounce-2 {
+  0% {
+    opacity: 0;
+    -webkit-transform: translateX(-100px);
+    -moz-transform: translateX(-100px);
+    -ms-transform: translateX(-100px);
+    -o-transform: translateX(-100px);
+    transform: translateX(-100px);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: translateX(20px);
+    -moz-transform: translateX(20px);
+    -ms-transform: translateX(20px);
+    -o-transform: translateX(20px);
+    transform: translateX(20px);
+  }
+
+  100% {
+    -webkit-transform: translateX(0);
+    -moz-transform: translateX(0);
+    -ms-transform: translateX(0);
+    -o-transform: translateX(0);
+    transform: translateX(0);
+  }
+}
+@-webkit-keyframes cd-bounce-2-inverse {
+  0% {
+    opacity: 0;
+    -webkit-transform: translateX(100px);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: translateX(-20px);
+  }
+
+  100% {
+    -webkit-transform: translateX(0);
+  }
+}
+@-moz-keyframes cd-bounce-2-inverse {
+  0% {
+    opacity: 0;
+    -moz-transform: translateX(100px);
+  }
+
+  60% {
+    opacity: 1;
+    -moz-transform: translateX(-20px);
+  }
+
+  100% {
+    -moz-transform: translateX(0);
+  }
+}
+@keyframes cd-bounce-2-inverse {
+  0% {
+    opacity: 0;
+    -webkit-transform: translateX(100px);
+    -moz-transform: translateX(100px);
+    -ms-transform: translateX(100px);
+    -o-transform: translateX(100px);
+    transform: translateX(100px);
+  }
+
+  60% {
+    opacity: 1;
+    -webkit-transform: translateX(-20px);
+    -moz-transform: translateX(-20px);
+    -ms-transform: translateX(-20px);
+    -o-transform: translateX(-20px);
+    transform: translateX(-20px);
+  }
+
+  100% {
+    -webkit-transform: translateX(0);
+    -moz-transform: translateX(0);
+    -ms-transform: translateX(0);
+    -o-transform: translateX(0);
+    transform: translateX(0);
+  }
+}

+ 19 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/css/view-media-tablet.css

@@ -0,0 +1,19 @@
+@media (min-width:720px) and (max-width:1024px) {
+	/*--- View Block Style ---*/
+	.bx-tl-grid-sizer { 
+		width: 50%;
+	}
+	.bx-layout-column-half .bx-tl-grid-sizer, 
+	.bx-layout-column-thin .bx-tl-grid-sizer {
+		width: 100%;
+	}
+
+    /*--- Timeline Item Style ---*/
+    div.bx-tl-view-timeline div.bx-tl-item-cnt {
+        position: relative;
+    
+        margin: 0px 0px 0px 56px;
+        margin: 0px 0px 0px 3.5rem;
+    }
+    
+}

+ 301 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/css/view.css

@@ -0,0 +1,301 @@
+/*--- General section ---*/
+
+
+/*--- View Block Style ---*/
+div.bx-tl-view {
+	position: relative;
+}
+.bx-tl-grid-sizer {
+	width: 100%;
+}
+.bx-tl-view-sizer {
+	width: 100%;
+}
+.bx-tl-view-sizer div.bx-tl-item-ind {
+	padding: 0px;
+}
+div.bx-tl-items-wrapper {
+	position: relative;
+}
+
+/*--- Back Style ---*/
+
+
+/*--- Load More Style ---*/
+div.bx-tl-view-timeline div.bx-tl-load-more {
+	padding-top: 0px;
+}
+
+div.bx-tl-jump-to {
+	position: relative;
+	float: right;
+	line-height: 36px;
+	line-height: 2.25rem;
+}
+
+
+/*--- Divider Styles ---*/
+div.bx-tl-divider {
+    position: relative;
+}
+
+div.bx-tl-divider-cnt {
+    position: relative;
+    box-sizing: border-box;
+
+    width: 100%;
+
+    border: 2px solid rgba(0, 0, 0, 0.1);
+    border-radius: 20px;
+    -moz-border-radius: 20px;
+    -webkit-border-radius: 20px;
+    background-color: rgba(0, 0, 0, 0.1);
+    
+    text-align: center;
+    text-transform: uppercase;
+    font-weight: bold;
+    color: #ffffff;
+}
+
+
+/*--- Timeline Item Style ---*/
+div.bx-tl-view-timeline div.bx-tl-items:before {
+    content: '';
+    position: absolute;
+    top: 0px;
+    left: 18px;
+    left: 1.125rem;
+    width: 4px;
+    height: 100%;
+
+    background: rgba(0, 0, 0, 0.1);
+}
+div.bx-tl-view-timeline div.bx-tl-items,
+div.bx-tl-view-item div.bx-tl-items {
+	margin-left: 0px;
+	margin-right: 0px;
+}
+div.bx-tl-view-timeline div.bx-tl-item,
+div.bx-tl-view-item div.bx-tl-item {
+    position: relative;
+}
+div.bx-tl-view-timeline div.bx-tl-item-type {
+	position: absolute;
+    top: 0px;
+    left: 0px;
+}
+div.bx-tl-view-timeline div.bx-tl-item-circle {
+	width: 40px;
+    width: 2.5rem;
+    height: 40px;
+    height: 2.5rem;
+
+	background-color: #ffffff;
+	background-clip: padding-box;
+	border-radius: 5rem;
+	box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.1);
+
+    text-align: center;
+    color: #999999;
+	
+	overflow: hidden;
+}
+div.bx-tl-view-timeline div.bx-tl-item-circle .sys-icon {
+	display: block;
+
+	margin-left: auto;
+	margin-right: auto;
+
+	width: 40px;
+    width: 2.5rem;
+    height: 40px;
+    height: 2.5rem;
+
+	text-align: center;
+
+	line-height: 38px;
+	line-height: 2.375rem;
+    font-size: 20px;
+	font-size: 1.25rem;
+}
+div.bx-tl-view-timeline div.bx-tl-item-cnt {
+    position: relative;
+}
+
+
+/*--- Outline Item Style ---*/
+div.bx-tl-view-outline div.bx-tl-item {
+	position: relative;
+}
+div.bx-tl-view-outline div.bx-tl-item-ind {
+	position: relative;
+}
+div.bx-tl-view-outline div.bx-tl-item-cnt {
+	position: relative;
+	overflow: hidden;
+}
+
+/*+++ Item Owner +++*/
+div.bx-tl-view-timeline div.bx-tl-item-owner, 
+div.bx-tl-view-outline div.bx-tl-item-owner,
+div.bx-tl-view-item div.bx-tl-item-owner {
+	position: relative;
+}
+div.bx-tl-view-timeline div.bx-tl-owner-avatar, 
+div.bx-tl-view-outline div.bx-tl-owner-avatar,
+div.bx-tl-view-item div.bx-tl-owner-avatar {
+	position: absolute;
+	top: 0px;
+	left: 0px;
+}
+div.bx-tl-view-timeline div.bx-tl-owner-info, 
+div.bx-tl-view-outline div.bx-tl-owner-info,
+div.bx-tl-view-item div.bx-tl-owner-info {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+}
+div.bx-tl-view-timeline div.bx-tl-owner-name,
+div.bx-tl-view-timeline div.bx-tl-item-info, 
+div.bx-tl-view-outline div.bx-tl-owner-name,
+div.bx-tl-view-outline div.bx-tl-item-info,
+div.bx-tl-view-item div.bx-tl-owner-name,
+div.bx-tl-view-item div.bx-tl-item-info {
+	text-overflow: ellipsis;
+	overflow: hidden;
+}
+div.bx-tl-view-timeline div.bx-tl-owner-name a.bx-tl-owner-name,
+div.bx-tl-view-outline div.bx-tl-owner-name a.bx-tl-owner-name,
+div.bx-tl-view-timeline div.bx-tl-owner-name a.bx-tl-timeline-owner-name,
+div.bx-tl-view-outline div.bx-tl-owner-name a.bx-tl-timeline-owner-name,
+div.bx-tl-view-item div.bx-tl-owner-name a.bx-tl-timeline-owner-name,
+div.bx-tl-view-item div.bx-tl-owner-name a.bx-tl-timeline-owner-name {
+	font-weight: 700;
+}
+
+div.bx-tl-view-timeline div.bx-tl-item-info .bx-tl-date,
+div.bx-tl-view-timeline div.bx-tl-item-info .bx-tl-pinned .sys-icon,
+div.bx-tl-view-outline div.bx-tl-item-info .bx-tl-date,
+div.bx-tl-view-outline div.bx-tl-item-info .bx-tl-pinned .sys-icon,
+div.bx-tl-view-item div.bx-tl-item-info .bx-tl-date,
+div.bx-tl-view-item div.bx-tl-item-info .bx-tl-pinned .sys-icon {
+	color: rgba(40, 60, 80, 0.5);
+}
+div.bx-tl-view-timeline div.bx-tl-item-info .bx-tl-pinned .sys-icon,
+div.bx-tl-view-outline div.bx-tl-item-info .bx-tl-pinned .sys-icon,
+div.bx-tl-view-item div.bx-tl-item-info .bx-tl-pinned .sys-icon {
+	cursor: default;
+}
+
+/*+++ Item Text +++*/
+div.bx-tl-view-outline div.bx-tl-item-text div.bx-tl-title {
+	font-weight: bold;
+}
+div.bx-tl-view-outline span.bx-tl-content-see-more a {
+	font-weight: bold;
+}
+
+/*+++ Item Image +++*/
+div.bx-tl-view-timeline div.bx-tl-item-images,
+div.bx-tl-view-outline div.bx-tl-item-images,
+div.bx-tl-view-item div.bx-tl-item-images {
+	position: relative;
+	white-space: nowrap;
+	overflow: hidden;
+}
+div.bx-tl-view-timeline div.bx-tl-item-images,
+div.bx-tl-view-item div.bx-tl-item-images {
+	margin-left: 0px;
+	margin-right: 0px;
+}
+div.bx-tl-view-timeline div.bx-tl-item-image,
+div.bx-tl-view-outline div.bx-tl-item-image,
+div.bx-tl-view-item div.bx-tl-item-image {
+	display: inline-block;
+}
+div.bx-tl-view-timeline div.bx-tl-item-image,
+div.bx-tl-view-item div.bx-tl-item-image {
+	margin-right: 2px;
+	margin-right: 0.125rem;
+}
+div.bx-tl-view-outline div.bx-tl-item-image {
+	width: 100%;
+    text-align: center;
+    overflow: hidden;
+}
+div.bx-tl-view-timeline div.bx-tl-item-image img,
+div.bx-tl-view-item div.bx-tl-item-image img {
+	height: 12.5rem;
+}
+div.bx-tl-view-outline div.bx-tl-item-image img {
+	max-width: 100%;
+	min-height: 12.5rem;
+	max-height: 18.4375rem;
+	object-fit: cover;
+	object-position: center center;
+}
+
+/*+++ Item Link +++*/
+div.bx-tl-view-outline div.bx-tl-item-link {
+	text-align: center;
+}
+div.bx-tl-view-outline div.bx-tl-il-thumbnail img {
+	width: 100%;
+	max-width: 100px;
+	height: 100%;
+	max-height: 100px;
+}
+div.bx-tl-view-outline div.bx-tl-il-embed iframe,
+div.bx-tl-view-timeline div.bx-tl-il-embed iframe {
+    width: 100%;
+    height: auto;
+}
+
+/*+++ Item Reposted +++*/
+div.bx-tl-view-outline div.bx-tl-reposted div.bx-tl-item-text {
+	padding-left: 5px;
+	padding-left: 0.3rem;
+
+	border-left: 1px solid #999999;
+	border-left: 0.07rem solid #999999;
+}
+div.bx-tl-view-outline div.bx-tl-reposted div.bx-tl-title {
+	font-size: 1.0rem;
+}
+div.bx-tl-view-outline div.bx-tl-reposted div.bx-tl-title a {
+	color: #999999;
+}
+div.bx-tl-view-outline div.bx-tl-reposted div.bx-tl-content {
+	font-size: 0.875rem;
+	color: #999999;
+}
+
+
+/*--- Empty Style ---*/
+div.bx-tl-empty div.bx-msg-box-container {
+	margin-top: 0px;
+	margin-bottom: 0px;
+}
+
+
+/*--- Comments Styles ---*/
+div.bx-tl-item-comments-holder .bx-def-thumb-size {
+	width: 32px;
+	width: 2rem;
+	height: 32px;
+	height: 2rem;
+
+	line-height: 32px;
+	line-height: 2rem;
+}
+div.bx-tl-item-comments-holder .bx-def-thumb-size-left-indent {
+	margin-left: 3.25rem;
+}
+div.bx-tl-item-comments-holder .bx-def-thumb-size-min-height {
+    min-height: 2rem;
+}
+div.bx-tl-item-comments-holder .cmts.cmts-margin {
+	font-size: 12px;
+	font-size: 0.75rem;
+}

+ 3 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/divider.html

@@ -0,0 +1,3 @@
+<div class="__style_prefix__-divider __style_prefix__-divider-__type__ bx-def-padding-bottom" <bx_if:show_hidden>style="display:none"</bx_if:show_hidden>>
+    <div class="__style_prefix__-divider-cnt bx-def-font-small">__content__</div>
+</div>

+ 41 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/item_outline.html

@@ -0,0 +1,41 @@
+<div id="__html_id__" class="__style_prefix__-item __class__">
+	<div class="__style_prefix__-item-ind bx-def-padding-sec">
+	    <div class="__style_prefix__-item-cnt bx-def-box bx-def-padding bx-def-round-corners __class_content__">
+	    	<div class="__style_prefix__-item-owner bx-def-margin-bottom"> 
+		       	<div class="__style_prefix__-owner-avatar bx-def-thumb bx-def-thumb-size">
+                    <a href="__item_owner_url__" class="__style_prefix__-owner-avatar" title="__item_owner_title__">
+						<bx_if:show_owner_icon>
+							<img class="bx-def-thumb bx-def-thumb-size" src="__owner_icon__" />
+						</bx_if:show_owner_icon>
+						<bx_if:show_owner_icon_empty>
+							<i class="sys-icon user"></i>
+						</bx_if:show_owner_icon_empty>
+                    </a>
+				</div>
+				<div class="__style_prefix__-owner-info bx-def-thumb-size-min-height bx-def-thumb-size-left-indent">
+				    <!-- NOTE: Spaces after and between elements in 'owner-name' DIV are needed for better line folding -->
+					<div class="__style_prefix__-owner-name bx-def-font-middle bx-def-font-light bx-def-font-grayed">
+						<a href="__item_owner_url__" class="__style_prefix__-owner-name" title="__item_owner_title__">__item_owner_name__</a> 
+			            <bx_if:show_timeline_owner>
+				        	<i class="sys-icon caret-right"></i> <a href="__owner_url__" class="__style_prefix__-timeline-owner-name">__owner_username__</a> 
+				        </bx_if:show_timeline_owner>
+				        <span class="bx-def-font-small"> __item_owner_action__ </span> <span class="bx-bullet-narrow"> </span><a class="__style_prefix__-date bx-base-text-unit-date bx-def-font-small" href="__item_view_url__"> __item_date__ </a> 
+                        <bx_if:show_pinned>
+                            <span class="__style_prefix__-pinned bx-def-margin-thd-left">
+                                <i class="sys-icon thumb-tack bx-def-margin-thd-left" title="<bx_text_attribute:_bx_timeline_txt_pinned />"></i>
+                            </span>
+                        </bx_if:show_pinned>
+					</div>
+				</div>
+			</div>
+			__content__
+			<bx_if:show_location>
+				<div class="__style_prefix__-item-location bx-def-margin-top bx-def-font-grayed bx-clearfix">__location__</div>
+			</bx_if:show_location>
+			<bx_if:show_menu_item_actions>
+				<div class="__style_prefix__-item-activity bx-def-margin-top bx-clearfix">__menu_item_actions__</div>
+			</bx_if:show_menu_item_actions>
+			<div class="__style_prefix__-item-comments-holder bx-def-font-middle">__comments__</div>
+		</div>
+	</div>
+</div>

+ 45 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/item_timeline.html

@@ -0,0 +1,45 @@
+<div id="__html_id__" class="__style_prefix__-item __class__ bx-def-thumb-size-min-height bx-def-padding-bottom bx-clearfix">
+    <a name="timeline-event-__id__"></a>
+    <div class="__style_prefix__-item-type bx-def-media-phone-hide">
+	    <div class="__style_prefix__-item-circle">
+			<i class="sys-icon __item_icon__"></i>
+        </div>
+    </div>
+    <div class="__style_prefix__-item-cnt bx-def-box bx-def-padding-topbottom bx-def-round-corners __class_content__">
+        <div class="__style_prefix__-item-owner bx-def-margin-leftright"> 
+            <div class="__style_prefix__-owner-avatar bx-def-thumb bx-def-thumb-size">
+                <a href="__item_owner_url__" class="__style_prefix__-owner-avatar" title="__item_owner_title__">
+                    <bx_if:show_owner_icon>
+                        <img class="bx-def-thumb bx-def-thumb-size" src="__owner_icon__" />
+                    </bx_if:show_owner_icon>
+                    <bx_if:show_owner_icon_empty>
+                        <i class="sys-icon user"></i>
+                    </bx_if:show_owner_icon_empty>
+                </a>
+            </div>
+            <div class="__style_prefix__-owner-info bx-def-thumb-size-min-height bx-def-thumb-size-left-indent">
+                <!-- NOTE: Spaces after and between elements in 'owner-name' DIV are needed for better line folding -->
+                <div class="__style_prefix__-owner-name bx-def-font-middle bx-def-font-light bx-def-font-grayed">
+                    <a href="__item_owner_url__" class="__style_prefix__-owner-name" title="__item_owner_title__">__item_owner_name__</a> 
+                    <bx_if:show_timeline_owner>
+                        <i class="sys-icon caret-right"></i> <a href="__owner_url__" class="__style_prefix__-timeline-owner-name">__owner_username__</a> 
+                    </bx_if:show_timeline_owner>
+                    <span class="bx-def-font-small"> __item_owner_action__ </span> <span class="bx-bullet-narrow"> </span><a class="__style_prefix__-date bx-base-text-unit-date bx-def-font-small" href="__item_view_url__"> __item_date__ </a> 
+                    <bx_if:show_pinned>
+                        <span class="__style_prefix__-pinned bx-def-margin-thd-left">
+                            <i class="sys-icon thumb-tack bx-def-margin-thd-left" title="<bx_text_attribute:_bx_timeline_txt_pinned />"></i>
+                        </span>
+                    </bx_if:show_pinned>
+                </div>
+            </div>
+        </div>
+		<div class="__style_prefix__-item-content bx-def-margin-leftright bx-def-margin-top bx-clearfix">__content__</div>
+		<bx_if:show_location>
+		    <div class="__style_prefix__-item-location bx-def-margin-leftright bx-def-margin-top bx-def-font-grayed bx-clearfix">__location__</div>
+		</bx_if:show_location>
+		<bx_if:show_menu_item_actions>
+		    <div class="__style_prefix__-item-activity bx-def-margin-leftright bx-def-margin-top bx-clearfix">__menu_item_actions__</div>
+		</bx_if:show_menu_item_actions>
+		<div class="__style_prefix__-item-comments-holder bx-def-margin-leftright bx-def-font-middle">__comments__</div>
+    </div>
+</div>

+ 9 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/repost_by_list.html

@@ -0,0 +1,9 @@
+<div class="__style_prefix__-by-list">
+	<div class="__style_prefix__-by-list-cnt">
+		<div class="__style_prefix__-by-items">
+			<bx_repeat:list>
+				<div class="__style_prefix__-by-item bx-def-padding-sec bx-clearfix">__user_unit__</div>
+			</bx_repeat:list>
+		</div>
+	</div>
+</div>

+ 1 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/repost_counter.html

@@ -0,0 +1 @@
+<bx_include_auto:bx_a.html />

+ 7 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/repost_element_block.html

@@ -0,0 +1,7 @@
+<div id="__html_id__" class="__style_prefix__-repost __class__ bx-def-margin-right-auto bx-def-margin-thd-topbottom bx-clearfix" bx_repost_data_count="__count__">
+	<div class="__style_prefix__-repost-element-holder">__do_repost__</div>
+	<bx_if:show_counter>
+		<div class="__style_prefix__-repost-counter-holder bx-btn-border"<bx_if:show_hidden> style="display:none"</bx_if:show_hidden>>__counter__</div>
+	</bx_if:show_counter>
+</div>
+__script__

+ 47 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/type_post.html

@@ -0,0 +1,47 @@
+<bx_if:show_images>
+    <div class="__style_prefix__-item-images bx-def-margin-topbottom bx-def-margin-leftright-neg">
+        <bx_repeat:images>
+            <div class="__style_prefix__-item-image">__image__</div>
+        </bx_repeat:images>
+    </div>
+</bx_if:show_images>
+<bx_if:show_videos>
+    <div class="__style_prefix__-item-videos bx-def-margin-top bx-def-margin-leftright-neg">
+        <bx_repeat:videos>
+            <div class="__style_prefix__-item-video bx-def-margin-top-auto">__video__</div>
+        </bx_repeat:videos>
+    </div>
+</bx_if:show_videos>
+<div class="__style_prefix__-item-text">
+	<bx_if:show_title>
+		<div class="__style_prefix__-title bx-def-margin-sec-bottom bx-def-font-h3">__title__</div>
+	</bx_if:show_title>
+	<bx_if:show_content>
+		<div class="__style_prefix__-content">
+		__item_content__<bx_if:show_more><span class="__style_prefix__-content-see-more">... <a class="bx-def-font-small" href="javascript:void(0)" onclick="__js_object__.showMoreContent(this);"><bx_text:_see_more /></a></span><span style="display:none;"> __item_content_more__</span></bx_if:show_more>
+		</div>
+	</bx_if:show_content>
+	<bx_if:show_content_raw>__item_content_raw__</bx_if:show_content_raw>
+</div>
+<bx_if:show_links>
+	<div class="__style_prefix__-item-links bx-def-margin-top">
+		<bx_repeat:links>
+	   		<div class="__style_prefix__-item-link bx-def-margin-top-auto bx-def-padding-sec bx-def-border">
+				<bx_if:show_embed_outer>
+				    <div class="__style_prefix__-il-embed">__embed__</div>
+				</bx_if:show_embed_outer>
+                <bx_if:show_embed_inner>
+		   			<bx_if:show_thumbnail>
+		   				<div class="__style_prefix__-il-thumbnail">
+		   					<img src="__thumbnail__" />
+		   				</div>
+		   			</bx_if:show_thumbnail>
+		   			<div class="__style_prefix__-il-title">__link__</div>
+		   			<bx_if:show_text>
+		   				<div class="__style_prefix__-il-text bx-def-font-small bx-def-font-grayed">__text__</div>
+		   			</bx_if:show_text>
+                </bx_if:show_embed_inner>
+	   		</div>
+	   	</bx_repeat:links>
+	</div>
+</bx_if:show_links>

+ 8 - 0
modules/boonex/timeline/updates/9.0.2_9.0.3/source/template/type_repost.html

@@ -0,0 +1,8 @@
+<bx_if:show_title>
+	<div class="__style_prefix__-title bx-def-margin-sec-bottom bx-def-font-large">__title__</div>
+</bx_if:show_title>
+<bx_if:show_content>
+	<div class="__style_prefix__-content __style_prefix__-reposted bx-def-margin-sec-bottom">
+	__content__
+	</div>
+</bx_if:show_content>