? .bzr ? 503452-retool-export.patch ? 586668-pluggable-pagers.patch ? 622608-attachment-inherit-pager_0_0.patch ? 630194-plugin-option-definition.patch ? alternatively-just-fix-the-help-text.patch ? compile_field.patch ? exposed-form-plugin-full.patch ? exposed-form-plugin.patch ? exposed-form-plugin2.patch ? exposed-forms-pre_execute-nevel-called.patch ? hack-views-module-2.txt ? retool-export.patch ? views-exposed-forms-form-alter_0.patch ? views-get-view-result.patch ? views-option_definition.patch ? views-paggers-pluggable_0.patch ? views-pluggable-exposed-forms_1.patch ? views-validate-term-cache.patch ? includes/group-by.patch Index: CHANGELOG.txt =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/CHANGELOG.txt,v retrieving revision 1.226.2.163 diff -u -p -r1.226.2.163 CHANGELOG.txt --- CHANGELOG.txt 30 Nov 2009 23:55:30 -0000 1.226.2.163 +++ CHANGELOG.txt 3 Dec 2009 01:47:12 -0000 @@ -31,6 +31,7 @@ Views 6.x-3.x-dev o #635966 by dagmar: Allow the exposed form plugin to actually control the exposed form. o #370651: Make Views AJAX work with mod_security enabled. o #614040 by dereine: Introduce hook_views_plugins_alter() + o #586668: Pagers turned into plugins to allow all kinds of new fun stuff with paging. Views 6.x-3.0-alpha1 Bugs fixed Index: handlers/views_handler_field_counter.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/handlers/views_handler_field_counter.inc,v retrieving revision 1.1.2.6 diff -u -p -r1.1.2.6 views_handler_field_counter.inc --- handlers/views_handler_field_counter.inc 9 Nov 2009 21:30:22 -0000 1.1.2.6 +++ handlers/views_handler_field_counter.inc 3 Dec 2009 01:47:12 -0000 @@ -29,10 +29,10 @@ class views_handler_field_counter extend // Note: 1 is subtracted from the counter start value below because the // counter value is incremented by 1 at the end of this function. $count = is_numeric($this->options['counter_start']) ? $this->options['counter_start'] - 1 : 0; - $pager = $this->view->pager; + $pager = $this->view->query->pager; // Get the base count of the pager. - if ($pager['use_pager']) { - $count += ($pager['items_per_page'] * $pager['current_page']) + $pager['offset']; + if ($pager->use_pager()) { + $count += ($pager->get_items_per_page() * $pager->get_current_page() + $pager->get_offset()); } // Add the counter for the current site. $count += $this->view->row_index + 1; Index: includes/plugins.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/plugins.inc,v retrieving revision 1.152.2.8 diff -u -p -r1.152.2.8 plugins.inc --- includes/plugins.inc 30 Nov 2009 23:55:30 -0000 1.152.2.8 +++ includes/plugins.inc 3 Dec 2009 01:47:12 -0000 @@ -290,6 +290,42 @@ function views_views_plugins() { 'help topic' => 'exposed-form-input-required', ), ), + 'pager' => array( + 'parent' => array( + 'no ui' => TRUE, + 'handler' => 'views_plugin_pager', + 'parent' => '', + ), + 'none' => array( + 'title' => t('Display all items'), + 'help' => t("Display all items that this view might find"), + 'handler' => 'views_plugin_pager_none', + 'help topic' => 'pager-none', + 'uses options' => TRUE, + ), + 'some' => array( + 'title' => t('Display a specified number of items'), + 'help' => t('Display a limited number items that this view might find.'), + 'handler' => 'views_plugin_pager_some', + 'help topic' => 'pager-some', + 'uses options' => TRUE, + ), + 'full' => array( + 'title' => t('Paged output, full pager'), + 'help' => t('Paged output, full Drupal style'), + 'handler' => 'views_plugin_pager_full', + 'help topic' => 'pager-full', + 'uses options' => TRUE, + ), + 'mini' => array( + 'title' => t('Paged output, mini pager'), + 'help' => t('Use the mini pager output.'), + 'handler' => 'views_plugin_pager_mini', + 'help topic' => 'pager-mini', + 'uses options' => TRUE, + 'parent' => 'full', + ), + ), ); } Index: includes/view.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/view.inc,v retrieving revision 1.151.2.22 diff -u -p -r1.151.2.22 view.inc --- includes/view.inc 26 Nov 2009 00:35:16 -0000 1.151.2.22 +++ includes/view.inc 3 Dec 2009 01:47:14 -0000 @@ -32,14 +32,8 @@ class view extends views_db_object { // Where the results of a query will go. var $result = array(); - // pager variables - var $pager = array( - 'use_pager' => FALSE, - 'items_per_page' => 10, - 'element' => 0, - 'offset' => 0, - 'current_page' => 0, - ); + // May be used to override the current page number. + var $current_page = NULL; // Places to put attached renderings: var $attachment_before = ''; @@ -93,42 +87,37 @@ class view extends views_db_object { } /** - * Set the page size for ranged or pager queries - */ - function set_items_per_page($items_per_page) { - $this->pager['items_per_page'] = $items_per_page; - if (empty($items_per_page)) { - $this->pager['use_pager'] = FALSE; - } - } - - /** * Change/Set the current page for the pager. */ function set_current_page($page) { - $this->pager['current_page'] = $page; + $this->current_page = $page; } /** - * Whether or not the pager should be used. + * Get the current page from the pager. */ - function set_use_pager($use_pager) { - $this->pager['use_pager'] = $use_pager; + function get_current_page() { + if (!empty($this->query->pager)) { + return $this->query->pager->get_current_page(); + } } /** - * The pager element id to use if use_apger is on + * Get the items per page from the pager. */ - function set_pager_element($pager_element) { - $this->pager['element'] = $pager_element; + function get_items_per_page() { + if (!empty($this->query->pager)) { + return $this->query->pager->get_items_per_page(); + } } /** - * How many records to skip. This does not function if use_pager is - * set. + * Get the pager offset from the pager. */ - function set_offset($offset) { - $this->pager['offset'] = $offset; + function get_offset() { + if (!empty($this->query->pager)) { + return $this->query->pager->get_offset(); + } } /** Index: plugins/views_plugin_cache.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/plugins/views_plugin_cache.inc,v retrieving revision 1.1.2.5 diff -u -p -r1.1.2.5 views_plugin_cache.inc --- plugins/views_plugin_cache.inc 13 Nov 2009 22:07:54 -0000 1.1.2.5 +++ plugins/views_plugin_cache.inc 3 Dec 2009 01:47:14 -0000 @@ -68,7 +68,7 @@ class views_plugin_cache extends views_p $data = array( 'result' => $this->view->result, 'total_rows' => $this->view->total_rows, - 'pager' => $this->view->pager, + 'current_page' => $this->view->get_current_page(), ); cache_set($this->get_results_key(), $data, $this->table); break; @@ -94,12 +94,12 @@ class views_plugin_cache extends views_p return FALSE; case 'results': // Values to set: $view->result, $view->total_rows, $view->execute_time, - // $view->pager['current_page']. + // $view->current_page. if ($cache = cache_get($this->get_results_key(), $this->table)) { if (!$cutoff || $cache->created > $cutoff) { $this->view->result = $cache->data['result']; $this->view->total_rows = $cache->data['total_rows']; - $this->view->pager = $cache->data['pager']; + $this->view->set_current_page = $cache->data['current_page']; $this->view->execute_time = 0; return TRUE; } Index: plugins/views_plugin_display.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/plugins/views_plugin_display.inc,v retrieving revision 1.20.2.19 diff -u -p -r1.20.2.19 views_plugin_display.inc --- plugins/views_plugin_display.inc 30 Nov 2009 19:05:43 -0000 1.20.2.19 +++ plugins/views_plugin_display.inc 3 Dec 2009 01:47:16 -0000 @@ -41,6 +41,35 @@ class views_plugin_display extends views } $this->unpack_options($this->options, $options); + + // Translate changed settings: + if ($this->get_option('items_per_page')) { + $type = $this->get_option('use_pager'); + $items_per_page = $this->get_option('items_per_page'); + if (!$type) { + $type = $items_per_page ? 'some' : 'none'; + } + + if ($type == 1) { + $type = 'full'; + } + + $pager = array( + 'type' => $type, + 'options' => array( + 'offset' => $this->get_option('offset'), + ), + ); + + if ($items_per_page) { + $pager['options']['items_per_page'] = $items_per_page; + } + if ($id = $this->get_option('pager_element')) { + $pager['options']['id'] = $id; + } + + $this->set_option('pager', $pager); + } } function destroy() { @@ -113,17 +142,10 @@ class views_plugin_display extends views * Does the display have a pager enabled? */ function use_pager() { - if (!empty($this->definition['use pager'])) { - return $this->get_option('use_pager'); + $pager = $this->get_plugin('pager'); + if ($pager) { + return $pager->use_pager(); } - return FALSE; - } - - /** - * Does the display render the pager if it has it enabled? - */ - function render_pager() { - return $this->use_pager(); } /** @@ -189,7 +211,7 @@ class views_plugin_display extends views 'empty' => array('empty', 'empty_format'), 'use_ajax' => array('use_ajax'), 'items_per_page' => array('items_per_page', 'offset', 'use_pager', 'pager_element'), - 'use_pager' => array('items_per_page', 'offset', 'use_pager', 'pager_element'), + 'pager' => array('pager'), 'use_more' => array('use_more', 'use_more_always', 'use_more_text'), 'link_display' => array('link_display'), 'distinct' => array('distinct'), @@ -262,8 +284,7 @@ class views_plugin_display extends views 'use_ajax' => TRUE, 'items_per_page' => TRUE, 'offset' => TRUE, - 'use_pager' => TRUE, - 'pager_element' => TRUE, + 'pager' => TRUE, 'use_more' => TRUE, 'use_more_always' => TRUE, 'use_more_text' => TRUE, @@ -329,13 +350,6 @@ class views_plugin_display extends views 'offset' => array( 'default' => 0, ), - 'use_pager' => array( - 'default' => FALSE, - 'bool' => TRUE, - ), - 'pager_element' => array( - 'default' => 0, - ), 'use_more' => array( 'default' => FALSE, 'bool' => TRUE, @@ -384,6 +398,12 @@ class views_plugin_display extends views 'options' => array('default' => array(), 'export' => FALSE), ), ), + 'pager' => array( + 'contains' => array( + 'type' => array('default' => 'none', 'export' => 'export_plugin'), + 'options' => array('default' => array(), 'export' => FALSE), + ), + ), // Note that the styles have their options completely independent. // Like access and cache above, this is a legacy pattern and @@ -544,35 +564,42 @@ class views_plugin_display extends views * Get the display or row plugin, if it exists. */ function get_plugin($type = 'style', $name = NULL) { - switch ($type) { - case 'style': - case 'row': - $option_name = $type . '_plugin'; - $options = $this->get_option($type . '_options'); - if (!$name) { - $name = $this->get_option($option_name); - } + static $cache = array(); + if (!isset($cache[$type][$name])) { + switch ($type) { + case 'style': + case 'row': + $option_name = $type . '_plugin'; + $options = $this->get_option($type . '_options'); + if (!$name) { + $name = $this->get_option($option_name); + } - break; - default: - $option_name = $type; - $options = $this->get_option($type); - if (!$name) { - $name = $options['type']; - } + break; + default: + $option_name = $type; + $options = $this->get_option($type); + if (!$name) { + $name = $options['type']; + } - // access & cache store their options as siblings with the - // type; all others use an 'options' array. - if ($type != 'access' && $type != 'cache') { - $options = $options['options']; - } - } + // access & cache store their options as siblings with the + // type; all others use an 'options' array. + if ($type != 'access' && $type != 'cache') { + $options = $options['options']; + } + } + + $plugin = views_get_plugin($type, $name); + if (!$plugin) { + return; + } - $plugin = views_get_plugin($type, $name); - if ($plugin) { $plugin->init($this->view, $this->display, $options); - return $plugin; + $cache[$type][$name] = $plugin; } + + return $cache[$type][$name]; } /** @@ -755,21 +782,26 @@ class views_plugin_display extends views } if (!empty($this->definition['use pager'])) { - $options['use_pager'] = array( + + $pager_plugin = $this->get_plugin('pager'); + if (!$pager_plugin) { + // default to the no pager plugin. + $pager_plugin = views_get_plugin('pager', 'none'); + } + + $pager_str = $pager_plugin->summary_title(); + + $options['pager'] = array( 'category' => 'basic', 'title' => t('Use pager'), - 'value' => $this->get_option('use_pager') ? ($this->get_option('use_pager') === 'mini' ? t('Mini') : t('Yes')) : t('No'), + 'value' => $pager_str, 'desc' => t("Change this display's pager setting."), ); } - $items = intval($this->get_option('items_per_page')); - $options['items_per_page'] = array( - 'category' => 'basic', - 'title' => $this->use_pager() ? t('Items per page') : t('Items to display'), - 'value' => $items ? $items : t('Unlimited'), - 'desc' => t('Change how many items to display.'), - ); + if (!empty($pager_plugin->definition['uses options'])) { + $options['pager']['links']['pager_options'] = t('Change settings for this pager type.'); + } if (!empty($this->definition['use more'])) { $options['use_more'] = array( @@ -835,6 +867,10 @@ class views_plugin_display extends views $options['cache']['links']['cache_options'] = t('Change settings for this caching type.'); } + if (!empty($access_plugin->definition['uses options'])) { + $options['access']['links']['access_options'] = t('Change settings for this access type.'); + } + if ($this->uses_link_display()) { // Only show the 'link display' if there is more than one option. $count = 0; @@ -971,35 +1007,6 @@ class views_plugin_display extends views '#default_value' => $this->get_option('use_ajax') ? 1 : 0, ); break; - case 'use_pager': - $form['#title'] .= t('Use a pager for this view'); - $form['use_pager'] = array( - '#type' => 'radios', - '#options' => array(TRUE => t('Full pager'), 'mini' => t('Mini pager'), 0 => t('No')), - '#default_value' => $this->get_option('use_pager'), - ); - $form['pager_element'] = array( - '#type' => 'textfield', - '#title' => t('Pager element'), - '#description' => t("Unless you're experiencing problems with pagers related to this view, you should leave this at 0. If using multiple pagers on one page you may need to set this number to a higher value so as not to conflict within the ?page= array. Large values will add a lot of commas to your URLs, so avoid if possible."), - '#default_value' => intval($this->get_option('pager_element')), - ); - break; - case 'items_per_page': - $form['#title'] .= $this->use_pager() ? t('Items per page') : t('Items to display'); - - $form['items_per_page'] = array( - '#type' => 'textfield', - '#description' => t('The number of items to display per page. Enter 0 for no limit.'), - '#default_value' => intval($this->get_option('items_per_page')), - ); - $form['offset'] = array( - '#type' => 'textfield', - '#title' => t('Offset'), - '#description' => t('The number of items to skip. For example, if this field is 3, the first 3 items will be skipped and not displayed. Offset can not be used if items to display is 0; instead use a very large number there.'), - '#default_value' => intval($this->get_option('offset')), - ); - break; case 'use_more': $form['#title'] .= t('Add a more link to the bottom of the display.'); $form['use_more'] = array( @@ -1508,7 +1515,45 @@ class views_plugin_display extends views $plugin->options_form($form['exposed_form_options'], $form_state); } break; + case 'pager': + $form['#title'] .= t('Select which pager, if any, to use for this view'); + $form['pager'] = array( + '#prefix' => '
', + '#suffix' => '
', + '#tree' => TRUE, + ); + + $pager = $this->get_option('pager'); + $form['pager']['type'] = array( + '#type' => 'radios', + '#options' => views_fetch_plugin_names('pager'), + '#default_value' => $pager['type'], + ); + + $pager_plugin = views_fetch_plugin_data('pager', $pager['type']); + if (!empty($pager_plugin['uses options'])) { + $form['markup'] = array( + '#prefix' => '
', + '#suffix' => '
', + '#value' => t('You may also adjust the !settings for the currently selected pager by clicking on the icon.', array('!settings' => $this->option_link(t('settings'), 'pager_options'))), + ); + } + + break; + case 'pager_options': + $plugin = $this->get_plugin('pager'); + $form['#title'] .= t('Pager options'); + if ($plugin) { + $form['#help_topic'] = $plugin->definition['help topic']; + + $form['pager_options'] = array( + '#tree' => TRUE, + ); + $plugin->options_form($form['pager_options'], $form_state); + } + break; } + } /** @@ -1580,6 +1625,12 @@ class views_plugin_display extends views $plugin->options_validate($form['exposed_form_options'], $form_state); } break; + case 'pager_options': + $plugin = $this->get_plugin('pager'); + if ($plugin) { + $plugin->options_validate($form['pager_options'], $form_state); + } + break; } } @@ -1645,17 +1696,6 @@ class views_plugin_display extends views case 'link_display': $this->set_option($section, $form_state['values'][$section]); break; - case 'use_ajax': - $this->set_option($section, (bool)$form_state['values'][$section]); - break; - case 'use_pager': - $this->set_option($section, $form_state['values'][$section]); - $this->set_option('pager_element', intval($form_state['values']['pager_element'])); - break; - case 'items_per_page': - $this->set_option($section, intval($form_state['values'][$section])); - $this->set_option('offset', intval($form_state['values']['offset'])); - break; case 'use_more': $this->set_option($section, intval($form_state['values'][$section])); $this->set_option('use_more_always', intval($form_state['values']['use_more_always'])); @@ -1742,6 +1782,33 @@ class views_plugin_display extends views $this->set_option('exposed_form', $exposed_form); } break; + case 'pager': + $pager = $this->get_option('pager'); + if ($pager['type'] != $form_state['values']['pager']['type']) { + $plugin = views_get_plugin('pager', $form_state['values']['pager']['type']); + if ($plugin) { + // Because pagers have very similar options, let's allow pagers to + // try to carry the options over. + $plugin->init($this->view, $this->display, $pager['options']); + + $pager = array('type' => $form_state['values']['pager']['type'], 'options' => $plugin->options); + $this->set_option('pager', $pager); + if (!empty($plugin->definition['uses options'])) { + views_ui_add_form_to_stack('display', $this->view, $this->display->id, array('pager_options')); + } + } + } + + break; + case 'pager_options': + $plugin = $this->get_plugin('pager'); + if ($plugin) { + $pager = $this->get_option('pager'); + $plugin->options_submit($form['pager_options'], $form_state); + $pager['options'] = $form_state['values'][$section]; + $this->set_option('pager', $pager); + } + break; } } @@ -1845,7 +1912,7 @@ class views_plugin_display extends views * Render the 'more' link */ function render_more_link() { - if ($this->use_more() && ($this->view->total_rows > $this->view->pager['items_per_page'] || $this->use_more_always())) { + if ($this->use_more() && ($this->use_more_always() || $this->view->query->pager->has_more_records())) { $path = $this->get_path(); if ($path) { $path = $this->view->get_url(NULL, $path); @@ -1953,11 +2020,6 @@ class views_plugin_display extends views */ function pre_execute() { $this->view->set_use_ajax($this->use_ajax()); - // Copy pager information from the display. - $this->view->set_use_pager($this->use_pager()); - $this->view->set_pager_element($this->get_option('pager_element')); - $this->view->set_items_per_page($this->get_option('items_per_page')); - $this->view->set_offset($this->get_option('offset')); if ($this->use_more()) { $this->view->get_total_rows = TRUE; } Index: plugins/views_plugin_exposed_form.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/plugins/Attic/views_plugin_exposed_form.inc,v retrieving revision 1.1.2.3 diff -u -p -r1.1.2.3 views_plugin_exposed_form.inc --- plugins/views_plugin_exposed_form.inc 30 Nov 2009 21:54:19 -0000 1.1.2.3 +++ plugins/views_plugin_exposed_form.inc 3 Dec 2009 01:47:16 -0000 @@ -14,12 +14,11 @@ class views_plugin_exposed_form extends * @param $display * The display handler. */ - function init(&$view, &$display) { + function init(&$view, &$display, $options = array()) { $this->view = &$view; $this->display = &$display; - $exposed_form = $display->handler->get_option('exposed_form'); - $this->unpack_options($this->options, $exposed_form['options']); + $this->unpack_options($this->options, $options); } /** @@ -92,9 +91,9 @@ class views_plugin_exposed_form extends function pre_execute() { } function exposed_form_alter(&$form, &$form_state) { } - + function exposed_form_validate(&$form, &$form_state) { } - + /** * This function is executed when exposed form is submited. * @@ -103,8 +102,8 @@ class views_plugin_exposed_form extends * @param $form_state * A keyed array containing the current state of the form. * @param $exclude - * Nested array of keys to exclude of insert into + * Nested array of keys to exclude of insert into * $view->exposed_raw_input - */ + */ function exposed_form_submit(&$form, &$form_state, &$exclude) { } } Index: plugins/views_plugin_pager.inc =================================================================== RCS file: plugins/views_plugin_pager.inc diff -N plugins/views_plugin_pager.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ plugins/views_plugin_pager.inc 3 Dec 2009 01:47:16 -0000 @@ -0,0 +1,173 @@ +view = &$view; + $this->display = &$display; + + $this->unpack_options($this->options, $options); + } + + /** + * Get how many items per page this pager will display. + * + * All but the leanest pagers should probably return a value here, so + * most pagers will not need to override this method. + */ + function get_items_per_page() { + return isset($this->options['items_per_page']) ? $this->options['items_per_page'] : 0; + } + + /** + * Get the page offset, or how many items to skip. + * + * Even pagers that don't actually page can skip items at the beginning, + * so few pagers will need to override this method. + */ + function get_offset() { + return isset($this->options['offset']) ? $this->options['offset'] : 0; + } + + /** + * Get the current page. + * + * If NULL, we do not know what the current page is. + */ + function get_current_page() { + return $this->current_page; + } + + /** + * Set the current page. + * + * @param $number + * If provided, the page number will be set to this. If NOT provided, + * the page number will be set from the global page array. + */ + function set_current_page($number = NULL) { + $this->current_page = $number; + } + + /** + * Get the total number of items. + * + * If NULL, we do not yet know what the total number of items are. + */ + function get_total_items() { + return $this->total_items; + } + + /** + * Provide the default form form for validating options + */ + function options_validate(&$form, &$form_state) { } + + /** + * Provide the default form form for submitting options + */ + function options_submit(&$form, &$form_state) { } + + /** + * Return a string to display as the clickable title for the + * pager plugin. + */ + function summary_title() { + return t('Unknown'); + } + + /** + * Determine if this pager actually uses a pager. + * + * Only a couple of very specific pagers will set this to false. + */ + function use_pager() { + return TRUE; + } + + /** + * Determine if a pager needs a count query. + * + * If a pager needs a count query, a simple query + */ + function use_count_query() { + return TRUE; + } + + /** + * Execute the count query, which will be done just prior to the query + * itself being executed. + */ + function execute_count_query(&$count_query, $args) { + $this->total_items = db_result(db_query($count_query, $args)); + if (!empty($this->options['offset'])) { + $this->total_items -= $this->options['offset']; + } + + $this->update_page_info(); + return $this->total_items; + } + + /** + * If there are pagers that need global values set, this method can + * be used to set them. It will be called when the count query is run. + */ + function update_page_info() { + + } + + /** + * Modify the query for paging + * + * This is called during the build phase and can directly modify the query. + */ + function query() { } + + /** + * Perform any needed actions just prior to the query executing. + */ + function pre_execute(&$query, &$args) { } + + /** + * Perform any needed actions just after the query executing. + */ + function post_execute(&$result) { } + + /** + * Render the pager. + * + * Called during the view render process, this will render the + * pager. + * + * @param $input + * Any extra GET parameters that should be retained, such as exposed + * input. + */ + function render($input) { } + + /** + * Determine if there are more records available. + * + * This is primarily used to control the display of a more link. + */ + function has_more_records() { + return $this->get_items_per_page() + && $this->total_items > (intval($this->current_page) + 1) * $this->get_items_per_page(); + } +} Index: plugins/views_plugin_pager_full.inc =================================================================== RCS file: plugins/views_plugin_pager_full.inc diff -N plugins/views_plugin_pager_full.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ plugins/views_plugin_pager_full.inc 3 Dec 2009 01:47:16 -0000 @@ -0,0 +1,117 @@ +options['offset'])) { + return format_plural($this->options['items_per_page'], 'Paged, @count item, skip @skip', 'Paged, @count items, skip @skip', array('@count' => $this->options['items_per_page'], '@skip' => $this->options['offset'])); + } + return format_plural($this->options['items_per_page'], 'Paged, @count item', 'Paged, @count items', array('@count' => $this->options['items_per_page'])); + } + + function option_definition() { + $options = parent::option_definition(); + $options['items_per_page'] = array('default' => 10); + $options['offset'] = array('default' => 0); + $options['id'] = array('default' => 0); + + return $options; + } + + /** + * Provide the default form for setting options. + */ + function options_form(&$form, &$form_state) { + $form['items_per_page'] = array( + '#title' => t('Items per page'), + '#type' => 'textfield', + '#description' => t('The number of items to display per page. Enter 0 for no limit.'), + '#default_value' => $this->options['items_per_page'], + ); + + $form['offset'] = array( + '#type' => 'textfield', + '#title' => t('Offset'), + '#description' => t('The number of items to skip. For example, if this field is 3, the first 3 items will be skipped and not displayed.'), + '#default_value' => $this->options['offset'], + ); + + $form['id'] = array( + '#type' => 'textfield', + '#title' => t('Pager ID'), + '#description' => t("Unless you're experiencing problems with pagers related to this view, you should leave this at 0. If using multiple pagers on one page you may need to set this number to a higher value so as not to conflict within the ?page= array. Large values will add a lot of commas to your URLs, so avoid if possible."), + '#default_value' => $this->options['id'], + ); + } + + function query() { + $this->view->query->set_limit($this->options['items_per_page']); + $this->view->query->set_offset($this->current_page * $this->options['items_per_page'] + $this->options['offset']); + } + + function render($input) { + $pager_theme = views_theme_functions('pager', $this->view, $this->display); + return theme($pager_theme, $input, $this->options['items_per_page'], $this->options['id']); + } + + /** + * Set the current page. + * + * @param $number + * If provided, the page number will be set to this. If NOT provided, + * the page number will be set from the global page array. + */ + function set_current_page($number = NULL) { + if (isset($number)) { + $this->current_page = $number; + return; + } + + // If the current page number was not prespecified, default to pulling it from 'page' + // based upon + global $pager_page_array; + // Extract the ['page'] info. + $pager_page_array = isset($_GET['page']) ? explode(',', $_GET['page']) : array(); + + $this->current_page = 0; + if (!empty($pager_page_array[$this->options['id']])) { + $this->current_page = intval($pager_page_array[$this->options['id']]); + } + } + + /** + * Update global paging info. + * + * This is called after the count query has been run to set the total + * items available and to update the current page if the requested + * page is out of range. + */ + function update_page_info() { + // Dump information about what we already know into the globals. + global $pager_page_array, $pager_total, $pager_total_items; + + // Set the item count for the pager. + $pager_total_items[$this->options['id']] = $this->total_items; + // Calculate and set the count of available pages. + $pager_total[$this->options['id']] = ceil($pager_total_items[$this->options['id']] / $this->get_items_per_page()); + + // See if the requested page was within range: + if ($this->current_page < 0) { + $this->current_page = 0; + } + else if ($this->current_page >= $pager_total[$this->options['id']]) { + // Pages are numbered from 0 so if there are 10 pages, the last page is 9. + $this->current_page = $pager_total[$this->options['id']] - 1; + } + + // Put this number in to guarantee that we do not generate notices when the pager + // goes to look for it later. + $pager_page_array[$this->options['id']] = $this->current_page; + } + +} Index: plugins/views_plugin_pager_mini.inc =================================================================== RCS file: plugins/views_plugin_pager_mini.inc diff -N plugins/views_plugin_pager_mini.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ plugins/views_plugin_pager_mini.inc 3 Dec 2009 01:47:16 -0000 @@ -0,0 +1,21 @@ +options['offset'])) { + return format_plural($this->options['items_per_page'], 'Mini pager, @count item, skip @skip', 'Mini pager, @count items, skip @skip', array('@count' => $this->options['items_per_page'], '@skip' => $this->options['offset'])); + } + return format_plural($this->options['items_per_page'], 'Mini pager, @count item', 'Mini pager, @count items', array('@count' => $this->options['items_per_page'])); + } + + function render($input) { + $pager_theme = views_theme_functions('views_mini_pager', $this->view, $this->display); + return theme($pager_theme, $input, $this->options['items_per_page'], $this->options['id']); + } +} Index: plugins/views_plugin_pager_none.inc =================================================================== RCS file: plugins/views_plugin_pager_none.inc diff -N plugins/views_plugin_pager_none.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ plugins/views_plugin_pager_none.inc 3 Dec 2009 01:47:16 -0000 @@ -0,0 +1,62 @@ +options['offset'])) { + return t('All items, skip @skip', array('@skip' => $this->options['offset'])); + } + return t('All items'); + } + + function option_definition() { + $options = parent::option_definition(); + $options['offset'] = array('default' => 0); + + return $options; + } + + /** + * Provide the default form for setting options. + */ + function options_form(&$form, &$form_state) { + $form['offset'] = array( + '#type' => 'textfield', + '#title' => t('Offset'), + '#description' => t('The number of items to skip. For example, if this field is 3, the first 3 items will be skipped and not displayed.'), + '#default_value' => $this->options['offset'], + ); + } + + function use_pager() { + return FALSE; + } + + function use_count_query() { + return FALSE; + } + + function get_items_per_page() { + return 0; + } + + function execute_count_query(&$count_query, $args) { + // If we are displaying all items, never count. But we can update the count in post_execute. + } + + function post_execute($result) { + $this->total_items = count($result); + } + + function query() { + // The only query modifications we might do are offsets. + if (!empty($this->options['offset'])) { + $this->view->query->set_offset($this->options['offset']); + } + } +} Index: plugins/views_plugin_pager_some.inc =================================================================== RCS file: plugins/views_plugin_pager_some.inc diff -N plugins/views_plugin_pager_some.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ plugins/views_plugin_pager_some.inc 3 Dec 2009 01:47:16 -0000 @@ -0,0 +1,56 @@ +options['offset'])) { + return format_plural($this->options['items_per_page'], '@count item, skip @skip', '@count items, skip @skip', array('@count' => $this->options['items_per_page'], '@skip' => $this->options['offset'])); + } + return format_plural($this->options['items_per_page'], '@count item', '@count items', array('@count' => $this->options['items_per_page'])); + } + + function option_definition() { + $options = parent::option_definition(); + $options['items_per_page'] = array('default' => 10); + $options['offset'] = array('default' => 0); + + return $options; + } + + /** + * Provide the default form for setting options. + */ + function options_form(&$form, &$form_state) { + $form['items_per_page'] = array( + '#title' => t('Items to display'), + '#type' => 'textfield', + '#description' => t('The number of items to display per page. Enter 0 for no limit.'), + '#default_value' => $this->options['items_per_page'], + ); + + $form['offset'] = array( + '#type' => 'textfield', + '#title' => t('Offset'), + '#description' => t('The number of items to skip. For example, if this field is 3, the first 3 items will be skipped and not displayed.'), + '#default_value' => $this->options['offset'], + ); + } + + function use_pager() { + return FALSE; + } + + function use_count_query() { + return FALSE; + } + + function query() { + $this->view->query->set_limit($this->options['items_per_page']); + $this->view->query->set_offset($this->options['offset']); + } +} Index: plugins/views_plugin_query.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/plugins/Attic/views_plugin_query.inc,v retrieving revision 1.1.2.3 diff -u -p -r1.1.2.3 views_plugin_query.inc --- plugins/views_plugin_query.inc 10 Nov 2009 23:20:06 -0000 1.1.2.3 +++ plugins/views_plugin_query.inc 3 Dec 2009 01:47:16 -0000 @@ -9,6 +9,10 @@ * Object used to create a SELECT query. */ class views_plugin_query extends views_plugin { + /** + * A pager plugin that should be provided by the display. + */ + var $pager = NULL; /** * Constructor; Create the basic query object and fill with default values. @@ -57,4 +61,37 @@ class views_plugin_query extends views_p * If NULL, aggregation is not allowed. */ function get_aggregation_info() { } + + /** + * Set a LIMIT on the query, specifying a maximum number of results. + */ + function set_limit($limit) { + $this->limit = $limit; + } + + /** + * Set an OFFSET on the query, specifying a number of results to skip + */ + function set_offset($offset) { + $this->offset = $offset; + } + + function init_pager(&$view) { + // @todo -- probably this should be a method on the display rather than directly calling + // get plugin? + $this->pager = $view->display_handler->get_plugin('pager'); + } + + /** + * Render the pager, if necessary. + */ + function render_pager() { + if (!empty($this->pager) && $this->pager->use_pager()) { + $exposed_input = isset($this->view->exposed_data_raw) ? $this->view->exposed_data_raw : NULL; + return $this->pager->render($exposed_input); + } + return ''; + } + + } Index: plugins/views_plugin_query_default.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/plugins/Attic/views_plugin_query_default.inc,v retrieving revision 1.1.2.11 diff -u -p -r1.1.2.11 views_plugin_query_default.inc --- plugins/views_plugin_query_default.inc 10 Nov 2009 23:20:06 -0000 1.1.2.11 +++ plugins/views_plugin_query_default.inc 3 Dec 2009 01:47:17 -0000 @@ -1043,6 +1043,14 @@ class views_plugin_query_default extends * Builds the necessary info to execute the query. */ function build(&$view) { + $this->init_pager($view); + if ($this->pager->use_pager()) { + $this->pager->set_current_page($view->current_page); + } + + // Let the pager modify the query to add limits. + $this->pager->query(); + $view->build_info['query'] = $this->query(); $view->build_info['count_query'] = $this->query(TRUE); $view->build_info['query_args'] = $this->get_where_args(); @@ -1053,7 +1061,7 @@ class views_plugin_query_default extends * values. * * Values to set: $view->result, $view->total_rows, $view->execute_time, - * $view->pager['current_page']. + * $view->current_page. */ function execute(&$view) { $external = FALSE; // Whether this query will run against an external database. @@ -1082,55 +1090,35 @@ class views_plugin_query_default extends } $start = views_microtime(); - if (!empty($view->pager['items_per_page'])) { - // We no longer use pager_query() here because pager_query() does not - // support an offset. This is fine as we don't actually need pager - // query; we've already been doing most of what it does, and we - // just need to do a little more playing with globals. - if (!empty($view->pager['use_pager']) || !empty($view->get_total_rows)) { - $view->total_rows = db_result(db_query($count_query, $args)) - $view->pager['offset']; - } - if (!empty($view->pager['use_pager'])) { - // Dump information about what we already know into the globals. - global $pager_page_array, $pager_total, $pager_total_items; - // Set the item count for the pager. - $pager_total_items[$view->pager['element']] = $view->total_rows; - // Calculate and set the count of available pages. - $pager_total[$view->pager['element']] = ceil($pager_total_items[$view->pager['element']] / $view->pager['items_per_page']); - - // What page was requested: - $pager_page_array = isset($_GET['page']) ? explode(',', $_GET['page']) : array(); - - // If the requested page was within range. $view->pager['current_page'] - // defaults to 0 so we don't need to set it in an out-of-range condition. - if (!empty($pager_page_array[$view->pager['element']])) { - $page = intval($pager_page_array[$view->pager['element']]); - if ($page > 0 && $page < $pager_total[$view->pager['element']]) { - $view->pager['current_page'] = $page; - } - } - $pager_page_array[$view->pager['element']] = $view->pager['current_page']; - } + if ($this->pager->use_count_query() || !empty($view->get_total_rows)) { + $this->pager->execute_count_query($count_query, $args); + } - $offset = $view->pager['current_page'] * $view->pager['items_per_page'] + $view->pager['offset']; - $result = db_query_range($query, $args, $offset, $view->pager['items_per_page']); + // Let the pager modify the query to add limits. + $this->pager->pre_execute($query, $args); + + if (!empty($this->limit) || !empty($this->offset)) { + // We can't have an offset without a limit, so provide a very large limit instead. + $limit = intval(!empty($this->limit) ? $this->limit : 999999); + $offset = intval(!empty($this->offset) ? $this->offset : 0); + $result = db_query_range($query, $args, $offset, $limit); } else { $result = db_query($query, $args); } - // If we already know how many items we have even if we did not run the - // count query, go ahead and set that value: - if (empty($view->pager['items_per_page'])) { - $view->total_rows = count($result); - } - $view->result = array(); while ($item = db_fetch_object($result)) { $view->result[] = $item; } + $this->pager->post_execute($view->result); + + if ($this->pager->use_pager()) { + $view->total_rows = $this->pager->get_total_items(); + } + if ($external) { db_set_active(); } Index: theme/theme.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/theme/theme.inc,v retrieving revision 1.73.2.14 diff -u -p -r1.73.2.14 theme.inc --- theme/theme.inc 30 Nov 2009 19:05:43 -0000 1.73.2.14 +++ theme/theme.inc 3 Dec 2009 01:47:17 -0000 @@ -72,19 +72,11 @@ function template_preprocess_views_view( } $vars['more'] = $view->display_handler->render_more_link(); $vars['feed_icon'] = !empty($view->feed_icon) ? $view->feed_icon : ''; + $vars['pager'] = $view->query->render_pager(); $vars['attachment_before'] = !empty($view->attachment_before) ? $view->attachment_before : ''; $vars['attachment_after'] = !empty($view->attachment_after) ? $view->attachment_after : ''; - $vars['pager'] = ''; - - $exposed_input = isset($view->exposed_data_raw) ? $view->exposed_data_raw : NULL; - if ($view->display_handler->render_pager()) { - $pager_type = ($view->pager['use_pager'] === 'mini' ? 'views_mini_pager' : 'pager'); - $pager_theme = views_theme_functions($pager_type, $view, $view->display_handler->display); - $vars['pager'] = theme($pager_theme, $exposed_input, $view->pager['items_per_page'], $view->pager['element']); - } - // if administrator, add some links. These used to be tabs, but this is better. if (user_access('administer views') && module_exists('views_ui') && empty($view->hide_admin_links) && !variable_get('views_no_hover_links', FALSE)) { $vars['admin_links_raw'] = array(