cms/drupal/includes/pager.inc
changeset 541 e756a8c72c3d
equal deleted inserted replaced
540:07239de796bb 541:e756a8c72c3d
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * @file
       
     5  * Functions to aid in presenting database results as a set of pages.
       
     6  */
       
     7 
       
     8 
       
     9 /**
       
    10  * Query extender for pager queries.
       
    11  *
       
    12  * This is the "default" pager mechanism.  It creates a paged query with a fixed
       
    13  * number of entries per page.
       
    14  */
       
    15 class PagerDefault extends SelectQueryExtender {
       
    16 
       
    17   /**
       
    18    * The highest element we've autogenerated so far.
       
    19    *
       
    20    * @var int
       
    21    */
       
    22   static $maxElement = 0;
       
    23 
       
    24   /**
       
    25    * The number of elements per page to allow.
       
    26    *
       
    27    * @var int
       
    28    */
       
    29   protected $limit = 10;
       
    30 
       
    31   /**
       
    32    * The unique ID of this pager on this page.
       
    33    *
       
    34    * @var int
       
    35    */
       
    36   protected $element = NULL;
       
    37 
       
    38   /**
       
    39    * The count query that will be used for this pager.
       
    40    *
       
    41    * @var SelectQueryInterface
       
    42    */
       
    43   protected $customCountQuery = FALSE;
       
    44 
       
    45   public function __construct(SelectQueryInterface $query, DatabaseConnection $connection) {
       
    46     parent::__construct($query, $connection);
       
    47 
       
    48     // Add pager tag. Do this here to ensure that it is always added before
       
    49     // preExecute() is called.
       
    50     $this->addTag('pager');
       
    51   }
       
    52 
       
    53   /**
       
    54    * Override the execute method.
       
    55    *
       
    56    * Before we run the query, we need to add pager-based range() instructions
       
    57    * to it.
       
    58    */
       
    59   public function execute() {
       
    60 
       
    61     // Add convenience tag to mark that this is an extended query. We have to
       
    62     // do this in the constructor to ensure that it is set before preExecute()
       
    63     // gets called.
       
    64     if (!$this->preExecute($this)) {
       
    65       return NULL;
       
    66     }
       
    67 
       
    68     // A NULL limit is the "kill switch" for pager queries.
       
    69     if (empty($this->limit)) {
       
    70       return;
       
    71     }
       
    72     $this->ensureElement();
       
    73 
       
    74     $total_items = $this->getCountQuery()->execute()->fetchField();
       
    75     $current_page = pager_default_initialize($total_items, $this->limit, $this->element);
       
    76     $this->range($current_page * $this->limit, $this->limit);
       
    77 
       
    78     // Now that we've added our pager-based range instructions, run the query normally.
       
    79     return $this->query->execute();
       
    80   }
       
    81 
       
    82   /**
       
    83    * Ensure that there is an element associated with this query.
       
    84    * If an element was not specified previously, then the value of the
       
    85    * $maxElement counter is taken, after which the counter is incremented.
       
    86    *
       
    87    * After running this method, access $this->element to get the element for this
       
    88    * query.
       
    89    */
       
    90   protected function ensureElement() {
       
    91     if (!isset($this->element)) {
       
    92       $this->element = self::$maxElement++;
       
    93     }
       
    94   }
       
    95 
       
    96   /**
       
    97    * Specify the count query object to use for this pager.
       
    98    *
       
    99    * You will rarely need to specify a count query directly.  If not specified,
       
   100    * one is generated off of the pager query itself.
       
   101    *
       
   102    * @param SelectQueryInterface $query
       
   103    *   The count query object.  It must return a single row with a single column,
       
   104    *   which is the total number of records.
       
   105    */
       
   106   public function setCountQuery(SelectQueryInterface $query) {
       
   107     $this->customCountQuery = $query;
       
   108   }
       
   109 
       
   110   /**
       
   111    * Retrieve the count query for this pager.
       
   112    *
       
   113    * The count query may be specified manually or, by default, taken from the
       
   114    * query we are extending.
       
   115    *
       
   116    * @return SelectQueryInterface
       
   117    *   A count query object.
       
   118    */
       
   119   public function getCountQuery() {
       
   120     if ($this->customCountQuery) {
       
   121       return $this->customCountQuery;
       
   122     }
       
   123     else {
       
   124       return $this->query->countQuery();
       
   125     }
       
   126   }
       
   127 
       
   128   /**
       
   129    * Specify the maximum number of elements per page for this query.
       
   130    *
       
   131    * The default if not specified is 10 items per page.
       
   132    *
       
   133    * @param $limit
       
   134    *   An integer specifying the number of elements per page.  If passed a false
       
   135    *   value (FALSE, 0, NULL), the pager is disabled.
       
   136    */
       
   137   public function limit($limit = 10) {
       
   138     $this->limit = $limit;
       
   139     return $this;
       
   140   }
       
   141 
       
   142   /**
       
   143    * Specify the element ID for this pager query.
       
   144    *
       
   145    * The element is used to differentiate different pager queries on the same
       
   146    * page so that they may be operated independently.  If you do not specify an
       
   147    * element, every pager query on the page will get a unique element.  If for
       
   148    * whatever reason you want to explicitly define an element for a given query,
       
   149    * you may do so here.
       
   150    *
       
   151    * Setting the element here also increments the static $maxElement counter,
       
   152    * which is used for determining the $element when there's none specified.
       
   153    *
       
   154    * Note that no collision detection is done when setting an element ID
       
   155    * explicitly, so it is possible for two pagers to end up using the same ID
       
   156    * if both are set explicitly.
       
   157    *
       
   158    * @param $element
       
   159    */
       
   160   public function element($element) {
       
   161     $this->element = $element;
       
   162     if ($element >= self::$maxElement) {
       
   163       self::$maxElement = $element + 1;
       
   164     }
       
   165     return $this;
       
   166   }
       
   167 }
       
   168 
       
   169 /**
       
   170  * Returns the current page being requested for display within a pager.
       
   171  *
       
   172  * @param $element
       
   173  *  An optional integer to distinguish between multiple pagers on one page.
       
   174  *
       
   175  * @return
       
   176  *  The number of the current requested page, within the pager represented by
       
   177  *  $element. This is determined from the URL query parameter $_GET['page'], or
       
   178  *  0 by default. Note that this number may differ from the actual page being
       
   179  *  displayed. For example, if a search for "example text" brings up three
       
   180  *  pages of results, but a users visits search/node/example+text?page=10, this
       
   181  *  function will return 10, even though the default pager implementation
       
   182  *  adjusts for this and still displays the third page of search results at
       
   183  *  that URL.
       
   184  *
       
   185  * @see pager_default_initialize()
       
   186  */
       
   187 function pager_find_page($element = 0) {
       
   188   $page = isset($_GET['page']) ? $_GET['page'] : '';
       
   189   $page_array = explode(',', $page);
       
   190   if (!isset($page_array[$element])) {
       
   191     $page_array[$element] = 0;
       
   192   }
       
   193   return (int) $page_array[$element];
       
   194 }
       
   195 
       
   196 /**
       
   197  * Initializes a pager for theme('pager').
       
   198  *
       
   199  * This function sets up the necessary global variables so that future calls
       
   200  * to theme('pager') will render a pager that correctly corresponds to the
       
   201  * items being displayed.
       
   202  *
       
   203  * If the items being displayed result from a database query performed using
       
   204  * Drupal's database API, and if you have control over the construction of the
       
   205  * database query, you do not need to call this function directly; instead, you
       
   206  * can simply extend the query object with the 'PagerDefault' extender before
       
   207  * executing it. For example:
       
   208  * @code
       
   209  *   $query = db_select('some_table')->extend('PagerDefault');
       
   210  * @endcode
       
   211  *
       
   212  * However, if you are using a different method for generating the items to be
       
   213  * paged through, then you should call this function in preparation.
       
   214  *
       
   215  * The following example shows how this function can be used in a page callback
       
   216  * that invokes an external datastore with an SQL-like syntax:
       
   217  * @code
       
   218  *   // First find the total number of items and initialize the pager.
       
   219  *   $where = "status = 1";
       
   220  *   $total = mymodule_select("SELECT COUNT(*) FROM data " . $where)->result();
       
   221  *   $num_per_page = variable_get('mymodule_num_per_page', 10);
       
   222  *   $page = pager_default_initialize($total, $num_per_page);
       
   223  *
       
   224  *   // Next, retrieve and display the items for the current page.
       
   225  *   $offset = $num_per_page * $page;
       
   226  *   $result = mymodule_select("SELECT * FROM data " . $where . " LIMIT %d, %d", $offset, $num_per_page)->fetchAll();
       
   227  *   $output = theme('mymodule_results', array('result' => $result));
       
   228  *
       
   229  *   // Finally, display the pager controls, and return.
       
   230  *   $output .= theme('pager');
       
   231  *   return $output;
       
   232  * @endcode
       
   233  *
       
   234  * A second example involves a page callback that invokes an external search
       
   235  * service where the total number of matching results is provided as part of
       
   236  * the returned set (so that we do not need a separate query in order to obtain
       
   237  * this information). Here, we call pager_find_page() to calculate the desired
       
   238  * offset before the search is invoked:
       
   239  * @code
       
   240  *   // Perform the query, using the requested offset from pager_find_page().
       
   241  *   // This comes from a URL parameter, so here we are assuming that the URL
       
   242  *   // parameter corresponds to an actual page of results that will exist
       
   243  *   // within the set.
       
   244  *   $page = pager_find_page();
       
   245  *   $num_per_page = variable_get('mymodule_num_per_page', 10);
       
   246  *   $offset = $num_per_page * $page;
       
   247  *   $result = mymodule_remote_search($keywords, $offset, $num_per_page);
       
   248  *
       
   249  *   // Now that we have the total number of results, initialize the pager.
       
   250  *   pager_default_initialize($result->total, $num_per_page);
       
   251  *
       
   252  *   // Display the search results.
       
   253  *   $output = theme('search_results', array('results' => $result->data, 'type' => 'remote'));
       
   254  *
       
   255  *   // Finally, display the pager controls, and return.
       
   256  *   $output .= theme('pager');
       
   257  *   return $output;
       
   258  * @endcode
       
   259  *
       
   260  * @param $total
       
   261  *  The total number of items to be paged.
       
   262  * @param $limit
       
   263  *  The number of items the calling code will display per page.
       
   264  * @param $element
       
   265  *  An optional integer to distinguish between multiple pagers on one page.
       
   266  *
       
   267  * @return
       
   268  *   The number of the current page, within the pager represented by $element.
       
   269  *   This is determined from the URL query parameter $_GET['page'], or 0 by
       
   270  *   default. However, if a page that does not correspond to the actual range
       
   271  *   of the result set was requested, this function will return the closest
       
   272  *   page actually within the result set.
       
   273  */
       
   274 function pager_default_initialize($total, $limit, $element = 0) {
       
   275   global $pager_page_array, $pager_total, $pager_total_items, $pager_limits;
       
   276 
       
   277   $page = pager_find_page($element);
       
   278 
       
   279   // We calculate the total of pages as ceil(items / limit).
       
   280   $pager_total_items[$element] = $total;
       
   281   $pager_total[$element] = ceil($pager_total_items[$element] / $limit);
       
   282   $pager_page_array[$element] = max(0, min($page, ((int) $pager_total[$element]) - 1));
       
   283   $pager_limits[$element] = $limit;
       
   284   return $pager_page_array[$element];
       
   285 }
       
   286 
       
   287 /**
       
   288  * Compose a URL query parameter array for pager links.
       
   289  *
       
   290  * @return
       
   291  *   A URL query parameter array that consists of all components of the current
       
   292  *   page request except for those pertaining to paging.
       
   293  */
       
   294 function pager_get_query_parameters() {
       
   295   $query = &drupal_static(__FUNCTION__);
       
   296   if (!isset($query)) {
       
   297     $query = drupal_get_query_parameters($_GET, array('q', 'page'));
       
   298   }
       
   299   return $query;
       
   300 }
       
   301 
       
   302 /**
       
   303  * Returns HTML for a query pager.
       
   304  *
       
   305  * Menu callbacks that display paged query results should call theme('pager') to
       
   306  * retrieve a pager control so that users can view other results. Format a list
       
   307  * of nearby pages with additional query results.
       
   308  *
       
   309  * @param $variables
       
   310  *   An associative array containing:
       
   311  *   - tags: An array of labels for the controls in the pager.
       
   312  *   - element: An optional integer to distinguish between multiple pagers on
       
   313  *     one page.
       
   314  *   - parameters: An associative array of query string parameters to append to
       
   315  *     the pager links.
       
   316  *   - quantity: The number of pages in the list.
       
   317  *
       
   318  * @ingroup themeable
       
   319  */
       
   320 function theme_pager($variables) {
       
   321   $tags = $variables['tags'];
       
   322   $element = $variables['element'];
       
   323   $parameters = $variables['parameters'];
       
   324   $quantity = $variables['quantity'];
       
   325   global $pager_page_array, $pager_total;
       
   326 
       
   327   // Calculate various markers within this pager piece:
       
   328   // Middle is used to "center" pages around the current page.
       
   329   $pager_middle = ceil($quantity / 2);
       
   330   // current is the page we are currently paged to
       
   331   $pager_current = $pager_page_array[$element] + 1;
       
   332   // first is the first page listed by this pager piece (re quantity)
       
   333   $pager_first = $pager_current - $pager_middle + 1;
       
   334   // last is the last page listed by this pager piece (re quantity)
       
   335   $pager_last = $pager_current + $quantity - $pager_middle;
       
   336   // max is the maximum page number
       
   337   $pager_max = $pager_total[$element];
       
   338   // End of marker calculations.
       
   339 
       
   340   // Prepare for generation loop.
       
   341   $i = $pager_first;
       
   342   if ($pager_last > $pager_max) {
       
   343     // Adjust "center" if at end of query.
       
   344     $i = $i + ($pager_max - $pager_last);
       
   345     $pager_last = $pager_max;
       
   346   }
       
   347   if ($i <= 0) {
       
   348     // Adjust "center" if at start of query.
       
   349     $pager_last = $pager_last + (1 - $i);
       
   350     $i = 1;
       
   351   }
       
   352   // End of generation loop preparation.
       
   353 
       
   354   $li_first = theme('pager_first', array('text' => (isset($tags[0]) ? $tags[0] : t('« first')), 'element' => $element, 'parameters' => $parameters));
       
   355   $li_previous = theme('pager_previous', array('text' => (isset($tags[1]) ? $tags[1] : t('‹ previous')), 'element' => $element, 'interval' => 1, 'parameters' => $parameters));
       
   356   $li_next = theme('pager_next', array('text' => (isset($tags[3]) ? $tags[3] : t('next ›')), 'element' => $element, 'interval' => 1, 'parameters' => $parameters));
       
   357   $li_last = theme('pager_last', array('text' => (isset($tags[4]) ? $tags[4] : t('last »')), 'element' => $element, 'parameters' => $parameters));
       
   358 
       
   359   if ($pager_total[$element] > 1) {
       
   360     if ($li_first) {
       
   361       $items[] = array(
       
   362         'class' => array('pager-first'),
       
   363         'data' => $li_first,
       
   364       );
       
   365     }
       
   366     if ($li_previous) {
       
   367       $items[] = array(
       
   368         'class' => array('pager-previous'),
       
   369         'data' => $li_previous,
       
   370       );
       
   371     }
       
   372 
       
   373     // When there is more than one page, create the pager list.
       
   374     if ($i != $pager_max) {
       
   375       if ($i > 1) {
       
   376         $items[] = array(
       
   377           'class' => array('pager-ellipsis'),
       
   378           'data' => '…',
       
   379         );
       
   380       }
       
   381       // Now generate the actual pager piece.
       
   382       for (; $i <= $pager_last && $i <= $pager_max; $i++) {
       
   383         if ($i < $pager_current) {
       
   384           $items[] = array(
       
   385             'class' => array('pager-item'),
       
   386             'data' => theme('pager_previous', array('text' => $i, 'element' => $element, 'interval' => ($pager_current - $i), 'parameters' => $parameters)),
       
   387           );
       
   388         }
       
   389         if ($i == $pager_current) {
       
   390           $items[] = array(
       
   391             'class' => array('pager-current'),
       
   392             'data' => $i,
       
   393           );
       
   394         }
       
   395         if ($i > $pager_current) {
       
   396           $items[] = array(
       
   397             'class' => array('pager-item'),
       
   398             'data' => theme('pager_next', array('text' => $i, 'element' => $element, 'interval' => ($i - $pager_current), 'parameters' => $parameters)),
       
   399           );
       
   400         }
       
   401       }
       
   402       if ($i < $pager_max) {
       
   403         $items[] = array(
       
   404           'class' => array('pager-ellipsis'),
       
   405           'data' => '…',
       
   406         );
       
   407       }
       
   408     }
       
   409     // End generation.
       
   410     if ($li_next) {
       
   411       $items[] = array(
       
   412         'class' => array('pager-next'),
       
   413         'data' => $li_next,
       
   414       );
       
   415     }
       
   416     if ($li_last) {
       
   417       $items[] = array(
       
   418         'class' => array('pager-last'),
       
   419         'data' => $li_last,
       
   420       );
       
   421     }
       
   422     return '<h2 class="element-invisible">' . t('Pages') . '</h2>' . theme('item_list', array(
       
   423       'items' => $items,
       
   424       'attributes' => array('class' => array('pager')),
       
   425     ));
       
   426   }
       
   427 }
       
   428 
       
   429 
       
   430 /**
       
   431  * @defgroup pagerpieces Pager pieces
       
   432  * @{
       
   433  * Theme functions for customizing pager elements.
       
   434  *
       
   435  * Note that you should NOT modify this file to customize your pager.
       
   436  */
       
   437 
       
   438 /**
       
   439  * Returns HTML for the "first page" link in a query pager.
       
   440  *
       
   441  * @param $variables
       
   442  *   An associative array containing:
       
   443  *   - text: The name (or image) of the link.
       
   444  *   - element: An optional integer to distinguish between multiple pagers on
       
   445  *     one page.
       
   446  *   - parameters: An associative array of query string parameters to append to
       
   447  *     the pager links.
       
   448  *
       
   449  * @ingroup themeable
       
   450  */
       
   451 function theme_pager_first($variables) {
       
   452   $text = $variables['text'];
       
   453   $element = $variables['element'];
       
   454   $parameters = $variables['parameters'];
       
   455   global $pager_page_array;
       
   456   $output = '';
       
   457 
       
   458   // If we are anywhere but the first page
       
   459   if ($pager_page_array[$element] > 0) {
       
   460     $output = theme('pager_link', array('text' => $text, 'page_new' => pager_load_array(0, $element, $pager_page_array), 'element' => $element, 'parameters' => $parameters));
       
   461   }
       
   462 
       
   463   return $output;
       
   464 }
       
   465 
       
   466 /**
       
   467  * Returns HTML for the "previous page" link in a query pager.
       
   468  *
       
   469  * @param $variables
       
   470  *   An associative array containing:
       
   471  *   - text: The name (or image) of the link.
       
   472  *   - element: An optional integer to distinguish between multiple pagers on
       
   473  *     one page.
       
   474  *   - interval: The number of pages to move backward when the link is clicked.
       
   475  *   - parameters: An associative array of query string parameters to append to
       
   476  *     the pager links.
       
   477  *
       
   478  * @ingroup themeable
       
   479  */
       
   480 function theme_pager_previous($variables) {
       
   481   $text = $variables['text'];
       
   482   $element = $variables['element'];
       
   483   $interval = $variables['interval'];
       
   484   $parameters = $variables['parameters'];
       
   485   global $pager_page_array;
       
   486   $output = '';
       
   487 
       
   488   // If we are anywhere but the first page
       
   489   if ($pager_page_array[$element] > 0) {
       
   490     $page_new = pager_load_array($pager_page_array[$element] - $interval, $element, $pager_page_array);
       
   491 
       
   492     // If the previous page is the first page, mark the link as such.
       
   493     if ($page_new[$element] == 0) {
       
   494       $output = theme('pager_first', array('text' => $text, 'element' => $element, 'parameters' => $parameters));
       
   495     }
       
   496     // The previous page is not the first page.
       
   497     else {
       
   498       $output = theme('pager_link', array('text' => $text, 'page_new' => $page_new, 'element' => $element, 'parameters' => $parameters));
       
   499     }
       
   500   }
       
   501 
       
   502   return $output;
       
   503 }
       
   504 
       
   505 /**
       
   506  * Returns HTML for the "next page" link in a query pager.
       
   507  *
       
   508  * @param $variables
       
   509  *   An associative array containing:
       
   510  *   - text: The name (or image) of the link.
       
   511  *   - element: An optional integer to distinguish between multiple pagers on
       
   512  *     one page.
       
   513  *   - interval: The number of pages to move forward when the link is clicked.
       
   514  *   - parameters: An associative array of query string parameters to append to
       
   515  *     the pager links.
       
   516  *
       
   517  * @ingroup themeable
       
   518  */
       
   519 function theme_pager_next($variables) {
       
   520   $text = $variables['text'];
       
   521   $element = $variables['element'];
       
   522   $interval = $variables['interval'];
       
   523   $parameters = $variables['parameters'];
       
   524   global $pager_page_array, $pager_total;
       
   525   $output = '';
       
   526 
       
   527   // If we are anywhere but the last page
       
   528   if ($pager_page_array[$element] < ($pager_total[$element] - 1)) {
       
   529     $page_new = pager_load_array($pager_page_array[$element] + $interval, $element, $pager_page_array);
       
   530     // If the next page is the last page, mark the link as such.
       
   531     if ($page_new[$element] == ($pager_total[$element] - 1)) {
       
   532       $output = theme('pager_last', array('text' => $text, 'element' => $element, 'parameters' => $parameters));
       
   533     }
       
   534     // The next page is not the last page.
       
   535     else {
       
   536       $output = theme('pager_link', array('text' => $text, 'page_new' => $page_new, 'element' => $element, 'parameters' => $parameters));
       
   537     }
       
   538   }
       
   539 
       
   540   return $output;
       
   541 }
       
   542 
       
   543 /**
       
   544  * Returns HTML for the "last page" link in query pager.
       
   545  *
       
   546  * @param $variables
       
   547  *   An associative array containing:
       
   548  *   - text: The name (or image) of the link.
       
   549  *   - element: An optional integer to distinguish between multiple pagers on
       
   550  *     one page.
       
   551  *   - parameters: An associative array of query string parameters to append to
       
   552  *     the pager links.
       
   553  *
       
   554  * @ingroup themeable
       
   555  */
       
   556 function theme_pager_last($variables) {
       
   557   $text = $variables['text'];
       
   558   $element = $variables['element'];
       
   559   $parameters = $variables['parameters'];
       
   560   global $pager_page_array, $pager_total;
       
   561   $output = '';
       
   562 
       
   563   // If we are anywhere but the last page
       
   564   if ($pager_page_array[$element] < ($pager_total[$element] - 1)) {
       
   565     $output = theme('pager_link', array('text' => $text, 'page_new' => pager_load_array($pager_total[$element] - 1, $element, $pager_page_array), 'element' => $element, 'parameters' => $parameters));
       
   566   }
       
   567 
       
   568   return $output;
       
   569 }
       
   570 
       
   571 
       
   572 /**
       
   573  * Returns HTML for a link to a specific query result page.
       
   574  *
       
   575  * @param $variables
       
   576  *   An associative array containing:
       
   577  *   - text: The link text. Also used to figure out the title attribute of the
       
   578  *     link, if it is not provided in $variables['attributes']['title']; in
       
   579  *     this case, $variables['text'] must be one of the standard pager link
       
   580  *     text strings that would be generated by the pager theme functions, such
       
   581  *     as a number or t('« first').
       
   582  *   - page_new: The first result to display on the linked page.
       
   583  *   - element: An optional integer to distinguish between multiple pagers on
       
   584  *     one page.
       
   585  *   - parameters: An associative array of query string parameters to append to
       
   586  *     the pager link.
       
   587  *   - attributes: An associative array of HTML attributes to apply to the
       
   588  *     pager link.
       
   589  *
       
   590  * @see theme_pager()
       
   591  *
       
   592  * @ingroup themeable
       
   593  */
       
   594 function theme_pager_link($variables) {
       
   595   $text = $variables['text'];
       
   596   $page_new = $variables['page_new'];
       
   597   $element = $variables['element'];
       
   598   $parameters = $variables['parameters'];
       
   599   $attributes = $variables['attributes'];
       
   600 
       
   601   $page = isset($_GET['page']) ? $_GET['page'] : '';
       
   602   if ($new_page = implode(',', pager_load_array($page_new[$element], $element, explode(',', $page)))) {
       
   603     $parameters['page'] = $new_page;
       
   604   }
       
   605 
       
   606   $query = array();
       
   607   if (count($parameters)) {
       
   608     $query = drupal_get_query_parameters($parameters, array());
       
   609   }
       
   610   if ($query_pager = pager_get_query_parameters()) {
       
   611     $query = array_merge($query, $query_pager);
       
   612   }
       
   613 
       
   614   // Set each pager link title
       
   615   if (!isset($attributes['title'])) {
       
   616     static $titles = NULL;
       
   617     if (!isset($titles)) {
       
   618       $titles = array(
       
   619         t('« first') => t('Go to first page'),
       
   620         t('‹ previous') => t('Go to previous page'),
       
   621         t('next ›') => t('Go to next page'),
       
   622         t('last »') => t('Go to last page'),
       
   623       );
       
   624     }
       
   625     if (isset($titles[$text])) {
       
   626       $attributes['title'] = $titles[$text];
       
   627     }
       
   628     elseif (is_numeric($text)) {
       
   629       $attributes['title'] = t('Go to page @number', array('@number' => $text));
       
   630     }
       
   631   }
       
   632 
       
   633   // @todo l() cannot be used here, since it adds an 'active' class based on the
       
   634   //   path only (which is always the current path for pager links). Apparently,
       
   635   //   none of the pager links is active at any time - but it should still be
       
   636   //   possible to use l() here.
       
   637   // @see http://drupal.org/node/1410574
       
   638   $attributes['href'] = url($_GET['q'], array('query' => $query));
       
   639   return '<a' . drupal_attributes($attributes) . '>' . check_plain($text) . '</a>';
       
   640 }
       
   641 
       
   642 /**
       
   643  * @} End of "Pager pieces".
       
   644  */
       
   645 
       
   646 /**
       
   647  * Helper function
       
   648  *
       
   649  * Copies $old_array to $new_array and sets $new_array[$element] = $value
       
   650  * Fills in $new_array[0 .. $element - 1] = 0
       
   651  */
       
   652 function pager_load_array($value, $element, $old_array) {
       
   653   $new_array = $old_array;
       
   654   // Look for empty elements.
       
   655   for ($i = 0; $i < $element; $i++) {
       
   656     if (empty($new_array[$i])) {
       
   657       // Load found empty element with 0.
       
   658       $new_array[$i] = 0;
       
   659     }
       
   660   }
       
   661   // Update the changed element.
       
   662   $new_array[$element] = (int) $value;
       
   663   return $new_array;
       
   664 }