diff --git a/README.txt b/README.txt index 850f2be..e1cdf8e 100644 --- a/README.txt +++ b/README.txt @@ -55,9 +55,3 @@ From plus1.module theme_plus1_widget function header: AUTHOR/MAINTAINER ================== -Caroline Schnapp at http://11heavens.com (chill35 on http://drupal.org) - - -Drupal 7 Conversion -================== -Eaton http://drupal.org/user/16496 (patch provided in http://drupal.org/node/506936#comment-2527110) -ReneB http://drupal.org/user/590180 (Rewrote a few things for vote_api 2, moved theme_ to seperate template file) diff --git a/images/down.png b/images/down.png new file mode 100644 index 0000000..e3727ac Binary files /dev/null and b/images/down.png differ diff --git a/images/up.png b/images/up.png index 37683bd..ed21cb8 100644 Binary files a/images/up.png and b/images/up.png differ diff --git a/jquery.plus1.js b/jquery.plus1.js index 96d1b9f..a0b51a5 100644 --- a/jquery.plus1.js +++ b/jquery.plus1.js @@ -1,18 +1,19 @@ -/** - * @author Caroline Schnapp - */ (function ($) { // Documentation on Drupal JavaScript behaviors can be found here: http://drupal.org/node/114774#javascript-behaviors Drupal.behaviors.plus1 = { attach: function(context){ - jQuery('.'+ Drupal.settings.plus1.widget_class +':not(.plus1-processed)', context).addClass('plus1-processed').each(function(){ - var plus1_widget = jQuery(this); - plus1_widget.find('.'+ Drupal.settings.plus1.link_class).attr('href', function(){ return jQuery(this).attr('href') + '&json=true'; }).click(function(){ - jQuery.getJSON(jQuery(this).attr('href'), function(json){ - plus1_widget.find('.'+ Drupal.settings.plus1.score_class).hide().fadeIn('slow').html(json.score); - plus1_widget.find('.'+ Drupal.settings.plus1.message_class).html(json.voted); + $('.plus1-widget', context).once('plus1', function(){ + var plus1_widget = $(this); + plus1_widget.find('.plus1-link').attr('href', function(){ return $(this).attr('href') + '&json=true'; }).click(function(){ + $.getJSON($(this).attr('href'), function(json){ + if (json) { + var newWidget = $(json.widget); + newWidget.hide(); + plus1_widget.replaceWith(newWidget); + newWidget.fadeIn('slow'); + Drupal.attachBehaviors(); + } }); - // Preventing the /plus1/vote/ target from being triggered. return false; }); }); diff --git a/plus1-widget.tpl.php b/plus1-widget.tpl.php deleted file mode 100644 index cf0be36..0000000 --- a/plus1-widget.tpl.php +++ /dev/null @@ -1,21 +0,0 @@ -
- -
- - - - -
- -
- - -
- -
-
\ No newline at end of file diff --git a/plus1.admin.inc b/plus1.admin.inc new file mode 100644 index 0000000..ce7688a --- /dev/null +++ b/plus1.admin.inc @@ -0,0 +1,222 @@ + 'fieldset', + '#title' => t('Plus1 global settings'), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + ); + + $form['plus1_global_settings']['plus1_add_js'] = array( + '#type' => 'checkbox', + '#title' => t('Include standard Plus1 js file.'), + '#default_value' => variable_get('plus1_add_js', 1), + ); + + $form['plus1_global_settings']['plus1_add_css'] = array( + '#type' => 'checkbox', + '#title' => t('Include standard Plus1 css file.'), + '#default_value' => variable_get('plus1_add_css', 1), + ); + + $form['plus1_node_widget_settings'] = array( + '#type' => 'fieldset', + '#title' => t('Node widget settings'), + '#description' => t('You may select none, one or both options.'), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + ); + + $form['plus1_node_widget_settings']['plus1_content_types'] = array( + '#type' => 'fieldset', + '#title' => t('Content types'), + '#collapsible' => FALSE, + ); + + $form['plus1_node_widget_settings']['plus1_content_types']['plus1_node_types'] = array( + '#type' => 'checkboxes', + '#options' => node_type_get_names(), + '#default_value' => variable_get('plus1_node_types', array('story')), + ); + + $form['plus1_node_widget_settings']['plus1_node_in_teaser'] = array( + '#type' => 'checkbox', + '#title' => t('Add a Plus 1 voting widget to the node in teaser view.'), + '#default_value' => variable_get('plus1_node_in_teaser', 0), + ); + + $form['plus1_node_widget_settings']['plus1_node_in_full_view'] = array( + '#type' => 'checkbox', + '#title' => t('Add a Plus 1 voting widget to the node in full view.'), + '#default_value' => variable_get('plus1_node_in_full_view', 1), + ); + + $form['plus1_node_widget_settings']['plus1_node_vote_text'] = array( + '#type' => 'textfield', + '#title' => t("Vote text"), + '#default_value' => variable_get('plus1_node_vote_text', t('Vote')), + '#description' => t('Enter, for example, Vote or Digg.'), + ); + + $form['plus1_node_widget_settings']['plus1_node_voted_text'] = array( + '#type' => 'textfield', + '#title' => t("Feedback provided to voter when he already voted"), + '#default_value' => variable_get('plus1_node_voted_text', t('You voted')), + '#description' => t('Enter, for example, Dugg, You voted, or Voted.'), + ); + + $form['plus1_node_widget_settings']['plus1_node_undo_vote'] = array( + '#type' => 'checkbox', + '#title' => t("Allow users to undo their node votes"), + '#default_value' => variable_get('plus1_node_undo_vote', 0), + ); + + $form['plus1_node_widget_settings']['plus1_node_undo_vote_text'] = array( + '#type' => 'textfield', + '#title' => t("Feedback provided to voter when he already voted and user CAN undo his vote"), + '#default_value' => variable_get('plus1_node_undo_vote_text', ''), + '#description' => t('Enter, for example, Undugg, Undo vote, or leave it blank to provide user with "arrow down" icon.'), + '#states' => array( + 'visible' => array( + 'input[name="plus1_node_undo_vote"]' => array('checked' => TRUE), + ), + ), + ); + + $form['plus1_node_widget_settings']['plus1_node_widget_weight'] = array( + '#type' => 'textfield', + '#title' => t('Weight of node voting widget'), + '#default_value' => variable_get('plus1_node_widget_weight', '100'), + '#description' => t('The higher the weight the lower in the node the widget will be added. Can be a negative number.'), + ); + + $form['plus1_comment_widget_settings'] = array( + '#type' => 'fieldset', + '#title' => t('Comment widget settings'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + + $form['plus1_comment_widget_settings']['plus1_comment_widget_show'] = array( + '#type' => 'checkbox', + '#title' => t("Add Plus 1 voting widget to comments"), + '#default_value' => variable_get('plus1_comment_widget_show', 0), + ); + + $form['plus1_comment_widget_settings']['plus1_comment_vote_text'] = array( + '#type' => 'textfield', + '#title' => t("Vote text"), + '#default_value' => variable_get('plus1_comment_vote_text', t('Vote')), + '#description' => t('Enter, for example, Vote or Digg.'), + ); + + $form['plus1_comment_widget_settings']['plus1_comment_voted_text'] = array( + '#type' => 'textfield', + '#title' => t('Feedback provided to voter when he already voted'), + '#default_value' => variable_get('plus1_comment_voted_text'), + '#description' => t('Enter, for example, Dugg, You voted, or Voted.'), + ); + + $form['plus1_comment_widget_settings']['plus1_comment_undo_vote'] = array( + '#type' => 'checkbox', + '#title' => t("Allow users to undo their comment votes"), + '#default_value' => variable_get('plus1_comment_undo_vote', 0), + ); + + $form['plus1_comment_widget_settings']['plus1_comment_undo_vote_text'] = array( + '#type' => 'textfield', + '#title' => t("Feedback provided to voter when he already voted and user CAN undo his vote"), + '#default_value' => variable_get('plus1_comment_undo_vote_text', ''), + '#description' => t('Enter, for example, Undugg, Undo vote, or leave it blank to provide user with "arrow down" icon.'), + '#states' => array( + 'visible' => array( + 'input[name="plus1_comment_undo_vote"]' => array('checked' => TRUE), + ), + ), + ); + + $form['plus1_comment_widget_settings']['plus1_comment_widget_weight'] = array( + '#type' => 'textfield', + '#title' => t('Weight of comment voting widget'), + '#default_value' => variable_get('plus1_comment_widget_weight', '100'), + '#description' => t('The higher the weight the lower in the comment the widget will be added. Can be a negative number.'), + ); + + $form['plus1_taxonomy_term_widget_settings'] = array( + '#type' => 'fieldset', + '#title' => t('Taxonomy term widget settings'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + + $form['plus1_taxonomy_term_widget_settings']['plus1_taxonomy_term_widget_show'] = array( + '#type' => 'checkbox', + '#title' => t('Add Plus 1 voting widget to taxonomy terms'), + '#default_value' => variable_get('plus1_taxonomy_term_widget_show', 0), + ); + + $vocabularies = array(); + foreach (taxonomy_get_vocabularies() as $voc) { + $vocabularies[$voc->vid] = $voc->name; + } + + $form['plus1_taxonomy_term_widget_settings']['plus1_taxonomy_vocabularies'] = array( + '#type' => 'checkboxes', + '#title' => t('Add voting widget to following vocabularies'), + '#options' => $vocabularies, + '#default_value' => variable_get('plus1_taxonomy_vocabularies', array()) + ); + + $form['plus1_taxonomy_term_widget_settings']['plus1_taxonomy_term_vote_text'] = array( + '#type' => 'textfield', + '#title' => t("Vote text"), + '#default_value' => variable_get('plus1_taxonomy_term_vote_text', t('Vote')), + '#description' => t('Enter, for example, Vote or Digg.'), + ); + + $form['plus1_taxonomy_term_widget_settings']['plus1_taxonomy_term_voted_text'] = array( + '#type' => 'textfield', + '#title' => t("Feedback provided to voter when he already voted"), + '#default_value' => variable_get('plus1_taxonomy_term_voted_text', t('You voted')), + '#description' => t('Enter, for example, Dugg, You voted, or Voted.'), + ); + + $form['plus1_taxonomy_term_widget_settings']['plus1_taxonomy_term_undo_vote'] = array( + '#type' => 'checkbox', + '#title' => t("Allow users to undo their taxonomy term votes"), + '#default_value' => variable_get('plus1_taxonomy_term_undo_vote', 0), + ); + + $form['plus1_taxonomy_term_widget_settings']['plus1_taxonomy_term_undo_vote_text'] = array( + '#type' => 'textfield', + '#title' => t("Feedback provided to voter when he already voted and user CAN undo his vote"), + '#default_value' => variable_get('plus1_taxonomy_term_undo_vote_text', ''), + '#description' => t('Enter, for example, Undugg, Undo vote, or leave it blank to provide user with "arrow down" icon.'), + '#states' => array( + 'visible' => array( + 'input[name="plus1_taxonomy_term_undo_vote"]' => array('checked' => TRUE), + ), + ), + ); + + $form['plus1_taxonomy_term_widget_settings']['plus1_taxonomy_term_widget_weight'] = array( + '#type' => 'textfield', + '#title' => t('Weight of taxonomy term voting widget'), + '#default_value' => variable_get('plus1_taxonomy_term_widget_weight', '100'), + '#description' => t('The higher the weight the lower in the comment the widget will be added. Can be a negative number.'), + ); + + + $form['array_filter'] = array('#type' => 'hidden'); + + return system_settings_form($form); +} diff --git a/plus1.css b/plus1.css index 0002a26..0563671 100644 --- a/plus1.css +++ b/plus1.css @@ -1,5 +1,5 @@ div.plus1-widget { - padding: 0.2em 0.2em 0.6em; + padding: 0.2em; border-top: 1px #fbf389 solid; border-bottom: 1px #fbf389 solid; background-color: #fbfbe6; @@ -12,16 +12,70 @@ div.plus1-widget a { text-decoration: none; } div.plus1-widget .plus1-score { - padding-top: 0.4em; + padding: 0.4em 0; font-size: 150%; } div.plus1-widget .plus1-vote { background: url(images/up.png) no-repeat center bottom; text-indent: -999em; } -div.plus1-widget .plus1-vote a { +div.plus1-widget .plus1-undo-vote { + background: url(images/down.png) no-repeat center top; + text-indent: -999em; +} +div.plus1-widget .plus1-vote a, +div.plus1-widget .plus1-undo-vote a { display: block; width: 100%; height: 100%; outline: none; } + +.plus1-comment-widget { + margin-bottom: 10px; +} + +.plus1-comment-abuse { + background: url(images/abuse.png) no-repeat 0 0; + padding-left: 18px; + padding-top: 1px; +} + +.plus1-comment-abuse-checked { + background: url(images/abuse.png) no-repeat 0 -16px; + padding-left: 18px; + padding-top: 1px; +} + +a.plus1-comment-abuse:hover { + background: url(images/abuse.png) no-repeat 0 -16px; +} + +a.plus1-comment-abuse-checked:hover { + background: url(images/abuse.png) no-repeat 0 0; +} + +.plus1-comment-vote { + background: url(images/thumbs_up.png) no-repeat 0 0; + padding: 2px 0 0 18px; + +} + +.plus1-comment-vote-checked { + background: url(images/thumbs_up.png) no-repeat 0 -20px; + padding: 2px 0 0 18px; + +} + +a.plus1-comment-vote:hover { + background: url(images/thumbs_up.png) no-repeat 0 -20px; +} + +a.plus1-comment-vote-checked:hover { + background: url(images/thumbs_up.png) no-repeat 0 0px; +} + +.plus1-comment-score { + color: black; + padding-right: 2px; +} diff --git a/plus1.info b/plus1.info index e631ca2..5a59583 100644 --- a/plus1.info +++ b/plus1.info @@ -1,12 +1,6 @@ name = Plus 1 -project = "plus1" - -description = "A +1 voting widget for nodes." -package = Voting - -core = 7.x -files[] = plus1.module -files[] = plus1.install +description = "A +1 voting widget for nodes and comments." +package = Other dependencies[] = votingapi - -datestamp = "1237353342" +dependencies[] = ctools +core = 7.x diff --git a/plus1.install b/plus1.install index d171d4f..7506aee 100644 --- a/plus1.install +++ b/plus1.install @@ -1,32 +1,35 @@ array( - 'title' => 'Vote on content', - 'description' => 'Cast votes on site content using the Plus1 voting widget.', + 'plus1 vote on node' => array( + 'title' => t('Vote on nodes'), + 'description' => t('Cast votes on site content using the Plus1 voting widget.'), + ), + 'plus1 vote on comment' => array( + 'title' => t('Vote on comments'), + 'description' => t('Cast votes on site comments using the Plus1 voting widget.'), ), - 'administer the voting widget' => array( - 'title' => 'Administer the voting widget', - 'description' => 'Make configuration changes to the Plus1 voting widget.', + 'plus1 vote on taxonomy_term' => array( + 'title' => t('Vote on taxonomy terms'), + 'description' => t('Cast votes on taxonomy terms using the Plus1 voting widget.'), + ), + 'administer the plus1 voting widget' => array( + 'title' => t('Administer the voting widget'), + 'description' => t('Make configuration changes to the Plus1 voting widget.'), ), ); } /** -* Implements of hook_menu(). -*/ + * Implements hook_menu(). + */ function plus1_menu() { - $items['plus1/vote/%'] = array( + $items['plus1/vote/%/%'] = array( 'title' => 'Vote', 'page callback' => 'plus1_vote', - 'page arguments' => array(2), - 'access arguments' => array('vote on content'), + 'page arguments' => array(2, 3, 4), + 'access callback' => 'plus1_user_access', + 'access arguments' => array('plus1 vote on node', 'plus1 vote on comment', 'plus1 vote on taxonomy_term'), + 'type' => MENU_CALLBACK, + ); + + $items['plus1/undo-vote/%/%'] = array( + 'title' => 'Undo vote', + 'page callback' => 'plus1_undo_vote', + 'page arguments' => array(2, 3, 4), + 'access callback' => 'plus1_user_access', + 'access arguments' => array('plus1 vote on node', 'plus1 vote on comment', 'plus1 vote on taxonomy_term'), 'type' => MENU_CALLBACK, ); - $items['admin/structure/plus1'] = array( + $items['admin/config/user-interface/plus1'] = array( 'title' => 'Plus 1', 'description' => 'Allows readers to vote on content.', 'page callback' => 'drupal_get_form', 'page arguments' => array('plus1_settings'), + 'access callback' => 'plus1_user_access', 'access arguments' => array('administer the voting widget'), + 'file' => 'plus1.admin.inc', ); return $items; } /** -* Implements of hook_init(). -*/ -function plus1_init() { - variable_set('plus1_javascript_settings', 0); + * Custom access function, works with array of permissions. + */ +function plus1_user_access() { + global $user; + $permissions = func_get_args(); + if ($user->uid == 1) { + return TRUE; + } + foreach ($permissions as $perm) { + if (user_access($perm)) + return TRUE; + } } /** -* Menu callback to configure module settings. -*/ -function plus1_settings() { - - $form['plus1_nodetypes_fieldset'] = array( - '#type' => 'fieldset', - '#title' => t('Content type settings'), - '#description' => t('Select all node types to which a +1 voting widget can be added.'), - ); - - $form['plus1_nodetypes_fieldset']['plus1_nodetypes'] = array( - '#type' => 'checkboxes', - '#options' => node_type_get_names(), - '#default_value' => variable_get('plus1_nodetypes', array('story')), - ); - - $form['plus1_display'] = array( - '#type' => 'fieldset', - '#title' => t('Display settings'), - '#description' => t('You may select none, one or both options.'), - ); - - $form['plus1_display']['plus1_in_teaser'] = array( - '#type' => 'checkbox', - '#title' => t('Add a +1 voting widget to the node in teaser view.'), - '#default_value' => variable_get('plus1_in_teaser', 0), - ); - - $form['plus1_display']['plus1_in_full_view'] = array( - '#type' => 'checkbox', - '#title' => t('Add a +1 voting widget to the node in full view.'), - '#default_value' => variable_get('plus1_in_full_view', 1), - ); - - $form['plus1_display']['plus1_in_full_view'] = array( - '#type' => 'checkbox', - '#title' => t('Add a +1 voting widget to the node in full view.'), - '#default_value' => variable_get('plus1_in_full_view', 1), - ); - - $form['plus1_text'] = array( - '#type' => 'fieldset', - '#title' => t('Text settings'), - ); - - $form['plus1_text']['plus1_you_voted'] = array( - '#type' => 'textfield', - '#title' => t('Feedback provided to voter when he already voted'), - '#default_value' => variable_get('plus1_you_voted', t('You voted')), - '#description' => t('Enter, for example, Dugg, You voted, or Voted.'), - ); - - $form['plus1_weight'] = array( - '#type' => 'fieldset', - '#title' => t('Weight settings'), - ); - - $form['plus1_weight']['plus1_weight'] = array( - '#type' => 'textfield', - '#title' => t('Weight of voting widget'), - '#default_value' => variable_get('plus1_weight', '100'), - '#description' => t('The higher the weight the lower in the node the widget will be added. Can be a negative number.'), + * Implements hook_theme(). + */ +function plus1_theme() { + return array( + 'plus1_widget' => array( + 'variables' => array( + 'entity_type' => NULL, + 'entity_id' => NULL, + 'tag' => NULL, + 'score' => 0, + 'logged_in' => FALSE, + 'is_author' => FALSE, + 'voted' => FALSE, + 'vote_link' => NULL, + 'undo_vote_link' => NULL, + 'link_query' => array(), + 'can_vote' => NULL, + 'can_undo_vote' => NULL, + 'undo_vote_text' => NULL, + 'voted_text' => NULL, + 'vote_text' => NULL, + ), + 'template' => 'plus1-widget', + 'path' => drupal_get_path('module', 'plus1') . '/theme', + ), + 'plus1_json_response' => array( + 'variables' => array('entity_type' => NULL, 'entity_id' => NULL, 'tag' => NULL, 'score' => NULL, 'vote_type' => NULL), + ), ); - - $form['array_filter'] = array('#type' => 'hidden'); - - return system_settings_form($form); } /** -* Page callback. -* @param $nid -* A node ID. -* @param $ajax -* Equal to 'json' when the function is called by jQuery. -* Submits the vote request and refreshes the page without JavaScript. -* Otherwise, it submits the vote request and returns JSON to be parsed by jQuery. -*/ -function plus1_vote($nid) { + * Page callback. + * @param $entity_type + * Type of the entity, node or comment + * @param $entity_id + * A node, comment or taxonomy term ID. + * @param $tag + * Tag name to vote for. + * @param $value + * Value of vote, can be only 1 or -1. if another value will be provided, it will be handled as error. + * A tag for different voting on same entity type + * Submits the vote request and refreshes the page without JavaScript. + * Otherwise, it submits the vote request and returns JSON to be parsed by jQuery. + */ +function plus1_vote($entity_type, $entity_id, $tag = 'plus1_node_vote') { global $user; - $json = isset($_GET['json']) ? 'json' : NULL; - if (!drupal_valid_token($_GET['token'], $nid)) { - watchdog('Plus1', 'Voting form error: Invalid token.'); + if (!drupal_valid_token($_GET['token'], $entity_id)) { + watchdog('plus1', 'Voting form error: Invalid token.'); return drupal_access_denied(); } - - $voted = plus1_get_votes($nid, $user->uid); + $voted = plus1_get_votes($entity_type, $entity_id, $user->uid, $tag); // If the voter has not already voted. if (!$voted) { - $node_type = db_select('node','n')->fields('n', array('type'))->condition('nid', $nid)->execute()->fetchObject(); $votes[] = array( - 'entity_id' => $nid, - 'entity_type' => $node_type->type, + 'entity_type' => $entity_type, + 'entity_id' => $entity_id, 'value_type' => 'points', 'value' => 1, + 'tag' => $tag ? $tag : 'plus1_' . $entity_type . '_vote', ); votingapi_set_votes($votes); $criteria = array( - 'entity_id' => $nid, + 'entity_type' => $entity_type, + 'entity_id' => $entity_id, 'function' => 'sum', + 'tag' => $tag ? $tag : 'plus1_' . $entity_type . '_vote', ); $results = votingapi_select_results($criteria); - if ($json == 'json') { - // This print statement will return results to jQuery's request. - drupal_json_output(array('score' => $results[0]['value'], 'voted' => check_plain(variable_get('plus1_you_voted', t('You voted'))))); + $score = $results[0]['value'] ? $results[0]['value'] : 0; + module_invoke_all('plus1_voted', 'vote', $entity_type, $entity_id, $tag, $score, $user); + if (isset($_GET['json'])) { + // Return json to client side, taking into consideration entity type. + drupal_json_output(theme('plus1_json_response__' . $entity_type . '__' . $tag, array('entity_type' => $entity_type, 'entity_id' => $entity_id, 'tag' => $tag, 'score' => $score, 'vote_type' => 'vote'))); } else { - // Go to the full node view. drupal_set_message(t('Thank you for your vote.')); - drupal_goto('node/' . $nid); + // go to the page where user pressed vote button + drupal_goto(); + } + } +} + + +function plus1_undo_vote($entity_type, $entity_id, $tag = 'plus1_node_vote') { + global $user; + if (!drupal_valid_token($_GET['token'], $entity_id)) { + watchdog('plus1', 'Voting form error: Invalid token.'); + return drupal_access_denied(); + } + $voted = plus1_get_votes($entity_type, $entity_id, $user->uid, $tag); + $can_undo_vote = variable_get('plus1_' . $entity_type . '_undo_vote', 0); + // If the voter has already voted and he can undo his vote. + if ($voted && $can_undo_vote) { + $criteria['entity_type'] = $entity_type; + $criteria['entity_id'] = $entity_id; + $criteria['value_type'] = 'points'; + if ($user->uid == 0) { + $criteria['vote_source'] = ip_address(); + } + else { + $criteria['uid'] = $user->uid; + } + if (isset($tag) && $tag != "") { + $criteria['tag'] = $tag; + } + $votes = votingapi_select_votes($criteria); + votingapi_delete_votes($votes); + votingapi_recalculate_results($entity_type, $entity_id, TRUE); + + $criteria = array( + 'entity_type' => $entity_type, + 'entity_id' => $entity_id, + 'function' => 'sum', + 'tag' => $tag ? $tag : 'plus1_' . $entity_type . '_vote', + ); + $results = votingapi_select_results($criteria); + $score = $results[0]['value'] ? $results[0]['value'] : 0; + module_invoke_all('plus1_voted', 'undo_vote', $entity_type, $entity_id, $tag, $score, $user); + if (isset($_GET['json'])) { + drupal_json_output(theme('plus1_json_response__' . $entity_type . '__' . $tag, array('entity_type' => $entity_type, 'entity_id' => $entity_id, 'tag' => $tag, 'score' => $score, 'vote_type' => 'undo_vote'))); + } + else { + drupal_set_message(t('Thank you for your vote.')); + // go to the page where user pressed vote button + drupal_goto(); } } } /** -* Return the number of votes for a given node ID/user ID pair. -* -* @param $nid -* A node ID. -* @param $uid -* A user ID. -* @return Integer -* Number of votes the user has cast on this node. -*/ -function plus1_get_votes($nid, $uid) { - $criteria['entity_id'] = $nid; + * Return the number of votes for a given content. + * + * @param $entity_type + * An entity type, node or comment. + * @param $entity_id + * An ID of node or comment. + * @param $uid + * A user ID. + * @param $tag + * A tag for different voting on the content of same type + * @return Integer + * Number of votes the user has cast on this node. + */ +function plus1_get_votes($entity_type, $entity_id, $uid, $tag = 'plus1_node_vote') { + $criteria['entity_type'] = $entity_type; + $criteria['entity_id'] = $entity_id; $criteria['value_type'] = 'points'; if ($uid == 0) { $criteria['vote_source'] = ip_address(); @@ -185,22 +236,33 @@ function plus1_get_votes($nid, $uid) { else { $criteria['uid'] = $uid; } + if (isset($tag) && $tag != "") { + $criteria['tag'] = $tag; + } $results = votingapi_select_votes($criteria); return count($results); } /** -* Return the total score of a node. -* -* @param $nid -* A node ID. -* @return Integer -* The score. -*/ -function plus1_get_score($nid) { - $criteria['entity_id'] = $nid; + * Return the total score for a given content. + * + * @param $entity_type + * Node or comment + * @param $entity_id + * A node or comment ID. + * @param $tag + * A tag to identify different votes on the same content type + * @return Integer + * The score. + */ +function plus1_get_score($entity_type, $entity_id, $tag = 'plus1_node_vote') { + $criteria['entity_type'] = $entity_type; + $criteria['entity_id'] = $entity_id; $criteria['value_type'] = 'points'; $criteria['function'] = 'sum'; + if (isset($tag) && $tag != "") { + $criteria['tag'] = $tag; + } $results = votingapi_select_results($criteria); if (empty($results)) { return 0; @@ -211,103 +273,200 @@ function plus1_get_score($nid) { } /** -* Create voting widget to display on the webpage. -*/ -function plus1_jquery_widget($node, $teaser) { - $score = plus1_get_score($node->nid); + * Create voting widget to display on the webpage. + */ +function plus1_node_jquery_widget($entity_id, $tag = 'plus1_node_vote') { global $user; - // If user is not logged-in. - if ($user->uid == 0) { - $logged_in = FALSE; - $is_author = FALSE; - } - else { - $logged_in = TRUE; - $is_author = ($node->uid == $user->uid)? TRUE : FALSE; + $node = node_load($entity_id); + $score = plus1_get_score('node', $node->nid, $tag); + $logged_in = $user->uid > 0; + $is_author = $node->uid == $user->uid; + $voted = plus1_get_votes('node', $node->nid, $user->uid, $tag); + $variables = array( + 'entity_type' => 'node', + 'entity_id' => $node->nid, + 'tag' => $tag, + 'score' => $score, + 'logged_in' => $logged_in, + 'is_author' => $is_author, + 'voted' => $voted, + 'vote_link' => 'plus1/vote/node/' . $node->nid . '/' . $tag, + 'undo_vote_link' => 'plus1/undo-vote/node/' . $node->nid . '/' . $tag, + 'link_query' => array('token' => drupal_get_token($node->nid), drupal_get_destination()), + 'can_vote' => user_access('plus1 vote on node'), + 'can_undo_vote' => variable_get('plus1_node_undo_vote', 0), + 'undo_vote_text' => check_plain(variable_get('plus1_node_undo_vote_text', '')), + 'voted_text' => check_plain(variable_get('plus1_node_voted_text', t('You voted'))), + 'vote_text' => check_plain(variable_get('plus1_node_vote_text', t('Vote'))), + ); + return theme('plus1_widget__node__' . $tag, $variables); +} + +/** + * Create voting widget to display on the webpage. + */ +function plus1_comment_jquery_widget($entity_id, $tag = 'plus1_comment_vote') { + global $user; + $comment = comment_load($entity_id); + $score = plus1_get_score('comment', $comment->cid, $tag); + $logged_in = $user->uid > 0; + $is_author = $comment->uid == $user->uid; + $voted = plus1_get_votes('comment', $comment->cid, $user->uid, $tag); + $variables = array( + 'entity_type' => 'comment', + 'entity_id' => $comment->cid, + 'tag' => $tag, + 'score' => $score, + 'logged_in' => $logged_in, + 'is_author' => $is_author, + 'voted' => $voted, + 'vote_link' => 'plus1/vote/comment/' . $comment->cid . '/' . $tag, + 'undo_vote_link' => 'plus1/undo-vote/comment/' . $comment->cid . '/' . $tag, + 'link_query' => array('token' => drupal_get_token($comment->cid), drupal_get_destination()), + 'can_vote' => user_access('plus1 vote on comment'), + 'can_undo_vote' => variable_get('plus1_comment_undo_vote', 0), + 'undo_vote_text' => check_plain(variable_get('plus1_comment_undo_vote_text', "")), + 'voted_text' => check_plain(variable_get('plus1_comment_voted_text', t('You voted'))), + 'vote_text' => check_plain(variable_get('plus1_comment_vote_text', t('Vote'))), + ); + return theme('plus1_widget__comment__' . $tag, $variables); +} + +/** + * Create voting widget to display on the webpage. + */ +function plus1_taxonomy_term_jquery_widget($entity_id, $tag = 'plus1_taxonomy_term_vote') { + global $user; + $term = taxonomy_term_load($entity_id); + $score = plus1_get_score('taxonomy_term', $term->tid, $tag); + $logged_in = $user->uid > 0; + $voted = plus1_get_votes('taxonomy_term', $term->tid, $user->uid, $tag); + $variables = array( + 'entity_type' => 'taxonomy_term', + 'entity_id' => $term->tid, + 'tag' => $tag, + 'score' => $score, + 'logged_in' => $logged_in, + 'is_author' => FALSE, + 'voted' => $voted, + 'vote_link' => 'plus1/vote/taxonomy_term/' . $term->tid . '/' . $tag, + 'undo_vote_link' => 'plus1/undo-vote/taxonomy_term/' . $term->tid . '/' . $tag, + 'link_query' => array('token' => drupal_get_token($term->tid), drupal_get_destination()), + 'can_vote' => user_access('plus1 vote on taxonomy_term'), + 'can_undo_vote' => variable_get('plus1_taxonomy_term_undo_vote', 0), + 'undo_vote_text' => check_plain(variable_get('plus1_taxonomy_term_undo_vote_text', '')), + 'voted_text' => check_plain(variable_get('plus1_taxonomy_term_voted_text', t('You voted'))), + 'vote_text' => check_plain(variable_get('plus1_taxonomy_term_vote_text', t('Vote'))), + ); + return theme('plus1_widget__taxonomy_term__' . $tag, $variables); +} + +/** + * Implements hook_node_view(). + */ +function plus1_node_view($node, $view_mode) { + // Only show the voting widget in allowed content types. + if (in_array($node->type, variable_get('plus1_node_types', array()))) { + if (($view_mode == 'teaser' && variable_get('plus1_node_in_teaser', 0)) || ($view_mode == 'full' && variable_get('plus1_node_in_full_view', 1))) { + $node->content['plus1_widget'] = array( + '#markup' => plus1_node_jquery_widget($node->nid), + '#weight' => (int) variable_get('plus1_node_widget_weight', '100'), + ); + } } - $voted = plus1_get_votes($node->nid, $user->uid); - return theme('plus1_widget', array('node' => $node, 'score' => $score, 'logged_in' => $logged_in, 'is_author' => $is_author, 'voted' => $voted, 'teaser' => $teaser)); - } /** -* Implements of hook_nodeapi(). -*/ -function plus1_node_view($node, $buildmode, $langcode) { - if (in_array($node->type, variable_get('plus1_nodetypes', array('story')))) { - $teaser = variable_get('plus1_in_teaser', 0); - $full = variable_get('plus1_in_full_view', 1); - if (($buildmode == 'full' && $full) || ($buildmode='teaser' && $teaser)) { - $node->content['plus1_widget'] = array( - '#markup' => plus1_jquery_widget($node, ($buildmode == 'teaser'), FALSE), - '#weight' => (int) variable_get('plus1_weight', '100'), - ); - } - + * Implements hook_node_delete(). + */ +function plus1_node_delete($node) { + $criteria['entity_id'] = $node->nid; + $criteria['entity_type'] = 'node'; + $votes = votingapi_select_votes($criteria); + votingapi_delete_votes($votes); +} + + +/** + * Implements hook_taxonomy_term_view_alter(). + */ +function plus1_taxonomy_term_view_alter(&$build) { + if (variable_get('plus1_taxonomy_term_widget_show', 0) && in_array($build['#term']->vid, variable_get('plus1_taxonomy_vocabularies', array()))) { + $build['plus1_taxonomy_widget'] = array( + '#markup' => plus1_taxonomy_term_jquery_widget($build['#term']->tid), + '#weight' => (int) variable_get('plus1_taxonomy_widget_weight', '100'), + ); } } -function plus1_node_delete($node){ - var_dump($node); - exit(); +/** + * Implements hook_taxonomy_term_delete(). + */ +function plus1_taxonomy_term_delete($term) { + $criteria['entity_id'] = $term->nid; + $criteria['entity_type'] = 'taxonomy_term'; + $votes = votingapi_select_votes($criteria); + votingapi_delete_votes($votes); } /** -* Implements of hook_theme(). -*/ -function plus1_theme() { - $theme['plus1_widget'] = array( - 'arguments' => array('node', 'score', 'logged_in', 'is_author', 'voted', 'teaser', 'page'), - 'template' => 'plus1-widget', + * Implements hook_comment_view(). + */ +function plus1_comment_view($comment, $view_mode, $langcode) { + if (variable_get('plus1_comment_widget_show', 0) && !isset($comment->in_preview)) { + $comment->content['plus1_widget'] = array( + '#markup' => plus1_comment_jquery_widget($comment->cid), + '#weight' => (int) variable_get('plus1_comment_widget_weight', '100'), ); - return $theme; + } } /** -* Theme for the voting widget. -* -* You are free to load your own CSS and JavaScript files in your -* theming function override, instead of the ones provided by default. -* -* This function adds information to the Drupal.settings.plus1 JS object, -* concerning class names used for the voting widget. -* If you override this theming function but choose to use the -* default JavaScript file, simply assign different values to -* the following variables: -* $widget_class (The wrapper element for the voting widget.) -* $link_class (The anchor element to cast a vote.) -* $message_class (The wrapper element for the anchor element. May contain feedback when the vote has been cast.) -* $score_class (The placeholder element for the score.) -* The JavaScript looks for these CSS hooks to -* update the voting widget after a vote is cast. -* Of course you may choose to write your own JavaScript. -* The JavaScript adds presentation, ie: fade in. -* -*/ -function template_preprocess_plus1_widget(&$variables) { - extract($variables); - // Load the JavaScript and CSS files. - // You are free to load your own JavaScript files in your theming function to override. - drupal_add_js(drupal_get_path('module', 'plus1') . '/jquery.plus1.js'); - drupal_add_css(drupal_get_path('module', 'plus1') . '/plus1.css'); + * Implements gook_comment_delete(). + */ +function plus1_comment_delete($comment) { + $criteria['entity_id'] = $comment->cid; + $criteria['entity_type'] = 'comment'; + $votes = votingapi_select_votes($criteria); + votingapi_delete_votes($votes); +} - - - $variables['plus1']['widget_class'] = 'plus1-widget'; - $variables['plus1']['link_class'] = 'plus1-link'; - $variables['plus1']['message_class'] = 'plus1-msg'; - $variables['plus1']['score_class'] = 'plus1-score'; - $variables['plus1']['loginvote'] = l(t('Log in
to vote'), 'user', array('html' => TRUE)); - $variables['plus1']['youvoted'] = check_plain(variable_get('plus1_you_voted', t('You voted'))); - $variables['plus1']['linkvote'] = l(t('Vote'), 'plus1/vote/' . $node->nid, array('query' => - array('token' => drupal_get_token($node->nid)), 'attributes' => array('class' => $variables['plus1']['link_class']))); +/** + * Implements hook_votingapi_metadata_alter() + */ +function plus1_votingapi_metadata_alter(&$data) { + // Document several custom tags for rating restaurants and meals. + $data['tags']['plus1_node_vote'] = array( + 'name' => t('Plus1 node vote'), + 'description' => t('Plus1 votes for nodes.'), + 'module' => 'plus1', - // Attaching these hooks names to the Drupal.settings.plus1 JavaScript object. - // So these class names are NOT hard-coded in the JavaScript. - if (variable_get('plus1_javascript_settings', 0) == 0) { - drupal_add_js(array('plus1' => array('widget_class' => $variables['plus1']['widget_class'], 'link_class' => $variables['plus1']['link_class'] , - 'message_class' => $variables['plus1']['message_class'], - 'score_class' => $variables['plus1']['score_class'])), 'setting'); - variable_set('plus1_javascript_settings', 1); - } + ); + $data['tags']['plus1_comment_vote'] = array( + 'name' => t('Plus1 comment vote'), + 'description' => t('Plus1 votes for comments.'), + 'module' => 'plus1', + + ); + $data['tags']['plus1_taxonomy_term_vote'] = array( + 'name' => t('Plus1 term vote'), + 'description' => t('Plus1 votes for taxonomy terms.'), + 'module' => 'plus1', + + ); +} + +/** + * This hook is called when user votes on some content. + * @param $vote_type + * Vote type, "vote" or "undo_vote" + * @param $entity_type + * Entity type, node, comment etc. + * @param $entity_id + * @param $tag + * @param $score + * @param $user + * @return void + */ +function hook_plus1_voted($vote_type, $entity_type, $entity_id, $tag, $score, $user) { } diff --git a/theme/plus1-widget.tpl.php b/theme/plus1-widget.tpl.php new file mode 100644 index 0000000..84bafaa --- /dev/null +++ b/theme/plus1-widget.tpl.php @@ -0,0 +1,30 @@ + +
+ +
+ +
+ +
+ + + +
+ + +
+ +
+ + +
+
+ +
+
+
diff --git a/theme/theme.inc b/theme/theme.inc new file mode 100644 index 0000000..018d65b --- /dev/null +++ b/theme/theme.inc @@ -0,0 +1,82 @@ +to vote'), 'user', array('html' => TRUE)); + } + elseif ($variables['voted']) { // User already voted. + // is the user can undo his vote then provide him with link + if ($can_undo_vote) { + if ($undo_vote_text != "") { + $variables['widget_message'] = l($undo_vote_text, $undo_vote_link, array('query' => $link_query, 'attributes' => array('class' => array('plus1-link')))); + } + else { + // if we don't have text for undo action, add "arrow-down" link after score. + $variables['use_arrow_down'] = TRUE; + $variables['widget_message'] = l(t('Undo vote'), $undo_vote_link, array('query' => $link_query, 'attributes' => array('class' => array('plus1-link')))); + } + } + else { + $variables['widget_message'] = $voted_text; + } + } + elseif ($can_vote) { + // User is eligible to vote. + $variables['widget_message'] = l($vote_text, $vote_link, array('query' => $link_query, 'attributes' => array('class' => array('plus1-link')))); + } + + // Load the JavaScript and CSS files. + // You can disable loading of these files and create your own instead of them. + if (variable_get('plus1_add_js', 1)) { + drupal_add_js(drupal_get_path('module', 'plus1') . '/jquery.plus1.js'); + } + if (variable_get('plus1_add_css', 1)) { + drupal_add_css(drupal_get_path('module', 'plus1') . '/plus1.css'); + } +} + +/** + * Theming function for json response. + * @param $variables + * @return array + * Returns an array of variables which will be send back to browser, after ajax request. + * @see plus1_vote() and plus1_undo_vote() + */ +function theme_plus1_json_response($variables) { + switch ($variables['entity_type']) { + case 'node': + return array('widget' => plus1_node_jquery_widget($variables['entity_id'], $variables['tag'])); + break; + case 'taxonomy_term': + return array('widget' => plus1_taxonomy_term_jquery_widget($variables['entity_id'], $variables['tag'])); + break; + case 'comment': + return array('widget' => plus1_comment_jquery_widget($variables['entity_id'], $variables['tag'])); + break; + } +}