nid && count(fasttoggle_get_options('node', $node))) { $items[] = array( 'path' => 'node/'. arg(1) .'/toggle', 'title' => t('toggle'), 'callback' => 'fasttoggle_node_option', 'callback arguments' => array($node), 'access' => true, 'type' => MENU_CALLBACK, ); } } // The callback for toggling user settings elseif (arg(0) == 'admin' && arg(1) == 'user' && is_numeric(arg(2)) && arg(3) == 'toggle' && arg(4) != '') { $user = user_load(array('uid' => arg(2))); if ($user->uid && count(fasttoggle_get_options('user', $user))) { $items[] = array( 'path' => 'admin/user/'. arg(2) .'/toggle', 'title' => t('status'), 'callback' => 'fasttoggle_user_option', 'callback arguments' => array($user), 'access' => true, 'type' => MENU_CALLBACK, ); } } elseif (arg(0) == 'comment' && arg(1) == 'toggle' && is_numeric(arg(2)) && arg(3) != '') { $comment = _comment_load(arg(2)); if ($comment->cid && count(fasttoggle_get_options('comment', $comment))) { $items[] = array( 'path' => 'comment/toggle/'. arg(2), 'title' => t('status'), 'callback' => 'fasttoggle_comment_option', 'callback arguments' => array($comment), 'access' => true, 'type' => MENU_CALLBACK, ); } } } else { $items[] = array( 'path' => 'admin/settings/fasttoggle', 'title' => t('Fasttoggle'), 'description' => t('Configure what fast toggling options are available.'), 'callback' => 'drupal_get_form', 'callback arguments' => array('fasttoggle_settings_form'), ); } return $items; } /** * Implementation of hook_perm(). */ function fasttoggle_perm() { return array('promote posts', 'make posts sticky', 'moderate posts', 'moderate users', 'moderate comments', 'administer fasttoggle'); } /** * Implementation of hook_user(). * * Add togglable links to user pages. */ function fasttoggle_user($type, &$edit, &$user) { $settings = variable_get('fasttoggle_user_settings', array('status' => TRUE)); if ($type == 'view' && $settings['status'] && (user_access('administer users') || user_access('moderate users'))) { return array( t('Settings') => array( 'fasttoggle' => array( 'title' => '', 'value' => theme('links', fasttoggle_link('user', $user), array('class' => 'links inline')), 'class' => 'fasttoggle', ), ), ); } } /** * Implementation of hook_help(). */ function fasttoggle_help($section) { switch ($section) { case 'admin/settings/fasttoggle': return t('Configure what fast toggling options are available.'); break; } } /** * (Menu callback) Configures what fast toggling options are available. */ function fasttoggle_settings_form() { $form = array(); $form['fasttoggle_label_style'] = array( '#type' => 'radios', '#title' => t('Label style'), '#description' => t('Select what kind of labels you want for fasttoggle links. See the README.txt for information about providing your own labels.'), '#options' => array( FASTTOGGLE_LABEL_STATUS => t('Status (reflects the current state, e.g. "published", "active")'), FASTTOGGLE_LABEL_ACTION => t('Action (shows what happens upon a click, e.g. "unpublish", "block")'), ), '#default_value' => variable_get('fasttoggle_label_style', FASTTOGGLE_LABEL_STATUS), ); $custom_labels = variable_get('fasttoggle_labels', ''); if (!empty($custom_labels)) { $form['fasttoggle_label_style']['#options'][FASTTOGGLE_LABEL_CUSTOM] = t('Custom (configure in your settings.php)'); } $form['nodes'] = array( '#type' => 'fieldset', '#title' => t('Posts'), '#description' => t('Select what options for fast toggling of post settings are available.'), '#access' => user_access('administer fasttoggle'), ); $form['nodes']['fasttoggle_node_settings'] = array( '#type' => 'checkboxes', '#title' => t('Available settings'), '#options' => array( 'status' => t('Status (published/unpublished)'), 'sticky' => t('Sticky (stays at the top of listings)'), 'promote' => t('Promoted (visible on the front page)'), 'comment' => t('Topic opened/closed (users are allowed/disallowed to post comments)'), ), '#default_value' => array_keys(array_filter(variable_get('fasttoggle_node_settings', array('status' => TRUE, 'sticky' => TRUE, 'promote' => TRUE, 'comment' => FALSE)))), ); $form['nodes']['help_text'] = array( '#value' => t('Configure access restrictions for these settings on the access control page.', array('@url' => url('admin/user/access', NULL, 'module-fasttoggle'))), '#prefix' => '
', '#suffix' => '
', ); $form['comments'] = array( '#type' => 'fieldset', '#title' => t('Comments'), '#description' => t('Select what options for fast toggling of comment settings are available.'), '#access' => user_access('administer fasttoggle'), ); $form['comments']['fasttoggle_comment_settings'] = array( '#type' => 'checkboxes', '#title' => t('Available settings'), '#options' => array( 'status' => t('Status (published/unpublished)'), ), '#default_value' => array_keys(array_filter(variable_get('fasttoggle_comment_settings', array('status' => TRUE)))), ); $form['comments']['help_text'] = array( '#value' => t('Configure access restrictions for these settings on the access control page.', array('@url' => url('admin/user/access', NULL, 'module-fasttoggle'))), '#prefix' => '
', '#suffix' => '
', ); $form['users'] = array( '#type' => 'fieldset', '#title' => t('Users'), '#description' => t('Select what options for fast toggling of user settings are available.'), '#access' => user_access('administer fasttoggle'), ); $form['users']['fasttoggle_user_settings'] = array( '#type' => 'checkboxes', '#title' => t('Available settings'), '#options' => array( 'status' => t('Status (unblocked/blocked)'), ), '#default_value' => array_keys(array_filter(variable_get('fasttoggle_user_settings', array('status' => TRUE)))), ); $form['users']['help_text'] = array( '#value' => t('Get a listing of all users on the user overview page.', array('@url' => 'admin/user/user')), '#prefix' => '
', '#suffix' => '
', ); return system_settings_form($form); } /** * Add fasttoggle abilities to a link * * @param $title * The caption of the link * @param $callback * The callback URL that will be the queried when the user clicks on that link. * If queried via JS, it should perform the action because $_POST['confirm'] * is set to true. Return a JSON structure that has the key 'text' that contains * the updatd link text. * If the action is not confirmed, return a rendered confirmation form. * If you return JSON in your callback function, set the content type of the * header to text/javascript and the encoding to utf-8. Currently, only one * JSON parameter is used: text. * @param $html * (optional; defaults to true) Set whether this function should return a the * HTML code for the fast toggle link or a link structure for use in hook_link * hooks. * @param $token * (optional; defaults to an empty string) Provide a salt for the token * authentification added to each toggle link. If the string is empty, the * generic token for the user on this site is used. * * @return * Either a complete HTML link or a link array structure for use in hook_link. */ function fasttoggle($title, $callback, $html = true, $token = '') { static $sent = false; // Only include the support files once. if (!$sent) { $sent = true; drupal_add_js(drupal_get_path('module', 'fasttoggle') .'/fasttoggle.js'); drupal_add_css(drupal_get_path('module', 'fasttoggle') .'/fasttoggle.css', 'module', 'all', false); } $attributes = array('class' => 'fasttoggle', 'title' => t('Toggle this setting')); $query = drupal_get_destination() .'&token='. drupal_get_token($token); if ($html) { return l($title, $callback, $attributes, $query); } else { return array('title' => $title, 'href' => $callback, 'query' => $query, 'attributes' => $attributes); } } /** * Return an array of toggleable options of the object and the name of each state. * * @param $type * The object type the functions should return options for (e.g. node, comment, ...). * @param ... * Parameters for the fasttoggle_options hook. */ function fasttoggle_get_options($type) { $args = func_get_args(); array_unshift($args, 'fasttoggle_options'); return call_user_func_array('module_invoke_all', $args); } /** * Implementation of hook_fasttoggle_options(). */ function fasttoggle_fasttoggle_options($type, $obj = NULL) { $return = array(); switch ($type) { case 'node': // $obj = node $admin = user_access('administer nodes'); // Get an array with all enabled fast toggle links $settings = variable_get('fasttoggle_node_settings', array('status' => TRUE, 'sticky' => TRUE, 'promote' => TRUE, 'comment' => FALSE)); if ($settings['status'] && ($admin || user_access('moderate posts'))) { $return['status'] = _fasttoggle_get_label('node_status'); } if ($settings['sticky'] && ($admin || user_access('make posts sticky'))) { $return['sticky'] = _fasttoggle_get_label('node_sticky'); } if ($settings['promote'] && ($admin || user_access('promote posts'))) { $return['promote'] = _fasttoggle_get_label('node_promote'); } if (module_exists('comment') && $settings['comment'] && ($admin || user_access('administer comments'))) { $return['comment'] = _fasttoggle_get_label('comment_admin'); } break; case 'user': // $obj = user // Get an array with all enabled fast toggle links $settings = variable_get('fasttoggle_user_settings', array('status' => TRUE)); if ($settings['status'] && (user_access('administer users') || user_access('moderate users'))) { $return['status'] = _fasttoggle_get_label('user_status'); } break; case 'comment': // $obj = comment // Get an array with all enabled fast toggle links $settings = variable_get('fasttoggle_comment_settings', array('status' => TRUE)); if ($settings['status'] && (user_access('administer comments') || user_access('moderate comments'))) { $return['status'] = _fasttoggle_get_label('comment_status'); } break; } return $return; } /** * Implementation of hook_form_alter(). */ function fasttoggle_form_alter($form_id, &$form) { switch ($form_id) { case 'node_admin_nodes': // Add published/unpublished toggle links to the node overview page. if (isset($form['status'])) { foreach ($form['status'] as $key => $status) { $form['status'][$key]['#value'] = fasttoggle($status['#value'], 'node/'. $key .'/toggle/status', true, 'status_'. $key); } } break; case 'user_admin_account': // Add blocked/unblocked toggle links to the user overview page. if (isset($form['status'])) { foreach ($form['status'] as $key => $status) { $form['status'][$key]['#value'] = fasttoggle($status['#value'], 'admin/user/'. $key .'/toggle/status', true, 'status_'. $key); } } break; } } /** * Implementation of hook_link(). */ function fasttoggle_link($type, $obj = null, $teaser = false) { $links = array(); $options = fasttoggle_get_options($type, $obj); if (!empty($options)) { switch ($type) { case 'node': foreach (array_keys($options) as $key) { $links['fasttoggle_'. $key] = fasttoggle($options[$key][intval($obj->$key)], 'node/'. $obj->nid .'/toggle/'. $key, false, $key .'_'. $obj->nid); } break; case 'comment': foreach (array_keys($options) as $key) { $links['fasttoggle_'. $key] = fasttoggle($options[$key][intval($obj->$key)], 'comment/toggle/'. $obj->cid .'/'. $key, false, $key .'_'. $obj->cid); } break; // User is not one of the standard types for hook_link(). This // use enables adding of user links to a user profile. case 'user': foreach (array_keys($options) as $key) { $links['fasttoggle_'. $key] = fasttoggle($options[$key][intval($obj->$key)], 'admin/user/'. $obj->uid .'/toggle/'. $key, false, $key .'_'. $obj->uid); } break; } } return $links; } /** * Menu callback. Toggle options for a node if the action is confirmed via * POST. Otherwise, display a confirmation form. */ function fasttoggle_node_option($node, $option) { $options = fasttoggle_get_options('node', $node); // Check if the action is valid. This is essential to ensure the user has // access to the action. if (isset($options[$option]) && isset($_GET['token']) && drupal_valid_token($_GET['token'], $option .'_'. $node->nid, true)) { // The action is confirmed: either via form submit or via AJAX/POST if (isset($_POST['confirm']) && $_POST['confirm']) { // Get the next ID. while(key($options[$option]) != $node->$option) next($options[$option]); if (next($options[$option]) === FALSE) reset($options[$option]); // Save the node. $node->$option = key($options[$option]); node_save($node); // Output the new status for the updated link text on AJAX changes if (isset($_POST['javascript']) && $_POST['javascript']) { drupal_set_header('Content-Type: text/javascript; charset=utf-8'); echo drupal_to_js(array( 'text' => $options[$option][intval($node->$option)], 'callback' => 'node', 'option' => $option, 'status' => $node->$option, )); exit; } else { drupal_goto(); } } else { // The action is not confirmed. The user came here through a regular link; // no AJAX was involved. That means, we need a confirmation form so that // we get a POST form. return drupal_get_form('fasttoggle_node_option_confirm', $node, $options[$option][intval(!$node->$option)]); } } else { return MENU_NOT_FOUND; } } /** * Confirmation form for the option change of a node. */ function fasttoggle_node_option_confirm($node, $option) { return confirm_form(array(), t('Are you sure you want to set the post %title to %option?', array('%title' => $node->title, '%option' => $option)), $_GET['destination'] ? $_GET['destination'] : 'node/'. $node->nid, '', t('Change'), t('Cancel') ); } /** * Menu callback. Toggle the status of a user if the action is confirmed via * POST. Otherwise, display a confirmation form. */ function fasttoggle_user_option($user, $option) { $options = fasttoggle_get_options('user', $user); // Check if the action is valid. This is essential to ensure the user has // access to the action. if (isset($options[$option]) && isset($_GET['token']) && drupal_valid_token($_GET['token'], $option .'_'. $user->uid, true)) { if (isset($_POST['confirm']) && $_POST['confirm']) { $array = array($option => !$user->$option); $user = user_save($user, $array); // Output the new option for the updated link text on AJAX changes if (isset($_POST['javascript']) && $_POST['javascript']) { drupal_set_header('Content-Type: text/javascript; charset=utf-8'); echo drupal_to_js(array( 'text' => $options[$option][intval($array[$option])], )); exit; } else { drupal_goto(); } } else { // The action is not confirmed. The user came here through a regular link; // no AJAX was involved. That means, we need a confirmation form so that // we get a POST form. return drupal_get_form('fasttoggle_user_option_confirm', $user, $options[$option][intval($array[$option])]); } } else { return MENU_NOT_FOUND; } } /** * Confirmation form for the status change of a user. */ function fasttoggle_user_option_confirm($user, $option) { return confirm_form(array(), t('Are you sure you want to set the user %user to %option?', array('%user' => $user->name, '%option' => $option)), $_GET['destination'] ? $_GET['destination'] : 'user/'. $user->uid, '', t('Change'), t('Cancel') ); } /** * Menu callback. Toggle options for a comment if the action is confirmed via * POST. Otherwise, display a confirmation form. */ function fasttoggle_comment_option($comment, $option) { $options = fasttoggle_get_options('comment', $comment); // Check if the action is valid. This is essential to ensure the user has // access to the action. if (isset($options[$option]) && isset($_GET['token']) && drupal_valid_token($_GET['token'], $option .'_'. $comment->cid, true)) { // The action is confirmed: either via form submit or via AJAX/POST if (isset($_POST['confirm']) && $_POST['confirm']) { $comment->$option = !$comment->$option; comment_save((array)$comment); // Output the new status for the updated link text on AJAX changes if (isset($_POST['javascript']) && $_POST['javascript']) { drupal_set_header('Content-Type: text/javascript; charset=utf-8'); echo drupal_to_js(array( 'text' => $options[$option][intval($comment->$option)], 'callback' => 'comment', 'option' => $option, 'status' => $comment->$option, )); exit; } else { drupal_goto(); } } else { // The action is not confirmed. The user came here through a regular link; // no AJAX was involved. That means, we need a confirmation form so that // we get a POST form. return drupal_get_form('fasttoggle_comment_option_confirm', $comment, $options[$option][intval(!$comment->$option)]); } } else { return MENU_NOT_FOUND; } } /** * Confirmation form for the option change of a comment. */ function fasttoggle_comment_option_confirm($comment, $option) { return confirm_form(array(), t('Are you sure you want to set the comment %title to %option?', array('%title' => $comment->subject, '%option' => $option)), $_GET['destination'] ? $_GET['destination'] : 'comment/'. $comment->cid, '', t('Change'), t('Cancel') ); } /** * Implementation of hook_fasttoggle_labels(). */ function fasttoggle_fasttoggle_labels($style) { switch ($style) { case FASTTOGGLE_LABEL_ACTION: $labels = array( 'node_status' => array(0 => t('publish'), 1 => t('unpublish')), 'node_sticky' => array(0 => t('make sticky'), 1 => t('make unsticky')), 'node_promote' => array(0 => t('promote'), 1 => t('demote')), 'comment_admin' => array(0 => t('lock comments'), 1 => t('unlock comments'), 2 => t('hide comments')), 'user_status' => array(0 => t('unblock'), 1 => t('block')), 'comment_status' => array(0 => t('unpublish'), 1 => t('publish')), ); break; default: $labels = array( 'node_status' => array(0 => t('not published'), 1 => t('published')), 'node_sticky' => array(0 => t('not sticky'), 1 => t('sticky')), 'node_promote' => array(0 => t('not promoted'), 1 => t('promoted')), 'comment_admin' => array(0 => t('comments disabled'), 1 => t('comments read only'), 2 => t('comments read/write')), 'user_status' => array(0 => t('blocked'), 1 => t('active')), 'comment_status' => array(0 => t('published'), 1 => t('not published')), ); break; } return $labels; } /** * Returns an array with labels for a given setting. */ function _fasttoggle_get_label($label) { static $labels; if ($labels == NULL) { $style = variable_get('fasttoggle_label_style', FASTTOGGLE_LABEL_STATUS); $labels = module_invoke_all('fasttoggle_labels', $style); // Allow custom labels in settings.php. if ($style == FASTTOGGLE_LABEL_CUSTOM) { $labels = array_merge($labels, variable_get('fasttoggle_labels', array())); } } return $labels[$label]; } /** * Implementation of hook_views_tables(). */ function fasttoggle_views_tables() { $tables['fasttoggle'] = array( 'fields' => array( 'fasttoggle' => array( 'name' => t('Node: Fasttoggle'), 'handler' => 'fasttoggle_handler_field', 'query_handler' => 'fasttoggle_node_query_handler', 'sortable' => false, 'option' => array( '#type' => 'select', '#options' => array( 'status' => t('Status'), 'promote' => t('Promoted'), 'sticky' => t('Sticky'), 'comment' => t('Comment settings'), ), ), 'notafield' => 'true', 'help' => t('This field contains a fasttoggle link for the selected action for the current node.'), ), ), ); return $tables; } /** * Views query callback. */ function fasttoggle_node_query_handler($fielddata, $fieldinfo, &$query) { foreach(array('status', 'comment', 'promote', 'sticky') as $field) { if (!in_array('node.'. $field, $query->fields)) { $query->fields[] = 'node.'. $field; } } } /** * Views handler callback. */ function fasttoggle_handler_field($fieldinfo, $fielddata, $value, $data) { $options = fasttoggle_get_options('node', $data); $key = $fielddata['options']; if (isset($options[$key]) && isset($data->$key)) { return fasttoggle($options[$key][intval($data->$key)], 'node/'. $data->nid .'/toggle/'. $key, true, $key .'_'. $data->nid); } }