Jelajahi Sumber

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

RomanL 8 tahun lalu
induk
melakukan
f78560cdc8

+ 2 - 2
inc/classes/BxDolObject.php

@@ -94,9 +94,9 @@ class BxDolObject extends BxDolFactory implements iBxDolReplaceable
         return $this->_aSystem && (int)$this->_aSystem['is_on'] == 1;
     }
 
-    public function isPerformed($iObjectId, $iAuthorId)
+    public function isPerformed($iObjectId, $iAuthorId, $iAuthorIp = 0)
     {
-        return $this->_oQuery->isPerformed($iObjectId, $iAuthorId);        
+        return $this->_oQuery->isPerformed($iObjectId, $iAuthorId);
     }
 
 	/**

+ 331 - 0
inc/classes/BxDolScore.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    UnaCore UNA Core
+ * @{
+ */
+
+bx_import('BxDolAcl');
+
+define('BX_DOL_SCORE_USAGE_BLOCK', 'block');
+define('BX_DOL_SCORE_USAGE_INLINE', 'inline');
+define('BX_DOL_SCORE_USAGE_DEFAULT', BX_DOL_SCORE_USAGE_BLOCK);
+
+define('BX_DOL_SCORE_DO_UP', 'up');
+define('BX_DOL_SCORE_DO_DOWN', 'down');
+
+/**
+ * Score for any content
+ *
+ * Related classes:
+ * - BxDolScoreQuery - vote database queries
+ * - BxBaseScore - vote base representation
+ * - BxTemplScore - custom template representation
+ *
+ * AJAX vote for any content. Stars and Plus based representations are supported.
+ *
+ * To add vote section to your feature you need to add a record to 'sys_objects_vote' table:
+ *
+ * - ID - autoincremented id for internal usage
+ * - Name - your unique module name, with vendor prefix, lowercase and spaces are underscored
+ * - TableMain - table name where summary votigs are stored
+ * - TableTrack - table name where each vote is stored
+ * - PostTimeout - number of seconds to not allow duplicate vote
+ * - MinValue - min vote value, 1 by default
+ * - MaxValue - max vote value, 5 by default
+ * - IsUndo - is Undo enabled for Plus based votes
+ * - IsOn - is this vote object enabled
+ * - TriggerTable - table to be updated upon each vote
+ * - TriggerFieldId - TriggerTable table field with unique record id, primary key
+ * - TriggerFieldRate - TriggerTable table field with average rate
+ * - TriggerFieldRateCount - TriggerTable table field with votes count
+ * - ClassName - your custom class name, if you overrride default class
+ * - ClassFile - your custom class path
+ *
+ * You can refer to BoonEx modules for sample record in this table.
+ *
+ *
+ *
+ * @section example Example of usage:
+ * To get Star based vote you need to have different values for MinValue and MaxValue (for example 1 and 5)
+ * and IsUndo should be equal to 0. To get Plus(Like) based vote you need to have equal values
+ * for MinValue and MaxValue (for example 1) and IsUndo should be equal to 1. After filling the other
+ * paramenters in the table you can show vote in any place, using the following code:
+ * @code
+ * $o = BxDolScore::getObjectInstance('system object name', $iYourEntryId);
+ * if (!$o->isEnabled()) return '';
+ *     echo $o->getElementBlock();
+ * @endcode
+ *
+ *
+ * @section acl Memberships/ACL:
+ * - vote
+ *
+ *
+ *
+ * @section alerts Alerts:
+ * Alerts type/unit - every module has own type/unit, it equals to ObjectName.
+ * The following alerts are rised:
+ *
+ * - rate - comment was posted
+ *      - $iObjectId - entry id
+ *      - $iSenderId - rater user id
+ *      - $aExtra['rate'] - rate
+ *
+ */
+
+class BxDolScore extends BxDolObject
+{
+    protected function __construct($sSystem, $iId, $iInit = true, $oTemplate = false)
+    {
+        parent::__construct($sSystem, $iId, $iInit, $oTemplate);
+        if(empty($this->_sSystem))
+            return;
+
+        $this->_oQuery = new BxDolScoreQuery($this);
+    }
+
+    /**
+     * get votes object instanse
+     * @param $sSys vote object name
+     * @param $iId associated content id, where vote is available
+     * @param $iInit perform initialization
+     * @return null on error, or ready to use class instance
+     */
+    public static function getObjectInstance($sSys, $iId, $iInit = true, $oTemplate = false)
+    {
+        if(isset($GLOBALS['bxDolClasses']['BxDolScore!' . $sSys . $iId]))
+            return $GLOBALS['bxDolClasses']['BxDolScore!' . $sSys . $iId];
+
+        $aSystems = self::getSystems();
+        if(!isset($aSystems[$sSys]))
+            return null;
+
+        $sClassName = 'BxTemplScore';
+        if(!empty($aSystems[$sSys]['class_name'])) {
+            $sClassName = $aSystems[$sSys]['class_name'];
+            if(!empty($aSystems[$sSys]['class_file']))
+                require_once(BX_DIRECTORY_PATH_ROOT . $aSystems[$sSys]['class_file']);
+        }
+
+        $o = new $sClassName($sSys, $iId, $iInit, $oTemplate);
+        return ($GLOBALS['bxDolClasses']['BxDolScore!' . $sSys . $iId] = $o);
+    }
+
+    public static function &getSystems()
+    {
+        $sKey = 'bx_dol_cache_memory_score_systems';
+
+        if(!isset($GLOBALS[$sKey]))
+            $GLOBALS[$sKey] = BxDolDb::getInstance()->fromCache('sys_objects_score', 'getAllWithKey', '
+                SELECT
+                    `id` as `id`,
+                    `name` AS `name`,
+                    `table_main` AS `table_main`,
+                    `table_track` AS `table_track`,
+                    `post_timeout` AS `post_timeout`,
+                    `is_on` AS `is_on`,
+                    `trigger_table` AS `trigger_table`,
+                    `trigger_field_id` AS `trigger_field_id`,
+                    `trigger_field_author` AS `trigger_field_author`,
+                    `trigger_field_score` AS `trigger_field_score`,
+                    `trigger_field_cup` AS `trigger_field_cup`,
+                    `trigger_field_cdown` AS `trigger_field_cdown`,
+                    `class_name` AS `class_name`,
+                    `class_file` AS `class_file`
+                FROM `sys_objects_score`', 'name');
+
+        return $GLOBALS[$sKey];
+    }
+
+    public static function onAuthorDelete ($iAuthorId)
+    {
+        $aSystems = self::getSystems();
+        foreach($aSystems as $sSystem => $aSystem)
+            self::getObjectInstance($sSystem, 0)->getQueryObject()->deleteAuthorEntries($iAuthorId);
+
+        return true;
+    }
+
+    public function isPerformed($iObjectId, $iAuthorId, $iAuthorIp = 0)
+    {
+        return parent::isPerformed($iObjectId, $iAuthorId) && !$this->_oQuery->isPostTimeoutEnded($iObjectId, $iAuthorIp);        
+    }
+
+	public function getObjectAuthorId($iObjectId = 0)
+    {
+    	if(empty($this->_aSystem['trigger_field_author']))
+    		return 0;
+
+        return $this->_oQuery->getObjectAuthorId($iObjectId ? $iObjectId : $this->getId());
+    }
+
+
+    /**
+     * Interface functions for outer usage
+     */
+    public function getStatCounterUp()
+    {
+        $aScore = $this->_oQuery->getScore($this->getId());
+        return $aScore['count_up'];
+    }
+
+    public function getStatCounterDown()
+    {
+        $aScore = $this->_oQuery->getScore($this->getId());
+        return $aScore['count_down'];
+    }
+
+    public function getStatScore()
+    {
+        $aScore = $this->_oQuery->getScore($this->getId());
+        return $aScore['score'];
+    }
+
+
+    /**
+     * Actions functions
+     */
+    public function actionVoteUp()
+    {
+        return $this->_doVote(BX_DOL_SCORE_DO_UP);
+    }
+
+    public function actionVoteDown()
+    {
+        return $this->_doVote(BX_DOL_SCORE_DO_DOWN);
+    }
+
+    public function actionGetVotedBy()
+    {
+        if (!$this->isEnabled())
+           return '';
+
+        return $this->_getVotedBy();
+    }
+
+
+    /**
+     * Permissions functions
+     */
+    public function isAllowedVote($isPerformAction = false)
+    {
+        if(isAdmin())
+            return true;
+
+        return $this->checkAction('vote', $isPerformAction);
+    }
+
+    public function msgErrAllowedVote()
+    {
+        return $this->checkActionErrorMsg('vote');
+    }
+
+
+    /**
+     * Internal functions
+     */
+    protected function _doVote($sType)
+    {
+        if(!$this->isEnabled())
+            return echoJson(array('code' => 1, 'message' => _t('_sys_score_err_not_enabled')));
+
+        if(!$this->isAllowedVote(true))
+            return echoJson(array('code' => 2, 'message' => $this->msgErrAllowedVote()));
+
+        $iObjectId = $this->getId();
+        $iObjectAuthorId = $this->getObjectAuthorId($iObjectId);
+        $iAuthorId = $this->_getAuthorId();
+        $iAuthorIp = $this->_getAuthorIp();
+
+        $bVoted = $this->isPerformed($iObjectId, $iAuthorId, $iAuthorIp);
+        if($bVoted)
+            return echoJson(array('code' => 3, 'message' => _t('_sys_score_err_duplicate_vote')));
+
+		$iId = $this->_oQuery->putVote($iObjectId, $iAuthorId, $iAuthorIp, $sType);
+        if($iId === false)
+            return echoJson(array('code' => 5));
+
+        $this->_trigger();
+
+        $sAlertAction = 'doVote' . ucfirst($sType);
+        bx_alert($this->_sSystem, $sAlertAction, $iObjectId, $iAuthorId, array('score_id' => $iId, 'score_author_id' => $iAuthorId, 'object_author_id' => $iObjectAuthorId));
+        bx_alert('score', $sAlertAction, $iId, $iAuthorId, array('object_system' => $this->_sSystem, 'object_id' => $iObjectId, 'object_author_id' => $iObjectAuthorId));
+
+        $aScore = $this->_oQuery->getScore($iObjectId);
+        $iCup = (int)$aScore['count_up'];
+        $iCdown = (int)$aScore['count_down'];
+        echoJson(array(
+            'code' => 0,
+            'type' => $sType,
+            'score' => $aScore['score'],
+        	'scoref' => $iCup > 0 || $iCdown > 0 ? $this->_getLabelCounter($aScore['score']) : '',
+            'cup' => $iCup,
+        	'cdown' => $iCdown,
+        	'label_icon' => $this->_getIconDo($sType),
+        	'label_title' => _t($this->_getTitleDo($sType)),
+        	'disabled' => !$bVoted,
+        ));
+    }
+
+    /**
+     * Note. By default image based controls aren't used.
+     * Therefore it can be overwritten in custom template.
+     */
+    protected function _getImageDo($sType)
+    {
+        $sResult = '';
+
+        switch($sType) {
+            case BX_DOL_SCORE_DO_UP:
+                $sResult = '';
+                break;
+            case BX_DOL_SCORE_DO_DOWN:
+                $sResult = '';
+                break;
+        }
+
+    	return $sResult;
+    }
+
+    protected function _getIconDo($sType)
+    {
+        $sResult = '';
+
+        switch($sType) {
+            case BX_DOL_SCORE_DO_UP:
+                $sResult = 'arrow-up';
+                break;
+            case BX_DOL_SCORE_DO_DOWN:
+                $sResult = 'arrow-down';
+                break;
+        }
+
+    	return $sResult;
+    }
+
+    protected function _getTitleDo($sType)
+    {
+        $sResult = '';
+
+        switch($sType) {
+            case BX_DOL_SCORE_DO_UP:
+                $sResult = '_sys_score_do_up';
+                break;
+            case BX_DOL_SCORE_DO_DOWN:
+                $sResult = '_sys_score_do_down';
+                break;
+        }
+
+    	return $sResult;
+    }
+
+    protected function _getTitleDoBy()
+    {
+    	return '_sys_score_do_by';
+    }
+}
+
+/** @} */

+ 128 - 0
inc/classes/BxDolScoreQuery.php

@@ -0,0 +1,128 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+/**
+ * @see BxDolScore
+ */
+class BxDolScoreQuery extends BxDolObjectQuery
+{
+	protected $_sTriggerFieldScore;
+	protected $_sTriggerFieldCup;
+	protected $_sTriggerFieldCdown;
+
+    protected $_iPostTimeout;
+
+    public function __construct(&$oModule)
+    {
+        parent::__construct($oModule);
+
+        $aSystem = $this->_oModule->getSystemInfo();
+        $this->_sTriggerFieldScore = $aSystem['trigger_field_score'];
+        $this->_sTriggerFieldCup = $aSystem['trigger_field_cup'];
+        $this->_sTriggerFieldCdown = $aSystem['trigger_field_cdown'];
+
+        $this->_iPostTimeout = (int)$aSystem['post_timeout'];
+
+        $this->_sMethodGetEntry = 'getScore';
+    }
+
+    public function isPostTimeoutEnded($iObjectId, $sAuthorIp)
+    {
+        if($this->_iPostTimeout == 0)
+            return true;
+
+        return (int)$this->getOne("SELECT `object_id` FROM `{$this->_sTableTrack}` WHERE `object_id` = :object_id AND `author_nip` = :author_nip AND `date` > :date", array(
+            'object_id' => $iObjectId,
+            'author_nip' => ip2long($sAuthorIp),
+            'date' => time() - $this->_iPostTimeout
+        )) == 0;
+    }
+
+    public function getScore($iObjectId)
+    {
+        $aResult = $this->getRow("SELECT `count_up`, `count_down`, `count_up` - `count_down` AS `score` FROM {$this->_sTable} WHERE `object_id` = :object_id LIMIT 1", array(
+            'object_id' => $iObjectId
+        ));
+
+        if(empty($aResult) || !is_array($aResult))
+            $aResult = array('count_up' => 0, 'count_down' => 0, 'score' => 0);
+
+        return $aResult;
+    }
+
+    public function putVote($iObjectId, $iAuthorId, $sAuthorIp, $sType)
+    {
+        $bExists = (int)$this->getOne("SELECT `object_id` FROM `{$this->_sTable}` WHERE `object_id` = :object_id LIMIT 1", array('object_id' => $iObjectId)) != 0;
+
+        if(!$bExists)
+            $sQuery = $this->prepare("INSERT INTO {$this->_sTable} SET `object_id` = ?, `count_" . $sType . "` = '1'", $iObjectId);
+        else
+            $sQuery = $this->prepare("UPDATE `{$this->_sTable}` SET `count_" . $sType . "` = `count_" . $sType . "` + 1 WHERE `object_id` = ?", $iObjectId);
+
+        if((int)$this->query($sQuery) == 0)
+            return false;
+
+        if((int)$this->query("INSERT INTO `{$this->_sTableTrack}` SET " . $this->arrayToSQL(array(
+            'object_id' => $iObjectId, 
+            'author_id' => $iAuthorId, 
+            'author_nip' => ip2long($sAuthorIp), 
+            'type' => $sType, 
+            'date' => time()
+        ))) > 0)
+        	return $this->lastId();
+
+        return false;
+    }
+
+    public function getLegend($iObjectId)
+    {
+    	$sQuery = $this->prepare("SELECT `type` AS `type`, COUNT(`type`) AS `count` FROM `{$this->_sTableTrack}` WHERE `object_id` = ? GROUP BY `type`", $iObjectId);
+
+    	return $this->getAllWithKey($sQuery, 'type');
+    }
+
+    public function getSqlParts($sMainTable, $sMainField)
+    {
+    	$aResult = parent::getSqlParts($sMainTable, $sMainField);
+        if(empty($aResult))
+            return $aResult;
+
+		$aResult['fields'] = ", `{$this->_sTable}`.`count_up` AS `score_cup`, `{$this->_sTable}`.`count_down` AS `score_cdown`, (`{$this->_sTable}`.`count_up` - `{$this->_sTable}`.`count_down`) AS `score` ";
+        return $aResult;
+    }
+
+	protected function _updateTriggerTable($iObjectId, $aEntry)
+    {
+        $aSet = array(
+            $this->_sTriggerFieldScore => $aEntry['score'],
+            $this->_sTriggerFieldCup => $aEntry['count_up'],
+            $this->_sTriggerFieldCdown => $aEntry['count_down']
+        );
+
+        return (int)$this->query("UPDATE `{$this->_sTriggerTable}` SET " . $this->arrayToSQL($aSet) . " WHERE `{$this->_sTriggerFieldId}` = :object_id", array(
+        	'object_id' => $iObjectId
+        )) > 0;
+    }
+
+    protected function _deleteAuthorEntriesTableMain($aTrack)
+    {
+        return $this->query("UPDATE `{$this->_sTable}` SET `count_" . $aTrack['type'] . "`=`count_" . $aTrack['type'] . "`-1 WHERE `object_id`=:object_id", array(
+        	'object_id' => $aTrack['object_id']
+        ));
+    }
+
+    protected function _deleteAuthorEntriesTableTrigger($aTrack)
+    {
+        $aScore = $this->getScore($aTrack['object_id']);
+
+        return $this->_updateTriggerTable($aTrack['object_id'], $aScore);
+    }
+}
+
+/** @} */

+ 125 - 0
inc/js/classes/BxDolScore.js

@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+function BxDolScore(options)
+{
+	this._sObjName = undefined == options.sObjName ? 'oScore' : options.sObjName; // javascript object name, to run current object instance from onTimer
+	this._sSystem = options.sSystem; // current comment system
+	this._iAuthorId = options.iAuthorId; // this comment's author ID.
+    this._iObjId = options.iObjId; // this object id comments
+
+    this._sActionsUri = 'score.php';
+    this._sActionsUrl = options.sRootUrl + this._sActionsUri; // actions url address
+
+    this._sAnimationEffect = 'fade';
+    this._iAnimationSpeed = 'slow';
+    this._sSP = undefined == options.sStylePrefix ? 'bx-score' : options.sStylePrefix;
+    this._aHtmlIds = options.aHtmlIds;
+
+    this._iSaveWidth = -1;
+}
+
+BxDolScore.prototype.toggleByPopup = function(oLink) {
+	var $this = this;
+    var oData = this._getDefaultParams();
+    oData['action'] = 'GetVotedBy';
+
+	$(oLink).dolPopupAjax({
+		id: this._aHtmlIds['by_popup'], 
+		url: bx_append_url_params(this._sActionsUri, oData)
+	});
+};
+
+BxDolScore.prototype.voteUp = function (oLink, onComplete)
+{
+	this._vote(oLink, 'up', onComplete);
+};
+
+BxDolScore.prototype.voteDown = function (oLink, onComplete)
+{
+	this._vote(oLink, 'down', onComplete);
+};
+
+BxDolScore.prototype._vote = function (oLink, sType, onComplete)
+{
+    var $this = this;
+    var oParams = this._getDefaultParams();
+    oParams['action'] = 'vote_' + sType;
+
+    $.post(
+    	this._sActionsUrl,
+    	oParams,
+    	function(oData) {
+    		var fContinue = function() {
+    			if(oData && oData.code != 0)
+                    return;
+
+	    		if(oData && oData.label_icon)
+	    			$(oLink).find('.sys-icon').attr('class', 'sys-icon ' + oData.label_icon);
+
+	    		if(oData && oData.label_title) {
+	    			$(oLink).attr('title', oData.label_title);
+	    			$(oLink).find('span').html(oData.label_title);
+	    		}
+
+	    		if(oData && oData.disabled)
+	    			$this._getActions(oLink).removeAttr('onclick').addClass($(oLink).hasClass('bx-btn') ? 'bx-btn-disabled' : 'bx-score-disabled');
+
+                var oCounter = $this._getCounter(oLink);
+                if(oCounter && oCounter.length > 0) {
+                	oCounter.html(oData.scoref);
+
+                	oCounter.parents('.' + $this._sSP + '-counter-holder:first:hidden').bx_anim('show');
+                }
+
+                if(typeof onComplete == 'function')
+                	onComplete(oLink, oData);
+    		};
+
+    		if(oData && oData.message != undefined)
+                bx_alert(oData.message, fContinue);
+    		else
+    			fContinue();
+        },
+        'json'
+    );
+};
+
+BxDolScore.prototype._getActions = function(oElement) {
+	var oParent = $(oElement);
+	if(!oParent.hasClass(this._sSP))
+		oParent = $(oElement).parents('.' + this._sSP + ':first');
+
+	return oParent.find('.' + this._sSP + '-do-vote');
+};
+
+BxDolScore.prototype._getCounter = function(oElement) {
+	var oParent = $(oElement);
+	if(!oParent.hasClass(this._sSP))
+		oParent = $(oElement).parents('.' + this._sSP + ':first');
+
+	return oParent.find('.' + this._sSP + '-counter');
+};
+
+BxDolScore.prototype._loadingInButton = function(e, bShow) {
+	if($(e).length)
+		bx_loading_btn($(e), bShow);
+	else
+		bx_loading($('body'), bShow);	
+};
+
+BxDolScore.prototype._getDefaultParams = function() {
+	var oDate = new Date();
+    return {
+        sys: this._sSystem,
+        id: this._iObjId,
+        _t: oDate.getTime()
+    };
+};
+
+/** @} */

File diff ditekan karena terlalu besar
+ 0 - 0
install/sql/system.sql


+ 9 - 2
modules/base/general/classes/BxBaseModGeneralFormsEntryHelper.php

@@ -15,11 +15,18 @@
 class BxBaseModGeneralFormsEntryHelper extends BxDolProfileForms
 {
     protected $_oModule;
+    protected $_bDynamicMode;
 
     public function __construct($oModule)
     {
         parent::__construct();
         $this->_oModule = $oModule;
+        $this->_bDynamicMode = false;
+    }
+
+    public function setDynamicMode($bDynamicMode)
+    {
+        $this->_bDynamicMode = (bool)$bDynamicMode;
     }
 
     public function getObjectStorage()
@@ -148,14 +155,14 @@ class BxBaseModGeneralFormsEntryHelper extends BxDolProfileForms
         $oForm->initChecker();
 
         if (!$oForm->isSubmittedAndValid())
-            return $oForm->getCode();
+            return $oForm->getCode($this->_bDynamicMode);
 
         // insert data into database
         $aValsToAdd = array ();
         $iContentId = $oForm->insert ($aValsToAdd);
         if (!$iContentId) {
             if (!$oForm->isValid())
-                return $oForm->getCode();
+                return $oForm->getCode($this->_bDynamicMode);
             else
                 return MsgBox(_t('_sys_txt_error_entry_creation'));
         }

+ 19 - 2
modules/base/general/classes/BxBaseModGeneralModule.php

@@ -346,11 +346,20 @@ class BxBaseModGeneralModule extends BxDolModule
      * Create entry form
      * @return HTML string
      */
-    public function serviceEntityCreate ($sDisplay = false)
+    public function serviceEntityCreate ($sParams = false)
     {
+        $bParamsArray = is_array($sParams);
+
+        $sDisplay = is_string($sParams) ? $sParams : false;
+        if($bParamsArray && !empty($sParams['display']))
+            $sDisplay = $sParams['display'];
+
         bx_import('FormsEntryHelper', $this->_aModule);
         $sClass = $this->_aModule['class_prefix'] . 'FormsEntryHelper';
         $oFormsHelper = new $sClass($this);
+        if($bParamsArray && isset($sParams['dynamic_mode']))
+            $oFormsHelper->setDynamicMode($sParams['dynamic_mode']);
+
         return $oFormsHelper->addDataForm($sDisplay);
     }
 
@@ -473,6 +482,7 @@ class BxBaseModGeneralModule extends BxDolModule
             'object_transcoder' => false,
         	'object_view' => !empty($CNF['OBJECT_VIEWS']) ? $CNF['OBJECT_VIEWS'] : '',
         	'object_vote' => !empty($CNF['OBJECT_VOTES']) ? $CNF['OBJECT_VOTES'] : '',
+        	'object_score' => !empty($CNF['OBJECT_SCORES']) ? $CNF['OBJECT_SCORES'] : '',
         	'object_favorite' => !empty($CNF['OBJECT_FAVORITES']) ? $CNF['OBJECT_FAVORITES'] : '',
             'object_feature' => !empty($CNF['OBJECT_FEATURED']) ? $CNF['OBJECT_FEATURED'] : '',
         	'object_report' => !empty($CNF['OBJECT_REPORTS']) ? $CNF['OBJECT_REPORTS'] : '',
@@ -1240,6 +1250,12 @@ class BxBaseModGeneralModule extends BxDolModule
         if ($oVotes)
             $sVotes = $oVotes->getElementBlock(array('show_do_vote_as_button' => $bShowAsButton));
 
+        //--- Scores
+        $sScores = '';
+        $oScores = !empty($aParams['object_score']) ? BxDolScore::getObjectInstance($aParams['object_score'], $iId) : false;
+        if ($oScores)
+            $sScores = $oScores->getElementBlock(array('show_do_vote_as_button' => $bShowAsButton));
+
         //--- Favorite
         $sFavorites = '';
         $oFavorites = !empty($aParams['object_favorite']) ? BxDolFavorite::getObjectInstance($aParams['object_favorite'], $iId) : false;
@@ -1276,13 +1292,14 @@ class BxBaseModGeneralModule extends BxDolModule
             $sSocial = $oSocial->getCode();
         }
 
-        if(empty($sComments)  && empty($sViews) && empty($sVotes) && empty($sFavorites)  && empty($sFeatured) && empty($sRepost) && empty($sReport) && empty($sSocial))
+        if(empty($sComments)  && empty($sViews) && empty($sVotes) && empty($sScores) && empty($sFavorites)  && empty($sFeatured) && empty($sRepost) && empty($sReport) && empty($sSocial))
             return '';
 
         return $this->_oTemplate->parseHtmlByName('entry-share.html', array(
             'comments' => $sComments,
         	'view' => $sViews,
             'vote' => $sVotes,
+        	'score' => $sScores,
             'favorite' => $sFavorites,
             'feature' => $sFeatured,
             'repost' => $sRepost,

+ 1 - 0
modules/base/general/template/css/main.css

@@ -7,6 +7,7 @@
 .bx-base-general-entity-share .bx-base-general-comments,
 .bx-base-general-entity-share .bx-view,
 .bx-base-general-entity-share .bx-vote,
+.bx-base-general-entity-share .bx-score,
 .bx-base-general-entity-share .bx-favorite,
 .bx-base-general-entity-share .bx-feature,
 .bx-base-general-entity-share .bx-report,

+ 1 - 1
modules/base/general/template/entry-share.html

@@ -1 +1 @@
-<div class="bx-base-general-entity-share bx-clearfix">__comments____view____vote____favorite____feature____repost____report____social__</div>
+<div class="bx-base-general-entity-share bx-clearfix">__comments____view____vote____score____favorite____feature____repost____report____social__</div>

+ 21 - 0
modules/boonex/decorous/data/template/system/scripts/BxTemplScore.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolScore
+ */
+class BxTemplScore extends BxBaseScore
+{
+    function __construct($sSystem, $iId, $iInit = true, $oTemplate = false)
+    {
+        parent::__construct($sSystem, $iId, $iInit, $oTemplate);
+    }
+}
+
+/** @} */

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

@@ -2440,6 +2440,12 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_request_page_not_found_cnt"><![CDATA[Page({0}) was not found in module({1})]]></string>
 	<string name="_sys_request_method_not_found_cpt"><![CDATA[Method was not found]]></string>
 	<string name="_sys_request_method_not_found_cnt"><![CDATA[Method({0}) was not found in module({1})]]></string>
+	<string name="_sys_score_counter"><![CDATA[{0}]]></string>
+	<string name="_sys_score_do_up"><![CDATA[Up vote]]></string>
+	<string name="_sys_score_do_down"><![CDATA[Down vote]]></string>
+	<string name="_sys_score_do_by"><![CDATA[Voted by]]></string>
+	<string name="_sys_score_err_not_enabled"><![CDATA[The feature is not available right now. Please, try again later.]]></string>
+    <string name="_sys_score_err_duplicate_vote"><![CDATA[Duplicate vote]]></string>
 	<string name="_sys_search_main_title"><![CDATA[Search Home]]></string>
 	<string name="_sys_select"><![CDATA[Select]]></string>
 	<string name="_sys_send"><![CDATA[Send]]></string>

+ 21 - 0
modules/boonex/ocean/data/template/system/scripts/BxTemplScore.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolScore
+ */
+class BxTemplScore extends BxBaseScore
+{
+    function __construct($sSystem, $iId, $iInit = true, $oTemplate = false)
+    {
+        parent::__construct($sSystem, $iId, $iInit, $oTemplate);
+    }
+}
+
+/** @} */

+ 1 - 1
modules/boonex/polls/classes/BxPollsVoteSubentries.php

@@ -81,7 +81,7 @@ class BxPollsVoteSubentries extends BxTemplVote
         return $aContentInfo[$this->_aSystem['trigger_field_author']];
     }
 
-    public function isPerformed($iObjectId, $iAuthorId)
+    public function isPerformed($iObjectId, $iAuthorId, $iAuthorIp = 0)
     {
         $CNF = $this->_oModule->_oConfig->CNF;
 

+ 1 - 0
modules/boonex/posts/classes/BxPostsConfig.php

@@ -80,6 +80,7 @@ class BxPostsConfig extends BxBaseModTextConfig
         	'OBJECT_REPORTS' => 'bx_posts',
             'OBJECT_VIEWS' => 'bx_posts',
             'OBJECT_VOTES' => 'bx_posts',
+        	'OBJECT_SCORES' => 'bx_posts',
         	'OBJECT_FAVORITES' => 'bx_posts',
             'OBJECT_FEATURED' => 'bx_posts',
             'OBJECT_METATAGS' => 'bx_posts',

+ 26 - 0
modules/boonex/posts/install/sql/install.sql

@@ -15,6 +15,9 @@ CREATE TABLE IF NOT EXISTS `bx_posts_posts` (
   `views` int(11) NOT NULL default '0',
   `rate` float NOT NULL default '0',
   `votes` 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',
@@ -162,6 +165,25 @@ CREATE TABLE `bx_posts_favorites_track` (
   KEY `id` (`object_id`,`author_id`)
 );
 
+-- TABLE: scores
+CREATE TABLE IF NOT EXISTS `bx_posts_scores` (
+  `object_id` int(11) NOT NULL default '0',
+  `count_up` int(11) NOT NULL default '0',
+  `count_down` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_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
 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
@@ -280,6 +302,10 @@ INSERT INTO `sys_objects_cmts` (`Name`, `Module`, `Table`, `CharsPostMin`, `Char
 INSERT INTO `sys_objects_vote` (`Name`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
 ('bx_posts', 'bx_posts_votes', 'bx_posts_votes_track', '604800', '1', '1', '0', '1', 'bx_posts_posts', 'id', 'author', 'rate', 'votes', '', '');
 
+-- 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_posts', 'bx_posts', 'bx_posts_scores', 'bx_posts_scores_track', '604800', '0', 'bx_posts_posts', 'id', 'author', 'score', 'sc_up', 'sc_down', '', '');
+
 -- REPORTS
 INSERT INTO `sys_objects_report` (`name`, `table_main`, `table_track`, `is_on`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
 ('bx_posts', 'bx_posts_reports', 'bx_posts_reports_track', '1', 'page.php?i=view-post&id={object_id}', 'bx_posts_posts', 'id', 'author', 'reports', '', '');

+ 4 - 1
modules/boonex/posts/install/sql/uninstall.sql

@@ -1,6 +1,6 @@
 
 -- TABLES
-DROP TABLE IF EXISTS `bx_posts_posts`, `bx_posts_files`, `bx_posts_photos_resized`, `bx_posts_cmts`, `bx_posts_votes`, `bx_posts_votes_track`, `bx_posts_views_track`, `bx_posts_meta_keywords`, `bx_posts_meta_locations`, `bx_posts_meta_mentions`, `bx_posts_reports`, `bx_posts_reports_track`, `bx_posts_favorites_track`;
+DROP TABLE IF EXISTS `bx_posts_posts`, `bx_posts_files`, `bx_posts_photos_resized`, `bx_posts_cmts`, `bx_posts_votes`, `bx_posts_votes_track`, `bx_posts_views_track`, `bx_posts_meta_keywords`, `bx_posts_meta_locations`, `bx_posts_meta_mentions`, `bx_posts_reports`, `bx_posts_reports_track`, `bx_posts_favorites_track`, `bx_posts_scores`, `bx_posts_scores_track`;
 
 -- STORAGES & TRANSCODERS
 DELETE FROM `sys_objects_storage` WHERE `object` = 'bx_posts_files' OR `object` = 'bx_posts_photos_resized';
@@ -27,6 +27,9 @@ DELETE FROM `sys_objects_cmts` WHERE `Name` = 'bx_posts';
 -- VOTES
 DELETE FROM `sys_objects_vote` WHERE `Name` = 'bx_posts';
 
+-- SCORES
+DELETE FROM `sys_objects_score` WHERE `name` = 'bx_posts';
+
 -- REPORTS
 DELETE FROM `sys_objects_report` WHERE `name` = 'bx_posts';
 

+ 21 - 0
modules/boonex/protean/data/template/system/scripts/BxTemplScore.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolScore
+ */
+class BxTemplScore extends BxBaseScore
+{
+    function __construct($sSystem, $iId, $iInit = true, $oTemplate = false)
+    {
+        parent::__construct($sSystem, $iId, $iInit, $oTemplate);
+    }
+}
+
+/** @} */

+ 7 - 1
modules/boonex/russian/data/langs/system/ru.xml

@@ -2439,6 +2439,12 @@
 	<string name="_sys_request_page_not_found_cnt"><![CDATA[Страница({0}) не найдена в модуле ({1})]]></string>
 	<string name="_sys_request_method_not_found_cpt"><![CDATA[Метод не найден]]></string>
 	<string name="_sys_request_method_not_found_cnt"><![CDATA[Метод ({0}) не найден в модуле ({1})]]></string>
+	<string name="_sys_score_counter"><![CDATA[{0}]]></string>
+    <string name="_sys_score_do_up"><![CDATA[Проголосовать за]]></string>
+    <string name="_sys_score_do_down"><![CDATA[Проголосовать против]]></string>
+    <string name="_sys_score_do_by"><![CDATA[Проголосовали]]></string>
+    <string name="_sys_score_err_not_enabled"><![CDATA[Ваш голос не может быть принят в данный момент. Пожалуйста, попробуйте позднее.]]></string>
+    <string name="_sys_score_err_duplicate_vote"><![CDATA[Повторный голос]]></string>
 	<string name="_sys_search_main_title"><![CDATA[Поиск - Домой]]></string>
 	<string name="_sys_select"><![CDATA[Выбрать]]></string>
 	<string name="_sys_send"><![CDATA[Послать]]></string>
@@ -2645,7 +2651,7 @@
 	<string name="_vote_counter"><![CDATA[{0}]]></string>
 	<string name="_vote_do_like"><![CDATA[Спасибо!]]></string>
 	<string name="_vote_do_unlike"><![CDATA[Нет, спасибо]]></string>
-	<string name="_vote_do_by"><![CDATA[Поблагодарил]]></string>
+	<string name="_vote_do_by"><![CDATA[Поблагодарили]]></string>
 	<string name="_vote_err_not_enabled"><![CDATA[Ваш голос не может быть принят в данный момент. Пожалуйста, попробуйте позднее.]]></string>
 	<string name="_vote_err_duplicate_vote"><![CDATA[Повторный голос]]></string>
 	<string name="_week_fri"><![CDATA[Пятница]]></string>

+ 30 - 0
score.php

@@ -0,0 +1,30 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+require_once('./inc/header.inc.php');
+require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
+
+bx_import('BxDolLanguages');
+
+check_logged();
+
+$sSys = isset($_REQUEST['sys']) ? bx_process_input($_REQUEST['sys']) : false;
+$iObjectId = isset($_REQUEST['id']) ? bx_process_input($_REQUEST['id'], BX_DATA_INT) : 0;
+$sAction = isset($_REQUEST['action']) && preg_match ('/^[A-Za-z_-]+$/', $_REQUEST['action']) ? bx_process_input($_REQUEST['action']) : '';
+
+$oScore = BxDolScore::getObjectInstance($sSys, $iObjectId, true);
+
+if ($oScore && $sSys && $iObjectId && $sAction) {
+    header('Content-Type: text/html; charset=utf-8');
+    $sMethod = 'action' . bx_gen_method_name($sAction);
+    if(method_exists($oScore, $sMethod))
+        echo $oScore->$sMethod();
+}
+
+/** @} */

+ 50 - 0
template/css/score.css

@@ -0,0 +1,50 @@
+/*--- Comment Plused By ---*/
+div.bx-score-by-list {}
+div.bx-score-by-list-cnt {
+	max-height: 200px;
+	max-height: 12.5rem;
+	min-width: 220px;
+	min-width: 13.75rem;
+	overflow: auto;
+}
+div.bx-score-by-list div.bx-base-pofile-unit {
+	float: none;
+	margin-right: 0px;
+	margin-bottom: 0px;
+}
+
+/*--- Vote Element Styles ---*/
+div.bx-score-element-holder,
+div.bx-score-counter-holder {
+	position: relative;
+	float: left;
+
+	line-height: 20px;
+    line-height: 1.25rem;
+}
+
+.bx-score-button .bx-score-element-holder,
+.bx-score-button .bx-score-counter-holder {
+	line-height: 36px;
+	line-height: 2.2rem;
+}
+
+.bx-score-button-small .bx-score-element-holder,
+.bx-score-button-small .bx-score-counter-holder {
+	line-height: 24px;
+	line-height: 1.6rem;
+}
+
+.bx-score-element-holder .bx-score-do-vote.bx-score-disabled,
+.bx-score-element-holder .bx-score-do-vote.bx-score-disabled .sys-icon {
+	color: #ddd;
+}
+
+.bx-score:not(.bx-score-button):not(.bx-score-button-small) .bx-score-counter-holder.bx-btn-border {
+    border-width: 0px;
+}
+
+.bx-score-button .bx-score-counter-holder,
+.bx-score-button-small .bx-score-counter-holder {
+	font-size: 1.5rem;
+}

+ 9 - 0
template/score_by_list.html

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

+ 1 - 0
template/score_do_vote_label.html

@@ -0,0 +1 @@
+<bx_if:show_image><img src="__src__" /></bx_if:show_image><bx_if:show_icon><i class="sys-icon __name__"></i></bx_if:show_icon><bx_if:show_text><span class="bx-def-margin-sec-left-auto">__text__</span></bx_if:show_text>

+ 15 - 0
template/score_element_block.html

@@ -0,0 +1,15 @@
+<div id="__html_id__" class="__style_prefix__ __class__ bx-def-margin-right-auto bx-def-margin-thd-topbottom" bx_score_data_score="__score__" bx_score_data_cup="__cup__" bx_score_data_cdown="__cdown__">
+	<div class="__style_prefix__-do bx-clearfix">
+		<bx_if:show_do_vote_up>
+			<div class="__style_prefix__-element-holder __style_prefix__-eh-up">__do_vote__</div>
+		</bx_if:show_do_vote_up>
+		<bx_if:show_counter>
+			<div class="__style_prefix__-counter-holder bx-def-margin-sec-left-auto bx-btn-border"<bx_if:show_hidden> style="display:none"</bx_if:show_hidden>>__counter__</div>
+		</bx_if:show_counter>
+		<bx_if:show_do_vote_down>
+            <div class="__style_prefix__-element-holder __style_prefix__-eh-down bx-def-margin-sec-left-auto">__do_vote__</div>
+        </bx_if:show_do_vote_down>
+	</div>
+	<bx_if:show_legend>__legend__</bx_if:show_legend>
+	__script__
+</div>

+ 3 - 0
template/score_element_inline.html

@@ -0,0 +1,3 @@
+<span id="__html_id__" class="__style_prefix__ __class__ bx-def-margin-right-auto bx-def-margin-thd-topbottom" bx_score_data_score="__score__" bx_score_data_cup="__cup__" bx_score_data_cdown="__cdown__">
+	<span class="__style_prefix__-do"><bx_if:show_do_vote_up><span class="__style_prefix__-element-holder __style_prefix__-eh-up">__do_vote__</span></bx_if:show_do_vote_up><bx_if:show_counter><span class="__style_prefix__-counter-holder bx-def-margin-thd-left-auto bx-btn-border"<bx_if:show_hidden> style="display:none"</bx_if:show_hidden>>__counter__</span></bx_if:show_counter><bx_if:show_do_vote_down><span class="__style_prefix__-element-holder __style_prefix__-eh-down bx-def-margin-thd-left-auto">__do_vote__</span></bx_if:show_do_vote_down></span>__script__
+</span>

+ 8 - 0
template/score_legend.html

@@ -0,0 +1,8 @@
+<div id="__html_id__" class="__style_prefix__-legend bx-def-margin-top-auto">
+	<bx_repeat:items>
+		<div class="__style_prefix__-legend-item bx-def-margin-thd-topbottom bx-clearfix">
+			<div class="__style_prefix__-element-holder">__value__</div>
+			<div class="__style_prefix__-counter-holder bx-def-margin-sec-left bx-def-font-grayed">__label__</div>
+		</div>
+	</bx_repeat:items>
+</div>

+ 367 - 0
template/scripts/BxBaseScore.php

@@ -0,0 +1,367 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaBaseView UNA Base Representation Classes
+ * @{
+ */
+
+/**
+ * @see BxDolScore
+ */
+class BxBaseScore extends BxDolScore
+{
+    protected static $_sTmplContentElementBlock;
+    protected static $_sTmplContentElementInline;
+    protected static $_sTmplContentDoVoteLabel;
+
+	protected $_bCssJsAdded;
+
+    protected $_sJsObjName;
+    protected $_sStylePrefix;
+
+    protected $_aHtmlIds;
+
+    protected $_aElementDefaults;
+
+    protected $_sTmplNameLegend;
+    protected $_sTmplNameByList;
+
+    public function __construct($sSystem, $iId, $iInit = true, $oTemplate = false)
+    {
+        parent::__construct($sSystem, $iId, $iInit, $oTemplate);
+
+        $this->_bCssJsAdded = false;
+
+        $this->_sJsObjName = 'oScore' . bx_gen_method_name($sSystem, array('_' , '-')) . $iId;
+        $this->_sStylePrefix = 'bx-score';
+
+        $sHtmlId = str_replace(array('_' , ' '), array('-', '-'), $sSystem) . '-' . $iId;
+        $this->_aHtmlIds = array(
+            'main' => 'bx-score-' . $sHtmlId,
+            'counter' => 'bx-score-counter-' . $sHtmlId,
+            'by_popup' => 'bx-score-by-popup-' . $sHtmlId,
+        	'legend' => 'bx-score-legend-' . $sHtmlId,
+        );
+
+        $this->_aElementDefaults = array(
+            'show_do_vote_as_button' => false,
+            'show_do_vote_as_button_small' => false,
+            'show_do_vote_image' => false,
+            'show_do_vote_icon' => true,
+            'show_do_vote_label' => false,
+            'show_counter' => true,
+        	'show_counter_empty' => false,
+        	'show_legend' => false
+        );
+
+        $this->_sTmplNameLegend = 'score_legend.html';
+        $this->_sTmplNameByList = 'score_by_list.html';
+
+        if(empty(self::$_sTmplContentElementBlock))
+            self::$_sTmplContentElementBlock = $this->_oTemplate->getHtml('score_element_block.html');
+
+        if(empty(self::$_sTmplContentElementInline))
+            self::$_sTmplContentElementInline = $this->_oTemplate->getHtml('score_element_inline.html');
+
+        if(empty(self::$_sTmplContentDoVoteLabel))
+            self::$_sTmplContentDoVoteLabel = $this->_oTemplate->getHtml('score_do_vote_label.html');
+    }
+
+    public function addCssJs($bDynamicMode = false)
+    {
+    	if($bDynamicMode || $this->_bCssJsAdded)
+    		return;
+
+    	$this->_oTemplate->addJs(array('jquery.anim.js', 'BxDolScore.js'));
+        $this->_oTemplate->addCss(array('score.css'));
+
+        $this->_bCssJsAdded = true;
+    }
+
+    public function getJsObjectName()
+    {
+        return $this->_sJsObjName;
+    }
+
+    public function getJsScript($bDynamicMode = false)
+    {
+        $aParams = array(
+            'sObjName' => $this->_sJsObjName,
+            'sSystem' => $this->getSystemName(),
+            'iAuthorId' => $this->_getAuthorId(),
+            'iObjId' => $this->getId(),
+            'sRootUrl' => BX_DOL_URL_ROOT,
+            'sStylePrefix' => $this->_sStylePrefix,
+            'aHtmlIds' => $this->_aHtmlIds
+        );
+        $sCode = $this->_sJsObjName . " = new BxDolScore(" . json_encode($aParams) . ");";
+
+        if($bDynamicMode) {
+			$sCode = "var " . $this->_sJsObjName . " = null; 
+			$.getScript('" . bx_js_string($this->_oTemplate->getJsUrl('BxDolScore.js'), BX_ESCAPE_STR_APOS) . "', function(data, textStatus, jqxhr) {
+				bx_get_style('" . bx_js_string($this->_oTemplate->getCssUrl('score.css'), BX_ESCAPE_STR_APOS) . "');
+				" . $sCode . "
+        	}); ";
+        }
+        else
+        	$sCode = "var " . $sCode;
+
+        $this->addCssJs($bDynamicMode);
+        return $this->_oTemplate->_wrapInTagJsCode($sCode);
+    }
+
+    public function getJsClick($sType)
+    {
+        return $this->getJsObjectName() . '.vote' . ucfirst($sType) . '(this)';
+    }
+
+    public function getJsClickCounter()
+    {
+        return $this->getJsObjectName() . '.toggleByPopup(this)';
+    }
+
+    public function getCounter($aParams = array())
+    {
+        $sJsObject = $this->getJsObjectName();
+
+        $bShowEmpty = isset($aParams['show_counter_empty']) && $aParams['show_counter_empty'] == true;
+        $bShowDoVoteAsButtonSmall = isset($aParams['show_do_vote_as_button_small']) && $aParams['show_do_vote_as_button_small'] == true;
+        $bShowDoVoteAsButton = !$bShowDoVoteAsButtonSmall && isset($aParams['show_do_vote_as_button']) && $aParams['show_do_vote_as_button'] == true;
+
+        $aScore = $this->_oQuery->getScore($this->getId());
+        $sClass = $this->_sStylePrefix . '-counter';
+        if($bShowDoVoteAsButtonSmall)
+            $sClass .= ' bx-btn-small-height';
+        if($bShowDoVoteAsButton)
+            $sClass .= ' bx-btn-height';
+
+        $iCup = (int)$aScore['count_up'];
+        $iCdown = (int)(int)$aScore['count_down'];
+        $sCounter = $bShowEmpty || $iCup > 0 || $iCdown > 0 ? $this->_getLabelCounter($iCup - $iCdown) : '';
+        return $this->_oTemplate->parseLink('javascript:void(0)', $sCounter, array(
+            'id' => $this->_aHtmlIds['counter'],
+            'class' => $sClass,
+            'title' => _t($this->_getTitleDoBy()),
+            'onclick' => 'javascript:' . $this->getJsClickCounter() 
+        ));
+    }
+
+    public function getLegend($aParams = array())
+    {
+        $aLegend = $this->_oQuery->getLegend($this->_iId);
+        $aTypes = array(
+            BX_DOL_SCORE_DO_UP,
+            BX_DOL_SCORE_DO_DOWN
+        );
+
+        $aTmplVarsItems = array();
+        foreach($aTypes as $sType)
+	        $aTmplVarsItems[] = array(
+	        	'style_prefix' => $this->_sStylePrefix,
+	            'value' => $this->_getLabelDo($sType, $aParams),
+	        	'label' => isset($aLegend[$sType]['count']) ? (int)$aLegend[$sType]['count'] : 0
+	        );
+
+        return $this->_oTemplate->parseHtmlByName($this->_sTmplNameLegend, array(
+        	'style_prefix'  => $this->_sStylePrefix,
+        	'html_id' => $this->_aHtmlIds['legend'],
+        	'bx_repeat:items' => $aTmplVarsItems
+        ));
+    }
+
+    public function getElementBlock($aParams = array())
+    {
+        $aParams['usage'] = BX_DOL_SCORE_USAGE_BLOCK;
+
+        return $this->getElement($aParams);
+    }
+
+    public function getElementInline($aParams = array())
+    {
+        $aParams['usage'] = BX_DOL_SCORE_USAGE_INLINE;
+
+        return $this->getElement($aParams);
+    }
+
+    public function getElement($aParams = array())
+    {
+    	$aParams = array_merge($this->_aElementDefaults, $aParams);
+    	$bDynamicMode = isset($aParams['dynamic_mode']) && $aParams['dynamic_mode'] === true;
+
+        $bShowDoVoteAsButtonSmall = isset($aParams['show_do_vote_as_button_small']) && $aParams['show_do_vote_as_button_small'] == true;
+        $bShowDoVoteAsButton = !$bShowDoVoteAsButtonSmall && isset($aParams['show_do_vote_as_button']) && $aParams['show_do_vote_as_button'] == true;
+        $bShowCounterEmpty = isset($aParams['show_counter_empty']) && $aParams['show_counter_empty'] == true;
+
+		$iObjectId = $this->getId();
+		$iAuthorId = $this->_getAuthorId();
+		$iAuthorIp = $this->_getAuthorIp();
+		$aScore = $this->_oQuery->getScore($iObjectId);
+        $bCount = (int)$aScore['count_up'] != 0 || (int)$aScore['count_down'] != 0;
+
+        $isAllowedVote = $this->isAllowedVote();
+        $aParams['is_voted'] = $this->isPerformed($iObjectId, $iAuthorId, $iAuthorIp) ? true : false;
+
+        //--- Do Vote
+        $bTmplVarsDoVote = $this->_isShowDoVote($aParams, $isAllowedVote, $bCount);
+        $aTmplVarsDoVoteUp = $aTmplVarsDoVoteDown = array();
+        if($bTmplVarsDoVote)
+        	$aTmplVarsDoVoteUp = array(
+				'style_prefix' => $this->_sStylePrefix,
+				'do_vote' => $this->_getDoVote(BX_DOL_SCORE_DO_UP, $aParams, $isAllowedVote),
+			);
+        
+        if($bTmplVarsDoVote)
+        	$aTmplVarsDoVoteDown = array(
+				'style_prefix' => $this->_sStylePrefix,
+        		'do_vote' => $this->_getDoVote(BX_DOL_SCORE_DO_DOWN, $aParams, $isAllowedVote),
+			);
+
+        //--- Counter
+        $bTmplVarsCounter = $this->_isShowCounter($aParams, $isAllowedVote, $bCount);
+        $aTmplVarsCounter = array();
+        if($bTmplVarsCounter)
+        	$aTmplVarsCounter = array(
+				'style_prefix' => $this->_sStylePrefix,
+				'bx_if:show_hidden' => array(
+					'condition' => !$bShowCounterEmpty && !$bCount,
+					'content' => array()
+				),
+				'counter' => $this->getCounter($aParams)
+        	);
+
+		//--- Legend
+		$bTmplVarsLegend = $this->_isShowLegend($aParams, $isAllowedVote, $bCount);
+		$aTmplVarsLegend = array();
+		if($bTmplVarsLegend)
+			$aTmplVarsLegend = array(
+				'legend' => $this->getLegend($aParams)
+			);
+
+		if(!$bTmplVarsDoVote && !$bTmplVarsCounter && !$bTmplVarsLegend)
+			return '';
+
+        $sTmplName = self::${'_sTmplContentElement' . bx_gen_method_name(!empty($aParams['usage']) ? $aParams['usage'] : BX_DOL_SCORE_USAGE_DEFAULT)};
+        return $this->_oTemplate->parseHtmlByContent($sTmplName, array(
+            'style_prefix' => $this->_sStylePrefix,
+            'html_id' => $this->_aHtmlIds['main'],
+            'class' => $this->_sStylePrefix . ($bShowDoVoteAsButton ? '-button' : '') . ($bShowDoVoteAsButtonSmall ? '-button-small' : ''),
+            'score' => $aScore['score'],
+            'cup' => $aScore['count_up'],
+        	'cdown' => $aScore['count_down'],
+        	'bx_if:show_do_vote_up' => array(
+        		'condition' => $bTmplVarsDoVote,
+        		'content' => $aTmplVarsDoVoteUp
+        	),
+        	'bx_if:show_counter' => array(
+				'condition' => $bTmplVarsCounter,
+				'content' => $aTmplVarsCounter
+			),
+			'bx_if:show_do_vote_down' => array(
+        		'condition' => $bTmplVarsDoVote,
+        		'content' => $aTmplVarsDoVoteDown
+        	),
+            'bx_if:show_legend' => array(
+            	'condition' => $bTmplVarsLegend,
+            	'content' => $aTmplVarsLegend
+            ),
+            'script' => $this->getJsScript($bDynamicMode)
+        ));
+    }
+
+    protected function _getDoVote($sType, $aParams = array(), $isAllowedVote = true)
+    {
+    	$bVoted = isset($aParams['is_voted']) && $aParams['is_voted'] === true;
+        $bShowDoVoteAsButtonSmall = isset($aParams['show_do_vote_as_button_small']) && $aParams['show_do_vote_as_button_small'] == true;
+        $bShowDoVoteAsButton = !$bShowDoVoteAsButtonSmall && isset($aParams['show_do_vote_as_button']) && $aParams['show_do_vote_as_button'] == true;
+		$bDisabled = !$isAllowedVote || $bVoted;
+
+        $sClass = '';
+		if($bShowDoVoteAsButton)
+			$sClass = 'bx-btn';
+		else if ($bShowDoVoteAsButtonSmall)
+			$sClass = 'bx-btn bx-btn-small';
+
+		if($bDisabled)
+			$sClass .= $bShowDoVoteAsButton || $bShowDoVoteAsButtonSmall ? ' bx-btn-disabled' : 'bx-score-disabled';
+
+        return $this->_oTemplate->parseLink('javascript:void(0)', $this->_getLabelDo($sType, $aParams), array(
+            'class' => $this->_sStylePrefix . '-do-vote ' . $this->_sStylePrefix . '-dv-' . $sType . ' ' . $sClass,
+            'title' => _t($this->_getTitleDo($sType)),
+            'onclick' => !$bDisabled ? $this->getJsClick($sType) : ''
+        ));
+    }
+
+    protected function _getLabelCounter($iCount)
+    {
+        return _t('_sys_score_counter', $iCount);
+    }
+
+    protected function _getLabelDo($sType, $aParams = array())
+    {
+        return $this->_oTemplate->parseHtmlByContent(self::$_sTmplContentDoVoteLabel, array(
+        	'bx_if:show_image' => array(
+        		'condition' => isset($aParams['show_do_vote_image']) && $aParams['show_do_vote_image'] == true,
+        		'content' => array(
+        			'src' => $this->_getImageDo($sType)
+        		)
+        	),
+        	'bx_if:show_icon' => array(
+        		'condition' => isset($aParams['show_do_vote_icon']) && $aParams['show_do_vote_icon'] == true,
+        		'content' => array(
+        			'name' => $this->_getIconDo($sType)
+        		)
+        	),
+        	'bx_if:show_text' => array(
+        		'condition' => isset($aParams['show_do_vote_label']) && $aParams['show_do_vote_label'] == true,
+        		'content' => array(
+        			'text' => _t($this->_getTitleDo($sType))
+        		)
+        	)
+        ));
+    }
+
+    protected function _getVotedBy()
+    {
+        $aTmplUsers = array();
+
+        $aUserIds = $this->_oQuery->getPerformedBy($this->getId());
+        foreach($aUserIds as $iUserId) {
+            list($sUserName, $sUserUrl, $sUserIcon, $sUserUnit) = $this->_getAuthorInfo($iUserId);
+            $aTmplUsers[] = array(
+                'style_prefix' => $this->_sStylePrefix,
+                'user_unit' => $sUserUnit
+            );
+        }
+
+        if(empty($aTmplUsers))
+            $aTmplUsers = MsgBox(_t('_Empty'));
+
+        return $this->_oTemplate->parseHtmlByName($this->_sTmplNameByList, array(
+            'style_prefix' => $this->_sStylePrefix,
+            'bx_repeat:list' => $aTmplUsers
+        ));
+    }
+
+    protected function _isShowDoVote($aParams, $isAllowedVote, $bCount)
+    {
+        $bShowDoVote = !isset($aParams['show_do_vote']) || $aParams['show_do_vote'] == true;
+
+        return $bShowDoVote && ($isAllowedVote || $bCount);
+    }
+
+    protected function _isShowCounter($aParams, $isAllowedVote, $bCount)
+    {
+        $bShowCounter = isset($aParams['show_counter']) && $aParams['show_counter'] === true;
+
+        return $bShowCounter && ($isAllowedVote || $bCount);
+    }
+
+    protected function _isShowLegend($aParams, $isAllowedVote, $bCount)
+    {
+        return isset($aParams['show_legend']) && $aParams['show_legend'] === true;
+    }
+}
+
+/** @} */

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini