Index: theme/flag.tpl.php =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/flag/theme/Attic/flag.tpl.php,v retrieving revision 1.1.2.3 diff -u -r1.1.2.3 flag.tpl.php --- theme/flag.tpl.php 10 Oct 2008 06:52:31 -0000 1.1.2.3 +++ theme/flag.tpl.php 14 Nov 2008 00:02:24 -0000 @@ -12,6 +12,7 @@ * following variables don't suffice. * - $flag_name_css: The flag name, with all "_" replaced with "-". For use in 'class' * attributes. + * - $flag_classes: A space-separated list of CSS classes that should be applied to the link. * * - $action: The action the link is about to carry out, either "flag" or "unflag". * - $last_action: The action, as a passive English verb, either "flagged" or @@ -40,7 +41,7 @@ } ?> -   +   Index: theme/flag.js =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/flag/theme/Attic/flag.js,v retrieving revision 1.1.2.4 diff -u -r1.1.2.4 flag.js --- theme/flag.js 10 Oct 2008 06:52:31 -0000 1.1.2.4 +++ theme/flag.js 14 Nov 2008 00:02:24 -0000 @@ -91,7 +91,7 @@ return false; } - $('a.flag:not(.flag-processed)').addClass('flag-processed').click(flagClick); + $('a.flag-link-toggle:not(.flag-processed)').addClass('flag-processed').click(flagClick); }; Index: flag.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/flag/Attic/flag.module,v retrieving revision 1.11.2.49 diff -u -r1.11.2.49 flag.module --- flag.module 9 Nov 2008 08:40:00 -0000 1.11.2.49 +++ flag.module 14 Nov 2008 00:02:24 -0000 @@ -60,6 +60,14 @@ 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); + $items['flag/confirm'] = array( + 'title' => 'Flag confirm', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('flag_confirm'), + 'access callback' => 'user_access', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); return $items; } @@ -168,6 +176,42 @@ } /** + * Implementation of hook_flag_link(). + * + * When Flag uses a link type provided by this module, it will call this + * implementation of hook_flag_link(). It returns a single link's attributes, + * using the same structure as hook_link(). Note that "title" is provided by + * the Flag configuration if not specified here. + * + * @param $flag + * The full flag object of for the flag link being generated. + * @param $action + * The action this link will perform. Either 'flag' or 'unflag'. + * @param $content_id + * The ID of the node, comment, user, or other object being flagged. + * @return + * An array defining properties of the link. + */ +function flag_flag_link(&$flag, $action, $content_id) { + $token = flag_get_token($content_id); + return array( + 'href' => "flag/". ($flag->link_type == 'confirm' ? 'confirm/' : '') ."$action/$flag->name/$content_id", + 'query' => drupal_get_destination() .'&token='. $token, + ); +} + +/** + * Implementation of hook_flag_link_types(). + */ +function flag_flag_link_types() { + return array( + 'toggle' => t('JavaScript toggle'), + 'normal' => t('Normal link'), + 'confirm' => t('Confirmation form'), + ); +} + +/** * Implementation of hook_form_alter(). */ function flag_form_alter(&$form, &$form_state, $form_id) { @@ -488,11 +532,18 @@ '#description' => t('The description of the "flag this" link. Usually displayed on mouseover.'), ); + $form['flag_confirmation'] = array( + '#type' => 'textfield', + '#title' => t('Flag confirmation message'), + '#default_value' => $flag->flag_confirmation, + '#description' => t('Message displayed if the user has clicked the "flag this" link and confirmation is required. Usually presented in the form of a question such as, "Are you sure you want to flag this content?"'), + ); + $form['flag_message'] = array( '#type' => 'textfield', '#title' => t('Flagged message'), '#default_value' => $flag->flag_message, - '#description' => t('Message displayed when the user has clicked the "flag this" link. If javascript is enabled, it will be displayed below the link. If not, it will be displayed in the message area.'), + '#description' => t('Message displayed after flagging content. If JavaScript is enabled, it will be displayed below the link. If not, it will be displayed in the message area.'), ); $form['unflag_short'] = array( @@ -510,11 +561,18 @@ '#description' => t('The description of the "unflag this" link. Usually displayed on mouseover.'), ); + $form['unflag_confirmation'] = array( + '#type' => 'textfield', + '#title' => t('Unflag confirmation message'), + '#default_value' => $flag->unflag_confirmation, + '#description' => t('Message displayed if the user has clicked the "unflag this" link and confirmation is required. Usually presented in the form of a question such as, "Are you sure you want to unflag this content?"'), + ); + $form['unflag_message'] = array( '#type' => 'textfield', '#title' => t('Unflagged message'), '#default_value' => $flag->unflag_message, - '#description' => t('Message displayed when the user has clicked the "unflag this" link. If javascript is enabled, it will be displayed below the link. If not, it will be displayed in the message area.'), + '#description' => t('Message displayed after content has been unflagged. If JavaScript is enabled, it will be displayed below the link. If not, it will be displayed in the message area.'), ); if (module_exists('token')) { @@ -564,6 +622,14 @@ '#tree' => FALSE, ); + $form['display']['link_type'] = array( + '#type' => 'radios', + '#title' => t('Link type'), + '#options' => _flag_link_type_options(), + '#default_value' => $this->link_type, + '#weight' => 2, + ); + $form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'), @@ -581,8 +647,20 @@ * Add/Edit flag form validate. */ function flag_form_validate($form, &$form_state) { + $form_values = $form_state['values']; + + if ($form_values['link_type'] == 'confirm') { + if (empty($form_values['flag_confirmation'])) { + form_set_error('flag_confirmation', t('A flag confirmation message is required when using the confirmation link type.')); + } + if (empty($form_values['unflag_confirmation'])) { + form_set_error('unflag_confirmation', t('An unflag confirmation message is required when using the confirmation link type.')); + } + } + + $flag = $form['#flag']; - $flag->form_input($form_state['values']); + $flag->form_input($form_values); $flag->validate(); } @@ -649,8 +727,9 @@ * * Used both for the regular callback as well as the JS version. */ -function flag_page($action, $flag_name, $content_id, $token) { +function flag_page($action, $flag_name, $content_id) { $js = isset($_REQUEST['js']); + $token = $_REQUEST['token']; // Check the flag token, then perform the flagging. if (!flag_check_token($token, $content_id)) { @@ -684,6 +763,7 @@ if ($js) { drupal_set_header('Content-Type: text/javascript; charset=utf-8'); $flag = flag_get_flag($flag_name); + $flag->link_type = 'toggle'; print drupal_to_js(array( 'status' => TRUE, 'newLink' => $flag->theme($flag->is_flagged($content_id) ? 'unflag' : 'flag', $content_id, TRUE), @@ -698,6 +778,37 @@ } /** + * Form for confirming the (un)flagging of a piece of content. + */ +function flag_confirm(&$form_state, $action = 'flag', $flag_name, $content_id = '') { + $form = array(); + + $form['action'] = array( + '#type' => 'value', + '#value' => $action, + ); + $form['flag_name'] = array( + '#type' => 'value', + '#value' => $flag_name, + ); + $form['content_id'] = array( + '#type' => 'value', + '#value' => $content_id, + ); + + $flag = flag_get_flag($flag_name); + $question = $flag->get_label($action .'_confirmation', $content_id); + $path = isset($_GET['destination']) ? $_GET['destination'] : ''; + $yes = $flag->get_label($action .'_short', $content_id); + + return confirm_form($form, $question, $path, '', $yes); +} + +function flag_confirm_submit(&$form, &$form_state) { + flag_page($form_state['values']['action'], $form_state['values']['flag_name'], $form_state['values']['content_id']); +} + +/** * Flags, on unflags, an item. * * @param $account @@ -827,18 +938,41 @@ $action = $variables['action']; $content_id = $variables['content_id']; - $variables['setup'] = $first_time; - $first_time = FALSE; + // Generate the link URL. + $link_types = flag_get_link_types(); + $link_type_module = $link_types[$flag->link_type]['module']; + $link = module_invoke($link_type_module, 'flag_link', $flag, $action, $content_id); + if (isset($link['title']) && (!isset($link['html']) || $link['html'] != TRUE)) { + $link['title'] = check_plain($link['title']); + } + + if ($flag->link_type == 'toggle' && $first_time) { + $variables['setup'] = $first_time; + $first_time = FALSE; + } + $token = flag_get_token($content_id); - $variables['link_href'] = check_url(url("flag/$action/$flag->name/$content_id/$token", array('query' => drupal_get_destination()))); - $variables['link_text'] = strip_tags($flag->get_label($action . '_short', $content_id), ''); - $variables['link_title'] = strip_tags($flag->get_label($action . '_long', $content_id)); + $variables['link_href'] = url($link['href'], $link); + $variables['link_text'] = isset($link['title']) ? $link['title'] : strip_tags($flag->get_label($action . '_short', $content_id), ''); + $variables['link_title'] = isset($link['attributes']['title']) ? $link['attributes']['title'] : strip_tags($flag->get_label($action . '_long', $content_id)); $variables['flag_name_css'] = str_replace('_', '-', $flag->name); $variables['last_action'] = ($action == 'flag' ? 'unflagged' : 'flagged'); + $variables['flag_classes_array'] = array(); + $variables['flag_classes_array'][] = 'flag'; + $variables['flag_classes_array'][] = $variables['action'] .'-action'; + $variables['flag_classes_array'][] = 'flag-link-'. $flag->link_type; + + if (isset($link['attributes']['class'])) { + $variables['flag_classes_array'][] = $link['attributes']['class']; + } + if ($variables['after_flagging']) { $inverse_action = ($action == 'flag' ? 'unflag' : 'flag'); $variables['message_text'] = $flag->get_label($inverse_action . '_message', $content_id); + $variables['flag_classes_array'][] = $variables['last_action']; } + + $variables['flag_classes'] = implode(' ', $variables['flag_classes_array']); } /** @@ -908,6 +1042,18 @@ return $flag_names; } +/** + * Return an array of flag link types suitable for a select list or radios. + */ +function _flag_link_type_options() { + $options = array(); + $types = flag_get_link_types(); + foreach ($types as $type_name => $type) { + $options[$type_name] = $type['title']; + } + return $options; +} + // --------------------------------------------------------------------------- // Non-Views public API @@ -1129,6 +1275,28 @@ } /** + * Return an array of link types provided by modules. + */ +function flag_get_link_types($reset = FALSE) { + static $link_types; + + if (!isset($link_types) || $reset) { + $link_types = array(); + foreach (module_implements('flag_link_types') as $module) { + $module_types = module_invoke($module, 'flag_link_types'); + foreach ($module_types as $type_name => $type_title) { + $link_types[$type_name] = array( + 'module' => $module, + 'title' => $type_title, + ); + } + } + } + + return $link_types; +} + +/** * Get a private token used to protect links from spoofing - CSRF. */ function flag_get_token($nid) { Index: flag.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/flag/Attic/flag.inc,v retrieving revision 1.1.2.20 diff -u -r1.1.2.20 flag.inc --- flag.inc 13 Nov 2008 21:00:04 -0000 1.1.2.20 +++ flag.inc 14 Nov 2008 00:02:23 -0000 @@ -171,9 +171,12 @@ 'flag_short' => '', 'flag_long' => '', 'flag_message' => '', + 'flag_confirmation' => '', 'unflag_short' => '', 'unflag_long' => '', 'unflag_message' => '', + 'unflag_confirmation' => '', + 'link_type' => 'toggle', ); } Index: includes/flag_handler_field_ops.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/flag/includes/Attic/flag_handler_field_ops.inc,v retrieving revision 1.1.2.2 diff -u -r1.1.2.2 flag_handler_field_ops.inc --- includes/flag_handler_field_ops.inc 18 Sep 2008 15:37:47 -0000 1.1.2.2 +++ includes/flag_handler_field_ops.inc 14 Nov 2008 00:02:24 -0000 @@ -34,6 +34,17 @@ } } + function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); + + $form['link_type'] = array( + '#type' => 'radios', + '#title' => t('Link type'), + '#options' => array('' => t('Use flag link settings')) + _flag_link_type_options(), + '#default_value' => $this->options['link_type'], + ); + } + /** * Override base ::query(). The purpose here is to make it possible for the * render() method to know two things: what's the content ID, and whether @@ -110,7 +121,10 @@ // Flag does not apply to this content. return; } - + + if (!empty($this->options['link_type'])) { + $flag->link_type = $this->options['link_type']; + } return $flag->theme($is_flagged ? 'unflag' : 'flag', $content_id); } }