Jakoś nigdy nie miałem motywacji by zająć się stworzeniem skryptu do tworzenia rozwijanego drzewa na bazie list nieuporządkowanych, ale zmieniło się to wraz z moimi planami stworzenia pewnej małej webaplikacji, która docelowo ma ułatwić życie programistom JavaScript. Na razie nie zdradzę szczegółów samej aplikacji, ale chciałem tu zaprezentować jak niewiele potrzeba by stworzyć rozwijane drzewko z użyciem MooTools 1.2 . Skrypt działa wszędzie poza IE, ale docelowo sama aplikacja też będzie działać na przeglądarkach wspierających standardy (bo z nich mam nadzieję korzysta tzw. grupa docelowa tworzonej aplikacji), więc póki co darowałem sobie zabawy związane z IE zwłaszcza jeszcze, że nie wiem czy to wina MooTools 1.2 w wersji beta 2 czy nie.

Oczywiście zaczęło się od kodu xHTML i CSS. W wypadku struktury dokumentu, każdy element listy ma następującą budowę:

<li><img [odpowiednia grafika węzła] /><span>Etykieta</span>[ewentualne submenu]</li>

Kod CSS prezentuje się następująco:


ul{
        margin:0;
        padding: 0;
        list-style-type: none;
        font-size: 11px;
        font-family: Arial, Verdana, sans-serif;
        color: #636363;
}

ul li{
        margin: 0;
        padding: 0 0 0 15px;
        line-height: 15px;      
        background: url(line.png) repeat-y;
}

ul li img{
        display: block;
        width: 15px;
        height: 15px;
        margin: 0 0 0 -15px;
        padding: 0;
        float: left;
}

W powyższym kodzie najważniejsze jest to, że każdy element listy ma przypisane tło, które będzie tworzyć na każdym poziomie linię, która wraz z odpowiednimi grafikami węzłów stworzy odpowiednią strukturę drzewa...

Drzewko od strony CSS i kodu xHTML jest gotowe - możemy teraz zająć się kodem JS. Zaczynamy jak zwykle od zdarzenia domready w którym umieszczamy cały pozostały kod.

Pierwsza rzecz to mała korekta kodu CSS - każdy ostatni element listy musi mieć inny obrazek węzła, a dodatkowo należy wyłączyć powtarzanie tła - bez tego, jeżeli ostatni węzeł będzie rozwijalny to obok rozwiniętego menu pojawi się linia, a tego chyba nie chcemy ? Cały problem załatwia jedna, za to dość długa linijka:

$$('ul li:last-child').getElement('img').setProperty('src','last.png').getParent().setStyle('background-repeat','no-repeat');

Sprawa druga - należy do węzłów, które mają menu podrzędne dodać odpowiednią ikonkę węzła. Rozwiązałem to w ten sposób, że dokonuję selekcji wszystkich list umieszczonych w elementach list, a następnie dla każdego z nich dokonuję selekcji rodzica (czyli węzła) i mu zmieniam grafikę oraz samą listę ukrywam (będzie rozwijana):

$$('li ul').each(function(el){
        var img = el.getParent().getElement('img');
        img.setProperty('src',(img.getProperty("src") == 'last.png') ? 'last-node.png' : 'center-node.png');
        el.setStyle("display","none");
});

No i dochodzimy do sprawy ostatniej czyli zwijania/rozwijania. Skrypt ma być elastyczny, zatem miło by było gdyby po dodaniu jakiegoś podmenu nie trzeba było dodawać kolejnego zdarzenia. Rozwiązałem to za pomocą jednego obserwatora zdarzeń, który na bazie event.target odnosi się do odpowiednich elementów, wykonując odpowiednie operacje. Na bazie atrybutu src skrypt decyduje czy lista ma być rozwinięta czy zwinięta:

$("tree").addEvent("click",function(e){
        var event = new Event(e);
        var el = event.target;
                
        if((el.getProperty("src") == 'last-node.png') || (el.getProperty("src") == 'center-node.png')){
                el.getParent().getElement('ul').setStyle('display','block')
                el.setProperty('src',(el.getProperty("src") == 'last-node.png') ? 'last-node-h.png' : 'center-node-h.png');
        }
        else if((el.getProperty("src") == 'last-node-h.png') || (el.getProperty("src") == 'center-node-h.png')){
                el.getParent().getElement('ul').setStyle('display','none')
                el.setProperty('src',(el.getProperty("src") == 'last-node-h.png') ? 'last-node.png' : 'center-node.png');
        }
});

I w ten oto sposób za pomocą kilkunastu linijek CSS i JS zamieniamy zagnieżdżone listy UL w eleganckie rozwijane drzewko.

Co jeszcze można poprawić ? Aktualnie dwie rzeczy mi się nasuwają - elementy img zamienić na divy i wykorzystać technikę z background-position by nie ładować wszystkich ikonek węzłów oddzielnie. Druga sprawa to zamienienie tego prostego skryptu w klasę, która będzie pozwalała na łatwe manipulowanie otrzymanym drzewkiem. Ale te usprawnienia stworzę już później gdy drzewko zostanie wykorzystane w webaplikacji.

Komentarze do wpisu "Rozwijane drzewka w MooTools 1.2":

1. Wasacz napisał(a):
16 marca 2008, 16:09:43

HTML jest obrzydliwy.

2. Dziudek napisał(a):
16 marca 2008, 16:12:22

@Wasacz – ale wpis jest o JS, a nie xHTML :P

3. Wasacz napisał(a):
16 marca 2008, 16:14:02

Ja bym dodawał te „plusiki” w JS, albo w CSS tło i padding-left – kilkalny byłby też tekst. Bez JS i tak obrazki są bezużyteczne, więc mogą być generowane przez coś innego.

4. Dziudek napisał(a):
16 marca 2008, 16:16:58

@Wasacz – :D Chyba nie przemyślałeś tego co wykombinowałeś – po cholerę generować coś co mogę mieć z miejsca w kodzie ? To ma być element webaplikacji, która bez JS nawet tego drzewka nie pokaże :P Im mniej się generuje w JS tym lepiej. Jeszcze można jedną linijkę JS spokojnie wywalić, ale to detal ;)

5. Wasacz napisał(a):
16 marca 2008, 16:20:22

Ale z miejsca w kodzie masz SYF.

6. Dziudek napisał(a):
16 marca 2008, 16:25:52

@Wasacz – to Twoja subiektywna opinia ;) W tym momencie reprezentujesz stanowisko bardzo skrajne, które głosi iż kod powinien być czyściutki, bez względu na poniesione z tego tytułu koszty, a ja zawsze stawiałem na kompromis – struktura kodu nie jest syfiasta jak twierdzisz, bo ma pewien określony układ i świetnie nadaje się do manipulowania via DOM, a ponadto jestem kilkadziesiąt operacji JS do przodu,kosztem kilkunastu bajtów – a zysk będzie jeszcze mocniej odczuwalny gdy drzewko będzie naprawdę duże… Jeżeli kierujesz się w tworzeniu stron tylko jedynie słuszną ideologią to życzę powodzenia, ale daleko nie zajedziesz :P

7. Wasacz napisał(a):
16 marca 2008, 16:28:00

Dwie operacje JS do przodu, a teraz policz ile kodu HTML jesteś do tyłu. Enjoy.

8. Dziudek napisał(a):
16 marca 2008, 16:30:22

@Wasacz – teraz mogę powiedzieć tylko jedno – doucz się i wtedy wróć to pogadamy… W swoim pseudoobliczeniach zapomniałeś o jednym – stosunku wydajności silnika renderowania stron i silnika JS. JS o wiele bardziej obciąża przeglądarkę niż pobranie paru dodatkowych bajtów i ich wyrenderowanie… Tyle wtemacie…

9. Wasacz napisał(a):
16 marca 2008, 16:32:55

Dorzuć jeszcze ze sto razy spacer.gif, skoro to takie pseudopoprawne.

10. Dziudek napisał(a):
16 marca 2008, 16:35:19

@Wasacz – gdybym podchodził do robienia stron jak Ty czy na jedną pałę, to pewnie by mi to nie przeszkadzało, ale ja w przeciwieństwie do Ciebie najpierw bym przeanalizował czy warto owy spacer.gif dodawać i zastanowił się czy korzystniej będzie w ogóle to generować, generować JSem czy mieć od razu w kodzie xHTML ów zapis…

11. Wasacz napisał(a):
16 marca 2008, 16:37:42

Podałem ci przykład innego rozwiązania. Jest jeszcze CSS, a on nie żre 100% CPU i na pewno jest lżejszy niż powielanie takiej samej konstrukcji HTML. To jest moja opinia, nikt nie każe ci się z nią zgadzać.

12. teamon napisał(a):
16 marca 2008, 16:38:25

To w takim razie na poczatku duzymi leterkami na czerwono
„wykorzystywać wyłącznie w aplikacjach nie działających bez JS” czy coś w tym stylu

13. Dziudek napisał(a):
16 marca 2008, 16:41:55

@Wasacz – tło już w CSS mam zarezerwowane na rysowanie linii dla danego poziomu, a w żadne pseudoelementy się bawił nie będę, bo to utrudni późniejsze rozszerzenie skryptu dla IE, a tak drzewko ładnie się rysuje nawet w IE.

@teamon – we wstępie zawarłem wystarczającą informację...

14. Wasacz napisał(a):
16 marca 2008, 16:43:07

Jak się chce to się wszystko da. Jeszcze bym usunął „eleganckie” z linku.

15. Dziudek napisał(a):
16 marca 2008, 16:45:52

@Wasacz – z pewnością kapkę dłużej tworzę strony WWW i skrypty JS do nich i mogę Cię brutalnie uświadomić, wybijając z głowy młodzieńczą fantazję – nie wszystko da się rozwiązać w sposób racjonalny, czyli wydajny…

16. Wasacz napisał(a):
16 marca 2008, 16:46:41

Dziwne, bo ja mam taki ficzer i potrafię.

17. Dziudek napisał(a):
16 marca 2008, 16:48:37

@Wasacz – pfff… znowu zawężasz… A to, że coś zrobiłeś według swojego widzimisię nie oznacza iż zrobiłeś to lepiej, to Twoja subiektywna opinia, że zrobiłeś lepiej …

18. Wasacz napisał(a):
16 marca 2008, 16:50:11

Zaweżam – ale co? Da się to rozwiązać inaczej jak się chce i koniec. Ty nie chcesz i nawrzucałeś setkę tagów img. To tyle. Nie wiem, nad czym tu jeszcze płakać – ale brutalnie cię uświadomię: mnie nie przekonasz.

19. Dziudek napisał(a):
16 marca 2008, 16:55:05

@Wasacz – bujasz się w dyskusji pomiędzy ogólnikami i szczegółami, a to że Cię nie przekonam to ja wiedziałem od pierwszego komentarza, dawniej już nie z takimi uparciuchami się użerałem w dyskusjach i zawsze kończyło się na prawie chamskim tonie z obu stron, a z dyskusji i tak nic nie wynikało, bo wizje są zupełnie odmienne i ciężko stwierdzić która jest słuszna, co też radzę zaakceptować, a nie ciągle udawać mądrzejszego niż się jest…

20. Wasacz napisał(a):
16 marca 2008, 16:57:24

No przepraszam bardzo, ale to ty mi „skrajność” zarzuciłeś, nie odwrotnie. Z resztą się zgadzam.

21. Dziudek napisał(a):
16 marca 2008, 16:59:46

@Wasacz – no sry, ale jak ktoś mi mówi, że mam coś generować JS-em by oszczędzić kilkadziesiąt bajtów to inaczej tego nazwać nie mogłem…

EOT

22. Wasacz napisał(a):
16 marca 2008, 17:01:11

Bo się uczepiłeś słowa „JS”, a nacisk byl na „alternatywę”. EoT++

23. Bigismall napisał(a):
16 marca 2008, 17:42:27

Proponuję przerwać bezowocną dyskusję i rzucić okiem na: http://www.mindplay.dk/mootree/

24. Bigismall napisał(a):
16 marca 2008, 17:44:35

Poniżej link klikalny
http://www.mindplay.dk/mootree/

25. kalin napisał(a):
22 maja 2008, 14:45:25

Witaj
Mam pytanie z troche innej beczki… dzieki Tobie zainteresowalem sie mootools i wlasnie studiuje kurs :)

Zastanawiam sie czy istnieje (w mootools lub wogole) mozliwosc wykrycia zmiany rozmiaru okna.
Poki co przychodzi mi do glowy jedynie sprawdzanie co x sekund wartosci window.getWidth, ale czy istnieje jakis bardziej elegancki sposob ?
pozdrawiam :)

26. Dziudek napisał(a):
23 maja 2008, 01:26:43

@kalin – teoretycznie istnieje zdarzenie onResize, ale wyżaliłem się kiedyś na jego temat dość obficie ;)

Zatem chyba pozostaje ta dość nieludzka metoda ze sprawdzaniem co x sekund ;)

27. wlamywacz napisał(a):
01 grudnia 2008, 22:10:43

Szkoda że nie działa pod IE 6

Dodaj komentarz:

Textile Lite włączony ( szczegółowy opis znaczników ):
*strong* | # lista numerowana | * lista wypunktowana | _em_ | __italic__ | "link":http:// | bq. cytat.