瀏覽代碼

Ticket #404 - the engine itself.

AntonLV 9 年之前
父節點
當前提交
34f9c742ac

+ 30 - 0
feature.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['object_id']) ? bx_process_input($_REQUEST['object_id'], BX_DATA_INT) : 0;
+$sAction = isset($_REQUEST['action']) && preg_match ('/^[A-Za-z_-]+$/', $_REQUEST['action']) ? bx_process_input($_REQUEST['action']) : '';
+
+$oFeature = BxDolFeature::getObjectInstance($sSys, $iObjectId, true);
+
+if ($oFeature && $sSys && $iObjectId && $sAction) {
+    header('Content-Type: text/html; charset=utf-8');
+    $sMethod = 'action' . ucfirst($sAction);
+    if(method_exists($oFeature, $sMethod))
+        echo $oFeature->$sMethod();
+}
+
+/** @} */

+ 196 - 0
inc/classes/BxDolFeature.php

@@ -0,0 +1,196 @@
+<?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
+ * @{
+ */
+
+define('BX_DOL_FEATURED_USAGE_BLOCK', 'block');
+define('BX_DOL_FEATURED_USAGE_INLINE', 'inline');
+define('BX_DOL_FEATURED_USAGE_DEFAULT', BX_DOL_FEATURED_USAGE_BLOCK);
+
+/**
+ * @page objects
+ * @section feature Feature
+ * @ref BxDolFeature
+ */
+
+/**
+ * Track any object feature automatically
+ *
+ * Add record to sys_object_feature table to track object feature,
+ * to record feature just create this class instance with your object id,
+ * for example:
+ * @code
+ *  BxDolFeature::getObjectInstance('my_system', 25); // 25 - is object id
+ * @endcode
+ *
+ * Description of sys_object_feature table fields:
+ * @code
+ *  `name` - system name, it is better to use unique module prefix here, lowercase and all spaces are underscored
+ *  `table_track` - table to track feature
+ *  `is_on` - is the system activated
+ *  `trigger_table` - table where you need to update feature field
+ *  `trigger_field_id` - table field id to unique determine object
+ *  `trigger_field_count` - table field where the featuring date is stored
+ *  `class_name` - your custom class name, if you overrride default class
+ *  `class_file` - your custom class path
+ * @endcode
+ *
+ */
+class BxDolFeature extends BxDolObject
+{
+    protected $_sBaseUrl;
+
+    protected function __construct($sSystem, $iId, $iInit = true, $oTemplate = false)
+    {
+        parent::__construct($sSystem, $iId, $iInit, $oTemplate);
+        if(empty($this->_sSystem))
+            return;
+
+        $this->_oQuery = new BxDolFeatureQuery($this);
+
+        $this->_sBaseUrl = BxDolPermalinks::getInstance()->permalink($this->_aSystem['base_url']);
+        if(get_mb_substr($this->_sBaseUrl, 0, 4) != 'http')
+            $this->_sBaseUrl = BX_DOL_URL_ROOT . $this->_sBaseUrl;
+    }
+
+   /**
+     * get feature object instanse
+     * @param $sSys feature object name
+     * @param $iId associated content id, where feature is available
+     * @param $iInit perform initialization
+     * @return null on error, or ready to use class instance
+     */
+    public static function getObjectInstance($sSys, $iId, $iInit = true)
+    {
+        if(isset($GLOBALS['bxDolClasses']['BxDolFeature!' . $sSys . $iId]))
+            return $GLOBALS['bxDolClasses']['BxDolFeature!' . $sSys . $iId];
+
+        $aSystems = self::getSystems();
+        if(!isset($aSystems[$sSys]))
+            return null;
+
+        $sClassName = 'BxTemplFeature';
+        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);
+        return ($GLOBALS['bxDolClasses']['BxDolFeature!' . $sSys . $iId] = $o);
+    }
+
+    public static function &getSystems()
+    {
+        if(!isset($GLOBALS['bx_dol_feature_systems']))
+            $GLOBALS['bx_dol_feature_systems'] = BxDolDb::getInstance()->fromCache('sys_objects_feature', 'getAllWithKey', '
+                SELECT
+                    `id` as `id`,
+                    `name` AS `name`,
+                    `is_on` AS `is_on`,
+                    `is_undo` AS `is_undo`,
+                    `base_url` AS `base_url`,
+                    `trigger_table` AS `trigger_table`,
+                    `trigger_field_id` AS `trigger_field_id`,
+                    `trigger_field_author` AS `trigger_field_author`,
+                    `trigger_field_flag` AS `trigger_field_flag`,
+                    `class_name` AS `class_name`,
+                    `class_file` AS `class_file`
+                FROM `sys_objects_feature`', 'name');
+
+        return $GLOBALS['bx_dol_feature_systems'];
+    }
+
+	/**
+     * Actions functions
+     */
+    public function actionFeature()
+    {
+        return echoJson($this->_doFeature());
+    }
+
+    public function actionGetFeatureBy()
+    {
+        return '';
+    }
+
+    /**
+     * Permissions functions
+     */
+    public function isAllowedFeature($isPerformAction = false)
+    {
+        if(isAdmin())
+            return true;
+
+        return $this->checkAction('feature', $isPerformAction);
+    }
+
+	public function msgErrAllowedFeature()
+    {
+        return $this->checkActionErrorMsg('feature');
+    }
+
+    /**
+     * Auxiliary functions
+     */
+    public function isUndo()
+    {
+        return (int)$this->_aSystem['is_undo'] == 1;
+    }
+
+	/**
+     * Internal functions
+     */
+	protected function _doFeature()
+    {
+        if (!$this->isEnabled())
+           return array('code' => 1, 'msg' => _t('_feature_err_not_enabled'));
+
+        $iObjectId = $this->getId();
+        $iObjectAuthorId = $this->_oQuery->getObjectAuthorId($iObjectId);
+        $iAuthorId = $this->_getAuthorId();
+
+        $bUndo = $this->isUndo();
+        $bPerformed = $this->isPerformed($iObjectId, $iAuthorId);
+        $bPerformUndo = $bPerformed && $bUndo ? true : false;
+
+        if(!$bPerformUndo && !$this->isAllowedFeature())
+            return array('code' => 2, 'msg' => $this->msgErrAllowedFeature());
+
+        if($bPerformed && !$bUndo)
+        	return array('code' => 3, 'msg' => _t('_feature_err_duplicate_feature'));
+
+        if(!$this->_triggerValue($bPerformUndo ? 0 : time()))
+            return array('code' => 4, 'msg' => _t('_feature_err_cannot_perform_action'));
+            
+        if(!$bPerformUndo)
+            $this->isAllowedFeature(true);
+
+        bx_alert($this->_sSystem, ($bPerformUndo ? 'un' : '') . 'feature', $iObjectId, $iAuthorId, array('object_author_id' => $iObjectAuthorId));
+        bx_alert('feature', ($bPerformUndo ? 'un' : '') . 'do', 0, $iAuthorId, array('object_system' => $this->_sSystem, 'object_id' => $iObjectId, 'object_author_id' => $iObjectAuthorId));
+
+        return array(
+        	'eval' => $this->getJsObjectName() . '.onFeature(oData, oElement)',
+        	'code' => 0, 
+        	'label_icon' => $this->_getIconDoFeature(!$bPerformed),
+            'label_title' => _t($this->_getTitleDoFeature(!$bPerformed)),
+            'disabled' => !$bPerformed && !$bUndo
+        );
+    }
+
+    protected function _getIconDoFeature($bPerformed)
+    {
+    	return $bPerformed && $this->isUndo() ? 'star-o' : 'star';
+    }
+
+    protected function _getTitleDoFeature($bPerformed)
+    {
+    	return $bPerformed && $this->isUndo() ? '_feature_do_unfeature' : '_feature_do_feature';
+    }
+}
+
+/** @} */

+ 61 - 0
inc/classes/BxDolFeatureQuery.php

@@ -0,0 +1,61 @@
+<?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 BxDolFeature
+ */
+class BxDolFeatureQuery extends BxDolObjectQuery
+{
+    protected $_sTriggerFieldFlag;
+
+    public function __construct(&$oModule)
+    {
+        parent::__construct($oModule);
+
+        $aSystem = $this->_oModule->getSystemInfo();
+        $this->_sTriggerFieldFlag = isset($aSystem['trigger_field_flag']) ? $aSystem['trigger_field_flag'] : '';
+
+        $this->_sMethodGetEntry = 'getFeature';
+    }
+
+    public function isPerformed($iObjectId, $iAuthorId)
+    {
+        return (int)$this->getObjectFlag($iObjectId) > 0;
+    }
+
+    public function getPerformedBy($iObjectId)
+    {
+        return array();
+    }
+
+    public function getObjectFlag($iId)
+    {
+        $sQuery = $this->prepare("SELECT `{$this->_sTriggerFieldFlag}` FROM `{$this->_sTriggerTable}` WHERE `{$this->_sTriggerFieldId}` = ? LIMIT 1", $iId);
+        return (int)$this->getOne($sQuery);
+    }
+
+    public function updateTriggerTableValue($iObjectId, $iValue)
+    {
+        $sQuery = $this->prepare("UPDATE `{$this->_sTriggerTable}` SET `{$this->_sTriggerFieldFlag}` = ? WHERE `{$this->_sTriggerFieldId}` = ?", (int)$iValue, $iObjectId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    protected function _updateTriggerTable($iObjectId, $aEntry)
+    {
+    	$sQuery = $this->prepare("UPDATE `{$this->_sTriggerTable}` SET `{$this->_sTriggerFieldFlag}` = ? WHERE `{$this->_sTriggerFieldId}` = ?", $aEntry['count'], $iObjectId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+	public function getFeature($iObjectId)
+    {
+        return array('count' => $this->getObjectFlag($iObjectId));
+    }
+}
+
+/** @} */

+ 116 - 0
inc/js/classes/BxDolFeature.js

@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+function BxDolFeature(options)
+{
+	this._sObjName = undefined == options.sObjName ? 'oFeature' : 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 = 'feature.php';
+    this._sActionsUrl = options.sRootUrl + this._sActionsUri; // actions url address
+
+    this._sAnimationEffect = 'fade';
+    this._iAnimationSpeed = 'slow';
+    this._sSP = undefined == options.sStylePrefix ? 'bx-feature' : options.sStylePrefix;
+    this._aHtmlIds = options.aHtmlIds;
+
+    this._oParent = null;
+}
+
+BxDolFeature.prototype.feature = function(oLink) {
+	var $this = this;
+    var oData = this._getDefaultParams();
+    oData['action'] = 'Feature';
+
+    this._oParent = oLink;
+
+    $.get(
+    	this._sActionsUrl,
+    	oData,
+    	function(oData) {
+    		$this.processJson(oData, oLink);
+    	},
+    	'json'
+    );
+};
+
+BxDolFeature.prototype.onFeature = function(oData, oElement)
+{
+	if(oData && oData.msg != undefined && oData.msg.length > 0)
+        alert(oData.msg);
+
+	if(oData && oData.code != 0)
+        return;
+
+	if(oData && oData.label_icon)
+		$(oElement).find('.sys-icon').attr('class', 'sys-icon ' + oData.label_icon);
+
+	if(oData && oData.label_title) {
+		$(oElement).attr('title', oData.label_title);
+		$(oElement).find('span').html(oData.label_title);
+	}
+
+	if(oData && oData.disabled)
+		$(oElement).removeAttr('onclick').addClass($(oElement).hasClass('bx-btn') ? 'bx-btn-disabled' : 'bx-feature-disabled');
+};
+
+BxDolFeature.prototype.processJson = function(oData, oElement) {
+	oElement = oElement != undefined ? oElement : this._oParent;
+
+    //--- Show Message
+    if(oData && oData.msg != undefined)
+        alert(oData.msg);
+    if(oData && oData.message != undefined)
+        alert(oData.message);
+
+    //--- Show Popup
+    if(oData && oData.popup != undefined) {
+    	$('#' + oData.popup_id).remove();
+
+    	$(oData.popup).hide().prependTo('body').dolPopup({
+    		pointer: {
+    			el: oElement
+    		},
+            fog: {
+				color: '#fff',
+				opacity: .7
+            }
+        });
+    }
+
+    //--- Evaluate JS code
+    if (oData && oData.eval != undefined)
+        eval(oData.eval);
+};
+
+BxDolFeature.prototype._getButtons = function(oElement) {
+	if($(oElement).hasClass(this._sSP))
+		return $(oElement).find('.' + this._sSP + '-button');
+	else
+		return $(oElement).parents('.' + this._sSP + ':first').find('.' + this._sSP + '-button');
+};
+
+BxDolFeature.prototype._loadingInButton = function(e, bShow) {
+	if($(e).length)
+		bx_loading_btn($(e), bShow);
+	else
+		bx_loading($('body'), bShow);	
+};
+
+BxDolFeature.prototype._getDefaultParams = function() {
+	var oDate = new Date();
+    return {
+        sys: this._sSystem,
+        object_id: this._iObjId,
+        _t: oDate.getTime()
+    };
+};
+
+/** @} */

文件差異過大導致無法顯示
+ 0 - 0
install/sql/system.sql


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

@@ -39,6 +39,11 @@
 	<string name="_favorite_err_cannot_perform_action"><![CDATA[Cannot perform the action.]]></string>
 	<string name="_favorite_err_duplicate_favorite"><![CDATA[You already favorited this item.]]></string>
 	<string name="_favorite_err_not_enabled"><![CDATA[The feature is not available right now. Please, try again later.]]></string>
+	<string name="_feature_do_feature"><![CDATA[Feature]]></string>
+    <string name="_feature_do_unfeature"><![CDATA[Unfeature]]></string>
+    <string name="_feature_err_cannot_perform_action"><![CDATA[Cannot perform the action.]]></string>
+    <string name="_feature_err_duplicate_feature"><![CDATA[The item was already added in featured list.]]></string>
+    <string name="_feature_err_not_enabled"><![CDATA[The feature is not available right now. Please, try again later.]]></string>
 	<string name="_Female"><![CDATA[Woman]]></string>
 	<string name="_From"><![CDATA[From]]></string>
 	<string name="_Header"><![CDATA[Header]]></string>
@@ -1497,6 +1502,7 @@
 	<string name="_sys_acl_action_every_period"><![CDATA[ every {4} hours]]></string>
 	<string name="_sys_acl_action_favorite"><![CDATA[Favorite]]></string>
 	<string name="_sys_acl_action_favorite_view"><![CDATA[View favorites]]></string>
+	<string name="_sys_acl_action_feature"><![CDATA[Feature]]></string>
 	<string name="_sys_acl_action_view_view"><![CDATA[View views]]></string>
 	<string name="_sys_acl_action_view_view_viewers"><![CDATA[View viewers]]></string>
 	<string name="_sys_acl_action_limit_reached"><![CDATA[You have reached your limit for now. Your current membership ({2}) allows you to {1} no more than {3} times]]></string>

+ 21 - 0
modules/boonex/ocean/data/template/system/scripts/BxTemplFeature.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 BxDolFeature
+ */
+class BxTemplFeature extends BxBaseFeature
+{
+    function __construct($sSystem, $iId, $iInit = true, $oTemplate = false)
+    {
+        parent::__construct($sSystem, $iId, $iInit, $oTemplate);
+    }
+}
+
+/** @} */

+ 21 - 0
modules/boonex/protean/data/template/system/scripts/BxTemplFeature.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 BxDolFeature
+ */
+class BxTemplFeature extends BxBaseFeature
+{
+    function __construct($sSystem, $iId, $iInit = true, $oTemplate = false)
+    {
+        parent::__construct($sSystem, $iId, $iInit, $oTemplate);
+    }
+}
+
+/** @} */

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

@@ -39,6 +39,11 @@
 	<string name="_favorite_err_cannot_perform_action"><![CDATA[Невозможно выполнить действие.]]></string>
 	<string name="_favorite_err_duplicate_favorite"><![CDATA[Вы уже добавляли данный объект в избранное ранее.]]></string>
 	<string name="_favorite_err_not_enabled"><![CDATA[Действие не доступно в данный момент. Пожалуйста, попробуйте позднее.]]></string>
+    <string name="_feature_do_feature"><![CDATA[В продвинутые]]></string>
+    <string name="_feature_do_unfeature"><![CDATA[Из продвинутых]]></string>
+    <string name="_feature_err_cannot_perform_action"><![CDATA[Невозможно выполнить действие.]]></string>
+    <string name="_feature_err_duplicate_feature"><![CDATA[Данный объект уже добавлен в список продвинутых.]]></string>
+    <string name="_feature_err_not_enabled"><![CDATA[Действие не доступно в данный момент. Пожалуйста, попробуйте позднее.]]></string>
 	<string name="_Female"><![CDATA[Женщина]]></string>
 	<string name="_From"><![CDATA[От]]></string>
 	<string name="_Header"><![CDATA[Заголовок]]></string>
@@ -1495,6 +1500,7 @@
 	<string name="_sys_acl_action_every_period"><![CDATA[ каждые {4} часа]]></string>
 	<string name="_sys_acl_action_favorite"><![CDATA[Избранное - Добавлять]]></string>
 	<string name="_sys_acl_action_favorite_view"><![CDATA[Избранное - Просматривать]]></string>
+	<string name="_sys_acl_action_feature"><![CDATA[Продвинутое - Добавлять]]></string>
 	<string name="_sys_acl_action_view_view"><![CDATA[Просмотры - Просматривать]]></string>
 	<string name="_sys_acl_action_view_view_viewers"><![CDATA[Просмотры - Просматривать смотревших]]></string>
 	<string name="_sys_acl_action_limit_reached"><![CDATA[Вы достигли лимита. Ваше текущее членство ({2}) позволяет {1} не более {3} раз]]></string>

+ 26 - 0
template/css/feature.css

@@ -0,0 +1,26 @@
+/*--- Feature Element Styles ---*/
+div.bx-feature div.bx-feature-element-holder {
+	position: relative;
+	float: left;
+}
+
+/*--- Feature Element Styles ---*/
+.bx-feature-feature .bx-feature-element-holder {
+	line-height: 20px;
+	line-height: 1.25rem;
+}
+
+.bx-feature-button .bx-feature-element-holder {
+	line-height: 36px;
+	line-height: 2.2rem;
+}
+
+.bx-feature-button-small .bx-feature-element-holder {
+	line-height: 24px;
+	line-height: 1.6rem;
+}
+
+.bx-feature .bx-feature-element-holder .bx-feature-do-feature.bx-feature-disabled,
+.bx-feature .bx-feature-element-holder .bx-feature-do-feature.bx-feature-disabled .sys-icon {
+	color: #ddd;
+}

+ 1 - 0
template/feature_do_feature.html

@@ -0,0 +1 @@
+<a id="__html_id__" class="__style_prefix__-do-feature __class__" href="javascript:void(0)" <bx_if:show_onclick>onclick="javascript:__onclick__"</bx_if:show_onclick> title="__title__">__do_feature__</a>

+ 1 - 0
template/feature_do_feature_label.html

@@ -0,0 +1 @@
+<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>

+ 4 - 0
template/feature_element_block.html

@@ -0,0 +1,4 @@
+<div id="__html_id__" class="__style_prefix__ __class__ bx-def-margin-right-auto bx-def-margin-thd-topbottom bx-clearfix" bx_feature_data_count="__count__">
+	<div class="__style_prefix__-element-holder">__do_feature__</div>
+</div>
+__script__

+ 4 - 0
template/feature_element_inline.html

@@ -0,0 +1,4 @@
+<span id="__html_id__" class="__style_prefix__ __class__ bx-def-margin-right-auto bx-def-margin-thd-topbottom" bx_feature_data_count="__count__">
+	<span class="__style_prefix__-element-holder">__do_feature__</span>
+</span>
+__script__

+ 198 - 0
template/scripts/BxBaseFeature.php

@@ -0,0 +1,198 @@
+<?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 BxDolFeature
+ */
+class BxBaseFeature extends BxDolFeature
+{
+    protected $_bCssJsAdded;
+
+	protected $_sJsObjClass;
+    protected $_sJsObjName;
+    protected $_sStylePrefix;
+
+    protected $_aHtmlIds;
+
+    protected $_aElementDefaults;
+
+    protected $_sTmplNameCounter;
+    protected $_sTmplNameDoFeature;
+
+    public function __construct($sSystem, $iId, $iInit = 1, $oTemplate = false)
+    {
+        parent::__construct($sSystem, $iId, $iInit, $oTemplate);
+
+        $this->_bCssJsAdded = false;
+
+        $this->_sJsObjClass = 'BxDolFeature';
+        $this->_sJsObjName = 'oFeature' . bx_gen_method_name($sSystem, array('_' , '-')) . $iId;
+        $this->_sStylePrefix = 'bx-feature';
+
+        $sHtmlId = str_replace(array('_' , ' '), array('-', '-'), $sSystem) . '-' . $iId;
+        $this->_aHtmlIds = array(
+            'main' => 'bx-feature-' . $sHtmlId,
+        	'do_link' => 'bx-feature-do-link-' . $sHtmlId
+        );
+
+        $this->_aElementDefaults = array(
+			'show_do_feature_as_button' => false,
+			'show_do_feature_as_button_small' => false,
+			'show_do_feature_icon' => true,
+			'show_do_feature_label' => false
+        );
+
+        $this->_sTmplNameCounter = 'feature_counter.html';
+        $this->_sTmplNameDoFeature = 'feature_do_feature.html';
+    }
+
+    public function addCssJs($bDynamicMode = false)
+    {
+    	if($bDynamicMode || $this->_bCssJsAdded)
+    		return;
+
+    	$this->_oTemplate->addJs(array('jquery.anim.js', 'BxDolFeature.js'));
+        $this->_oTemplate->addCss(array('feature.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 " . $this->_sJsObjClass . "(" . json_encode($aParams) . ");";
+
+        if($bDynamicMode) {
+			$sCode = "var " . $this->_sJsObjName . " = null; 
+			$.getScript('" . bx_js_string($this->_oTemplate->getJsUrl('BxDolFeature.js'), BX_ESCAPE_STR_APOS) . "', function(data, textStatus, jqxhr) {
+				bx_get_style('" . bx_js_string($this->_oTemplate->getCssUrl('feature.css'), BX_ESCAPE_STR_APOS) . "');
+				" . $sCode . "
+        	}); ";
+        }
+        else
+        	$sCode = "var " . $sCode;
+
+        $this->addCssJs($bDynamicMode);
+        return $this->_oTemplate->_wrapInTagJsCode($sCode);
+    }
+
+    public function getJsClick()
+    {
+        return $this->getJsObjectName() . '.feature(this)';
+    }
+
+    public function getElementBlock($aParams = array())
+    {
+        $aParams['usage'] = BX_DOL_FEATURED_USAGE_BLOCK;
+
+        return $this->getElement($aParams);
+    }
+
+    public function getElementInline($aParams = array())
+    {
+        $aParams['usage'] = BX_DOL_FEATURED_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;
+
+        $bShowDoFeatureAsButtonSmall = isset($aParams['show_do_feature_as_button_small']) && $aParams['show_do_feature_as_button_small'] == true;
+        $bShowDoFeatureAsButton = !$bShowDoFeatureAsButtonSmall && isset($aParams['show_do_feature_as_button']) && $aParams['show_do_feature_as_button'] == true;
+
+		$iObjectId = $this->getId();
+		$iAuthorId = $this->_getAuthorId();
+        $aFeature = $this->_oQuery->getFeature($iObjectId);
+        $bCount = (int)$aFeature['count'] != 0;
+
+        $bAllowedFeature = $this->isAllowedFeature();
+        if(!$bAllowedFeature)
+            return '';
+
+        $aParams['is_featured'] = $this->isPerformed($iObjectId, $iAuthorId) ? true : false;
+
+        $sTmplName = 'feature_element_' . (!empty($aParams['usage']) ? $aParams['usage'] : BX_DOL_FEATURED_USAGE_DEFAULT) . '.html';
+        return $this->_oTemplate->parseHtmlByName($sTmplName, array(
+            'style_prefix' => $this->_sStylePrefix,
+            'html_id' => $this->_aHtmlIds['main'],
+            'class' => $this->_sStylePrefix . ($bShowDoFeatureAsButton ? '-button' : '') . ($bShowDoFeatureAsButtonSmall ? '-button-small' : ''),
+            'count' => $aFeature['count'],
+            'do_feature' => $this->_getDoFeature($aParams, $bAllowedFeature),
+            'script' => $this->getJsScript($bDynamicMode)
+        ));
+    }
+
+    protected function _getDoFeature($aParams = array(), $bAllowedFeature = true)
+    {
+    	$bFeatured = isset($aParams['is_featured']) && $aParams['is_featured'] === true;
+        $bShowDoFeatureAsButtonSmall = isset($aParams['show_do_feature_as_button_small']) && $aParams['show_do_feature_as_button_small'] == true;
+        $bShowDoFeatureAsButton = !$bShowDoFeatureAsButtonSmall && isset($aParams['show_do_feature_as_button']) && $aParams['show_do_feature_as_button'] == true;
+		$bDisabled = !$bAllowedFeature || ($bFeatured  && !$this->isUndo());
+
+        $sClass = '';
+		if($bShowDoFeatureAsButton)
+			$sClass = 'bx-btn';
+		else if ($bShowDoFeatureAsButtonSmall)
+			$sClass = 'bx-btn bx-btn-small';
+
+		if($bDisabled)
+			$sClass .= $bShowDoFeatureAsButton || $bShowDoFeatureAsButtonSmall ? ' bx-btn-disabled' : 'bx-feature-disabled';
+
+        return $this->_oTemplate->parseHtmlByName($this->_sTmplNameDoFeature, array(
+            'style_prefix' => $this->_sStylePrefix,
+        	'html_id' => $this->_aHtmlIds['do_link'],
+            'class' => $sClass,
+            'title' => bx_html_attribute(_t($this->_getTitleDoFeature($bFeatured))),
+        	'bx_if:show_onclick' => array(
+        		'condition' => !$bDisabled,
+        		'content' => array(
+        			'onclick' => $this->getJsClick()
+        		)
+        	),
+            'do_feature' => $this->_getLabelDoFeature($aParams),
+        ));
+    }
+
+    protected function _getLabelDoFeature($aParams = array())
+    {
+    	$bFeatured = isset($aParams['is_featured']) && $aParams['is_featured'] === true;
+        return $this->_oTemplate->parseHtmlByName('feature_do_feature_label.html', array(
+        	'bx_if:show_icon' => array(
+        		'condition' => isset($aParams['show_do_feature_icon']) && $aParams['show_do_feature_icon'] == true,
+        		'content' => array(
+        			'name' => $this->_getIconDoFeature($bFeatured)
+        		)
+        	),
+        	'bx_if:show_text' => array(
+        		'condition' => isset($aParams['show_do_feature_label']) && $aParams['show_do_feature_label'] == true,
+        		'content' => array(
+        			'text' => _t($this->_getTitleDoFeature($bFeatured))
+        		)
+        	)
+        ));
+    }
+}
+
+/** @} */

部分文件因文件數量過多而無法顯示