Perfection or Vanity

Project: Terminated

Blog nie jest już dalej prowadzony ani aktualizowany. Mimo tego, wpisy i komentarze są dalej dostępne. Możesz przeczytać pożegnalny wpis albo przejść do archiwum.

Kolejne usprawnienie na blogu - zastanawiam się nad dodaniem gdzieś znaczka Bety - ale tym razem mniej jałowy opis. Przed testowaniem upewnij się, że wczytane masz nowe pliki CSS i JS - Ctrl + Shift + R.

Code Switcher

W postach umieszczam często fragmenty kodu HTML / CSS albo JavaScript, dlatego zwróciłem szczególną uwagę na ten element strony. Roger Johansson bodaj pierwszy wpadł na pomysł, aby linijki kodu umieszczać w liście numerowanej. Poddana odpowiedniemu stylowaniu wygląda bardzo profesjonalnie no i oczywiście przejrzyście - porównując ją z tekstem preformatowanym <pre/>.

Do ciekawego stylowania listy jeszcze wrócę, teraz jednak chciałem skupić się na ważnym problemie związanym z użytecznością. Bo o ile <ol/> daje nam automatyczne numerowanie, to kopiowanie takiego kodu nie jest przyjemne. Kopiujemy bowiem także liczby / markery.

Mogłem zawsze wrócić do starego dobrego <pre/>, mogłem korzystając z buga dot. zaznaczania generowanej treści w Firefoksie porobić numerki licznikami (i czekać na klątwę od Quirisa ;-D). Lecz po co, skoro mamy JavaScript.


Skoro pre da się ładnie zaznaczać - niech tak będzie. Podmienimy listę na tekst preformatowany na żywo. Najlepszym sposobem na uporanie się z zadaniem operującym na DOM jest wypisanie sobie w pliku / na kartce punktów kontrolnych. Oto i one:

  1. Zaaplikować JavaScript wszystkim listingom kodu po załadowaniu się dokumentu.
  2. Otoczyć listy dodatkowym divem - ułatwienie w relacjach przełącznika z elementami przełączanymi.
  3. Dodać klikalny przełącznik lista / <pre/>.
  4. Zamienić każdy element listy na linijkę tekstu aplikując odstępy na podstawie nazw klas.
  5. Dodać tekst preformatowany przed listę. Ukryć go.
  6. Ustawić zdarzenie po kliknięciu na przełącznik. Włala.

Zanim przejdziesz dalej możesz chceć zapoznać się z całym kodem JavaScript - korzystałem trochę z Prototype, ale powinno być przejrzyście.

Pierwszy punkt - u mnie są to wszystkie ol.code. Pobieram więc w dokumencie wszystkie elementy ol za pomocą getElementsByTagName a następnie w pętli wykonuję proste sprawdzenie czy aktualna lista ma klasę code. Można zrobić to od razu przez funkcję Prototype getElementsByClassName, ale kiedyś używałem klasy code także dla akapitów.

W moim przypadku należy jeszcze wykonać ponowną konwersję gdy używamy Ajaxa na stronie głównej bloga. Załatwiłem to dodając klasę modified dla zmienionego ol.code i sprawdzając jej obecność w pętli.

Drugi punkt - tworzymy <div/> za pomocą createElement, wstawiamy go przed listę (insertBefore) i na końcu wstawiamy do niego kod za pomocą appendChild. Funkcja insertBefore jest bardzo przydatna i użyjemy jej jeszcze dwa razy - tutaj należy pobrać uchwyt do elementu nadrzędnego (parentNode załatwia sprawę) i wywołać ją na nim z dwoma parametrami - nowym elementem i tym przed którego coś wstawiamy. Przykład (no i upragniona zamiana, niejako demo):

  1. var div = document.createElement("div");
  2. ols[i].parentNode.insertBefore(div, ols[i]);
  3. div.appendChild(ols[i]);

Trzeci punkt - załatwiłem to spanem. Z lenistwa głównie - stylowanie linków trochę bruździ w kaskadzie, a span jest dry clean jak to się mówi. Leniuchując dalej użyłem innerHTML do wstawienia gotowego wycinka kodu przycisku. Aby ten punkt był zły jak diabli skorzystałem także z wywołania zdarzenia inline = onclick. Mam jednak swoje powody, a zawsze możesz zrobić inaczej niż ja. :P

Czwarty punkt - jako że nadal działamy w pętli (na każdym dostępnym w dokumencie ol.code) wystarczy że pobierzemy wszystkie elementy listy i zrobimy im kuku. Ja przekazałem gotową tablicę do nowej funkcji, żeby było przejrzyściej w kodzie.

  1. var lis = ols[i].getElementsByTagName("li");
  2. var output = convListToPre(lis);

W funkcji convListToPre wyszukuję wystąpień klasy space dla elementu listy. Jeśli znajdę - dodaję <br/> więcej. Następnie tak samo szukam klas ix, gdzie x jest numerkiem od 1 do iluś tam (w CSS mam ustawione na razie 5 - więcej wcięć nie potrzebowałem). Jeśli znajdę, to pobieram numerek i następnie w pętli while dodaję tyle podwójnych spacji ile trzeba (i1 = dwie, i3 = sześć). Wreszcie wyciągam kod z elementu i wszystko razem (bo wyniki są agregowane w zmiennej s) wysyłam z powrotem. Chciałem zaznaczyć, że w normalnych przeglądarkach zadziałałoby \n oraz "(spacja)(spacja)" lecz Explorer się foszy i wymaga dopieszczenia.

Pozostaje nudne jak flaki z olejem dodanie <pre/>, w środku niego <code/>, wlanie wyniku konwersji do środka i ukrycie elementu przed wścibskimi oczkami gości.

Na końcu używając funkcji z haniebnego onclick sprawdzamy klasę spana i przełączamy raz to listę uporządkowaną raz to tekst preformatowany. Klasa zmienia także obrazek tła dla przycisku. W celu zaspokojenia zapędów badawczo-poznawczych czytelników dodałem także odpowiedni title. Pre dostał też hacka związanego z overflow. Działa. :)


Wracając do stylowania - takie fajne numerowanie uzyskujemy za pomocą list-style-type: decimal-leading-zero. Szare prostokąty kodu to code zamieniony na element blokowy. Wcięcia to 3ex, 5ex… - ex to szerokość litery x w danym tekście - mamy tutaj stałą szerokość znaku, więc dostajemy równe wcięcie. Odstęp pionowy jest zrobiony klasą space (o czym wcześniej była mowa)

Dopieszczenia wymaga dopełnienie dla listingu na Operze 8.5 przesuwające numerowanie - chociaż nie ustawiałem żadnego paddingu dla li, wygląda na to że jest to mało ważne.

Wpadłem też na pomysł jak pokazać przez CSS że złamano linijkę kodu. Dodałem obrazek tła wypozycjonowany od drugiej linijki w dół. Póki nie można ustawiać wielu obrazków tła na raz pozostaje sklejenie jednego (co wpływa na wygląd gdy zwiększymy rozmiar tekstu, niestety). Efekt:

  1. ol {
  2. overflow: hidden;
  3. padding-top: 3em; /* 3 razy mnożymy 100% co daje 300% font-size dla elementu li co przekłada się na wysokość tego samego markera */
  4. }

Mam nadzieję, że ten artykuł pomoże podjąć właściwe decyzje podczas projektowania swoich stron i umieszczania na nich kawałków kodu. :) Ja tymczasem przymierzam się do czegoś co zautomatyzuje ospanowywanie CSSa w zależności czy mamy właściwość, wartość, selektor i tak dalej - może przydać się w przyszłości.

Informacje i hiperłącza

Blog o projektowaniu zgodnych ze standardami stron internetowych.

Praktyczne przykłady, sztuczki CSS, sposoby obchodzenia błędów przeglądarek, lekki i nieinwazyjny JavaScript, użyteczny design, dostępność i skrypty użytkownika.

RSS

Informacje o wpisie

Napisał riddle 16 czerwca 2006 o 13:16

Kategorie: HTML & Semantyka, JavaScript & DOM, Użyteczność

Dodaj do:

Wpisy archiwalne

Archiwum miesięczne

Dzięki!

Dodaj bloga do Technorati Favorites Dodaj bloga do Del.icio.us Blog należy do sieci 10przykazań.com

  1. Opera 9, cache odświeżone. http://img145.imageshack.us/img145/798/listing1cv.png -- czy tak to ma wyglądać? Mimo tego - świetne.

  2. b3x: Chyba już jest okej (marginesy pionowe). Dzięki za opinię. :)

  3. Bardzo ciekawa notka, przyda się :)

  4. <cite> Bo o ile ol daje nam automatyczne numerowanie, to kopiowanie takiego kodu nie jest przyjemne. Kopiujemy bowiem także liczby / markery.</cite>
    O_o : Opera 8.54 , windows xp :kopiuje się elegancko zama zawartosć, bez "odznaczników" (to samo przy ul,
    na linuchu też elegancko działa)

  5. Ale nie wszędzie jest tak pięknie. Przykładowo przeglądarki Gecko-based kopiują również numerki [przy ol]/gwiazdki [przy ul].

  6. Mi Firefox kopiuje bez numerków (może dlatego, że używam FF 3.0a1)

  7. Chyba ramka lekko szwankuje przy dłuższym kodzie w jednej linijce.
    http://img48.imageshack.us/img48/2100/zs4xy.jpg

  8. kiero: Mhm. Ale to tylko jak coś wystaje. Nie przejmuje się tym - bardziej dziwactwem Opery (chociaż niedawno było o list-style-position: inside i czymś blokowym w środku i to Gecko nawalał).

    matid: Tak czy inaczej IE kopiuje numerki. A tutaj nie kopiuje więcej jak jedną linijkę, bo każdy <li> ma overflowa.

  9. Hmm u mnie marginesy nadal źle.

  10. 9.0 to beta, co począć.

  11. Riddle:

    Tylko po co numerować wiersze w listingach? Zwłaszcza jeśli mają po 5 linii (a przy dłuższych przełącznik jest równie nieużyteczny).

    reod:

    <cite/> nie służy do cytowania, tylko do podawania źródła cytatu.

  12. Czemu numerować? Bo jest estetycznie. Do tego każda linijka kodu w moim odczuciu zasługuje na markup a nie pusty enter albo <br /> Żeby można było zwiększyć czytelność i tak dalej. Przełącznik służy do kopiowania kodu jeśli chcesz go u siebie użyć / potestować. Proste jak d r u t.

    OT: Kolejny komentarz „ja nie robię, to po co masz ty” i stwierdzę że jesteś rasowym nihilistą. Nie wiem, może dodawaj emotki, bo na razie wszystko co piszesz u mnie w komentarzach jest negatywne… podpadłem czymś znowu? ;)

  13. @Patrys: Numerowanie linii jest nieraz przydatne (ot choćby jak się podaje jakiś cytat z wypocin debuggera, który opiera się na numerach linii). Natomiast przełącznik przy dłuższych kodach - czemu nie? Jak ktoś zamierza kopiować kod, to przegląda w trybie <pre/>, natomiast jak ktoś analizuje szukając źródeł błędów (na przykład) - w trybie listy numerowanej.

  14. wpis IMO bardzo ciekawy:)

    Patrys:
    Mimo calego twego doświadczenia w robieniu www, którego jestem świadom, nie mam zielonego pojęcia czego się czepiasz;-) Moim zdaniem to bardzo wygodne jeśli mamy ponumerowane linijki kodu, przydaje się bardzo przecież nie każdy kawałek kodu ma te 5 linii:) a przełącznik chyba można zrobić przesuwany z viewportem przeglądarki [relative?].

  15. A tak swoją drogą, to ja mile bym widział coś, co działa w drugą stronę. Tzn. umieszczam tekst w <pre> czy tam innym ustrojstwie, a JS zamieniłby mi na <ol>.

  16. eXtreme:
    na dłuższą metę to mozna by robić <div class="unordered_list"> <div class="ordered_list"> itp. i jakoś to zmieniać javascriptem czy css'em, ale cóż w tym za sens?:)

  17. A jak ktoś Lynxa używa? ;) Chyba lepiej jakby początkowo nie było listy, a to JS ją dorabiał.

  18. Zgadzam się w pełni z eXtreme. Domyślnie powinien zostać <pre/> w kodzie. Listy w niczym nie pomagają, a jak powiedział Riddle, "wyglądają estetycznie."

    Mogą być śliczne, ale przeszkadzają w używaniu tego kodu. Rozumiem, gdyby potem odwoływać się do fragmentów tego kodu, ale to się robi maksymalnie niewygodne (trzeba inicjować liczniki konkretnymi numerami, bo numeracja fragmentu od 1 jeszcze bardziej zmniejsza czytelność).

    Czepiam się tego, tak jak czepiam się podświetlania nieklikalnych elementów na :hover. Dodawanie pierdół tylko dlatego, że się da, a nie dlatego, że w czymś realnym pomagają (raczej nikt nie debuguje kodu wklejonego na blogu) jest dla mnie tym samym, co wstawianie migających gifów na blogaskach. Zbędne elementy dekoracyjne.

  19. Może ktoś nazwie mnie "ignorantem", ale jedno pytanie: po co to wogóle? Jak dla mnie to niepotrzebne kilobajty / bajty.

  20. Ja myślę że dużo łatwiej/wygodniej byłoby mieć w kodzie <pre> a potem w JS dzielić na linijki...

  21. Cóż, wyjdę na ignoranta, ale miałem to u siebie już jakiś czas temu (jeszcze na joggerze) i podpiszę się pod innymi - pre jest o wiele wygodniejsze.

  22. Wydaje mi się, że osoby z brakiem obsługi JS powinny zobaczyć kod w <pre />, jako domyślny. Nie wiem jak to zrobić, ale tak byłoby wygodniej ;-)

    P.S. Kiedyś naprawdę trochę się zdenerwowałem, jak chciałem przekopiować Twoją klasę z tekstu w webesteem :)

  23. Imo, bardzo ciekawy blog. Duzo ciekawych treści na temat. Pozdrawiam.

  24. [Riddle]: „Tak czy inaczej IE kopiuje numerki.”

    A która wersja, jeżeli można wiedzieć? Bo szóstką próbowałem wzdłuż, w szerz i w poprzek zaznaczać i numerków nigdy nie łapał.

  25. blue: Blah, rzeczywiście, jest jak mówisz… ale ciężko się zaznacza ten listing tak czy inaczej (overflow przeszkadza).

  26. Osobiście mam wszystko oparte o znaczniki code.
    Wklwjam tutaj przykładowy kod (wystarczy dodać zmianę ukrywania po naciśńięciu czegoś i jestesmy w domu):
    <html>
    <head>
    <title>Test</title>
    <style type="text/css">
    code {
    white-space: pre;
    }
    .hide {
    display: none;
    }
    </style>
    <script>
    function code2ol() {
    var codes = document.getElementsByTagName("code");
    for(var i = 0; i < codes.length; i++) {
    var code = codes[i];
    var lines = code.innerHTML.split('\n');
    var ol = document.createElement("ol");
    for(var x = 0; x < lines.length; x++) {
    var li = document.createElement("li");
    li.appendChild(document.createTextNode(lines[i]));
    ol.appendChild(li);
    }
    code.parentNode.insertBefore(ol, code);
    code.setAttribute("class", "hide");
    }
    }
    </script>
    </head>
    <body onload="code2ol();">
    <code>something;
    something_else;</code>
    </body>
    </html>

    Przydałoby się ładniejsze rozwiązanie ukrywania. Działa przynajmniej w gecko.

  27. Skoro już bawimy się w JS, to może zupełnie odpuścić sobie pokazywanie taga <pre> i zamiast buttona podmieniającego widoczne bloki, zrobić buttona kopiującego zawartość (ukrytego pre, diva, czy czego tam) do schowka?

    Druga sprawa, to countery. Definiowane w CSS obsługiwane są tylko tu-i-ówdzie (nie sprawdzałem, mogę się mylić), a atrubut "start" na <ol /> jest deprecated w strictach. (Nie zawsze zamieszczam cały kod, czasami tylko kilkuliniowy fragment pliku, który ma 10tys linii)

    No i rzecz trzecia - na ile jest to semantycznie poprawne?

  28. Nie znam się dobrze na JS, ale nie słyszałem o dostępie do schowka przeglądarek poza IE. Mogę się mylić.

    Co do start to: http://www.w3.org/TR/html401/struct/lists.html
    <ol>
    <li value="30"> makes this list item number 30.
    <li value="40"> makes this list item number 40.
    <li> makes this list item number 41.
    </ol>

  29. Nie wygląda to u mnie najlepiej, ale już działa - zmiana kliknięciem.

  30. Czy ja wiem? Chyba faktycznie lepiej wpisywać <pre> a potem podmieniać na listę. Jest to może trochę trudniejsze w realizacji, ale nie niemożliwe.
    Popracowałbym jeszcze nad skakaniem tekstu. Przy dłuższych liniach, które po zmianie trybu są łamane, nie da się tego uniknąć. Ale przy tych krótszych... Mógłbyś precyzyjniej wyliczyć wartości odstępów.

  31. Jakiś czas temu natknąłem się na podobny skrypt na innym blogu. W tym jest jednak kilka błędów.

    1. Często nie widać numerków przy linijkach, po prostu je ucina zostawiając jeedn milimetr liczby i kropkę

    2. Ramka, a dokłądnie jej prawa krawędź, jest źle wyświetlana w blokach które się nie mieszczą i trzeba je przewijać suwakiem

    3. Górna i dolna ramka jest źle wyświetlana, tzn posiada pewien margines w stosunku do ramki dwuliniowej (opera 9)

    Opisane błędy występują w operze 8.52 i 9.0 (to NIE jest beta)

  32. Aha zapomniałem dodać. Może i "pre" wygląda lepiej i przejrzyściej dla krótkich kawałków kodu ale za to lista lepiej wyświetla długie linie. Nie podoba mi sie jedynie znaczek strzałki w lewo która ma sygnalizować koniec linii. Przeszkadza mi. Po co jest ona skoro i tak wiadomo, że jest tam koniec.

  33. Mnie się podoba...
    btw, jeśli powiększę czcionkę to strzałki oznaczające zawijanie linii nierówno się rozkładają, no i widać większy lub mniejszy kawałek takiej która jest poniżej końca linii (imo nie powinno w ogóle jej być).

  34. „Póki nie można ustawiać wielu obrazków tła na raz pozostaje sklejenie jednego (co wpływa na wygląd gdy zwiększymy rozmiar tekstu, niestety)”

    Jak powiększasz rozmiar tekstu godzisz się na różne zmiany / przekłamania w oryginalnym layoucie… a u mnie nie staje się nic niewidoczne bądź rozklejone. ;)

  35. straszna laska 35 13 marca 2007, 13:20

    niepodoba mi się to wcale….to nie jest wogóle fajne:(ja lubię czarne mangowo japonskie i z dodatkiem jakiejś tajemniczosci….uwielbiam gdy to jest straszne i jak zachwycają się tym….mój blog nie potrzebuje czegoś takiego:) ja mam strzasnie fajny i dzięks za takie gówno

  36. Raczej nie wydaje mi się, żeby ten listing sprostał CSS Naked Day.
    Lepiej, żeby w HTML’u było to „pre” a JS zamieniał to na listę numerowaną (co uważam za bardzo dobry i pomocny dodatek).

  37. I było bez dodatkowych elementów w kodzie.

  38. Pre jest znacznikiem prezentacyjnym. Chociaż tutaj jest naprawdę wiele opinii, więc może pozostańmy przy swoich.

Dodaj komentarz

Do formatowania komentarzy używaj Textile (HTML nie działa). Szczególnie jeśli wklejasz większe fragmenty kodu. W razie niepewności użyj podglądu komentarza.

Wypowiedzi obraźliwe, infantylne oraz nie na temat będą moderowane – pisząc postaraj się zwiększyć wartość dyskusji.

Komentarze nie służą do wysyłania wiadomości albo informowania o błędach, itd. Chcesz coś mi napisać – skontaktuj się.