--- fivestar-admin.css	Mon Mar 10 02:44:42 2008
+++ fivestar-admin.css	Mon Mar 24 23:05:52 2008
@@ -25,3 +25,10 @@
   border: 1px solid #CCC;
   padding: 10px;
 }
+#fivestar-direct-preview div.description {
+  margin-bottom: 0;
+}
+#fivestar-direct-preview div.feedback{
+  font-size: 0.85em;
+  line-height: 150%;
+}
--- fivestar-admin.js	Mon Mar 10 02:53:10 2008
+++ fivestar-admin.js	Mon Mar 24 13:45:08 2008
@@ -21,6 +21,7 @@
     $enable = $('#edit-fivestar');
     $unvote = $('#edit-fivestar-unvote');
     $title  = $('#edit-fivestar-title');
+    $feedback = $('#edit-fivestar-feedback');
     $style  = $('#edit-fivestar-style');
     $text   = $('#edit-fivestar-text');
 
@@ -33,14 +34,14 @@
       nodePreview.disable();
     }
     else {
-      nodePreview.enable($unvote.attr('checked') ? 1 : 0, $style.val(), $text.val(), $title.attr('checked') ? 1 : 0);
+      nodePreview.enable($unvote.attr('checked') ? 1 : 0, $style.val(), $text.val(), $title.attr('checked') ? 1 : 0, $feedback.attr('checked') ? 1 : 0);
     }
 
     // Add event handler for enable checkbox.
     $enable.change(function() {
       if ($(this).attr('checked')) {
         // Enable the node preview.
-        nodePreview.enable($unvote.attr('checked') ? 1 : 0, $style.val(), $text.val(), $title.attr('checked') ? 1 : 0);
+        nodePreview.enable($unvote.attr('checked') ? 1 : 0, $style.val(), $text.val(), $title.attr('checked') ? 1 : 0, $feedback.attr('checked') ? 1 : 0);
         nodePreview.update()
 
         // Enable the comment preview if available.
@@ -72,6 +73,7 @@
     $text.change(function() { nodePreview.setValue('text', this.value); });
     $title.change(function() { nodePreview.setValue('title', $(this).attr('checked') ? 1 : 0); });
     $unvote.change(function() { nodePreview.setValue('unvote', $(this).attr('checked') ? 1 : 0); });
+    $feedback.change(function() { nodePreview.setValue('feedback', $(this).attr('checked') ? 1 : 0); });
 
     if (commentPreview) {
       // Enable the comment preview.
@@ -115,6 +117,7 @@
   this.enabled = false;
   this.unvote = 0;
   this.title = 1;
+  this.feedback = 1;
   this.stars = this.elements.stars.val();
   this.style = '';
   this.text = '';
@@ -141,7 +144,7 @@
 /**
  * Enable the preview functionality and show the preview.
  */
-fivestarPreview.prototype.enable = function(unvote, style, text, title) {
+fivestarPreview.prototype.enable = function(unvote, style, text, title, feedback) {
   if (!this.enabled) {
     this.enabled = true;
 
@@ -157,6 +160,7 @@
     // Update settings specific to this preview.
     this.unvote = unvote;
     this.title = title;
+    this.feedback = feedback;
     this.style = style;
     this.text = text;
 
@@ -205,7 +209,7 @@
     };
 
     // Prepare data to send to the server.
-    var data = { style: this.style, text: this.text, stars: this.stars, unvote: this.unvote, title: this.title, labels_enable: this.labelsEnable }
+    var data = { style: this.style, text: this.text, stars: this.stars, unvote: this.unvote, title: this.title, feedback: this.feedback, labels_enable: this.labelsEnable }
 
     // Covert labels array format understood by PHP and add to data.
     for (n in this.labels) {
--- fivestar.css	Mon Mar 10 02:44:42 2008
+++ fivestar.css	Mon Mar 24 22:57:53 2008
@@ -86,3 +86,10 @@
 div.fivestar-widget div.hover a, div.rating div a:hover {
   background-position: 0 -32px;
 }
+form.fivestar-widget div.description {
+  margin-bottom: 0;
+}
+form.fivestar-widget div.feedback{
+  font-size: 0.92em;
+  line-height: 150%;
+}
--- fivestar.module	Mon Mar 10 07:24:08 2008
+++ fivestar.module	Tue Mar 25 00:22:57 2008
@@ -206,6 +206,13 @@
       '#return_value' => 1,
     );
 
+    $form['fivestar']['direct']['fivestar_feedback'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enable confirmations to inform a vote was saved or deleted.'),
+      '#default_value' => variable_get('fivestar_feedback_'. $form['#node_type']->type, 1),
+      '#return_value' => 1
+    );
+
     $form['fivestar']['direct']['fivestar_unvote'] = array(
       '#type' => 'checkbox',
       '#title' => t('Allow users to undo their votes'),
@@ -315,6 +322,7 @@
   $direct .= drupal_render($form['direct']['fivestar_text']);
   $direct .= drupal_render($form['direct']['fivestar_title']);
   $direct .= drupal_render($form['direct']['fivestar_unvote']);
+  $direct .= drupal_render($form['direct']['fivestar_feedback']);
   $direct .= drupal_render($form['direct']['fivestar_position_teaser']);
   $direct .= drupal_render($form['direct']['fivestar_position']);
   $direct .= '</div>';
@@ -467,18 +475,19 @@
   $stars = (int)$_POST['stars'];
   $unvote = (boolean)$_POST['unvote'];
   $title = (boolean)$_POST['title'];
+  $feedback = (boolean)$_POST['feedback'];
   $labels_enable = (boolean)$_POST['labels_enable'];
   $labels = (array)$_POST['labels'];
   foreach ($labels as $key => $label) {
     $labels[$key] = filter_xss_admin($label);
   }
 
-  $output = theme('fivestar_preview', $style, $text, $stars, $unvote, $title ? NULL : FALSE, $labels_enable, $labels);
+  $output = theme('fivestar_preview', $style, $text, $stars, $unvote, $title ? NULL : FALSE, $feedback, $labels_enable, $labels);
   drupal_set_header('Content-Type: text/javascript; charset=utf-8');
   print drupal_to_js(array('status' => TRUE, 'data' => $output));
 }
 
-function theme_fivestar_preview($style = NULL, $text = NULL, $stars = NULL, $unvote = NULL, $title = NULL, $labels_enable = TRUE, $labels = array()) {
+function theme_fivestar_preview($style = NULL, $text = NULL, $stars = NULL, $unvote = NULL, $title = NULL, $feedback = TRUE, $labels_enable = TRUE, $labels = array()) {
   $values = array(
     'average' => 50,
     'user' => 80,
@@ -490,6 +499,7 @@
     'style' => $style,
     'text' => $text,
     'title' => $title,
+    'feedback' => $feedback,
     'autosubmit' => FALSE,
     'labels_enable' => $labels_enable,
     'labels' => $labels,
@@ -923,6 +933,7 @@
   $form['vote'] = array(
     '#type' => 'fivestar',
     '#stars' => $settings['stars'],
+    '#feedback' => $settings['feedback'],
     '#vote_count' => $values['count'],
     '#vote_average' => $values['average'],
     '#auto_submit' => isset($settings['autosubmit']) ? $settings['autosubmit'] : TRUE,
@@ -1094,6 +1105,11 @@
   if ($form['#parameters'][2]['text'] != 'none' || !empty($form['#parameters'][2]['labels'])) {
     $output .= '<div class="description fivestar-summary-'. $form['content_id']['#value'] .'">'. $description .'</div>';
   }
+  $feedbackPreview = $form['vote']['#feedback'];
+  if ( (!isset($feedbackPreview) && variable_get('fivestar_feedback_'. $form['#node_type']->type, 1)) ||
+       (isset($feedbackPreview) && $feedbackPreview) ) {
+    $output .= '<div class="feedback fivestar-feedback-'. $form['content_id']['#value'] .'">&nbsp;</div>';
+  }
   $output .= '</div>';
   return $output;
 }
@@ -1210,8 +1226,13 @@
 
   // Add necessary javascript only once per page.
   if (!$js_added) {
+    $feedbackEnabled = variable_get('fivestar_feedback_'. $form['#node_type']->type, 1);
+    $settings = array('titleUser' => t('Your rating') .': ', 'titleAverage' => t('Average') .': ', 'feedbackEnabled' => $feedbackEnabled);
+    if ($feedbackEnabled) {
+      $settings = array_merge($settings, array('feedbackSavingVote' => t('Thank you for your vote!'), 'feedbackVoteSaved' => t('Your vote has been saved.'), 'feedbackDeletingVote' => t('Deleting your vote...'), 'feedbackVoteDeleted' => t('Your vote has been deleted.')));
+    }
     drupal_add_js(drupal_get_path('module', 'fivestar') .'/jquery.rating.js');
-    drupal_add_js(array('fivestar' => array('titleUser' => t('Your rating') .': ', 'titleAverage' => t('Average') .': ')), 'setting');
+    drupal_add_js(array('fivestar' => $settings), 'setting');
     $js_added = TRUE;
   }
 }
--- jquery.rating.js	Mon Jan 14 03:53:14 2008
+++ jquery.rating.js	Mon Mar 24 23:32:43 2008
@@ -30,6 +30,8 @@
             $stars = $('.star', $widget),
             $cancel = $('.cancel', $widget),
             $summary = $('.description', $obj).size() ? $('.description', $obj) : $($obj).siblings('.description'),
+            $feedback = $('.feedback', $obj).size() ? $('.feedback', $obj) : $($obj).siblings('.feedback'),
+            feedbackTimerId = 0,
             summaryText = $summary.html(),
             summaryHover = $obj.is('.fivestar-labels-hover'),
             currentValue = $("select", $obj).val(),
@@ -114,6 +116,10 @@
             currentValue = 0;
             event.reset();
             voteChanged = false;
+            // Inform a user that his vote is being processed
+            if (Drupal.settings.fivestar.feedbackEnabled) {
+              setFeedbackText(Drupal.settings.fivestar.feedbackDeletingVote);
+            }
             // Save the currentValue in a hidden field.
             $("select", $obj).val(0);
             // Update the title.
@@ -130,6 +136,10 @@
             // Update the display of the stars.
             voteChanged = true;
             event.reset();
+            // Inform a user that his vote is being processed
+            if (Drupal.settings.fivestar.feedbackEnabled) {
+              setFeedbackText(Drupal.settings.fivestar.feedbackSavingVote);
+            }
             // Submit the form if needed.
             $("input.fivestar-path", $obj).each(function () { $.ajax({ type: 'GET', dataType: 'xml', url: this.value + '/' + currentValue, success: voteHook }); });
             return false;
@@ -185,6 +195,15 @@
             }
         };
 
+        var setFeedbackText = function(text) {
+          // Kill previous timer if it isn't finished yet so that the text we are about to set will not get cleared too early
+          if (feedbackTimerId != 0) {                
+            clearTimeout(feedbackTimerId);
+            feedbackTimerId = 0;
+          }
+          $feedback.html(text);
+        };
+
         /**
          * Checks for the presence of a javascript hook 'fivestarResult' to be
          * called upon completion of a AJAX vote request.
@@ -216,6 +235,17 @@
           }
           // Update the summary text.
           summaryText = returnObj.result.summary[returnObj.display.text];
+          if (Drupal.settings.fivestar.feedbackEnabled) {
+            // Inform user that his/her vote has been processed
+            if (returnObj.vote.value != 0) { // check if vote has been saved or deleted 
+              setFeedbackText(Drupal.settings.fivestar.feedbackVoteSaved);
+            }
+            else {
+              setFeedbackText(Drupal.settings.fivestar.feedbackVoteDeleted);
+            }
+            // Setup a timer to clear the feedback text after 3 seconds
+            feedbackTimerId = setTimeout(function() { feedbackTimerId = 0; $feedback.html('&nbsp;'); }, 3000);
+          }
           // Update the current star currentValue to the previous average.
           if (returnObj.vote.value == 0 && starDisplay == 'average') {
             currentValue = returnObj.result.average;
