Index: nodequeue.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/nodequeue/nodequeue.module,v retrieving revision 1.79 diff -u -p -r1.79 nodequeue.module --- nodequeue.module 12 May 2009 16:50:37 -0000 1.79 +++ nodequeue.module 13 May 2009 14:27:32 -0000 @@ -1,11 +1,15 @@ $data) { $items['admin/content/nodequeue/add/'. $key] = array( 'title' => 'Add @type', - 'title arguments' => array('@type' => strtolower($data['title'])), + 'title arguments' => array('@type' => drupal_strtolower($data['title'])), 'access arguments' => $admin_access, 'page callback' => 'drupal_get_form', 'page arguments' => array('nodequeue_edit_queue_form', $key), @@ -131,15 +135,6 @@ function nodequeue_menu() { 'type' => MENU_CALLBACK ); - /*$sqid = arg(5); - if (is_numeric($sqid) && $subqueue = nodequeue_load_subqueue($sqid)) { - // The following operations require a sqid and a nid. - $nid = arg(6); - if (in_array(arg(4), array('add', 'remove-node')) && - is_numeric($nid)) { - $node = node_load($nid); - }*/ - $items["admin/content/nodequeue/%nodequeue/add/%subqueue/%node"] = array( 'access arguments' => array(6, 3, 5), 'access callback' => 'nodequeue_node_and_queue_access', @@ -200,8 +195,9 @@ function nodequeue_menu() { return $items; } + /** - * Implementation of hook_nodeapi + * Implementation of hook_nodeapi(). */ function nodequeue_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { switch ($op) { @@ -232,7 +228,7 @@ function nodequeue_nodeapi(&$node, $op, } /** - * Implementation of hook_link + * Implementation of hook_link(). */ function nodequeue_link($type, $node = NULL, $teaser = FALSE) { $links = array(); @@ -256,25 +252,25 @@ function nodequeue_link($type, $node = N unset($subqueues[$id]->position); } - if(!module_exists('translation')) { + if (!module_exists('translation')) { nodequeue_set_subqueue_positions($subqueues, $node->nid); } foreach ($subqueues as $subqueue) { $queue = $queues[$subqueue->qid]; $id = nodequeue_get_content_id($queue, $node); - if(module_exists('translation')) { + if (module_exists('translation')) { $subqueue = array($subqueue->sqid => $subqueue); nodequeue_set_subqueue_positions($subqueue, $id); $subqueue = array_shift($subqueue); } $query_string = nodequeue_get_query_string($id, TRUE); - $class = 'nodequeue-ajax-toggle nodequeue-toggle-q-'. $queue->qid. ' nodequeue-toggle-sq-'. $subqueue->sqid .' nodequeue-toggle-ref-'. $subqueue->reference; + $class = 'nodequeue-ajax-toggle nodequeue-toggle-q-'. $queue->qid .' nodequeue-toggle-sq-'. $subqueue->sqid .' nodequeue-toggle-ref-'. $subqueue->reference; if (!isset($subqueue->position)) { $links[$class] = array( 'title' => nodequeue_title_substitute($queue->link, $queue, $subqueue), 'href' => "admin/content/nodequeue/$queue->qid/add/$subqueue->sqid/$id", - 'attributes' => array('class' => $class . ' toggle-add'), + 'attributes' => array('class' => $class .' toggle-add'), 'query' => $query_string); } else if ($queue->link_remove) { @@ -292,7 +288,7 @@ function nodequeue_link($type, $node = N } /** - * Implementation of hook_views_api() + * Implementation of hook_views_api(). */ function nodequeue_views_api() { return array( @@ -309,14 +305,14 @@ function nodequeue_form_apachesolr_searc $weights = drupal_map_assoc(array('21.0', '13.0', '8.0', '5.0', '3.0', '2.0', '1.0', '0.8', '0.5', '0.3', '0.2', '0.1')); $weights['0'] = t('Normal'); $queues = nodequeue_load_subqueues_by_queue(array_keys(nodequeue_get_all_qids())); - + // build the form $form['biasing']['nodequeue_boost'] = array( '#type' => 'fieldset', '#title' => t('Nodequeue Biasing'), '#weight' => -5, - '#collapsible' => TRUE, - '#collapsed' => TRUE, + '#collapsible' => TRUE, + '#collapsed' => TRUE, ); $form['biasing']['nodequeue_boost']['nodequeue_apachesolr_boost'] = array( '#type' => 'item', @@ -359,7 +355,7 @@ function _nodequeue_solr_qid_key() { 'multiple' => TRUE, 'name' => "nodequeue", ); - + return apachesolr_index_key($qid_key); } @@ -371,7 +367,7 @@ function nodequeue_apachesolr_modify_que foreach ($queues as $sqid => $queue) { $boost = variable_get("nodequeue_apachesolr_boost_$sqid", 0); if (!empty($boost)) { - $params['bq'][] = _nodequeue_solr_qid_key() . ":$sqid^$boost"; + $params['bq'][] = _nodequeue_solr_qid_key() .":$sqid^$boost"; $params['facet.field'][] = _nodequeue_solr_qid_key(); } } @@ -533,7 +529,8 @@ function nodequeue_node_tab($node) { * Display a list of queues and their status for the administrator. */ function nodequeue_view_queues() { - $output = theme('advanced_help_topic', 'nodequeue', 'about', 'icon') . ' ' . theme('advanced_help_topic', 'nodequeue', 'about', t('Click here for information about this module')); + $output = theme('advanced_help_topic', 'nodequeue', 'about', 'icon') .' '. theme('advanced_help_topic', 'nodequeue', 'about', t('Click here for information about this module')); + // Fetch all of the queues. $queues = nodequeue_load_queues(nodequeue_get_all_qids(25)); foreach ($queues as $queue) { @@ -586,13 +583,13 @@ function nodequeue_view_queues() { $subqueues = nodequeue_load_subqueues_by_queue($qids); // Relate all the subqueues we loaded back to our queues. foreach ($subqueues as $subqueue) { - if (nodequeue_api_subqueue_access($subqueue, NULL, $queues[$subqueue->qid])) { - $queues[$subqueue->qid]->subqueue = $subqueue; - } + if (nodequeue_api_subqueue_access($subqueue, NULL, $queues[$subqueue->qid])) { + $queues[$subqueue->qid]->subqueue = $subqueue; + } } if (!empty($table_sort)) { - if (strtolower($table_sort['sort']) == 'desc') { + if (drupal_strtolower($table_sort['sort']) == 'desc') { array_multisort($sort_primary, $sort_direction['desc'], $sort_secondary, $queues); // Re-indexes array keys; key no longer equals qid. } else { @@ -607,7 +604,7 @@ function nodequeue_view_queues() { $sub_text .= " (". nodequeue_subqueue_size_text($queue->size, $queue->subqueue->count) .")"; } - $operations = array(l(t('View'), "admin/content/nodequeue/$queue->qid/view")); + $operations = array(l(t('View'), 'admin/content/nodequeue/'. $queue->qid .'/view/0')); if (user_access('administer nodequeue')) { $operations[] = l(t('Edit'), "admin/content/nodequeue/$queue->qid/edit"); $operations[] = l(t('Delete'), "admin/content/nodequeue/$queue->qid/delete"); @@ -664,11 +661,11 @@ function nodequeue_edit_queue_form(&$for // For adding queues. if (is_string($queue)) { // If the $queue is a string - name of a queue type, basically - then we test that it's a valid queue type. - $queue = strtolower($queue); + $queue = drupal_strtolower($queue); if (!isset($info[$queue])) { - return false; + return FALSE; } - drupal_set_title(t('Add @type', array('@type' => strtolower($info[$queue]['title'])))); + drupal_set_title(t('Add @type', array('@type' => drupal_strtolower($info[$queue]['title'])))); $queue = new nodequeue_queue($queue); } else { @@ -784,8 +781,8 @@ function nodequeue_edit_queue_form(&$for '#default_value' => empty($queue->qid) && module_exists('translation_helpers') ? 0 : $queue->i18n, '#description' => t('Treating translations as a single node allows users to add, remove and manipulate a node in the queue regardless of which translation is acted upon; nodequeue will only act on the original node. - When manually managing translation nodes, Nodequeue will ignore the relationship between node translations; - each translation node must be added to the queue separately and will occupy a separate spot in the queue. + When manually managing translation nodes, Nodequeue will ignore the relationship between node translations; + each translation node must be added to the queue separately and will occupy a separate spot in the queue. Changing this setting will not update content that is already in the queue.'), '#access' => module_exists('translation_helpers'), ); @@ -947,7 +944,7 @@ function nodequeue_admin_view($queue, $s $qid = $queue->qid; // If the queue has just one subqueue, it gets special treatment. - if (!$subqueue->sqid) { + if (empty($subqueue->sqid)) { if ($queue->subqueues == 1) { $subqueues = nodequeue_load_subqueues_by_queue($queue->qid); $subqueue = array_shift($subqueues); @@ -958,7 +955,7 @@ function nodequeue_admin_view($queue, $s } } else if ($subqueue->sqid) { - if (!nodequeue_api_subqueue_access($subqueue, NULL, $queue)) { + if (!nodequeue_api_subqueue_access($subqueue, NULL, $queue)) { return drupal_not_found(); } // Adjust properties of the page so our subqueue is in the right @@ -1025,168 +1022,149 @@ function nodequeue_arrange_subqueue_entr /** * View the contents of a subqueue, with links to re-order the queue. */ -function nodequeue_arrange_subqueue($queue, $subqueue) { - $qid = $queue->qid; - $sqid = $subqueue->sqid; - $output = ''; - - $order = $queue->reverse ? 'DESC' : 'ASC'; - $result = db_query("SELECT DISTINCT(n.nid), n.title, n.uid, u.name, n.created, nq.position FROM {node} n LEFT JOIN {users} u on n.uid = u.uid LEFT JOIN {nodequeue_nodes} nq ON nq.nid = n.nid WHERE nq.sqid = %d ORDER BY nq.position $order", $sqid); - - $body = ''; - - $nids = array(); - while ($node = db_fetch_object($result)) { - $nids[$node->position] = $node->nid; - $body .= nodequeue_arrange_subqueue_entry($queue, $subqueue, $node); +function nodequeue_arrange_subqueue($queue, $subqueue = NULL) { + // set title and load subqueue if it's not provided + drupal_set_title(t("Nodequeue '@title'", array('@title' => $queue->title))); + if (!$subqueue->sqid) { + if ($queue->subqueues == 1) { + $subqueues = nodequeue_load_subqueues_by_queue($queue->qid); + $subqueue = array_shift($subqueues); + } + else { + return drupal_not_found(); + } + } + else if ($subqueue->sqid) { + if (!nodequeue_api_subqueue_access($subqueue, NULL, $queue)) { + return drupal_not_found(); + } + drupal_set_title(t("Subqueue '@title'", array('@title' => nodequeue_title_substitute($queue->subqueue_title, $queue, $subqueue)))); } - $output = '

'. t('Max nodes in queue: @size', array('@size' => $queue->size ? $queue->size : t("Infinite"))) .'

'; - - $output .= '

'; - $output .= t('Changes made to the queue order and queue removals will not be active until you click Save, below. If you add more nodes than the queue can hold, they will be removed from the @end when you save!', array('@end' => $queue->reverse ? t('bottom') : t('top'))); - $output .= '

'; - - $output .= ''; - $output .= ''; - $output .= ''; - $output .= ''; - $output .= ''; - $output .= ''; - $output .= ''; - $output .= ''; - $output .= ''. $body .''; - $output .= '
'. t('Node') .''. t('Author') .''. t('Date Created') .''. t('Operation') .'
'; - - $output .= drupal_get_form('nodequeue_arrange_subqueue_form', $queue, $sqid, $nids); - drupal_add_js(drupal_get_path('module', 'nodequeue') .'/nodequeue.js'); + // get nodes from the queue + $nodes = _nodequeue_dragdrop_get_nodes($queue, $subqueue); - return $output; + return drupal_get_form('nodequeue_arrange_subqueue_form', $queue, $nodes, $subqueue); } /** - * Form used for arranging a queue + * Form definition for nodequeue drag'n'drop form. */ -//TODO: Form - Revise for D6 -function nodequeue_arrange_subqueue_form($form_state, $queue, $sqid, $nids) { - $form['qid'] = array( - '#type' => 'value', - '#value' => $queue->qid, - ); +function nodequeue_arrange_subqueue_form($form_state, $queue, $nodes, $subqueue) { + $form = array('#tree' => TRUE); - $form['sqid'] = array( - '#type' => 'hidden', - '#value' => $sqid, - ); - - $form['order'] = array( - '#type' => 'hidden', - '#id' => 'nodequeue-order', - '#default_value' => implode(',', array_keys($nids)), - ); - - $form['add'] = array( - '#type' => 'textfield', - '#title' => t('Select title to add'), - '#autocomplete_path' => "nodequeue/autocomplete/$sqid", - '#default_value' => '', - ); - - // For use by the validate handler - $form['nid'] = array( - '#type' => 'value', - '#value' => 0, - ); + // save queue and subqueue objects for later use + $form['#queue'] = (array) $queue; + $form['#subqueue'] = (array) $subqueue; - $form['add_submit'] = array( - '#type' => 'submit', - '#attributes' => array('class' => 'nodequeue-add'), - '#value' => t('Add'), - '#validate' => array('nodequeue_arrange_subqueue_form_add_validate'), - '#submit' => array('nodequeue_arrange_subqueue_form_add_submit'), - ); + // prepare the main part of the form which will be themed as a table + $count = count($nodes); + foreach ($nodes as $node) { + $form[$node->nid]['#node'] = (array) $node; + $form[$node->nid]['title'] = array('#value' => l($node->title, 'node/'. $node->nid)); + $form[$node->nid]['author'] = array('#value' => theme('username', $node)); + $form[$node->nid]['date'] = array('#value' => format_date($node->created)); + $form[$node->nid]['edit'] = array('#value' => l(t('edit'), 'node/'. $node->nid .'/edit')); + $form[$node->nid]['position'] = array( + '#type' => 'position', + '#delta' => $count, + '#default_value' => $node->position, + '#attributes' => array( + 'class' => 'node-position', + ), + ); - $form['save'] = array( - '#type' => 'submit', - '#attributes' => array('class' => 'nodequeue-hide-if-not-js-hide nodequeue-save'), - '#value' => t('Save'), - '#validate' => array('nodequeue_arrange_subqueue_form_save_validate'), - ); + $icon = theme('image', drupal_get_path('module', 'nodequeue') .'/images/delete.png', t('Remove from queue')); + $attr = array( + 'attributes' => array( + 'title' => t('Remove from queue'), + 'class' => 'nodequeue-remove', + 'style' => 'display:none;', + 'id' => 'nodequeue-remove-'. $node->nid, + ), + 'html' => TRUE, + ); + $form[$node->nid]['remove'] = array('#value' => l($icon, '', $attr)); + } - $form['clear'] = array( + // add submit, reverse, and shuffle buttons + $form['submit'] = array( '#type' => 'submit', - '#attributes' => array('class' => 'nodequeue-clear'), - '#value' => t('Clear'), - '#submit' => array('nodequeue_arrange_subqueue_form_clear_submit'), + '#value' => t('Save') ); - - $form['reverse_click'] = array( + $form['reverse'] = array( '#type' => 'submit', - '#attributes' => array('class' => 'nodequeue-reverse'), '#value' => t('Reverse'), - '#submit' => array('nodequeue_arrange_subqueue_form_submit'), + '#submit' => array('nodequeue_arrange_subqueue_form_reverse_submit'), ); - $form['shuffle'] = array( '#type' => 'submit', - '#attributes' => array('class' => 'nodequeue-shuffle'), '#value' => t('Shuffle'), '#submit' => array('nodequeue_arrange_subqueue_form_shuffle_submit'), ); - // Store the original order. - $form['nids'] = array( - '#type' => 'value', - '#value' => $nids, - ); + return $form; +} - $form['added_nids'] = array( - '#type' => 'hidden', - '#default_value' => '', - ); - - $settings = array( - 'nodequeue-table' => array( - // The gadget that stores our the order of items. - 'order' => 'input#nodequeue-order', - // The buttons that do stuff. - 'up' => 'a.nodequeue-move-up', - 'down' => 'a.nodequeue-move-down', - 'top' => 'a.nodequeue-move-front', - 'bottom' => 'a.nodequeue-move-back', - 'remove' => 'a.nodequeue-remove', - - // The button that adds an item - 'add' => 'input.nodequeue-add', - // The buttom to clear the queue - 'clear_list' => 'input.nodequeue-clear', - // Path for js to shuffle the queue - 'shuffle' => 'input.nodequeue-shuffle', - // Path for js to reverse the queue - 'reverse' => 'input.nodequeue-reverse', - // Path for ajax on adding an item - 'path' => url('nodequeue/ajax/add', array('absolute' => TRUE)), - // Which items to post when adding - 'post' => array('#edit-sqid', '#edit-add'), - // Where to get the id of an item - 'tr' => 'nodequeue-row-', - 'row_class' => 'tr.nodequeue-row', - // Where to put the extra (we're storing a nid) - 'extra' => '#edit-added-nids', - // What item to focus on ready - 'focus' => '#edit-add', - // What item(s) to clear after add - 'clear' => array('#edit-add'), - // What hidden class to show as soon as anything has changed that needs saving. - 'hidden' => '.nodequeue-js-hide', - // Do we add to the top or the bottom? - 'add_location' => $queue->reverse ? 'top' : 'bottom', - ), - ); - drupal_add_js(array('nodequeue' => $settings), 'setting'); - drupal_add_css(drupal_get_path('module', 'nodequeue') .'/nodequeue.css'); +/** + * Submit handler for nodequeue drag'n'drop form. Updates node positions in {nodequeue_nodes}. + */ +function nodequeue_arrange_subqueue_form_submit($form, &$form_state, $reverse = FALSE, $shuffle = FALSE) { + $nodes = array(); + $positions = array(); + foreach ($form_state['values'] as $nid => $element) { + if (is_numeric($nid)) { + $nodes[$form_state['values'][$nid]['position']] = $nid; + } + } - return $form; + // reverse the list if the queue is set to display in reverse or if the + // reverse button was clicked. + ksort($nodes); + if ($form['#queue']['reverse'] xor $reverse) { + krsort($nodes); + } + // shuffle the list if the shuffle button was pressed. + if ($shuffle) { + $keys = array_keys($nodes); + $values = array_values($nodes); + shuffle($values); + $nodes = array_combine($keys, $values); + } + + $qid = $form['#queue']['qid']; + $sqid = $form['#subqueue']['sqid']; + $return = nodequeue_save_subqueue_order($nodes, $qid, $sqid); + drupal_set_message(t($return[1])); +} + +/** + * Submit handler for nodequeue drag'n'drop reverse button. + */ +function nodequeue_arrange_subqueue_form_reverse_submit($form, &$form_state) { + nodequeue_arrange_subqueue_form_submit($form, $form_state, TRUE); +} + +/** + * Submit handler for nodequeue drag'n'drop shuffle button. + */ +function nodequeue_arrange_subqueue_form_shuffle_submit($form, &$form_state) { + nodequeue_arrange_subqueue_form_submit($form, $form_state, FALSE, TRUE); +} + +/** + * Return a list of nodes in a specific subqueue. + */ +function _nodequeue_dragdrop_get_nodes($queue, $subqueue) { + $order = $queue->reverse ? 'DESC' : 'ASC'; + $result = db_query('SELECT DISTINCT(n.nid), n.title, n.uid, u.name, n.created, nq.position FROM {node} n LEFT JOIN {users} u on n.uid = u.uid LEFT JOIN {nodequeue_nodes} nq ON nq.nid = n.nid WHERE nq.sqid = %d ORDER BY nq.position '. $order, $subqueue->sqid); + + $nodes = array(); + while ($node = db_fetch_object($result)) { + $nodes[] = $node; + } + + return $nodes; } /** @@ -1211,139 +1189,120 @@ function nodequeue_theme() { ); } -//TODO: Theme function for Form - do we need to revise? +/** + * Theme the subqueue overview as a sortable list. + */ function theme_nodequeue_arrange_subqueue_form($form) { - $header = array( - check_plain($form['add']['#title']), - '', - ); + $output = ''; - unset($form['add']['#title']); - $rows = array( - drupal_render($form['add']), - array('data' => drupal_render($form['add_submit']), 'width' => '80%'), - ); + $subqueue = $form['#subqueue']; - $output = theme('table', $header, array($rows)); - $output .= drupal_render($form); - return $output; -} + // get css to hide some of the help text if javascript is disabled + drupal_add_css(drupal_get_path('module', 'nodequeue') .'/nodequeue.css'); -/** - * Validate handler for nodequeue_arrange_subqueue_form - */ -function nodequeue_arrange_subqueue_form_validate($form, &$form_state) { - // Default Validator - does nothing -} + //TODO: Would be nice to expose qid, sqid, reference as classes for more custom theming :). + drupal_add_tabledrag('nodequeue-dragdrop-'. $subqueue['qid'] .'-'. $subqueue['sqid'], 'order', 'sibling', 'node-position'); + drupal_add_js(drupal_get_path('module', 'nodequeue') .'/nodequeue_dragdrop.js'); -/** - * Validate handler for nodequeue_arrange_subqueue_form for 'Add' button. - * - * @param unknown_type $form_id - * @param unknown_type $form_state - * @param unknown_type $form - */ -function nodequeue_arrange_subqueue_form_add_validate($form, &$form_state) { - $queue = nodequeue_load($form_state['values']['qid']); - $subqueue = nodequeue_load($form_state['values']['sqid']); - $nodes = nodequeue_api_autocomplete($queue, $subqueue, $form_state['values']['add']); - if (empty($nodes) || !is_array($nodes)) { - form_error($form['add'], t('Invalid node')); - return; + // render form as table rows + $rows = array(); + foreach (element_children($form) as $key) { + if (isset($form[$key]['title'])) { + $row = array(); + + $row[] = drupal_render($form[$key]['title']); + $row[] = drupal_render($form[$key]['author']); + $row[] = drupal_render($form[$key]['date']); + $row[] = drupal_render($form[$key]['position']); + $row[] = drupal_render($form[$key]['edit']); + $row[] = drupal_render($form[$key]['remove']); + + $rows[] = array( + 'data' => $row, + 'class' => 'draggable', + ); + } } - if (count($nodes) > 1) { - form_error($form['add'], t('That matches too many nodes')); - return; + if (empty($rows)) { + $rows[] = array(array('data' => t('No nodes in this queue.'), 'colspan' => '4')); } - $keys = array_keys($nodes); - $nid = array_pop($keys); - form_set_value($form['nid'], $nid, $form_state); + + $header = array(t('Title'), t('Author'), t('Date'), t('Position'), array('data' => t('Operations'), 'colspan' => '2')); + $output .= theme('table', $header, $rows, array('id' => 'nodequeue-dragdrop-'. $subqueue['qid'] .'-'. $subqueue['sqid'], 'class' => 'nodequeue-dragdrop')); + $output .= drupal_render($form); + + return $output; } /** - * Validate handler for nodequeue_arrange_subqueue_form for 'Save' button. - * - * @param unknown_type $form_id - * @param unknown_type $form_state - * @param unknown_type $form + * Validate handler for nodequeue_arrange_subqueue_form */ -function nodequeue_arrange_subqueue_form_save_validate($form, &$form_state) { - $nids = $form_state['values']['nids']; - - // We can't use array_merge because it'll reset our keys and we can't - // use + because it will overwrite. - if ($form_state['values']['added_nids']) { - foreach (explode(',', $form_state['values']['added_nids']) as $nid) { - if (empty($nids)) { - $nids[1] = $nid; - } - else { - $nids[max(array_keys($nids)) + 1] = $nid; - } +function nodequeue_arrange_subqueue_form_validate($form, &$form_state) { + $positions = array(); + foreach ($form_state['values'] as $nid => $element) { + if (is_numeric($nid) && is_numeric($element['position'])) { + $positions[] = $element['position']; } } - form_set_value($form['nids'], $nids, $form_state); + if (count(array_unique($positions)) < count($positions)) { + //This is also checked in nodequeue_save_subqueue_order to prevent invalid programmatic submissions; + //TODO: We could be more descriptive with the form_set_error. + form_set_error('', t('Duplicate position value.')); + } } /** - * Submit function for nodequeue_arrange_subqueue_form on 'Reverse' button. + * Validates new subqueue order information and if it passes validation, + * deletes the old subqueue data from the database and saves the new data. * - * Yeah, this just calls the below function with a different parameter, but in D6 we're not supposed to use the $form['ops']. - */ -function nodequeue_arrange_subqueue_form_reverse_submit($form, &$form_state) { - nodequeue_arrange_subqueue_form_submit($form, $form_state, TRUE, FALSE); -} - -function nodequeue_arrange_subqueue_form_shuffle_submit($form, &$form_state) { - nodequeue_arrange_subqueue_form_submit($form, $form_state, FALSE, TRUE); -} + * @param $nodes: + * an array of nodes, keyed on the subqueue position. + * @param $qid + * the queue id + * @param unknown_type $sqid + * the subqueue id + * @return An array where the first element is a numeric status code + * (0 means successfully saved) and the second element is a status message. + */ +function nodequeue_save_subqueue_order($nodes = array(), $qid, $sqid) { + $positions = array(); + $now = time(); -/** - * Submit function for nodequeue_arrange_subqueue_form - */ -//TODO: Form Submit - Revise for D6 -function nodequeue_arrange_subqueue_form_submit($form, &$form_state, $reverse=FALSE, $shuffle=FALSE) { - // Add a node to the queue if that's the intention. - $queue = nodequeue_load($form_state['values']['qid']); - $subqueue = nodequeue_load_subqueue($form_state['values']['sqid']); + $queue = nodequeue_load($qid); + $subqueue = nodequeue_load_subqueue($sqid); - db_query("DELETE FROM {nodequeue_nodes} WHERE sqid = %d", $form_state['values']['sqid']); - if ($form_state['values']['order']) { - $now = time(); - $sql = ''; - $args = array(); - $nids = $form_state['values']['nids']; - $subqueue->count = 0; - $order = explode(',', $form_state['values']['order']); - if ($queue->reverse xor $reverse) { - $order = array_reverse($order); + db_query('DELETE FROM {nodequeue_nodes} WHERE sqid = %d', $sqid); + foreach ($nodes as $pos => $nid) { + if ($pos != 'r' && (!is_numeric($pos) || $pos < 1)) { + return array(0 => 1, 1 => 'Invalid position value.'); } - foreach ($order as $new_pos => $old_pos) { - if ($sql) { - $sql .= ', '; - } - $sql .= ' (%d, %d, %d, %d, %d)'; - $args[] = $form_state['values']['sqid']; - $args[] = $form_state['values']['qid']; - $args[] = $nids[$old_pos]; - - // $new_pos starts from 0 but we start from 1. - $args[] = $new_pos + 1; - $args[] = $now; - $subqueue->count++; - } - $sql = "INSERT INTO {nodequeue_nodes} (sqid, qid, nid, position, timestamp) VALUES $sql"; - db_query($sql, $args); - if ($queue->size) { - // 0 means infinity so never do this if false - nodequeue_check_subqueue_size($queue, $subqueue); + if (!is_numeric($nid) || $nid < 1) { + return array(0 => 2, 1 => 'Invalid nid value.'); + } + if ($pos != 'r') { + $positions[] = $pos; + $sql = ' (%d, %d, %d, %d, %d)'; + $args = array($sqid, $qid, $nid, $pos, $now); } - if ($shuffle) { //$form_values['op'] == t('Shuffle')) { - nodequeue_subqueue_shuffle($subqueue); + + if (!empty($args)) { + $sql = 'INSERT INTO {nodequeue_nodes} (sqid, qid, nid, position, timestamp) VALUES '. $sql; + db_query($sql, $args); } } - drupal_set_message(t('The queue has been updated')); + // FIXME: Validate earlier than this + if (count(array_unique($positions)) < count($positions)) { + return array(0 => 3, 1 => 'Duplicate position values are not allowed.'); + } + if ($queue->size) { + // 0 means infinity so never do this if false + nodequeue_check_subqueue_size($queue, $subqueue); + } +// if ($shuffle) { +// nodequeue_subqueue_shuffle($subqueue); +// } + return array(0 => 0, 1 => 'The queue has been updated.'); } function nodequeue_arrange_subqueue_form_clear_submit($form, &$form_state) { @@ -1460,7 +1419,7 @@ function nodequeue_admin_remove($queue, //TODO: Form - Revise for D6. function nodequeue_clear_confirm(&$form_state, $queue, $subqueue) { if (!is_numeric($subqueue)) { - return false; + return FALSE; } drupal_set_title(t("Nodequeue '@title'", array('@title' => $queue->title))); $form['sqid'] = array('#type' => 'value', '#value' => $subqueue->sqid); @@ -1550,7 +1509,7 @@ function _nodequeue_ajax_add($sqid, $pos if (!nodequeue_api_subqueue_access($subqueue)) { return array('error' => t('Access denied')); } - + $nodes = nodequeue_api_autocomplete($queue, $subqueue, $string); if (empty($nodes) || !is_array($nodes)) { return array('error' => t('Invalid node')); @@ -1669,12 +1628,12 @@ function nodequeue_load_queues_by_type($ * @param unknown_type $queue * @return unknown */ -function nodequeue_node_and_queue_access($node, $queue, $subqueue = NULL) { +function nodequeue_node_and_queue_access($node, $queue, $subqueue = NULL) { return nodequeue_node_access($node->type) && nodequeue_queue_access($queue, $subqueue); } function nodequeue_node_tab_access($node) { - if (!user_access('manipulate queues')) { + if (!user_access('manipulate queues')) { //For performance reasons: If the user can't manipulate queues, there is no reason to run the rest of these queries. return FALSE; } @@ -1714,7 +1673,8 @@ function nodequeue_node_access($type, $l * Filter a list of qids returned by nodequeue_get_qids to a location. * * @param $qids - * An array of $qids from @see nodequeue_get_qids() + * An array of $qids from + * @see nodequeue_get_qids() * @param $location * One of: * - 'links': Only check for queues that have node links. @@ -1741,7 +1701,7 @@ function nodequeue_filter_qids(&$qids, $ * @return $qids * An array in the format: @code { array($qid => array('qid' => $qid, 'show_in_tab' ' * => true/false, 'show_in_links' => true/false } - * + * * @param $bypass_cache * Boolean value indicating whether to bypass the cache or not. */ @@ -1828,7 +1788,7 @@ function nodequeue_get_all_qids($page_si * * @param $qids * An array of queue IDs to load. - * + * * @param $bypass_cache * Boolean value indicating whether to bypass the cache or not. */ @@ -2039,7 +1999,7 @@ function nodequeue_load_subqueues_by_ref $where .= 's.qid = %d AND s.reference IN ('. implode(', ', $key_list) .')'; } - $result = db_query("SELECT s.*, COUNT(n.position) AS count FROM {nodequeue_subqueue} s LEFT JOIN {nodequeue_nodes} n ON n.sqid = s.sqid WHERE $where GROUP BY s.sqid", $values); + $result = db_query('SELECT s.*, COUNT(n.position) AS count FROM {nodequeue_subqueue} s LEFT JOIN {nodequeue_nodes} n ON n.sqid = s.sqid WHERE '. $where .' GROUP BY s.sqid', $values); while ($subqueue = db_fetch_object($result)) { $cache[$subqueue->qid][$subqueue->reference] = $subqueues[$subqueue->sqid] = $subqueue; @@ -2180,7 +2140,7 @@ function nodequeue_subqueue_add($queue, // If adding this would make the queue too big, pop the front node // (or nodes) out. - if ($queue->size) { + if (!empty($queue->size)) { // 0 means infinity so never do this if false nodequeue_check_subqueue_size($queue, $subqueue, $queue->size - 1); } @@ -2214,7 +2174,9 @@ function nodequeue_subqueue_remove_node( * Remove a node or node(s) from a nodequeue by position. * * If you know the nid but but not the position, use - * @see nodequeue_subqueue_remove_node() instead. + * nodequeue_subqueue_remove_node() instead. + * + * @see nodequeue_subqueue_remove_node() * * @param $sqid * The subqueue to remove nodes from. @@ -2389,7 +2351,7 @@ function nodequeue_get_subqueues_by_node // only allow the static cache to be used if the nid is the same as the last $subqueues = nodequeue_load_subqueues_by_reference($references, ($last_nid != $node->nid)); $last_nid = $node->nid; - + return $subqueues; } @@ -2471,7 +2433,7 @@ function nodequeue_subqueue_shuffle($sub // Hooks to implement the default nodequeue type. /** - * Implementation of hook_nodequeue_info() + * Implementation of hook_nodequeue_info(). */ function nodequeue_nodequeue_info() { return array('nodequeue' => array( @@ -2481,7 +2443,7 @@ function nodequeue_nodequeue_info() { } /** - * Implementation of hook_nodequeue_form_submit() + * Implementation of hook_nodequeue_form_submit(). */ function nodequeue_nodequeue_form_submit(&$queue, $form_state) { // This will add a single subqueue to our new queue. @@ -2497,9 +2459,9 @@ function nodequeue_nodequeue_form_submit /** * in general it's preferable to use Views for this functionality. */ -function nodequeue_node_titles($sqid, $title = '', $backward = true, $from = 0, $count = 0) { - $orderby = ($backward ? "DESC" : "ASC"); - $sql = db_rewrite_sql("SELECT n.nid, n.title FROM {node} n LEFT JOIN {nodequeue_nodes} nn ON n.nid = nn.nid WHERE nn.sqid = %d AND n.status = 1 ORDER BY nn.position $orderby"); +function nodequeue_node_titles($sqid, $title = '', $backward = TRUE, $from = 0, $count = 0) { + $orderby = ($backward ? 'DESC' : 'ASC'); + $sql = db_rewrite_sql('SELECT n.nid, n.title FROM {node} n LEFT JOIN {nodequeue_nodes} nn ON n.nid = nn.nid WHERE nn.sqid = %d AND n.status = 1 ORDER BY nn.position '. $orderby); if ($count) { $result = db_query_range($sql, $sqid, $from, $count); } @@ -2524,8 +2486,8 @@ function nodequeue_view_nodes($sqid, $ba * Load an array of node objects belonging to a particular nodequeue. */ function nodequeue_load_nodes($sqid, $backward = FALSE, $from = 0, $count = 5) { - $orderby = ($backward ? "DESC" : "ASC"); - $sql = db_rewrite_sql("SELECT n.nid FROM {node} n INNER JOIN {nodequeue_nodes} nn ON n.nid = nn.nid WHERE nn.sqid = %d AND n.status = 1 ORDER BY nn.position $orderby"); + $orderby = ($backward ? 'DESC' : 'ASC'); + $sql = db_rewrite_sql('SELECT n.nid FROM {node} n INNER JOIN {nodequeue_nodes} nn ON n.nid = nn.nid WHERE nn.sqid = %d AND n.status = 1 ORDER BY nn.position '. $orderby); if ($count) { $result = db_query_range($sql, $sqid, $from, $count); } @@ -2571,8 +2533,8 @@ function nodequeue_load_random_node($sqi } /** -* Get the position of a node in a subqueue, or FALSE if not found. -*/ + * Get the position of a node in a subqueue, or FALSE if not found. + */ function nodequeue_subqueue_position($sqid, $nid) { return db_result(db_query("SELECT position FROM {nodequeue_nodes} WHERE sqid = %d AND nid = %d", $sqid, $nid)); } @@ -2726,7 +2688,7 @@ function nodequeue_api_autocomplete($que return $function($queue, $subqueue, $string, $where, $where_args); } else { - $result = db_query_range(db_rewrite_sql("SELECT n.nid, n.title FROM {node} n WHERE $where"), $where_args, 0, 10); + $result = db_query_range(db_rewrite_sql('SELECT n.nid, n.title FROM {node} n WHERE '. $where), $where_args, 0, 10); while ($node = db_fetch_object($result)) { $matches[$node->nid] = check_plain($node->title) ." [nid: $node->nid]"; } @@ -2750,7 +2712,7 @@ function nodequeue_api_queue_access($que } if ($queue->owner != 'nodequeue') { // Avoids an infinite loop. - $function = $queue->owner . '_queue_access'; + $function = $queue->owner .'_queue_access'; if (function_exists($function)) { $access = $function($queue, $account); } @@ -2771,12 +2733,12 @@ function nodequeue_api_subqueue_access($ global $user; $account = $user; } - + if (!$queue) { $queue = nodequeue_load($subqueue->qid); } - $function = $queue->owner . '_subqueue_access'; + $function = $queue->owner .'_subqueue_access'; if (function_exists($function)) { $access = $function($subqueue, $account, $queue); } @@ -2851,3 +2813,47 @@ function nodequeue_get_token($nid) { function nodequeue_check_token($seed) { return drupal_get_token($seed) == $_GET['token']; } + +/** + * Implementation of hook_elements(). + */ +function nodequeue_elements() { + $type = array(); + + $type['position'] = array( + '#input' => TRUE, + '#delta' => 10, + '#default_value' => 0, + '#process' => array('process_position', 'form_expand_ahah'), + ); + + return $type; +} + +/** + * Expand position elements into selects. Works like the weight element, except + * only positive values are allowed. + */ +function process_position($element) { + for ($n = 1; $n <= $element['#delta']; $n++) { + $positions[$n] = $n; + } + $element['#options'] = $positions; + $element['#options']['r'] = t('Remove'); + $element['#type'] = 'select'; + $element += _element_info('select'); + + return $element; +} + +/** + * If no default value is set for position select boxes, use 1. + */ +function position_value(&$form) { + if (isset($form['#default_value'])) { + $form['#value'] = $form['#default_value']; + } + else { + $form['#value'] = 1; + } +} Index: nodequeue_dragdrop.js =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/nodequeue/nodequeue_dragdrop.js,v retrieving revision 1.1 diff -u -p -r1.1 nodequeue_dragdrop.js --- nodequeue_dragdrop.js 6 Jan 2009 15:23:00 -0000 1.1 +++ nodequeue_dragdrop.js 13 May 2009 14:27:32 -0000 @@ -1,4 +1,77 @@ -$(document).ready(function() { +// $Id$ + +Drupal.behaviors.nodeQueueReverse = function(context) { + var changed = false; + + $('#edit-reverse').click(function(){ + // reverse table rows... + $('tr.draggable').each(function(i){ + $('.nodequeue-dragdrop tbody').prepend(this); + }); + + // ...and update node positions + var size = $('.node-position').size(); + $('.node-position').each(function(i){ + var val = $(this).val(); + $(this).val(size - val + 1); + }); + + if (changed == false) { + $(Drupal.theme('tableDragChangedWarning')).insertAfter('#nodequeue-dragdrop-1-1').hide().fadeIn('slow'); + changed = true; + } + + // restripe table + $('table.nodequeue-dragdrop tbody tr:not(:hidden)') + .filter(':odd') //.filter('.odd') + .removeClass('odd').addClass('even') + .end() + .filter(':even') + .removeClass('even').addClass('odd') + .end(); + + return false; + }); +}; + +Drupal.behaviors.nodeQueueShuffle = function(context) { + var changed = false; + + $('#edit-shuffle').click(function(){ + // randomize table rows... + rows = $('table.nodequeue-dragdrop tbody tr:not(:hidden)').get(); + rows.sort(function(){return (Math.round(Math.random())-0.5);}); + $.each(rows, function(i, row) { + $('.nodequeue-dragdrop tbody').prepend(this); + }); + + // ...and update node positions + var size = $('.node-position').size(); + $('.node-position').each(function(i){ + var val = $(this).val(); + $(this).val(size); + size--; + }); + + if (changed == false) { + $(Drupal.theme('tableDragChangedWarning')).insertAfter('#nodequeue-dragdrop-1-1').hide().fadeIn('slow'); + changed = true; + } + + // restripe table + $('table.nodequeue-dragdrop tbody tr:not(:hidden)') + .filter(':odd') //.filter('.odd') + .removeClass('odd').addClass('even') + .end() + .filter(':even') + .removeClass('even').addClass('odd') + .end(); + + return false; + }); +}; + +Drupal.behaviors.nodeQueueRemoveNode = function(context) { $('a.nodequeue-remove').css("display", "block"); $('a.nodequeue-remove').click(function() { a = $(this).attr('id'); @@ -17,4 +90,4 @@ $(document).ready(function() { .removeClass('even').addClass('odd'); return false; }); -}); \ No newline at end of file +}