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

Ticket #5005 - Timeline: Allow to attach poll to an update.

AntonLV 1 год назад
Родитель
Сommit
1fe550b814

+ 5 - 5
modules/boonex/posts/classes/BxPostsConfig.php

@@ -227,15 +227,15 @@ class BxPostsConfig extends BxBaseModTextConfig
             'style' => 'bx-posts',
         );
         
-        $this->_aJsClasses = array_merge($this->_aJsClasses, array(
+        $this->_aJsClasses = array_merge($this->_aJsClasses, [
             'manage_tools' => 'BxPostsManageTools',
             'categories' => 'BxDolCategories'
-        ));
+        ]);
 
-        $this->_aJsObjects = array_merge($this->_aJsObjects, array(
+        $this->_aJsObjects = array_merge($this->_aJsObjects, [
             'manage_tools' => 'oBxPostsManageTools',
-             'categories' => 'oBxDolCategories'
-        ));
+            'categories' => 'oBxDolCategories'
+        ]);
 
         $this->_aGridObjects = array(
             'common' => $this->CNF['OBJECT_GRID_COMMON'],

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

@@ -121,6 +121,7 @@
     <string name="_bx_timeline_form_post_input_sys_video"><![CDATA[Видео]]></string>
     <string name="_bx_timeline_form_post_input_video"><![CDATA[]]></string>
     <string name="_bx_timeline_form_post_input_video_alt"><![CDATA[Добавить видео]]></string>
+    <string name="_bx_timeline_form_post_input_sys_polls"><![CDATA[Голосования]]></string>
     <string name="_bx_timeline_form_post_input_sys_attachments"><![CDATA[Прикрепления]]></string>
     <string name="_bx_timeline_form_post_input_sys_do_submit"><![CDATA[Создать]]></string>
     <string name="_bx_timeline_form_post_input_do_submit"><![CDATA[Создать]]></string>
@@ -137,6 +138,19 @@
     <string name="_bx_timeline_form_attach_link_input_do_submit"><![CDATA[Добавить]]></string>
     <string name="_bx_timeline_form_attach_link_input_do_cancel"><![CDATA[Закрыть]]></string>
 
+    <string name="_bx_timeline_form_poll"><![CDATA[Голосования]]></string>
+    <string name="_bx_timeline_form_poll_display_add"><![CDATA[Добавить голосование]]></string>
+    <string name="_bx_timeline_form_poll_input_sys_text"><![CDATA[Вопрос]]></string>
+    <string name="_bx_timeline_form_poll_input_text"><![CDATA[Вопрос]]></string>
+    <string name="_bx_timeline_form_poll_input_text_err"><![CDATA[Вопрос обязателен. Пожалуйста, заполните это поле]]></string>
+    <string name="_bx_timeline_form_poll_input_sys_answers"><![CDATA[Ответы]]></string>
+    <string name="_bx_timeline_form_poll_input_answers"><![CDATA[Ответы]]></string>
+    <string name="_bx_timeline_form_poll_input_answers_err"><![CDATA[Голосование должно иметь как минимум 2 не пустых ответа.]]></string>
+    <string name="_bx_timeline_form_poll_input_answers_add"><![CDATA[Добавить ещё]]></string>    
+    <string name="_bx_timeline_form_poll_input_sys_do_submit"><![CDATA[Добавить]]></string>
+    <string name="_bx_timeline_form_poll_input_do_submit"><![CDATA[Добавить]]></string>
+    <string name="_bx_timeline_form_poll_input_do_cancel"><![CDATA[Закрыть]]></string>
+
     <string name="_bx_timeline_form_reposto"><![CDATA[Сделать репост]]></string>
     <string name="_bx_timeline_form_repost_display_with"><![CDATA[Cделать репост с текстом]]></string>
     <string name="_bx_timeline_form_repost_display_to"><![CDATA[Cделать репост в]]></string>
@@ -207,6 +221,8 @@
     <string name="_bx_timeline_page_block_title_item"><![CDATA[Элемент]]></string>
     <string name="_bx_timeline_page_block_title_item_content"><![CDATA[Содержимое]]></string>
     <string name="_bx_timeline_page_block_title_item_info"><![CDATA[Информация]]></string>
+    <string name="_bx_timeline_page_block_title_item_polls"><![CDATA[Голосования]]></string>
+    <string name="_bx_timeline_page_block_title_entry_reports"><![CDATA[Жалобы]]></string>
     <string name="_bx_timeline_page_block_title_item_comments"><![CDATA[Комментарии]]></string>
     <string name="_bx_timeline_page_block_title_system_post_account"><![CDATA[Создать публикацию]]></string>
     <string name="_bx_timeline_page_block_title_post_account"><![CDATA[Создать публикацию]]></string>
@@ -351,13 +367,14 @@
     <string name="_bx_timeline_menu_item_title_add_file"><![CDATA[Добавить Файл]]></string>
     <string name="_bx_timeline_menu_item_title_system_add_file_simple"><![CDATA[Добавить Файл (Обычная загрузка)]]></string>
     <string name="_bx_timeline_menu_item_title_system_add_file_html5"><![CDATA[Добавить Файл (Множественная загрузка)]]></string>
+    <string name="_bx_timeline_menu_item_title_system_add_poll"><![CDATA[Добавить голосование]]></string>
+    <string name="_bx_timeline_menu_item_title_add_poll"><![CDATA[Добавить голосование]]></string>
     <string name="_bx_timeline_menu_item_title_system_timeline"><![CDATA[Лента]]></string>
     <string name="_bx_timeline_menu_item_title_timeline"><![CDATA[Лента]]></string>
     <string name="_bx_timeline_menu_item_title_system_create_entry"><![CDATA[Статус]]></string>
     <string name="_bx_timeline_menu_item_title_create_entry"><![CDATA[Статус]]></string>
     <string name="_bx_timeline_menu_item_title_system_view_timeline_view"><![CDATA[Лента]]></string>
     <string name="_bx_timeline_menu_item_title_view_timeline_view"><![CDATA[Лента]]></string>
-
     <string name="_bx_timeline_menu_item_title_system_manage_my_timeline"><![CDATA[Лента]]></string>
     <string name="_bx_timeline_menu_item_title_manage_my_timeline"><![CDATA[Лента]]></string>
 
@@ -453,6 +470,12 @@
     <string name="_bx_timeline_txt_msg_success_repost"><![CDATA[Репост данного элемента был сделан успешно.]]></string>
     <string name="_bx_timeline_txt_object_reposted"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> - {entry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b>]]> (репост)</string>
 
+    <string name="_bx_timeline_txt_poll_view_answers"><![CDATA[опрос]]></string>
+    <string name="_bx_timeline_txt_poll_view_results"><![CDATA[результаты]]></string>
+    <string name="_bx_timeline_txt_poll_answer_vote_do_by"><![CDATA[Проголосовали за]]></string>
+    <string name="_bx_timeline_txt_poll_answer_vote_counter"><![CDATA[{0} голосов]]></string>
+    <string name="_bx_timeline_txt_poll_answer_vote_percent"><![CDATA[({0}%)]]></string>
+
     <!-- EMAIL TEMPLATES -->
     <string name="_bx_timeline_et_txt_name_send"><![CDATA[Послать другу.]]></string>
     <string name="_bx_timeline_et_txt_subject_send"><![CDATA[Это может быть интересно для вас.]]></string>

+ 25 - 8
modules/boonex/timeline/classes/BxTimelineConfig.php

@@ -67,6 +67,7 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
     protected $_iForYouThdRecomFrds;
     protected $_iForYouThdRecomSbns;
 
+    protected $_sEditorId;
     protected $_bEditorToolbar;
     protected $_bEditorAutoAttach;
     protected $_bEnableMediaPriority;
@@ -101,7 +102,7 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
     {
         parent::__construct($aModule);
 
-        $this->CNF = array (
+        $this->CNF = array_merge($this->CNF, [
             'ICON' => 'far clock col-green1',
 
             // database tables
@@ -129,6 +130,7 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
             'FIELD_PHOTO' => 'photo',
             'FIELD_VIDEO' => 'video',
             'FIELD_FILE' => 'file',
+            'FIELD_POLL' => 'polls',
             'FIELD_STATUS' => 'status',
             'FIELD_STATUS_ADMIN' => 'status_admin',
             'FIELD_STICKED' => 'sticked',
@@ -183,6 +185,8 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
             'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => $this->_sName . '_post_edit',
             'OBJECT_FORM_ATTACH_LINK' => $this->_sName . '_attach_link',
             'OBJECT_FORM_ATTACH_LINK_DISPLAY_ADD' => $this->_sName . '_attach_link_add',
+            'OBJECT_FORM_POLL' => $this->_sName . '_poll',
+            'OBJECT_FORM_POLL_DISPLAY_ADD' => $this->_sName . '_poll_add',
             'OBJECT_GRID_ADMINISTRATION' => $this->_sName . '_administration',
             'OBJECT_GRID_COMMON' => $this->_sName . '_common',
             'OBJECT_GRID_MUTE' => $this->_sName . '_mute',
@@ -213,6 +217,13 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
                 'txt_sample_with_video' => '_bx_timeline_txt_sample_with_video',
                 'txt_sample_with_file' => '_bx_timeline_txt_sample_with_file',
                 'txt_sample_with_media' => '_bx_timeline_txt_sample_with_media',
+                'txt_poll_form_answers_add' => '_bx_posts_form_poll_input_answers_add',
+                'txt_poll_menu_view_answers' => '_bx_posts_txt_poll_view_answers',
+                'txt_poll_menu_view_results' => '_bx_posts_txt_poll_view_results',
+                'txt_poll_menu_view_' => '_bx_posts_txt_poll_view_',
+                'txt_poll_answer_vote_do_by' => '_bx_posts_txt_poll_answer_vote_do_by',
+                'txt_poll_answer_vote_counter' => '_bx_posts_txt_poll_answer_vote_counter',
+                'txt_poll_answer_vote_percent' => '_bx_posts_txt_poll_answer_vote_percent',
                 'grid_action_err_delete' => '_bx_timeline_grid_action_err_delete', 
                 'grid_txt_account_manager' => '_bx_timeline_grid_txt_account_manager',
                 'filter_item_active' => '_bx_timeline_grid_filter_item_title_adm_active',
@@ -238,7 +249,7 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
                 'option_fyfs_recom_friends' => '_bx_timeline_option_for_you_sources_recom_friends',
                 'option_fyfs_recom_subscriptions' => '_bx_timeline_option_for_you_sources_recom_subscriptions',
             ),
-        );
+        ]);
 
         $this->_aTypeToFormDisplay = array(
             BX_BASE_MOD_NTFS_TYPE_OWNER => 'form_display_post_add_profile',
@@ -328,21 +339,21 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
             'add-file-html5' => $this->CNF['OBJECT_UPLOADER_FILE_HTML5'],
         );
 
-        $this->_aJsClasses = array(
+        $this->_aJsClasses = array_merge($this->_aJsClasses, [
             'main' => 'BxTimelineMain',
             'view' => 'BxTimelineView',
             'view_filters' => 'BxTimelineViewFilters',
             'post' => 'BxTimelinePost',
             'repost' => 'BxTimelineRepost',
             'manage_tools' => 'BxTimelineManageTools'
-        );
-        $this->_aJsObjects = array(
+        ]);
+        $this->_aJsObjects = array_merge($this->_aJsObjects, [
             'view' => 'oTimelineView',
             'view_filters' => 'oTimelineViewFilters',
             'post' => 'oTimelinePost',
             'repost' => 'oTimelineRepost',
             'manage_tools' => 'oBxTimelineManageTools'
-        );
+        ]);
 
         $this->_aGridObjects = array(
             'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
@@ -352,7 +363,7 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
         $sHp = str_replace('_', '-', $this->_sName);
         $sHpT = BX_TIMELINE_VIEW_TIMELINE;
         $sHpO = BX_TIMELINE_VIEW_OUTLINE;
-        $this->_aHtmlIds = array(
+        $this->_aHtmlIds = array_merge($this->_aHtmlIds, [
             'view' => array(
                 'edit_form' => $sHp . '-edit-',
                 'attach_link_form_field' => $sHp . '-attach-link-form-field-',
@@ -380,7 +391,7 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
                 'with_popup' => $sHp . '-repost-with',
                 'to_popup' => $sHp . '-repost-to',
             )
-        );
+        ]);
 
         $this->_aRepostDefaults = [
             'do' => 'repost',
@@ -527,6 +538,7 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
         $this->_iForYouThdRecomFrds = (int)getParam($sOptionPrefix . 'for_you_threshold_recom_friends');
         $this->_iForYouThdRecomSbns = (int)getParam($sOptionPrefix . 'for_you_threshold_recom_subscriptions');
 
+        $this->_sEditorId = $this->getHtmlIds('post', 'textarea') . time();
         $this->_bEditorToolbar = getParam($sOptionPrefix . 'enable_editor_toolbar') == 'on';
         $this->_bEditorAutoAttach = getParam($sOptionPrefix . 'editor_auto_attach_insertion') == 'on';
         $this->_bEnableMediaPriority = getParam($sOptionPrefix . 'enable_media_priority') == 'on';
@@ -708,6 +720,11 @@ class BxTimelineConfig extends BxBaseModNotificationsConfig
     	return $this->_bEditorAutoAttach;
     }
 
+    public function getEditorId()
+    {
+        return $this->_sEditorId;
+    }
+
     public function isMediaPriority()
     {
         return $this->_bEnableMediaPriority;

+ 24 - 0
modules/boonex/timeline/classes/BxTimelineFormPoll.php

@@ -0,0 +1,24 @@
+<?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 BxTimelineFormPoll extends BxBaseModGeneralFormPoll
+{
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_timeline';
+
+        parent::__construct($aInfo, $oTemplate);
+    }
+}
+
+class BxTimelineFormPollCheckerHelper extends BxBaseModGeneralFormPollCheckerHelper {}
+
+/** @} */

+ 8 - 1
modules/boonex/timeline/classes/BxTimelineFormPost.php

@@ -55,6 +55,13 @@ class BxTimelineFormPost extends BxBaseModGeneralFormEntry
         $this->_aUploadersInfo = [];
     }
 
+    public function addCssJsPolls($bDynamicMode = false)
+    {
+        $sInclude = parent::addCssJsPolls($bDynamicMode);
+        $sInclude .= $this->_oModule->_oTemplate->addJs(['polls.js'], $bDynamicMode);
+        return $bDynamicMode ? $sInclude : '';
+    }
+
     public function getUploadersInfo($sField = '')
     {
         if(empty($sField))
@@ -245,7 +252,7 @@ class BxTimelineFormPost extends BxBaseModGeneralFormEntry
             if(empty($this->aInputs['text']['attrs']) || !is_array($this->aInputs['text']['attrs']))
                 $this->aInputs['text']['attrs'] = array();
 
-            $this->aInputs['text']['attrs']['id'] = $this->_oModule->_oConfig->getHtmlIds('post', 'textarea') . time();
+            $this->aInputs['text']['attrs']['id'] = $this->_oModule->_oConfig->getEditorId();
         }
 
         $this->_initPrivacyFields();

+ 3 - 2
modules/boonex/timeline/classes/BxTimelineMenuPostAttachments.php

@@ -27,9 +27,10 @@ class BxTimelineMenuPostAttachments extends BxTemplMenu
 
         $this->_oModule = BxDolModule::getInstance('bx_timeline');
 
-        $this->addMarkers(array(
+        $this->addMarkers([
             'js_object' => $this->_oModule->_oConfig->getJsObject('post'),
-        ));
+            'js_object_poll' => $this->_oModule->_oConfig->getJsObject('poll'),
+        ]);
     }
 
     public function setEventById($iEventId, $aBrowseParams = array())

+ 34 - 2
modules/boonex/timeline/classes/BxTimelineModule.php

@@ -3904,8 +3904,12 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
             //--- Process Files ---//
             $aFileIds = $oForm->getCleanValue($CNF['FIELD_FILE']);
             $bFileIds = !empty($aFileIds) && is_array($aFileIds);
+            
+            //--- Process Polls ---//
+            $aPollIds = $oForm->getCleanValue($CNF['FIELD_POLL']);
+            $bPollIds = !empty($aPollIds) && is_array($aPollIds);            
 
-            if(!$bText && !$bLinkIds && !$bPhotoIds && !$bVideoIds && !$bFileIds) {
+            if(!$bText && !$bLinkIds && !$bPhotoIds && !$bVideoIds && !$bFileIds && !$bPollIds) {
                 $oForm->aInputs['text']['error'] =  _t('_bx_timeline_txt_err_empty_post');
                 $oForm->setValid(false);
 
@@ -3986,6 +3990,9 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
                 $this->_saveMedia($CNF['FIELD_VIDEO'], $iId, $aVideoIds, $iUserId, true);
                 $this->_saveMedia($CNF['FIELD_FILE'], $iId, $aFileIds, $iUserId, true);
 
+                //--- Process Poll ---//
+                $oForm->processPolls($CNF['FIELD_POLL'], $iId);
+
                 //--- Process Privacy
                 $aEvent = $this->_oDb->getEvents(['browse' => 'id', 'value' => $iId]);
                 if(($sKey = 'FIELD_OBJECT_PRIVACY_VIEW') && !empty($aEvent[$CNF[$sKey]]) && ($oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_VIEW'])) !== false)
@@ -4134,8 +4141,12 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
 
             $aFileIds = $oForm->getCleanValue($CNF['FIELD_FILE']);
             $bFileIds = !empty($aFileIds) && is_array($aFileIds);
+            
+            //--- Process Poll ---//
+            $aPollIds = $oForm->getCleanValue($CNF['FIELD_POLL']);
+            $bPollIds = !empty($aPollIds) && is_array($aPollIds);
 
-            if(!$bText && !$bLinkIds && !$bPhotoIds && !$bVideoIds && !$bFileIds) {
+            if(!$bText && !$bLinkIds && !$bPhotoIds && !$bVideoIds && !$bFileIds && !$bPollIds) {
                 $oForm->aInputs['text']['error'] =  _t('_bx_timeline_txt_err_empty_post');
                 $oForm->setValid(false);
 
@@ -4163,6 +4174,9 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
             $this->_saveMedia($CNF['FIELD_VIDEO'], $iId, $aVideoIds, $iUserId);
             $this->_saveMedia($CNF['FIELD_FILE'], $iId, $aFileIds, $iUserId);
 
+            //--- Process Poll ---//
+            $oForm->processPolls($CNF['FIELD_POLL'], $iId);
+
             //--- Process Privacy
             $aEvent = $this->_oDb->getEvents(['browse' => 'id', 'value' => $iId]);
             if(($sKey = 'FIELD_OBJECT_PRIVACY_VIEW') && !empty($aEvent[$CNF[$sKey]]) && ($oPrivacy = BxDolPrivacy::getObjectInstance($CNF['OBJECT_PRIVACY_VIEW'])) !== false)
@@ -5319,6 +5333,8 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
             $this->_deleteMedia($CNF['FIELD_VIDEO'], $aEvent[$CNF['FIELD_ID']]);
             $this->_deleteMedia($CNF['FIELD_FILE'], $aEvent[$CNF['FIELD_ID']]);
             $this->_deleteLinks($aEvent[$CNF['FIELD_ID']]);
+
+            $this->_oDb->deletePolls(['content_id' => $aEvent[$CNF['FIELD_ID']]]);
     	}
 
     	//--- Update parent event when repost event was deleted.
@@ -5652,6 +5668,22 @@ class BxTimelineModule extends BxBaseModNotificationsModule implements iBxDolCon
         return $aResult;
     }
 
+    public function getEventPolls($iEventId)
+    {
+        $aPolls = $this->_oDb->getPolls([
+            'type' => 'content_id', 
+            'content_id' => $iEventId, 
+        ]);
+        if(empty($aPolls) || !is_array($aPolls))
+            return;
+
+        $aResult = [];
+        foreach($aPolls as $aPoll)
+            $aResult[$aPoll['id']] = $aPoll;
+
+        return $aResult;
+    }
+
     public function hasMedia($iEventId, $iProfileId = 0)
     {
         $CNF = &$this->_oConfig->CNF;

+ 58 - 14
modules/boonex/timeline/classes/BxTimelineTemplate.php

@@ -52,14 +52,15 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
         $aCss = array();
         switch($sType) {
             case 'view':
-                $aCss = array(
+                $aCss = [
                     BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'flickity/|flickity.css',
                     'cmts.css',
                     'view.css',
                     'view-media-tablet.css',
                     'view-media-desktop.css',
                     'repost.css',
-                );
+                    'polls.css'
+                ];
 
                 if($this->_oConfig->isJumpTo()) {
                     list($aCssCalendar, $aJsCalendar) = BxBaseFormView::getCssJsCalendar();
@@ -68,7 +69,10 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
                 break;
 
             case 'post':
-                $aCss[] = 'post.css';
+                $aCss = [
+                    'post.css',
+                    'polls.css'
+                ];
                 break;
         }
 
@@ -93,6 +97,8 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
                     'BxDolCmts.js',
                     'view.js',
                     'repost.js',
+                    'modules/base/general/js/|polls.js',
+                    'polls.js'
                 ));
 
                 if ($this->_oConfig->isJumpTo()) {
@@ -111,6 +117,8 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
                 $aJs = array_merge($aJs, array(
                     'jquery.form.min.js',
                     'post.js',
+                    'modules/base/general/js/|polls.js',
+                    'polls.js'
                 ));
                 break;
         }
@@ -147,7 +155,7 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
         return parent::getJsCode('view_filters', $aParams, $bWrap, $bDynamic);
     }
     
-    public function getJsCodePost($iOwnerId, $aParams = array(), $bWrap = true, $bDynamic = false)
+    public function getJsCodePost($iOwnerId, $aParams = [], $bWrap = true, $bDynamic = false)
     {
         $aGeneralParams = [];
         $aRequestParams = $aParams;
@@ -156,24 +164,34 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
             $aRequestParams = $aParams['rparams'];
         }
 
-        return $this->getJsCode('post', array_merge(array(
+        return $this->getJsCode('post', array_merge([
             'bAutoAttach' => $this->_oConfig->isEditorAutoAttach(),
             'bMediaPriority' => $this->_oConfig->isMediaPriority(),
             'iLimitAttachLinks' => $this->_oConfig->getLimitAttachLinks(),
             'sLimitAttachLinksErr' => bx_js_string(_t('_bx_timeline_txt_err_attach_links')),
-            'oAttachedLinks' => $this->_oDb->getLinksBy(array(
+            'oAttachedLinks' => $this->_oDb->getLinksBy([
                 'type' => 'unused', 
                 'profile_id' => $this->getModule()->getUserId(), 
                 'short' => true
-            )),
+            ]),
             'sVideosAutoplay' => $this->_oConfig->getVideosAutoplay(),
-            'oRequestParams' => array_merge(array(
+            'oRequestParams' => array_merge([
                 'type' => isset($aRequestParams['type']) ? $aRequestParams['type'] : BX_TIMELINE_TYPE_DEFAULT, 
                 'owner_id' => $iOwnerId
-            ), $aRequestParams)
-        ), $aGeneralParams), $bWrap, $bDynamic);
+            ], $aRequestParams)
+        ], $aGeneralParams), $bWrap, $bDynamic);
     }
 
+    public function getJsCode($sType, $aParams = [], $bWrap = true, $bDynamic = false)
+    {
+        $aParams = array_merge([
+            'sEditorId' => $this->_oConfig->getEditorId(),
+        ], $aParams);
+        
+        return parent::getJsCode($sType, $aParams, $bWrap, $bDynamic);
+    }
+    
+    
     public function getPostBlock($iOwnerId, $aParams = array())
     {
         $CNF = &$this->_oConfig->CNF;
@@ -190,7 +208,7 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
                 ];
         }
 
-        if(bx_is_api()) {
+        if($this->_bIsApi) {
             $aType2Uri = [
                 '' => 'get_block_post_account',
                 'account' => 'get_block_post_account',
@@ -548,7 +566,7 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
         ), array(
             'wrap' => true,
             'mask_markers' => array('object' => $sJsObject)
-        )) . $this->getJsCode('repost');
+        )) . $this->getJsCode('repost') . $this->getJsCode('poll');
 
         /**
          * @hooks
@@ -2653,6 +2671,26 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
                 ];
             }
 
+        //--- Process Polls ---//
+        $aTmplVarsAttachmentsPolls = [];
+        if(!$bViewItem && !empty($aContent['polls_attach']) && is_array($aContent['polls_attach'])) {
+            $iProfile = bx_get_logged_profile_id();
+
+            $aPollsAttach = [];
+            foreach($aContent['polls_attach'] as $aPoll)
+                $aPollsAttach[] = [
+                    'style_prefix' => $sStylePrefix,
+                    'poll' => $this->getPollItem($aPoll, $iProfile)
+                ];
+
+            if(!empty($aPollsAttach)) {
+                $aTmplVarsAttachmentsPolls = [
+                    'style_prefix' => $sStylePrefix,
+                    'bx_repeat:polls' => $aPollsAttach
+                ];
+            }
+        }
+
         /*
          * View Item page and Snippet in Search Results should use Gallery layout.
          */
@@ -2661,7 +2699,7 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
             $sAttachmentsLayout = BX_TIMELINE_ML_GALLERY;
 
         $iAttachmentsTotal = 0;
-        $aTmplVarsImages = $aTmplVarsVideos = $aTmplVarsFiles = $aTmplVarsAttachments = $aTmplVarsAttachmentsFiles = array();
+        $aTmplVarsImages = $aTmplVarsVideos = $aTmplVarsFiles = $aTmplVarsAttachments = $aTmplVarsAttachmentsFiles = [];
 
         //--- Process Photos ---//
         $bImages = !empty($aContent['images']) && is_array($aContent['images']);
@@ -2822,7 +2860,11 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
             'bx_if:show_attachments_files' => [
                 'condition' => !empty($aTmplVarsAttachmentsFiles),
                 'content' => $aTmplVarsAttachmentsFiles
-            ]
+            ],
+            'bx_if:show_attachments_polls' => [
+                'condition' => !empty($aTmplVarsAttachmentsPolls),
+                'content' => $aTmplVarsAttachmentsPolls
+            ],
         ];
     }
 
@@ -3342,6 +3384,8 @@ class BxTimelineTemplate extends BxBaseModNotificationsTemplate
                 $aResult['content']['images_attach'] = $oModule->getEventImages($aEvent['id']);
                 $aResult['content']['videos_attach'] = $oModule->getEventVideos($aEvent['id']);
                 $aResult['content']['files_attach'] = $oModule->getEventFiles($aEvent['id']);
+                $aResult['content']['polls_attach'] = $oModule->getEventPolls($aEvent['id']);
+
                 if($this->_bIsApi) {
                     $aResult['content']['videos_attach'] = array_values($aResult['content']['videos_attach']);
                     $aResult['content']['files_attach'] = array_values($aResult['content']['files_attach']);

+ 22 - 0
modules/boonex/timeline/classes/BxTimelineVotePollAnswers.php

@@ -0,0 +1,22 @@
+<?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 BxTimelineVotePollAnswers extends BxBaseModGeneralVotePollAnswers
+{
+    public function __construct($sSystem, $iId, $iInit = 1)
+    {
+    	$this->_sModule = 'bx_timeline';
+
+        parent::__construct($sSystem, $iId, $iInit);
+    }
+}
+
+/** @} */

+ 24 - 4
modules/boonex/timeline/install/langs/en.xml

@@ -115,12 +115,13 @@
     <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_files"><![CDATA[File]]></string>
     <string name="_bx_timeline_form_post_input_files"><![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_polls"><![CDATA[Polls]]></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>
@@ -137,6 +138,19 @@
     <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_form_poll"><![CDATA[Polls]]></string>
+    <string name="_bx_timeline_form_poll_display_add"><![CDATA[Add Poll]]></string>
+    <string name="_bx_timeline_form_poll_input_sys_text"><![CDATA[Question]]></string>
+    <string name="_bx_timeline_form_poll_input_text"><![CDATA[Question]]></string>
+    <string name="_bx_timeline_form_poll_input_text_err"><![CDATA[Question is essential. Please, fill in this field]]></string>
+    <string name="_bx_timeline_form_poll_input_sys_answers"><![CDATA[Answers]]></string>
+    <string name="_bx_timeline_form_poll_input_answers"><![CDATA[Answers]]></string>
+    <string name="_bx_timeline_form_poll_input_answers_err"><![CDATA[Poll should have at least 2 non-empty answers.]]></string>
+    <string name="_bx_timeline_form_poll_input_answers_add"><![CDATA[Add More]]></string>
+    <string name="_bx_timeline_form_poll_input_sys_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_timeline_form_poll_input_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_timeline_form_poll_input_do_cancel"><![CDATA[Close]]></string>
+
     <string name="_bx_timeline_form_repost"><![CDATA[Repost]]></string>
     <string name="_bx_timeline_form_repost_display_with"><![CDATA[Repost With Text]]></string>
     <string name="_bx_timeline_form_repost_display_to"><![CDATA[Repost To]]></string>
@@ -209,6 +223,7 @@
     <string name="_bx_timeline_page_block_title_item"><![CDATA[Item]]></string>
     <string name="_bx_timeline_page_block_title_item_content"><![CDATA[Content]]></string>
     <string name="_bx_timeline_page_block_title_item_info"><![CDATA[Info]]></string>
+    <string name="_bx_timeline_page_block_title_item_polls"><![CDATA[Polls]]></string>
     <string name="_bx_timeline_page_block_title_entry_reports"><![CDATA[Reports]]></string>
     <string name="_bx_timeline_page_block_title_item_comments"><![CDATA[Comments]]></string>
     <string name="_bx_timeline_page_block_title_system_post_account"><![CDATA[Post to Feed]]></string>
@@ -352,21 +367,20 @@
     <string name="_bx_timeline_menu_item_title_add_photo"><![CDATA[Add Photo]]></string>
     <string name="_bx_timeline_menu_item_title_system_add_video_simple"><![CDATA[Add Video (Simple)]]></string>
     <string name="_bx_timeline_menu_item_title_system_add_video_html5"><![CDATA[Add Video (HTML5)]]></string>
-
     <string name="_bx_timeline_menu_item_title_add_file"><![CDATA[Add File]]></string>
     <string name="_bx_timeline_menu_item_title_system_add_file_simple"><![CDATA[Add File (Simple)]]></string>
     <string name="_bx_timeline_menu_item_title_system_add_file_html5"><![CDATA[Add File (HTML5)]]></string>
-
     <string name="_bx_timeline_menu_item_title_add_video"><![CDATA[Add Video]]></string>
     <string name="_bx_timeline_menu_item_title_system_add_video_record"><![CDATA[Record Video]]></string>
     <string name="_bx_timeline_menu_item_title_add_video_record"><![CDATA[Record Video]]></string>
+    <string name="_bx_timeline_menu_item_title_system_add_poll"><![CDATA[Add Poll]]></string>
+    <string name="_bx_timeline_menu_item_title_add_poll"><![CDATA[Add Poll]]></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]]></string>
     <string name="_bx_timeline_menu_item_title_create_entry"><![CDATA[Update]]></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_menu_item_title_system_manage_my_timeline"><![CDATA[Timeline]]></string>
     <string name="_bx_timeline_menu_item_title_manage_my_timeline"><![CDATA[Timeline]]></string>
 
@@ -463,6 +477,12 @@
     <string name="_bx_timeline_txt_msg_success_repost"><![CDATA[The item was successfully reposted.]]></string>
     <string name="_bx_timeline_txt_object_reposted"><![CDATA[<b class="bx-ntfs-content-profile">{owner_name}</b> reposted a {entry_sample} <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
 
+    <string name="_bx_timeline_txt_poll_view_answers"><![CDATA[poll]]></string>
+    <string name="_bx_timeline_txt_poll_view_results"><![CDATA[results]]></string>
+    <string name="_bx_timeline_txt_poll_answer_vote_do_by"><![CDATA[Voted for]]></string>
+    <string name="_bx_timeline_txt_poll_answer_vote_counter"><![CDATA[{0} votes]]></string>
+    <string name="_bx_timeline_txt_poll_answer_vote_percent"><![CDATA[({0}%)]]></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>

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

@@ -30,9 +30,10 @@ INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `
 ('bx_timeline_view_hot', 1, 'bx_timeline', '_bx_timeline_page_block_title_system_view_hot_outline', '_bx_timeline_page_block_title_view_hot_outline', 0, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:26:"get_block_view_hot_outline";}', 0, 1, 1, 2),
 
 ('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, 1),
-('bx_timeline_item', 1, 'bx_timeline', '', '_bx_timeline_page_block_title_item_comments', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:23:"get_block_item_comments";}', 0, 0, 1, 2),
+('bx_timeline_item', 1, 'bx_timeline', '', '_bx_timeline_page_block_title_item_polls', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:12:"entity_polls";}', 0, 0, 1, 5),
+('bx_timeline_item', 1, 'bx_timeline', '', '_bx_timeline_page_block_title_item_comments', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:23:"get_block_item_comments";}', 0, 0, 1, 10),
 ('bx_timeline_item', 2, 'bx_timeline', '', '_bx_timeline_page_block_title_item_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:19:"get_block_item_info";}', 0, 0, 1, 1),
-('bx_timeline_item', 1, 'bx_timeline', '', '_bx_timeline_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:11:\"bx_timeline\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6),
+('bx_timeline_item', 1, 'bx_timeline', '', '_bx_timeline_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:14:"entity_reports";}', 0, 0, 1, 15),
 
 ('bx_timeline_item_brief', 1, 'bx_timeline', '', '_bx_timeline_page_block_title_item_content', 0, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:22:"get_block_item_content";}', 0, 0, 1, 1),
 ('bx_timeline_item_brief', 0, 'bx_timeline', '', '_bx_timeline_page_block_title_item_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:19:"get_block_item_info";}', 0, 0, 1, 1),
@@ -81,7 +82,7 @@ INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `lay
 ('bx_timeline_administration', '_bx_timeline_page_title_sys_manage_administration', '_bx_timeline_page_title_manage', 'bx_timeline', 5, 192, 1, 'timeline-administration', 'page.php?i=timeline-administration', '', '', '', 0, 1, 0, 'BxTimelinePageBrowse', 'modules/boonex/timeline/classes/BxTimelinePageBrowse.php');
 
 INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
-('bx_timeline_administration', 1, 'bx_timeline', '_bx_timeline_page_block_title_system_manage_administration', '_bx_timeline_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:11:\"bx_timeline\";s:6:\"method\";s:12:\"manage_tools\";s:6:\"params\";a:1:{i:0;s:14:\"administration\";}}', 0, 1, 0);
+('bx_timeline_administration', 1, 'bx_timeline', '_bx_timeline_page_block_title_system_manage_administration', '_bx_timeline_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:"module";s:11:"bx_timeline";s:6:"method";s:12:"manage_tools";s:6:"params";a:1:{i:0;s:14:"administration";}}', 0, 1, 0);
 
 
 -- PAGE: service blocks
@@ -261,7 +262,8 @@ INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `titl
 ('bx_timeline_menu_post_attachments', 'bx_timeline', 'add-video-html5', '_bx_timeline_menu_item_title_system_add_video_html5', '_bx_timeline_menu_item_title_add_video', 'javascript:void(0)', 'javascript:{js_object_add_video_html5}.showUploaderForm();', '_self', 'video', '', '', 2147483647, 1, 0, 1, 5),
 ('bx_timeline_menu_post_attachments', 'bx_timeline', 'add-video-record', '_bx_timeline_menu_item_title_system_add_video_record', '_bx_timeline_menu_item_title_add_video_record', 'javascript:void(0)', 'javascript:{js_object_add_video_record}.showUploaderForm();', '_self', 'fas circle', '', '', 2147483647, 1, 0, 1, 6),
 ('bx_timeline_menu_post_attachments', 'bx_timeline', 'add-file-simple', '_bx_timeline_menu_item_title_system_add_file_simple', '_bx_timeline_menu_item_title_add_file', 'javascript:void(0)', 'javascript:{js_object_add_file_simple}.showUploaderForm();', '_self', 'file', '', '', 2147483647, 0, 0, 1, 7),
-('bx_timeline_menu_post_attachments', 'bx_timeline', 'add-file-html5', '_bx_timeline_menu_item_title_system_add_file_html5', '_bx_timeline_menu_item_title_add_file', 'javascript:void(0)', 'javascript:{js_object_add_file_html5}.showUploaderForm();', '_self', 'file', '', '', 2147483647, 1, 0, 1, 8);
+('bx_timeline_menu_post_attachments', 'bx_timeline', 'add-file-html5', '_bx_timeline_menu_item_title_system_add_file_html5', '_bx_timeline_menu_item_title_add_file', 'javascript:void(0)', 'javascript:{js_object_add_file_html5}.showUploaderForm();', '_self', 'file', '', '', 2147483647, 1, 0, 1, 8),
+('bx_timeline_menu_post_attachments', 'bx_timeline', 'add-poll', '_bx_timeline_menu_item_title_system_add_poll', '_bx_timeline_menu_item_title_add_poll', 'javascript:void(0)', 'javascript:{js_object_poll}.showPollForm(this);', '_self', 'tasks', '', '', 2147483647, 1, 0, 1, 9);
 
 -- 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);

+ 93 - 23
modules/boonex/timeline/install/sql/install.sql

@@ -461,6 +461,49 @@ CREATE TABLE IF NOT EXISTS `bx_timeline_scores_track` (
   KEY `vote` (`object_id`, `author_nip`)
 );
 
+-- TABLE: polls
+CREATE TABLE IF NOT EXISTS `bx_timeline_polls` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author_id` int(11) NOT NULL default '0',
+  `content_id` int(11) NOT NULL default '0',
+  `text` text NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `content_id` (`content_id`),
+  FULLTEXT KEY `search_fields` (`text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_polls_answers` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `poll_id` int(11) unsigned NOT NULL default '0',
+  `title` varchar(255) NOT NULL,
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `order` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `poll_id` (`poll_id`),
+  FULLTEXT KEY `title` (`title`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_polls_answers_votes` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_timeline_polls_answers_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`)
+);
+
 
 -- STORAGES, TRANSCODERS, UPLOADERS
 SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
@@ -545,6 +588,7 @@ INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `c
 ('bx_timeline_post', @sName, 'photo', 'a:1:{i:0;s:23:"bx_timeline_html5_photo";}', 'a:1:{s:23:"bx_timeline_html5_photo";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_timeline_form_post_input_sys_photo', '_bx_timeline_form_post_input_photo', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 ('bx_timeline_post', @sName, 'video', 'a:2:{i:0;s:23:"bx_timeline_html5_video";i:1;s:24:"bx_timeline_record_video";}', 'a:2:{s:23:"bx_timeline_html5_video";s:25:"_sys_uploader_html5_title";s:24:"bx_timeline_record_video";s:32:"_sys_uploader_record_video_title";}', 0, 'files', '_bx_timeline_form_post_input_sys_video', '_bx_timeline_form_post_input_video', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 ('bx_timeline_post', @sName, 'file', 'a:1:{i:0;s:22:"bx_timeline_html5_file";}', 'a:1:{s:22:"bx_timeline_html5_file";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_timeline_form_post_input_sys_files', '_bx_timeline_form_post_input_files', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_timeline_post', @sName, 'polls', '', '', 0, 'custom', '_bx_timeline_form_post_input_sys_polls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 ('bx_timeline_post', @sName, 'attachments', '', '', 0, 'custom', '_bx_timeline_form_post_input_sys_attachments', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 ('bx_timeline_post', @sName, 'controls', '', 'tlb_do_submit,tlb_do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
 ('bx_timeline_post', @sName, 'tlb_do_submit', '_bx_timeline_form_post_input_do_submit', '', 0, 'submit', '_bx_timeline_form_post_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
@@ -560,11 +604,12 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 ('bx_timeline_post_add', 'photo', 2147483647, 1, 7),
 ('bx_timeline_post_add', 'video', 2147483647, 1, 8),
 ('bx_timeline_post_add', 'file', 2147483647, 1, 9),
-('bx_timeline_post_add', 'object_privacy_view', 2147483647, 1, 10),
-('bx_timeline_post_add', 'object_cf', 2147483647, 1, 11),
-('bx_timeline_post_add', 'published', 192, 0, 12),
-('bx_timeline_post_add', 'location', 2147483647, 1, 13),
-('bx_timeline_post_add', 'tlb_do_submit', 2147483647, 1, 14),
+('bx_timeline_post_add', 'polls', 2147483647, 1, 10),
+('bx_timeline_post_add', 'object_privacy_view', 2147483647, 1, 11),
+('bx_timeline_post_add', 'object_cf', 2147483647, 1, 12),
+('bx_timeline_post_add', 'published', 192, 0, 13),
+('bx_timeline_post_add', 'location', 2147483647, 1, 14),
+('bx_timeline_post_add', 'tlb_do_submit', 2147483647, 1, 15),
 
 ('bx_timeline_post_add_public', 'type', 2147483647, 1, 1),
 ('bx_timeline_post_add_public', 'action', 2147483647, 1, 2),
@@ -575,11 +620,12 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 ('bx_timeline_post_add_public', 'photo', 2147483647, 1, 7),
 ('bx_timeline_post_add_public', 'video', 2147483647, 1, 8),
 ('bx_timeline_post_add_public', 'file', 2147483647, 1, 9),
-('bx_timeline_post_add_public', 'object_privacy_view', 2147483647, 1, 10),
-('bx_timeline_post_add_public', 'object_cf', 2147483647, 1, 11),
-('bx_timeline_post_add_public', 'published', 192, 0, 12),
-('bx_timeline_post_add_public', 'location', 2147483647, 1, 13),
-('bx_timeline_post_add_public', 'tlb_do_submit', 2147483647, 1, 14),
+('bx_timeline_post_add_public', 'polls', 2147483647, 1, 10),
+('bx_timeline_post_add_public', 'object_privacy_view', 2147483647, 1, 11),
+('bx_timeline_post_add_public', 'object_cf', 2147483647, 1, 12),
+('bx_timeline_post_add_public', 'published', 192, 0, 13),
+('bx_timeline_post_add_public', 'location', 2147483647, 1, 14),
+('bx_timeline_post_add_public', 'tlb_do_submit', 2147483647, 1, 15),
 
 ('bx_timeline_post_add_profile', 'type', 2147483647, 1, 1),
 ('bx_timeline_post_add_profile', 'action', 2147483647, 1, 2),
@@ -590,11 +636,12 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 ('bx_timeline_post_add_profile', 'photo', 2147483647, 1, 7),
 ('bx_timeline_post_add_profile', 'video', 2147483647, 1, 8),
 ('bx_timeline_post_add_profile', 'file', 2147483647, 1, 9),
-('bx_timeline_post_add_profile', 'object_privacy_view', 2147483647, 1, 10),
-('bx_timeline_post_add_profile', 'object_cf', 2147483647, 1, 11),
-('bx_timeline_post_add_profile', 'published', 192, 0, 12),
-('bx_timeline_post_add_profile', 'location', 2147483647, 1, 13),
-('bx_timeline_post_add_profile', 'tlb_do_submit', 2147483647, 1, 14),
+('bx_timeline_post_add_profile', 'polls', 2147483647, 1, 10),
+('bx_timeline_post_add_profile', 'object_privacy_view', 2147483647, 1, 11),
+('bx_timeline_post_add_profile', 'object_cf', 2147483647, 1, 12),
+('bx_timeline_post_add_profile', 'published', 192, 0, 13),
+('bx_timeline_post_add_profile', 'location', 2147483647, 1, 14),
+('bx_timeline_post_add_profile', 'tlb_do_submit', 2147483647, 1, 15),
 
 ('bx_timeline_post_edit', 'type', 2147483647, 1, 1),
 ('bx_timeline_post_edit', 'action', 2147483647, 1, 2),
@@ -605,13 +652,14 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 ('bx_timeline_post_edit', 'photo', 2147483647, 1, 7),
 ('bx_timeline_post_edit', 'video', 2147483647, 1, 8),
 ('bx_timeline_post_edit', 'file', 2147483647, 1, 9),
-('bx_timeline_post_edit', 'object_privacy_view', 2147483647, 1, 10),
-('bx_timeline_post_edit', 'object_cf', 2147483647, 1, 11),
-('bx_timeline_post_edit', 'published', 192, 0, 12),
-('bx_timeline_post_edit', 'location', 2147483647, 1, 13),
-('bx_timeline_post_edit', 'controls', 2147483647, 1, 14),
-('bx_timeline_post_edit', 'tlb_do_submit', 2147483647, 1, 15),
-('bx_timeline_post_edit', 'tlb_do_cancel', 2147483647, 1, 16);
+('bx_timeline_post_edit', 'polls', 2147483647, 1, 10),
+('bx_timeline_post_edit', 'object_privacy_view', 2147483647, 1, 11),
+('bx_timeline_post_edit', 'object_cf', 2147483647, 1, 12),
+('bx_timeline_post_edit', 'published', 192, 0, 13),
+('bx_timeline_post_edit', 'location', 2147483647, 1, 14),
+('bx_timeline_post_edit', 'controls', 2147483647, 1, 15),
+('bx_timeline_post_edit', 'tlb_do_submit', 2147483647, 1, 16),
+('bx_timeline_post_edit', 'tlb_do_cancel', 2147483647, 1, 17);
 
 -- 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
@@ -634,6 +682,27 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 ('bx_timeline_attach_link_add', 'do_submit', 2147483647, 1, 4),
 ('bx_timeline_attach_link_add', 'do_cancel', 2147483647, 1, 5);
 
+-- FORMS -> Attach poll
+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_poll', 'bx_timeline', '_bx_timeline_form_poll', '', '', 'do_submit', 'bx_timeline_polls', 'id', '', '', 'a:1:{s:14:"checker_helper";s:31:"BxTimelineFormPollCheckerHelper";}', 0, 1, 'BxTimelineFormPoll', 'modules/boonex/timeline/classes/BxTimelineFormPoll.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_timeline_poll_add', 'bx_timeline', 'bx_timeline_poll', '_bx_timeline_form_poll_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_poll', 'bx_timeline', 'text', '', '', 0, 'text', '_bx_timeline_form_poll_input_sys_text', '_bx_timeline_form_poll_input_text', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_timeline_form_poll_input_text_err', 'Xss', '', 1, 0),
+('bx_timeline_poll', 'bx_timeline', 'answers', '', '', 0, 'custom', '_bx_timeline_form_poll_input_sys_answers', '_bx_timeline_form_poll_input_answers', '', 1, 0, 0, '', '', '', 'AvailAnswers', '', '_bx_timeline_form_poll_input_answers_err', '', '', 1, 0),
+('bx_timeline_poll', 'bx_timeline', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_timeline_poll', 'bx_timeline', 'do_submit', '_bx_timeline_form_poll_input_do_submit', '', 0, 'submit', '_bx_timeline_form_poll_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_timeline_poll', 'bx_timeline', 'do_cancel', '_bx_timeline_form_poll_input_do_cancel', '', 0, 'button', '_bx_timeline_form_poll_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_poll_add', 'text', 2147483647, 1, 1),
+('bx_timeline_poll_add', 'answers', 2147483647, 1, 2),
+('bx_timeline_poll_add', 'controls', 2147483647, 1, 3),
+('bx_timeline_poll_add', 'do_submit', 2147483647, 1, 4),
+('bx_timeline_poll_add', 'do_cancel', 2147483647, 1, 5);
+
 -- Forms -> Repost To
 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_repost', @sName, '_bx_timeline_form_repost', '', '', 'do_submit', '', '', '', '', '', 0, 1, 'BxTimelineFormRepost', 'modules/boonex/timeline/classes/BxTimelineFormRepost.php');
@@ -693,7 +762,8 @@ INSERT INTO `sys_objects_view` (`name`, `module`, `table_track`, `period`, `is_o
 -- VOTES
 INSERT INTO `sys_objects_vote`(`Name`, `Module`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
 ('bx_timeline', 'bx_timeline', 'bx_timeline_votes', 'bx_timeline_votes_track', '604800', '1', '1', '0', '1', 'bx_timeline_events', 'id', 'object_owner_id', 'rate', 'votes', 'BxTimelineVoteLikes', 'modules/boonex/timeline/classes/BxTimelineVoteLikes.php'),
-('bx_timeline_reactions', 'bx_timeline', 'bx_timeline_reactions', 'bx_timeline_reactions_track', '604800', '1', '1', '1', '1', 'bx_timeline_events', 'id', 'object_owner_id', 'rrate', 'rvotes', 'BxTemplVoteReactions', '');
+('bx_timeline_reactions', 'bx_timeline', 'bx_timeline_reactions', 'bx_timeline_reactions_track', '604800', '1', '1', '1', '1', 'bx_timeline_events', 'id', 'object_owner_id', 'rrate', 'rvotes', 'BxTemplVoteReactions', ''),
+('bx_timeline_poll_answers', 'bx_timeline', 'bx_timeline_polls_answers_votes', 'bx_timeline_polls_answers_votes_track', '604800', '1', '1', '0', '1', 'bx_timeline_polls_answers', 'id', 'author_id', 'rate', 'votes', 'BxTimelineVotePollAnswers', 'modules/boonex/timeline/classes/BxTimelineVotePollAnswers.php');
 
 
 -- SCORES

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

@@ -32,6 +32,8 @@ DROP TABLE IF EXISTS `bx_timeline_scores`, `bx_timeline_scores_track`;
 
 DROP TABLE IF EXISTS `bx_timeline_cmts_notes`;
 
+DROP TABLE IF EXISTS `bx_timeline_polls`, `bx_timeline_polls_answers`, `bx_timeline_polls_answers_votes`, `bx_timeline_polls_answers_votes_track`;
+
 
 -- STORAGES, TRANSCODERS, UPLOADERS
 DELETE FROM `sys_objects_uploader` WHERE `object` LIKE 'bx_timeline%';
@@ -58,7 +60,7 @@ DELETE FROM `sys_objects_view` WHERE `name` = 'bx_timeline' LIMIT 1;
 
 
 -- VOTES
-DELETE FROM `sys_objects_vote` WHERE `Name` IN ('bx_timeline', 'bx_timeline_reactions');
+DELETE FROM `sys_objects_vote` WHERE `Name` IN ('bx_timeline', 'bx_timeline_reactions', 'bx_timeline_poll_answers');
 
 
 -- SCORES

+ 21 - 0
modules/boonex/timeline/js/polls.js

@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Timeline Timeline
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxTimelinePolls(oOptions)
+{
+    BxBaseModGeneralPolls.call(this, oOptions);
+
+    this._sObjName = oOptions.sObjName == undefined ? 'oBxTimelinePolls' : oOptions.sObjName;
+}
+
+BxTimelinePolls.prototype = Object.create(BxBaseModGeneralPolls.prototype);
+BxTimelinePolls.prototype.constructor = BxTimelinePolls;
+
+/** @} */

+ 7 - 0
modules/boonex/timeline/template/type_post.html

@@ -56,6 +56,13 @@
         </bx_repeat:items>
     </div>
 </bx_if:show_attachments_files>
+<bx_if:show_attachments_polls>
+    <div class="__style_prefix__-item-polls px-3 md:px-4">
+        <bx_repeat:polls>
+            <div class="__style_prefix__-item-link mt-3 md:mt-4">__poll__</div>
+        </bx_repeat:polls>
+    </div>
+</bx_if:show_attachments_polls>
 <bx_if:show_raw>
     <div class="__style_prefix__-item-raw px-3 md:px-4 mt-3 md:mt-4">__item_content_raw__</div>
 </bx_if:show_raw>