Projektowanie i inne takie...

by Piotr

Zabawa z tabelkami

, ,

Kończymy właśnie pisać naszego autorskiego CMSa. Jako, że dostałem wolną ręke jeśli chodzi o interfejs (Iiiihahaa!), postanowiłem, że będzie on dokładnie taki, jakiego sobie wymarzyłem, czyli lekki, estetyczny i maksymalnie przyjazny dla użytkownika. Interfejs ów opiera się m. in. na tabelkach, które są wypełnione zawartością - lista aktualności, podstron, wzorów listów, menu, galerii itp. Layout jest dynamiczny i konfigurowalny, toteż ktoś, kto, tak jak ja, ma pulpit szeroki na 1900 pikseli mógłby poczuć się niekomfortowo otrzymując tabelkę z kolumną zawierającą tytuły podstron rozjechaną na 1600 pikseli a resztę ściśniętą, gdzieś pod koniec, jak labrador w mikrofalówce. Oczywiście przewidziałem to i tak naprawdę, taka sytuacja nie ma prawa zajść, jednak mimo to chciałem dać użytkownikom wybór, która kolumna jest dla nich aktualnie najważniejsza i do której chcieliby mieć w danej chwili jak najwygodnieszy dostęp. Wybór był jeden - dynamiczna zmiana szerokości kolumn. Jako, że robiłem to pierwszy raz, ucząc się przy okazji, chciałbym teraz trochę pouczyć was. Tak więc dzisiejszy temat lekcji, to wspomiana już: "Dynamiczna zmiana szerokości kolumn - czyli, dlaczego lubimy Javascript." Jedziemy Potrzebna nam będzie tabelka. Ja zrobiłem sobie taką: Wy możecie zrobić zwykłą, prostą tabelkę zawierająca nagłówki i kilka rzędów komórek, dla zachowania przejrzystości:
<table border="0" cellpadding="2" cellspacing="0">
   <thead>
           <tr>
                  <th>Lp</th>
                  <th>Lorem</th>
                  <th>Ipsum</th>
                  <th>Dolor</th>
           </tr>
   <thead>
   <tbody>
            <tr>
                  <td>1</td>
                  <td>2</td>
                  <td>3</td>
                  <td>4[/html:td
            </tr]
            <tr>
                  <td>5</td>
                  <td>6</td>
                  <td>7</td>
                  <td>8</td>
             </tr>
   </tbody>
</table>
Teraz musimy przygotować sobie jakiś uchwyt, za który będzie można złapać i zacząć woogie boogie. Wystarczy jakiś DIV. Problem w tym, że elementy TH/TD ignorują position: absolute;... musimy więc użyć dwóch DIVów. Jeden będzie robił za containing block dla drugiego, pozycjonowanego absolutnie handlera (uchwytu):
<th>
  <div>
      Lorem <div class="handler"></div>
  </div>
</th>
Takie same DIVy dodajemy do pozostałych nagłówków tabelki. Następnie ostylujemy je trochę abyśmy wiedzieli, co się dzieje:
th > div {
    position: relative; /* tworzymy containing block */
}

.handler {
    position: absolute;
    top: 0;
    right: 99.5; /* uchwyt będzie na końcu każdego nagłówka a właściwie pomiędzy końcem a początkiem następnego */ 
    height: 100%;
    width: 9px; /* optymalna szerokośc dla uchwytu nie powodująca efektu "Kur... gdzie ten cycek?!" */
    cursor: ew-resize; /*  ew działa tylko w Safari, możecie użyć innego */
    border: 1px #900 solid; /* tymczasowo, żebyśmy wiedzieli, gdzie jesteśmy */
}
W rezultacie otrzymamy coś takiego: Javascript Front już mamy, teraz zaplecze, które wykona całą robote. Potrzebujemy dwie funkcje - jedną, która zajmie się zmianą szerokości i drugą, która wywoła cały mechanizm. Nie będziemy bawić się w żadne onclicki w TH a użyjemy do tego DOM poziomu drugiego i ładnie odseparujemy bebechy od warstwy prezentacji. Zaczniemy od resizowania. Funkcja, która napiszemy, będzie potrzebowała dwa parametry - referencje do obiektu, który będzie uchwytem (nasz DIV.handler) oraz drugi, obiekt Event zdarzenia mousedown.
    function resizeColumn(handler, event) { }
Teraz, musimy sprawdzić, jaką szerokość ma dany nagłówek i wyliczyć różnicę między nim a punktem kliknięcia myszką. Użyłem tu własnej funkcji do wyciągania reguł CSS - getStyleOf(), wy możecie użyć swojej.
function resizeColumn(handler, event) { 
var headerSize = parseInt(getStyleOf(handler.parentNode.parentNode, 0).getPropertyValue('width'));
var deltaX = event.clientX - headerSize;
}
Następnie musimy zarejestrować procedury obsługi zdarzenia, które będą odpowiadać na zdarzenia mousedown i mouseup, występującą bezpośednio po niej. Te procedury będą aktywne dopóty, dopóki będzie naciśniety lewy przycisk myszy i zostaną zwolnione gdy go puścimy. Dopisujemy dalej w ciele funkcji:
function resizeColumn(handler, event) { 
... /* tu poprzednie wyliczenia deltyX i headerSize */

document.addEventListener('mousemove', resizeDo, true);
document.addEventListener('mouseup', resizeStop, true);
	
event.stopPropagation();
event.preventDefault();
}
O stopPropagation() i preventDefault() oraz propagacji zdarzeń innym razem. Teraz po prostu przyjmij, że musimy tak zrobić. Ostatnim krokiem jest przygotowanie procedur resizeDo i resizeStop, które wykonają całą robotę:
function resizeColumn(handler, event) { 
...
function resizeDo(event) {
handler.parentNode.parentNode.style.width = (event.clientX - deltaX) + "px";
event.stopPropagation();	
}
	
function resizeStop(event) {
document.removeEventListener('mouseup', resizeStop, true);
document.removeEventListener('mousemove', resizeDo, true);
event.stopPropagation();	
}
Okey, funkcja resizeColumn() gotowa. Teraz musimy ją odpowiednio wywołać. Napiszemy drugą funkcje, która się tym zajmie i wywołamy ją z <BODY onload="">. Nię będe się tu rozpisywał, bo działanie jest chyba jasne - bierzemy wszystkie DIVy, szukamy tych, których nazwa klasy równa jest "handler" i aplikujemy im odpowiedni mechanizm. Oczywiście można to zrobić bardziej optymalnie (zadanie domowe wink ), na przykład przeszukując same tabelki a nie całe drzewo dokumentu ale tak też działa i, na potrzeby tego artykułu, jest bardziej przejrzyście.
function doResize() {
	var handlers = document.getElementsByTagName('div');
	for(var i=0; i<handlers.length; i++) {
		if(handlers[i].className == 'handler') {
			handlers[i].onmousedown = function (event) {resizeColumn(this, event)};
		}
	}	
}
Tak, jak wspomniałem - aplikujemy tę funkcję w BODY:
<body onload="doResize();">
...i usuwamy czerwoną ramkę:
.handler {
    border: 1px #900 solid; /* ciach! */
}
...i jeśli niczego po drodze nie popsuliśmy, to wszystko powinno fajnie hulać smile PS: uprzedzając komentarze - w IE nie działa i nie będzie. Mamy tę skromną i satysfakcjonującą możliwość wyboru środowiska pracy wink

Ktokolwiek widział, ktokolwiek wie...Muzo*ujnia*.pl

Comments

Anonymous Wednesday, July 23, 2008 9:59:09 PM

Five writes: Bardzo przyjemny artykulik, no i przypomnieć lub nauczyć się paru rzeczy można :) A do tego przykuł moją uwagę design layoutu, tak podobny do Findera ;) Pozdrawiam

Piotrarti040 Wednesday, July 23, 2008 10:01:05 PM

> tak podobny do Findera
To mój osobisty skin :]

Anonymous Thursday, July 24, 2008 12:03:04 AM

Five writes: http://www.5design.pl/scr.jpg Czuję się prawie jak w domu ;) Ale myślę, że nie ja jeden :) Ale i tak należą się baty za brak wsparcia dla IE ;) [W sumie to nie chciało mi się wierzyć, że w ogóle nie pomyślałeś o ie, co zmusiło mnie do odpalenia vmware. Nie daruję ;) ] Mimo wszystko zapytam: czy w ogóle nie planujesz obsługi tego 'fjuczersa' dla ie w finalnej wersji CMSa?

.qki Thursday, July 24, 2008 1:47:49 AM

@Five, bo nie znasz Go tyle co ja bigsmile ja sie absolutnie nie dziwie dlaczego bigsmile on jakby mogl to by dodal ficzer zeby sie to tylko dalo ogladac na maku a wczesniej na amidze p

Piotrarti040 Thursday, July 24, 2008 5:06:43 AM

> wczesniej na amidze
To by bylo wyzwanie - HTML 3.2 i brak CSS bigsmile

Anonymous Thursday, July 24, 2008 1:07:16 PM

epi writes: U mnie jakoś dziwnie to działa :P Ciężko trafić w tą krawędź do przesuwania i nie przesuwa sie to co trzeba. Albo szerokość zmieniają wszystkie kolumny. Dziwne. Chyba że taki był zamiar :>

Piotrarti040 Thursday, July 24, 2008 2:10:38 PM

@epi
> Ciężko trafić w tą krawędź do przesuwania
W przegladarce?

> Albo szerokość zmieniają wszystkie kolumny
Po czesci tak. Pozostale sie proporcjonalnie zmieniaja w stosunku do tej, ktora zmieniasz.

Anonymous Thursday, July 24, 2008 9:08:42 PM

epi writes: > W przegladarce? To chyba pytanie retoryczne? :P >Po czesci tak. Pozostale sie proporcjonalnie zmieniaja w stosunku do tej, ktora zmieniasz. No właśnie, to jest lekko nieintuicyjne zachowanie. Imho powinna sie tylko zmieniac szerokosc sasiedniej kolumny. Ale to pewnie rzecz gustu :]

Piotrarti040 Friday, July 25, 2008 12:08:31 AM

> To chyba pytanie retoryczne?
Nie wiem, nie lubie sie domyslac, jesli cos mam naprawic.

> No właśnie, to jest lekko nieintuicyjne zachowanie.
Pisz do W3C. Nie bede hackowal naturalnego zachowania komorek w tabelach HTML wink


How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies