jQuery

индекс
283,92

Плагин сворачивающий каждую строку таблицы до высоты одной текcтовой строки

Добрый день, Хабрасообщество.

Недавно у моего начальства появилось желание в нашем корпоративном сайте иметь возможность, указанную в хабратопике. Первым моим желанием было внушить начальству, что «это невозможно» или «это не нужно».

Сразу оговоримся — этот топик абсолютно не затрагивает философский вопрос «а нужно ли это?». Конкретно в нашем корпоративном сайте это пригодилось и все довольны (с).

Поисковики со мной не хотели нормально общаться, но вот люди на одном из IRC серверов, где я обитаю подсказали как с помощью css и вложенного в td div-а ужать tr до 1-ой строки. За что им спасибо.

.collapsing {
height : 1em;
overflow : hidden;
}


Но оставалось еще несколько задач и проблем:
— 1em криво работало в Chrome и Safari.
— нужно было выделить те ячейки, которые не влезли в 1 строку
— ну и конечно же при клике на строку — развернуть ее (самое простое)

Как смог я эти задачи решил и в результате у меня родился плагин jquery.
Сперва живое демо. А затем сам плагин:

(function($) {
  //коллекция div с классом indicator
  var collapseСollection= $([]);
  // таймер отслеживания изменения размера window
  var resizeTimer = null;
  // отслеживаем изменение окна
  $(window).bind('resize', function() {
    if (resizeTimer) clearTimeout(resizeTimer);
    resizeTimer = setTimeout(function() {
      //обновляем стили коллекции
      updateCollapse(collapseСollection);
    }, 100);
  });

  //функция удаляет класс collapsed тем дивам, которые не влезли в одну строку, и убирает у тех, которые влезли
  function updateCollapse(collapsingElements)
  {
    if (collapsingElements)
    {
      //отсеиваем только те, которым нужно переключить класс
      collapsingElements.filter(
        function ()
        {
          var element=$(this);
          // высотой больше stringsCountTable строк и не класса collapsed или высотой stringsCountTable строк и класса collapsed
          return (element.height()>(element.data('height'))) ^ element.hasClass('collapsed');
        }
        ).
      // переключаем класс
      toggleClass('collapsed');
    }
  }

  // подгатавливает указанные талицы
  $.fn.addCollapse = function(stringsCount) {

    //пробегаемся по элементам
    $(this).each (
      function () {
        if ($(this).is('table')) {
          //число текстовых строк, до которых обрезается строка
          var stringsCountTable=stringsCount ? 1*stringsCount : 1;

          // если содержит <tbody> переключаемся на него
          var tablebody= $('tbody',this).lenght==0 ? $(this) : $('tbody',this) ;

          // следующие 3 строки после комментария вычисляют высоту 1 текстовой строки данной таблицы
          // можно было бы задаться высотой 1em, но во-первых, 1em нельзя сравнить с height() ,
          // а во-вторых, браузеры по разному отображают шрифты и высота скачет.
          // FIXME: нужно найти способ лучше
          var temp=$('<tr><td><div>A</div></td></td>').appendTo(tablebody);
          var height=temp.find('div').height();
          temp.remove();
          // переменная уникальная для каждой из таблиц - содержит развернутую строку
          var oldUnCollapse=null;
          // перебираем строки
          tablebody.children('tr:not(.trCollapsing)').
          // добавляем класс
          addClass('trCollapsing').
          // по клику на строку разворачиваем ее
          bind('click.tcollapse',
            function () {
              // получаем строку
              var element=$(this).has('.collapsed');
              // если строка содержит свернутые ячейки
              if (element.length!=0) {
                // развернута ли уже строка
                var isUnCollapsed=element.data('uncollapsed');
                // сворачиваем строку, которая уже была развернута
                if (oldUnCollapse) {
                  oldUnCollapse.addClass('trCollapsing').data('uncollapsed','').find('.collapsing').height(stringsCountTable*height);
                }
                // строка еще не развернута
                if (!isUnCollapsed){
                  // разворачиваем строку путем удаления класса trCollapsing и снятием height у свернутых дивов
                  element.data('uncollapsed',true).removeClass('trCollapsing').find('.collapsing').height('');
                  // сохраняем строку
                  oldUnCollapse = element;
                }
              }
            }
            ).
          // берем все ячейки ( не берем th )
          children('td').
          each(
            function ()
            {
              // вставляем два div внутрь каждой ячейки:
              // первый div с помощью класса collapsing и свойства height обрезается до высоты в stringsCountTable текстовых строк
              // второй div не обрезается и служит в дальнейшем индикатором высоты - его высоту сравниваем с высотой stringsCountTable текстовых строк в функции updateCollapse
              $(this).html( "<div class='collapsing' style='height:"+(stringsCountTable*height)+"px;'><div class='indicator'>"+ $(this).html() + "</div></div>");
            }
            );
          // добавляем к коллекции новые элементы
          collapseСollection = collapseСollection.
          add($('.indicator',this).
            // также указываем им данные о высоте, чтобы ускорить работу функции updateCollapse
            data('height',1*stringsCountTable*height));
        }
      }
      );

    updateCollapse(collapseСollection);

    return this;

  };

  // удаляет таблицу из управляемых плагином
  $.fn.removeCollapse = function() {
    //пробегаемся по элементам
    $(this).each (
      function () {
        if ($(this).is('table')) {
          // ищем все строки, управляемые плагином
          $('.trCollapsing',this).
          removeClass('trCollapsing').
          unbind('click.tcollapse').
          children('td').
          each(
            function()
            {
              //удаляем вспомогательные div
              $(this).html($('.indicator',this).html());
            }
            );
        }
      }
      );
  };

})(jQuery);


* This source code was highlighted with Source Code Highlighter.


и стили к нему:
.tr_collapsing .collapsing {
overflow : hidden;
}

.tr_collapsing .collapsed {
background-color: #ddd;
cursor: s-resize;
}


Последний класс .collapsed отвечает за внешний вид тех ячеек, которые не влезли в 1 текстовую строчку. Его можно настраивать как душе угодно.

Плагин старался делать более универсальным (что делалось парой костылей — увы). Но требования все-равно жесткие:
-Высота строк во всей таблице должна быть одинакова.
-Не учитываются элементы в таблице, которые могут быть выше по высоте, чем простой текст (например изображения или же текст с другой высотой)
Количество обрабатываемых плагином таблиц на странице неограниченно:

$().ready(function() {
        $('#table0,#table1').addCollapse();
        $('#table2').addCollapse();
      } );


* This source code was highlighted with Source Code Highlighter.


Тестировалось на версии jquery 1.4.1 и браузерах:
Windows: IE8, Chrome 4.0, Opera 10.10, Firefox 3.6, Safari 4.0.3
Mac OS: Chrome 5.0 dev, Opera 10.10, Firefox 3.6, Safari 4.0.4

Скачать:
>Смотри апдейт номер 3.<

Если ХОТЬ кому-то плагин пригодится очень хорошо, но лучше если вы меня пожурите и укажете на косяки — это будет полезно для меня.

UPD.1:
-Добавлена опция strings_count в метод addCollapse, задающая количество текстовых строк, до высоты которых будут сжиматься строки таблиц.
-Добавлен метод removeCollapse(), убирающий таблицу из под контроля плагина
-Добавлена «защита от дурака», когда addCollapse вызывается для какой-либо таблицы повторно.

UPD2:
-Исправлен баг, когда при клике на развернутую строку она сворачивалась и разворачивалась.
-Добавлено сворачивание развернутой строки по клику на нее
-Небольшая правка нотаций

UPD3:
У плагина появился свой сайт: irker.net/tCollapse/
Также выпущена новая версия, подробнее в этом хабратопике
+42
31 января 2010, 18:30
83

комментарии (26)

+2
Kastrulya0001 #
Почему-то не работает выделение таблицы, больше одной ячейки.
0
Irker #
Спасибо, есть такое. Буду думать. Баг критичный, хотя если развернуть нужную строку — ее содержимое можно скопировать.
0
Tiradoir #
Присоединяюсь.Баг имеет место.
0
Irker #
У вас Firefox? Я баг наблюдаю только в нем. если так, то буду копать в эту сторону.
0
Kastrulya0001 #
Да. В Хроме 4.0.249.78 и в ИЕ 6 выделяется и при клике раздвигается строчка, если текст не весь отображается.
+2
Blah #
Копать там нечего. Содержимое любого блочного элемента с overflow:hidden; будет себя так вести.
+6
habraname #
первым желанием было, конечно, спросить состав веществ ;)
+4
Galchenkov #
Сочетание горбатой нотации c «через подчёркивание» — удручает.
–8
mitrichlab #
Да ладно цепляться :)
Есть куча программеров которые об этом не задумываются, но делают что то стоящее.
+2
Irker #
Не спорю, но желание поделиться пересилило.
0
Galchenkov #
Да пример, собственно, полезный. Спасибо.

П.С. Для меня странно использовать и то и то. Поэтому бросилось в глаза. Никаких проблем. Захочу использовать — воспользуюсь рефакторингом. Благо он сейчас очень хорошо развит в IDE. Да и кода не так много.
0
deniamnet #
«нужна мыла ума нужна она раму мыла мне» :) прикольные примеры
+1
witzawitz #
Предусмотрено ли обратное сворачивание ячеек по клику? Имеются в виду, естественно, только строки с ячейками высотой больше одной текстовой строки.
0
Irker #
Пока не предусмотрено. Сворачивается только когда разворачивают другую строку.
Большого смысла не вижу, но это не будет лишним. Спасибо.
Добавлю как только наберется критическая масса для обновления.
+3
codemorgan #
О. Отлично… спасибо. есть идея как это заюзать для моей CMS и компонента DataGrid.
–3
codemorgan #
Жаль что кармы не хватает. добавил бы плюсик
+12
Azmorf #
Да уж, демо-пример довольно психоделичен…
НЛО прилетело и опубликовало эту надпись здесь
+1
timokhin #
психодел — у меня голова закружилась
0
nagato #
по моему, если в таблице было больше одного столбца, то A нарушит ее структуру :)
0
cream_brule #
что-то применения плагину не могу придумать
0
piumosso #
А вы можете дать ссылку на живой пример?
0
piumosso #
Ой, сорри, пропустил ссылку)) такая она незаметная!
0
tsx #
А я бы вставил троеточие в конце у сокращенных ячеек, а то совершенно неочевидно что серые ячейки содержат еще текст и нужно кликнуть чтобы развернуть.
0
Irker #
«Последний класс .collapsed отвечает за внешний вид тех ячеек, которые не влезли в 1 текстовую строчку. Его можно настраивать как душе угодно. „
0
Irker #
Хотя, если решусь выложить плагин на jquery.com, то в любом случае буду переделывать внешний вид.

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