From 7deb646da46d9dbfe6f791a9643ce6b3004ff79f Mon Sep 17 00:00:00 2001 From: AntonLV Date: Wed, 5 Jan 2022 11:33:06 +0300 Subject: [PATCH] Ticket #2948 - Reactions: Improve user experiance. --- inc/classes/BxDolObject.php | 25 ++++-- inc/classes/BxDolVoteReactions.php | 4 + inc/js/classes/BxDolVoteReactions.js | 79 +++++++++++++++---- install/sql/system.sql | 5 +- .../boonex/english/data/langs/system/en.xml | 7 +- .../boonex/russian/data/langs/system/ru.xml | 1 + template/scripts/BxBaseVote.php | 23 +++--- template/scripts/BxBaseVoteReactions.php | 31 +++++++- 8 files changed, 138 insertions(+), 37 deletions(-) diff --git a/inc/classes/BxDolObject.php b/inc/classes/BxDolObject.php index 22a8d5965c..2efb487c5b 100644 --- a/inc/classes/BxDolObject.php +++ b/inc/classes/BxDolObject.php @@ -233,7 +233,7 @@ public function onObjectDelete($iObjectId = 0) /** * Internal functions */ - protected function _getAuthorId () + protected function _getAuthorId () { return isMember() ? bx_get_logged_profile_id() : 0; } @@ -276,7 +276,7 @@ protected function _getAuthorObject($iAuthorId = 0) /** * Update Trigger table using data which is automatically gotten from object's internal table. */ - protected function _trigger() + protected function _trigger() { if(!$this->_aSystem['trigger_table']) return false; @@ -313,14 +313,29 @@ protected function _replaceMarkers ($mixed) return bx_replace_markers($mixed, $this->_aMarkers); } - + protected function _prepareParamsData($aParams) + { + $aParams = array_merge([ + 'sSystem' => $this->getSystemName(), + 'iObjId' => $this->getId(), + 'iAuthorId' => $this->_getAuthorId(), + 'sRootUrl' => BX_DOL_URL_ROOT, + ], $aParams); + + foreach($aParams as $sKey => $mixedValue) + if(is_bool($mixedValue)) + $aParams[$sKey] = (int)$mixedValue; + + return $aParams; + } + protected function _getRequestParamsData($aKeys = array()) { $sParams = bx_get('params'); if($sParams === false) - return array(); + return []; - $aParams = array(); + $aParams = []; parse_str(bx_process_input($sParams), $aParams); return $aParams; diff --git a/inc/classes/BxDolVoteReactions.php b/inc/classes/BxDolVoteReactions.php index bbb129f3ef..5850be690c 100644 --- a/inc/classes/BxDolVoteReactions.php +++ b/inc/classes/BxDolVoteReactions.php @@ -23,6 +23,8 @@ class BxDolVoteReactions extends BxTemplVote protected $_sDefault; //--- Default reaction name. + protected $_bQuickMode; //--- Give 'default' reaction when clicked. + public function __construct($sSystem, $iId, $iInit = true, $oTemplate = false) { parent::__construct($sSystem, $iId, $iInit, $oTemplate); @@ -36,6 +38,8 @@ public function __construct($sSystem, $iId, $iInit = true, $oTemplate = false) $this->_aDataList = array(); $this->_sDefault = 'default'; + + $this->_bQuickMode = getParam('sys_vote_reactions_quick_mode') == 'on'; } public function init($iId) diff --git a/inc/js/classes/BxDolVoteReactions.js b/inc/js/classes/BxDolVoteReactions.js index 397b88480f..f4947d44ce 100644 --- a/inc/js/classes/BxDolVoteReactions.js +++ b/inc/js/classes/BxDolVoteReactions.js @@ -9,6 +9,7 @@ function BxDolVoteReactions(oOptions) { BxDolVote.call(this, oOptions); + this._bQuickMode = oOptions.bQuickMode === undefined ? 0 : oOptions.bQuickMode; // enable 'quick' mode - vote with default reaction when clicked. this._iTimeoutShowId = 0; this._iTimeoutShowDelay = 750; @@ -34,16 +35,18 @@ BxDolVoteReactions.prototype.constructor = BxDolVoteReactions; BxDolVoteReactions.prototype.initVote = function() { var $this = this; + var bMobile = bx_check_mq() == 'mobile'; - this._fOnVoteIn = function() { - $this.onVoteIn(this); - }; - - this._fOnVoteOut = function() { - $this.onVoteOut(this); - }; - - $('#' + this._aHtmlIds['main'] + ' .' + this._sClassDo).hover(this._fOnVoteIn, this._fOnVoteOut); + if(!this._bQuickMode || !bMobile) + $('#' + this._aHtmlIds['main'] + ' .' + this._sClassDo).hover(function() { + $this.onVoteIn(this); + }, function() { + $this.onVoteOut(this); + }); + else + $('#' + this._aHtmlIds['main'] + ' .' + this._sClassDo).onLongTouch(function(oElement) { + $this.onTouch(oElement); + }); }; BxDolVoteReactions.prototype.vote = function(oLink, iValue, sReaction, onComplete) @@ -54,6 +57,9 @@ BxDolVoteReactions.prototype.vote = function(oLink, iValue, sReaction, onComplet oParams['value'] = iValue; oParams['reaction'] = sReaction; + if(this._iTimeoutShowId) + clearTimeout(this._iTimeoutShowId); + $('#' + this._aHtmlIds['do_popup']).dolPopupHide({}); $.post( @@ -80,7 +86,6 @@ BxDolVoteReactions.prototype.onVote = function (oLink, oData, onComplete) oLink = $('.' + this._aHtmlIds['main'] + ' .' + this._sClassDo); - console.log(oData); //--- Update Do button. oLink.each(function() { if(oData && oData.label_icon){ @@ -130,6 +135,8 @@ BxDolVoteReactions.prototype.onVote = function (oLink, oData, onComplete) BxDolVoteReactions.prototype.onVoteIn = function(oLink) { + var $this = this; + if($(oLink).hasClass(this._sClassDoVoted)) return; @@ -141,7 +148,7 @@ BxDolVoteReactions.prototype.onVoteIn = function(oLink) return; this._iTimeoutShowId = setTimeout(function() { - $(oLink).click(); + $this.toggleDoPopup(oLink, $(oLink).attr('bx-vote-value')); }, this._iTimeoutShowDelay); }; @@ -156,13 +163,24 @@ BxDolVoteReactions.prototype.onVoteOut = function(oLink) this.hideDoPopup(); }; +BxDolVoteReactions.prototype.onTouch = function(oLink) +{ + var oPopup = this.getDoPopup(); + if(oPopup !== false) + return; + + this.toggleDoPopup(oLink, $(oLink).attr('bx-vote-value'), { + closeOnOuterClick: false + }); +}; + BxDolVoteReactions.prototype.getDoPopup = function() { var oPopup = $('#' + this._aHtmlIds['do_popup'] + ':visible'); return oPopup.length > 0 && oPopup.hasClass('bx-popup-applied') ? oPopup : false; }; -BxDolVoteReactions.prototype.toggleDoPopup = function(oLink, iValue) +BxDolVoteReactions.prototype.toggleDoPopup = function(oLink, iValue, oOptions) { var $this = this; var oParams = this._getDefaultParams(); @@ -171,7 +189,8 @@ BxDolVoteReactions.prototype.toggleDoPopup = function(oLink, iValue) if(this._iTimeoutShowId) clearTimeout(this._iTimeoutShowId); - $(oLink).dolPopupAjax({ + oOptions = oOptions || {}; + oOptions = $.extend({}, { id: {value: this._aHtmlIds['do_popup'], force: true}, url: bx_append_url_params(this._sActionsUri, oParams), value: iValue, @@ -181,7 +200,9 @@ BxDolVoteReactions.prototype.toggleDoPopup = function(oLink, iValue) onHide: function(oPopup) { $this.onDoPopupHide(oPopup); } - }); + }, oOptions); + + $(oLink).dolPopupAjax(oOptions); }; BxDolVoteReactions.prototype.hideDoPopup = function() @@ -256,4 +277,34 @@ BxDolVoteReactions.prototype._getCounter = function(oElement) return $('.' + this._aHtmlIds['counter']).find('.' + this._sSP + '-counter'); }; +(function($) { + $.fn.onLongTouch = function(fCallback) { + return this.each(function() { + var iTimeoutId; + + this.addEventListener('touchstart', function(e) { + iTimeoutId = setTimeout(function() { + iTimeoutId = null; + e.stopPropagation(); + fCallback(e.target); + }, 500); + }); + + this.addEventListener('contextmenu', function(e) { + e.preventDefault(); + }); + + this.addEventListener('touchend', function () { + if(iTimeoutId) + clearTimeout(iTimeoutId); + }); + + this.addEventListener('touchmove', function () { + if(iTimeoutId) + clearTimeout(iTimeoutId); + }); + }); + }; +})(jQuery); + /** @} */ diff --git a/install/sql/system.sql b/install/sql/system.sql index 9260a328ff..c621b771f3 100644 --- a/install/sql/system.sql +++ b/install/sql/system.sql @@ -500,7 +500,10 @@ INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `ex (@iCategoryId, 'sys_profile_bot', '_adm_stg_cpt_option_sys_profile_bot', '', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:23:"get_options_profile_bot";s:5:"class";s:13:"TemplServices";}', '', '', 40), -(@iCategoryId, 'sys_hide_post_to_context_for_privacy', '_adm_stg_cpt_option_sys_hide_post_to_context_for_privacy', '', 'list', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:44:"get_options_module_list_for_privacy_selector";s:5:"class";s:13:"TemplServices";}', '', '', 50); +(@iCategoryId, 'sys_hide_post_to_context_for_privacy', '_adm_stg_cpt_option_sys_hide_post_to_context_for_privacy', '', 'list', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:44:"get_options_module_list_for_privacy_selector";s:5:"class";s:13:"TemplServices";}', '', '', 50), + +(@iCategoryId, 'sys_vote_reactions_quick_mode', '_adm_stg_cpt_option_sys_vote_reactions_quick_mode', '', 'checkbox', '', '', '', 60); + -- -- CATEGORY: Storage -- diff --git a/modules/boonex/english/data/langs/system/en.xml b/modules/boonex/english/data/langs/system/en.xml index f1bdf2c265..21a73be359 100644 --- a/modules/boonex/english/data/langs/system/en.xml +++ b/modules/boonex/english/data/langs/system/en.xml @@ -1618,18 +1618,19 @@ - - + + - + + diff --git a/modules/boonex/russian/data/langs/system/ru.xml b/modules/boonex/russian/data/langs/system/ru.xml index 175982f3d5..d8f2549a0b 100644 --- a/modules/boonex/russian/data/langs/system/ru.xml +++ b/modules/boonex/russian/data/langs/system/ru.xml @@ -1615,6 +1615,7 @@ + diff --git a/template/scripts/BxBaseVote.php b/template/scripts/BxBaseVote.php index 7455bc4e0e..63926f54ad 100644 --- a/template/scripts/BxBaseVote.php +++ b/template/scripts/BxBaseVote.php @@ -66,16 +66,9 @@ public function getJsScript($aParams = array()) $bDynamicMode = isset($aParams['dynamic_mode']) && (bool)$aParams['dynamic_mode'] === true; - $sCode = "if(window['" . $sJsObjName . "'] == undefined) var " . $sJsObjName . " = new " . $sJsObjClass . "(" . json_encode(array( - 'sObjName' => $sJsObjName, - 'sSystem' => $this->getSystemName(), - 'iAuthorId' => $this->_getAuthorId(), - 'iObjId' => $this->getId(), - 'sRootUrl' => BX_DOL_URL_ROOT, - 'sStylePrefix' => $this->_sStylePrefix, - 'aHtmlIds' => $this->_aHtmlIds, + $sCode = "if(window['" . $sJsObjName . "'] == undefined) var " . $sJsObjName . " = new " . $sJsObjClass . "(" . json_encode($this->_prepareParamsData([ 'aRequestParams' => $this->_prepareRequestParamsData($aParams) - )) . ");"; + ])) . ");"; return $this->_oTemplate->_wrapInTagJsCode($sCode); } @@ -177,7 +170,17 @@ public function getElement($aParams = array()) /** * Internal methods. - * + */ + protected function _prepareParamsData($aParams) + { + return parent::_prepareParamsData(array_merge([ + 'sObjName' => $this->getJsObjectName(), + 'sStylePrefix' => $this->_sStylePrefix, + 'aHtmlIds' => $this->_aHtmlIds, + ], $aParams)); + } + + /* * This method should be overwritten by subclass. */ protected function _getTmplVarsElement($aParams = array()) diff --git a/template/scripts/BxBaseVoteReactions.php b/template/scripts/BxBaseVoteReactions.php index 00df2e6263..b9e600e927 100644 --- a/template/scripts/BxBaseVoteReactions.php +++ b/template/scripts/BxBaseVoteReactions.php @@ -53,7 +53,13 @@ public function getJsClick($iValue = 0) if(empty($iValue)) $iValue = $this->getValue(); - return $this->getJsObjectName() . '.toggleDoPopup(this, ' . $iValue . ')'; + $sResult = ''; + if($this->_bQuickMode) + $sResult = $this->getJsClickDo($this->_aDataList[$this->_sDefault]['name'], $iValue); + else + $sResult = $this->getJsObjectName() . '.toggleDoPopup(this, ' . $iValue . ')'; + + return $sResult; } public function getJsClickDo($sReaction, $iValue = 0) @@ -298,6 +304,13 @@ public function getElement($aParams = array()) /** * Internal methods. */ + protected function _prepareParamsData($aParams) + { + return parent::_prepareParamsData(array_merge([ + 'bQuickMode' => $this->_bQuickMode + ], $aParams)); + } + protected function _isShowDoVote($aParams, $isAllowedVote, $bCount) { $bResult = parent::_isShowDoVote($aParams, $isAllowedVote, $bCount); @@ -321,14 +334,22 @@ protected function _getDoVote($aParams = array(), $isAllowedVote = true) else if ($bShowDoVoteAsButtonSmall) $sClass = ' bx-btn bx-btn-small'; + $iValue = 0; + $sReaction = ''; $sJsClick = ''; if(!$bDisabled) { if($bVoted && $bUndo) { $sClass = ' ' . $this->_sStylePrefix . '-voted' . $sClass; - $sJsClick = $this->getJsClickDo($aParams['track']['reaction']); + + $iValue = $aParams['track']['value']; + $sReaction = $aParams['track']['reaction']; + $sJsClick = $this->getJsClickDo($sReaction, $iValue); + } + else { + $iValue = $this->getValue(); + $sReaction = $this->_aDataList[$this->_sDefault]['name']; + $sJsClick = $this->getJsClick($iValue); } - else - $sJsClick = $this->getJsClick(); } else $sClass .= $bShowDoVoteAsButton || $bShowDoVoteAsButtonSmall ? ' bx-btn-disabled' : ' ' . $this->_sStylePrefix . '-disabled'; @@ -337,6 +358,8 @@ protected function _getDoVote($aParams = array(), $isAllowedVote = true) 'class' => $this->_sStylePrefix . '-do-vote' . $sClass, 'title' => _t($this->_getTitleDoWithTrack($bVoted, $aParams['track'])), 'onclick' => $sJsClick, + 'bx-vote-reaction' => $sReaction, + 'bx-vote-value' => $iValue, )); }