Index: flag.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/Attic/flag.inc,v
retrieving revision 1.1.4.2
diff -u -F^[^a-z]*function -r1.1.4.2 flag.inc
--- flag.inc	6 Jul 2008 09:46:11 -0000	1.1.4.2
+++ flag.inc	21 Jul 2008 18:03:19 -0000
@@ -1,5 +1,5 @@
 <?php
-// $Id: flag.inc,v 1.1.4.2 2008/07/06 09:46:11 mooffie Exp $
+// $Id: flag.inc,v 1.1.2.1 2008/07/06 08:22:08 mooffie Exp $
 /**
  * @file flag.inc
  * Implements various flags. Uses object oriented style inspired by that
@@ -273,6 +273,37 @@   function delete() {
     db_query('DELETE FROM {flag_types} WHERE fid = %d', $this->fid);
     db_query('DELETE FROM {flag_counts} WHERE fid = %d', $this->fid);
   }
+
+  /**
+   * Renders a flag/unflag link. This is a wrapper around theme('flag') that,
+   * in Drupal 6, easily channels the call to the right template file.
+   *
+   * For parameters docmentation, see theme_flag().
+   */
+  function theme($action, $content_id, $after_flagging = FALSE) {
+    // The following 'if ... else' is because I don't want to maintain two
+    // versions of this file because of 1 line of code.
+    if (function_exists('theme_get_registry')) {
+      // We're running Drupal 6.
+      return theme($this->theme_suggestions(), $this, $action, $content_id, $after_flagging);
+    }
+    else {
+      // We're running Drupal 5. Noting to do: The theme_suggestions[] are
+      // handed to phptemplate in phptemplate_flag(), if the user bothered to
+      // copy that function into her 'template.php'.
+      return theme('flag', $this, $action, $content_id, $after_flagging);
+    }
+  }
+
+  /**
+   * Provides an array of possible themes to try for a given flag.
+   */
+  function theme_suggestions() {
+    $suggestions = array();
+    $suggestions[] = 'flag_' . $this->name;
+    $suggestions[] = 'flag';
+    return $suggestions;
+  }
 }
 
 /**
Index: flag.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/flag.js,v
retrieving revision 1.1.2.9
diff -u -F^[^a-z]*function -r1.1.2.9 flag.js
--- flag.js	22 Jun 2008 09:36:42 -0000	1.1.2.9
+++ flag.js	21 Jul 2008 18:03:20 -0000
@@ -8,7 +8,7 @@
      */
     function flipLink(element, settings) {
       // If this is a 'flag this' link...
-      if ($(element).is('.flag')) {
+      if ($(element).is('.flag-action')) {
         // ...then turn it into an 'unflag this' link;
         var newHtml = settings.unflag;
       }
@@ -115,10 +115,8 @@     function getLinkSettings(element) {
     }
 
     // On load, bind the click behavior for all links on the page.
-    for (flagName in Drupal.settings.flag.flags) {
-      $('a.flag-' + flagName).click(function() {
-        return flagClick(this, getLinkSettings(this));
-      });
-    }
+    $('a.flag').click(function() {
+      return flagClick(this, getLinkSettings(this));
+    });
   });
 }
Index: flag.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/flag.module,v
retrieving revision 1.1.2.26
diff -u -F^[^a-z]*function -r1.1.2.26 flag.module
--- flag.module	17 Jul 2008 07:07:02 -0000	1.1.2.26
+++ flag.module	21 Jul 2008 18:03:22 -0000
@@ -230,10 +230,11 @@ function flag_link($type, $object = NULL
     // Token replacements.
     $flag = flag_process_labels($flag, $type, $id, array('flag_short', 'flag_long', 'flag_message'), array('teaser' => $teaser));
 
+    $is_flagged = isset($flag_status[$flag->name]);
     // The flag links are actually fully rendered theme functions.
     // The HTML attribute is set to TRUE to allow whatever the themer desires.
     $links['flag-'. $flag->name] = array(
-      'title' => theme('flag', $flag, $type, $id, isset($flag_status[$flag->name])),
+      'title' => $flag->theme($is_flagged ? 'unflag' : 'flag', $id),
       'html' => TRUE,
      );
   }
@@ -815,18 +816,95 @@ function flag_nodes($nodes) {
 }
 
 /**
- * Theme an entire flag link, including JavaScript behaviors.
+ * Theme an individual link and a message after the link is marked.
  *
  * @param $flag
  *   The flag object.
- * @param $content_type
- *   The type of content being flagged. Usually "node".
+ * @param $action
+ *   Which link to show: either "flag" or "unflag".
  * @param $content_id
  *   The ID of the content being flagged.
- * @param $is_flagged
- *   Boolean value of the current status of the flag being output.
+ * @param $after_flagging
+ *   This function is called for both the link both before and after being
+ *   flagged. If displaying to the user immediately after flagging, this value
+ *   will be boolean TRUE. This is usually used in conjunction with immedate
+ *   JavaScript-based toggling of flags.
+ */
+function theme_flag($flag, $action, $content_id, $after_flagging = FALSE) {
+  static $template;
+  if (!isset($template)) {
+    $template = './' . drupal_get_path('module', 'flag') . '/theme/flag.tpl.php';
+  }
+  $variables = array(
+    'flag' => $flag,
+    'action' => $action,
+    'content_id' => $content_id,
+    'after_flagging' => $after_flagging,
+  );
+  template_preprocess_flag($variables);
+  extract($variables);
+  ob_start();
+  include $template;
+  $output = ob_get_contents();
+  ob_end_clean();
+
+  // Unfortunately, the antique jQuery shipped with Drupal 5 has a bug: the
+  // expression $('<tag>something</tag>') fails is 'something' contains a
+  // newline. That's because jQuery's source has:
+  //
+  //  // Handle HTML strings
+  //  if ( typeof a  == "string" ) {
+  //    var m = /^[^<]*(<.+>)[^>]*$/.exec(a);
+  //    if ( m ) a = jQuery.clean( [ m[1] ] );
+  //  }
+  //
+  // Note the "<.+>", which doesn't match newlines. In newer jQuery's that
+  // expression was changed to:
+  //
+  //  var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/
+  //
+  // Note the \s which does match newlines.
+  //
+  // So we have to remove all newlines:
+  $output = strtr($output, "\r\n", '  ');
+  return $output;
+}
+
+/**
+ * A preprocess function for our theme('flag'). It generates the
+ * variables needed there.
+ *
+ * See 'flag.tpl.php' for documentation for these variables.
+ *
+ * Note: The Drupal 5 version of this module calls this function directly.
  */
-function theme_flag($flag, $content_type, $content_id, $is_flagged) {
+function template_preprocess_flag(&$variables) {
+  // Some typing shotcuts:
+  $flag =& $variables['flag'];
+  $action = $variables['action'];
+
+  // Add the JS portion to the page. But be careful: _flag_add_js() calls
+  // this function back, to generate links to store in some JS array, so we guard
+  // against recursion.
+  if (!$variables['after_flagging']) {
+    _flag_add_js($flag, $action, $variables['content_id']);
+  }
+
+  $variables['link_href'] = check_url(url("flag/$action/$flag->name/$flag->content_type/$variables[content_id]", drupal_get_destination()));
+  $variables['link_text'] = $flag->{$action .'_short'};
+  $variables['link_title'] = strip_tags($flag->{$action .'_long'});
+  $variables['flag_name_css'] = str_replace('_', '-', $flag->name);
+  $variables['last_action'] = ($action == 'flag' ? 'unflagged' : 'flagged');
+  if ($variables['after_flagging']) {
+    $inverse_action = ($action == 'flag' ? 'unflag' : 'flag');
+    $variables['message_text'] = $flag->{$inverse_action .'_message'};
+  }
+}
+
+/**
+ * Helper function for adding the JavaScript behaviour.
+ */
+function _flag_add_js(&$flag, $action, $content_id) {
   static $added_flags, $js_added;
 
   // Add initial JS/CSS to the page.
@@ -838,41 +916,12 @@ function theme_flag($flag, $content_type
   }
 
   // Add JavaScript copies of the links so we can swap them out when the user clicks.
-  if (!(isset($added_flags[$flag->name][$content_type][$content_id]))) {
-    $flag_html = theme('flag_link', $flag, $content_type, $content_id, 'flag', TRUE);
-    $unflag_html = theme('flag_link', $flag, $content_type, $content_id, 'unflag', TRUE);
-    drupal_add_js(array('flag' => array('flags' => array($flag->name => array($content_type .'_'. $content_id => array('flag' => $flag_html, 'unflag' => $unflag_html))))), 'setting');
-    $added_flags[$flag->name][$content_type][$content_id] = TRUE;
+  if (!(isset($added_flags[$flag->name][$flag->content_type][$content_id]))) {
+    $flag_html = $flag->theme('flag', $content_id, TRUE);
+    $unflag_html = $flag->theme('unflag', $content_id, TRUE);
+    drupal_add_js(array('flag' => array('flags' => array($flag->name => array($flag->content_type .'_'. $content_id => array('flag' => $flag_html, 'unflag' => $unflag_html))))), 'setting');
+    $added_flags[$flag->name][$flag->content_type][$content_id] = TRUE;
   }
-
-  return theme('flag_link', $flag, $content_type, $content_id, $is_flagged ? 'unflag' : 'flag');
-}
-
-/**
- * Theme an individual link and a message after the link is marked.
- *
- * @param $flag
- *   The flag object.
- * @param $content_type
- *   The type of content being flagged. Usually "node".
- * @param $content_id
- *   The ID of the content being flagged.
- * @param $action
- *   Either "flag" or "unflag".
- * @param $after_flagging
- *   This function is called for both the link both before and after being
- *   flagged. If displaying to the user immediately after flagging, this value
- *   will be boolean TRUE. This is usually used in conjunction with immedate
- *   JavaScript-based toggling of flags.
- */
-function theme_flag_link($flag, $content_type, $content_id, $action, $after_flagging = FALSE) {
-  $output = '<span class="flag-wrapper">';
-  $output .= l($flag->{$action .'_short'}, 'flag/'. $action .'/'. $flag->name .'/'. $content_type .'/'. $content_id, array('title' => $flag->{$action .'_long'}, 'class' => $action .' flag-'. $flag->name . ($after_flagging ? ($action == 'flag' ? ' unflagged' : ' flagged') : '')), drupal_get_destination());
-  if ($after_flagging) {
-    $output .= '<span class="flag-message flag-'. $action .'-message">'. $flag->{($action == 'flag' ? 'unflag' : 'flag') .'_message'} .'</span>';
-  }
-  $output .= '</span>';
-  return $output;
 }
 
 /**
@@ -1146,6 +1195,7 @@ function flag_create_link($flag_name, $c
 
   $flag = flag_process_labels($flag, $flag->content_type, $content_id, array('flag_short', 'flag_long', 'flag_message'));
   $flag_status = flag_get_user_flags($flag->content_type, $content_id);
-  return theme('flag', $flag, $flag->content_type, $content_id, isset($flag_status[$flag->name]));
+  $is_flagged = isset($flag_status[$flag->name]);
+  return $flag->theme($is_flagged ? 'unflag' : 'flag', $content_id);
 }
 
Index: flag.views.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/flag.views.inc,v
retrieving revision 1.1.2.5
diff -u -F^[^a-z]*function -r1.1.2.5 flag.views.inc
--- flag.views.inc	15 Jun 2008 08:40:39 -0000	1.1.2.5
+++ flag.views.inc	21 Jul 2008 18:03:22 -0000
@@ -213,7 +213,7 @@ function flag_field_handler_ops($fieldin
 
   // Token replacements.
   $flag = flag_process_labels($flag, 'node', $data->nid, array('flag_short', 'flag_long', 'flag_message'));
-  return theme('flag', $flag, 'node', $data->nid, $is_flagged);
+  return $flag->theme($is_flagged ? 'unflag' : 'flag', $data->nid);
 }
 
 /**
