動態為 Node 增加投票功能(hook_node_view)

1 篇文章 / 0 new
author
動態為 Node 增加投票功能(hook_node_view)
► 主要利用 hook_node_view() 在呈現時加入投票機制
// 實作 hook_node_view, 動態增加 node 顯示資料
function plusone_node_view($node, $view_mode) {
    global $user;
    $total = plusone_get_total($node->nid);
    $is_author = db_query('SELECT uid from {node} where nid = :nid AND uid = :uid', array(":nid" => $node->nid, ":uid" => $user->uid))->fetchField();
    if ($is_author) {
        $is_author = TRUE;
    } else {
        $is_author = FALSE;
    }
    $voted = plusone_get_vote($node->nid, $user->uid);
    if ($view_mode == 'full') {//增加顯示資料
        $variables = array('nid' => (int) $node->nid, 'total' => (int) $total, 'is_author' => $is_author, 'voted' => $voted);
        $node->content['plusone_vote'] = array(//加入自訂元素
            '#markup' => theme('plusone_widget', $variables),//組成資料
            '#weight' => 100,
        );
    }
}
► 投票樣式處理 theme
// Implementation of hook_theme(). 註冊 theme function.
function plusone_theme() {
    return array(
        'plusone_widget' => array(
        //'template' => 'plusone_widget', //使用模板方式呈現樣式 tpl.php
        ),
    );
}
//投票 顯示樣式(Theme) 非 template 形式
function theme_plusone_widget($variables) {
    drupal_add_js(drupal_get_path('module', 'plusone') . '/plusone.js');
    drupal_add_css(drupal_get_path('module', 'plusone') . '/plusone.css');
    $output = '<div class="plusone-widget">';
    $output .= '<div class="score">' . $variables['total'] . '</div>';
    if (user_access('rate content') && !$variables['is_author']) {//許可投票者才顯示連結
        $output .= '<div class="vote">';
        if ($variables['voted']) {
            $output .= t('已投票');
        } else { //加入投票連結.
            $output .= l(t('投一票'), "plusone/vote/" . $variables['nid'], array(
                'attributes' => array('class' => 'plusone-link')
            ));
        }
        $output .= '</div>'; // Close div with class "vote".
    }
    $output .= '</div>'; // Close div with class "plusone-widget".
    return $output;
}
► 資料處理
// 增加投票紀錄
function plusone_vote($nid) {
    global $user;
    $nid = (int) $nid;
    // 檢查該node是否為作者本人
    $is_author = db_query('SELECT uid from {node} where nid = :nid AND uid = :uid', array(":nid" => (int) $nid, ":uid" => (int) $user->uid))->fetchField();
 
    if ($nid > 0 && !$is_author) {
        $vote_count = plusone_get_vote($nid, $user->uid);
        if (!$vote_count) {//該使用怎若無投票紀錄則增加票數儲存
            db_delete('plusone_votes')
                    ->condition('uid', $user->uid)
                    ->condition('nid', $nid)->execute();
            db_insert('plusone_votes')
                    ->fields(array(
                        'uid' => $user->uid,
                        'nid' => $nid,
                        'vote_count' => $vote_count + 1,
                    ))->execute();
        }
    }
    $total_votes = plusone_get_total($nid);
    // 確認是否為 AJAX 呼叫, 若是則POST請求中會含 js=1(自行定義) 資訊
    if (!empty($_POST['js'])) {//採用 JavaScript 呼叫時以 JSON 回應更新頁面資訊
        drupal_json_output(array(
            'total_votes' => $total_votes,
            'voted' => t('You Voted')
                )
        );
        exit();
    }
    // 若不是使用 JavaScript 呼叫則採用轉向方式更新頁面
    $path = drupal_get_path_alias('node/' . $nid);
    drupal_goto($path);
}
 
//取得當前使用者該node投票紀錄
function plusone_get_vote($nid, $uid) {
    $vote_count = db_query('SELECT vote_count FROM {plusone_votes} WHERE
        nid = :nid AND uid = :uid', array(':nid' => $nid, ':uid' => $uid))->fetchField();
    return $vote_count;
}
// 傳回node總票數
function plusone_get_total($nid) {
    $total_count = (int) db_query('SELECT SUM(vote_count) from {plusone_votes} where nid = :nid', array(':nid' => $nid))->fetchField();
    return ($total_count);
}
► javascript 使用AJAX傳送投票請求 plusone.js
// jQuery 雖可用 $ 代替簡化, 但若同時載入多個 js 時,其內部也定義 $ 時, 則當下 $ 是否代表為 jQuery 就不一定
// 多重載入 js 時, $ 表示為呼叫前最後一個載入的 js, 因此還是不用使用 $ 為佳
jQuery(document).ready(function() {
    // 為 連結類別 "plusone-link" 增加 按鍵事件 for the .
    jQuery('a.plusone-link').click(function() {
        // When clicked, first define an anonymous function to the variable voteSaved.
        var voteSaved = function(data) {// Update data.
            jQuery('div.score').html(data.total_votes);
            jQuery('div.vote').html(data.voted);
        }
        // 使用 AJAX 方式投票
        jQuery.ajax({
            type: 'POST', // 使用 POST 請求.
            url: this.href,
            dataType: 'json',
            success: voteSaved,
            data: 'js=1' // 傳送 js=1 告訴處理者以 JSON 方式回應資料
        });
        // Prevent the browser from handling the click.
        return false;
    });
});
► CSS plusone.css
div.plusone-widget {
  width: 100px;
  margin-bottom: 5px;
  text-align: center;
}
div.plusone-widget .score {
  padding: 10px;
  border: 1px solid #999;
  background-color: #eee;
  font-size: 175%;
}
div.plusone-widget .vote {
  padding: 1px 5px;
  margin-top: 2px;
  border: 1px solid #666;
  background-color: #ddd;
}
選單,權限登錄
//hook_permission().
function plusone_permission() {
    $perms = array(
        'rate content' => array( 'title' => t('rate content'), ),
    );
    return $perms;
}
// hook_menu() 投票action
function plusone_menu() {
    $items['plusone/vote/%'] = array(
        'title' => 'Vote',
        'page callback' => 'plusone_vote',
        'page arguments' => array(2),
        'access arguments' => array('rate content'),
        'type' => MENU_CALLBACK,
    );
    return $items;
}
► 使用模板方式呈現 plusone_widget.tpl.php
drupal_add_js(drupal_get_path('module', 'plusone') . '/plusone.js');
drupal_add_css(drupal_get_path('module', 'plusone') . '/plusone.css');
$output = '<div class="plusone-widget">';
//$variables[] 內 key值 均可以變數型態直接取值$key
//$variables['total'] 與 $total 是相同的
$output .= '<div class="score">' . $total . '</div>';
if (user_access('rate content') && !$is_author) {//有投票權才顯示連結
    $output .= '<div class="vote">';
    if ($voted > 0) {
        $output .= t('已投票');
    } else {
        $output .= l(t('投一票'), "plusone/vote/$nid", array(
            'attributes' => array('class' => 'plusone-link')
        ));
    }
    $output .= '</div>'; // Close div with class "vote".
}
$output .= '</div>'; // Close div with class "plusone-widget".
print $output;
Free Web Hosting