Начало · Справочники · Курсы · Разговоры

leechy.ru · Сайт почти придуман

Делаем дерево из таблицы (часть 1)

Так плохо становится, когда надежды начинают растворятся в воздухе... я говорю по поводу стандартов, W3C, DOM и то, что я связывал с ними свое желание писать код один раз для всех браузеров. Оказывается, что единственный браузер на данный момент, который действительно поддерживает стандарты - это Mozilla (и Netscape 6). MSIE5 поддерживает многие, но не следует стандартов стриктно, Opera... Opera на мой взгляд поддерживает жизненный минимум, а только что вышедшая 5-я версия отличается от четвертой только банером.

Все это начинает всплывать только, когда начинаеш писать реальные скрипты. Один из этих скриптов - это динамическое дерево. Я в свое время писал такой скрипт (его можно найти здесь), но у него есть существенный недостаток - он построен на слоях и если не делать дизайн страницы специально под него, то есть большая вероятность, что он "налезет" на ее остальное содержание. Решение конечно есть, либо содержание, которое может попасть под деревом, тоже засунуть в слой и двигать вместе с ним, либо сделать дерево без помощи слоев. Для многих целей второй вариант гораздо предпочтительнее.

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

Задача...

Сделать дерево без помощи слоев. Дерево будет построено на базе обычных HTML-элементов (скорее всего строки таблицы).

Ясно, что дерево будет работать только в браузерах, в которых доступны свойства HTML-элементов, а это все DOM-совместимые браузеры + MSIE4. При этом браузеры, которые не умеют работать со всеми свойствами должны показывать дерево полностью раскрытое.

...и ее решение

В предыдущей статье (см. Играем в прятки) я писал о свойстве display и приводил код двух функций putElem() и removeElem(). С их помощью можно скрывать и показывать всех блочных HTML-элементов. Поэтому, логично, что сделав такую табличную строку:

<tr id="myRow"><td>Моя строка</td></tr>

сможем ее скрыть и показать используя соответственно putElem('myRow') и removeElem('myRow').

Если вы пользуетесь MSIE, то все заработало, но если у вас NN6 то вы смогли только скрыть строку, а в Опере вообще ничего не произошло. Нужно выяснить почему.

Первое, что приходит в голову, это то, что NN6 понял значение display = "none", но не понял display = "block". Почему? Ответ есть на сайте W3C — документация CSS2 The 'display' property. Оказывается, что по стандарту, значение display для строки таблицы должно быть table-row. Чтобы учесть это, а также дать возвожность задавать любое значение для display перепишем функцию putElem():

function putElem(elemId,displayValue) {
   if (dom) document.getElementById(elemId).style.display = (displayValue)? displayValue : "block";
   else if (ie) document.all[elemId].style.display = "block";
}

Как видите, добавили параметр displayValue, но при его отсутствии все равно выставляем block. Теперь с помощью putElem('myRow', 'table-row') строка таблицы показывается в NN6. MSIE не соответствует стандартам и для него необходимо все-таки устанавливать значение block (см. diplay Property). Но в функцию putElem() это учитывать не будем.

Еще к сожалению мне никак не удалось с помощью JavaScript воздействовать на свойство display как в Opera4, так и в 5-ую версию. А используя свойство visibility при любое значение empty-cells строка так и не захотела полностью скрываться. Из этого следует, что придется Opera третировать как "старый браузер" и для нее показывать разкрытое дерево.

Определяем браузер

В связи с тем, что только что выяснили придется определять браузер не так, как я писал в статье "Скажи мне, что у тебя за браузер...". Во первых нужно исключить Оперу, а она во первых понимает функцию getElementById, а во вторых может выдавать себя за MSIE и понимать document.all. После этого нужно иметь ввиду, что MSIE5 не ведет себя как DOM-совместимый браузер. Поэтому только для этого скрипта буду использовать вот такой код:

opera = (navigator.userAgent.indexOf('Opera') >= 0)? true : false;
ie = (document.all && !opera)? true : false;
dom = (document.getElementById && !ie && !opera)? true : false;

... и буду надеятся, что не появится еще один «не совсем совместимый со стандартами» браузер.

Промежуточный результат

дерево...
первая ветка
первый пункт дерева
второй пункт дерева
третий пункт дерева
вторая ветка
четвертый пункт дерева
третяя ветка
пятый пункт дерева
шестой пункт дерева

Чтобы сделать хорошее дерево, кроме dHTML-функций нужны еще и знания JavaScript, чтобы сделать объектную модель и делать на ее основе деревья любой разветвленности. Это все будет во второй части статьи, а пока приведу маленький пример того, что получается используя тех функций, которые вывели на настоящий момент — двухуровневое "дерево", которое расположено справа.

Если посмотрите код этой страницы, то увидите, что кроме описанных функций я использовал еще два массива treeOpen и treeItems, а также открывающую/закрывающую функцию changeTree. Но подробнее об этом в следующий раз.