Преглед изворни кода

Ticket 4879 - Stories Module.

AntonLV пре 1 година
родитељ
комит
7dee3749e4
45 измењених фајлова са 4167 додато и 0 уклоњено
  1. 35 0
      modules/boonex/stories/classes/BxStoriesAlertsResponse.php
  2. 24 0
      modules/boonex/stories/classes/BxStoriesCmtsSearchResult.php
  3. 230 0
      modules/boonex/stories/classes/BxStoriesConfig.php
  4. 221 0
      modules/boonex/stories/classes/BxStoriesDb.php
  5. 151 0
      modules/boonex/stories/classes/BxStoriesFormEntry.php
  6. 72 0
      modules/boonex/stories/classes/BxStoriesFormMedia.php
  7. 23 0
      modules/boonex/stories/classes/BxStoriesFormsEntryHelper.php
  8. 22 0
      modules/boonex/stories/classes/BxStoriesGridAdministration.php
  9. 22 0
      modules/boonex/stories/classes/BxStoriesGridCommon.php
  10. 25 0
      modules/boonex/stories/classes/BxStoriesMenu.php
  11. 26 0
      modules/boonex/stories/classes/BxStoriesMenuManageTools.php
  12. 31 0
      modules/boonex/stories/classes/BxStoriesMenuSnippetMeta.php
  13. 29 0
      modules/boonex/stories/classes/BxStoriesMenuView.php
  14. 40 0
      modules/boonex/stories/classes/BxStoriesMenuViewActions.php
  15. 345 0
      modules/boonex/stories/classes/BxStoriesModule.php
  16. 24 0
      modules/boonex/stories/classes/BxStoriesPageAuthor.php
  17. 25 0
      modules/boonex/stories/classes/BxStoriesPageBrowse.php
  18. 42 0
      modules/boonex/stories/classes/BxStoriesPageEntry.php
  19. 141 0
      modules/boonex/stories/classes/BxStoriesSearchResult.php
  20. 157 0
      modules/boonex/stories/classes/BxStoriesSearchResultMedia.php
  21. 331 0
      modules/boonex/stories/classes/BxStoriesTemplate.php
  22. 39 0
      modules/boonex/stories/classes/BxStoriesUploaderCrop.php
  23. 39 0
      modules/boonex/stories/classes/BxStoriesUploaderHTML5.php
  24. 38 0
      modules/boonex/stories/classes/BxStoriesUploaderRecordVideo.php
  25. 140 0
      modules/boonex/stories/install/config.php
  26. 20 0
      modules/boonex/stories/install/installer.php
  27. 252 0
      modules/boonex/stories/install/langs/en.xml
  28. 59 0
      modules/boonex/stories/install/sql/disable.sql
  29. 445 0
      modules/boonex/stories/install/sql/enable.sql
  30. 385 0
      modules/boonex/stories/install/sql/install.sql
  31. 56 0
      modules/boonex/stories/install/sql/uninstall.sql
  32. 187 0
      modules/boonex/stories/js/main.js
  33. 21 0
      modules/boonex/stories/js/manage_tools.js
  34. 18 0
      modules/boonex/stories/request.php
  35. 236 0
      modules/boonex/stories/template/css/main.css
  36. 1 0
      modules/boonex/stories/template/embed.html
  37. 27 0
      modules/boonex/stories/template/form_ghost_template.html
  38. 40 0
      modules/boonex/stories/template/images/icons/std-icon.svg
  39. 20 0
      modules/boonex/stories/template/media_edit.html
  40. 26 0
      modules/boonex/stories/template/play.html
  41. 28 0
      modules/boonex/stories/template/unit.html
  42. 17 0
      modules/boonex/stories/template/unit_gallery.html
  43. 16 0
      modules/boonex/stories/template/unit_media.html
  44. 23 0
      modules/boonex/stories/template/unit_media_gallery.html
  45. 18 0
      modules/boonex/stories/template/unit_showcase.html

+ 35 - 0
modules/boonex/stories/classes/BxStoriesAlertsResponse.php

@@ -0,0 +1,35 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxStoriesAlertsResponse extends BxBaseModTextAlertsResponse
+{
+    public function __construct()
+    {
+        $this->MODULE = 'bx_stories';
+
+        parent::__construct();
+    }
+
+    public function response($oAlert)
+    {
+        if ('bx_stories_files' == $oAlert->sUnit && 'file_deleted' == $oAlert->sAction)
+            BxDolService::call($this->MODULE, 'delete_file_associations', array($oAlert->iObject));
+
+        parent::response($oAlert);
+    }
+
+    protected function _onVideoTranscoded($iGhostId, $bResult, $aParams = array())
+    {
+        return parent::_onVideoTranscoded($iGhostId, $bResult, array('storage' => $this->_oModule->_oConfig->CNF['OBJECT_STORAGE']));
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/stories/classes/BxStoriesCmtsSearchResult.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    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxStoriesCmtsSearchResult extends BxBaseModGeneralCmtsSearchResult
+{
+    function __construct($sMode = '', $aParams = array())
+    {
+    	$this->sModule = 'bx_stories';
+
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent['title'] = _t('_bx_stories_page_block_title_browse_cmts');
+    }
+}
+
+/** @} */

+ 230 - 0
modules/boonex/stories/classes/BxStoriesConfig.php

@@ -0,0 +1,230 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxStoriesConfig extends BxBaseModTextConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $aMenuItems2Methods = array (
+            'approve' => 'checkAllowedApprove',
+            'add-media-to-story' => 'checkAllowedEdit',
+            'edit-story' => 'checkAllowedEdit',
+            'edit-image' => 'checkAllowedEdit',
+            'move-image' => 'checkAllowedEdit',
+            'delete-story' => 'checkAllowedDelete',
+            'delete-image' => 'checkAllowedDelete',
+        );
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'far image col-blue1',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'entries',
+            'TABLE_ENTRIES_FULLTEXT' => 'title_text',
+            'TABLE_ENTRIES_MEDIA' => $aModule['db_prefix'] . 'entries_media',
+            'TABLE_FILES' => $aModule['db_prefix'] . 'files',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_EXPIRED' => 'expired',
+            'FIELD_TITLE' => 'title',
+            'FIELD_TEXT' => 'text',
+            'FIELD_TEXT_ID' => 'story-desc',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_CF' => 'cf',
+            'FIELD_PHOTO' => 'pictures',
+            'FIELD_THUMB' => 'thumb',
+            'FIELD_VIEWS' => 'views',
+            'FIELD_COMMENTS' => 'comments',
+            'FIELD_STATUS' => 'status',
+            'FIELD_STATUS_ADMIN' => 'status_admin',
+            'FIELD_LABELS' => 'labels',
+            'FIELDS_WITH_KEYWORDS' => 'auto', // can be 'auto', array of fields or comma separated string of field names, works only when OBJECT_METATAGS is specified
+            'FIELDS_DELAYED_PROCESSING' => 'pictures', // can be array of fields or comma separated string of field names
+
+            'FIELD_MEDIA_CONTENT_ID' => 'content_id',
+            
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-story',
+            'URI_AUTHOR_ENTRIES' => 'stories-author',
+            'URI_ENTRIES_BY_CONTEXT' => 'stories-context',
+            'URI_ADD_ENTRY' => 'create-story',
+            'URI_EDIT_ENTRY' => 'edit-story',
+            'URI_MANAGE_COMMON' => 'stories-manage',
+
+            'URL_HOME' => 'page.php?i=stories-home',
+            'URL_POPULAR' => 'page.php?i=stories-popular',
+            'URL_TOP' => 'page.php?i=stories-top',
+            'URL_UPDATED' => 'page.php?i=stories-home',
+            'URL_MANAGE_COMMON' => 'page.php?i=stories-manage',
+            'URL_MANAGE_ADMINISTRATION' => 'page.php?i=stories-administration',
+
+            // some params
+            'PARAM_AUTO_APPROVE' => 'bx_stories_enable_auto_approve',
+            'PARAM_CHARS_SUMMARY' => 'bx_stories_summary_chars',
+            'PARAM_CHARS_SUMMARY_PLAIN' => 'bx_stories_plain_summary_chars',
+            'PARAM_NUM_RSS' => 'bx_stories_rss_num',
+            'PARAM_SEARCHABLE_FIELDS' => 'bx_stories_searchable_fields',
+            'PARAM_CARD_MEDIA_NUM' => 'bx_stories_card_media_num',
+            'PARAM_EXPIRATION_PERIOD' => 'bx_stories_expiration_period',
+            'PARAM_DURATION' => 'bx_stories_duration',
+            'PARAM_ORDER_BY_GHOSTS' => true,
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_stories_files',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW' => 'bx_stories_proxy_preview',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => '',
+            'OBJECT_IMAGES_TRANSCODER_BIG' => 'bx_stories_big',
+            'OBJECT_VIDEOS_TRANSCODERS' => array(
+                'poster' => 'bx_stories_video_poster_big', 
+                'poster_preview' => 'bx_stories_video_poster_preview', 
+                'mp4' => 'bx_stories_video_mp4', 
+                'mp4_hd' => 'bx_stories_video_mp4_hd'
+            ),
+            'OBJECT_VIDEO_TRANSCODER_HEIGHT' => '480px',
+            'OBJECT_TRANSCODER_BROWSE' => 'bx_stories_proxy_browse',
+            'OBJECT_TRANSCODER_COVER' => 'bx_stories_proxy_cover',
+            'OBJECT_REPORTS' => 'bx_stories',
+            'OBJECT_REPORTS_MEDIA' => 'bx_stories_media',
+            'OBJECT_VIEWS' => 'bx_stories',
+            'OBJECT_VIEWS_MEDIA' => 'bx_stories_media',
+            'OBJECT_VOTES' => 'bx_stories',
+            'OBJECT_VOTES_MEDIA' => 'bx_stories_media',
+            'OBJECT_REACTIONS' => 'bx_stories_reactions',
+            'OBJECT_SCORES' => 'bx_stories',
+            'OBJECT_SCORES_MEDIA' => 'bx_stories_media',
+            'OBJECT_FAVORITES' => 'bx_stories',
+            'OBJECT_FAVORITES_MEDIA' => 'bx_stories_media',
+            'OBJECT_FEATURED' => 'bx_stories',
+            'OBJECT_FEATURED_MEDIA' => 'bx_stories_media',
+            'OBJECT_METATAGS' => 'bx_stories',
+            'OBJECT_COMMENTS' => 'bx_stories',
+            'OBJECT_NOTES' => 'bx_stories_notes',
+            'OBJECT_COMMENTS_MEDIA' => 'bx_stories_media',
+            'OBJECT_PRIVACY_VIEW' => 'bx_stories_allow_view_to',
+            'OBJECT_PRIVACY_LIST_VIEW' => 'bx_stories_allow_view_favorite_list',
+            'OBJECT_FORM_ENTRY' => 'bx_stories',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_stories_entry_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_stories_entry_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => 'bx_stories_entry_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_stories_entry_delete',
+            'OBJECT_FORM_MEDIA' => 'bx_stories_media',
+            'OBJECT_FORM_MEDIA_DISPLAY_EDIT' => 'bx_stories_media_edit',
+            'OBJECT_FORM_MEDIA_DISPLAY_MOVE' => 'bx_stories_media_move',
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_stories_view', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL' => 'bx_stories_view_actions', // all actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_MEDIA' => 'bx_stories_view_actions_media', // actions menu on view media page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_stories_my', // actions menu on my entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_stories_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_stories_view_submenu', // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'stories-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_SNIPPET_META' => 'bx_stories_snippet_meta', // menu for snippet meta info
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_stories_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_stories_administration',
+            'OBJECT_GRID_COMMON' => 'bx_stories_common',
+            'OBJECT_UPLOADERS' => array('bx_stories_html5', 'bx_stories_crop'),
+            
+            'FUNCTION_FOR_GET_ITEM_INFO' => 'getMediaInfoById',
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_stories_my' => array (
+                    'create-story' => 'checkAllowedAdd',
+                ),
+                'bx_stories_view' => $aMenuItems2Methods,
+                'bx_stories_view_media' => $aMenuItems2Methods,
+            ),
+
+            // informer messages
+            'INFORMERS' => array (
+                'approving' => array (
+                    'name' => 'bx-stories-approving',
+                    'map' => array (
+                        'pending' => array('msg' => '_bx_stories_txt_msg_status_pending', 'type' => BX_INFORMER_ALERT),
+                        'hidden' => array('msg' => '_bx_stories_txt_msg_status_hidden', 'type' => BX_INFORMER_ERROR),
+                    ),
+                ),
+                'processing' => array (
+                    'name' => 'bx_stories-processing',
+                    'map' => array (
+                        'awaiting' => array('msg' => '_bx_stories_txt_processing_awaiting', 'type' => BX_INFORMER_ALERT),
+                        'failed' => array('msg' => '_bx_stories_txt_processing_failed', 'type' => BX_INFORMER_ERROR)
+                    ),
+                ),
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_stories_txt_sample_single',
+            	'txt_sample_single_with_article' => '_bx_stories_txt_sample_single_with_article',
+            	'txt_sample_comment_single' => '_bx_stories_txt_sample_comment_single',
+            	'txt_sample_vote_single' => '_bx_stories_txt_sample_vote_single',
+                'txt_sample_reaction_single' => '_bx_stories_txt_sample_reaction_single',
+                'txt_sample_score_up_single' => '_bx_stories_txt_sample_score_up_single',
+                'txt_sample_score_down_single' => '_bx_stories_txt_sample_score_down_single',
+                'txt_sample_action_changed' => '_bx_stories_txt_sample_action_changed',
+                'txt_media_single' => '_bx_stories_txt_media_single',
+                'txt_media_comment_single' => '_bx_stories_txt_media_comment_single',
+            	'txt_media_vote_single' => '_bx_stories_txt_media_vote_single',
+                'txt_media_score_up_single' => '_bx_stories_txt_media_score_up_single',
+                'txt_media_score_down_single' => '_bx_stories_txt_media_score_down_single',
+            	'form_field_author' => '_bx_stories_form_entry_input_author',
+            	'grid_action_err_delete' => '_bx_stories_grid_action_err_delete',
+            	'grid_txt_account_manager' => '_bx_stories_grid_txt_account_manager',
+                'filter_item_active' => '_bx_stories_grid_filter_item_title_adm_active',
+            	'filter_item_hidden' => '_bx_stories_grid_filter_item_title_adm_hidden',
+                'filter_item_pending' => '_bx_stories_grid_filter_item_title_adm_pending',
+            	'filter_item_select_one_filter1' => '_bx_stories_grid_filter_item_title_adm_select_one_filter1',
+                'filter_item_select_one_filter2' => '_bx_stories_grid_filter_item_title_adm_select_one_filter2',
+            	'menu_item_manage_my' => '_bx_stories_menu_item_title_manage_my',
+            	'menu_item_manage_all' => '_bx_stories_menu_item_title_manage_all',
+                'txt_all_entries_by' => '_bx_stories_txt_all_entries_by',
+                'txt_all_entries_in' => '_bx_stories_txt_all_entries_in',
+            	'txt_all_entries_by_author' => '_bx_stories_page_title_browse_by_author',
+                'txt_all_entries_by_context' => '_bx_stories_page_title_browse_by_context',
+            ),
+        );
+
+        $this->_aJsClasses = [
+            'main' => 'BxStoriesMain',
+            'manage_tools' => 'BxStoriesManageTools'
+        ];
+
+        $this->_aJsObjects = [
+            'main' => 'oBxStoriesMain',
+            'manage_tools' => 'oBxStoriesManageTools'
+        ];
+
+        $this->_aGridObjects = [
+            'common' => $this->CNF['OBJECT_GRID_COMMON'],
+            'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
+        ];
+
+        $sPrefix = str_replace('_', '-', $this->_sName);
+        $this->_aHtmlIds = [
+            'play_popup' =>  $sPrefix . '-play-popup',
+        ];
+    }
+
+    public function getDuration()
+    {
+        return (int)getParam($this->CNF['PARAM_DURATION']);
+    }
+}
+
+/** @} */

+ 221 - 0
modules/boonex/stories/classes/BxStoriesDb.php

@@ -0,0 +1,221 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/*
+ * Module database queries
+ */
+class BxStoriesDb extends BxBaseModTextDb
+{
+    function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+    }
+
+    public function associateFileWithContent($iContentId, $iFileId, $iProfileId, $sTitle, $sData = '')
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iOrder = 1 + (int)$this->getOne("SELECT MAX(`order`) FROM `" . $CNF['TABLE_ENTRIES_MEDIA'] . "` WHERE `content_id` = :content_id", [
+            'content_id' => $iContentId
+        ]);
+
+        return $this->query("INSERT INTO `" . $CNF['TABLE_ENTRIES_MEDIA'] . "` SET `content_id` = :content_id, `file_id` = :file_id, `author` = :author, `title` = :title, `data` = :data, `order` = :order ON DUPLICATE KEY UPDATE `title` = :title, `data` = :data", [
+            'content_id' => $iContentId,
+            'file_id' => $iFileId,
+            'author' => $iProfileId,
+            'title' => $sTitle,
+            'data' => $sData,
+            'order' => $iOrder
+        ]);
+    }
+
+    public function deassociateFileWithContent($iContentId, $iFileId)
+    {
+    	$aBindings = array();
+
+        $sWhere = '';
+        if ($iContentId) {
+        	$aBindings['content_id'] = $iContentId;
+
+            $sWhere .= " AND `content_id` = :content_id";
+        }
+
+        if ($iFileId) {
+        	$aBindings['file_id'] = $iFileId;
+
+            $sWhere .= " AND `file_id` = :file_id";
+        }
+
+        $sQuery = "DELETE FROM `" . $this->_oConfig->CNF['TABLE_ENTRIES_MEDIA'] . "` WHERE 1 " . $sWhere;
+        return $this->query($sQuery, $aBindings);
+    }
+
+    public function getFileTitle($iFileId)
+    {
+        $sQuery = $this->prepare ("SELECT `title` FROM `" . $this->_oConfig->CNF['TABLE_ENTRIES_MEDIA'] . "` WHERE `file_id` = ?", $iFileId);
+        return $this->getOne($sQuery);
+    }
+
+    public function getMediaInfoById($iMediaId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sSelectClause = "`f2e`.*, `f`.`added`";
+        $sJoinClause = "INNER JOIN `" . $CNF['TABLE_FILES'] . "` AS `f` ON (`f`.`id` = `f2e`.`file_id`) INNER JOIN `" . $CNF['TABLE_ENTRIES'] . "` AS `e` ON (`e`.`id` = `f2e`.`content_id`)";
+
+        if($CNF['PARAM_ORDER_BY_GHOSTS']) {
+            $sSelectClause .= ", `g`.`order` as `gorder`";
+            $sJoinClause .= $this->prepareAsString("INNER JOIN `sys_storage_ghosts` AS `g` ON `g`.`id`=`f2e`.`file_id` AND `g`.`content_id`=`f2e`.`content_id` AND `g`.`object`=?", $CNF['OBJECT_STORAGE']);
+        }
+
+        $sQuery = $this->prepare("SELECT " . $sSelectClause . " FROM `" . $CNF['TABLE_ENTRIES_MEDIA'] . "` AS `f2e` " . $sJoinClause . " WHERE `f2e`.`id` = ?", $iMediaId);
+        return $this->getRow($sQuery);
+    }
+
+    public function getMediaInfoSimpleByFileId($iFileId)
+    {
+        $sQuery = $this->prepare ("SELECT * FROM `" . $this->_oConfig->CNF['TABLE_ENTRIES_MEDIA'] . "` WHERE `file_id` = ?", $iFileId);
+        return $this->getRow($sQuery);
+    }
+
+    public function getMediaCountByContentId($iContentId)
+    {
+        $sQuery = $this->prepare ("SELECT COUNT(*) FROM `" . $this->_oConfig->CNF['TABLE_ENTRIES_MEDIA'] . "` WHERE `content_id` = ? LIMIT 1", $iContentId);
+        return $this->getOne($sQuery);
+    }
+
+    public function getMediaListByContentId($iContentId, $iLimit = false)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aBindings = ['id' => $iContentId];
+
+        $sSelectClause = "`f2e`.*";
+        $sJoinClause = "";
+        $sOrderClause = "`f2e`.`order`";
+
+        if($CNF['PARAM_ORDER_BY_GHOSTS']) {
+            $sSelectClause .= ", `g`.`order` as `gorder`";
+            $sJoinClause .= $this->prepareAsString("INNER JOIN `sys_storage_ghosts` AS `g` ON `g`.`id`=`f2e`.`file_id` AND `g`.`content_id`=`f2e`.`content_id` AND `g`.`object`=?", $CNF['OBJECT_STORAGE']);
+            $sOrderClause = "`gorder` ASC";
+        }
+
+        if($sOrderClause)
+            $sOrderClause = "ORDER BY " . $sOrderClause;
+
+        $sLimitQuery = '';
+        if((int)$iLimit) {
+            $aBindings['limit'] = (int)$iLimit;
+
+            $sLimitQuery = ' LIMIT :limit';
+        }
+
+        return $this->getAll("SELECT " . $sSelectClause . " FROM `" . $CNF['TABLE_ENTRIES_MEDIA'] . "` AS `f2e` " . $sJoinClause . " WHERE `f2e`.`content_id` = :id " . $sOrderClause . " " . $sLimitQuery, $aBindings);
+    }
+
+    function getMediaBy($aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query', 1 => array()));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        $sSelectClause = "`{$CNF['TABLE_ENTRIES_MEDIA']}`.*";
+
+        switch($aParams['type']) {
+            case 'id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1]['id'] = (int)$aParams['id'];
+
+                $sWhereClause .= " AND `{$CNF['TABLE_ENTRIES_MEDIA']}`.`id` = :id";
+                break;
+
+            case 'search_ids':
+                $aMethod['name'] = 'getColumn';
+                
+                $sSelectClause = "`{$CNF['TABLE_ENTRIES_MEDIA']}`.`id`";
+
+                if (!empty($aParams['start']) && !empty($aParams['per_page']))
+                    $sLimitClause = $this->prepareAsString("?, ?", $aParams['start'], $aParams['per_page']);
+                elseif (!empty($aParams['per_page']))
+                    $sLimitClause = $this->prepareAsString("?", $aParams['per_page']);
+
+                $sWhereConditions = "1";
+                foreach($aParams['search_params'] as $sSearchParam => $aSearchParam) {
+                    $sSearchValue = "";
+                    switch ($aSearchParam['operator']) {
+                        case 'like':
+                            $sSearchValue = " LIKE " . $this->escape("%" . $aSearchParam['value'] . "%");
+                            break;
+
+                        case 'in':
+                            $sSearchValue = " IN (" . $this->implode_escape($aSearchParam['value']) . ")";
+                            break;
+
+                        case 'and':
+                            $iResult = 0;
+                            if (is_array($aSearchParam['value']))
+                                foreach ($aSearchParam['value'] as $iValue)
+                                    $iResult |= pow (2, $iValue - 1);
+                            else 
+                                $iResult = (int)$aSearchParam['value'];
+
+                            $sSearchValue = " & " . $iResult . "";
+                            break;
+
+                        default:
+                             $sSearchValue = " " . $aSearchParam['operator'] . " :" . $sSearchParam;
+                             $aMethod['params'][1][$sSearchParam] = $aSearchParam['value'];                             
+                    }
+
+                    $sWhereConditions .= " AND `{$CNF['TABLE_ENTRIES_MEDIA']}`.`" . $sSearchParam . "`" . $sSearchValue;
+                }
+
+                $sWhereClause .= " AND (" . $sWhereConditions . ")"; 
+
+                $sOrderClause .=  "`{$CNF['TABLE_ENTRIES_MEDIA']}`.`id` ASC";
+                break;
+
+            case 'all_ids':
+                $aMethod['name'] = 'getColumn';
+
+                $sSelectClause = "`{$CNF['TABLE_ENTRIES_MEDIA']}`.`id`";
+                $sOrderClause .=  "`{$CNF['TABLE_ENTRIES_MEDIA']}`.`id` ASC";
+                break;
+
+            case 'all':
+                $sOrderClause .=  "`{$CNF['TABLE_ENTRIES_MEDIA']}`.`id` ASC";
+                break;
+        }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = 'ORDER BY ' . $sOrderClause;
+
+        if(!empty($sLimitClause))
+            $sLimitClause = 'LIMIT ' . $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `{$CNF['TABLE_ENTRIES_MEDIA']}` " . $sJoinClause . " WHERE 1 " . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+		return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+    
+    public function updateMedia($aParamsSet, $aParamsWhere)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($aParamsSet) || empty($aParamsWhere))
+            return false;
+
+        $sSql = "UPDATE `" . $CNF['TABLE_FILES'] . "` SET " . $this->arrayToSQL($aParamsSet) . " WHERE " . $this->arrayToSQL($aParamsWhere, " AND ");
+        return $this->query($sSql);
+    }
+}
+
+/** @} */

+ 151 - 0
modules/boonex/stories/classes/BxStoriesFormEntry.php

@@ -0,0 +1,151 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Create/Edit entry form
+ */
+class BxStoriesFormEntry extends BxBaseModTextFormEntry
+{
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_stories';
+
+        parent::__construct($aInfo, $oTemplate);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if (isset($CNF['FIELD_PHOTO']) && isset($this->aInputs[$CNF['FIELD_PHOTO']]))
+            $this->aInputs[$CNF['FIELD_PHOTO']]['init_reordering'] = true;
+    }
+
+    public function processFiles ($sFieldFile, $iContentId = 0, $isAssociateWithContent = false)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if($isAssociateWithContent)
+            return parent::processFiles ($sFieldFile, $iContentId, $isAssociateWithContent);
+
+        $aMediasOld = $this->_oModule->_oDb->getMediaListByContentId($iContentId);                
+
+        if(!parent::processFiles ($sFieldFile, $iContentId, $isAssociateWithContent)) 
+            return false;
+
+        $aMediasNew = $this->_oModule->_oDb->getMediaListByContentId($iContentId);
+
+        $aIdsOld = array_column($aMediasOld, 'id');
+        $aIdsNew = array_column($aMediasNew, 'id');
+        $aIdsAdded = array_diff($aIdsNew, $aIdsOld);
+
+        if(!empty($aIdsAdded)) {
+            $aContentInfo = $this->_oModule->_oDb->getContentInfoById($iContentId);
+            $iProfileId = $this->getContentOwnerProfileId($iContentId);
+
+             /**
+             * @hooks
+             * @hookdef hook-bx_stories-medias_added 'bx_stories', 'medias_added' - hook on new medias added in story
+             * - $unit_name - equals `bx_stories`
+             * - $action - equals `medias_added` 
+             * - $object_id - story_id
+             * - $sender_id - author's profile_id
+             * - $extra_params - array of additional params with the following array keys:
+             *      - `object_author_id` - [int] confirmation type can be none/phone/email/email_and_phone/email_or_phone
+             *      - `subobjects_ids` - [array] array of ids for added media's
+             *      - `medias_added` - [array] array of ids for added media's
+             *      - `privacy_view` - [string] privacy view value for current story
+             *      - `cf` - [int] content filter id
+             * @hook @ref hook-bx_stories-medias_added
+             */
+            bx_alert($this->_oModule->getName(), 'medias_added', $iContentId, $iProfileId, [
+                'object_author_id' => $iProfileId,
+
+                'subobjects_ids' => $aIdsAdded,
+                'medias_added' => $aIdsAdded,
+
+                'privacy_view' => $aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']],
+                'cf' => $aContentInfo[$CNF['FIELD_CF']]
+            ]);
+        }
+
+        return true;
+    }
+    
+    protected function _associalFileWithContent($oStorage, $iFileId, $iProfileId, $iContentId, $sPictureField = '')
+    {
+        parent::_associalFileWithContent($oStorage, $iFileId, $iProfileId, $iContentId, $sPictureField);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oTranscoder = BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_IMAGES_TRANSCODER_BIG']);
+        
+        $aInfo = bx_get_image_exif_and_size($oStorage, $oTranscoder, $iFileId);
+        if($this->_oModule->_oDb->associateFileWithContent ($iContentId, $iFileId, $iProfileId, $this->getCleanValue('title-' . $iFileId), $aInfo['size']) === false)
+            return;
+
+        $aMediaInfo = $this->_oModule->_oDb->getMediaInfoSimpleByFileId($iFileId);
+        $aContentInfo = $this->_oModule->_oDb->getContentInfoById($iContentId);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_stories-media_added 'bx_stories', 'media_added' - hook on new media added in story
+         * - $unit_name - equals `bx_stories`
+         * - $action - equals `media_added` 
+         * - $object_id - story_id
+         * - $sender_id - author's profile_id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object_author_id` - [int] confirmation type can be none/phone/email/email_and_phone/email_or_phone
+         *      - `subobject_id` - [int] id for added media
+         *      - `media_id` - [int] id for added media
+         *      - `media_info` - [array] media info
+         * @hook @ref hook-bx_stories-media_added
+         */
+        bx_alert($this->_oModule->getName(), 'media_added', $iContentId, $iProfileId, array(
+            'object_author_id' => $aContentInfo[$CNF['FIELD_AUTHOR']],
+
+            'subobject_id' => $aMediaInfo['id'],
+
+            'media_id' => $aMediaInfo['id'], 
+            'media_info' => $aMediaInfo,
+        ));
+
+        bx_alert($this->_oModule->getName() . '_media', 'added', $aMediaInfo['id'], $iProfileId, array(
+            'object_id' => $iContentId, 
+            'object_author_id' => $aContentInfo[$CNF['FIELD_AUTHOR']], 
+
+            'media_info' => $aMediaInfo
+        ));
+    }
+
+    public function insert ($aValsToAdd = [], $isIgnore = false)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(empty($aValsToAdd[$CNF['FIELD_EXPIRED']]) && empty($this->getCleanValue($CNF['FIELD_EXPIRED'])))
+            $aValsToAdd[$CNF['FIELD_EXPIRED']] = time() + 3600 * (int)getParam($CNF['PARAM_EXPIRATION_PERIOD']);
+
+        return parent::insert ($aValsToAdd, $isIgnore);
+    }
+
+    public function delete ($iContentId, $aContentInfo = [])
+    {
+        if (!($bRet = parent::delete ($iContentId, $aContentInfo)))
+            return $bRet;
+
+        if (!($aMediaList = $this->_oModule->_oDb->getMediaListByContentId($iContentId)))
+            return $bRet;
+
+        foreach ($aMediaList as $aMediaInfo)
+            $this->_oModule->serviceDeleteFileAssociations($aMediaInfo['file_id']);
+        
+        return $bRet;
+    }
+}
+
+/** @} */

+ 72 - 0
modules/boonex/stories/classes/BxStoriesFormMedia.php

@@ -0,0 +1,72 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Create/Edit entry form
+ */
+class BxStoriesFormMedia extends BxTemplFormView
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_iMediaId;
+    protected $_aMediaInfo;
+
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_stories';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct($aInfo, $oTemplate);
+    }
+
+    public function initChecker($aValues = array (), $aSpecificValues = array())
+    {
+        if(!empty($this->_aMediaInfo) && is_array($this->_aMediaInfo))
+            $aValues = $this->_aMediaInfo;
+
+        parent::initChecker($aValues, $aSpecificValues);
+    }
+
+    public function initForm($aAction, $iMediaId)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $this->_iMediaId = $iMediaId;
+        $this->_aMediaInfo = $this->_oModule->_oDb->getMediaInfoById($iMediaId);
+
+        $this->aFormAttrs['action'] = BX_DOL_URL_ROOT . $this->_oModule->_oConfig->getBaseUri() . $aAction . '_media/' . $iMediaId;
+
+        if(isset($this->aInputs['content_id'])) {
+            $aStories = $this->_oModule->_oDb->getEntriesBy(array('type' => 'author', 'author' => $this->_aMediaInfo['author']));
+            foreach($aStories as $aStory)
+                $this->aInputs['content_id']['values'][] = ['key' => $aStory[$CNF['FIELD_ID']], 'value' => $aStory[$CNF['FIELD_TITLE']]];
+        }
+    }
+    
+    public function update($val, $aValsToAdd = array(), &$aTrackTextFieldsChanges = null)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $sField = 'content_id';
+        if(isset($this->aInputs[$sField])) {
+            $iContentId = $this->getCleanValue($sField);
+
+            $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+            if(!$oStorage->updateGhostsContentId($this->_aMediaInfo['file_id'], $this->_aMediaInfo['author'], $iContentId))
+                return false;
+        }
+
+        return parent::update($val, $aValsToAdd, $aTrackTextFieldsChanges);
+    }
+}
+
+/** @} */

+ 23 - 0
modules/boonex/stories/classes/BxStoriesFormsEntryHelper.php

@@ -0,0 +1,23 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Entry forms helper functions
+ */
+class BxStoriesFormsEntryHelper extends BxBaseModTextFormsEntryHelper
+{
+    public function __construct($oModule)
+    {
+        parent::__construct($oModule);
+    }
+}
+
+/** @} */

+ 22 - 0
modules/boonex/stories/classes/BxStoriesGridAdministration.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    Stories Stories
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+class BxStoriesGridAdministration extends BxBaseModTextGridAdministration
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_stories';
+
+        parent::__construct ($aOptions, $oTemplate);
+    }
+}
+
+/** @} */

+ 22 - 0
modules/boonex/stories/classes/BxStoriesGridCommon.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    Stories Stories
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+class BxStoriesGridCommon extends BxBaseModTextGridCommon
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_stories';
+
+        parent::__construct ($aOptions, $oTemplate);
+    }
+}
+
+/** @} */

+ 25 - 0
modules/boonex/stories/classes/BxStoriesMenu.php

@@ -0,0 +1,25 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * General class for module menu.
+ */
+class BxStoriesMenu extends BxBaseModTextMenu
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_stories';
+
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 26 - 0
modules/boonex/stories/classes/BxStoriesMenuManageTools.php

@@ -0,0 +1,26 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * 'Stories manage tools' menu.
+ */
+class BxStoriesMenuManageTools extends BxBaseModTextMenuManageTools
+{
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_stories';
+
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 31 - 0
modules/boonex/stories/classes/BxStoriesMenuSnippetMeta.php

@@ -0,0 +1,31 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxStoriesMenuSnippetMeta extends BxBaseModTextMenuSnippetMeta
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_stories';
+
+        parent::__construct($aObject, $oTemplate);
+    }
+
+    protected function _getMenuItemItems($aItem)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iCount = $this->_oModule->_oDb->getMediaCountByContentId($this->_aContentInfo[$CNF['FIELD_ID']]);
+
+        return $this->getUnitMetaItemText(_t($aItem['title'], $iCount));
+    }
+}
+
+/** @} */

+ 29 - 0
modules/boonex/stories/classes/BxStoriesMenuView.php

@@ -0,0 +1,29 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * View entry menu
+ */
+class BxStoriesMenuView extends BxBaseModTextMenuView
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_stories';
+
+        parent::__construct($aObject, $oTemplate);
+
+        $this->addMarkers([
+            'js_object' => $this->_oModule->_oConfig->getJsObject('main')
+        ]);
+    }
+}
+
+/** @} */

+ 40 - 0
modules/boonex/stories/classes/BxStoriesMenuViewActions.php

@@ -0,0 +1,40 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * View entry social actions menu
+ */
+class BxStoriesMenuViewActions extends BxBaseModTextMenuViewActions
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_stories';
+
+        parent::__construct($aObject, $oTemplate);
+    }
+
+    protected function _getMenuItemAddMediaToStory($aItem)
+    {
+        return $this->_getMenuItemByNameActions($aItem);
+    }
+
+    protected function _getMenuItemEditStory($aItem)
+    {
+        return $this->_getMenuItemByNameActions($aItem);
+    }
+
+    protected function _getMenuItemDeleteStory($aItem)
+    {
+        return $this->_getMenuItemByNameActions($aItem);
+    }
+}
+
+/** @} */

+ 345 - 0
modules/boonex/stories/classes/BxStoriesModule.php

@@ -0,0 +1,345 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+bx_import('BxDolAcl');
+
+/**
+ * Stories module
+ */
+class BxStoriesModule extends BxBaseModTextModule
+{
+    protected $_aContexts = array('popular', 'public', 'author');
+
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    public function actionEmbed($iContentId, $sUnitTemplate = '', $sAddCode = '')
+    {
+        return $this->_oTemplate->getJsCode('main') . parent::actionEmbed($iContentId);
+    }
+
+    public function actionPlay($iContentId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sJsObject = $this->_oConfig->getJsObject('main');
+
+        $aContentInfo = $this->_oDb->getContentInfoById($iContentId);
+        if(($sMsg = $this->checkAllowedEdit($aContentInfo)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return echoJson(['msg' => $sMsg]);
+
+        return echoJson(['popup' => [
+            'html' => $this->_oTemplate->entryPlay($aContentInfo), 
+            'options' => [
+                'closeOnOuterClick' => true,
+                'removeOnClose' => true,
+                'onShow' => $sJsObject . '.playInit()',
+                'onHide' => $sJsObject . '.playDestroy()'
+            ]
+        ]]);
+    }
+
+    public function actionEmbedMedia($iContentId)
+    {
+        $oTemplate = BxDolTemplate::getInstance();
+        
+        $aContentInfo = $this->_oDb->getMediaInfoById($iContentId);
+        if(empty($aContentInfo))
+            $oTemplate->getEmbed(false);
+
+        if(empty($sUnitTemplate))
+            $sUnitTemplate = 'unit_media_gallery.html';
+
+        $oTemplate->getEmbed($this->_oTemplate->unit($aContentInfo, true, $sUnitTemplate));
+    }
+
+    public function actionEditMedia($iMediaId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $iMediaId = (int)$iMediaId;
+        $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        $aContentInfo = $this->_oDb->getContentInfoById($aMediaInfo['content_id']);
+        if(($sMsg = $this->checkAllowedEdit($aContentInfo)) !== CHECK_ACTION_RESULT_ALLOWED)
+            return echoJson(['msg' => $sMsg]);
+
+        $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_MEDIA'], $CNF['OBJECT_FORM_MEDIA_DISPLAY_EDIT']);
+        $oForm->initForm('edit', $iMediaId);
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($iMediaId) !== false) {
+                $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+                $aRes = array('reload' => 1);
+            }
+            else
+                $aRes = array('msg' => _t('_bx_stories_txt_err_cannot_perform_action'));
+
+            return echoJson($aRes);
+        }
+
+        $sContent = BxTemplStudioFunctions::getInstance()->transBox('bx-stories-edit-media-popup', $this->_oTemplate->parseHtmlByName('media_edit.html', array(
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true)
+        )));
+
+        echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+	
+    public function actionDeleteMedia($iMediaId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sUploader = reset($CNF['OBJECT_UPLOADERS']);
+        $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        if(!$sUploader || empty($aMediaInfo) || !is_array($aMediaInfo))
+            return echoJson([]);
+
+        $oUploader = BxDolUploader::getObjectInstance($sUploader, $CNF['OBJECT_STORAGE'], '');
+        if($oUploader === false) 
+            return echoJson(['msg' => _t('_sys_txt_error_occured')]);
+
+        $oUploader->deleteGhost($aMediaInfo['file_id'], bx_get_logged_profile_id());
+
+        return echoJson(['redirect' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aMediaInfo['content_id']))]);            
+    }
+
+    public function actionGetSiblingMedia($iMediaId, $mixedContext)
+    {
+        $aSiblings = false;
+        $sErrorMsg = false;
+        if (!($aMediaInfo = $this->_oDb->getMediaInfoById((int)$iMediaId))) 
+            $sErrorMsg = _t('_sys_txt_error_occured');
+
+        if (empty($sErrorMsg) && !($aContentInfo = $this->_oDb->getContentInfoById($aMediaInfo['content_id'])))
+            $sErrorMsg = _t('_sys_txt_error_occured');
+
+        if (empty($sErrorMsg) && (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->checkAllowedView($aContentInfo))))
+            $sErrorMsg = $sMsg;
+
+        if (empty($sErrorMsg)) {
+            $aSiblings = array (
+                'next' => $this->_oTemplate->getNextPrevMedia($aMediaInfo, true, $mixedContext),
+                'prev' => $this->_oTemplate->getNextPrevMedia($aMediaInfo, false, $mixedContext),
+            );
+        }
+    
+        $a = $sErrorMsg ? array('error' => $sErrorMsg) : array('next' => $aSiblings['next'], 'prev' => $aSiblings['prev']);
+
+        $s = json_encode($a);
+
+        header('Content-type: text/html; charset=utf-8');
+        echo $s;
+    }
+
+    public function serviceGetSafeServices()
+    {
+        return array_merge(parent::serviceGetSafeServices(), [
+            'EntityAddFiles' => '',
+        ]);
+    }
+
+    /**
+     * Entry actions and social sharing block
+     */
+    public function serviceEntityAllActions ($mixedContent = false, $aParams = array())
+    {
+        if(!empty($mixedContent)) {
+            if(!is_array($mixedContent))
+               $mixedContent = array((int)$mixedContent, array());
+        }
+        else {
+            $mixedContent = $this->_getContent();
+            if($mixedContent === false)
+                return false;
+        }
+        
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        $aMedias = $this->_oDb->getMediaListByContentId($iContentId);
+        if(!empty($aMedias) && is_array($aMedias)) {
+            $aMedia = array_shift($aMedias);
+            if(!empty($aMedia['file_id']))
+                $aParams = array_merge(array(
+                    'entry_thumb' => $aMedia['file_id']
+                ), $aParams);
+        }
+
+        return parent::serviceEntityAllActions(array($iContentId, $aContentInfo), $aParams);
+    }
+
+    public function serviceMediaAllActions ($mixedContent = false, $aParams = [])
+    {
+        $iMediaId = 0;
+        $aMediaInfo = [];
+
+        $bContent = !empty($mixedContent);
+        if($bContent && is_array($mixedContent))
+            list($iMediaId, $aMediaInfo) = $mixedContent;
+        else {
+            if($bContent)
+                $iMediaId = (int)$mixedContent;
+            else
+                $iMediaId = bx_process_input(bx_get('id'), BX_DATA_INT);
+
+            if(!$iMediaId)
+                return false;
+
+            $aMediaInfo = $this->_oDb->getMediaInfoById($iMediaId);
+        }
+
+        if(!$iMediaId || !$aMediaInfo)
+            return false;
+
+        $CNF = &$this->_oConfig->CNF;
+
+        return parent::serviceEntityAllActions ([$iMediaId, $aMediaInfo], array_merge([
+            'object_menu' => $CNF['OBJECT_MENU_ACTIONS_VIEW_MEDIA'],
+            'object_transcoder' => $CNF['OBJECT_IMAGES_TRANSCODER_BIG'],
+            'entry_url' => bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aMediaInfo[$CNF['FIELD_MEDIA_CONTENT_ID']])),
+            'entry_title' => $aMediaInfo['title'],
+            'entry_thumb' => $aMediaInfo['file_id']
+        ], $aParams));
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_stories Stories
+     * @subsection bx_stories-forms Forms
+     * @subsubsection bx_stories-entity_add_files entity_add_files
+     * 
+     * @code bx_srv('bx_stories', 'entity_add_files', [...]); @endcode
+     * 
+     * Display form for adding media to the story.
+     * @param $iContentId story content id where media will be added, if it's not provided then it's determined from 'id' GET variable
+     * @return HTML string with form, all necessary CSS and JS files are automatically added to the HEAD section of the site HTML. On error false or empty string is returned.
+     * 
+     * @see BxStoriesModule::serviceEntityAddFiles
+     */
+    /** 
+     * @ref bx_stories-entity_add_files "entity_add_files"
+     */
+    public function serviceEntityAddFiles ($iContentId = 0)
+    {
+        return $this->_serviceEntityForm ('editDataForm', $iContentId, 'bx_stories_entry_add_media');
+    }
+
+    /**
+     * Delete file and story association, also file views, votes, comments, meta data are also deleted
+     * @param $iFileId file ID
+     * @return true on success of false on error
+     */ 
+    public function serviceDeleteFileAssociations($iFileId)
+    {        
+        $CNF = &$this->_oConfig->CNF;
+
+        if (!($aMediaInfo = $this->_oDb->getMediaInfoSimpleByFileId($iFileId))) // file is already deleted
+            return true; 
+    
+        if (!$this->_oDb->deassociateFileWithContent(0, $iFileId))
+            return false;
+
+        $aContentInfo = $this->_oDb->getContentInfoById($aMediaInfo['content_id']);
+        $iSender = isLogged() ? bx_get_logged_profile_id() : $aMediaInfo['author'];
+        $iAuthor = isset($aContentInfo[$CNF['FIELD_AUTHOR']]) ? $aContentInfo[$CNF['FIELD_AUTHOR']] : $aMediaInfo['author'];
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_stories-media_deleted 'bx_stories', 'media_deleted' - hook on new media deleted from story
+         * - $unit_name - equals `bx_stories`
+         * - $action - equals `media_deleted` 
+         * - $object_id - story_id
+         * - $sender_id - author's profile_id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `object_author_id` - [int] confirmation type can be none/phone/email/email_and_phone/email_or_phone
+         *      - `subobject_id` - [int] id for added media
+         *      - `media_id` - [int] id for added media
+         *      - `media_info` - [array] media info
+         * @hook @ref hook-bx_stories-media_deleted
+         */
+        bx_alert($this->getName(), 'media_deleted', $aMediaInfo['content_id'], $iSender, array(
+            'object_author_id' => $iAuthor,
+
+            'subobject_id' => $aMediaInfo['id'],
+
+            'media_id' => $aMediaInfo['id'], 
+            'media_info' => $aMediaInfo,
+        ));
+
+        bx_alert($this->getName() . '_media', 'deleted', $aMediaInfo['id'], $iSender, array(
+            'object_id' => $aMediaInfo['content_id'],
+            'object_author_id' => $iAuthor,
+
+            'media_info' => $aMediaInfo,
+        ));        
+
+        if (!empty($CNF['OBJECT_VIEWS_MEDIA'])) {
+            $o = BxDolView::getObjectInstance($CNF['OBJECT_VIEWS_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        if (!empty($CNF['OBJECT_VOTES_MEDIA'])) {
+            $o = BxDolVote::getObjectInstance($CNF['OBJECT_VOTES_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        if (!empty($CNF['OBJECT_SCORES_MEDIA'])) {
+            $o = BxDolScore::getObjectInstance($CNF['OBJECT_SCORES_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        if (!empty($CNF['OBJECT_COMMENTS_MEDIA'])) {
+            $o = BxDolCmts::getObjectInstance($CNF['OBJECT_COMMENTS_MEDIA'], $aMediaInfo['id']);
+            if ($o) $o->onObjectDelete();
+        }
+
+        BxDolPage::deleteSeoLink ($this->getName(), 'bx_stories_media', $aMediaInfo['id']);
+
+        return true;
+    }
+
+    public function checkAllowedSetThumb ($iContentId = 0)
+    {
+        return CHECK_ACTION_RESULT_NOT_ALLOWED;
+    }
+
+    public function serviceGetTimelineData()
+    {
+    	return [];
+    }
+
+    public function getMediaDuration($aMediaInfo) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(empty($aMediaInfo) || !is_array($aMediaInfo))
+            return 0;
+
+        $sField = 'duration';
+        if(!empty($aMediaInfo[$sField]))
+            return (int)$aMediaInfo[$sField];
+
+        $iMedia = $aMediaInfo['id'];
+        $sMedia = BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['mp4'])->getFileUrl($iMedia);
+        if(empty($sMedia))
+            return 0;
+
+        $iDuration = (int)BxDolTranscoderVideo::getDuration($sMedia);
+        if(!empty($iDuration))
+            $this->_oDb->updateMedia(array($sField => $iDuration), array('id' => $iMedia));
+
+        return $iDuration;
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/stories/classes/BxStoriesPageAuthor.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    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Profile's entries page.
+ */
+class BxStoriesPageAuthor extends BxBaseModTextPageAuthor
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+    }
+
+}
+
+/** @} */

+ 25 - 0
modules/boonex/stories/classes/BxStoriesPageBrowse.php

@@ -0,0 +1,25 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Browse entries pages.
+ */
+class BxStoriesPageBrowse extends BxBaseModTextPageBrowse
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_stories';
+
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 42 - 0
modules/boonex/stories/classes/BxStoriesPageEntry.php

@@ -0,0 +1,42 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Entry create/edit pages
+ */
+class BxStoriesPageEntry extends BxBaseModTextPageEntry
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_stories';
+
+        parent::__construct($aObject, $oTemplate);
+    }
+
+    public function getCode ()
+    {
+        return $this->_oTemplate->getJsCode('main') . parent::getCode();
+    }
+
+    protected function _getThumbForMetaObject ()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if (!($aMediaList = $this->_oModule->_oDb->getMediaListByContentId($this->_aContentInfo[$CNF['FIELD_ID']])))
+            return false;
+
+        $aMedia = array_shift($aMediaList);
+
+        return array('id' => $aMedia['file_id'], 'transcoder' => $CNF['OBJECT_TRANSCODER_COVER']);
+    }
+}
+
+/** @} */

+ 141 - 0
modules/boonex/stories/classes/BxStoriesSearchResult.php

@@ -0,0 +1,141 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxStoriesSearchResult extends BxBaseModTextSearchResult
+{
+    public function __construct($sMode = '', $aParams = [])
+    {
+        $this->aUnitViews = ['extended' => 'unit.html', 'gallery' => 'unit_gallery.html'];
+
+        if(empty($aParams['unit_view'])) {
+            if(!is_array($aParams))
+                $aParams = [];
+
+            $aParams['unit_view'] = 'extended';
+        }
+
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_stories',
+            'module_name' => 'bx_stories',
+            'object_metatags' => 'bx_stories',
+            'title' => _t('_bx_stories_page_title_browse'),
+            'table' => 'bx_stories_entries',
+            'ownFields' => array('id', 'title', 'text', 'thumb', 'author', 'added'),
+            'searchFields' => array(),
+            'restriction' => array(
+                'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+                'expired' => array('value' => time(), 'field' => 'expired', 'operator' => '>'),
+                'status' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+                'statusAdmin' => array('value' => 'active', 'field' => 'status_admin', 'operator' => '='),
+            ),
+            'paginate' => array('perPage' => getParam('bx_stories_per_page_browse'), 'start' => 0),
+            'sorting' => 'last',
+            'rss' => array(
+                'title' => '',
+                'link' => '',
+                'image' => '',
+                'profile' => 0,
+                'fields' => array (
+                    'Guid' => 'link',
+                    'Link' => 'link',
+                    'Title' => 'title',
+                    'DateTimeUTS' => 'added',
+                    'Desc' => 'text',
+            		'Image' => 'thumb'
+                ),
+            ),
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_stories_filter';
+        $this->oModule = $this->getMain();
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $sSearchFields = getParam($CNF['PARAM_SEARCHABLE_FIELDS']);
+        $this->aCurrent['searchFields'] = !empty($sSearchFields) ? explode(',', $sSearchFields) : '';
+
+        $oProfileAuthor = null;
+
+        switch ($sMode) {
+
+            case 'author':
+                $this->aCurrent['restriction']['expired'] = '';
+
+                if(!$this->_updateCurrentForAuthor($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+                
+            case 'context':
+                if(!$this->_updateCurrentForContext($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'public':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_stories_page_title_browse_recent');
+                $this->aCurrent['rss']['link'] = 'modules/?r=stories/rss/' . $sMode;
+                break;
+
+            case 'popular':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_POPULAR']);
+                $this->aCurrent['title'] = _t('_bx_stories_page_title_browse_popular');
+                $this->aCurrent['rss']['link'] = 'modules/?r=stories/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'popular';
+                break;
+
+            case 'top':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_TOP']);
+                $this->aCurrent['title'] = _t('_bx_stories_page_title_browse_top');
+                $this->aCurrent['rss']['link'] = 'modules/?r=stories/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'top';
+                break;
+
+            case 'updated':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_UPDATED']);
+                $this->aCurrent['title'] = _t('_bx_stories_page_title_browse_updated');
+                $this->aCurrent['rss']['link'] = 'modules/?r=stories/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'updated';
+                break;
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_stories');
+                unset($this->aCurrent['paginate']['perPage'], $this->aCurrent['rss']);
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+        }
+
+        $this->processReplaceableMarkers($oProfileAuthor);
+
+        $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+        $this->addCustomConditions($CNF, $oProfileAuthor, $sMode, $aParams);
+    }
+
+    function displayResultBlock ()
+    {
+        $s = parent::displayResultBlock ();
+        $s = '<div class="bx-stories-wrapper">' . $s . '</div>';
+        return $this->oModule->_oTemplate->getJsCode('main') . $s;
+    }
+
+    function getDesignBoxMenu ()
+    {
+        return BxBaseModGeneralSearchResult::getDesignBoxMenu ();
+    }
+}
+
+/** @} */

+ 157 - 0
modules/boonex/stories/classes/BxStoriesSearchResultMedia.php

@@ -0,0 +1,157 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxStoriesSearchResultMedia extends BxBaseModTextSearchResult
+{
+    protected $sOrderDirection = 'DESC';
+
+    function __construct($sMode = '', $aParams = array())
+    {
+        $this->sUnitTemplateLiveSearch = 'unit_media_live_search.html';
+
+        $aParams['unit_views'] = array('gallery' => 'unit_media.html', 'showcase' => 'unit_showcase.html');
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_stories_media',
+            'module_name' => 'bx_stories',
+            'object_metatags' => 'bx_stories_media',
+            'title' => _t('_bx_stories_media'),
+            'table' => 'bx_stories_entries_media',
+            'ownFields' => array('id', 'title', 'data', 'content_id', 'file_id', 'order'),
+            'searchFields' => array('title'),
+            'restriction_sql' => '',
+            'restriction' => array(
+                'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+                'story' => array('value' => '', 'field' => 'content_id', 'operator' => '='),
+                'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>'),
+                'status' => array('value' => 'active', 'field' => 'status', 'operator' => '=', 'table' => 'bx_stories_entries'),
+                'statusAdmin' => array('value' => 'active', 'field' => 'status_admin', 'operator' => '=', 'table' => 'bx_stories_entries'),
+            ),
+            'join' => array(
+                'stories' => array(
+                    'type' => 'INNER',
+                    'table' => 'bx_stories_entries',
+                    'mainField' => 'content_id',
+                    'onField' => 'id',
+                    'joinFields' => array(),
+                ),
+                'files' => array(
+                    'type' => 'INNER',
+                    'table' => 'bx_stories_files',
+                    'table_alias' => 'f',
+                    'mainField' => 'file_id',
+                    'onField' => 'id',
+                    'joinFields' => array('added'),
+                ),
+            ),
+            'paginate' => array('perPage' => getParam('bx_stories_per_page_browse'), 'start' => 0),
+            'sorting' => 'last',
+            'rss' => array(
+                'title' => '',
+                'link' => '',
+                'image' => '',
+                'profile' => 0,
+                'fields' => array (
+                    'Guid' => 'link',
+                    'Link' => 'link',
+                    'Title' => 'title',
+                    'DateTimeUTS' => 'added',
+                    'Desc' => 'title',
+                ),
+            ),
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_stories_filter';
+        $this->oModule = $this->getMain();
+
+        $oProfileAuthor = isset($aParams['author']) ? BxDolProfile::getInstance((int)$aParams['author']) : null;
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        switch ($sMode) {
+            case 'story':
+                $iAlbumId = (int)$aParams['story_id'];
+                $this->aCurrent['restriction']['story']['value'] = $iAlbumId;
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iAlbumId);
+                $this->aCurrent['title'] = _t('_bx_stories_page_title_browse_media_in_story');
+                $this->aCurrent['rss']['link'] = 'modules/?r=stories/rss_media/' . $sMode . '/' . $iAlbumId;
+                $this->aCurrent['sorting'] = 'order';
+                $this->sOrderDirection = 'ASC';
+                $this->setProcessPrivateContent(true);
+
+                if($CNF['PARAM_ORDER_BY_GHOSTS'])
+                    $this->_updateCurrentForOrderByGhosts();
+                break;
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                unset($this->aCurrent['paginate']['perPage'], $this->aCurrent['rss']);
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+        }
+
+        $this->sBrowseUrl = $this->_replaceMarkers($this->sBrowseUrl);
+        $this->aCurrent['title'] = $this->_replaceMarkers($this->aCurrent['title']); 
+
+        $this->removeContainerClass('bx-def-margin-bottom-neg');
+        $this->addContainerClass(array('bx-def-margin-sec-lefttopright-neg', 'bx-def-margin-sec-bottom-neg', 'bx-stories-medias-wrapper'));
+
+        $this->addCustomConditions($CNF, $oProfileAuthor, $sMode, $aParams);
+    }
+
+    function getAlterOrder()
+    {
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $sTable = $this->aCurrent['table'];
+        $sWay = $this->sOrderDirection;
+
+        $aSql = array();
+        switch ($this->aCurrent['sorting']) {
+            case 'order':
+                $aSql['order'] = " ORDER BY `" . $sTable . "`.`order` " . $sWay . ", `" . $sTable . "`.`id` " . $sWay . " ";
+                break;
+
+            case 'order_by_ghosts':
+                $aSql['order'] = " ORDER BY `g`.`order` " . $sWay . ", `" . $sTable . "`.`id` " . $sWay . " ";
+                break;
+
+            case 'last':
+                $aSql['order'] = " ORDER BY `f`.`added` " . $sWay . ", `" . $sTable . "`.`id` " . $sWay . " ";
+                break;
+        }
+
+        return $aSql;
+    }
+
+    protected function _updateCurrentForOrderByGhosts()
+    {
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $this->aCurrent['join']['ghosts'] = [
+            'type' => 'INNER',
+            'table' => 'sys_storage_ghosts',
+            'table_alias' => 'g',
+            'mainField' => 'file_id',
+            'on_sql' => $this->oModule->_oDb->prepareAsString(" `g`.`id`=`bx_stories_entries_media`.`file_id` AND `g`.`content_id`=`bx_stories_entries_media`.`content_id` AND `g`.`object`=? ", $CNF['OBJECT_STORAGE']),
+            'joinFields' => array('order'),
+        ];
+        $this->aCurrent['sorting'] = 'order_by_ghosts';
+        $this->sOrderDirection = 'ASC';
+    }
+}
+
+/** @} */

+ 331 - 0
modules/boonex/stories/classes/BxStoriesTemplate.php

@@ -0,0 +1,331 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/*
+ * Module representation.
+ */
+class BxStoriesTemplate extends BxBaseModTextTemplate
+{
+    /**
+     * Constructor
+     */
+    function __construct(&$oConfig, &$oDb)
+    {
+        $this->MODULE = 'bx_stories';
+
+        parent::__construct($oConfig, $oDb);
+
+        $this->addCss([BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'flickity/|flickity.css', 'main.css']);
+        $this->addJs(['flickity/flickity.pkgd.min.js', 'main.js']);
+    }
+
+    public function getJsCode($sType, $aParams = [], $bWrap = true)
+    {
+        $aParams = array_merge([
+            'aHtmlIds' => $this->_oConfig->getHtmlIds(),
+            'iDuration' => $this->_oConfig->getDuration()
+        ], $aParams);
+
+        return parent::getJsCode($sType, $aParams, $bWrap);
+    }
+
+    public function unit($aData, $isCheckPrivateContent = true, $sTemplateName = 'unit.html', $aParams = [])
+    {
+        if(in_array($sTemplateName, ['unit_media.html', 'unit_media_gallery.html', 'unit_media_live_search.html']))
+            return $this->unitMedia($aData, $isCheckPrivateContent, $sTemplateName, $aParams);
+
+        if(!empty($aParams['template_name']))
+            $sTemplateName = $aParams['template_name'];
+        else 
+            $aParams['template_name'] = $sTemplateName;
+
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        if($s = $this->checkPrivacy ($aData, $isCheckPrivateContent, $oModule))
+            return $s;
+
+        $CNF = &$this->_oConfig->CNF;
+        $sJsObject = $this->_oConfig->getJsObject('main');
+
+        $iId = (int)$aData[$CNF['FIELD_ID']];
+
+        // get entry url        
+        $sUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $iId));
+
+        $oProfile = BxDolProfile::getInstance($aData[$CNF['FIELD_AUTHOR']]);
+        if (!$oProfile) 
+            $oProfile = BxDolProfileUndefined::getInstance();
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        $oTranscoder = BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_TRANSCODER_BROWSE']);
+        $oTranscoderPoster = $CNF['OBJECT_VIDEOS_TRANSCODERS'] ? BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['poster']) : false;
+
+        $aBrowseUnits = array ();
+        $aMediaList = $oModule->_oDb->getMediaListByContentId($iId, getParam($CNF['PARAM_CARD_MEDIA_NUM']));
+        foreach ($aMediaList as $k => $a) {
+            $aFileInfo = $oStorage->getFile($a['file_id']);
+
+            $bVideo = $oTranscoderPoster && strncmp('video/', $aFileInfo['mime_type'], 6) === 0 && $oTranscoderPoster->isMimeTypeSupported($aFileInfo['mime_type']);            
+            $iVideoDuration = $bVideo ? $oModule->getMediaDuration($aFileInfo) : 0;
+
+            $aBrowseUnits[] = array (
+                'img_url' => $oTranscoder->getFileUrl($a['file_id']),
+                'url' => $sUrl,
+                'title_attr' => bx_html_attribute($a['title']),
+                'bx_if:show_play' => array(
+                    'condition' => $bVideo,
+                    'content' => array()
+                ),
+                'bx_if:show_duration' => array(
+                    'condition' => $iVideoDuration > 0,
+                    'content' => array(
+                        'duration' => _t_format_duration($iVideoDuration)
+                    )
+                )
+            );
+        }
+
+        // get summary
+        $sLinkMore = ' <a title="' . bx_html_attribute(_t('_sys_read_more', $aData[$CNF['FIELD_TITLE']])) . '" href="' . $sUrl . '"><i class="sys-icon ellipsis-h"></i></a>';
+        $sSummary = strmaxtextlen($aData[$CNF['FIELD_TEXT']], (int)getParam($CNF['PARAM_CHARS_SUMMARY']), $sLinkMore);
+        $sSummaryPlain = BxTemplFunctions::getInstance()->getStringWithLimitedLength(strip_tags($sSummary), (int)getParam($CNF['PARAM_CHARS_SUMMARY_PLAIN']));
+
+        $aTmplVarsMeta = [];
+        if(!empty($CNF['OBJECT_MENU_SNIPPET_META']) && ($oMenuMeta = BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SNIPPET_META'], $this)) !== false) {
+            $oMenuMeta->setContentId($iId);
+            $aTmplVarsMeta = [
+                'meta' => $oMenuMeta->getCode()
+            ];
+        }
+
+        $aVars = [
+            'class' => $this->_getUnitClass($aData,(isset($aParams['template_name']) ? $aParams['template_name'] : '')),
+            'html_id' => $this->_getUnitHtmlId($aData,(isset($aParams['template_name']) ? $aParams['template_name'] : '')),
+            'id' => $iId,
+            'content_url' => $sUrl,
+            'title' => bx_process_output($aData[$CNF['FIELD_TITLE']]),
+            'summary' => $sSummary,
+            'author' => $oProfile->getDisplayName(),
+            'author_url' => $oProfile->getUrl(),
+            'entry_posting_date' => bx_time_js($aData[$CNF['FIELD_ADDED']], BX_FORMAT_DATE),
+            'module_name' => _t($CNF['T']['txt_sample_single']),
+            'ts' => $aData[$CNF['FIELD_ADDED']],
+            'bx_if:meta' => [
+                'condition' => !empty($aTmplVarsMeta),
+                'content' => $aTmplVarsMeta
+            ],
+            'bx_repeat:browse' => $aBrowseUnits,
+            'bx_if:thumb' => [
+                'condition' => $aBrowseUnits,
+                'content' => [
+                    'title' => bx_process_output($aData[$CNF['FIELD_TITLE']]),
+                    'summary_attr' => bx_html_attribute($sSummaryPlain),
+                    'content_url' => $sUrl,
+                    'bx_if:show_thumb_onclick' => [
+                        'condition' => true,
+                        'content' => [
+                            'content_onclick' => 'return ' . $sJsObject . '.play(this, ' . $iId . ');',
+                        ]
+                    ],
+                    'thumb_url' => $aBrowseUnits ? $aBrowseUnits[0]['img_url'] : '',
+                    'gallery_url' => $aBrowseUnits ? $aBrowseUnits[0]['img_url'] : '',
+                    'image_settings' => '',
+                ],
+            ],
+            'bx_if:no_thumb' => [
+                'condition' => !$aBrowseUnits,
+                'content' => [
+                    'content_url' => $sUrl,
+                    'summary_plain' => '',
+                    'strecher' => '',
+                ],
+            ],
+        ];
+
+        return $this->parseHtmlByName($sTemplateName, $aVars);
+    }
+
+    function unitMedia ($aData, $isCheckPrivateContent = true, $sTemplateName = 'unit.html', $aParams = array())
+    {
+        $oModule = BxDolModule::getInstance($this->MODULE);
+        $CNF = &$oModule->_oConfig->CNF;
+
+        if(!($aMediaInfo = $oModule->_oDb->getMediaInfoById($aData['id'])))
+            return '';
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        if(!($aFile = $oStorage->getFile($aMediaInfo['file_id'])))
+            return '';
+
+        $aTmplVars = $this->mediaVars($aMediaInfo, $CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW'], $CNF['OBJECT_VIDEOS_TRANSCODERS']['poster_preview'], $aParams);
+
+        return $this->parseHtmlByName($sTemplateName, array_merge($aTmplVars, [
+            'class' => $this->_getUnitClass($aData, $sTemplateName),
+            'module_name' => _t($CNF['T']['txt_media_single']),
+            'content_url' => $aTmplVars['url'],
+            'ts' => $aFile['added'],
+            'actions' => $oModule->serviceMediaAllActions([$aData['id'], $aMediaInfo]),
+        ]));
+    }
+
+    public function entryText ($aData, $sTemplateName = 'entry-text.html')
+    {
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        $aVars = $this->getTmplVarsText($aData);
+        if(empty($aVars[$CNF['FIELD_TITLE']]) && empty($aVars[$CNF['FIELD_TEXT']]))
+            return false;
+
+        return $this->parseHtmlByName($sTemplateName, $aVars);
+    }
+
+    public function entryAttachments ($aData, $aParams = [])
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return $this->getModule()->_serviceBrowse ('story', ['unit_view' => 'gallery', 'story_id' => $aData[$CNF['FIELD_ID']], 'author' => $aData[$CNF['FIELD_AUTHOR']]], BX_DB_PADDING_DEF, true, true, 'SearchResultMedia');
+    }
+    
+    public function entryPlay($aData)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $oModule = BxDolModule::getInstance($this->MODULE);
+
+        $iId = (int)$aData[$CNF['FIELD_ID']];
+        $aMediaList = $oModule->_oDb->getMediaListByContentId($iId);
+
+        $aTmplsVarsMedia = [];
+        foreach($aMediaList as $aMedia) {
+            $aMediaVars = $this->mediaVars($aMedia, $CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW'], $CNF['OBJECT_VIDEOS_TRANSCODERS']['poster_preview'], ['muted' => true]);
+            if(!$aMediaVars)
+                continue;
+
+            $aTmplsVarsMedia[] = array_merge($aMediaVars, [
+                'bx_if:title' => [
+                    'condition' => !empty($aMedia['title']),
+                    'content' => [
+                        'title' => $aMedia['title']
+                    ]
+                ]
+            ]);
+        }
+
+        return BxTemplStudioFunctions::getInstance()->transBox($this->_oConfig->getHtmlIds('play_popup'), $this->parseHtmlByName('play.html', [
+            'width' => floor(100/count($aMediaList)),
+            'bx_repeat:media' => $aTmplsVarsMedia
+        ]));
+    }
+
+    protected function mediaVars ($aMediaInfo, $sImageTranscoder = false, $sVideoPosterTranscoder = false, $aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . $aMediaInfo[$CNF['FIELD_MEDIA_CONTENT_ID']]));
+
+        $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+        $oTranscoder = BxDolTranscoderImage::getObjectInstance($sImageTranscoder);
+        $aTranscodersVideo = false;
+
+        if ($CNF['OBJECT_VIDEOS_TRANSCODERS'])
+            $aTranscodersVideo = array (
+                'poster' => BxDolTranscoderImage::getObjectInstance($sVideoPosterTranscoder),
+                'mp4' => BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['mp4']),
+                'mp4_hd' => BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_VIDEOS_TRANSCODERS']['mp4_hd']),
+            );
+        
+        $aFileInfo = $oStorage->getFile ($aMediaInfo['file_id']);
+        if(!$aFileInfo)
+            return false;
+
+        $isImage = 0 === strncmp('image/', $aFileInfo['mime_type'], 6) && $oTranscoder->isMimeTypeSupported($aFileInfo['mime_type']); // preview for images, transcoder object for preview must be defined
+        $isVideo = $aTranscodersVideo && (0 === strncmp('video/', $aFileInfo['mime_type'], 6)) && $aTranscodersVideo['poster']->isMimeTypeSupported($aFileInfo['mime_type']); // preview for videos, transcoder object for video must be defined
+
+        $sMediaTitle = $this->getMediaTitle($aMediaInfo);
+        $sMediaTitleAttr = bx_html_attribute($sMediaTitle);
+        $mixedContext = isset($aParams['context']) ? $aParams['context'] : '';
+
+        $aTmplVarsImage = array();
+        if($isImage) {
+            $aSize = $aMediaInfo['data'] ? explode('x', $aMediaInfo['data']) : array(0, 0);
+
+            $aTmplVarsImage = array (
+                'title_attr' => $sMediaTitleAttr,
+                'title' => $sMediaTitle,
+                'url' => $sUrl,
+                'url_img' => $oTranscoder ? $oTranscoder->getFileUrl($aFileInfo['id']) : $oStorage->getFileUrlById($aFileInfo['id']),
+                'media_id' => $aMediaInfo['id'],
+                'w' => $aSize[0],
+                'h' => $aSize[1],
+                'context' => $mixedContext,
+            );
+        }
+
+        $oModule = BxDolModule::getInstance($this->MODULE);
+
+        $aTmplVarsVideo = array();
+        if($isVideo) {
+            $mixedAttrs = [];
+            if(!empty($aParams['autoplay']))
+                $mixedAttrs['autoplay'] = 'autoplay';
+            if(!empty($aParams['muted']))
+                $mixedAttrs['muted'] = 'muted';
+
+            $iVideoDuration = $oModule->getMediaDuration($aFileInfo);
+            $sVideoDuration = _t_format_duration($iVideoDuration);
+
+            $sVideoUrl = $oStorage->getFileUrlById($aMediaInfo['file_id']);
+            $aVideoFile = $oStorage->getFile($aMediaInfo['file_id']);
+
+            $sVideoUrlHd = '';
+            if (!empty($aVideoFile['dimensions']) && $aTranscodersVideo['mp4_hd']->isProcessHD($aVideoFile['dimensions']))
+                $sVideoUrlHd = $aTranscodersVideo['mp4_hd']->getFileUrl($aMediaInfo['file_id']);
+
+            $aTmplVarsVideo = array (
+                'title_attr' => $sMediaTitleAttr,
+                'title' => $sMediaTitle,
+                'url' => bx_append_url_params($sUrl, array('autoplay' => 1)),
+                'url_img' => $isVideo ? $aTranscodersVideo['poster']->getFileUrl($aMediaInfo['file_id']) : '',
+                'video' => $isVideo && $aTranscodersVideo ? BxTemplFunctions::getInstance()->videoPlayer(
+                    $aTranscodersVideo['poster']->getFileUrl($aMediaInfo['file_id']), 
+                    $aTranscodersVideo['mp4']->getFileUrl($aMediaInfo['file_id']), 
+                    $sVideoUrlHd, $mixedAttrs, 'max-height:' . $CNF['OBJECT_VIDEO_TRANSCODER_HEIGHT']
+                ) : '',
+                'duration' => $sVideoDuration,
+                'bx_if:show_duration' => array(
+                    'condition' => $iVideoDuration > 0,
+                    'content' => array(
+                        'duration' => $sVideoDuration
+                    )
+                )
+            );
+        }
+
+        return array(
+            'bx_if:image' => array (
+                'condition' => $isImage,
+                'content' => $aTmplVarsImage,
+            ),
+            'bx_if:video' => array (
+                'condition' => $isVideo,
+                'content' => $aTmplVarsVideo,
+            ),
+            'title_attr' => $sMediaTitleAttr,
+            'title' => $sMediaTitle,
+            'url' => $sUrl,
+        );
+    }
+
+    function getMediaTitle ($aMediaInfo)
+    {
+        return !empty($aMediaInfo['title']) ? bx_process_output($aMediaInfo['title']) : _t('_bx_stories_txt_media_title_empty');
+    }
+}
+
+/** @} */

+ 39 - 0
modules/boonex/stories/classes/BxStoriesUploaderCrop.php

@@ -0,0 +1,39 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxStoriesUploaderCrop extends BxTemplUploaderCrop
+{
+    protected $_oModule;
+
+    public function __construct ($aObject, $sStorageObject, $sUniqId, $oTemplate)
+    {
+        parent::__construct($aObject, $sStorageObject, $sUniqId, $oTemplate);
+
+        $this->_oModule = BxDolModule::getInstance('bx_stories');
+    }
+
+    protected function getGhostTemplateVars($aFile, $iProfileId, $iContentId, $oStorage, $oImagesTranscoder)
+    {
+        $sTitle = $this->_oModule->_oDb->getFileTitle($aFile['id']);
+        $a = array(
+            'file_title' => $sTitle ? $sTitle : ''
+        );
+        $a['file_title_attr'] = bx_html_attribute($a['file_title']);
+        return $a;
+    }
+
+    protected function isAdmin ($iContentId = 0)
+    {
+        return $this->_oModule->_isModerator (false);
+    }
+}
+
+/** @} */

+ 39 - 0
modules/boonex/stories/classes/BxStoriesUploaderHTML5.php

@@ -0,0 +1,39 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxStoriesUploaderHTML5 extends BxTemplUploaderHTML5
+{
+    protected $_oModule;
+
+    public function __construct ($aObject, $sStorageObject, $sUniqId, $oTemplate)
+    {
+        parent::__construct($aObject, $sStorageObject, $sUniqId, $oTemplate);
+
+        $this->_oModule = BxDolModule::getInstance('bx_stories');
+    }
+
+    protected function getGhostTemplateVars($aFile, $iProfileId, $iContentId, $oStorage, $oImagesTranscoder)
+    {
+        $sTitle = $this->_oModule->_oDb->getFileTitle($aFile['id']);
+        $a = array(
+            'file_title' => $sTitle ? $sTitle : ''
+        );
+        $a['file_title_attr'] = bx_html_attribute($a['file_title']);
+        return $a;
+    }
+
+    protected function isAdmin ($iContentId = 0)
+    {
+        return $this->_oModule->_isModerator (false);
+    }
+}
+
+/** @} */

+ 38 - 0
modules/boonex/stories/classes/BxStoriesUploaderRecordVideo.php

@@ -0,0 +1,38 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxStoriesUploaderRecordVideo extends BxTemplUploaderRecordVideo
+{
+    protected $_oModule;
+
+    public function __construct ($aObject, $sStorageObject, $sUniqId, $oTemplate)
+    {
+        parent::__construct($aObject, $sStorageObject, $sUniqId, $oTemplate);
+        $this->_oModule = BxDolModule::getInstance('bx_stories');
+    }
+
+    protected function getGhostTemplateVars($aFile, $iProfileId, $iContentId, $oStorage, $oImagesTranscoder)
+    {
+        $sTitle = $this->_oModule->_oDb->getFileTitle($aFile['id']);
+        $a = array(
+            'file_title' => $sTitle ? $sTitle : ''
+        );
+        $a['file_title_attr'] = bx_html_attribute($a['file_title']);
+        return $a;
+    }
+
+    protected function isAdmin ($iContentId = 0)
+    {
+        return $this->_oModule->_isModerator (false);
+    }
+}
+
+/** @} */

+ 140 - 0
modules/boonex/stories/install/config.php

@@ -0,0 +1,140 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_stories',
+    'title' => 'Stories',
+    'note' => 'Photo & video stories',
+    'version' => '14.0.0.DEV',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '14.0.x'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/stories/',
+    'home_uri' => 'stories',
+
+    'db_prefix' => 'bx_stories_',
+    'class_prefix' => 'BxStories',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Stories',
+
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry',
+    ),
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu',
+        'trigger_group_view_submenu',
+    ),
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_stories_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+        'bx_stories_preview',
+        'bx_stories_browse',
+        'bx_stories_big',
+        'bx_stories_video_poster_browse',
+        'bx_stories_video_poster_preview',
+        'bx_stories_video_poster_big',
+        'bx_stories_video_mp4',
+        'bx_stories_video_mp4_hd',
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_stories',
+    	'bx_stories_cmts',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+        'process_menu_triggers' => 1,
+        'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 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(),
+
+    /**
+     * Connections Section
+     */
+    'relations' => array(
+        'bx_notifications'
+    ),
+
+);
+
+/** @} */

+ 20 - 0
modules/boonex/stories/install/installer.php

@@ -0,0 +1,20 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxStoriesInstaller extends BxBaseModTextInstaller
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}
+
+/** @} */

+ 252 - 0
modules/boonex/stories/install/langs/en.xml

@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_stories"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_cmts"><![CDATA[Stories' Comments]]></string>
+    <string name="_bx_stories_reactions"><![CDATA[Stories' Reactions]]></string>
+    <string name="_bx_stories_media"><![CDATA[Media]]></string>
+
+    <string name="_bx_stories_option_enable_auto_approve"><![CDATA[Auto approve an story after creation]]></string>
+    <string name="_bx_stories_option_summary_chars"><![CDATA[Number of characters in auto-cropped story summary]]></string>
+    <string name="_bx_stories_option_plain_summary_chars"><![CDATA[Number of characters in plain story description when story hasn't thumb]]></string>
+    <string name="_bx_stories_option_card_media_num"><![CDATA[Number of media items in story card]]></string>
+    <string name="_bx_stories_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_stories_option_per_page_profile"><![CDATA[Number of items on profile page]]></string>
+    <string name="_bx_stories_option_rss_num"><![CDATA[Number of items in RSS feed]]></string>
+    <string name="_bx_stories_option_searchable_fields"><![CDATA[Searchable fields for keyword search]]></string>
+    <string name="_bx_stories_option_expiration_period"><![CDATA[Story expiration period (in hours)]]></string>
+    <string name="_bx_stories_option_duration"><![CDATA[Period of time while story is visible (in seconds)]]></string>
+
+    <string name="_bx_stories_form_entry"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_form_entry_display_add"><![CDATA[Add Story]]></string>
+    <string name="_bx_stories_form_entry_display_edit"><![CDATA[Edit Story]]></string>
+    <string name="_bx_stories_form_entry_display_delete"><![CDATA[Delete Story]]></string>
+    <string name="_bx_stories_form_entry_display_view"><![CDATA[View Story]]></string>
+    <string name="_bx_stories_form_entry_input_author"><![CDATA[Author]]></string>
+    <string name="_bx_stories_form_entry_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_stories_form_entry_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_stories_form_entry_input_sys_title"><![CDATA[Caption]]></string>
+    <string name="_bx_stories_form_entry_input_title"><![CDATA[Caption]]></string>
+    <string name="_bx_stories_form_entry_input_title_err"><![CDATA[Caption is essential. Please, fill in this field]]></string>
+    <string name="_bx_stories_form_entry_input_sys_text"><![CDATA[Story Description]]></string>
+    <string name="_bx_stories_form_entry_input_text"><![CDATA[Story Description]]></string>
+    <string name="_bx_stories_form_entry_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+    <string name="_bx_stories_form_entry_input_delete_confirm"><![CDATA[I am sure I want to delete this story]]></string>
+    <string name="_bx_stories_form_entry_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+    <string name="_bx_stories_form_entry_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the story]]></string>
+    <string name="_bx_stories_form_entry_input_sys_pictures"><![CDATA[Content]]></string>
+    <string name="_bx_stories_form_entry_input_pictures"><![CDATA[Content]]></string>
+    <string name="_bx_stories_form_entry_input_pictures_err"><![CDATA[Content is essential. Please, select at least one photo or video.]]></string>
+    <string name="_bx_stories_form_entry_input_sys_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_stories_form_entry_input_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_stories_form_entry_file_title"><![CDATA[Caption]]></string>
+    <string name="_bx_stories_form_entry_input_sys_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_stories_form_entry_input_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_stories_form_entry_input_sys_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_stories_form_entry_input_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_stories_form_entry_input_sys_date_expired"><![CDATA[Expires]]></string>
+    <string name="_bx_stories_form_entry_input_date_expired"><![CDATA[Expires]]></string>
+
+    <string name="_bx_stories_form_media"><![CDATA[Medias]]></string>
+    <string name="_bx_stories_form_media_display_edit"><![CDATA[Edit Media]]></string>
+    <string name="_bx_stories_form_media_input_sys_title"><![CDATA[Caption]]></string>
+    <string name="_bx_stories_form_media_input_title"><![CDATA[Caption]]></string>
+    <string name="_bx_stories_form_media_input_sys_content_id"><![CDATA[Story]]></string>
+    <string name="_bx_stories_form_media_input_content_id"><![CDATA[Story]]></string>
+    <string name="_bx_stories_form_media_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_stories_form_media_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_stories_form_media_input_sys_do_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_stories_form_media_input_do_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_stories_acl_action_create_entry"><![CDATA[Create Story]]></string>
+    <string name="_bx_stories_acl_action_delete_entry"><![CDATA[Delete Story]]></string>
+    <string name="_bx_stories_acl_action_view_entry"><![CDATA[View Story]]></string>
+    <string name="_bx_stories_acl_action_edit_any_entry"><![CDATA[Edit Any Story]]></string>
+    <string name="_bx_stories_acl_action_delete_any_entry"><![CDATA[Delete Any Story]]></string>
+
+    <string name="_bx_stories_page_title_sys_create_entry"><![CDATA[New Story]]></string>
+    <string name="_bx_stories_page_title_create_entry"><![CDATA[New Story]]></string>
+    <string name="_bx_stories_page_block_title_create_entry"><![CDATA[New Story]]></string>
+    <string name="_bx_stories_page_title_sys_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_stories_page_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_stories_page_title_sys_add_media"><![CDATA[Add/Edit Media]]></string>
+    <string name="_bx_stories_page_title_add_media"><![CDATA[Add/Edit Media]]></string>
+    <string name="_bx_stories_page_block_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_stories_page_block_title_add_media"><![CDATA[Add/Edit Media]]></string>
+    <string name="_bx_stories_page_title_sys_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_stories_page_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_stories_page_block_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_stories_page_title_sys_view_entry"><![CDATA[View Story]]></string>
+    <string name="_bx_stories_page_title_view_entry"><![CDATA[{title}]]></string>
+    <string name="_bx_stories_page_title_sys_view_media"><![CDATA[View Image]]></string>
+    <string name="_bx_stories_page_title_view_media"><![CDATA[{title}]]></string>
+    <string name="_bx_stories_page_block_title_entry_view_media"><![CDATA[View Image]]></string>
+    <string name="_bx_stories_page_block_title_entry_view_media_exif"><![CDATA[EXIF]]></string>
+    <string name="_bx_stories_page_block_title_entry_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_stories_page_block_title_entry_text"><![CDATA[Story Description]]></string>
+    <string name="_bx_stories_page_title_browse"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_page_title_search_results"><![CDATA[Stories matching "{0}"]]></string>
+    <string name="_bx_stories_page_title_browse_by_author"><![CDATA[{display_name}'s Stories]]></string>
+    <string name="_bx_stories_page_title_browse_by_context"><![CDATA[Stories in {display_name}]]></string>
+    <string name="_bx_stories_page_title_browse_recent"><![CDATA[Latest Stories]]></string>
+    <string name="_bx_stories_page_title_browse_popular"><![CDATA[Popular Stories]]></string>
+    <string name="_bx_stories_page_title_browse_top"><![CDATA[Top Stories]]></string>
+    <string name="_bx_stories_page_title_browse_media_in_story"><![CDATA[Media]]></string>
+    <string name="_bx_stories_page_title_browse_updated"><![CDATA[Updated Stories]]></string>
+    <string name="_bx_stories_page_title_sys_home"><![CDATA[Stories Home]]></string>
+    <string name="_bx_stories_page_title_home"><![CDATA[Stories]]></string>
+    
+    <string name="_bx_stories_page_block_title_sys_recent_entries_view_showcase"><![CDATA[Latest Stories (Showcase View)]]></string>
+    <string name="_bx_stories_page_block_title_sys_recent_entries_view_gallery"><![CDATA[Latest Stories (Gallery View)]]></string>
+    <string name="_bx_stories_page_block_title_recent_entries"><![CDATA[Latest Stories]]></string>
+    <string name="_bx_stories_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_stories_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+    <string name="_bx_stories_page_block_title_entry_author"><![CDATA[Author]]></string>
+    <string name="_bx_stories_page_block_title_entry_info"><![CDATA[Info]]></string>
+    <string name="_bx_stories_page_block_title_entry_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_stories_page_block_title_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_stories_page_block_title_entry_reports"><![CDATA[Reports]]></string>
+    <string name="_bx_stories_page_block_title_entry_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_stories_page_block_title_entry_location"><![CDATA[Location]]></string>
+    <string name="_bx_stories_page_title_sys_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_stories_page_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_stories_page_block_title_popular_entries"><![CDATA[Popular]]></string>
+    <string name="_bx_stories_page_title_sys_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_stories_page_title_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_stories_page_block_title_top_entries"><![CDATA[Top]]></string>
+    <string name="_bx_stories_page_block_title_updated_entries"><![CDATA[Updated Stories]]></string>
+    <string name="_bx_stories_page_title_sys_view_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_stories_page_title_view_entry_comments"><![CDATA[Comments to {title}]]></string>
+    <string name="_bx_stories_page_title_sys_entries_of_author"><![CDATA[Stories of author]]></string>
+    <string name="_bx_stories_page_title_entries_of_author"><![CDATA[{display_name}'s stories]]></string>
+    <string name="_bx_stories_page_title_sys_entries_in_context"><![CDATA[Stories in context]]></string>
+    <string name="_bx_stories_page_title_entries_in_context"><![CDATA[Stories in {display_name}]]></string>
+    <string name="_bx_stories_page_block_title_entries_of_author"><![CDATA[Stories by <a href="{profile_link}">{display_name}</a>]]></string>   
+    <string name="_bx_stories_page_block_title_sys_entries_of_author"><![CDATA[Stories of author]]></string>
+    <string name="_bx_stories_page_block_title_entries_in_context"><![CDATA[Stories in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_stories_page_block_title_sys_entries_in_context"><![CDATA[Stories in context]]></string>
+    <string name="_bx_stories_page_block_title_entries_actions"><![CDATA[Stories actions]]></string>
+    <string name="_bx_stories_page_block_title_browse_cmts"><![CDATA[Stories' Comments]]></string>
+    <string name="_bx_stories_page_title_sys_manage"><![CDATA[Manage Own Stories]]></string>
+    <string name="_bx_stories_page_title_sys_manage_administration"><![CDATA[Manage All Stories]]></string>
+    <string name="_bx_stories_page_title_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_stories_page_block_title_system_manage"><![CDATA[Manage Own Stories]]></string>
+    <string name="_bx_stories_page_block_title_system_manage_administration"><![CDATA[Manage All Stories]]></string>  
+    <string name="_bx_stories_page_block_title_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_stories_page_block_title_popular_keywords_stories"><![CDATA[Popular Stories Hashtags]]></string>
+    <string name="_bx_stories_page_block_title_sys_my_entries"><![CDATA[User Stories]]></string>
+    <string name="_bx_stories_page_block_title_my_entries"><![CDATA[{display_name} Stories]]></string>
+    <string name="_bx_stories_page_title_sys_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_stories_page_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_stories_page_block_title_search_form"><![CDATA[Search Form]]></string>
+    <string name="_bx_stories_page_block_title_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_stories_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+    <string name="_bx_stories_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+    <string name="_bx_stories_page_block_title_sys_entry_context"><![CDATA[Posted in]]></string>
+    <string name="_bx_stories_page_block_title_entry_context"><![CDATA[Posted in]]></string>
+
+    <string name="_bx_stories_menu_set_title_view_entry"><![CDATA[Story Actions]]></string>
+    <string name="_bx_stories_menu_title_view_entry"><![CDATA[Story Actions]]></string>
+    <string name="_bx_stories_menu_title_submenu"><![CDATA[Stories Submenu]]></string>
+    <string name="_bx_stories_menu_set_title_submenu"><![CDATA[Stories Submenu]]></string>
+    <string name="_bx_stories_menu_item_title_system_create_entry"><![CDATA[Story]]></string>
+    <string name="_bx_stories_menu_item_title_create_entry"><![CDATA[Story]]></string>
+    <string name="_bx_stories_menu_item_title_system_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_stories_menu_item_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_stories_menu_item_title_system_edit_story"><![CDATA[Edit Story]]></string>
+    <string name="_bx_stories_menu_item_title_edit_story"><![CDATA[Edit Story]]></string>
+    <string name="_bx_stories_menu_item_title_system_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_stories_menu_item_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_stories_menu_item_title_system_view_entry"><![CDATA[View Story]]></string>
+    <string name="_bx_stories_menu_item_title_system_entries_home"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_menu_item_title_entries_home"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_menu_item_title_system_entries_recent"><![CDATA[Latest]]></string>
+    <string name="_bx_stories_menu_item_title_entries_recent"><![CDATA[Latest]]></string>
+    <string name="_bx_stories_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_stories_menu_item_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_stories_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_stories_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_stories_menu_item_title_system_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_stories_menu_item_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_stories_menu_item_title_system_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_stories_menu_item_title_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_stories_menu_title_view_entry_submenu"><![CDATA[View Story Submenu]]></string>
+    <string name="_bx_stories_menu_set_title_view_entry_submenu"><![CDATA[View Story Submenu]]></string>
+    <string name="_bx_stories_menu_item_title_view_entry_submenu_entry"><![CDATA[Story]]></string>
+    <string name="_bx_stories_menu_item_title_view_entry_submenu_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_stories_menu_item_title_system_view_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_stories_menu_item_title_system_view_entries_author"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_menu_item_title_view_entries_author"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_menu_item_title_system_view_entries_in_context"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_menu_item_title_view_entries_in_context"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_menu_title_entries_my"><![CDATA[My Stories Action Menu]]></string>
+    <string name="_bx_stories_menu_set_title_entries_my"><![CDATA[My Stories Menu]]></string>
+    <string name="_bx_stories_menu_item_title_system_manage_my_stories"><![CDATA[My stories]]></string>
+    <string name="_bx_stories_menu_item_title_manage_my_stories"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_stories_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_stories_menu_item_title_system_admt_stories"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_menu_item_title_admt_stories"><![CDATA[Stories]]></string>
+    <string name="_bx_stories_menu_item_title_manage_my"><![CDATA[My Stories]]></string>
+    <string name="_bx_stories_menu_item_title_manage_all"><![CDATA[All Stories]]></string>
+    <string name="_bx_stories_menu_item_title_system_sm_items"><![CDATA[Items]]></string>
+    <string name="_bx_stories_menu_item_title_sm_items"><![CDATA[{0} items]]></string>
+    <string name="_bx_stories_menu_set_title_view_actions_media"><![CDATA[Media Actions]]></string>
+    <string name="_bx_stories_menu_title_view_actions_media"><![CDATA[Media Actions]]></string>
+    <string name="_bx_stories_menu_item_title_system_edit_image"><![CDATA[Edit Media]]></string>
+    <string name="_bx_stories_menu_item_title_edit_image"><![CDATA[Edit Media]]></string>
+    <string name="_bx_stories_menu_item_title_system_delete_image"><![CDATA[Delete Media]]></string>
+    <string name="_bx_stories_menu_item_title_delete_image"><![CDATA[Delete Media]]></string>
+
+    <string name="_bx_stories_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+    <string name="_bx_stories_grid_filter_item_title_adm_select_one_filter2"><![CDATA[Any Audience]]></string>
+    <string name="_bx_stories_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_stories_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+    <string name="_bx_stories_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_stories_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_stories_grid_column_title_adm_title"><![CDATA[Caption]]></string>
+    <string name="_bx_stories_grid_column_title_adm_added"><![CDATA[Added]]></string>
+    <string name="_bx_stories_grid_column_title_adm_author"><![CDATA[Author]]></string>
+    <string name="_bx_stories_grid_action_title_adm_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_stories_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_stories_grid_action_title_adm_clear_reports"><![CDATA[Сlear reports]]></string>
+    <string name="_bx_stories_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_stories_grid_action_title_adm_audit_content"><![CDATA[Audit actions]]></string>
+    <string name="_bx_stories_grid_column_title_adm_status_admin"><![CDATA[Moderation]]></string>
+    <string name="_bx_stories_grid_action_err_delete"><![CDATA[Cannot delete the selected story(s).]]></string>
+    <string name="_bx_stories_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_stories_chart_growth"><![CDATA[Stories: Growth]]></string>
+    <string name="_bx_stories_chart_growth_speed"><![CDATA[Stories: Growth Speed]]></string>
+
+    <string name="_bx_stories_search_extended"><![CDATA[Stories Search]]></string>
+    <string name="_bx_stories_search_extended_cmts"><![CDATA[Stories Comments Search]]></string>
+
+    <string name="_bx_stories_txt_all_entries_by"><![CDATA[{0} stories]]></string>
+    <string name="_bx_stories_txt_all_entries_in"><![CDATA[<a href="{0}">All Stories in {1} ({2})</a>]]></string>
+    <string name="_bx_stories_txt_sample_single"><![CDATA[story]]></string>
+    <string name="_bx_stories_txt_sample_single_with_article"><![CDATA[a story]]></string>
+    <string name="_bx_stories_txt_sample_comment_single"><![CDATA[comment to story]]></string>
+    <string name="_bx_stories_txt_sample_vote_single"><![CDATA[vote to story]]></string>
+    <string name="_bx_stories_txt_sample_reaction_single"><![CDATA['{0}' reaction to story]]></string>
+    <string name="_bx_stories_txt_sample_score_up_single"><![CDATA[score up vote to story]]></string>
+    <string name="_bx_stories_txt_sample_score_down_single"><![CDATA[score down vote to story]]></string>
+    <string name="_bx_stories_txt_sample_action_changed"><![CDATA[changed {0}]]></string>
+    <string name="_bx_stories_txt_media_single"><![CDATA[image]]></string>
+    <string name="_bx_stories_txt_media_comment_single"><![CDATA[image's comment]]></string>
+    <string name="_bx_stories_txt_media_vote_single"><![CDATA[image's vote]]></string>
+    <string name="_bx_stories_txt_media_score_up_single"><![CDATA[image's score up vote]]></string>
+    <string name="_bx_stories_txt_media_score_down_single"><![CDATA[image's score down vote]]></string>
+    <string name="_bx_stories_txt_media_title_alt"><![CDATA[{0}'s media]]></string>
+    <string name="_bx_stories_txt_media_title_empty"><![CDATA[No Title]]></string>
+    <string name="_bx_stories_txt_media_story_link"><![CDATA[<a href="{0}">{1}</a> story by <a href="{2}">{3}</a>]]></string>
+    <string name="_bx_stories_txt_processing_awaiting"><![CDATA[Scheduled for publishing as soon as video conversion is complete.]]></string>
+    <string name="_bx_stories_txt_processing_failed"><![CDATA[Story isn't published because video conversion failed, edit video to fix the issue.]]></string>
+
+    <string name="_bx_stories_txt_msg_status_hidden"><![CDATA[This story was hidden.]]></string>
+    <string name="_bx_stories_txt_msg_status_pending"><![CDATA[This story is pending approval.]]></string>
+    <string name="_bx_stories_txt_err_cannot_perform_action"><![CDATA[Cannot perform the action. Please report.]]></string>
+
+    <string name="_bx_stories_alert_action_medias_added"><![CDATA[add images]]></string>
+    <string name="_bx_stories_alert_action_medias_added_follow_member"><![CDATA[New media]]></string>
+    <string name="_bx_stories_alert_action_medias_added_follow_context"><![CDATA[New media]]></string>
+</resources>

+ 59 - 0
modules/boonex/stories/install/sql/disable.sql

@@ -0,0 +1,59 @@
+
+-- SETTINGS
+SET @iTypeId = (SELECT `ID` FROM `sys_options_types` WHERE `name` = 'bx_stories' 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;
+
+
+-- PAGES
+DELETE FROM `sys_objects_page` WHERE `module` = 'bx_stories';
+DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_stories' OR `object` IN('bx_stories_create_entry', 'bx_stories_add_media', 'bx_stories_edit_entry', 'bx_stories_delete_entry', 'bx_stories_view_entry', 'bx_stories_view_entry_comments', 'bx_stories_home', 'bx_stories_popular', 'bx_stories_top', 'bx_stories_updated', 'bx_stories_author', 'bx_stories_context', 'bx_stories_search', 'bx_stories_manage');
+
+
+-- MENU
+DELETE FROM `sys_objects_menu` WHERE `module` = 'bx_stories';
+DELETE FROM `sys_menu_sets` WHERE `module` = 'bx_stories';
+DELETE FROM `sys_menu_items` WHERE `module` = 'bx_stories' OR `set_name` IN('bx_stories_view', 'bx_stories_view_actions', 'bx_stories_view_actions_media', 'bx_stories_submenu', 'bx_stories_view_submenu', 'bx_stories_snippet_meta', 'bx_stories_menu_manage_tools', 'bx_stories_my');
+
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` WHERE `object` IN ('bx_stories_allow_view_to');
+
+
+-- 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_stories';
+DELETE FROM `sys_acl_actions` WHERE `Module` = 'bx_stories';
+
+
+-- SEARCH
+DELETE FROM `sys_objects_search` WHERE `ObjectName` IN ('bx_stories', 'bx_stories_cmts', 'bx_stories_media');
+
+
+-- METATAGS
+DELETE FROM `sys_objects_metatags` WHERE `object` IN ('bx_stories');
+
+
+-- STATS
+DELETE FROM `sys_statistics` WHERE `name` LIKE 'bx_stories%';
+
+
+-- CHARTS
+DELETE FROM `sys_objects_chart` WHERE `object` LIKE 'bx_stories%';
+
+
+-- GRIDS
+DELETE FROM `sys_objects_grid` WHERE `object` IN ('bx_stories_administration', 'bx_stories_common');
+DELETE FROM `sys_grid_fields` WHERE `object` IN ('bx_stories_administration', 'bx_stories_common');
+DELETE FROM `sys_grid_actions` WHERE `object` IN ('bx_stories_administration', 'bx_stories_common');
+
+
+-- UPLOADERS
+DELETE FROM `sys_objects_uploader` WHERE `object` IN('bx_stories_html5', 'bx_stories_crop', 'bx_stories_record_video');
+
+
+-- ALERTS
+SET @iHandler := (SELECT `id` FROM `sys_alerts_handlers` WHERE `name` = 'bx_stories' LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `handler_id` = @iHandler;
+DELETE FROM `sys_alerts_handlers` WHERE `id` = @iHandler;

+ 445 - 0
modules/boonex/stories/install/sql/enable.sql

@@ -0,0 +1,445 @@
+
+-- 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_stories', '_bx_stories', 'bx_stories@modules/boonex/stories/|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_stories', '_bx_stories', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_stories_enable_auto_approve', 'on', @iCategId, '_bx_stories_option_enable_auto_approve', 'checkbox', '', '', '', 0),
+('bx_stories_summary_chars', '700', @iCategId, '_bx_stories_option_summary_chars', 'digit', '', '', '', 10),
+('bx_stories_plain_summary_chars', '200', @iCategId, '_bx_stories_option_plain_summary_chars', 'digit', '', '', '', 12),
+('bx_stories_card_media_num', '10', @iCategId, '_bx_stories_option_card_media_num', 'digit', '', '', '', 16),
+('bx_stories_per_page_browse', '12', @iCategId, '_bx_stories_option_per_page_browse', 'digit', '', '', '', 20),
+('bx_stories_per_page_profile', '6', @iCategId, '_bx_stories_option_per_page_profile', 'digit', '', '', '', 22),
+('bx_stories_rss_num', '10', @iCategId, '_bx_stories_option_rss_num', 'digit', '', '', '', 30),
+('bx_stories_searchable_fields', '', @iCategId, '_bx_stories_option_searchable_fields', 'list', '', '', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:21:"get_searchable_fields";}', 40),
+('bx_stories_expiration_period', '48', @iCategId, '_bx_stories_option_expiration_period', 'digit', '', '', '', 50),
+('bx_stories_duration', '3', @iCategId, '_bx_stories_option_duration', 'digit', '', '', '', 52);
+
+-- PAGE: create entry
+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_stories_create_entry', '_bx_stories_page_title_sys_create_entry', '_bx_stories_page_title_create_entry', 'bx_stories', 5, 2147483647, 1, 'create-story', 'page.php?i=create-story', '', '', '', 0, 1, 0, 'BxStoriesPageBrowse', 'modules/boonex/stories/classes/BxStoriesPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_stories_create_entry', 1, 'bx_stories', '_bx_stories_page_block_title_create_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:13:"entity_create";}', 0, 1, 1);
+
+-- PAGE: add images
+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_stories_add_media', '_bx_stories_page_title_sys_add_media', '_bx_stories_page_title_add_media', 'bx_stories', 5, 2147483647, 1, 'story-add-media', '', '', '', '', 0, 1, 0, 'BxStoriesPageEntry', 'modules/boonex/stories/classes/BxStoriesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_stories_add_media', 1, 'bx_stories', '_bx_stories_page_block_title_add_media', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:16:"entity_add_files";}', 0, 0, 0);
+
+-- PAGE: edit entry
+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_stories_edit_entry', '_bx_stories_page_title_sys_edit_entry', '_bx_stories_page_title_edit_entry', 'bx_stories', 5, 2147483647, 1, 'edit-story', '', '', '', '', 0, 1, 0, 'BxStoriesPageEntry', 'modules/boonex/stories/classes/BxStoriesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_stories_edit_entry', 1, 'bx_stories', '_bx_stories_page_block_title_edit_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:11:"entity_edit";}', 0, 0, 0);
+
+-- PAGE: delete entry
+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_stories_delete_entry', '_bx_stories_page_title_sys_delete_entry', '_bx_stories_page_title_delete_entry', 'bx_stories', 5, 2147483647, 1, 'delete-story', '', '', '', '', 0, 1, 0, 'BxStoriesPageEntry', 'modules/boonex/stories/classes/BxStoriesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_stories_delete_entry', 1, 'bx_stories', '_bx_stories_page_block_title_delete_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:13:"entity_delete";}', 0, 0, 0);
+
+-- PAGE: view entry
+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_stories_view_entry', '_bx_stories_page_title_sys_view_entry', '_bx_stories_page_title_view_entry', 'bx_stories', 12, 2147483647, 1, 'view-story', '', '', '', '', 0, 1, 0, 'BxStoriesPageEntry', 'modules/boonex/stories/classes/BxStoriesPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_stories_view_entry', 2, 'bx_stories','' , '_bx_stories_page_block_title_entry_text', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:17:"entity_text_block";}', 0, 0, 1, 1),
+('bx_stories_view_entry', 2, 'bx_stories','' , '_bx_stories_page_block_title_entry_attachments', 0, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:18:"entity_attachments";}', 0, 0, 1, 3),
+('bx_stories_view_entry', 4, 'bx_stories','' , '_bx_stories_page_block_title_entry_social_sharing', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:21:"entity_social_sharing";}', 0, 0, 0, 0),
+('bx_stories_view_entry', 2, 'bx_stories','' , '_bx_stories_page_block_title_entry_comments', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:15:"entity_comments";}', 0, 0, 1, 4),
+('bx_stories_view_entry', 3, 'bx_stories','' , '_bx_stories_page_block_title_entry_location', 3, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:13:"locations_map";s:6:"params";a:2:{i:0;s:10:"bx_stories";i:1;s:4:"{id}";}s:5:"class";s:20:"TemplServiceMetatags";}', 0, 0, 1, 4),
+('bx_stories_view_entry', 3, 'bx_stories','' , '_bx_stories_page_block_title_entry_author', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:13:"entity_author";}', 0, 0, 1, 2),
+('bx_stories_view_entry', 3, 'bx_stories', '_bx_stories_page_block_title_sys_entry_context', '_bx_stories_page_block_title_entry_context', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:14:"entity_context";}', 0, 0, 1, 1),
+('bx_stories_view_entry', 3, 'bx_stories','' , '_bx_stories_page_block_title_entry_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:11:"entity_info";}', 0, 0, 1, 3),
+('bx_stories_view_entry', 3, 'bx_stories', '', '_bx_stories_page_block_title_entry_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:14:"entity_actions";}', 0, 0, 0, 0),
+('bx_stories_view_entry', 2, 'bx_stories','' , '_bx_stories_page_block_title_entry_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:18:"entity_all_actions";}', 0, 0, 1, 2),
+('bx_stories_view_entry', 2, 'bx_stories', '', '_bx_stories_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:14:"entity_reports";}', 0, 0, 1, 6);
+
+-- PAGE: view entry comments
+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_stories_view_entry_comments', '_bx_stories_page_title_sys_view_entry_comments', '_bx_stories_page_title_view_entry_comments', 'bx_stories', 5, 2147483647, 1, 'view-story-comments', '', '', '', '', 0, 1, 0, 'BxStoriesPageEntry', 'modules/boonex/stories/classes/BxStoriesPageEntry.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_stories_view_entry_comments', 1, 'bx_stories', '_bx_stories_page_block_title_entry_comments', '_bx_stories_page_block_title_entry_comments_link', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:15:"entity_comments";}', 0, 0, 1);
+
+-- PAGE: popular stories
+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_stories_popular', '_bx_stories_page_title_sys_entries_popular', '_bx_stories_page_title_entries_popular', 'bx_stories', 5, 2147483647, 1, 'stories-popular', 'page.php?i=stories-popular', '', '', '', 0, 1, 0, 'BxStoriesPageBrowse', 'modules/boonex/stories/classes/BxStoriesPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_stories_popular', 1, 'bx_stories', '_bx_stories_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_stories";s:6:"method";s:14:"browse_popular";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1);
+
+-- PAGE: top stories
+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_stories_top', '_bx_stories_page_title_sys_entries_top', '_bx_stories_page_title_entries_top', 'bx_stories', 5, 2147483647, 1, 'stories-top', 'page.php?i=stories-top', '', '', '', 0, 1, 0, 'BxStoriesPageBrowse', 'modules/boonex/stories/classes/BxStoriesPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_stories_top', 1, 'bx_stories', '_bx_stories_page_block_title_top_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_stories";s:6:"method";s:10:"browse_top";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1);
+
+-- PAGE: entries of author
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_author', 'stories-author', '_bx_stories_page_title_sys_entries_of_author', '_bx_stories_page_title_entries_of_author', 'bx_stories', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxStoriesPageAuthor', 'modules/boonex/stories/classes/BxStoriesPageAuthor.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_stories_author', 1, 'bx_stories', '', '_bx_stories_page_block_title_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:18:"my_entries_actions";}', 0, 0, 1, 1),
+('bx_stories_author', 1, 'bx_stories', '_bx_stories_page_block_title_sys_entries_of_author', '_bx_stories_page_block_title_entries_of_author', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:13:"browse_author";}', 0, 0, 1, 2),
+('bx_stories_author', 1, 'bx_stories', '_bx_stories_page_block_title_sys_entries_in_context', '_bx_stories_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_stories";s:6:"method";s:14:"browse_context";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";i:0;a:1:{s:13:"empty_message";b:0;}}}', 0, 0, 1, 3);
+
+-- PAGE: entries in context
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_context', 'stories-context', '_bx_stories_page_title_sys_entries_in_context', '_bx_stories_page_title_entries_in_context', 'bx_stories', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxStoriesPageAuthor', 'modules/boonex/stories/classes/BxStoriesPageAuthor.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_stories_context', 1, 'bx_stories', '_bx_stories_page_block_title_sys_entries_in_context', '_bx_stories_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:14:"browse_context";}', 0, 0, 1, 1);
+
+-- PAGE: module home
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_home', 'stories-home', '_bx_stories_page_title_sys_home', '_bx_stories_page_title_home', 'bx_stories', 5, 2147483647, 1, 'page.php?i=stories-home', '', '', '', 0, 1, 0, 'BxStoriesPageBrowse', 'modules/boonex/stories/classes/BxStoriesPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('bx_stories_home', 0, 'bx_stories', '', '_bx_stories_page_block_title_popular_keywords_stories', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:14:"keywords_cloud";s:6:"params";a:3:{i:0;s:10:"bx_stories";i:1;s:10:"bx_stories";i:2;a:1:{s:10:"show_empty";b:1;}}s:5:"class";s:20:"TemplServiceMetatags";}', 1, 0, 1, 0),
+('bx_stories_home', 1, 'bx_stories', '_bx_stories_page_block_title_sys_recent_entries_view_gallery', '_bx_stories_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_stories";s:6:"method";s:13:"browse_public";s:6:"params";a:2:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;}}', 0, 1, 1, 1);
+
+-- PAGE: search for entries
+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_stories_search', '_bx_stories_page_title_sys_entries_search', '_bx_stories_page_title_entries_search', 'bx_stories', 1, 2147483647, 1, 'stories-search', 'page.php?i=stories-search', '', '', '', 0, 1, 0, 'BxStoriesPageBrowse', 'modules/boonex/stories/classes/BxStoriesPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_stories_search', 0, 'bx_stories', '_bx_stories_page_block_title_search_form_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:15:"bx_stories_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 0),
+('bx_stories_search', 0, 'bx_stories', '_bx_stories_page_block_title_search_results_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:15:"bx_stories_cmts";s:10:"show_empty";b:0;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 0),
+('bx_stories_search', 1, 'bx_stories', '_bx_stories_page_block_title_search_form', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:10:"bx_stories";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_stories_search', 2, 'bx_stories', '_bx_stories_page_block_title_search_results', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:10:"bx_stories";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1);
+
+-- PAGE: module manage own
+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_stories_manage', '_bx_stories_page_title_sys_manage', '_bx_stories_page_title_manage', 'bx_stories', 5, 2147483647, 1, 'stories-manage', 'page.php?i=stories-manage', '', '', '', 0, 1, 0, 'BxStoriesPageBrowse', 'modules/boonex/stories/classes/BxStoriesPageBrowse.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_stories_manage', 1, 'bx_stories', '_bx_stories_page_block_title_system_manage', '_bx_stories_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:12:"manage_tools";}}', 0, 1, 0);
+
+-- PAGE: module manage all
+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_stories_administration', '_bx_stories_page_title_sys_manage_administration', '_bx_stories_page_title_manage', 'bx_stories', 5, 192, 1, 'stories-administration', 'page.php?i=stories-administration', '', '', '', 0, 1, 0, 'BxStoriesPageBrowse', 'modules/boonex/stories/classes/BxStoriesPageBrowse.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_stories_administration', 1, 'bx_stories', '_bx_stories_page_block_title_system_manage_administration', '_bx_stories_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:"module";s:10:"bx_stories";s:6:"method";s:12:"manage_tools";s:6:"params";a:1:{i:0;s:14:"administration";}}', 0, 1, 0);
+
+-- PAGE: add block to homepage
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = 'sys_home' AND `cell_id` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('sys_home', 1, 'bx_stories', '_bx_stories_page_block_title_sys_recent_entries_view_showcase', '_bx_stories_page_block_title_recent_entries', 13, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_stories";s:6:"method";s:13:"browse_public";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}', 1, 0, 1, IFNULL(@iBlockOrder, 0) + 1);
+
+-- TODO: Block should check Expiration.
+
+-- PAGES: add page block to profiles modules (trigger* page objects are processed separately upon modules enable/disable)
+SET @iPBCellProfile = 3;
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_stories', '_bx_stories_page_block_title_sys_my_entries', '_bx_stories_page_block_title_my_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_stories";s:6:"method";s:13:"browse_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:2:{s:8:"per_page";s:27:"bx_stories_per_page_profile";s:13:"empty_message";b:0;}}}', 0, 0, 0);
+
+-- PAGE: service blocks
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = '' AND `cell_id` = 0 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('', 0, 'bx_stories', '', '_bx_stories_page_block_title_popular_keywords_stories', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:14:"keywords_cloud";s:6:"params";a:2:{i:0;s:10:"bx_stories";i:1;s:10:"bx_stories";}s:5:"class";s:20:"TemplServiceMetatags";}', 0, 1, 1, @iBlockOrder + 1),
+('', 0, 'bx_stories', '', '_bx_stories_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_stories";s:6:"method";s:13:"browse_public";s:6:"params";a:3:{s:9:"unit_view";s:8:"extended";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1, @iBlockOrder + 2),
+('', 0, 'bx_stories', '', '_bx_stories_page_block_title_updated_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_stories";s:6:"method";s:14:"browse_updated";s:6:"params";a:3:{s:9:"unit_view";s:8:"extended";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1, @iBlockOrder + 3);
+
+-- MENU: add to site menu
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' AND `active` = 1 AND `order` < 9999 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_site', 'bx_stories', 'stories-home', '_bx_stories_menu_item_title_system_entries_home', '_bx_stories_menu_item_title_entries_home', 'page.php?i=stories-home', '', '', 'far image col-blue1', 'bx_stories_submenu', 2147483647, 1, 1, IFNULL(@iSiteMenuOrder, 0) + 1);
+
+-- MENU: add to homepage menu
+SET @iHomepageMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_homepage' 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_homepage', 'bx_stories', 'stories-home', '_bx_stories_menu_item_title_system_entries_home', '_bx_stories_menu_item_title_entries_home', 'page.php?i=stories-home', '', '', 'far image col-blue1', 'bx_stories_submenu', 2147483647, 1, 1, IFNULL(@iHomepageMenuOrder, 0) + 1);
+
+-- 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_stories', 'create-story', '_bx_stories_menu_item_title_system_create_entry', '_bx_stories_menu_item_title_create_entry', 'page.php?i=create-story', '', '', 'far image col-blue1', '', 2147483647, 1, 1, IFNULL(@iAddMenuOrder, 0) + 1);
+
+-- MENU: actions menu for view entry 
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_view', '_bx_stories_menu_title_view_entry', 'bx_stories_view', 'bx_stories', 9, 0, 1, 'BxStoriesMenuView', 'modules/boonex/stories/classes/BxStoriesMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_stories_view', 'bx_stories', '_bx_stories_menu_set_title_view_entry', 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_stories_view', 'bx_stories', 'add-media-to-story', '_bx_stories_menu_item_title_system_add_media', '_bx_stories_menu_item_title_add_media', 'page.php?i=story-add-media&id={content_id}', '', '', 'plus', '', 2147483647, 1, 0, 10),
+('bx_stories_view', 'bx_stories', 'edit-story', '_bx_stories_menu_item_title_system_edit_entry', '_bx_stories_menu_item_title_edit_entry', 'page.php?i=edit-story&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 1, 0, 20),
+('bx_stories_view', 'bx_stories', 'delete-story', '_bx_stories_menu_item_title_system_delete_entry', '_bx_stories_menu_item_title_delete_entry', 'page.php?i=delete-story&id={content_id}', '', '', 'remove', '', 2147483647, 1, 0, 30),
+('bx_stories_view', 'bx_stories', 'approve', '_sys_menu_item_title_system_va_approve', '_sys_menu_item_title_va_approve', 'javascript:void(0)', 'javascript:bx_approve(this, ''{module_uri}'', {content_id});', '', 'check', '', 2147483647, 1, 0, 40);
+
+-- MENU: all actions menu for view entry 
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_view_actions', '_sys_menu_title_view_actions', 'bx_stories_view_actions', 'bx_stories', 15, 0, 1, 'BxStoriesMenuViewActions', 'modules/boonex/stories/classes/BxStoriesMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_stories_view_actions', 'bx_stories', '_sys_menu_set_title_view_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`, `order`) VALUES 
+('bx_stories_view_actions', 'bx_stories', 'edit-story', '_bx_stories_menu_item_title_system_edit_entry', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 10),
+('bx_stories_view_actions', 'bx_stories', 'delete-story', '_bx_stories_menu_item_title_system_delete_entry', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 20),
+('bx_stories_view_actions', 'bx_stories', 'approve', '_sys_menu_item_title_system_va_approve', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 30),
+('bx_stories_view_actions', 'bx_stories', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 200),
+('bx_stories_view_actions', 'bx_stories', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 210),
+('bx_stories_view_actions', 'bx_stories', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 220),
+('bx_stories_view_actions', 'bx_stories', 'reaction', '_sys_menu_item_title_system_va_reaction', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 225),
+('bx_stories_view_actions', 'bx_stories', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 230),
+('bx_stories_view_actions', 'bx_stories', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 240),
+('bx_stories_view_actions', 'bx_stories', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 250),
+('bx_stories_view_actions', 'bx_stories', 'repost', '_sys_menu_item_title_system_va_repost', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 260),
+('bx_stories_view_actions', 'bx_stories', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 270),
+('bx_stories_view_actions', 'bx_stories', 'notes', '_sys_menu_item_title_system_va_notes', '_sys_menu_item_title_va_notes', 'javascript:void(0)', 'javascript:bx_get_notes(this,  ''{module_uri}'', {content_id});', '', 'exclamation-triangle', '', '', 0, 2147483647, 1, 0, 280),
+('bx_stories_view_actions', 'bx_stories', 'audit', '_sys_menu_item_title_system_va_audit', '_sys_menu_item_title_va_audit', 'page.php?i=dashboard-audit&module=bx_stories&content_id={content_id}', '', '', 'history', '', '', 0, 192, 1, 0, 290),
+('bx_stories_view_actions', 'bx_stories', 'social-sharing', '_sys_menu_item_title_system_social_sharing', '_sys_menu_item_title_social_sharing', 'javascript:void(0)', 'oBxDolPage.share(this, \'{url_encoded}\')', '', 'share', '', '', 0, 2147483647, 1, 0, 300),
+('bx_stories_view_actions', 'bx_stories', 'more-auto', '_sys_menu_item_title_system_va_more_auto', '_sys_menu_item_title_va_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, 1, 0, 9999);
+
+
+-- MENU: actions menu for view media
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_view_actions_media', '_bx_stories_menu_title_view_actions_media', 'bx_stories_view_actions_media', 'bx_stories', 9, 0, 1, 'BxStoriesMenuView', 'modules/boonex/stories/classes/BxStoriesMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_stories_view_actions_media', 'bx_stories', '_bx_stories_menu_set_title_view_actions_media', 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_stories_view_actions_media', 'bx_stories', 'edit-media', '_bx_stories_menu_item_title_system_edit_image', '_bx_stories_menu_item_title_edit_image', 'javascript:void(0)', 'javascript:{js_object}.editMedia(this, {id});', '', 'pencil-alt', '', 2147483647, 1, 0, 10),
+('bx_stories_view_actions_media', 'bx_stories', 'delete-media', '_bx_stories_menu_item_title_system_delete_image', '_bx_stories_menu_item_title_delete_image', 'javascript:void(0)', 'javascript:{js_object}.deleteMedia(this, {id});', '', 'remove', '', 2147483647, 1, 0, 20);
+
+
+-- MENU: actions menu for my entries
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_my', '_bx_stories_menu_title_entries_my', 'bx_stories_my', 'bx_stories', 9, 0, 1, 'BxStoriesMenu', 'modules/boonex/stories/classes/BxStoriesMenu.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_stories_my', 'bx_stories', '_bx_stories_menu_set_title_entries_my', 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_stories_my', 'bx_stories', 'create-story', '_bx_stories_menu_item_title_system_create_entry', '_bx_stories_menu_item_title_create_entry', 'page.php?i=create-story', '', '', 'plus', '', 2147483647, 1, 0, 0);
+
+-- MENU: module sub-menu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_submenu', '_bx_stories_menu_title_submenu', 'bx_stories_submenu', 'bx_stories', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_stories_submenu', 'bx_stories', '_bx_stories_menu_set_title_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_stories_submenu', 'bx_stories', 'stories-home', '_bx_stories_menu_item_title_system_entries_recent', '_bx_stories_menu_item_title_entries_recent', 'page.php?i=stories-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_stories_submenu', 'bx_stories', 'stories-popular', '_bx_stories_menu_item_title_system_entries_popular', '_bx_stories_menu_item_title_entries_popular', 'page.php?i=stories-popular', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_stories_submenu', 'bx_stories', 'stories-top', '_bx_stories_menu_item_title_system_entries_top', '_bx_stories_menu_item_title_entries_top', 'page.php?i=stories-top', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_stories_submenu', 'bx_stories', 'stories-search', '_bx_stories_menu_item_title_system_entries_search', '_bx_stories_menu_item_title_entries_search', 'page.php?i=stories-search', '', '', '', '', 2147483647, 1, 1, 4),
+('bx_stories_submenu', 'bx_stories', 'stories-manage', '_bx_stories_menu_item_title_system_entries_manage', '_bx_stories_menu_item_title_entries_manage', 'page.php?i=stories-manage', '', '', '', '', 2147483646, 1, 1, 5);
+
+-- MENU: sub-menu for view entry
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_view_submenu', '_bx_stories_menu_title_view_entry_submenu', 'bx_stories_view_submenu', 'bx_stories', 8, 0, 1, 'BxStoriesMenuView', 'modules/boonex/stories/classes/BxStoriesMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_stories_view_submenu', 'bx_stories', '_bx_stories_menu_set_title_view_entry_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_stories_view_submenu', 'bx_stories', 'view-story', '_bx_stories_menu_item_title_system_view_entry', '_bx_stories_menu_item_title_view_entry_submenu_entry', 'page.php?i=view-story&id={content_id}', '', '', '', '', 2147483647, 1, 0, 1),
+('bx_stories_view_submenu', 'bx_stories', 'view-story-comments', '_bx_stories_menu_item_title_system_view_entry_comments', '_bx_stories_menu_item_title_view_entry_submenu_comments', 'page.php?i=view-story-comments&id={content_id}', '', '', '', '', 2147483647, 1, 0, 2);
+
+-- MENU: custom menu for snippet meta info
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_snippet_meta', '_sys_menu_title_snippet_meta', 'bx_stories_snippet_meta', 'bx_stories', 15, 0, 1, 'BxStoriesMenuSnippetMeta', 'modules/boonex/stories/classes/BxStoriesMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_stories_snippet_meta', 'bx_stories', '_sys_menu_set_title_snippet_meta', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_stories_snippet_meta', 'bx_stories', 'date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_stories_snippet_meta', 'bx_stories', 'author', '_sys_menu_item_title_system_sm_author', '_sys_menu_item_title_sm_author', '', '', '', '', '', 2147483647, 1, 0, 1, 2),
+('bx_stories_snippet_meta', 'bx_stories', 'tags', '_sys_menu_item_title_system_sm_tags', '_sys_menu_item_title_sm_tags', '', '', '', '', '', 2147483647, 0, 0, 1, 3),
+('bx_stories_snippet_meta', 'bx_stories', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 2147483647, 0, 0, 1, 4),
+('bx_stories_snippet_meta', 'bx_stories', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 2147483647, 0, 0, 1, 5),
+('bx_stories_snippet_meta', 'bx_stories', 'items', '_bx_stories_menu_item_title_system_sm_items', '_bx_stories_menu_item_title_sm_items', '', '', '', '', '', 2147483647, 0, 0, 1, 6);
+
+-- MENU: profile stats
+SET @iNotifMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name` = 'sys_profile_stats' AND `active` = 1 LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES
+('sys_profile_stats', 'bx_stories', 'profile-stats-my-stories', '_bx_stories_menu_item_title_system_manage_my_stories', '_bx_stories_menu_item_title_manage_my_stories', 'page.php?i=stories-author&profile_id={member_id}', '', '_self', 'far image col-blue1', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:41:"get_menu_addon_manage_tools_profile_stats";}', '', 2147483646, 1, 0, @iNotifMenuOrder + 1);
+
+-- MENU: manage tools submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_menu_manage_tools', '_bx_stories_menu_title_manage_tools', 'bx_stories_menu_manage_tools', 'bx_stories', 6, 0, 1, 'BxStoriesMenuManageTools', 'modules/boonex/stories/classes/BxStoriesMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_stories_menu_manage_tools', 'bx_stories', '_bx_stories_menu_set_title_manage_tools', 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_stories_menu_manage_tools', 'bx_stories', 'delete-with-content', '_bx_stories_menu_item_title_system_delete_with_content', '_bx_stories_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'far trash-alt', '', 128, 1, 0, 0);
+
+-- MENU: dashboard manage tools
+SET @iManageMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard_manage_tools' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_account_dashboard_manage_tools', 'bx_stories', 'stories-administration', '_bx_stories_menu_item_title_system_admt_stories', '_bx_stories_menu_item_title_admt_stories', 'page.php?i=stories-administration', '', '_self', 'far image', 'a:2:{s:6:"module";s:10:"bx_stories";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 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_stories', 'stories-author', '_bx_stories_menu_item_title_system_view_entries_author', '_bx_stories_menu_item_title_view_entries_author', 'page.php?i=stories-author&profile_id={profile_id}', '', '', 'far image col-blue1', '', 2147483647, 1, 0, 0),
+('trigger_group_view_submenu', 'bx_stories', 'stories-context', '_bx_stories_menu_item_title_system_view_entries_in_context', '_bx_stories_menu_item_title_view_entries_in_context', 'page.php?i=stories-context&profile_id={profile_id}', '', '', 'far image col-blue1', '', 2147483647, 1, 0, 0);
+
+
+-- 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_stories_allow_view_to', 'bx_stories', 'view', '_bx_stories_form_entry_input_allow_view_to', '3', 'bx_stories_entries', 'id', 'author', '', '');
+
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_stories', 'create entry', NULL, '_bx_stories_acl_action_create_entry', '', 1, 3);
+SET @iIdActionEntryCreate = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_stories', 'delete entry', NULL, '_bx_stories_acl_action_delete_entry', '', 1, 3);
+SET @iIdActionEntryDelete = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_stories', 'view entry', NULL, '_bx_stories_acl_action_view_entry', '', 1, 0);
+SET @iIdActionEntryView = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_stories', 'edit any entry', NULL, '_bx_stories_acl_action_edit_any_entry', '', 1, 3);
+SET @iIdActionEntryEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_stories', 'delete any entry', NULL, '_bx_stories_acl_action_delete_any_entry', '', 1, 3);
+SET @iIdActionEntryDeleteAny = 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
+
+-- entry create
+(@iStandard, @iIdActionEntryCreate),
+(@iModerator, @iIdActionEntryCreate),
+(@iAdministrator, @iIdActionEntryCreate),
+(@iPremium, @iIdActionEntryCreate),
+
+-- entry delete
+(@iStandard, @iIdActionEntryDelete),
+(@iModerator, @iIdActionEntryDelete),
+(@iAdministrator, @iIdActionEntryDelete),
+(@iPremium, @iIdActionEntryDelete),
+
+-- entry view
+(@iUnauthenticated, @iIdActionEntryView),
+(@iAccount, @iIdActionEntryView),
+(@iStandard, @iIdActionEntryView),
+(@iUnconfirmed, @iIdActionEntryView),
+(@iPending, @iIdActionEntryView),
+(@iModerator, @iIdActionEntryView),
+(@iAdministrator, @iIdActionEntryView),
+(@iPremium, @iIdActionEntryView),
+
+-- edit any entry
+(@iModerator, @iIdActionEntryEditAny),
+(@iAdministrator, @iIdActionEntryEditAny),
+
+-- delete any entry
+(@iAdministrator, @iIdActionEntryDeleteAny);
+
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `GlobalSearch`, `ClassName`, `ClassPath`) VALUES
+('bx_stories', '_bx_stories', @iSearchOrder + 1, 1, 'BxStoriesSearchResult', 'modules/boonex/stories/classes/BxStoriesSearchResult.php'),
+('bx_stories_cmts', '_bx_stories_cmts', @iSearchOrder + 2, 1, 'BxStoriesCmtsSearchResult', 'modules/boonex/stories/classes/BxStoriesCmtsSearchResult.php'),
+('bx_stories_media', '_bx_stories_media', @iSearchOrder + 3, 0, 'BxStoriesSearchResultMedia', 'modules/boonex/stories/classes/BxStoriesSearchResultMedia.php');
+
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `module`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_stories', 'bx_stories', 'bx_stories_meta_keywords', '', 'bx_stories_meta_mentions', '', '');
+
+
+-- STATS
+SET @iMaxOrderStats = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_statistics`);
+INSERT INTO `sys_statistics` (`module`, `name`, `title`, `link`, `icon`, `query`, `order`) VALUES 
+('bx_stories', 'bx_stories', '_bx_stories', 'page.php?i=stories-home', 'far image col-blue1', 'SELECT COUNT(*) FROM `bx_stories_entries` WHERE 1 AND `status` = ''active'' AND `status_admin` = ''active''', @iMaxOrderStats + 1);
+
+
+-- CHARTS
+SET @iMaxOrderCharts = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_objects_chart`);
+INSERT INTO `sys_objects_chart` (`object`, `title`, `table`, `field_date_ts`, `field_date_dt`, `field_status`, `query`, `active`, `order`, `class_name`, `class_file`) VALUES
+('bx_stories_growth', '_bx_stories_chart_growth', 'bx_stories_entries', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
+('bx_stories_growth_speed', '_bx_stories_chart_growth_speed', 'bx_stories_entries', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', '');
+
+
+-- GRIDS: moderation tools
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_stories_administration', 'Sql', 'SELECT * FROM `bx_stories_entries` WHERE 1 ', 'bx_stories_entries', 'id', 'added', 'status_admin', '', 20, NULL, 'start', '', 'title,text', '', 'like', 'reports', '', 192, 'BxStoriesGridAdministration', 'modules/boonex/stories/classes/BxStoriesGridAdministration.php'),
+('bx_stories_common', 'Sql', 'SELECT * FROM `bx_stories_entries` WHERE 1 ', 'bx_stories_entries', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'title,text', '', 'like', '', '', 2147483647, 'BxStoriesGridCommon', 'modules/boonex/stories/classes/BxStoriesGridCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_stories_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_stories_administration', 'switcher', '_bx_stories_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_stories_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
+('bx_stories_administration', 'title', '_bx_stories_grid_column_title_adm_title', '25%', 0, '', '', 4),
+('bx_stories_administration', 'added', '_bx_stories_grid_column_title_adm_added', '20%', 1, '25', '', 5),
+('bx_stories_administration', 'author', '_bx_stories_grid_column_title_adm_author', '20%', 0, '25', '', 6),
+('bx_stories_administration', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_stories_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_stories_common', 'switcher', '', '8%', 0, '', '', 2),
+('bx_stories_common', 'title', '_bx_stories_grid_column_title_adm_title', '40%', 0, '', '', 3),
+('bx_stories_common', 'added', '_bx_stories_grid_column_title_adm_added', '15%', 1, '25', '', 4),
+('bx_stories_common', 'status_admin', '_bx_stories_grid_column_title_adm_status_admin', '15%', 0, '16', '', 5),
+('bx_stories_common', 'actions', '', '20%', 0, '', '', 6);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_stories_administration', 'bulk', 'delete', '_bx_stories_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_stories_administration', 'bulk', 'clear_reports', '_bx_stories_grid_action_title_adm_clear_reports', '', 0, 1, 2),
+('bx_stories_administration', 'single', 'edit', '_bx_stories_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_stories_administration', 'single', 'delete', '_bx_stories_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_stories_administration', 'single', 'settings', '_bx_stories_grid_action_title_adm_more_actions', 'cog', 1, 0, 3),
+('bx_stories_administration', 'single', 'audit_content', '_bx_stories_grid_action_title_adm_audit_content', 'search', 1, 0, 4),
+('bx_stories_administration', 'single', 'clear_reports', '_bx_stories_grid_action_title_adm_clear_reports', 'eraser', 1, 0, 5),
+('bx_stories_common', 'bulk', 'delete', '_bx_stories_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_stories_common', 'single', 'edit', '_bx_stories_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_stories_common', 'single', 'delete', '_bx_stories_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_stories_common', 'single', 'settings', '_bx_stories_grid_action_title_adm_more_actions', 'cog', 1, 0, 3);
+
+
+-- UPLOADERS
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_stories_html5', 1, 'BxStoriesUploaderHTML5', 'modules/boonex/stories/classes/BxStoriesUploaderHTML5.php'),
+('bx_stories_record_video', 1, 'BxStoriesUploaderRecordVideo', 'modules/boonex/stories/classes/BxStoriesUploaderRecordVideo.php'),
+('bx_stories_crop', 1, 'BxStoriesUploaderCrop', 'modules/boonex/stories/classes/BxStoriesUploaderCrop.php');
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_stories', 'BxStoriesAlertsResponse', 'modules/boonex/stories/classes/BxStoriesAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('profile', 'delete', @iHandler),
+
+('bx_stories_files', 'file_deleted', @iHandler),
+('bx_stories_video_mp4', 'transcoded', @iHandler);

+ 385 - 0
modules/boonex/stories/install/sql/install.sql

@@ -0,0 +1,385 @@
+-- TABLE: entries
+CREATE TABLE IF NOT EXISTS `bx_stories_entries` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `author` int(11) unsigned NOT NULL,
+  `added` int(11) NOT NULL,
+  `changed` int(11) NOT NULL,
+  `expired` int(11) NOT NULL,
+  `thumb` int(11) NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `text` text NOT NULL,
+  `labels` text NOT NULL,
+  `location` text NOT NULL,
+  `views` int(11) NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `rrate` float NOT NULL default '0',
+  `rvotes` int(11) NOT NULL default '0',
+  `score` int(11) NOT NULL default '0',
+  `sc_up` int(11) NOT NULL default '0',
+  `sc_down` int(11) NOT NULL default '0',
+  `favorites` int(11) NOT NULL default '0',
+  `comments` int(11) NOT NULL default '0',
+  `reports` int(11) NOT NULL default '0',
+  `featured` int(11) NOT NULL default '0',
+  `cf` int(11) NOT NULL default '1',
+  `allow_view_to` varchar(16) NOT NULL DEFAULT '3',
+  `status` enum('active','awaiting','failed','hidden') NOT NULL DEFAULT 'active',
+  `status_admin` enum('active','hidden','pending') NOT NULL DEFAULT 'active',
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `title_text` (`title`,`text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_stories_entries_media` (
+  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  `content_id` int(11) unsigned NOT NULL,
+  `file_id` int(11) NOT NULL,
+  `author` int(10) unsigned NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `cf` int(11) NOT NULL default '1',
+  `data` text NOT NULL,
+  `order` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `file_content` (`file_id`,`content_id`),
+  KEY `content_id` (`content_id`),
+  FULLTEXT KEY `search_fields` (`title`)
+);
+
+-- TABLE: storages & transcoders
+CREATE TABLE IF NOT EXISTS `bx_stories_files` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(11) 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` bigint(20) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
+  `duration` 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_stories_photos_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(11) 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` bigint(20) 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`)
+);
+
+-- TABLE: comments
+CREATE TABLE IF NOT EXISTS `bx_stories_cmts` (
+  `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(11) NOT NULL DEFAULT '0',
+  `cmt_level` int(11) NOT NULL DEFAULT '0',
+  `cmt_text` text NOT NULL,
+  `cmt_mood` tinyint(4) NOT NULL DEFAULT '0',
+  `cmt_rate` int(11) NOT NULL DEFAULT '0',
+  `cmt_rate_count` int(11) NOT NULL DEFAULT '0',
+  `cmt_time` int(11) unsigned NOT NULL DEFAULT '0',
+  `cmt_replies` int(11) NOT NULL DEFAULT '0',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  `cmt_cf` int(11) NOT NULL default '1',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_stories_cmts_notes` (
+  `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(11) NOT NULL DEFAULT '0',
+  `cmt_level` int(11) NOT NULL DEFAULT '0',
+  `cmt_text` text NOT NULL,
+  `cmt_mood` tinyint(4) NOT NULL DEFAULT '0',
+  `cmt_rate` int(11) NOT NULL DEFAULT '0',
+  `cmt_rate_count` int(11) NOT NULL DEFAULT '0',
+  `cmt_time` int(11) unsigned NOT NULL DEFAULT '0',
+  `cmt_replies` int(11) NOT NULL DEFAULT '0',
+  `cmt_pinned` 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: votes
+CREATE TABLE IF NOT EXISTS `bx_stories_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_stories_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_stories_reactions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `reaction` varchar(32) NOT NULL default '',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `reaction` (`object_id`, `reaction`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_stories_reactions_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',
+  `reaction` varchar(32) NOT NULL default '',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- TABLE: views
+CREATE TABLE IF NOT EXISTS `bx_stories_views_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `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',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+);
+
+-- TABLE: metas
+CREATE TABLE IF NOT EXISTS `bx_stories_meta_keywords` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_stories_meta_mentions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `profile_id` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `profile_id` (`profile_id`)
+);
+
+-- TABLE: reports
+CREATE TABLE IF NOT EXISTS `bx_stories_reports` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_stories_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',
+  `checked_by` int(11) NOT NULL default '0',
+  `status` tinyint(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+);
+
+-- TABLE: scores
+CREATE TABLE IF NOT EXISTS `bx_stories_scores` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count_up` int(11) NOT NULL default '0',
+  `count_down` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_stories_scores_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(8) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+
+-- STORAGES & TRANSCODERS
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+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_stories_files', @sStorageEngine, '', 360, 2592000, 3, 'bx_stories_files', 'allow-deny', '{imagevideo}', '', 0, 0, 0, 0, 0, 0),
+('bx_stories_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_stories_photos_resized', 'allow-deny', '{imagevideo}', '', 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_stories_preview', 'bx_stories_photos_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_stories_files";}', 'no', '1', '2592000', '0', '', ''),
+('bx_stories_browse', 'bx_stories_photos_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_stories_files";}', 'no', '1', '2592000', '0', '', ''),
+('bx_stories_big', 'bx_stories_photos_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_stories_files";}', 'no', '1', '2592000', '0', '', ''),
+('bx_stories_video_poster_browse', 'bx_stories_photos_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_stories_files";}', 'no', 0, 0, 0, 'BxDolTranscoderVideo', ''),
+('bx_stories_video_poster_preview', 'bx_stories_photos_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_stories_files";}', 'no', 0, 0, 0, 'BxDolTranscoderVideo', ''),
+('bx_stories_video_poster_big', 'bx_stories_photos_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_stories_files";}', 'no', 0, 0, 0, 'BxDolTranscoderVideo', ''),
+('bx_stories_video_mp4', 'bx_stories_photos_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_stories_files";}', 'no', 0, 0, 0, 'BxDolTranscoderVideo', ''),
+('bx_stories_video_mp4_hd', 'bx_stories_photos_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_stories_files";}', 'no', 0, 0, 0, 'BxDolTranscoderVideo', ''),
+('bx_stories_proxy_preview', 'bx_stories_photos_resized', 'Proxy', 'a:4:{s:6:"object";s:16:"bx_stories_files";s:5:"image";s:18:"bx_stories_preview";s:12:"video_poster";s:31:"bx_stories_video_poster_preview";s:5:"video";a:4:{i:0;s:20:"bx_stories_video_mp4";i:1;s:23:"bx_stories_video_mp4_hd";i:2;s:30:"bx_stories_video_poster_browse";i:3;s:27:"bx_stories_video_poster_big";}}', 'no', 0, 0, 0, 'BxDolTranscoderProxy', ''),
+('bx_stories_proxy_browse', 'bx_stories_photos_resized', 'Proxy', 'a:4:{s:6:"object";s:16:"bx_stories_files";s:5:"image";s:17:"bx_stories_browse";s:12:"video_poster";s:30:"bx_stories_video_poster_browse";s:5:"video";a:2:{i:0;s:20:"bx_stories_video_mp4";i:1;s:23:"bx_stories_video_mp4_hd";}}', 'no', 0, 0, 0, 'BxDolTranscoderProxy', ''),
+('bx_stories_proxy_cover', 'bx_stories_photos_resized', 'Proxy', 'a:4:{s:6:"object";s:16:"bx_stories_files";s:5:"image";s:14:"bx_stories_big";s:12:"video_poster";s:27:"bx_stories_video_poster_big";s:5:"video";a:2:{i:0;s:20:"bx_stories_video_mp4";i:1;s:23:"bx_stories_video_mp4_hd";}}', 'no', 0, 0, 0, 'BxDolTranscoderProxy', '');
+
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_stories_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"300";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_stories_browse', 'Resize', 'a:1:{s:1:"h";s:3:"180";}', '0'),
+('bx_stories_big', 'Resize', 'a:2:{s:1:"w";s:4:"1280";s:1:"h";s:4:"1280";}', '0'),
+('bx_stories_video_poster_browse', 'Poster', 'a:2:{s:1:"h";s:3:"180";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_stories_video_poster_preview', 'Poster', 'a:2:{s:1:"h";s:3:"480";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_stories_video_poster_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"300";s:13:"square_resize";s:1:"1";}', 10),
+('bx_stories_video_poster_big', 'Poster', 'a:2:{s:1:"h";s:3:"480";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_stories_video_mp4', 'Mp4', 'a:2:{s:1:"h";s:3:"480";s:10:"force_type";s:3:"mp4";}', 0),
+('bx_stories_video_mp4_hd', 'Mp4', 'a:3:{s:1:"h";s:3:"720";s:13:"video_bitrate";s:4:"1536";s:10:"force_type";s:3:"mp4";}', 0);
+
+
+-- FORMS
+INSERT INTO `sys_objects_form`(`object`, `module`, `title`, `action`, `form_attrs`, `table`, `key`, `uri`, `uri_title`, `submit_name`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories', 'bx_stories', '_bx_stories_form_entry', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_stories_entries', 'id', '', '', 'do_submit', '', 0, 1, 'BxStoriesFormEntry', 'modules/boonex/stories/classes/BxStoriesFormEntry.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_stories', 'bx_stories_entry_add', 'bx_stories', 0, '_bx_stories_form_entry_display_add'),
+('bx_stories', 'bx_stories_entry_edit', 'bx_stories', 0, '_bx_stories_form_entry_display_edit'),
+('bx_stories', 'bx_stories_entry_delete', 'bx_stories', 0, '_bx_stories_form_entry_display_delete'),
+('bx_stories', 'bx_stories_entry_view', 'bx_stories', 1, '_bx_stories_form_entry_display_view');
+
+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_stories', 'bx_stories', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_stories_form_entry_input_sys_delete_confirm', '_bx_stories_form_entry_input_delete_confirm', '_bx_stories_form_entry_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_stories_form_entry_input_delete_confirm_error', '', '', 1, 0),
+('bx_stories', 'bx_stories', 'do_submit', '_bx_stories_form_entry_input_do_submit', '', 0, 'submit', '_bx_stories_form_entry_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_stories', 'bx_stories', 'title', '', '', 0, 'text', '_bx_stories_form_entry_input_sys_title', '_bx_stories_form_entry_input_title', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_stories_form_entry_input_title_err', 'Xss', '', 1, 0),
+('bx_stories', 'bx_stories', 'text', '', '', 0, 'textarea', '_bx_stories_form_entry_input_sys_text', '_bx_stories_form_entry_input_text', '', 0, 0, 2, '', '', '', '', '', '', 'XssHtml', '', 1, 0),
+('bx_stories', 'bx_stories', 'pictures', 'a:1:{i:0;s:16:"bx_stories_html5";}', 'a:3:{s:16:"bx_stories_html5";s:25:"_sys_uploader_html5_title";s:23:"bx_stories_record_video";s:32:"_sys_uploader_record_video_title";s:15:"bx_stories_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_stories_form_entry_input_sys_pictures', '_bx_stories_form_entry_input_pictures', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_stories_form_entry_input_pictures_err', '', '', 1, 0),
+('bx_stories', 'bx_stories', 'cf', '1', '#!sys_content_filter', 0, 'select', '_sys_form_entry_input_sys_cf', '_sys_form_entry_input_cf', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_stories', 'bx_stories', 'allow_view_to', '', '', 0, 'custom', '_bx_stories_form_entry_input_sys_allow_view_to', '_bx_stories_form_entry_input_allow_view_to', '', 1, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_stories', 'bx_stories', 'added', '', '', 0, 'datetime', '_bx_stories_form_entry_input_sys_date_added', '_bx_stories_form_entry_input_date_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_stories', 'bx_stories', 'changed', '', '', 0, 'datetime', '_bx_stories_form_entry_input_sys_date_changed', '_bx_stories_form_entry_input_date_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_stories', 'bx_stories', 'expired', '', '', 0, 'datetime', '_bx_stories_form_entry_input_sys_date_expired', '_bx_stories_form_entry_input_date_expired', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_stories', 'bx_stories', 'labels', '', '', 0, 'custom', '_sys_form_input_sys_labels', '_sys_form_input_labels', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_stories_entry_add', 'pictures', 2147483647, 1, 1),
+('bx_stories_entry_add', 'allow_view_to', 2147483647, 1, 2),
+('bx_stories_entry_add', 'do_submit', 2147483647, 1, 3),
+
+('bx_stories_entry_edit', 'pictures', 2147483647, 1, 1),
+('bx_stories_entry_edit', 'allow_view_to', 2147483647, 1, 2),
+('bx_stories_entry_edit', 'do_submit', 2147483647, 1, 3),
+
+('bx_stories_entry_view', 'added', 2147483647, 1, 1),
+('bx_stories_entry_view', 'changed', 2147483647, 1, 2),
+('bx_stories_entry_view', 'expired', 2147483647, 1, 3),
+
+('bx_stories_entry_delete', 'delete_confirm', 2147483647, 1, 1),
+('bx_stories_entry_delete', 'do_submit', 2147483647, 1, 2);
+
+INSERT INTO `sys_objects_form`(`object`, `module`, `title`, `action`, `form_attrs`, `table`, `key`, `uri`, `uri_title`, `submit_name`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stories_media', 'bx_stories', '_bx_stories_form_media', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_stories_entries_media', 'id', '', '', 'do_submit', '', 0, 1, 'BxStoriesFormMedia', 'modules/boonex/stories/classes/BxStoriesFormMedia.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_stories_media', 'bx_stories_media_edit', 'bx_stories', 0, '_bx_stories_form_media_display_edit');
+
+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_stories_media', 'bx_stories', 'title', '', '', 0, 'text', '_bx_stories_form_media_input_sys_title', '_bx_stories_form_media_input_title', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_stories_media', 'bx_stories', 'content_id', '', '', 0, 'select', '_bx_stories_form_media_input_sys_content_id', '_bx_stories_form_media_input_content_id', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_stories_media', 'bx_stories', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_stories_media', 'bx_stories', 'do_submit', '_bx_stories_form_media_input_do_submit', '', 0, 'submit', '_bx_stories_form_media_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_stories_media', 'bx_stories', 'do_cancel', '_bx_stories_form_media_input_do_cancel', '', 0, 'button', '_bx_stories_form_media_input_sys_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_stories_media_edit', 'title', 2147483647, 1, 1),
+('bx_stories_media_edit', 'controls', 2147483647, 1, 2),
+('bx_stories_media_edit', 'do_submit', 2147483647, 1, 3),
+('bx_stories_media_edit', 'do_cancel', 2147483647, 1, 4);
+
+
+-- COMMENTS
+INSERT INTO `sys_objects_cmts` (`Name`, `Module`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Html`, `PerView`, `PerViewReplies`, `BrowseType`, `IsBrowseSwitch`, `PostFormPosition`, `NumberOfLevels`, `IsDisplaySwitch`, `IsRatable`, `ViewingThreshold`, `IsOn`, `RootStylePrefix`, `BaseUrl`, `ObjectVote`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('bx_stories', 'bx_stories', 'bx_stories_cmts', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-story&id={object_id}', '', 'bx_stories_entries', 'id', 'author', 'title', 'comments', '', ''),
+('bx_stories_notes', 'bx_stories', 'bx_stories_cmts_notes', 1, 5000, 1000, 0, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-post&id={object_id}', '', 'bx_stories_entries', 'id', 'author', 'title', '', 'BxTemplCmtsNotes', '');
+
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `Module`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_stories', 'bx_stories', 'bx_stories_votes', 'bx_stories_votes_track', '604800', '1', '1', '0', '1', 'bx_stories_entries', 'id', 'author', 'rate', 'votes', '', ''),
+('bx_stories_reactions', 'bx_stories', 'bx_stories_reactions', 'bx_stories_reactions_track', '604800', '1', '1', '1', '1', 'bx_stories_entries', 'id', 'author', 'rrate', 'rvotes', 'BxTemplVoteReactions', '');
+
+
+-- SCORES
+INSERT INTO `sys_objects_score` (`name`, `module`, `table_main`, `table_track`, `post_timeout`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_score`, `trigger_field_cup`, `trigger_field_cdown`, `class_name`, `class_file`) VALUES 
+('bx_stories', 'bx_stories', 'bx_stories_scores', 'bx_stories_scores_track', '604800', '0', 'bx_stories_entries', 'id', 'author', 'score', 'sc_up', 'sc_down', '', '');
+
+
+-- REPORTS
+INSERT INTO `sys_objects_report` (`name`, `module`, `table_main`, `table_track`, `is_on`, `base_url`, `object_comment`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_stories', 'bx_stories', 'bx_stories_reports', 'bx_stories_reports_track', '1', 'page.php?i=view-story&id={object_id}', 'bx_stories_notes', 'bx_stories_entries', 'id', 'author', 'reports', '', '');
+
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `module`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_stories', 'bx_stories', 'bx_stories_views_track', '86400', '1', 'bx_stories_entries', 'id', '', 'views', '', '');
+
+
+-- CONTENT INFO
+INSERT INTO `sys_objects_content_info` (`name`, `title`, `alert_unit`, `alert_action_add`, `alert_action_update`, `alert_action_delete`, `class_name`, `class_file`) VALUES
+('bx_stories', '_bx_stories', 'bx_stories', 'added', 'edited', 'deleted', '', ''),
+('bx_stories_cmts', '_bx_stories_cmts', 'bx_stories', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', '');
+
+INSERT INTO `sys_content_info_grids` (`object`, `grid_object`, `grid_field_id`, `condition`, `selection`) VALUES
+('bx_stories', 'bx_stories_administration', 'id', '', ''),
+('bx_stories', 'bx_stories_common', 'id', '', '');
+
+
+-- SEARCH EXTENDED
+INSERT INTO `sys_objects_search_extended` (`object`, `object_content_info`, `module`, `title`, `active`, `class_name`, `class_file`) VALUES
+('bx_stories', 'bx_stories', 'bx_stories', '_bx_stories_search_extended', 1, '', ''),
+('bx_stories_cmts', 'bx_stories_cmts', 'bx_stories', '_bx_stories_search_extended_cmts', 1, 'BxTemplSearchExtendedCmts', '');
+
+
+-- STUDIO: page & widget
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_stories', '_bx_stories', '_bx_stories', 'bx_stories@modules/boonex/stories/|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`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_stories', 'content', '{url_studio}module.php?name=bx_stories', '', 'bx_stories@modules/boonex/stories/|std-icon.svg', '_bx_stories', '', '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));

+ 56 - 0
modules/boonex/stories/install/sql/uninstall.sql

@@ -0,0 +1,56 @@
+
+-- TABLES
+DROP TABLE IF EXISTS `bx_stories_entries`, `bx_stories_files`, `bx_stories_photos_resized`, `bx_stories_entries_media`, `bx_stories_cmts`, `bx_stories_cmts_notes`, `bx_stories_votes`, `bx_stories_votes_track`, `bx_stories_reactions`, `bx_stories_reactions_track`, `bx_stories_views_track`, `bx_stories_meta_keywords`, `bx_stories_meta_mentions`, `bx_stories_reports`, `bx_stories_reports_track`, `bx_stories_scores`, `bx_stories_scores_track`;
+
+
+-- STORAGES & TRANSCODERS
+DELETE FROM `sys_objects_storage` WHERE `object` = 'bx_stories_files' OR `object` = 'bx_stories_photos_resized';
+DELETE FROM `sys_storage_tokens` WHERE `object` = 'bx_stories_files' OR `object` = 'bx_stories_photos_resized';
+
+DELETE FROM `sys_objects_transcoder` WHERE `object` IN('bx_stories_preview', 'bx_stories_browse', 'bx_stories_big', 'bx_stories_video_poster_browse', 'bx_stories_video_poster_preview', 'bx_stories_video_poster_big', 'bx_stories_video_mp4', 'bx_stories_video_mp4_hd', 'bx_stories_proxy_preview', 'bx_stories_proxy_browse', 'bx_stories_proxy_cover');
+DELETE FROM `sys_transcoder_filters` WHERE `transcoder_object` IN('bx_stories_preview', 'bx_stories_browse', 'bx_stories_big', 'bx_stories_video_poster_browse', 'bx_stories_video_poster_preview', 'bx_stories_video_poster_big', 'bx_stories_video_mp4', 'bx_stories_video_mp4_hd');
+DELETE FROM `sys_transcoder_images_files` WHERE `transcoder_object` IN('bx_stories_preview', 'bx_stories_browse', 'bx_stories_big', 'bx_stories_video_poster_browse', 'bx_stories_video_poster_preview', 'bx_stories_video_poster_big', 'bx_stories_video_mp4', 'bx_stories_video_mp4_hd');
+DELETE FROM `sys_transcoder_videos_files` WHERE `transcoder_object` IN('bx_stories_video_mp4', 'bx_stories_video_mp4_hd');
+
+
+-- FORMS
+DELETE FROM `sys_objects_form` WHERE `module` = 'bx_stories';
+DELETE FROM `sys_form_displays` WHERE `module` = 'bx_stories';
+DELETE FROM `sys_form_inputs` WHERE `module` = 'bx_stories';
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` LIKE 'bx_stories%';
+
+
+-- COMMENTS
+DELETE FROM `sys_objects_cmts` WHERE `Name` LIKE 'bx_stories%';
+
+
+-- VOTES
+DELETE FROM `sys_objects_vote` WHERE `Name` LIKE 'bx_stories%';
+
+
+-- SCORES
+DELETE FROM `sys_objects_score` WHERE `name` LIKE 'bx_stories%';
+
+
+-- REPORTS
+DELETE FROM `sys_objects_report` WHERE `name` LIKE 'bx_stories%';
+
+
+-- VIEWS
+DELETE FROM `sys_objects_view` WHERE `name` LIKE 'bx_stories%';
+
+
+-- CONTENT INFO
+DELETE FROM `sys_objects_content_info` WHERE `name` IN ('bx_stories', 'bx_stories_cmts');
+
+DELETE FROM `sys_content_info_grids` WHERE `object` IN ('bx_stories');
+
+
+-- SEARCH EXTENDED
+DELETE FROM `sys_objects_search_extended` WHERE `module` = 'bx_stories';
+
+
+-- STUDIO: page & widget
+DELETE FROM `tp`, `tw`, `twb`, `tpw` 
+USING `sys_std_pages` AS `tp` LEFT JOIN `sys_std_widgets` AS `tw` ON `tp`.`id` = `tw`.`page_id` LEFT JOIN `sys_std_widgets_bookmarks` AS `twb` ON `tw`.`id` = `twb`.`widget_id` LEFT JOIN `sys_std_pages_widgets` AS `tpw` ON `tw`.`id` = `tpw`.`widget_id`
+WHERE  `tp`.`name` = 'bx_stories';

+ 187 - 0
modules/boonex/stories/js/main.js

@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxStoriesMain(oOptions) {
+    this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjName = oOptions.sObjName == undefined ? 'oBxStoriesMain' : oOptions.sObjName;
+
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+
+    this._aHtmlIds = oOptions.aHtmlIds == undefined ? {} : oOptions.aHtmlIds;
+    this._oRequestParams = oOptions.oRequestParams == undefined ? {} : oOptions.oRequestParams;
+
+    this._iDuration = oOptions.iDuration == undefined ? 0 : oOptions.iDuration;
+    this._iPlayHandle = 0;
+
+    var $this = this;
+    $(document).ready(function() {
+    	$this.init();
+    });
+}
+
+BxStoriesMain.prototype.init = function() {
+    $('.bx-stories-unit-images').flickity({
+        cellSelector: '.bx-stories-unit-image',
+        cellAlign: 'left',
+        imagesLoaded: true,
+        wrapAround: true,
+        pageDots: false
+    });
+};
+
+BxStoriesMain.prototype.play = function(oElement, iId) {
+    var $this = this;
+    var oDate = new Date();
+
+    this.loadingInBlock(oElement, true);
+
+    $.get(
+        this._sActionsUrl + 'play/' + iId, 
+        {
+            _t: oDate.getTime()
+        },
+        function(oData) {
+            $this.loadingInBlock(oElement, false);
+
+            processJsonData(oData);
+        },
+        'json'
+    );
+
+    return false;
+};
+
+BxStoriesMain.prototype.playInit = function() {
+    const $this = this;
+
+    const oVideos = document.querySelectorAll('.bx-popup-applied .bx-stories-play video');
+
+    if(oVideos)
+        oVideos.forEach((oVideo) => {
+            oVideo.addEventListener("play", (event) => {
+                $this.playStop();
+            });
+            oVideo.addEventListener("ended", (event) => {
+                $this.showNext();
+                $this.playStart();
+            });
+        });
+
+    var oVideo = $('.bx-popup-applied .bx-stories-play .bx-stories-pl-media:visible video');
+    if(oVideo.length)
+        oVideo.get(0).play();
+    else
+        this.playStart();
+};
+
+BxStoriesMain.prototype.playDestroy = function() {
+    this.playStop();
+};
+
+BxStoriesMain.prototype.playStart = function() {
+    var $this = this;
+
+    if(this._iPlayHandle)
+        this.playStop();
+
+    this._iPlayHandle = setInterval(function() {
+        $this.showNext();
+    }, 1000 * this._iDuration);
+};
+
+BxStoriesMain.prototype.playStop = function() {
+    if(this._iPlayHandle)
+        clearInterval(this._iPlayHandle);
+};
+
+BxStoriesMain.prototype.showNext = function() {
+    var oPlayer = $('.bx-popup-applied .bx-stories-play');
+
+    var oPointer = oPlayer.find('.bx-stories-pp-pointer');
+    if(oPointer) {
+        var iLeft = parseInt(oPointer.css('left'));
+        if(!iLeft)
+            iLeft = 0;
+
+        oPointer.css('left', iLeft + oPointer.width());
+    }
+
+    var oNext = oPlayer.find('.bx-stories-pl-media:visible').hide().next();
+    if(oNext.length)
+        oNext.show({complete: function() {
+            var oVideo = $('.bx-popup-applied .bx-stories-play .bx-stories-pl-media:visible video');
+            if(oVideo.length)
+                oVideo.get(0).play();
+        }});
+    else
+        $('.bx-popup-applied:visible').dolPopupHide();
+};
+
+BxStoriesMain.prototype.editMedia = function(oButton, iId) {
+    var $this = this;
+    var oDate = new Date();
+
+    this.loadingInButton(oButton, true);
+
+    $.get(
+        this._sActionsUrl + 'edit_media/' + iId, 
+        {
+            _t: oDate.getTime()
+        },
+        function(oData) {
+            $this.loadingInButton(oButton, false);
+
+            processJsonData(oData);
+        },
+        'json'
+    );
+};
+
+BxStoriesMain.prototype.onEditMedia = function(oData) {
+    if(oData && oData.content != undefined)
+        $('#' + this._oHtmlIds['subentry_votes'] + oData.content.subentry_id).html(oData.content.votes_formated);
+};
+
+BxStoriesMain.prototype.deleteMedia = function(oButton, iId) {
+    var $this = this;
+
+    bx_confirm(_t('_Are_you_sure'), function() {
+        var oDate = new Date();
+        $this.loadingInButton(oButton, true);
+
+        $.get(
+            $this._sActionsUrl + 'delete_media/' + iId, 
+            {
+                _t: oDate.getTime()
+            },
+            function(oData) {
+                $this.loadingInButton(oButton, false);
+
+                processJsonData(oData);
+            },
+            'json'
+        );
+    });
+};
+
+BxStoriesMain.prototype.loadingInButton = function(e, bShow) {
+    if($(e).length)
+        bx_loading_btn($(e), bShow);
+    else
+        bx_loading($('body'), bShow);
+};
+
+BxStoriesMain.prototype.loadingInBlock = function(e, bShow) {
+    var oParent = $(e).length ? $(e).parents('.bx-db-container:first') : $('body'); 
+    bx_loading(oParent, bShow);
+};
+
+/** @} */

+ 21 - 0
modules/boonex/stories/js/manage_tools.js

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

+ 18 - 0
modules/boonex/stories/request.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Stories Stories
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
+
+check_logged();
+
+BxBaseModTextRequest::processAsAction($GLOBALS['aModule'], $GLOBALS['aRequest']);
+
+/** @} */

+ 236 - 0
modules/boonex/stories/template/css/main.css

@@ -0,0 +1,236 @@
+/* flexbox */
+.bx-stories-medias-wrapper {
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: -ms-flexbox;
+    display: flex;
+
+    /* makes all items on a row equal height */
+    -webkit-box-align: stretch;
+    -webkit-align-items: stretch;
+    -ms-flex-align: stretch;
+    align-items: stretch;
+
+    /* wrap onto the next line rather than stretching or shrinking */
+    -webkit-flex-wrap: wrap;
+    -ms-flex-wrap: wrap;
+    flex-wrap: wrap;
+
+    /* tells flexbox to start items from the left */
+    -webkit-box-pack: start;
+    -ms-flex-pack: start;
+    plex-pack: start;
+    -webkit-justify-content: flex-start;
+    justify-content: flex-start;
+}
+
+.bx-stories-medias-wrapper .bx-stories-media-wrapper {
+    -webkit-box-flex: 0;
+
+    -webkit-flex: 0 0 100%;
+    -ms-flex: 0 0 100%;
+    flex: 0 0 100%;
+
+    max-width: 100%;
+}
+
+.bx-stories-media-wrapper .bx-stories-unit-size {
+    width: 100%;
+    height: auto;
+    min-height: 10rem;
+    object-fit: cover;
+}
+	
+/* MEDIA: phone2 */
+
+.bx-media-phone2 .bx-layout-column-half .bx-stories-medias-wrapper .bx-stories-media-wrapper,
+.bx-media-phone2 .bx-layout-column-thin .bx-stories-medias-wrapper .bx-stories-media-wrapper {
+    -webkit-flex: 0 0 49.8%;
+    -ms-flex: 0 0 49.8%;
+    flex: 0 0 49.8%;
+    
+    max-width: 49.8%;
+}
+
+/* MEDIA: tablet2 */
+
+.bx-media-tablet2 #sys_search_results .bx-stories-medias-wrapper .bx-stories-media-wrapper,
+.bx-media-tablet2 .bx-layout-column-wide .bx-stories-medias-wrapper .bx-stories-media-wrapper,
+.bx-media-tablet2 .bx-layout-column-fullwidth .bx-stories-medias-wrapper .bx-stories-media-wrapper {
+    -webkit-flex: 0 0 49.8%;
+    -ms-flex: 0 0 49.8%;
+    flex: 0 0 49.8%;
+    
+    max-width: 49.8%;
+}
+
+.bx-media-tablet2 .bx-layout-column-wide .bx-stories-medias-wrapper .bx-stories-media-wrapper .bx-stories-unit-size {
+    width: 100%;
+    height: auto;
+}
+
+.bx-media-tablet2 #sys_search_results .bx-stories-medias-wrapper .bx-stories-media-wrapper .bx-stories-unit-size,
+.bx-media-tablet2 .bx-layout-column-fullwidth .bx-stories-medias-wrapper .bx-stories-media-wrapper .bx-stories-unit-size {
+    height: 18.0rem;
+}
+
+/* MEDIA: desktop */
+
+.bx-media-desktop .bx-layout-column-wide .bx-stories-medias-wrapper .bx-stories-media-wrapper {
+    -webkit-flex: 0 0 49.8%;
+    -ms-flex: 0 0 49.8%;
+    flex: 0 0 49.8%;
+    
+    max-width: 49.8%;
+}
+
+.bx-media-desktop .bx-layout-column-wide .bx-stories-medias-wrapper .bx-stories-media-wrapper .bx-stories-unit-size {
+    width: 100%;
+    height: auto;
+}
+    
+.bx-media-desktop #sys_search_results .bx-stories-medias-wrapper .bx-stories-media-wrapper,
+.bx-media-desktop .bx-layout-column-fullwidth .bx-stories-medias-wrapper .bx-stories-media-wrapper {
+    -webkit-flex: 0 0 33.25%;
+    -ms-flex: 0 0 33.25%;
+    flex: 0 0 33.25%;
+    
+    max-width: 33.25%;
+}
+
+.bx-media-desktop #sys_search_results .bx-stories-medias-wrapper .bx-stories-media-wrapper .bx-stories-unit-size,
+.bx-media-desktop .bx-layout-column-half .bx-stories-medias-wrapper .bx-stories-media-wrapper .bx-stories-unit-size,
+.bx-media-desktop .bx-layout-column-fullwidth .bx-stories-medias-wrapper .bx-stories-media-wrapper .bx-stories-unit-size {
+    height: 18.0rem;
+}
+
+.bx-search-result-block .bx-base-text-unit-gallery-wrapper {
+	display: block;
+}
+.bx-search-result-block.bx-base-text-unit-gallery-wrapper .bx-base-text-unit.bx-base-text-unit-gallery {
+	display: inline-block;
+}
+.bx-search-result-block.bx-stories-media .bx-search-result-content {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+    flex-wrap: wrap;
+
+    margin: -0.5rem;
+}
+
+.bx-stories-media-thumb {
+    position: relative;    
+}
+.bx-stories-media-thumb a {
+    position: relative;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-justify-content: center;
+    justify-content: center;
+    -webkit-align-items: center;
+    align-items: center;
+}
+.bx-stories-media-play {
+    position: absolute;
+
+    width: 3rem;
+    height: 3rem;
+
+    background-color: rgba(255, 255, 255, 0.3);
+
+    text-align: center;
+    line-height: 3rem;
+    font-size: 1.5rem;
+}
+.bx-stories-media-duration {
+    position: absolute;
+    right: 10px;
+    bottom: 10px;
+
+    background-color: rgba(255, 255, 255, 0.9);
+}
+.bx-stories-media-caption {
+    white-space:nowrap;
+    overflow:hidden;
+    text-overflow:ellipsis;
+}
+.bx-stories-media-actions {
+    text-align: center;
+}
+.bx-base-text-unit-ext .bx-stories-unit-text-cont {
+    text-align: left;
+}
+.bx-stories-unit-images {
+    white-space:nowrap;
+    width:100%;
+    overflow: hidden;
+}
+
+.bx-stories-unit-image {
+    display: inline-block;
+    margin-right: 0.125rem;
+}
+
+.bx-stories-unit-image,
+.bx-stories-unit-image img {
+    height: 11.25rem;
+}
+.bx-stories-unit-image {
+    display: -webkit-inline-flex;
+    display: inline-flex;
+    -webkit-justify-content: center;
+    justify-content: center;
+    -webkit-align-items: center;
+    align-items: center;
+}
+.bx-base-text-unit-gallery .bx-stories-unit-images-cont {
+    padding: 0.125rem 0.125rem 0 0.125rem;
+}
+.bx-base-text-unit-gallery .bx-stories-unit-text-cont {
+    line-height: 150%;
+}
+.bx-base-text-unit-gallery .bx-stories-unit-text-cont .bx-base-text-unit-title {
+    text-align: left;
+}
+
+.bx-stories-media-file {
+    text-align: center;    
+}
+
+.bx-stories-media-file img,
+.bx-stories-media-file video {
+    max-width:100%;
+}
+
+.bx-stories-media-title {
+    position:relative;
+    padding-right:6rem;
+}
+
+.bx-stories-media-title h1, 
+.bx-stories-media-title h2, 
+.bx-stories-media-title p {
+    margin:0;
+}
+
+.bx-stories-media-controls {
+    position:absolute;
+    top:0;
+    right:0;
+}
+
+/*--- Play popup ---*/
+.bx-stories-play {
+    width: 20rem;
+}
+
+.bx-stories-p-list .bx-stories-pl-media {
+    display: none;
+}
+.bx-stories-p-list .bx-stories-pl-media:first-child {
+    display: flex;
+}
+.bx-stories-pl-media {
+    max-width: 18rem;
+}

+ 1 - 0
modules/boonex/stories/template/embed.html

@@ -0,0 +1 @@
+<iframe width="300" height="230" src="__url__" frameborder="0" allowfullscreen></iframe>

+ 27 - 0
modules/boonex/stories/template/form_ghost_template.html

@@ -0,0 +1,27 @@
+<div id="bx-uploader-file-{storage_object}-{file_id}" class="bx-uploader-ghost mt-2 flex items-start">
+    <div class="bx-uploader-ghost-cnt">
+        <a class="bx-anchor-invisible" name="story-media-{file_id}"></a>
+        <input type="hidden" name="__name__[]" value="{file_id}" />
+        <div class="bx-base-general-icon-wrapper">
+            <img src="{file_icon}" class="bx-def-round-corners bx-base-general-icon bx-base-general-icon-{file_id}" />
+        </div>
+        <span class="bx-base-general-uploader-ghost">
+            <a class="bx-btn bx-btn-small bx-def-margin-sec-right" href="javascript:void(0);" title="<bx_text:_sys_txt_form_entry_input_picture_delete />" onclick="bx_base_general_delete_ghost('{file_id}', '{file_url}', '{file_icon}', ['__editor_id__'], {js_instance_name});">
+                <bx_image_auto:times />
+            </a>
+            <a class="bx-btn bx-btn-small mr-2" href="javascript:void(0);" title="<bx_text:_sys_txt_form_entry_input_picture_copy />" onclick="bx_copy_to_clipboard('{file_url}');">
+                <bx_image_auto:copy />
+            </a>
+        </span>
+    </div>
+    <input placeholder="<bx_text:_bx_stories_form_entry_file_title />" class="bx-def-font-inputs bx-form-input-text block w-full py-2 px-3 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm bg-white dark:bg-gray-900 placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-2 focus:text-gray-900 dark:focus:text-gray-100 focus:ring-blue-500 focus:border-opacity-70 focus:ring-opacity-20 focus:border-blue-500 text-sm text-gray-700 dark:text-gray-300 appearance-none" type="text" value="{file_title_attr}" name="title-{file_id}" />
+    <bx_if:set_thumb>
+        <span class="bx-base-general-use-as-thumb">
+            <input type="checkbox" name="__name_thumb__[]" value="{file_id}" onclick="bx_base_general_select_thumb(this)" id="__name_thumb__-{file_id}" /> 
+            <label for="__name_thumb__-{file_id}"><bx_text:_sys_txt_form_entry_input_picture_use_as_thumb /></label>
+        </span>
+    </bx_if:set_thumb>
+</div>
+<script>
+    $('#bx-uploader-file-{storage_object}-{file_id} .bx-base-general-use-as-thumb input[value="__thumb_id__"]').attr('checked', true);
+</script>

+ 40 - 0
modules/boonex/stories/template/images/icons/std-icon.svg

@@ -0,0 +1,40 @@
+<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_935_6804)">
+<path d="M160 0C281.326 0 320 38.6737 320 160C320 281.326 281.326 320 160 320C38.6736 320 0 281.326 0 160C0 38.6737 38.6736 0 160 0Z" fill="url(#paint0_linear_935_6804)"/>
+<path d="M160 2C220.573 2 259.85 11.6833 284.083 35.9168C308.317 60.1504 318 99.4272 318 160C318 220.573 308.317 259.85 284.083 284.083C259.85 308.317 220.573 318 160 318C99.4272 318 60.1504 308.317 35.9168 284.083C11.6833 259.85 2 220.573 2 160C2 99.4272 11.6833 60.1504 35.9168 35.9168C60.1504 11.6833 99.4272 2 160 2Z" stroke="#0F172A" stroke-opacity="0.2" stroke-width="4"/>
+<g clip-path="url(#clip1_935_6804)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M81.9394 81.0474C79.5575 84.9494 83.9695 89.1266 88.2974 87.6542C104.079 82.2851 124.353 80.0001 150 80.0001C233.412 80.0001 260 104.171 260 180V180C260 183.888 264.49 184.914 265.521 181.165C268.63 169.855 270 156.245 270 140C270 71.7539 245.829 50 170 50C122.941 50 95.7774 58.3782 81.9394 81.0474Z" fill="url(#paint1_linear_935_6804)"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M50 180C50 111.754 74.1711 90 150 90C225.829 90 250 111.754 250 180C250 248.246 225.829 270 150 270C74.1711 270 50 248.246 50 180ZM147.679 150C155.377 136.667 174.623 136.667 182.321 150L216.962 210C224.66 223.333 215.037 240 199.641 240H130.359C114.963 240 105.34 223.333 113.038 210L147.679 150ZM105 170C118.807 170 130 158.807 130 145C130 131.193 118.807 120 105 120C91.1929 120 80 131.193 80 145C80 158.807 91.1929 170 105 170Z" fill="url(#paint2_linear_935_6804)"/>
+<path d="M156.34 155C160.189 148.333 169.811 148.333 173.66 155L208.301 215C212.15 221.667 207.339 230 199.641 230H130.359C122.661 230 117.85 221.667 121.699 215L156.34 155Z" fill="url(#paint3_linear_935_6804)"/>
+<circle cx="105" cy="145" r="15" fill="url(#paint4_linear_935_6804)"/>
+</g>
+</g>
+<defs>
+<linearGradient id="paint0_linear_935_6804" x1="160" y1="0" x2="160" y2="320" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F8FAFC"/>
+<stop offset="1" stop-color="#E2E8F0"/>
+</linearGradient>
+<linearGradient id="paint1_linear_935_6804" x1="175.635" y1="50" x2="175.635" y2="183.504" gradientUnits="userSpaceOnUse">
+<stop stop-color="#7DD3FC"/>
+<stop offset="1" stop-color="#0EA5E9"/>
+</linearGradient>
+<linearGradient id="paint2_linear_935_6804" x1="150" y1="90" x2="150" y2="270" gradientUnits="userSpaceOnUse">
+<stop stop-color="#60A5FA"/>
+<stop offset="1" stop-color="#2563EB"/>
+</linearGradient>
+<linearGradient id="paint3_linear_935_6804" x1="165" y1="140" x2="165" y2="260" gradientUnits="userSpaceOnUse">
+<stop stop-color="#34D399"/>
+<stop offset="1" stop-color="#059669"/>
+</linearGradient>
+<linearGradient id="paint4_linear_935_6804" x1="105" y1="130" x2="105" y2="160" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FB923C"/>
+<stop offset="1" stop-color="#EA580C"/>
+</linearGradient>
+<clipPath id="clip0_935_6804">
+<rect width="320" height="320" fill="white"/>
+</clipPath>
+<clipPath id="clip1_935_6804">
+<rect width="240" height="240" fill="white" transform="translate(40 40)"/>
+</clipPath>
+</defs>
+</svg>

+ 20 - 0
modules/boonex/stories/template/media_edit.html

@@ -0,0 +1,20 @@
+<div class="bx-stories-media-edit">
+    <div class="bx-stories-media-edit-cnt bx-def-padding">
+        __form__
+        <script language="javascript">
+            $(document).ready(function () {
+                $("#__form_id__").ajaxForm({ 
+                    dataType: "json",
+                    beforeSubmit: function (formData, jqForm, options) {
+                        bx_loading($("#__form_id__"), true);
+                    },
+                    success: function (oData) {
+                        $(".bx-popup-applied:visible").dolPopupHide();
+
+                        processJsonData(oData);
+                    }
+                });
+            });
+        </script>
+    </div>
+</div>

+ 26 - 0
modules/boonex/stories/template/play.html

@@ -0,0 +1,26 @@
+<div class="bx-stories-play">
+    <div class="bx-stories-play-cnt bx-def-padding">
+        <div class="bx-stories-p-progress bx-def-border-block flex flex-nowrap w-full h-1 rounded">
+            <div class="bx-stories-pp-pointer relative h-full bg-gray-400 dark:bg-gray-500 rounded" style="width:__width__%"></div>
+        </div>
+        <div class="bx-stories-p-list mt-4">
+            <bx_repeat:media>
+                <div class="bx-stories-pl-media">
+                    <div class="bx-stories-plm-cnt flex flex-col items-center w-full">
+                        <bx_if:title>
+                            <div class="bx-stories-plm-title mb-2 text-2xl">__title__</div>
+                        </bx_if:title>
+                        <div class="bx-stories-m-content flex-1">
+                            <bx_if:image>
+                                <img class="bx-stories-unit-size" src="__url_img__" alt="__title_attr__" />
+                            </bx_if:image>
+                            <bx_if:video>
+                                <div class="bx-stories-mt-video">__video__</div>
+                            </bx_if:video>
+                        </div>
+                    </div>
+                </div>
+            </bx_repeat:media>
+        </div>
+    </div>
+</div>

+ 28 - 0
modules/boonex/stories/template/unit.html

@@ -0,0 +1,28 @@
+<div class="bx-base-text-unit bx-base-text-unit-ext bx-def-box bx-def-box-round-corners bx-def-color-bg-box mb-3 md:mb-4 lg:mb-6 text-left">
+    <div class="bx-stories-unit-text-cont px-4 pt-4 pb-2">
+        <div class="bx-base-text-unit-title">
+            <a href="__content_url__">__title__</a>
+        </div>
+        <bx_if:meta>
+            <div class="bx-base-text-unit-info mt-1 mb-2">
+                <div class="bx-base-general-unit-meta">__meta__</div>
+            </div>
+        </bx_if:meta>
+        <div class="bx-base-text-unit-summary bx-clearfix">__summary__</div> 
+    </div>
+    <div class="bx-stories-unit-images-cont px-1 pb-4">
+        <div class="bx-stories-unit-images">
+            <bx_repeat:browse>
+                <a class="bx-stories-unit-image" title="__title_attr__" href="__url__">
+                    <img alt="__title_attr__" src="__img_url__" />
+                    <bx_if:show_play>
+                        <div class="bx-stories-media-play rounded"><i class="sys-icon play"></i></div>
+                    </bx_if:show_play>
+                    <bx_if:show_duration>
+                        <div class="bx-stories-media-duration px-2 py-1 border rounded text-base">__duration__</div>
+                    </bx_if:show_duration>
+                </a>
+            </bx_repeat:browse>
+        </div> 
+    </div> 
+</div>

+ 17 - 0
modules/boonex/stories/template/unit_gallery.html

@@ -0,0 +1,17 @@
+<div id="__html_id__" class="bx-base-text-unit bx-base-text-unit-gallery bx-def-gal-unit-size p-2">
+    <div class="bx-base-text-unit-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box mb-3 md:mb-4 lg:mb-6 text-left">
+        <div class="bx-stories-unit-images-cont">
+            <div class="bx-stories-unit-images rounded-t-2xl overflow-hidden">
+                <bx_repeat:browse><a class="bx-stories-unit-image" title="__title_attr__" href="__url__"><img alt="__title_attr__" src="__img_url__" /></a></bx_repeat:browse>
+            </div> 
+        </div>
+        <div class="bx-stories-unit-text-cont px-4 py-2 text-center">
+            <div class="bx-base-text-unit-title">
+                <a href="__content_url__">__title__</a>
+            </div>
+            <div class="bx-base-text-unit-info">
+                <bx_if:meta><div class="bx-base-general-unit-meta">__meta__</div></bx_if:meta>
+            </div>
+        </div>
+    </div>
+</div>

+ 16 - 0
modules/boonex/stories/template/unit_media.html

@@ -0,0 +1,16 @@
+<div class="__class__ bx-stories-media-wrapper sm:w-full md:w-1/2 lg:w-1/3 p-2 box-border">
+    <div class="bx-stories-media-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box flex flex-col h-full rounded-tl-md rounded-tr-md overflow-hidden">
+        <div class="bx-stories-media-thumb bx-stories-unit-size flex items-center flex-1 h-48">
+            <bx_if:image>
+                <img class="bx-stories-unit-size h-48" src="__url_img__" alt="__title_attr__" />
+            </bx_if:image>
+            <bx_if:video>
+                <div class="bx-stories-mt-video w-full">__video__</div>
+            </bx_if:video>
+        </div>
+        <div class="bx-base-text-unit-title bx-stories-media-caption m-2">
+            <a href="__url__" title="__title_attr__">__title__</a>
+        </div>
+        <div class="bx-stories-media-actions mx-2 mb-2">__actions__</div>
+    </div>
+</div>

+ 23 - 0
modules/boonex/stories/template/unit_media_gallery.html

@@ -0,0 +1,23 @@
+<div class="__class__ bx-stories-media-wrapper sm:w-full md:w-1/2 lg:w-1/3 p-2 box-border">
+    <div class="bx-stories-media-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box">
+        <div class="bx-stories-media-thumb bx-stories-unit-size h-48 rounded-tl-md rounded-tr-md overflow-hidden">
+            <bx_if:image>
+                <a href="__url__" title="__title_attr__">
+                    <img class="bx-stories-unit-size h-48" src="__url_img__" alt="__title_attr__" />
+                </a>
+            </bx_if:image>
+            <bx_if:video>
+                <a href="__url__" title="__title_attr__">
+                    <img class="bx-stories-unit-size h-48" src="__url_img__" alt="__title_attr__" />
+                    <div class="bx-stories-media-play rounded-md"><i class="sys-icon play"></i></div>
+                </a>
+                <bx_if:show_duration>
+                    <div class="bx-stories-media-duration px-2 py-1 border text-sm rounded-md">__duration__</div>
+                </bx_if:show_duration>
+            </bx_if:video>
+        </div>
+        <div class="bx-base-text-unit-title bx-stories-media-caption m-2">
+            <a href="__url__" title="__title_attr__">__title__</a>
+        </div>
+    </div>
+</div>

+ 18 - 0
modules/boonex/stories/template/unit_showcase.html

@@ -0,0 +1,18 @@
+<div class="__class__ bx-base-text-unit bx-base-text-unit-gallery bx-def-gal-unit-size p-2">
+    <div class="bx-base-text-unit-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box mb-3 md:mb-4 lg:mb-6 text-left">
+        <div class="bx-stories-unit-images-cont">
+            <bx_if:thumb>
+                <a href="__content_url__" <bx_if:show_thumb_onclick>onclick="javascript:__content_onclick__"</bx_if:show_thumb_onclick> title="__summary_attr__">
+                    <div class="shrink-0 m-1">
+                        <img class="bx-def-round-corners aspect-video object-cover bg-cover w-full" alt="__title__" style="background-image:url(__gallery_url__); __image_settings__" src="<bx_icon_url:spacer.gif />"  />
+                    </div>
+                </a>
+            </bx_if:thumb>
+            <bx_if:no_thumb>
+                <div class="bx-def-gal-img-column shrink-0 m-1">
+                    <div class="bx-base-text-unit-no-thumb bx-def-round-corners flex flex-col items-center justify-center aspect-video p-4 bg-gradient-to-b from-red-400 to-red-500 box-border"></div>
+                </div>
+            </bx_if:no_thumb>
+        </div>
+    </div>
+</div>