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

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

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


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


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


    Ниже привожу вариант своего решения этих недочетов (для Drupal 6.x)



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

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

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

    P.S. Не забудьте заменить yourthemename на название вашей темы в названии функции и в параметре функции drupal_add_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'));
     }
    }


    * This source code was highlighted with Source Code Highlighter.



    Код файла jquery.paginatior.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();
      
     });
    }


    * This source code was highlighted with Source Code Highlighter.

    Поделиться публикацией

    Похожие публикации

    Комментарии 54
      +1
      Спасибо!
      Хотел реализовать что-то похожее, да все руки не доходили.
        +1
        Версию Друпала бы указали что ли :)
          +5
          D 6.x
          Добавил к статье, спасибо за замечание.
          +2
          Кому на XSLT очень похожее решение надо? Сам XSL.
            +2
            Кажется я не туда пишу. :) Это же друпаловкий журнал…
              +1
              Скорее, автор ошибся темой — проблема не чисто друпаловская, а юзабилити. Решение для Друпала — частный случай более правильной реализации интерфейса.
              Вам отдельное спасибо за решение для э… более другой :) технологии.
              Только xsl:output наверное все же не html а xml, а то валидатор ругаться будет…
            0
            Не в тему но кто-то знает примерные сроки семерки?
              +1
              В Code Freeze уже вошли. Выпустят когда доделают, как всегда :) Точная дата пока неизвестна.
                0
                говорят, что не раньше начала следующего года выйдет релиз.
                –1
                Во-первых, ссылка на последнюю страницу стала бы более информативна и занимала бы меньше места, если её заменить на номер последней страницы [28].


                А зачем вам делать ссылку на последнюю страницу меньше?
                Есть такой закон Фитса, он говорит о том, что чем больше и ближе цель, тем быстрее и проще по ней кликнуть мышкой.

                Т.е. то, что в Друпале самые часто нажимаемые кнопки постраничной навигации сделали больще — забота о пользователях.
                  +2
                  Возможно, вы правы, предполагая, что ссылки «На первую» и «На последнюю» страницы являются частонажимаемыми. Хотя, если бы вы привели heatmap, это бы добавило веса вашим словам.

                  Лично для меня гораздо важнее видеть, сколько страниц всего мне предстоит пролистать. Ну а любовь к компактности — это уже исключительно лично ;)
                    0
                    как вариант решения — сделать для первой и последней страницы отдельный класс, который, напрммер, выделял бы эти страницы большим размером фоновой плашки, плюс, как вариант — сделать светленький фон у них, даже когда они — просто ссылки
                  0
                  Есть тут небольшой минус — если страниц будет очень много (порядка сотен), то надо будет очень много кликать до страницы находящейся где-нибудь в середине списка.

                  Мне кажется имеет смысл добавить крошечную формочку, где пользователь мог бы ввести номер страницы и нажав на кнопку попадал бы прямиком туда. Форму можно сделать выпадающей.

                  Знаю, что идея не нова, но порой этого часто не хватает
                    0
                    Для того, о чем вы говорите есть специальный модуль. Называется как-то вроде goto или типа того. На drupal.ru как-то проскакивал анонс модуля на главной.
                      +3
                      Если вам зачем-то понадобилось попасть на 30-ю страницу из 200 — значит с юзабилити уже проблема. Быстрый переход её не решит, а лишь облегчит мучения ;-)
                        0
                        Спорно. Порой на крупных ресурсах скапливается достаточно много информации (та же лента.ру или наш любимый Хабр) и тут уж никак не избавится от сотен (а порой и тысяч) страниц.
                          +1
                          Ну, во первых, я бы не стал так категорично утверждать что «никак».
                          А во вторых, зачем может понадобиться переход именно не 30-ю страницу? На вас снизошло озарение и вы поняли что нужный материал именно на 30-й, а не на 29-й и не на 31-й странице? :)
                            0
                            Я, например, дальше 4 страницы на хабре не захожу… И то уже 10*4 = 40 топиков очень сильно загружают голову. Ведь человека в основном интересует не все подряд, а какая-то определенная тема (наука, спорт, программирование, ...). ИМХО
                        +3
                        на мой взгляд гораздо лучше, нумерация страниц от большего к меньшему:
                        22  21  20  ...  3  2  1


                        Это для блогов, новостных порталов было бы актуально.
                        Допустим поисковик ссылается на сайт:
                        somedomain.com/content/12/
                        где 12 — номер страницы на которой найденная новость. Это справедливо для того момента когда поисковый робот проиндексировал сайт. Но вот добавились еще какие то материалы на главной, и новость по ссылке поисковика «съехала» на страницу 13 или дальше. Пользователю в этом случае придется делать поиск еще и по сайту.

                        В случае же обратной нумерации, сдвига не будет, новости будут иметь постоянный номер страницы.
                          +2
                          Полностью с вами согласен. Но это уже отдельная история )
                            +2
                            Ну здесь тоже есть проблема. На первой (последней, в вашем примере 22й) странице ведь всегда должно быть 10 записей? Тогда все остальные будут скакать со страницы на страницу. Так что это не является решением проблемы.

                            Например было 15 записей, записи с 5-15 были на странице №2. Стало 20 записей, на странице №2 теперь записи 10-20, а 5-15 перекочевали на страницу №1. Потом стало 25 и они обратно перелезли на страницу №2.

                            Как от этого избавиться, может кто знает?)
                            0
                            О, я как раз тоже только что кастомизировал пейджер друпала. Правда я делал из него то, что нарисовал мне дизайнер. Из принципиальных отличий там была ссылка «показать все», а реализована это ссылка через дополнительный display для view, в котором неограниченно кол-во объектов на страницу.
                              0
                              Мне кажется это вопрос юзабилити — _зачем_ пользователь пролистывает 20 страниц?
                              Можно ли достичь той же цели, вообще не пролистывая страницы?
                                0
                                А если пользователь ничего не ишет? А просто просматривает, например, список статей?
                                  +2
                                  30 страниц?

                                  Но даже в таком случае есть улучшения.
                                  Например, можно использовать «бесконечный скролл». Тогда взгляд не перескакивает, и контекст не теряется.
                                  Или «More» в стиле twitter, с теми же достоинствами.
                                –11
                                матерь божья!!! афигеть сколько коду нада исписать чтобы сделать такую простоую весчь в такой простой ЦМС — абалдеть я стал ненавить друмал еще больше!
                                  +5
                                  Половина листинга — комментарии, половина — js код для удобной навигации с клавиатуры. Осталось всего ничего. Можете снова любить друпал :)
                                    0
                                    Привидите пример, пожалуйста, как это реализовано в других системах. Тогда можно будет говорить о простоте. Если разобратся, не так уж все и просто в этой «весчи»…
                                      0
                                      ну как я это пишу в своих системах, где используются Quicky (он аналог Смарти)
                                      {include file=«components/paging.tpl» count=$totalCount pageNum=$page}
                                      шаблон параметризуем:
                                      {*
                                      параметры:
                                      count — общее число записей
                                      pageSize — размер страницы
                                      pageNum — текущая страница
                                      url — адрес,
                                      если адрес содержит %d то туда подставляется номер страницы, иначе используется параметр page
                                      param — параметр страницы (по дефолту «page»)
                                      show — количество показываемых страниц в навигаторе, по умолчанию 9
                                      scroll_postfix — параметр id элемента к которому прокрутить страницу
                                      *}

                                      я что хочу сказать главным образом — что задача вывода целиком решается а рамках шаблонизатора и меня удивило что тут есть php код в чистом виде
                                      0
                                      убедили! но не минусами
                                        0
                                        хотя вообще мне вот еще что не очень понятно — почему пайджингом занимается не только шаблон но и PHP код, ведь шаблону нужно дать номер текущей страницы, сколько всего постов и сколько постов на странице а остальное он должен считать сам. или theme_pager() это какой-то метод его внутреннего своего шаблонизатора? тоесть там шаблоны на PHP пишутся? а как разделяются области видимости переменных?
                                          0
                                          Drupal генерирует HTML-код стандарнтых элементов интерфейса в т.н. функциях темизации. Полный список можете найти здесь. Шаблоны — это немного другое. Шаблон можно определить для страницы, для блока, для куска страницы. А относительно мелкие атомарные элементы генерируются функциями theme_…
                                          И да, по умолчанию Drupal использует собственный движок шаблонов PHP Template. Хотя можно прицепить любой другой, Smarty тот же, например.
                                        +1
                                        хорошая статья, если бы увидел ее пару месяцев назад то реализовал бы =)
                                        у себя проблему решил наглым читом:
                                        заменил перевод «первая» «предыдущая» «следующая» «последняя» на ‹‹‹ « » ›››
                                          +1
                                          Вообще-то когда мы на второй странице то ссылок на первую 3 — 1, предыдущая, первая. А так мне ваш вариант решения нравится. Красивая ленейка получилась. Для большой линейки неплохо бы еще промежуточные точки включать т.е. находясь на 150 странице из 300, что бы были ссылки не только на 1 и 300, но и на 100 и 200 например.
                                            0
                                            Попасть на определенную страницу (или «в середину»), можно, узнав общее их число и набирая номер страницы в строке браузера, ибо друпал тут не мудрствует лукаво и предоставляет сервис вида /some-page-url?page=23
                                              0
                                              Попасть на определенную страницу (или «в середину»), можно, узнав общее их число и набирая номер страницы в строке браузера, ибо друпал тут не мудрствует лукаво и предоставляет сервис вида /some-page-url?page=23
                                                0
                                                может быть вы знаете нормальный pager для Drupal 6, а то ссылки вида ?page=0,1 смотрятся очень коряво

                                                я пытался как-то исправить данный недочет, но моих знаний не хватает — слишком много изменений нужно вносить в сам движок

                                                PS: нужны ссылки вида /uri/page/2, ну или хотя бы ?page=2, а то запятая только все портит
                                                  0
                                                  где вы там запятую нашли?
                                                  0
                                                  забыл сказать, я имел в виду модуль pager, который разбивает большую страницу (этот модуль можно найти на drupal.org)

                                                  может быть вы знаете решение, как убрать там запятую из урла?
                                                    0
                                                    вы бы хоть указали, у кого js брали ;)
                                                      –3
                                                      Я никого не хочу обидеть, но это ужасно! Неужели так еще пишут код? Я конечно не видел кода друпала, но если он такой, то даже смотреть не хочу. MVC? Отделение бизнес логики от представления? JS в переменной!!! Мне очень грустно товарищи, на дворе уже почти 2010, а пишут всё так же…
                                                        0
                                                        На счет js согласен — вынес в отдельный файл. А остальные ваши замечания не у дел.
                                                        0
                                                        Я бы выделил цифры под активной страницей более ярче, черный цвет был бы в самый раз!
                                                          0
                                                          Я бы скопировал себе на сайт, но при клике на последнюю ссылку у меня ломается дизайн. Да и JS такой в наше время некошерно писать. Про Non-intrusive Javascript слышали?
                                                            0
                                                            Могли бы пояснить, что именно и как ломается?
                                                            А насчет non-intrusive js, если вы знаете, как сделать перелистывание страниц клавишами при отключенном js — чего же вы ждете? Поделитесь с нами!
                                                            Этот кусок JS в моем проекте вынесен в общую библиотеку. Кому это нужно — без труда проделает это самостоятельно
                                                            0
                                                            может мне кто-то объяснить, зачем надо посылать пользователя на самую последнюю страницу?
                                                            тоесть зачем там ссылка на 36 страницу?
                                                              0
                                                              Чтобы узнать, откуда началась жизнь ))) Мне, например, иногда интересно посмотреть, какие были первые посты…
                                                              0
                                                              Вопрос по юзабилити.

                                                              А как переходить, например, со страницы 32 на страницу 15?
                                                                0
                                                                А зачем?

                                                                Есть отдельный модуль, который добавляет форму для перехода на конкретную страницу. Зачем забивать дефолтный код лишними елементами?
                                                                0
                                                                Не буду спорить по поводу того, как должны выглядеть ссылки в пейджере. Хочу только спросить, а drupal_add_js использовать религия не позволяет? Ведь потом люди по таким примерам будут учиться писать под друпал…
                                                                  0
                                                                  Во благо будущих поколений переписал js и вынес в отдельный файл.

                                                                  Кстати, в PHP-коде был небольшой глюк, из-за которого дублировались крайние страницы при их небольшом количестве.
                                                                  Теперь все исправлено. Если кто-то успел скопировать код до момента публикации этого комментария — рекомендую обновить.
                                                                  0
                                                                  Спасибо, давно уже искал что-то подобное.
                                                                    0
                                                                    По мне так Drupal.behaviors вместо этого что здесь написано намного удобнее.
                                                                      0
                                                                      По поводу юзабилити пейджера хочу добавить то, что правильнее было бы сделать обратный порядок, чтобы ноды не скакали с 1й страницы на 2ю и так далее. Чтобы они оставались на определённых страницах, потому что люди с поисковиков переходят по ссылкам на страницы пейджера и найти там то, что хотели не могут — это не есть хорошо.

                                                                      Я пробовал развернуть пейджер, но проблема в том, что тогда первая страница не всегда заполнена — не всегда там будет все 10 анонсов.
                                                                      За решение — спасибо. Буду использовать на своих сайтах.

                                                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                      Самое читаемое