Răsfoiți Sursa

Merge branch 'master' of https://github.com/unaio/una

roman.lesnikov@gmail.com 3 ani în urmă
părinte
comite
21d46d1f3a

+ 9 - 9
inc/classes/BxDolTemplate.php

@@ -1528,7 +1528,7 @@ class BxDolTemplate extends BxDolFactory implements iBxDolSingleton
     {
         $sUrl = $this->getCssUrl($sName, $sCheckIn);
         if(!empty($sUrl))
-            $sUrl = $this->_addRevision($sUrl);
+            $sUrl = $this->addRevision($sUrl);
 
         return $sUrl;
     }
@@ -1564,7 +1564,7 @@ class BxDolTemplate extends BxDolFactory implements iBxDolSingleton
     {
         $sUrl = $this->getJsUrl($sName);
         if(!empty($sUrl))
-            $sUrl = $this->_addRevision($sUrl);
+            $sUrl = $this->addRevision($sUrl);
 
         return $sUrl;
     }
@@ -2165,7 +2165,7 @@ class BxDolTemplate extends BxDolFactory implements iBxDolSingleton
 
             list($sUrl) = $mixedFile;
 
-            $aFilesLocated[] = $this->_addRevision($sUrl);
+            $aFilesLocated[] = $this->addRevision($sUrl);
         }
         $sFilesLocated = json_encode($aFilesLocated);
 
@@ -2369,7 +2369,7 @@ class BxDolTemplate extends BxDolFactory implements iBxDolSingleton
 
             list($sUrl) = $mixedFile;
 
-            $aFilesLocated[] = $this->_addRevision($sUrl);
+            $aFilesLocated[] = $this->addRevision($sUrl);
         }
         $sFilesLocated = json_encode($aFilesLocated);
 
@@ -2741,7 +2741,7 @@ class BxDolTemplate extends BxDolFactory implements iBxDolSingleton
 
             $sFileUrl = $aFile['url'];
             if(!$this->{'_b' . $sUpcaseType . 'Cache'})
-                $sFileUrl = $this->_addRevision($sFileUrl);
+                $sFileUrl = $this->addRevision($sFileUrl);
 
             if($bWrap)
                 $mixedResult .= $this->$sMethodWrap($sFileUrl);
@@ -2791,7 +2791,7 @@ class BxDolTemplate extends BxDolFactory implements iBxDolSingleton
                     ]);
 
                     if($bDynamic)
-                        $sResult .= $this->$sMethodWrap($this->_addRevision($sUrl));
+                        $sResult .= $this->$sMethodWrap($this->addRevision($sUrl));
                     else {
                         $bFound = false;
                         $aSearchIn = $bSystem ? $this->aPage[$sArrayKey] : array_merge($this->aPage[$sType . '_system'], $this->aPage[$sArrayKey]);
@@ -3417,7 +3417,7 @@ class BxDolTemplate extends BxDolFactory implements iBxDolSingleton
      * 
      * @return integer number
      */
-    function _getRevision()
+    public function getRevision()
     {
         return (int)getParam('sys_revision');
     }
@@ -3427,9 +3427,9 @@ class BxDolTemplate extends BxDolFactory implements iBxDolSingleton
      * 
      * @return string with URL 
      */
-    function _addRevision($sUrl)
+    public function addRevision($sUrl)
     {
-        return bx_append_url_params($sUrl, ['rev' => $this->_getRevision()]);
+        return bx_append_url_params($sUrl, ['rev' => $this->getRevision()]);
     }
 
     /**

+ 2 - 2
inc/js/classes/BxDolForm.js

@@ -84,8 +84,8 @@ BxDolForm.prototype.init = function()
         if(!sHref || (sOnclick != undefined && sOnclick.trim().length > 0))
             return;
 
-        sHref = sHref.trim();
-        if(!sHref || sHref == 'javascript:void(0)')
+        var oRegExp = new RegExp('^' + bx_get_regexp('url') + '$', 'i');
+        if(!sHref.trim().match(oRegExp))
             return;
 
         event.preventDefault();

+ 12 - 0
inc/js/functions.js

@@ -1505,6 +1505,18 @@ function bx_regexp_escape(s)
         .replace(/[|\\{}()[\]^$+*?.]/mg, '\\$&')
         .replace(/-/mg, '\\x2d');
 }
+
+function bx_get_regexp(sType) 
+{
+    var o = {
+        tag:"(<([^>]+bx-tag[^>]+)>)",
+        mention: "(<([^>]+bx-tag[^>]+)>)",
+        url: "(([A-Za-z]{3,9}:(?:\\/\\/)?)(?:[\\-;:&=\\+\\$,\\w]+@)?[A-Za-z0-9\\.\\-]+|(?:www\\.|[\\-;:&=\\+\\$,\\w]+@)[A-Za-z0-9\\.\\-]+)((?:\\/[\\+~%#\\/\\.\\w\\-_!\\(\\)]*)?\\??(?:[\\-\\+=&;%@\\.\\w_]*)#?(?:[\\.\\!\\/\\w]*))?"
+    };
+
+    return o[sType];
+}
+
 function bx_process_links()
 {
     // process links in container

+ 16 - 7
install/sql/system.sql

@@ -753,18 +753,27 @@ INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `ex
 
 
 --
--- CATEGORY (HIDDEN): PWA
+-- CATEGORY (HIDDEN): PWA Manifest
 --
-INSERT INTO `sys_options_categories`(`type_id`, `name`, `caption`, `hidden`, `order`) VALUES (@iTypeId, 'pwa', '_adm_stg_cpt_category_pwa', 1, 2);
+INSERT INTO `sys_options_categories`(`type_id`, `name`, `caption`, `hidden`, `order`) VALUES (@iTypeId, 'pwa_manifest', '_adm_stg_cpt_category_pwa_manifest', 1, 2);
 SET @iCategoryId = LAST_INSERT_ID();
 
 INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
-(@iCategoryId, 'sys_pwa_name', '_adm_stg_cpt_option_sys_pwa_name', '', 'digit', '', '', '', 1),
-(@iCategoryId, 'sys_pwa_short_name', '_adm_stg_cpt_option_sys_pwa_short_name', '', 'digit', '', '', '', 2),
-(@iCategoryId, 'sys_pwa_description', '_adm_stg_cpt_option_sys_pwa_description', '', 'text', '', '', '', 3), 
-(@iCategoryId, 'sys_pwa_background_color', '_adm_stg_cpt_option_sys_pwa_background_color', '', 'digit', '', '', '', 4),
-(@iCategoryId, 'sys_pwa_theme_color', '_adm_stg_cpt_option_sys_pwa_theme_color', '', 'digit', '', '', '', 5);
+(@iCategoryId, 'sys_pwa_manifest_name', '_adm_stg_cpt_option_sys_pwa_manifest_name', '', 'digit', '', '', '', 1),
+(@iCategoryId, 'sys_pwa_manifest_short_name', '_adm_stg_cpt_option_sys_pwa_manifest_short_name', '', 'digit', '', '', '', 2),
+(@iCategoryId, 'sys_pwa_manifest_description', '_adm_stg_cpt_option_sys_pwa_manifest_description', '', 'text', '', '', '', 3), 
+(@iCategoryId, 'sys_pwa_manifest_background_color', '_adm_stg_cpt_option_sys_pwa_manifest_background_color', '', 'digit', '', '', '', 4),
+(@iCategoryId, 'sys_pwa_manifest_theme_color', '_adm_stg_cpt_option_sys_pwa_manifest_theme_color', '', 'digit', '', '', '', 5);
 
+--
+-- CATEGORY (HIDDEN): PWA Service Worker
+--
+INSERT INTO `sys_options_categories`(`type_id`, `name`, `caption`, `hidden`, `order`) VALUES (@iTypeId, 'pwa_sw', '_adm_stg_cpt_category_pwa_sw', 1, 2);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+(@iCategoryId, 'sys_pwa_sw_cache', '_adm_stg_cpt_option_sys_pwa_sw_cache', '', 'text', '', '', '', 1), 
+(@iCategoryId, 'sys_pwa_sw_offline', '_adm_stg_cpt_option_sys_pwa_sw_offline', '', 'digit', '', '', '', 2);
 
 --
 -- Table structure for table `sys_options_mixes`

+ 5 - 3
manifest.json.php

@@ -18,13 +18,15 @@ $aContent = [
     'orientation' => 'portrait',
     'start_url' => parse_url(BX_DOL_URL_ROOT, PHP_URL_PATH),
     'display' => 'standalone',
-    'scope' => '/',
-    'background_color' => getParam('sys_pwa_background_color'),
-    'theme_color' => getParam('sys_pwa_theme_color')
+    'scope' => '/'
 ];
 
 $aContent['name'] = ($sName = getParam('sys_pwa_name')) != '' ? $sName : parse_url(BX_DOL_URL_ROOT, PHP_URL_HOST);
 $aContent['short_name'] = ($sShortName = getParam('sys_pwa_short_name')) != '' ? $sShortName : $aContent['name'];
+if(($sBackgroundColor = getParam('sys_pwa_background_color')) != '')
+    $aContent['background_color'] = $sBackgroundColor;
+if(($sThemeColor = getParam('sys_pwa_theme_color')) != '')
+    $aContent['theme_color'] = $sThemeColor;
 
 if(isLogged())
     $aContent['gcm_sender_id'] = '482941778795';

+ 7 - 4
modules/base/general/classes/BxBaseModGeneralModule.php

@@ -966,14 +966,17 @@ class BxBaseModGeneralModule extends BxDolModule
     /** 
      * @ref bx_base_general-browse_by_category "browse_by_category"
      */
-    public function serviceBrowseByCategory($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $bShowHeader = true)
+    public function serviceBrowseCategory($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $aParams = [])
     {
         $sType = 'category';
-        $iCategory = bx_process_input(bx_get('category'), BX_DATA_INT);
-        
+
+        $aParams = array_merge(['category' => bx_process_input(bx_get('category'), BX_DATA_INT)], $aParams);
+        if($sUnitView)
+            $aParams['unit_view'] = $sUnitView;
+
         return $this->_serviceBrowse($sType, $aParams, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
     }
-    
+
     /**
      * @page service Service Calls
      * @section bx_base_general Base General

+ 10 - 6
modules/base/text/classes/BxBaseModTextPageBrowse.php

@@ -17,13 +17,17 @@ class BxBaseModTextPageBrowse extends BxBaseModGeneralPageBrowse
     public function __construct($aObject, $oTemplate = false)
     {
         parent::__construct($aObject, $oTemplate);
-        
-        $iCategory = bx_process_input(bx_get('category'), BX_DATA_INT);
-        if(!empty($iCategory))
-            $this->addMarkers(array(
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(!empty($CNF['OBJECT_CATEGORY']) && ($iCategory = bx_get('category')) !== false) {
+            $iCategory = bx_process_input($iCategory, BX_DATA_INT);
+
+            $this->addMarkers([
                 'category_id' => $iCategory,
-                'category_name' => BxDolCategory::getObjectInstance($this->_oModule->_oConfig->CNF['OBJECT_CATEGORY'])->getCategoryTitle($iCategory),
-        ));
+                'category_name' => BxDolCategory::getObjectInstance($CNF['OBJECT_CATEGORY'])->getCategoryTitle($iCategory),
+            ]);
+        }
     }
 }
 

+ 22 - 9
modules/base/text/classes/BxBaseModTextVotePollAnswers.php

@@ -17,6 +17,9 @@ class BxBaseModTextVotePollAnswers extends BxTemplVoteLikes
     protected $_aObjectInfo;
     protected $_aPollInfo;
 
+    protected $_bContentInfo;
+    protected $_aContentInfo;
+
     protected $_bHiddenResults;
     protected $_bAnonymousVoting;
 
@@ -38,6 +41,11 @@ class BxBaseModTextVotePollAnswers extends BxTemplVoteLikes
         $this->_aObjectInfo = $this->_oModule->_oDb->getPollAnswers(array('type' => 'id', 'id' => $iId));
         $this->_aPollInfo = $this->_oModule->_oDb->getPolls(array('type' => 'answer_id', 'answer_id' => $iId));
 
+        $this->_aContentInfo = [];
+        if(!empty($this->_aPollInfo[$CNF['FIELD_POLL_CONTENT_ID']]))
+            $this->_aContentInfo = $this->_oModule->_oDb->getContentInfoById($this->_aPollInfo[$CNF['FIELD_POLL_CONTENT_ID']]);
+        $this->_bContentInfo = !empty($this->_aContentInfo) && is_array($this->_aContentInfo);
+
         $this->_bHiddenResults = $CNF['PARAM_POLL_HIDDEN_RESULTS'];
         $this->_bAnonymousVoting = $CNF['PARAM_POLL_ANONYMOUS_VOTING'];
 
@@ -97,17 +105,10 @@ class BxBaseModTextVotePollAnswers extends BxTemplVoteLikes
      */
     public function isAllowedVote($isPerformAction = false)
     {
-        if(!parent::isAllowedVote($isPerformAction))
+        if($this->_bContentInfo && $this->_oModule->checkAllowedView($this->_aContentInfo) !== CHECK_ACTION_RESULT_ALLOWED)
             return false;
 
-        $CNF = &$this->_oModule->_oConfig->CNF;
-
-        $iContentId = $this->_aPollInfo[$CNF['FIELD_POLL_CONTENT_ID']];
-        if(empty($iContentId))
-            return true;
-
-        $aContentInfo = $this->_oModule->_oDb->getContentInfoById($iContentId);
-        return $this->_oModule->checkAllowedView($aContentInfo) === CHECK_ACTION_RESULT_ALLOWED;
+        return parent::isAllowedVote($isPerformAction);
     }
 
     public function isAllowedVoteViewVoters($isPerformAction = false)
@@ -121,6 +122,18 @@ class BxBaseModTextVotePollAnswers extends BxTemplVoteLikes
     /**
      * Internal functions
      */
+    protected function _isAllowedVoteByObject($aObject)
+    {
+        /**
+         * If a poll wasn't attached to any content yet, 
+         * then we cannot check content's visibility.
+         */
+        if(!$this->_bContentInfo)
+            return true;
+
+        return parent::_isAllowedVoteByObject($this->_aContentInfo);
+    }
+
     protected function _getIconDo($bVoted)
     {
     	return $bVoted ?  'far dot-circle' : 'far circle';

+ 5 - 9
modules/base/text/js/links.js

@@ -20,13 +20,9 @@ function BxBaseModTextLinks(oOptions) {
     this._iLimitAttachLinks = oOptions.iLimitAttachLinks == undefined ? 0 : oOptions.iLimitAttachLinks;
     this._sLimitAttachLinksErr = oOptions.sLimitAttachLinksErr == undefined ? '' : oOptions.sLimitAttachLinksErr;
     this._oAttachedLinks = oOptions.oAttachedLinks == undefined ? {} : oOptions.oAttachedLinks;
-    
-    this._sPregTag = "(<([^>]+bx-tag[^>]+)>)";
-    this._sPregMention = "(<([^>]+bx-mention[^>]+)>)";
-    this._sPregUrl = "(([A-Za-z]{3,9}:(?:\\/\\/)?)(?:[\\-;:&=\\+\\$,\\w]+@)?[A-Za-z0-9\\.\\-]+|(?:www\\.|[\\-;:&=\\+\\$,\\w]+@)[A-Za-z0-9\\.\\-]+)((?:\\/[\\+~%#\\/\\.\\w\\-_!\\(\\)]*)?\\??(?:[\\-\\+=&;%@\\.\\w_]*)#?(?:[\\.\\!\\/\\w]*))?";
-    
+
     var $this = this;
-    
+
     $(document).ready(function () {
         $this.initFormPost($this._sFormId);
     });
@@ -81,13 +77,13 @@ BxBaseModTextLinks.prototype.parseContent = function(oForm, sData, bPerformAttac
 {
     var oExp, aMatch = null;
 
-    oExp = new RegExp(this._sPregTag , "ig");
+    oExp = new RegExp(bx_get_regexp('tag'), "ig");
     sData = sData.replace(oExp, '');
 
-    oExp = new RegExp(this._sPregMention , "ig");
+    oExp = new RegExp(bx_get_regexp('mention'), "ig");
     sData = sData.replace(oExp, '');
 
-    oExp = new RegExp(this._sPregUrl , "ig");
+    oExp = new RegExp(bx_get_regexp('url'), "ig");
     while(aMatch = oExp.exec(sData)) {
         var sUrl = aMatch[0].replace(/^(\s|(&nbsp;))+|(\s|(&nbsp;))+$/gm,'');
         if(!sUrl.length || this._oAttachedLinks[sUrl] != undefined || (this._iLimitAttachLinks != 0 && Object.keys(this._oAttachedLinks).length >= this._iLimitAttachLinks))

+ 11 - 23
modules/boonex/ads/classes/BxAdsModule.php

@@ -527,33 +527,21 @@ class BxAdsModule extends BxBaseModTextModule
     /**
      * @ref bx_ads-browse_category "browse_category"
      */
-    public function serviceBrowseCategory($iCategoryId = 0, $aParams = array())
+    public function serviceBrowseCategory($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $aParams = [])
     {
-        $sParamName = $sParamGet = 'category';
-
-        if(!$iCategoryId && bx_get($sParamGet) !== false)
-            $iCategoryId = bx_process_input(bx_get($sParamGet), BX_DATA_INT);
-
-        $bEmptyMessage = true;
-        if(isset($aParams['empty_message'])) {
-            $bEmptyMessage = (bool)$aParams['empty_message'];
-            unset($aParams['empty_message']);
-        }
+        $mixedResult = parent::serviceBrowseCategory($sUnitView, $bEmptyMessage, $bAjaxPaginate, $aParams);
+        if(empty($mixedResult['content']))
+            return $mixedResult;
 
-        $bAjaxPaginate = true;
-        if(isset($aParams['ajax_paginate'])) {
-            $bAjaxPaginate = (bool)$aParams['ajax_paginate'];
-            unset($aParams['ajax_paginate']);
-        }
+        $aCategory = $this->_oDb->getCategories([
+            'type' => 'id', 
+            'id' => !empty($aParams['category']) ? (int)$aParams['category'] : bx_process_input(bx_get('category'), BX_DATA_INT)
+        ]);
 
-        $aBlock = $this->_serviceBrowse ($sParamName, array_merge(array($sParamName => $iCategoryId), $aParams), BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
-        if(!empty($aBlock['content'])) {
-            $aCategory = $this->_oDb->getCategories(array('type' => 'id', 'id' => $iCategoryId));
-            if(!empty($aCategory['title']))
-                $aBlock['title'] = _t('_bx_ads_page_block_title_entries_by_category_mask', _t($aCategory['title']));
-        }
+        if(!empty($aCategory['title']))
+            $mixedResult['title'] = _t('_bx_ads_page_block_title_entries_by_category_mask', _t($aCategory['title']));
 
-        return $aBlock;
+        return $mixedResult;
     }
 
     public function serviceGetNotificationsData()

+ 1 - 1
modules/boonex/ads/install/sql/enable.sql

@@ -101,7 +101,7 @@ INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `lay
 
 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_ads_categories', 1, 'bx_ads', '', '_bx_ads_page_block_title_categories', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:15:"categories_list";s:6:"params";a:1:{i:0;a:1:{s:10:"show_empty";b:1;}}}', 0, 0, 1, 1),
-('bx_ads_categories', 2, 'bx_ads', '', '_bx_ads_page_block_title_entries_by_category', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:15:"browse_category";s:6:"params";a:2:{i:0;i:0;i:1;a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1, 1);
+('bx_ads_categories', 2, 'bx_ads', '', '_bx_ads_page_block_title_entries_by_category', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"bx_ads";s:6:"method";s:15:"browse_category";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, 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 

+ 4 - 4
modules/boonex/artificer/classes/BxArtificerTemplate.php

@@ -26,11 +26,11 @@ class BxArtificerTemplate extends BxBaseModGeneralTemplate
 
         switch($sType) {
             case 'head':
-                $this->addCss([
+                $this->addCssSystem([
                     'main.css'
                 ]);
 
-                $this->addJs([
+                $this->addJsSystem([
                     'utils.js'
                 ]);
                 $sResult .= $this->_oModule->_oTemplate->getJsCode('utils', [
@@ -45,9 +45,9 @@ class BxArtificerTemplate extends BxBaseModGeneralTemplate
                 break;
 
             case 'footer':
-                $sResult .= $this->addJs([
+                $this->addJsSystem([
                     'sidebar.js'
-                ], true);
+                ]);
                 break;
         }
 

+ 10 - 6
modules/boonex/english/data/langs/system/en.xml

@@ -1736,12 +1736,16 @@
     <string name="_adm_stg_cpt_option_sys_api_extended_units"><![CDATA[Use extended units]]></string>
     <string name="_adm_stg_cpt_option_sys_viewport_meta_tag"><![CDATA[Viewport meta tag]]></string>
 
-    <string name="_adm_stg_cpt_category_pwa"><![CDATA[Progressive Web Apps]]></string>
-    <string name="_adm_stg_cpt_option_sys_pwa_name"><![CDATA[Name]]></string>
-    <string name="_adm_stg_cpt_option_sys_pwa_short_name"><![CDATA[Short name]]></string>
-    <string name="_adm_stg_cpt_option_sys_pwa_description"><![CDATA[Description]]></string>
-    <string name="_adm_stg_cpt_option_sys_pwa_background_color"><![CDATA[Background color]]></string>
-    <string name="_adm_stg_cpt_option_sys_pwa_theme_color"><![CDATA[Theme color]]></string>
+    <string name="_adm_stg_cpt_category_pwa_manifest"><![CDATA[Manifest]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_name"><![CDATA[Name]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_short_name"><![CDATA[Short name]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_description"><![CDATA[Description]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_background_color"><![CDATA[Background color]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_theme_color"><![CDATA[Theme color]]></string>
+
+    <string name="_adm_stg_cpt_category_pwa_sw"><![CDATA[Service Worker]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_sw_cache"><![CDATA[URLs to cache on install (each in new line)]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_sw_offline"><![CDATA[Offline page]]></string>
 
     <string name="_adm_stg_cpt_category_sockets"><![CDATA[Sockets server]]></string>
     <string name="_adm_stg_cpt_option_sys_sockets_type"><![CDATA[Type]]></string>

+ 6 - 5
modules/boonex/forum/classes/BxForumModule.php

@@ -577,7 +577,7 @@ class BxForumModule extends BxBaseModTextModule
     /** 
      * @ref bx_forum-browse_category "browse_category"
      */
-    public function serviceBrowseCategory($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $bShowHeader = true)
+    public function serviceBrowseCategory($sUnitView = false, $bEmptyMessage = true, $bAjaxPaginate = true, $aParams = [])
     {
         $sType = 'category';
         $iCategory = bx_process_input(bx_get('category'), BX_DATA_INT);
@@ -586,10 +586,11 @@ class BxForumModule extends BxBaseModTextModule
         if(!empty($aCategory['visible_for_levels']) && !BxDolAcl::getInstance()->isMemberLevelInSet($aCategory['visible_for_levels']))
             return $bEmptyMessage ? MsgBox(_t('_sys_txt_access_denied')) : '';
 
-        if($sUnitView != 'table')   {
-            $aParams = array('category' => $iCategory);
-            if ($sUnitView)
+        if($sUnitView != 'table') {
+            $aParams = array_merge(['category' => $iCategory], $aParams);
+            if($sUnitView)
                 $aParams['unit_view'] = $sUnitView;
+
             return $this->_serviceBrowse($sType, $aParams, BX_DB_PADDING_DEF, $bEmptyMessage, $bAjaxPaginate);
         }
 
@@ -598,7 +599,7 @@ class BxForumModule extends BxBaseModTextModule
             'where' => array('fld' => 'cat', 'val' => $iCategory, 'opr' => '='),
             'empty_message' => $bEmptyMessage,
             'ajax_paginate' => $bAjaxPaginate
-        ), $bShowHeader);
+        ), !isset($aParams['show_header']) || (bool)$aParams['show_header'] === true);
     }
 
     /**

+ 6 - 5
modules/boonex/market/classes/BxMarketSearchResult.php

@@ -25,6 +25,7 @@ class BxMarketSearchResult extends BxBaseModTextSearchResult
             'searchFields' => array(),
             'restriction' => array(
                 'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+                'category' => array('value' => '', 'field' => 'cat', 'operator' => '='),
                 'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>'),
                 'except' => array('value' => '', 'field' => 'id', 'operator' => 'not in'),
                 'status' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
@@ -105,11 +106,11 @@ class BxMarketSearchResult extends BxBaseModTextSearchResult
                 break;
                 
              case 'category':
-                    $iCategory = (int)$aParams['category'];
-                    $this->addMarkers(array(
-                        'category_id' => $iCategory,
-                        'category_name' => BxDolCategory::getObjectInstance($CNF['OBJECT_CATEGORY'])->getCategoryTitle($iCategory),
-                    ));
+                $iCategory = (int)$aParams['category'];
+                $this->addMarkers([
+                    'category_id' => $iCategory,
+                    'category_name' => BxDolCategory::getObjectInstance($CNF['OBJECT_CATEGORY'])->getCategoryTitle($iCategory),
+                ]);
 
                 $this->aCurrent['restriction']['category']['value'] = $iCategory;
 

+ 2 - 2
modules/boonex/market/install/sql/enable.sql

@@ -107,8 +107,8 @@ INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module
 ('bx_market_category', 'products-category', '_bx_market_page_title_sys_entries_by_category', '_bx_market_page_title_entries_by_category', 'bx_market', 1, 2147483647, 1, 'page.php?i=products-category', '', '', '', 0, 1, 0, 'BxMarketPageBrowse', 'modules/boonex/market/classes/BxMarketPageBrowse.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_market_category', 2, 'bx_market', '_bx_market_page_block_title_sys_entries_by_category', '_bx_market_page_block_title_entries_by_category', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_market";s:6:"method";s:18:"browse_by_category";s:6:"params";a:1:{i:0;s:5:"table";}}', 0, 0, 1, 1),
-('bx_market_category', 1, 'bx_market', '_bx_market_page_block_title_cats', '_bx_market_page_block_title_cats', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:15:"categories_list";s:6:"params";a:2:{i:0;s:14:"bx_market_cats";i:1;a:1:{s:10:"show_empty";b:1;}}s:5:"class";s:20:"TemplServiceCategory";}', 0, 0, 1, 1);
+('bx_market_category', 1, 'bx_market', '_bx_market_page_block_title_cats', '_bx_market_page_block_title_cats', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:15:"categories_list";s:6:"params";a:2:{i:0;s:14:"bx_market_cats";i:1;a:1:{s:10:"show_empty";b:1;}}s:5:"class";s:20:"TemplServiceCategory";}', 0, 0, 1, 1),
+('bx_market_category', 2, 'bx_market', '_bx_market_page_block_title_sys_entries_by_category', '_bx_market_page_block_title_entries_by_category', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_market";s:6:"method";s:15:"browse_category";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, 0, 1, 1);
 
 -- PAGE: latest 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 

+ 10 - 6
modules/boonex/russian/data/langs/system/ru.xml

@@ -1714,12 +1714,16 @@
     <string name="_adm_stg_cpt_option_sys_api_extended_units"><![CDATA[Использовать расширенные юниты]]></string>
     <string name="_adm_stg_cpt_option_sys_viewport_meta_tag"><![CDATA[Метатег области просмотра]]></string>
 
-    <string name="_adm_stg_cpt_category_pwa"><![CDATA[Прогрессивные веб-приложения]]></string>
-    <string name="_adm_stg_cpt_option_sys_pwa_name"><![CDATA[Имя]]></string>
-    <string name="_adm_stg_cpt_option_sys_pwa_short_name"><![CDATA[Сокращенное имя]]></string>
-    <string name="_adm_stg_cpt_option_sys_pwa_description"><![CDATA[Описание]]></string>
-    <string name="_adm_stg_cpt_option_sys_pwa_background_color"><![CDATA[Цвет фона]]></string>
-    <string name="_adm_stg_cpt_option_sys_pwa_theme_color"><![CDATA[Цвет темы]]></string>
+    <string name="_adm_stg_cpt_category_pwa_manifest"><![CDATA[Manifest]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_name"><![CDATA[Имя]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_short_name"><![CDATA[Сокращенное имя]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_description"><![CDATA[Описание]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_background_color"><![CDATA[Цвет фона]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_manifest_theme_color"><![CDATA[Цвет темы]]></string>
+
+    <string name="_adm_stg_cpt_category_pwa_sw"><![CDATA[Service Worker]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_sw_cache"><![CDATA[URL-адреса для кэширования при установке (каждый в новой строке)]]></string>
+    <string name="_adm_stg_cpt_option_sys_pwa_sw_offline"><![CDATA[Офлайн-страница]]></string>
 
     <string name="_adm_stg_cpt_category_sockets"><![CDATA[Сервер для сокетов]]></string>
     <string name="_adm_stg_cpt_option_sys_sockets_type"><![CDATA[Тип]]></string>

+ 3 - 7
modules/boonex/timeline/js/main.js

@@ -38,10 +38,6 @@ function BxTimelineMain() {
     this.bViewOutline = false;
     this.bViewItem = false;
 
-    this._sPregTag = "(<([^>]+bx-tag[^>]+)>)";
-    this._sPregMention = "(<([^>]+bx-mention[^>]+)>)";
-    this._sPregUrl = "(([A-Za-z]{3,9}:(?:\\/\\/)?)(?:[\\-;:&=\\+\\$,\\w]+@)?[A-Za-z0-9\\.\\-]+|(?:www\\.|[\\-;:&=\\+\\$,\\w]+@)[A-Za-z0-9\\.\\-]+)((?:\\/[\\+~%#\\/\\.\\w\\-_!\\(\\)]*)?\\??(?:[\\-\\+=&;%@\\.\\w_]*)#?(?:[\\.\\!\\/\\w]*))?";
-
     this._iLimitAttachLinks = 0;
     this._sLimitAttachLinksErr = '';
     this._oAttachedLinks = {};
@@ -324,13 +320,13 @@ BxTimelineMain.prototype.parseContent = function(oForm, iId, sData, bPerformAtta
 {
     var oExp, aMatch = null;
 
-    oExp = new RegExp(this._sPregTag , "ig");
+    oExp = new RegExp(bx_get_regexp('tag'), "ig");
     sData = sData.replace(oExp, '');
 
-    oExp = new RegExp(this._sPregMention , "ig");
+    oExp = new RegExp(bx_get_regexp('mention'), "ig");
     sData = sData.replace(oExp, '');
 
-    oExp = new RegExp(this._sPregUrl , "ig");
+    oExp = new RegExp(bx_get_regexp('url'), "ig");
     while(aMatch = oExp.exec(sData)) {
         var sUrl = aMatch[0].replace(/^(\s|(&nbsp;))+|(\s|(&nbsp;))+$/gm,'');        
         if(!sUrl.length || this._oAttachedLinks[sUrl] != undefined || (this._iLimitAttachLinks != 0 && Object.keys(this._oAttachedLinks).length >= this._iLimitAttachLinks))

+ 1 - 1
studio/template/scripts/BxBaseStudioDesigner.php

@@ -651,7 +651,7 @@ class BxBaseStudioDesigner extends BxDolStudioDesigner
 
     protected function getPwa()
     {
-        $oOptions = new BxTemplStudioOptions(BX_DOL_STUDIO_STG_TYPE_SYSTEM, 'pwa');
+        $oOptions = new BxTemplStudioOptions(BX_DOL_STUDIO_STG_TYPE_SYSTEM, ['pwa_manifest', 'pwa_sw']);
 
         $this->aPageCss = array_merge($this->aPageCss, $oOptions->getCss());
         $this->aPageJs = array_merge($this->aPageJs, $oOptions->getJs());

+ 88 - 58
sw.js.php

@@ -12,7 +12,11 @@ define('BX_SERVICE_WORKER', true);
 require_once('./inc/header.inc.php');
 $oTemplate = BxDolTemplate::getInstance();
 
+$sCacheName = 'app' . $oTemplate->getRevision();
+
 $aAssets = [];
+
+//--- CSS/JS files
 foreach(['css' , 'js'] as $sType) {
     $aFiles = $oTemplate->includeFiles($sType, true, false);
     if(!is_array($aFiles))
@@ -21,8 +25,39 @@ foreach(['css' , 'js'] as $sType) {
     $aAssets = array_merge($aAssets, $aFiles);
 }
 
-foreach($aAssets as $iKey => $sAsset)
-    $aAssets[$iKey] = str_replace(BX_DOL_URL_ROOT, '/', $sAsset);
+if(($sCache = getParam('sys_pwa_sw_cache')) != '') {
+    $aItems = preg_split("/\\r\\n|\\r|\\n/", $sCache);
+    if(!empty($aItems) && is_array($aItems))
+        foreach($aItems as $sItem) {
+            if(strpos($sItem, BX_DOL_URL_ROOT) === false)
+                $sItem = BX_DOL_URL_ROOT . $sItem;
+
+            $aAssets[] = $oTemplate->addRevision($sItem);
+        }
+}
+
+//--- Offline page
+if(($sOffline = getParam('sys_pwa_sw_offline')) != '')
+    $aAssets[] = BX_DOL_URL_ROOT . $sOffline;
+
+//--- Favicon or SVG icon
+$sIconUrl = '';
+if(($iId = (int)getParam('sys_site_icon')) != 0)
+    $sIconUrl = BxDolStorage::getObjectInstance(BX_DOL_STORAGE_OBJ_FILES)->getFileUrlById($iId);          
+if(!$sIconUrl && ($iId = (int)getParam('sys_site_icon_svg')) != 0)
+    $sIconUrl = BxDolStorage::getObjectInstance(BX_DOL_STORAGE_OBJ_IMAGES)->getFileUrlById($iId);
+if(!empty($sIconUrl))
+    $aAssets[] = $sIconUrl;
+
+//--- Fonts
+if(getParam('sys_css_icons_default') != '') {
+    $sHomeUrl = BX_DOL_URL_ROOT;
+    if(BxDolModuleQuery::getInstance()->isEnabledByName('bx_fontawesome'))
+        $sHomeUrl = BxDolModule::getInstance('bx_fontawesome')->_oConfig->getHomeUrl();
+
+    $aAssets[] = $sHomeUrl . 'template/fonts/fa-solid-900.woff2';
+    $aAssets[] = $sHomeUrl . 'template/fonts/fa-regular-400.woff2';
+}
 
 header("Content-Type: text/javascript");
 ?>
@@ -32,13 +67,32 @@ let coreAssets = <?php echo json_encode($aAssets); ?>;
 
 // On install, cache core assets
 self.addEventListener('install', function (event) {
+    console.log("Service Worker: <?php echo $sCacheName; ?>");
     // Cache core assets
-    event.waitUntil(caches.open('app').then(function (cache) {
-        for (let asset of coreAssets) {
-            cache.add(new Request(asset));
-        }
-        return cache;
-    }));
+    event.waitUntil((async () => { 
+        caches.open('<?php echo $sCacheName; ?>').then(function (cache) {
+            for (let asset of coreAssets) {
+                cache.add(new Request(asset));
+            }
+            return cache;
+        });
+    })());
+});
+
+const deleteCache = async (key) => {
+  await caches.delete(key);
+};
+
+const deleteOldCaches = async () => {
+  const cacheKeepList = ["<?php echo $sCacheName; ?>"];
+  const keyList = await caches.keys();
+  const cachesToDelete = keyList.filter((key) => !cacheKeepList.includes(key));
+  await Promise.all(cachesToDelete.map(deleteCache));
+};
+
+// delete old cache on activate
+self.addEventListener("activate", (event) => {
+  event.waitUntil(deleteOldCaches());
 });
 
 // Listen for request events
@@ -51,58 +105,34 @@ self.addEventListener('fetch', function (event) {
     // https://stackoverflow.com/a/49719964
     if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') return;
 
-    // HTML files
-    // Network-first
-    if (request.headers.get('Accept').includes('text/html')) {
-        event.respondWith(
-            fetch(request).then(function (response) {
-                // Create a copy of the response and save it to the cache
-                let copy = response.clone();
-                event.waitUntil(caches.open('app').then(function (cache) {
-                    return cache.put(request, copy);
-                }));
-
-                // Return the response
-                return response;
-            }).catch(function (error) {
-                // If there's no item in cache, respond with a fallback
-                return caches.match(request).then(function (response) {
-                    return response || caches.match('/offline.html');
-                });
-            })
-        );
-    }
-
-    // CSS & JavaScript
-    // Offline-first
-    if (request.headers.get('Accept').includes('text/css') || request.headers.get('Accept').includes('text/javascript')) {
+    // regular pages and static assets
+    if (request.mode === 'navigate' || request.url.match(/\.(css|js|woff2|svg|png|jpg)$/)) {
+        const failedResponse = async (err) => {
+            let reponse = null;
+            if (request.mode === 'navigate') {
+                const cache = await caches.open('<?php echo $sCacheName; ?>');
+                reponse = await cache.match('<?php echo BX_DOL_URL_ROOT . 'offline'; ?>');
+            }
+            return reponse || new Response("Network error happened", {
+                status: 408,
+                headers: { "Content-Type": "text/plain" },
+            });
+        }
         event.respondWith(
-            caches.match(request).then(function (response) {
-                return response || fetch(request).then(function (response) {
-                    // Return the response
-                    return response;
-                });
+            caches.match(request).then((response) => {
+                try {
+                    return response || fetch(request)
+                        .then((response) => {
+                            return response;
+                        })
+                        .catch((err) => {
+                            return failedResponse(err);
+                        });
+                } catch (error) {
+                    return failedResponse(err);
+                }
             })
         );
-        return;
     }
 
-    // Images
-    // Offline-first
-    if (request.headers.get('Accept').includes('image')) {
-        event.respondWith(
-            caches.match(request).then(function (response) {
-                return response || fetch(request).then(function (response) {
-                    // Save a copy of it in cache
-                    let copy = response.clone();
-                    event.waitUntil(caches.open('app').then(function (cache) {
-                        return cache.put(request, copy);
-                    }));
-
-                    // Return the response
-                    return response;
-                });
-            })
-        );
-    }
-});
+});