Interval.cz
NewsTicker aneb pr·₧ok s be₧iacim textom

Dlho sme bojovali proti neÜtandardn²m elementom, ktorΘ si v dobßch "Browser Wars" vym²Ü╛ali tvorcovia prehliadaΦov Explorer a Netscape. Jedn²m z nich bol aj MARQUEE. Niekedy vÜak nastßvaj· situßcie, kedy na strßnkach potrebujeme ma¥ pr·₧ok s be₧iacim textom. Ako ho urobi¥ tak, aby narobil viac ·₧itku ne₧ Ükody, si povieme v tomto Φlßnku.

╚o vlastne chceme?

V prvom rade sa musφme zamyslie¥ nad t²m, Φo vlastne chceme:

  • Chceme urobi¥ jednoduch² newsticker, v ktorom sa bude pohybova¥ nieko╛ko textov²ch sprßv sprava do╛ava.
  • Chceme aby jeden dokument mohol obsahova¥ neobmedzenΘ mno₧stvo newstickerov.
  • Ke∩ sa textovß sprßva dostane na koniec newstickeru, mala by sa na chvφ╛u zastavi¥ a a₧ potom odφs¥.
  • Chceme ma¥ mo₧nos¥ ovplyvni¥ r²chlos¥ pohybu textu a dσ₧ku pauzy.
  • Skript by mal fungova¥ v prehliadaΦoch podporuj·cich Ütandardy, priΦom informßcie v ≥om zobrazovanΘ by mali by¥ prφstupnΘ vo vÜetk²ch prehliadaΦoch.
  • Forma by mala by¥ oddelenß od obsahu. Skript by mal by¥ Φo najviac oddelen² od dokumentu.

Je dos¥ d⌠le₧itΘ, aby sme sa pred pφsanφm skriptu v₧dy zamysleli nad t²m, Φo od neho oΦakßvame. V∩aka tomu budeme ma¥ u₧ vopred dobr· predstavu o tom, Φo budeme potrebova¥ a ako budeme postupova¥. Pokia╛ vßs v²sledok nßÜho sna₧enia zaujφma u₧ teraz, pozrite si mal· ukß₧ku.

Ako to urobφme?

Budeme vychßdza¥ zo zoznamu s odrß₧kami. Je jednoduch², zobrazφ sa korektne vo vÜetk²ch prehliadaΦoch a presne vystihuje Ütrukt·ru, ktor· budeme potrebova¥ û element UL reprezentuje dr₧iak (rßmΦek), v ktorom sa pohybuj· jednotlivΘ sprßvy (element LI):

<ul>
  <li>prva sprava</li>
  <li>druha sprava</li>
  <li>tretia sprava</li>
</ul>

Zoznam naformßtujeme pomocou CSS. Aby sme zbytoΦne nerozhodili vzh╛ad strßnky v archaick²ch prehliadaΦoch (v ktor²ch nßÜ skript nebude fungova¥), ulo₧φme definφcie CSS do samostatnΘho s·boru ("newsticker.css") a ten prilinkujeme pomocou met≤dy @import:

<style type="text/css" media="screen">@import url(newsticker.css);</style>

Samotn² skript tie₧ ulo₧φme do samostatnΘho s·boru ("newsticker.js") a k dokumentu ho pripojφme Ütandardn²m sp⌠sobom:

<script type="text/javascript" src="newsticker.js"></script>

Postup bude celkom jednoduch². Najprv si pomocou CSS naformßtujeme zoznam. JednotlivΘ sprßvy umiestnime do dr₧iaku absol·tne a animova¥ ich budeme pomocou zmeny CSS atrib·tu left v pravideln²ch intervaloch. Pre lepÜiu predstavu o tom, ako to funguje, je pripravenß ilustrovanß verzia skriptu, kde to vÜetko pekne vidno.

Te≤ria absol·tnej relativity

Element UL si oznaΦφme triedou newsticker (<ul class="newsTicker">). Ke∩₧e chceme ma¥ mo₧nos¥ umiestni¥ do jednΘho dokumentu viac newstickerov, je vhodnejÜie pou₧i¥ triedu (class) namiesto unikßtneho ID. Zadefinujeme si zßkladn² vzh╛ad dr₧iaku. Dajme tomu, ₧e bude rßmovan² jednopixelovou Φiarou. To je Φisto kozmetickß zßle₧itos¥. ╧alej by mal ma¥ v²Üku asi tak 1,5 em, aby sa nßm tam v pohode voÜiel jednoriadkov² text. ╚o je vÜak d⌠le₧itΘ, je schovanie preteΦenΘho obsahu (overflow). Chceme toti₧, aby text, ktor² prßve nie je v dr₧iaku, nebolo vidno (v opaΦnom prφpade by nßm tie texty poletovali hore-dole po strßnke a newsticker by nemal ve╛mi zmysel). A ke∩₧e mßme naformßtovan² odrß₧kov² zoznam (kv⌠li starÜφm prehliadaΦom), ale chceme ho zobrazova¥ ako normßlne texty, zruÜφme odrß₧ky a r⌠zne defaultnΘ odsadenia (padding, margin). NaÜa definφcia teda bude vyzera¥ asi takto:

ul.newsTicker {
  border: 1px solid #000;
  height: 1.5em;
  list-style: none;
  padding: 0;
  margin: 0;
  overflow: hidden;
}

Ch²ba nßm tam vÜak eÜte jedna ve╛mi d⌠le₧itß vec. Aby sme mohli jednotlivΘ sprßvy pohodlne animova¥, potrebujeme ich umiestni¥ absol·tne vzh╛adom k dr₧iaku. Nie je to niΦ komplikovanΘ, ale ve╛a ╛udφ mß o absol·tnom pozicovanφ mylnΘ predstavy. Myslia si toti₧, ₧e absol·tna pozφcia elementu sa vz¥ahuje k ╛avΘmu hornΘmu rohu dokumentu. Nie je to pravda a Üpecifikßcia CSS2 nßm to potvrdφ. V modele absol·tneho pozicovania je blok pozicovan² vzh╛adom k rodiΦovskΘmu bloku.

V praxi to vÜak vyzerß tak, ₧e pokia╛ rodiΦovsk² blok nemß zadefinovan² typ pozicovania (t.j. relative alebo absolute), neovplyv≥uje polohu absol·tne pozicovanΘho bloku. Tak₧e pokia╛ nßÜmu dr₧iaku pridßme eÜte definφciu position: relative;, sme hotovφ. NßÜ newsticker bude normßlne umiestnen² v toku dokumentu a jednotlivΘ sprßvy v ≥om bud· napozicovanΘ sprßvne.

Vzh╛ad sprßv

Naformßtovanie jednotliv²ch sprßv bude jednoduchΘ. U₧ sme si povedali, ₧e bud· pozicovanΘ absol·tne. ╧alej im zruÜφme (podobne ako u dr₧iaku) okraje a odsadenia vypl²vaj·ce z toho, ₧e p⌠vodne obsahovali odrß₧ky. Nakoniec eÜte vypneme zalamovanie textu (vytvßralo by to ve╛mi ÜkaredΘ efekty):

ul.newsTicker li {
  padding: 0;
  margin: 0;
  position: absolute;
  white-space: nowrap;
}

ZaΦφname skriptova¥

Newsticker mßme naformßtovan². Ke∩ sa na v²sledok nßÜho sna₧enia pozrieme teraz, uvidφme, ₧e v rßmΦeku s· jednotlivΘ sprßvy naukladanΘ jedna na druh· a Φakaj· len na to, aby s nimi niekto zaΦal h²ba¥. Vpred!

Vytvorφme si prßzdny objekt newsTicker. Ten bude fungova¥ ako akΘsi puzdro pre vÜetky premennΘ a funkcie, ktorΘ budeme pou₧φva¥. Pokia╛ vytvßrame nejak² komplexnejÜφ skript, je lepÜie ho zapuzdri¥ do jednΘho objektu. Spreh╛adnφme si t²m prßcu a predφdeme zbytoΦn²m konfliktom pomenovania premenn²ch a podobne. ObzvlßÜ¥ sa to vyplatφ, ak pφÜeme skripty pre projekt, kde bude ved╛a seba tak²chto skriptov viac. Tak₧e si vytvorφme ten objekt:

var newsTicker = {};

Teraz sa zamyslφme nad t²m, akΘ funkcie a objekty vlastne budeme potrebova¥ a vytvorφme si ich. Nesk⌠r pravdepodobne budeme musie¥ prida¥ nejakΘ pomocnΘ veci, ale aspo≥ uvidφme zßkladn· kostru skriptu a budeme sa jej m⌠c¥ dr₧a¥.

  • Asi budeme potrebova¥ nejak· funkciu, ktorß nßÜ newsTicker zinicializuje a predß mu zßkladnΘ atrib·ty ako r²chlos¥ posunu, odmlku a podobne. Nazveme ju init().
  • Ve╛mi d⌠le₧itß bude funkcia, ktorß bude vykonßva¥ samotn² pohyb sprßv. Bude sa vola¥ roll().
  • Vytvorφme si eÜte objekt, v ktorom budeme skladova¥ informßcie, ktorΘ budeme potrebova¥. Nazveme ho ticker a bude to pole. Ka₧d² newsticker, ktor² bude na strßnke, si bude uklada¥ svoje informßcie v podobe ∩alÜieho po╛a do po╛a ticker. Mßte v tom gulßÜ? To niΦ. Predstavte si to ako dvojrozmernΘ pole. Alebo eÜte jednoduchÜie ako tabu╛ku. Ka₧d² riadok reprezentuje jeden newsticker, stσpce obsahuj· informßcie. V praxi to bude vyzera¥ asi takto:
    idelementr²chlos¥krokodmlkaaktußlna sprßva
    0element110ms2px1000ms3
    1element224ms1px0ms1

Pozrime sa teda na to, ako zatia╛ vyzerß obsah nßÜho s·boru newsticker.js:

var newsTicker = {};
newsTicker.ticker = new Array();
newsTicker.init = function() {};
newsTicker.roll = function() {};

Inicializßcia

Pri inicializßcii newstickera nßs bude zaujφma¥:

  • Ktor² element mßme prerobi¥ na newsticker? (Mal by to by¥ element UL.)
  • Ak² ve╛k² skok urobia sprßvy pri ka₧dom posune?
  • Ako r²chlo sa bud· jednotlivΘ sprßvy pos·va¥ (t.j. v ak²ch Φasov²ch intervaloch)?
  • Ako dlho ostan· stߥ, ke∩ sa dostan· na zaΦiatok newstickeru?

V skutoΦnosti je pre nßs d⌠le₧it² jedin² ·daj - element, ktor² budeme formßtova¥. VÜetky ostatnΘ ·daje m⌠₧eme doplni¥ nejak²mi defaultn²mi hodnotami. Poskytova¥ v tak²chto skriptoch defaultnΘ hodnoty je celkom dobrß vec. Na jednej strane dßvame u₧φvate╛ovi mo₧nos¥ nastavi¥ si vÜetko tak ako chce a potrebuje. Na druhej strane mu vÜak dßvame mo₧nos¥ zjednoduÜi¥ si prßcu. Okrem toho, pokia╛ v nejakom projekte vÜade pou₧φvame newstickery s defaultn²mi hodnotami, iba na jednom mieste potrebujeme nieΦo mierne neÜtandardnΘ, bolo by zlΘ, keby sme kv⌠li tomu museli bu∩ pφsa¥ nov· funkciu, alebo uvßdza¥ tie istΘ defaultnΘ hodnoty pri ka₧dom volanφ skriptu.

Tak₧e m⌠₧eme zaΦa¥. Najprv si vy₧iadame atrib·ty, ktorΘ sa bud· predßva¥ funkcii init():

newsTicker.init = function(elm, step, speed, delay) {}

Prvß vec, ktor· skript urobφ, bude zbe₧nß kontrola vstupu a prostredia, aby sa zbytoΦne nesna₧il o nieΦo, Φo nie je mo₧nΘ, a nevyhadzoval chyby. Prekontrolujeme teda, Φi sme funkcii poslali atrib·t elm, Φi sa tento atrib·t odkazuje na element typu UL a Φi pou₧it² browser podporuje met≤dy, ktorΘ s· pre skript d⌠le₧itΘ (v naÜom prφpade je to met≤da document.getElementsByTagName). V prφpade, ₧e s· podmienky splnenΘ, funkcia urobφ Φo mß a vrßti nßm true. Ak nie, vrßti false a niΦ neurobφ:

newsTicker.init = function(elm, step, speed, delay) {
  if (elm && (elm.tagName == "UL") && document.getElementsByTagName) {
    // obsah funkcie
    return true;
  }
  return false;
}

Nßsledne si overφme, Φi s· zadanΘ ∩alÜie atrib·ty, a ak nie, nahradφme ich defaultn²mi hodnotami. Ke∩₧e vÜetky ostatnΘ atrib·ty s· Φφsla, bude ich kontrola jednoduchß:

if (isNaN(step)) {var step = 2};
if (isNaN(speed)) {var speed = 25};
if (isNaN(delay)) {var delay = 1000};

Toto vÜetko je sφce peknΘ, ale zatia╛ je to len vata. NßÜ skript a₧ doteraz neurobil niΦ konkrΘtne. ╚o vÜak od neho pri inicializßcii oΦakßvame? V podstate od neho chceme tri veci:

  1. Aby naÜiel vÜetky sprßvy, ktorΘ bud· v newstickeri rotova¥ a umiestnil ich tak, aby nßm nezavadzali.
  2. Aby ulo₧il potrebnΘ ·daje do premennej newsTicker.ticker.
  3. Aby nakoniec spustil samotn² pohyb sprßv.

Sprßvy nßjdeme jednoducho. Ide o vÜetky elementy LI v rßmci nßÜho elementu UL. Ich zoznam si ulo₧φme do doΦasnej premennej message:

var message = elm.getElementsByTagName("LI");

Nßsledne si celΘ pole message prejdeme a ka₧d· sprßvu posunieme do╛ava o jej vlastn· Üφrku (t.j. prav² okraj sprßvy bude tam, kde je ╛av² okraj dr₧iaku). V∩aka absol·tnemu pozicovaniu proste odpoΦφtame Üφrku sprßvy od nuly:

for (var i = 0; i < message.length; i++) {
  message[i].style.left = 0 - message[i].offsetWidth + "px";
}

V podstate t²m simulujeme situßciu, kedy u₧ vÜetky sprßvy prebehli a cel² cyklus ich rotßcie mß zaΦa¥ odznova. PreΦo? To si povieme o chvφ╛u, ke∩ budeme rozobera¥ funkciu na pohyb sprßv. Teraz toti₧ eÜte musφme ulo₧i¥ do po╛a newsTicker.ticker potrebnΘ ·daje. Budeme potrebova¥ to, Φo sme u₧ funkcii predali ako atrib·ty, plus poradovΘ Φφslo sprßvy, ktorou prßve pohybujeme. Ke∩₧e pri inicializßcii simulujeme ukonΦen² cyklus, ulo₧φme ako poradovΘ Φφslo Φφslo poslednej sprßvy:

var tickerID = newsTicker.ticker.length;
newsTicker.ticker[tickerID] = new Array(elm, step, speed, delay, message.length-1);

Premennß tickerID je unikßtny identifikßtor newstickeru v dokumente. Vedie¥ jeho ID je u₧itoΦnΘ, preto₧e nesk⌠r bude staΦi¥, ke∩ sa odkß₧eme na toto ID, a budeme ma¥ v∩aka po╛u newsTicker.ticker k dispozφcii vÜetky ·daje, ktorΘ budeme potrebova¥. A hne∩ to aj vyu₧ijeme, preto₧e zavolßme funkciu roll() s t²mto ID:

newsTicker.roll(tickerID);

èkatule, h²bte sa

Funkcia roll() na svojom konci nastavφ timeout, v ktorom zavolß sama seba a tak plynulo animuje jednotlivΘ sprßvy. V podstate mß na starosti tri veci:

  1. Zistφ, Φi u₧ nßhodou sprßva neprebehla na koniec a ak ßno, zaΦne pos·va¥ ∩alÜiu.
  2. Rozhoduje, za ak² Φas sa sprßva opΣ¥ posunie.
  3. Fyzicky posunie sprßvu.

Najprv vÜak musφ zisti¥, Φi jej niΦ nebrßni v tom, aby to urobila. Ako atrib·t jej poÜleme ID newstickeru, aby vedela, Φφm mß vlastne h²ba¥. Toto ID musφ by¥ Φφslo a v poli newsTicker.ticker musφ existova¥ polo₧ka s dan²m ID:

newsTicker.roll = function(id) {
    if (!isNaN(id) && newsTicker.ticker[id]) {
      // obsah funkcie
      return true;
    }
  return false;
}

Vytvorφme si premenn· ticker, ktorß bude referenciou na polo₧ku z po╛a newsTicker.ticker s aktußlnym ID. Tßto premennß je v podstate zbytoΦnß a zaobiÜli by sme sa aj bez nej, ale zjednoduÜφ a zpreh╛adnφ nßm k≤d:

var ticker = newsTicker.ticker[id];

Pomocou tejto premennej sa teraz jednoducho a r²chlo m⌠₧eme dosta¥ k ulo₧en²m informßcißm, ktorΘ potrebujeme. Tak₧e naprφklad element, s ktor²m pracujeme, je ticker[0], poradovΘ Φφslo aktußlnej sprßvy je zas ticker[4]. Vytvorφme si ∩alÜie dve pomocnΘ premennΘ. Jedna z nich (message) bude obsahova¥ zoznam sprßv a druhß (actualMessage) bude odkazova¥ priamo na aktußlnu sprßvu:

var message = ticker[0].getElementsByTagName("li");
var actualMessage = message[ticker[4]];

Ke∩ mßme pripravenΘ tieto pom⌠cky, m⌠₧eme sa zaΦa¥ rozhodova¥. Musφme si toti₧ zisti¥, Φi aktußlna sprßva nedorazila na koniec svojej cesty a nenastal Φas posla¥ ∩alÜiu. Ak ßno, musφme si zisti¥, Φi aktußlna sprßva nßhodou nebola poslednß v zozname a ak ßno, poÜleme opΣ¥ prv·. Nov· sprßvu si potom umiestnime za dr₧iak newstickeru, aby na nßs vykukla z pravej strany.

if (parseInt(actualMessage.style.left) <= 0 - actualMessage.offsetWidth) {
  if (ticker[4]+1 == message.length) {
    ticker[4] = 0;
  } else {
    ticker[4] = ticker[4] + 1;
  }
  actualMessage = message[ticker[4]];
}

Nov· sprßvu si vÜak nesmieme umiestni¥ len tak, na koniec dr₧iaku. Chceme toti₧, ke∩ sa dostane na nulov· pozφciu (t.j. na zaΦiatok dr₧iaku), aby sa na chvφ╛u zastavila (vi∩ premennß delay pri inicializßcii). Preto ju musφme umiestni¥ tak, aby jej pozφcia bola delite╛nß dσ₧kou kroku:

actualMessage.style.left = ticker[0].offsetWidth + (ticker[0].offsetWidth % ticker[1]);

Spome≥me si eÜte, ako sme pri inicializßcii simulovali, ₧e u₧ vÜetky sprßvy prebehli. To prßve kv⌠li tomu, aby pri prvom spustenφ tejto funkcie boli splnenΘ vÜetky podmienky a prvß sprßva naozaj vyrazila ako prvß.

Po∩me teraz fyzicky posun·¥ aktußlnu sprßvu. O ko╛ko pixelov sa mß posun·¥, to nßm prezradφ premennß ticker[1]. Novß pozφcia sprßvy teda bude aktußlna pozφcia mφnus posun. Aktußlnu pozφciu zistφme dotazom na style.left aktußlnej sprßvy. To nßm vÜak vrßti pozφciu aj s mernou jednotkou (px), tak₧e si z nej musφme vyparsova¥ celΘ Φφslo:

actualMessage.style.left = parseInt(actualMessage.style.left) - ticker[1] + "px";

Nakoniec sa eÜte musφme rozhodn·¥, za ako dlho opΣ¥ posunieme sprßvu ∩alej. Ak toti₧ dorazila na zaΦiatok dr₧iaku, chceme, aby sa na chvφ╛u zdr₧ala. Pomocou met≤dy setTimeout() si teda zavolßme funkciu newsTicker.roll s aktußlnym ID a pod╛a pozφcie aktußlnej sprßvy sa rozhodneme, Φi ju posunieme za normßlny Φas (speed), alebo si ju tam chvφ╛u podr₧φme (delay).

setTimeout("newsTicker.roll(" + id + ")", (parseInt(actualMessage.style.left) == 0) ? ticker[3] : ticker[2]);

Koniec dobr², vÜetko dobrΘ

A to je vlastne vÜetko. To, Φo sme si predsavzali, sme splnili. Teraz m⌠₧eme skript bu∩ necha¥ tak, alebo sa s nφm ∩alej hra¥, rozÜirova¥ ho a zdokona╛ova¥. Samozrejme m⌠₧eme k≤d trochu zoptimalizova¥ a zjednoduÜi¥ (treba skrßten²mi zßpismi podmienok, ktorΘ som kv⌠li nßzornosti radÜej nepou₧φval). M⌠₧eme prida¥ novΘ funkcie, naprφklad aby sa pohyb newstickeru zastavil, ke∩ na≥ho ukß₧eme myÜou, a opΣ¥ spustil, ke∩ myÜ dßme preΦ. M⌠₧eme sa pok·si¥ ten skript dopφsa¥ tak, aby fungoval aj v Ütandardy nepodporuj·cich prehliadaΦoch.. Malou zmenou v k≤de to m⌠₧eme prepφsa¥ tak, aby sa text nepohyboval horizontßlne, ale vertikßlne. Alebo to m⌠₧eme necha¥ tak ako to je.

SlabΘ miesta

NiΦ nie je dokonalΘ a tento skript u₧ v⌠bec nie. NiektorΘ jeho problΘmy s· drobnosti, ktorΘ sa daj· ╛ahko vyrieÜi¥, nieΦo je zas komplikovanejÜie. Toto s· problΘmy, ktorΘ na tom skripte vidφm ja:

  • Pri inicializßcii je niekedy mo₧nΘ vidie¥ vÜetky sprßvy nakopenΘ na seba. A₧ po tom, Φo sa pri inicializßcii posun· mimo dr₧iak, je vÜetko ako mß by¥. Tento problΘm sa dß vyrieÜi¥ ve╛mi jednoducho. V definφcii CSS staΦφ nastavi¥ polo₧kßm zoznamu display: none a pri inicializßcii im vrßti¥ display: block.
  • Ve╛k²m problΘmom je Opera. Vlastne iba jej starÜie verzie. Tie sφce zvlßdaj· CSS a met≤du @import, ale zlyhßvaj· v podpore DOM. Tak₧e v Opere 5 skript v⌠bec nefunguje, preto₧e nie je podporovanß met≤da getElementsByTagName(). A v Opere 6 zas nefunguje orezßvanie obsahu elementu pomocou atrib·tu overflow, tak₧e jednotlivΘ sprßvy vidno, aj ke∩ vyjd· mimo dr₧iak. S· to urΦite neprφjemnΘ chyby a ich oprava by si vy₧iadala r⌠zne hacky, workaroundy a browser sniffing. V najnovÜej verzii Opery vÜak tento skript funguje sprßvne a ja si myslφm, ₧e Opera je minoritn² prehliadaΦ, ktorΘho u₧φvatelia vedia Φo robia, zaujφmaj· sa o svoj prehliadaΦ a ve╛mi r²chlo prechßdzaj· na novΘ verzie, tak₧e to pod╛a m≥a zas a₧ takß katastrofa nie je.
  • Pou₧itie met≤dy offsetWidth nie je celkom ΦistΘ. Sprßvne by sa mala aktußlna Üφrka elementu zis¥ova¥ pomocou document.defaultView.getComputedStyle(mojElement, "").getPropertyValue("width"), ale bohu₧ia╛, zatia╛ najrozÜφrenejÜφ prehliadaΦ IE to nepodporuje. A tak som sa pri pφsanφ skriptu musel uch²li¥ k offsetWidth, Φo sφce nie je Ütandardn² sp⌠sob, ale zato je podporovan² vo vÜetk²ch momentßlne aktußlnych prehliadaΦoch. Mo₧no by stßlo za to napφsa¥ si na zis¥ovanie aktußlnych rozmerov elementu vlastn· funkciu (ale to u₧ je o nieΦom trochu inom).

PraktickΘ ukß₧ky

Bugreporting a vylepÜovanie

Som si ist², ₧e sa nßjdu r⌠zne drobnΘ chyby v Üpecifick²ch prehliadaΦoch na Üpecifick²ch platformßch. Budem rßd, ak ma o nich budete (s prφpadn²m nßvrhom ako ich opravi¥) informova¥ v komentßroch. Takisto rßd privφtam vÜetky nßvrhy a nßpady ako skript vylepÜi¥ alebo rozÜφri¥ o u₧itoΦnΘ funkcie.



Richard Fridrich (3.2. 2003)

Redakce Interval.cz |  Inzerce na Interval.cz |  Hledßme novΘ autory ISSN 1212-8651 
 ⌐ Zoner software, s.r.o., vÜechna prßva vyhrazena, tento server dodr₧uje prßvnφ p°edpisy o ochran∞ osobnφch ·daj∙.