Небольшой апгрейд постраничной навигации Drupal-a

29 октября 2009 в 22:57
Аватар пользователя Stutzer Stutzer 0 79

На мой взгляд, у стандартной постраничной навигации Друпала есть несколько недостатков.

Во-первых, ссылка на последнюю страницу стала бы более информативна и занимала бы меньше места, если её заменить на номер последней страницы [28].

Во-вторых, стоит нам перейти на вторую страницу и мы тут же видим две ссылки на первую страницу: [1] и [Первая]

Аналогичную картину мы видим с противоположной стороны навигационной линейки

Итак, привожу наглядный вариант своего решения этих недочетов:

Как вы можете видеть, ссылки на крайние страницы диапазона представлены в виде номеров, а также интегрированы в саму линейку.
Ссылки «Назад» и «Вперед» вынесены наружу и представлены в виде стрелок (но это уже мелочь, сделанная просто путем перевода интерфейса)

Кроме того, я добавил возможность пролистывать страницы с помощью клавиш Ctrl + ← и Ctrl + →
Протестировано в IE6+ FF3.5 Chrome 3.

Все, что нужно — это дописать несколько строк в файл template.php вашей темы оформления (а точнее переопределить функцию [ru-api=theme_pager]theme_pager()[/ru-api]), создать в директории темы папку js, а в ней файл jquery.paginatior.js, после чего обновить реестр тем.

UPD: Кстати, может ли быть на странице более одного пэйджера? Если да, то js-код надо бы немного переделать.

Переопределнный код функции theme_pager()

function YOURTHEMENAME_pager($tags = array(), $limit = 10, $element = 0, $parameters = array(), $quantity = 9) {
 
  global $pager_page_array, $pager_total, $theme;
 
  // Add js code for Ctrl+arrows navigation
  drupal_add_js( drupal_get_path('theme', $theme) .'/js/jquery.paginator.js' );
 
  // Calculate various markers within this pager piece:
  // Middle is used to "center" pages around the current page.
  $pager_middle = ceil($quantity / 2);
  // current is the page we are currently paged to
  $pager_current = $pager_page_array[$element] + 1;
  // first is the first page listed by this pager piece (re quantity)
  $pager_first = $pager_current - $pager_middle + 1;
  // last is the last page listed by this pager piece (re quantity)
  $pager_last = $pager_current + $quantity - $pager_middle;
  // max is the maximum page number
  $pager_max = $pager_total[$element];
  // End of marker calculations.

  // Prepare for generation loop.
  $i = $pager_first;
  if ($pager_last > $pager_max) {
    // Adjust "center" if at end of query.
    $i = $i + ($pager_max - $pager_last);
    $pager_last = $pager_max;
  }
  if ($i <= 0) {
    // Adjust "center" if at start of query.
    $pager_last = $pager_last + (1 - $i);
    $i = 1;
  }
  // End of generation loop preparation.
  $li_previous = theme('pager_previous', (isset($tags[1]) ? $tags[1] : t('previous page')), $limit, $element, 1, $parameters);
  $li_next = theme('pager_next', (isset($tags[3]) ? $tags[3] : t('next page')), $limit, $element, 1, $parameters);
 
  $li_first = theme('pager_first', 1, $limit, $element, $parameters);
  $li_last = theme('pager_last', $pager_max, $limit, $element, $parameters);
 
  // First-page link display condition
  $show_first = ( $i > 1 ) ? true : false ;
 
  if ($pager_total[$element] > 1) {
   
    if ( $li_previous ) $items[] = array( 'class' => 'pager-previous', 'data' => $li_previous );
    if ( $show_first && $li_first ) $items[] = array( 'class' => 'pager-first', 'data' => $li_first );

    // When there is more than one page, create the pager list.
    if ($i != $pager_max) {
     
      if ($i > 2) $items[] = array( 'class' => 'pager-ellipsis', 'data' => '<span>...</span>' );
     
      // Now generate the actual pager piece.
      for (; $i <= $pager_last && $i <= $pager_max; $i++) {
        if ($i < $pager_current ) $items[] = array( 'class' => 'pager-item', 'data' => theme('pager_previous', $i, $limit, $element, ($pager_current - $i), $parameters) );
        if ($i == $pager_current) $items[] = array( 'class' => 'pager-current', 'data' => '<span>' . $i . '</span>' );
        if ($i > $pager_current) $items[] = array( 'class' => 'pager-item', 'data' => theme('pager_next', $i, $limit, $element, ($i - $pager_current), $parameters) );
      }
     
      if ($i < $pager_max) $items[] = array( 'class' => 'pager-ellipsis', 'data' => '<span>...</span>' );
     
    }
   
    // Last-page link display condition
    $show_last = ( $pager_max  > ($i-1) ) ? true : false ;  
   
    // End generation.
    if ( $show_last && $li_last) $items[] = array( 'class' => 'pager-last', 'data' => $li_last );
    if ( $li_next) $items[] = array( 'class' => 'pager-next', 'data' => $li_next );
   
    return theme('item_list', $items, NULL, 'ul', array('class' => 'pager'));
  }
}

Код файла jquery.paginator.js

if (Drupal.jsEnabled) {

  paginator = function () {
   
    /**
     *  Private properties
     */

    var linkNext = null;
    var linkPrev = null;
   
    /**
     *  Private methods
     */

    var setLinks = function () {
   
      linkPrev = $("ul.pager li.pager-previous a").attr("href");
      linkNext = $("ul.pager li.pager-next a").attr("href");
     
    }
   
    var navigate = function (event) {
   
      var href = null;    
      if ( event.ctrlKey && event.keyCode == 37 ) href = linkPrev;
      if ( event.ctrlKey && event.keyCode == 39 ) href = linkNext;
      if ( href ) document.location = href;
     
    }
   
   
     /**
       *  Public methods
       */

    this.__init = function () {

      // Get next/prev hrefs
      setLinks();
     
      // Ctrl + arrow event handle
      $(document).keydown( function(event) {
        navigate(event);
      });
     
    }
   
  }
 
 
 
  $(document).ready(function(){
   
    var pageNavigation = new paginator();
    pageNavigation.__init();
   
  });
}

Комментарии

Stan.Ezersky wrote:
Отлично! Но заработало только с function phptemplate_theme_pager(.......

Спасибо, исправил. Хотя у меня и так работает.

29 октября 2009 в 23:52

Можно попробовать предложить и в ядре обновить дефаултного монстра?
Мы пофлешмобим Wink В 7 - думаю можно попытаться красоты добавить...

30 октября 2009 в 0:23

PVasili wrote:
Можно попробовать предложить и в ядре обновить дефаултного монстра?
Мы пофлешмобим Wink В 7 - думаю можно попытаться красоты добавить...

Да, я думал насчет этого. Завтра переведу на английский и запощу. Кстати, куда постить то? ))

30 октября 2009 в 0:28

PVasili wrote:
Х.м. не завелось :(

У меня в данный момент функция определена как themename_pager(), а не phptemplate_theme_pager().
Попробуйте и так и так. У Stan.Ezersky не заработало с themename_pager(), а с phptemplate_theme_pager() заработало.

Ну и реестр тем обновить не забудьте.

30 октября 2009 в 1:48

заработало, только с theme_pager
Посмотрел, как у меня определено в самом pager`e

Спасибочки Wink

p.s. в вдогонку вопрос по стилям. Как сделать также, как в Вашем примере? =Р

30 октября 2009 в 1:06

lopata24 wrote:
в вдогонку вопрос по стилям. Как сделать также, как в Вашем примере? =Р

Я думаю, вы получите больше удовольствия и пользы, если сами попытаетесь Wink

30 октября 2009 в 1:09

С темой в имени завелось Smile Классное(а главное удобное) решение.
Ещё бы строки в t() оставить как в оригинале...

30 октября 2009 в 1:10

не поверите, сам сегодня потратил не один час на это (новичек Smile ).
Выжал максимум вот так

к сожалению так и не смог и не понял как сделать
1) стрелки, как у Вас
2) активную страницу в рамке, в отличии от остальных

30 октября 2009 в 1:15

lopata24 wrote:
к сожалению так и не смог и не понял как сделать
1) стрелки, как у Вас
2) активную страницу в рамке, в отличии от остальных

Стрелки, как у нас, сделаны элементарно переводом интерфейса.
А рамки — это CSS чистой воды.

30 октября 2009 в 1:19

"lopata24" wrote:
p.s. в вдогонку вопрос по стилям. Как сделать также, как в Вашем примере? =Р
Текущая страница: .pager-current span {background: #cecece; padding: 5px 10px; }. Дальше включайте фантазию.
Вот вам пару стрелок: ← (&larr;) и → (&rarr;)

30 октября 2009 в 1:33

по ссылкам "первая" и "последняя" гораздо удобнее попадать чем по номерам, и глядя на номера ещё нужно сообразить что это за числа. есть хорошая статья эту на тему http://www.birzool.com/page-navigation/

30 октября 2009 в 8:25

Неплохо, для начала стоит предложить сие в Custom pagers

А почему бы проосто не переопределить темизацию [ru-api=theme_pager_first]theme_pager_first()[/ru-api] и соседей?

PS: ссылки у автора ведут не на API, а на страницы модулей - просьба поправить...

30 октября 2009 в 8:40

"<a href="mailto:andypost@drupal.org">andypost@drupal.org</a>" wrote:
для начала стоит предложить сие в Custom pagers
а почему не замахнутся на Шекспира ядро? Вроде родное ососбо ни на что не влияет, и красивости будет больше в 7...

30 октября 2009 в 9:37

А у меня не получилось. В каталоге с темой нет файла template.php, но есть node.tpl.php и page.tpl.php. Попробовал добавлять в оба файла код - изменений не обнаружил. И кстати что значит "обновить реестр тем"? Точнее где и как? =\ Спасибо.

30 октября 2009 в 10:25

apaden wrote:
А у меня не получилось. В каталоге с темой нет файла template.php ... И кстати что значит "обновить реестр тем"? Точнее где и как? =\ Спасибо.

Так создайте его!
Чтобы обновить реестр, надо переустановить тему в соответствующем разделе админки.

30 октября 2009 в 10:51

"Stan.Ezersky" wrote:
Вот вам пару стрелок: ← (&larr;) и → (&rarr;)

коды стрелок, то я знаю, только вот как их вставить?
если так t('&larr;')), то и отображает &larr;, вместо стрелки (

30 октября 2009 в 10:57

Немного обновлений:

  • Пофиксил баг, обнаруженный пользователем PVasili
  • Вынес JS-код в отдельный файл и переписал его в виде объекта, поскольку эстеты с Хабра загнобили )
31 октября 2009 в 4:47

Неплохо!

Но я просто поставил Paginator 3000 и все мои проблемы остались в прошлом.

Впрочем, осталось понять, как вернуть на место AJAX-возможности страничного контроля.

30 октября 2009 в 12:48

Мне больше нравится пейджер яндекса (там ссылки вперед и назад рядом), но ваш тоже оптически привлекателен.

Иссу по юзабилити для 7-рки постят где-то тут: http://drupal.org/project/issues/search/drupal?version[0]=7.x&issue_tags...

Но я думаю, его пока отклонят, предоставив возможность темизаторам самостоятельно определять внешний вид пейджера.

30 октября 2009 в 12:49

Мой 6-ой осел пустые квадратики показывает.

//об этих символах: я для своих сайтов специально пытался избавиться от этого бага, указывал конкретно шрифт Courier New, но гад иногда все равно что-то свое выведет. Поэтому в конечном итоге решил в графику перегнать.

30 октября 2009 в 17:04

Насчет 7ки - еще весной была поднята тема http://www.angrydonuts.com/modernizing-the-drupal-pager-system

Нашел только http://drupal.org/node/33809 и http://drupal.org/node/173037

Походу так ни у кого и не дошли руки... а вот на www.d7ux.org вообще как-то не обсуждалось

31 октября 2009 в 0:02

Было бы чем Smile я как-то пропустил, что там с pager - знаю только, что теперь это дело сделали в слое базы данных экстендером, а вот на уровне рендера...

31 октября 2009 в 0:36
Аватар пользователя Dan Dan 0

"Stutzer" wrote:
UPD: Кстати, может ли быть на странице более одного пэйджера? Если да, то js-код надо бы немного переделать.

Да, может - у каждого свой номер, начиная с нуля.

31 октября 2009 в 12:25

Очень полезная и нужная вещь. Спасибо.

А как можно уменьшить число возможных страниц для перехода?
То есть, сейчас друпал показывает сразу 9 возможных страниц, а нужно всего три.

31 октября 2009 в 13:09

CASHMAR wrote:
А как можно уменьшить число возможных страниц для перехода?

За это отвечает параметр $quantity. Можете его явно задать непосредственно в функции, в самом начале.

31 октября 2009 в 13:21

В новой версии периодически вылезает:
warning: file_get_contents(sites/all/themes/.../js/jquery.paginator.js) [function.file-get-contents]: failed to open stream: No such file or directory in /.../includes/common.inc on line 2403.

5 ноября 2009 в 19:50

PVasili wrote:
В новой версии периодически вылезает:
warning: file_get_contents(sites/all/themes/.../js/jquery.paginator.js) [function.file-get-contents]: failed to open stream: No such file or directory in /.../includes/common.inc on line 2403.

Эм... Честно говоря идей нет.
А при каких именно действиях вылетает?
JS подгружается здесь:

// Add js code for Ctrl+arrows navigation
drupal_add_js( drupal_get_path('theme', 'YOURTHEMENAME') .'/js/jquery.paginator.js' );

Соответственно, это может произойти при смене темы, например.

UPD: Заменил
drupal_add_js( drupal_get_path('theme', 'YOURTHEMENAME') .'/js/jquery.paginator.js' );
на
drupal_add_js( drupal_get_path('theme', $theme) .'/js/jquery.paginator.js' );

6 ноября 2009 в 21:25

PVasili wrote:
В новой версии периодически вылезает:
warning: file_get_contents(sites/all/themes/.../js/jquery.paginator.js) [function.file-get-contents]: failed to open stream: No such file or directory in /.../includes/common.inc on line 2403.

У меня это вылазит и без доработок.

22 ноября 2009 в 16:18

Вылезает периодически. Путь к JS корректно указывает. Тема не меняется. В самом JS вроде нечему...
Может из-за 2 пейджеров?

А как с обратной нумерацией?

6 ноября 2009 в 13:35

PVasili wrote:
Может из-за 2 пейджеров?
А как с обратной нумерацией?

Из-за двух пэйджеров на одной странице? Вполне возможно. В такой случае JS следует подключать в page.tpl.php например
С обратной никак пока — некогда.

6 ноября 2009 в 16:05

Думал, думал над этим пейджером, решил оставить стандартный, заменив надписи на символы и поджав все css-ом.
Pager

10 ноября 2015 в 11:46

хм... у меня при всех сделанных изменениях, все равно страницы дублируется иногда, как заскриншотено на прошлой странице...
=\

24 ноября 2009 в 14:04

lopata24 wrote:
хм... у меня при всех сделанных изменениях, все равно страницы дублируется иногда, как заскриншотено на прошлой странице...
=\

Хотелост бы больше информации, поскольку у меня никаких глюков не замечено.
Скрины приветствуются.

24 ноября 2009 в 18:31

Нашел баг. На страницах где расположен проапгрейженый пейджер не работает theme developer модуля devel. Не смертельно, можно переключится на стандартную тему, но неудобно. Видимо js скрипты плохо дружат.

19 января 2010 в 22:24

А что если постраничная навигация будет висеть внизу "экрана", недвижимо или например она бы показывалась при наведении курсором вниз сайта (экрана), а не внизу страницы, когда нужно опускаться вниз и только потом уже доступна постраничная навигация, или мжб такое уже сделали?

14 июля 2011 в 3:57

Да неплохо было бы увидеть подобное решение для 7 ветки. Пытался своими силами, но пока безрезультатно...

4 января 2012 в 16:53

Код файла jquery.paginatior.js для D7

(function ($) {
        window.paginator = function() {
                var linkNext = null;
                var linkPrev = null;
                var setLinks = function () {
                        linkPrev = $("ul.pager li.pager-previous a").attr("href");
                        linkNext = $("ul.pager li.pager-next a").attr("href");
                }
                var navigate = function (event) {
                        var href = null;    
                        if ( event.ctrlKey && event.keyCode == 37 ) href = linkPrev;
                        if ( event.ctrlKey && event.keyCode == 39 ) href = linkNext;
                        if ( href ) document.location = href;
                }
                this.__init = function () {
                        setLinks();
                        $(document).keydown( function(event) {
                                navigate(event);
                        });
                }
        };
        $(document).ready(function() {
                var pageNavigation = new paginator();
                pageNavigation.__init();
        });
       
})(jQuery);

Если бы еще подсказали как выделить ссылки Следущая и Предыдущая в отдельный див, было бы вообще замечательно:

<div>
<a>Предыдущая</a>
<a>Следущая</a>
</div>
23 января 2012 в 13:55

"virbus" wrote:
выделить ссылки Следущая и Предыдущая в отдельный див

Как говориться сам вопрос задал, сам же на него и ответил:
в function YOURTHEMENAME_pager ссылки на $li_previous и $li_next добавляем в новый массив к примеру $items_link[] и в вывод добавляем новый массив:

<?phpreturn '<h2 class="element-invisible">' . t('Pages') . '</h2>' .
 theme('item_list', array(
      'items' => $items_link, 
      'attributes' => array('class' => array('link_pager')),
    )) .
 theme('item_list', array(
      'items' => $items, 
      'attributes' => array('class' => array('pager')),
    ));?>

плюс немного css и получаем

10 ноября 2015 в 11:48

допоможіть рішити цей баг, у мене стоїть D7.13 сторінки зовсім не переключаються. пробував знайти файл що за це відповідає не получається, мені здається його немає правда таке не можливо бути:((((((

23 мая 2012 в 22:23

Коллеги, а как сделать навигатор на аяксе (как в контакте)?
Как на вьюсе это реализовать я знаю, на это модуль есть)
А как превратить стандартный пейджер без использования вьюхи
в такое вот show more?)

28 мая 2012 в 21:50
Аватар пользователя Dan Dan 0

"chelwolf" wrote:
А как превратить стандартный пейджер без использования вьюхи
в такое вот show more?)

При клике на ссылку страницы - подгружать её аяксом и заменять текщий контент новым.
Как пример реализации - infinity scroll. Немного другая тема, но принцип тот же.

29 мая 2012 в 3:08

Уважаемый автор, обратите внимание на ошибку в тексте, она очень важна:

«Код файла jquery.paginatior.js»

Не jquery.paginatior.js а jquery.paginator.js

А то я название скопировал, файл создал, сделал всё как надо а не работает) Очень хитрая ошибка, при условии, что большинство копирует текст ваш а не называет файл ручками Smile

12 июля 2012 в 14:42

Для Drupal 7.

Добавил 4 строки в общем.

Добавил цифры

$li_first = theme('pager_first', array('text'=>1),$element, $parameters);
$li_last = theme('pager_last', array('text'=>$pager_max), $element, $parameters);

Добавил условие для вывода в начале и конце

$show_first = ( $i > 1 ) ? true : false ;
$show_last = ( $pager_max > ($i-1) ) ? true : false ;

Весь код ниже

function theme_pager($variables) {

  $tags = $variables['tags'];
  $element = $variables['element'];
  $parameters = $variables['parameters'];
  $quantity = $variables['quantity'];
  global $pager_page_array, $pager_total;

  // Calculate various markers within this pager piece:
  // Middle is used to "center" pages around the current page.
  $pager_middle = ceil($quantity / 2);
  // current is the page we are currently paged to
  $pager_current = $pager_page_array[$element] + 1;
  // first is the first page listed by this pager piece (re quantity)
  $pager_first = $pager_current - $pager_middle + 1;
  // last is the last page listed by this pager piece (re quantity)
  $pager_last = $pager_current + $quantity - $pager_middle;
  // max is the maximum page number
  $pager_max = $pager_total[$element];
  // End of marker calculations.

  // Prepare for generation loop.
  $i = $pager_first;
  if ($pager_last > $pager_max) {
    // Adjust "center" if at end of query.
    $i = $i + ($pager_max - $pager_last);
    $pager_last = $pager_max;
  }
  if ($i <= 0) {
    // Adjust "center" if at start of query.
    $pager_last = $pager_last + (1 - $i);
    $i = 1;
  }
  // End of generation loop preparation.

  $li_previous = theme('pager_previous', array('text' => (isset($tags[1]) ? $tags[1] : t('‹ previous')), 'element' => $element, 'interval' => 1, 'parameters' => $parameters));
  $li_next = theme('pager_next', array('text' => (isset($tags[3]) ? $tags[3] : t('next ›')), 'element' => $element, 'interval' => 1, 'parameters' => $parameters));

  //$li_first = theme('pager_first', array('text' => (isset($tags[0]) ? $tags[0] : t('« first')), 'element' => $element, 'parameters' => $parameters));
  //$li_last = theme('pager_last', array('text' => (isset($tags[4]) ? $tags[4] : t('last »')), 'element' => $element, 'parameters' => $parameters));
  $li_first = theme('pager_first', array('text'=>1),$element, $parameters);
  $li_last = theme('pager_last', array('text'=>$pager_max), $element, $parameters);

    if ($li_previous) {
      $items[] = array(
        'class' => array('pager-previous'),
        'data' => $li_previous,
      );
    }

   if ($pager_total[$element] > 1) {
        $show_first = ( $i > 1 ) ? true : false ;
    if ($show_first && $li_first) {
      $items[] = array(
        'class' => array('pager-first'),
        'data' => $li_first,
      );
    }

    // When there is more than one page, create the pager list.
    if ($i != $pager_max) {
      if ($i > 1) {
        $items[] = array(
          'class' => array('pager-ellipsis'),
          'data' => '…',
        );
      }
      // Now generate the actual pager piece.
      for (; $i <= $pager_last && $i <= $pager_max; $i++) {

        if ($i < $pager_current) {
          $items[] = array(
            'class' => array('pager-item'),
            'data' => theme('pager_previous', array('text' => $i, 'element' => $element, 'interval' => ($pager_current - $i), 'parameters' => $parameters)),
          );
        }
        if ($i == $pager_current) {
          $items[] = array(
            'class' => array('pager-current'),
            'data' => '<span>'.$i.'</span>',
          );
        }
        if ($i > $pager_current) {
          $items[] = array(
            'class' => array('pager-item'),
            'data' => theme('pager_next', array('text' => $i, 'element' => $element, 'interval' => ($i - $pager_current), 'parameters' => $parameters)),
          );
        }
      }

      if ($i < $pager_max) {
          $items[] = array(
          'class' => array('pager-ellipsis'),
          'data' => '…',
        );
      }
    }
    // End generation.

    $show_last = ( $pager_max > ($i-1) ) ? true : false ;
    if ($show_last && $li_last) {
      $end = $pager_max;
      $items[] = array(
        'class' => array('pager-last'),
        'data' => $li_last,
      );
    }

    if ($li_next) {
      $items[] = array(
        'class' => array('pager-next'),
        'data' => $li_next,
      );
    }

    return '<h2 class="element-invisible">' . t('Pages') . '</h2>' . theme('item_list', array(
      'items' => $items,
      'attributes' => array('class' => array('pager')),
    ));
  }
}

21 мая 2013 в 23:52

Как сделать что бы комментарии тоже подцепляли этот вывод страниц??? А то только на вьюхи распространяется.

Для варианта 6 друпала там и на комменты распространялось.

4 июня 2013 в 12:21