Folyamatosan frissülő naptár – RELOADED

2007. márciusában kaptunk Fehérvári Gergelytől egy értékes leírást a javascript-es naptárkészítésre vonatkozóan.

Már én is kerestem egy naptár tutorialt valahol, így akadtam erre. Ahogy egyre jobban beleástam magam, rájöttem, hogy ez a leírás nagyon jó, viszont van néhány hiányossága is. Például nem kezeli a szökőévet, valamint a kódhoz minden évben hozzá kell nyúlni, hogy manuálisan begépeljünk néhány az aktuális évre vonatkozó adatot. Vagyis a folyamatos frissülés, amit a cím ír egy kissé sántít.

Az átdolgozott naptár “alkalmazás” három részből áll: van egy keret .html, ami a naptárat tartalmazza. Egy külső .css tartalmazza a formázásokat, és egy .js képezi a naptár motorját.

A konténerként funkcionáló .html annyiban változott, hogy kikerült belőle minden css formázás:

1
2
3
4
5
 
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<link href="naptar.css" rel="stylesheet" type="text/css" />
 
<script src="naptar.js" type="text/javascript" language="javascript"></script>

A .css file-t külön nem részletezem, mivel technikailag semmi szerepe sincs, “csak” a design-ban segít. A csatolt csomagban megtalálható.

A lényeg most a javascript-en van. Nézzük tehát mi az, amiben kissé megváltozott:

1
2
3
4
5
var aktdat = new Date();            // aktuális dátum
var ev = aktdat.getFullYear();    // aktuális év 4 karakter hosszban
var honap = aktdat.getMonth();  // aktuális hónap (0 = január, február = 1, ...)
var nap = aktdat.getDate();       // aktuális nap (azaz hányadika van ma)
var hetnapja = aktdat.getDay(); // a mai nap az a hét hányadik napja (vasárnap = 0, hétfő = 1, ...)

Magyarítottam a változóneveket, hogy az angolban kevésbé jártas webfejleszteni kívánó kollégák jobban átláthassák. Látható, hogy én a korábbi getYear() metódus helyett a getFullYear() metódust használtam, ami az évet az általánosabb ÉÉÉÉ formában, azaz 4 karakter hosszban adja vissza. Ezzel könnyebb lesz dolgozni később. Eléggé részletes komment van a .js file-ban, de természetesen minden magyarázatot ide is leírok.
Amit nem árt észben tartani – mert sok nehezen kinyomozható hiba adódhat belőle -, hogy a javascript sok nyelvhez hasonlóan 0-tól kezdve indexeli a tömböket. Fentebb a kód kommentjében látható, hogy ha a getMonth() metódusa 0-át ad vissza eredményül, akkor az bizony a január hónapot jelenti.

A getDay() metódus azt mondja meg, hogy az aktuális nap a hét hányadik napjának felel meg. Itt is 0-tól kezdődik az indexelés, méghozzá úgy, hogy a 0-hoz a vasárnapot rendelték.
Ne keverjük össze ezt a metódust a getDate() metódussal, mert ez utóbbi adja vissza a hónap aktuális napját, ami viszont nem nullával kezdődik, mert 0. nap nincs.

Most következik az a rész, ami a korábbi programba mintegy be volt égetve. Ezt a részt amikor évet váltottunk nekünk kellett módosítani úgy, hogy megnéztünk egy naptárat. Azt javaslom, hogy bízzuk ezt is rá a javascriptre.

Ha kicsit félretesszük a billentyűzetet és magunk elé veszünk egy naptárat, akkor azt láthatjuk, hogy ha egy hónapban az első nap nem hétfőre esik, akkor az elsejét megelőző napokon nincs semmi. Üresen vannak hagyva ezek a helyek. Korábban ezeket az üres helyeket kellett megszámolnunk a naptárban, minden hónapra vonatkozóan, majd beírni a javascript file-ba. Nos akkor dobjuk el a papírnaptárat és számoltassuk ki ezt is a programmal:

1
2
3
4
5
6
var dat2 = new Date(); // segéd Dátum objektum az üres helyek számításához
var kezdoUresek = new Array(12);
for(i=0;i<12;i++){
  dat2.setFullYear(ev,i,1);
  kezdoUresek[i] = (dat2.getDay()==0) ? 6 : dat2.getDay()-1;
}

Először is létrehoztam egy újabb Date objektumot (dat2), amit az üresek helyének megállapításához fogunk használni. Továbbá kell egy 12 elemű tömb, ami minden hónapra nézve tartalmazza azt a számot, hogy hány üres hely van a hónap első napja előtt.

Következik a tömb feltöltése:
A setFullYear() metódussal egy cikluson belül minden lépésben beállítjuk az évet ÉÉÉÉ-HH-NN formában.
A metódusnak három szám paramétert kell megadnunk, hogy előállíthassunk egy érvényes dátumot: év, hónap és nap.
Jelen esetben 2 fix adattal dolgozunk: az évet (ev) már a script elején lekértük és ezt fogjuk felhasználni, a napot pedig mindig 1-nek vesszük.
Ami változik az a hónap sorszáma (i ciklusváltozó). Ne felejtsük el, hogy 0-tól kezdődik a sorszámozás, azaz a nulla januárnak felel meg, 1 februárnak és így tovább.

Hogyan állítjuk be a kezdő üres helyeket?
Miután beállítottuk a dátumot, az “i”-nek megfelelő hónap első napjára, a getDay() metódussal megnézzük, hogy az adott hónap elseje, a hét melyik napjára esik. Figyelem!: vasárnap = 0, hétfő = 1, stb.
Első végiggondolásra azt mondhatjuk, hogy ahhoz, hogy megkapjuk, hogy mennyi üres hely kell a kezdő “1”-es előtt, megnézzük milyen napra esik és ebből kivonunk egyet. Ha például elseje szerdára esik, akkor a szerda getDay() által visszaadott értéke 3, amiből ha 1-et kivonunk az kettő, tehát H és K helyét fel kell töltenünk üres hellyel.
Azonban van egy eset, aminél, ha kivonunk egyet az értékből akkor -1-et kapunk. Ez pedig az az eset, amikor elseje vasárnapra esik, aminek 0 az értéke. Ezt kezeltük le a következő módon:

1
kezdoUresek[i] = (dat2.getDay()==0) ? 6 : dat2.getDay()-1;

A kód következő részében beállítjuk egy tömbben, hogy az egyes hónapok hány naposak. Ezt nem másolom ide, mert nem változott a régi file-hoz képest. Amit viszont pótolni kell az a szökőév lekezelése. A szökőév meghatározásához az alábbi egyszerű szabályt alkalmazzuk: a 4-el osztható évek szökőévek, kivéve a százas évszámokat, amelyek közül csak a 400-zal oszthatók szökőévek. Programban ez így néz ki:

1
if (((ev % 4 == 0) && !(ev % 100 == 0)) || (ev % 400 == 0)) napszamPerHo[1]++;

A hónapnevek beállítása szintén tömbben történik. Ez sem változott.
Kis esztétikai változás, hogy a hétvégére eső napokat eltérő színnel jelezzük. Ehhez természetesen a css-ben lett definiálva egy új szelektor.

És tulajdonképpen majdnem a végére is érkeztünk. Hátravan még a kiíratás. Ami nem változott, hogy először kiíratjuk a fejléceket (aktuális év és hónap, valamint a napok kezdőbetűit). Utána jönnek (ha vannak) a kezdő üres helyek.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
...
 
for(o=0;o<kezdouresek[honap];o++)>
 
') };
 
for(i=0;i<(7-kezdoUresek[honap]);i++){
	if (n == nap) {
        document.write ('
');
	    document.write (n++);
	    document.write ('
 
');
	}
	else {
		if ((i==5-kezdoUresek[honap]) || (i==6-kezdoUresek[honap])){
			document.write ('
');
	  		document.write (n++);
	  		document.write ('
 
');
		}
		else{
			document.write('
');
	   		document.write(n++);
	  		document.write('
 
');
		}
	}
}
 
document.write('
 
');
 
do {
	document.write('
');
	for(i=0;i<7;i++){
		if (n <= napszamPerHo[honap]) {
			if (n == nap) {
	  		   document.write ('
');
			   document.write (n++);
			   document.write ('
 
');
			}
			else {
			    if ((i==5) || (i==6)){
					document.write ('
');
					document.write (n++);
					document.write ('
 
');
				}
				else{
					document.write('
');
			    	document.write(n++);
		    		document.write('
 
');
				}
			}
		}
		else  document.write('
 
');
	}
document.write('
 
');
} while (n<=napszamPerHo[honap]);
document.write('
 
');</kezdouresek[honap];o++)>

Amint az látszik a korábbi kódot egy kissé lerövidítettem, mert ha belegondolunk az első sor kivételével (amiben a kezdő üres helyek is előfordulhatnak) az összes többi sor megjelenítése azonos módon történik. Így ezt minden gond nélkül bele tehetjük egy do-while ciklusba, hiszen minek gépeljünk annyit.

Ezzel el is érkeztünk a leírás végéhez. Persze tovább lehet gondolni, finomítani, csinosítani a naptárt. Lehet bele tenni névnapot. Ha akarjuk kiíratjuk a heteket vagy az aktuális hét számát. Kiemelhetjük az ünnepnapokat. A lehetőségek széles tárháza áll előttünk. Mindenkinek a kreativitására van bízva, hogy mivel egészíti még ki a naptárat!

Sok sikert a naptár használatához!

Forrásfile-ok: naptár.zip

10 HOZZÁSZÓLÁS

  1. A forráskódokban előforduló “esztétikai” hibákért elnézéseteket kérem. Rengetegszer átnéztem, most mégis találtam benne olyan hibákat, amiket a WordPress nem hajlandó rendesen megmutatni. (Megjegyezem: beküldéskor úgy tűnt, hogy minden szuperül megjelenik)

  2. Milyen esztétikai hibákra gondolsz? Ha gondolod átküldöm a cikk mostani forrását, amit gondolsz javíts benne, és utána kiteszem a módosítottat.

  3. Sziasztok,

    nem teljesen kapcsolódó, de azért érintett a dologban: nemrég találtam egy nagyon jó kis API-t (?), ami a naptár funkciókat bővíti a JavaScript alapjain túl. Gyakorlatilag nem generál neked naptárat, de nagyon hasznos funkciókat tartalmaz. DateJS a neve, és még alpha stádiumban van, ámbár én még nem találtam benne hibát. próba itt: http://www.datejs.com/ .

    Kicsi harc után rájöttem, hogy magyarítva is van. Hogy saját töketlenségemet más megspórolja magának ezt kell tenni a magyarításhoz: Jobb fent nagy kék “Download”-ra kattintva letöltöd a csomagot, kitömöríted, és a build/date-hu-HU.js fájlt betöltöd egy html doksiba valahogy így:

    Erre már lehet naptárat építeni :)

  4. Bocsánat, nem tudom szerkeszteni a hozzászólásom. A script beszúrásáért felelős sort a rendszer (nagyon helyesen) kiszűrte. Igazából nem is fontos. Az angolul tudóknak van leírás az odalon.

  5. Sziasztok!
    Ebbe a scriptbe bele lehet tenni egy olyan funkciót, hogy egy általam megnevezett napnak a cellája másik formázást kapjon?

    (Tehát ugye az aktuális napot jelzi ez a script, nekem meg egy olyan funkció kéne, ami egy tetszőleges napnak a celláját másik formázással jelenítse meg. pl: július 29, vagy augusztus 20)

  6. Természetesen, nyugodtan írd bele ezt a funckiót.
    Bár, ha ismered a jQuery-t, akkor annak elhasználásával is egész szép kis “kalendárt” lehet csinálni ;)

  7. Nem bírok ezzel a naptárral :(.

    Eddig sikerült egy ilyet összehoznom: (1-2 script módosítás + css)
    http://imagerz.com/QEJHWUtvAwJRA1NLQgVR

    Az Események az úgy működik, hogy minden hónapban mást ír ki.
    Júliusban pl 27-ét írtam ki, augusztusban megint egy másik dátumot írtam ki. (Szeptemberben megint, stb…)
    Eddig még jó is, viszont a naptárban nem tudom kiemelni a 27-ét.

    Ezért ha valakinek van egy kis ideje, ránézhetne az eredeti kódra, és ha lehet, akkor leírhatná, hogy mit kell módósítanom, vagy egyáltalán hol induljak el…

HOZZÁSZÓLOK A CIKKHEZ

Kérjük, írja be véleményét!
írja be ide nevét