generic cialis buy generic cialis discount generic cialis effect generic cialis for impotence order 10 mg cialis order 100 mg cialis order 15 mg cialis order 20 mg cialis order 25 mg cialis order 30 mg cialis order 40 mg cialis order 50 mg cialis order cialis cheap order cialis com order cialis fast shipping order cialis for men and women order cialis for woman order cialis generico order cialis georgia order cialis in holland order cialis lowest price order cialis medication order cialis mexican order cialis money order order cialis nevada order cialis now order cialis oklahoma order cialis overnight order cialis pills generic order cialis pro order cialis sale order cialis san francisco order cialis soft tab order cialis softtabs order cialis texas order cialis washington order cialis wisconsin Milan Stojanov homepage!

Brza pretraga fajlova preko SSH-a i PuTTY-a

Da li vam se ikada desilo da želite da obrišete određeni string ili liniju iz nekog od Vaših fajlova na web serveru, ali pojma nemate gde se to nalazi? Na primer, „navukli“ ste virus, pa vam se maliciozna linija koda ubacila u neki fajl – obično to bude index stranica i to nakon poslednje linije koda. Međutim, ponekad radite sa tuđim skriptama i niste uvek sigurni gde se koja naredba nalazi, a baš morate da je pronađete kako biste rešili postojeći problem. U takvim situacijama možete da:

1) ručno osmatrate ceo kod i izgubite puno vremena dok ne pronađete to što tražite
2) download-ujete sa servera sve fajlove, a onda preko nekog programa (na primer FileZilla) ili nekog naprednijeg texteditor-a (npr Notepad++) podesite da se u svim fajlovima pretraži to što vam treba.
3) preko SSH-a pristupite serveru i direktno nađete ono što tražite.

S obzirom da prvo rešenje iziskuje previše vremena, odbaciću ga kao nepraktično. Druga opcija je sasvim okej, ukoliko vas ne mrzi da skinete sve fajlove sa servera. :) Ali treća je definitivno najinteresantnija i ona je zapravo poenta u ovom zapisu.

Šta je SSH?

Za detaljan odgovor na ovo pitanje bih vas najradije uputio na Google i blogove mrežnih administratora, s obzirom da je to složenija (ali pritom i razrađena) tema, pa ću ja ovde reći samo najosnovnije – SSH (Secure Shell) je mrežni protokol koji vam dozvoljava da na siguran način pristupite udaljenom računaru i preko komandne linije završite neki posao na njemu. Praktično, ovaj protokol radi isto što i Telnet, samo što se ovde radi o potpuno sigurnoj komunikaciji.

Kako raditi sa SSH?

Ukoliko ste na shared hosting-u, gotovo nikako, jer retko koji provajderi dozvoljavaju SSH pristup, koliko sam imao priliku da se informišem. Na primer, ja koristim Uniweb hosting koji mi to ne dozvoljava. Međutim, održavam sajtove za prijatelja koji su na dedicated serveru, gde mogu da idem preko SSH.

Ukoliko vam je provajder omogućio SSH, verovatno već imate sve podešeno u cPanel-u – samo je potrebno da pogledate u SSH/Shell Access meniju kako idu parametri za konekciju. Ukoliko to nije slučaj, pogledajte ovde detaljno napisan članak kako možete sami da kreirate par javnog i tajnog ključa. Naredni korak je, naravno, da se konektujete na SSH preko nekog programa. S obzirom da nisam na Linux-u, morao sam da instaliram Putty (aplikacija za Windows), preko koga pristupam udaljenom serveru. Verovatno postoje i drugi klijenti za ovo, ali ja sam od prijatelja dobio preporuku za Putty – download.

Kada se konektujete, ostaje vam da dobro proučite Linux komande kojim ćete rešavati vaše probleme. Konkretno, kod mene je bio slučaj da među svim fajlovima WordPress bloga pronađem one u kojima se nalazi sledeći string „http://imgaaa.net/t.php?“ (jasno vam je da se radi o bezveznoj skripti koja se downloadovala preko slike). Umesto skidanja svih WP fajlova, sve što je trebalo da uradim je:

grep  „http://imgaaa.net/t.php?“ putanja/do/wordpress_foldera*.php

(jer su me zanimali svi php fajlovi).

Kroz par sekundi sam video gde je sve bila ta linija ubačena, obrisao je ručno i svi problemi su bili rešeni. Vama će možda trebati nešto drugo, ali verujem da ćete naći adekvatnu Linux komandu za to.

Moje prvo predavanje – „Upoznajte HTML5″ (novine u HTML5)

Posle tolike pauze, red je da se posvetim malo i svom blogu. Puno lepih stvari mi se desilo u poslednjih mesec dana – odlazak u Suboticu na eTalk sa svojom ekipom iz FONIS-a, upoznavanje sa Draganom Varagićem i prisustvo na njegovom predavanju na otvaranju projekta Blogeri studentima na kome sam, sa FONIS-om, radio čitavog leta…U svakom slučaju, o svemu tome mogu puno pisati, međutim ono što je svakako najbitnije i čemu posvećujem ovaj zapis je zapravo predavanje o HTML5, koje sam ja održao na FON-u.

Tačnije, tema je bila „Upoznajte HTML5″, sa osnovnom idejom da predstavim novine koje dolaze u HTML5 specifikaciji – obratite pažnju, govorio sam o specifikaciji koja se zove HTML5, a ne o brendu koji se zove HTML5. U čemu je razlika? Pa…razlika postoji i ogromna je. Kada kažete da ćete govoriti o HTML5 specifikaciji, onda to znači da ćete govoriti samo o onome što se nalazi u dokumentu koji se zove HTML5 specifikacija i koji je svima dostupan na W3C sajtu. :) Sa druge strane, kada govorite o HTML5 kao brendu, onda možete sebi da date slobodu da govorite o čemu god želite na webu, a što izgleda fancy i cool. Tipičan primer za to je kada Vam neko govori o CSS3 kao o HTML5 tehnologiji. Svako ko vam priča o CSS3 u tom kontekstu je najblaže rečeno neinformisan i prestanite slobodno da ga slušate. CSS3 je fantastična specifikacija, ali potpuno odvojena od HTML5 specifikacije i nema nikakve veze sa njom.

To sam na samom startu naglasio svojim slušaocima i izvinio se, jer je u samom početku ovog projekta bilo u planu da govorim o CSS3 na predavanju. Naravno, jasno vam je da sam želeo da pričam o HTML5 kao brendu i to je sasvim okej, ukoliko se ljudima naglasi da se predavač ne drži striktno specifikacije. Jedan veliki Apple, na primer, piše o HTML5 kao brandu! Ali, u svakom slučaju, to što sam odustao da pričam o CSS3 ne znači da posetioci gube – baš naprotiv, dobijaju i to tako što se stvara više vremena za priču o samom HTML5. Međutim, postojala je dilema – da li da stanem ispred 200 i kusur kolega i da im jednostavno nabrojim sve što je novo u HTML5 ili (pod dva) da nabrojim samo neke, bitne stvari koje su nove i objasnim zašto su baš te stvari ubačene. Hm…pa odgovor je jednostavan – ukoliko želiš štreberski-orijentisano predavanje, idi na prvu varijantu. U suprotnom, druga varijanta naravno! I tako i bi! :) Na kraju krajeva, svako ko se uopšte interesuje za ovo predavanje je dovoljno sposoban da na W3C-u/WHATWG-u nađe sve što ga interesuje vezano za HTML5 novine – čemu onda ja da smorim sa tom pričom? I naravno, postojao je još jedan dovoljno dobar razlog da se opredelim za drugu varijantu: znao sam da mnogi ljudi u sali nisu puno radili ni u prethodnim verzijama (X)HTML-a, te bi čisto poređenje izmedju HTML4 i 5 bilo takođe neadekvatno.

…Prva zvanična verzija HTML-a je bila verzija 2.0. Nakon toga, izašla je verzija 3.0, pa onda 3.2 ali nisam hteo time da opterećujem ljude. Zapravo, stavio sam akcenat na dešavanje posle verzije 4.0 i 4.01, koja je bila poslednja verzija HTML-a. Ali, ono što se kasnije desilo jeste da je W3C krenuo da razvija specifikaciju koja se zove XHTML 1.0. Poenta je u tome da su oni želeli da preformulišu sintaksu HTML-a, koja se do tada bazirala na SGML-u u XML. A kakva je XML sintaksa? Sve se piše malim slovima, svaki atribut mora biti pod navodnicima, svaki otvoreni element mora da se zatvori i tome slično…I to je bilo sasvim okej, jer je W3C želeo da neguje jedinstveni stil pisanja HTML-a, zasnovan na najboljoj praksi. Ali, godinu dana kasnije, izašla je nova, XHTML1.1 verzija koja je imala jednu jako bitnu promenu – dok ste u XHTML1.0 mogli da kodirate vaš sadržaj sa MIME-om text-html, u XHTML1.1 ste morali da imate MIME type application/xhtml+xml. I to je bila katastrofa zbog načina na koji XML parser tretira nevalidnu sintaksu. Tri reči su ovde bitne: Draconian error handling, a odnose se na sledeći scenario: čim brauzer prilikom čitanja vašeg fajla naiđe na prvu grešku – mora prestati sa renderovanjem strane i izbaciti grešku. To je bio ogroman problem jer je vodio pravo u katastru – da je ta praksa nastavljena po volji W3C-a, sve što je na Internetu napisano bi praktično bilo nedostupno.

Naravno, takvim odlukama W3C nisu bili zadovoljni mnogi, čak ni oni koji su unutar samog W3C-a. Tako su predstavnici Opere, Mozille i Apple-a formirali Web Hypertext Application Technology Working Group (WHATWG), koja je rešila da povrati dobri, stari HTML, ubaci neke nove elemente, unapredi web forme i poboljša razvoj web aplikacija. Ta grupa je nastala 2004. i time počinje razvoj HTML5….

Ovo je samo jedna od zanimljivih priča kojom sam uveo ljude u predavanje (naravno, dosta detaljnije). Smatram da je ovo zanimljivo iz više razloga – prvo, malo ko je uopšte znao koja je tačno razlika između HTML-a i XHTML-a; drugo, šta je MIME type uopšte i naravno, ono što je najneverovatnije – podatak da je razvoj HTML5 počeo davne 2004.

Govorio sam i o filozofskim aspektima i principima razvoja koji stoje iza HTML5, kao i o mnogim uprošćenim stvarima koje sada imate u HTML5. Naravno, morao sam da analiziram i nove, semantične HTML5 tagove koji znatno poboljšavaju strukturu i značenje samog dokumenta. Zaista, mi, web-designeri smo oduvek koristili div tag za bilo koju sekciju na strani – ali, div tag sam po sebi ima dva velika nedostatka: prvo i osnovno, div tag nema nikakvo semantično značenje, koje će u budućnosti biti jako bitno za pretraživače, pomoćne tehnologije (associative technologies) i slično. Drugo, možda čak i bitnije – div tag je dobio naziv od engleske reči devide. Ironično, div tag uopšte ne može da deli stranicu na više segmenta (header, footer, sidebar…), već je podela u koju mi slepo verujemo zapravo u CSS-u i pomalo u glavama. :) Drugim rečima, u HTML4 smo imali samo heading elemente (h1 – h6) kojim smo pravili nove celine u document outline-u i to je ono što je HTML5 unapredio – sada imate article, section, nav i aside elemente koji zaista kreiraju mikrocelinu unutar vašeg HTML dokumenta.

Naravno, priča o HTML5 ne može da se završi, a da se ne spomenu novi cool APIi. :) Ja sam se koncentrisao na najosnovnije API-e: Web Forms API, Audio&Video, Canvas i Offline Web Application, uz napomenu da Canvas API nije deo HTML5 specifikacije. Ipak, odlučih se da govorim o njemu zato što sam znao da ljudi ne znaju šta je Canvas, a sa druge strane – svi internet mediji bruje o njemu. Canvas, sa druge strane, zaslužuje pažnju na ovakvom predavanju jer jeste bio deo HTML5 specifikacije – trenutno nije, ali je to odrađeno iz praktičnih razloga.

Kako sam ja lično zadovoljan predavanjem?

Iako sam u većini slučajeva samokritičan, moram da priznam da sam zaista zadovoljan svojim prvim nastupom. Mislio sam da ću biti preplašen i da neću moći jasno da pričam od treme. Međutim, to se nije desilo – trema je nestala bukvalno posle prvih 30 sekundi. Ipak, sve vreme sam bio pod nekom tenzijom – ono, 200 i kusur ljudi te gleda, sluša i nije ti baš svejedno, pogotovu kada nemaš iskustva u ovim stvarima. Ipak, zahvaljujući feedback-u koji su baš ti ljudi popunili, video sam da su i više nego zadovoljni predavanjem. Naravno, ima i zamerki: previše sam dinamično šetao od jednog do drugog kraja amfiteatra prilikom izlaganja i to je nekima bio problem. Sad kad analiziram predavanje, vidim da jeste bilo tako i iskreno se izvinjavam zbog toga – zaista, to je bilo potpuno van moje kontrole. Takođe, nekoliko njih su napisali da nisu očekivali da će predavanje trajati samo 60 minuta. Detaljno sam razmislio o tome pre predavanja i shvatio da je optimalno vreme između 45-80 minuta. Nakon 45 minuta, ljudima opada koncentracija i ukoliko niste slatkorečivi, teško ćete uspeti da održavate pažnju. Zaista mislim da je u mom slučaju 60 minuta pun pogodak. Treća zamerka koja se javila jeste manjak interakcije na predavanju – sa ovim se u potpunosti slažem – zapravo, ja sam pitao par puta ljude šta misle o tome i tome…Ali, očigledno je trebalo više. I da, sledeći put ću definitivno više uključiti ljude u priču. :)

Naravno, želim da iskoristim priliku i da se javno zahvalim svima koji su došli i slušali HTML5. Bila mi je neopisiva čast što sam imao priliku da govorim o tome na B2S projektu i naravno, nadam se drugim i novim izazovima. :)

Sajt za aukciju: javascript odbrojavanje vremena

Autor ovog članka je Igor Manjenčić. Pogledajte DEMO ovde.

Iako je vreme kada su se na našem prostoru masovno pojavljivali sajtovi za aukciju davno prošlo, ja sam ipak dobio zadatak da odradim ceo mehanizam za sajt tog tipa (da, sajtova za aukciju nikad dosta). Potrebno je napraviti što je moguće življe okruženje na taj način što bi se vreme za prikazane aukcije odbrojavalo i ponude automatski osvežavale bez refresh-ovanja stranice. Trenutno sam odradio samo javascript odbrojavanje vremena pa ću ovde to predstaviti kako funkcioniše i koji su dalji koraci.

<html>
<head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <title>JavaScript - odbrojavanje</title>
      <script src="script.js" type="text/javascript"></script>
      <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
      <div id="brojac" class="brojac">
                <ul class="odbrojavanje">
		        <li><div class="odbrojavanje_num" id="odbrojavanje_day"></div><div>Dan(a)</div></li>
		        <li><div class="odbrojavanje_num" id="odbrojavanje_hour"></div><div>Sat(i)</div></li>
		        <li><div class="odbrojavanje_num" id="odbrojavanje_min"></div><div>Minut(a)</div></li>
		        <li><div class="odbrojavanje_num" id="odbrojavanje_sec"></div><div>Sekund(i)</div></li>
               </ul>
      </div>

      <div id="expired" style="width:400px;display:none;">
	       <h1>Vreme je isteklo.</h1><br/><br/>
      </div>

      <div id="odbrojavanje_timer1"></div><div id="odbrojavanje_timer1_isteklo" style="display:none;">Vreme je isteklo.</div>
      <div id="odbrojavanje_timer2"></div><div id="odbrojavanje_timer2_isteklo" style="display:none;"><br/>Vreme je isteklo.</div>
      <div id="odbrojavanje_timer3"></div><div id="odbrojavanje_timer3_isteklo" style="display:none;"><br/>Vreme je isteklo.</div>

</body>

style.css fajl:

html {
 background: #333333;
 height:100%;
}
body {
 font:"Lucida Grande","Lucida Sans Unicode",sans-serif;
 color:#fff;
}

.brojac ul.odbrojavanje{
 list-style-type: none;
 color: white;
 font-weight: bold;
 text-align: center;
}
.brojac ul.odbrojavanje li{
 float: left;
 height:110px;
 width: 105px;
 padding-top: 15px;
}
.brojac ul.odbrojavanje li div{
 font-size: 15px;
}
.brojac ul.odbrojavanje li div.odbrojavanje_num{
 font-size: 48px;
}
.brojac ul.odbrojavanje li.no_odbrojavanje{
 padding-top:4px;
 height:110px;
 width:180px;
}

Evo kako izgleda script.js fajl:

window.onload=initialize;
function initialize() {
	//kreiranje vremena isteka za 3 aukcije - prvi nacin
	var vreme = new Date();
	var deadlineYear = vreme.getYear();
	if (deadlineYear < 1000)
	deadlineYear+=1900
	var deadline1 = new Date(deadlineYear, vreme.getMonth(), vreme.getDate(), vreme.getHours(), vreme.getMinutes(), vreme.getSeconds()+30);
	var deadline2 = new Date(deadlineYear, vreme.getMonth(), vreme.getDate(), vreme.getHours(), vreme.getMinutes()+10, vreme.getSeconds()+35);
	var deadline3 = new Date(deadlineYear, vreme.getMonth(), vreme.getDate()+4, vreme.getHours(), vreme.getMinutes(), vreme.getSeconds());

	//kreiranje vremena isteka za 3 aukcije - drugi nacin
	//var deadline1 = new Date(2010, 10, 25, 21, 25, 36);
	//var deadline2 = new Date(2010, 10, 26, 8, 13, 50);
	//var deadline3 = new Date(2010, 10, 25, 21, 14, 41);

	//id vrednosti divova u koje su smestena odbrojavanja
	var timer1="odbrojavanje_timer1";
	var timer2="odbrojavanje_timer2";
	var timer3="odbrojavanje_timer3";

	var niz = new Array(timer1, deadline1, timer2, deadline2, timer3, deadline3);

	//pocetno pozivanje funkcije odbrojavanja
	odbrojavanje(niz);
}

//funkcija koja se poziva svake sekunde i kojoj se prosledjuje niz potrebnih promenljivih
function odbrojavanje(n){
	niz=n;

	//danasnji datum
	var today=new Date()

	//prolazak kroz niz elemenata tacno onoliko puta koliko ima tajmera (aukcija sa odbrojavanjem)
	//svaka aukcija ima dve promenljeve: prvu predstavlja id diva u koji se ispisuje preostalo vreme; drugi predstavlja vreme kada istice aukcija
	for(var i=0; i<niz.length; i=i+2){
	var thediv=niz[i];
	var deadline=niz[i+1];

	//oduzimanje datuma, dobija se broj koji predstavlja broj milisekundi izmedju dva vremena
	dd=deadline-today;

	//pretvaranje u dane, sate, minute i sekunde
	dday=Math.floor(dd/(60*60*1000*24)*1)
	dhour=Math.floor((dd%(60*60*1000*24))/(60*60*1000)*1)
	dmin=Math.floor(((dd%(60*60*1000*24))%(60*60*1000))/(60*1000)*1)
	dsec=Math.floor((((dd%(60*60*1000*24))%(60*60*1000))%(60*1000))/1000*1)

	//ukoliko je doslo do kraja sakrij odbrojavnje i prikazi poruku da je vreme isteklo
	if(dday==0&&dhour==0&&dmin==0&&dsec==0){
		document.getElementById(thediv).style.display='none';
		document.getElementById(thediv+"_isteklo").style.display='inline';
		niz.splice(i,2);

	}
	//u suprotnom update-uj podatke
	else{
		document.getElementById('odbrojavanje_day').innerHTML=dday;
		document.getElementById('odbrojavanje_hour').innerHTML=dhour;
		document.getElementById('odbrojavanje_min').innerHTML=dmin;
		document.getElementById('odbrojavanje_sec').innerHTML=dsec;
		document.getElementById(thediv).innerHTML=dday+"d "+dhour+"c "+dmin+"m "+dsec+"s";
		//posle 1000 milisekundi opet pozovi istu funkciju i prosledi joj niz parametara aukcija

	}

	}//kraj for petlje
	setTimeout("odbrojavanje(niz)",1000)
}

Što se samog početka tiče, bitno je bilo napraviti neku osnovnu postavku i da sve to lepo funkcioniše tako da nije preterano pažnja obraćana na izgled i sam raspored brojača. Recimo da će se na stranici nalaziti nekoliko vrućih aukcija koje će imati live odbrojavanje i osvežavanje ponuda kao i jedna centralna aukcija koja će se prikazivati u krupnom planu. Za sada ćemo pažnju usmeriti ka tim tajmerima i funkcionisanje istih. Namerno sam ostavio neke manje greške u kodu da bih se bolje osvrnuo na njih.

Potrebno je bilo napraviti jednu funkciju koja će se izvršavati svake sekunde i koja će update-ovati tajmere. Upravo to radi funkcija odbrojavanje(). Postavilo se pitanje da li svaka aukcija posebno da poziva funkciju za pomeranje brojača međutim to nije moguće iz razloga što se funkcija setTimeout() poziva nad objektom window i ona jednostavno zamrzne celu stranicu. Dakle, neko višenitno izvršavanje nije moguće. Za razliku od tog pristupa, primenio sam drugi, a to je: svake sekunde izvrši mi pomeranje brojača za sve aukcije na stranici. Prilikom izvršavanja te funkcije proverava se da li je brojač došao do nule i tada se ispisuje poruka da je aukcija završena.

Zbog optimizacije koda nije dovodljno samo sakriti aukciju i prikazati poruku da je vreme isteklo. U tom slučaju, kada dođe do nule, brojač se samo sakriva a ta aukcija koja je završena i dalje ostaje u nizu, i dalje se kroz nju prolazi for petljom, i dalje se računa razlika u datumima i rastavlja na dane, sate, minute i sekunde. Dakle, nema potrebe da se ta aukcija i dalje obrađuje, ona je završena. Rešenje ovog problema je jednostavno izbacivanje iz niza tog para promenljivih koji se odnose na aukciju koja je završena da bi se prilikom ponovnog pozivanja iste funkcije prosledio taj novi niz.

Druga stvar, primetićete, kod koji se odnosi na refreshovanje odbrojavanja za top aukciju se ponavlja onoliko puta koliko ima aukcija umesto samo jednom u jednoj sekundi. Potrebno je tih par linija koda izbaciti odatle i staviti na mesto gde će se izvršiti samo jedanput u sekundi.

Treća stvar, opet ćete primetiti, neke sekunde se «preklapaju» tj. razmak između dva pomeraja brojača je nekad veći a nekad manji u zavisnosti od zagušenosti računara. Ja pretpostavljam da je to zbog ne izvršavanja koda u trenutku. Naime, posao koji treba da se uradi za tu jednu sekundu se nekad uradi pre a nekad mu je potrebno više vremena. Otud to preklapanje. U ovom trenutku mi se javlja druga ideja, da aukcije kod kojih je ostalo do kraja više od 3 minuta ne prikazuju sekunde. Dakle, tek kada se uđe u finiš aukcije da se pojave sekunde. Mada, i to je pitanje koliko bi optimizovalo kod jer se ondastalno provera da li je ostalo manje od 3 sekunde.

Dalje, postavlja se pitanje: šta ako korisnici web aplikacije imaju različito podešene satove na računaru ili još gore druge vremenske zone? Jasno je da JavaScript radi na strani klijenta i da svaki klijent ima različito vreme. Rešenje problema jeste uvođenje serverskog vremena i računanje odstupanja lokalnog od serverskog vremena. To bi omogućilo odbrojavanje po serverskom vremenu jer bi se svake sekunde uračunalo i to odstupanje.

Ima još jedan problemčić ali da ne zamaram previše. Dalji koraci su ispravljanje ovog koda, uvođenje serverskog vremena, kao i upotreba ajaxa za osvežavanje najboljih ponuda.

Igor ManjencicIgor Manjenčić je apsolvent Fakulteta Organizacionih Nauka, smer Informacioni sistemi i tehnologije. Dve godine je bio u Upravnom odboru Udruženja informatičara FONIS. Trenutno radi kao demonstrator na katedri za elektronsko poslovanje. Bavi se web programiranjem, dizajnom, internet marketingom, optimizacijom sajtova za pretraživače. Bloger bez bloga : ). Možete ga pratiti na twitteru.

Kako napraviti News ticker pomocu PHP-a i RSS feed-a

Danas mi se Žika, glavni urednik HandballPlanet i BalkanHandball portala, koje ja tehnički održavam javio i zamolio da malo proširim funkcionalnost tih sajtova. Naime, zatražio je da na HandballPlanet stavim ticker sa 5 najnovijih vesti sa BalkanHandball-a i obrnuto – da na BalkanHandball-u prikažem 5 najnovijih vesti sa PlanetHandball-a.

Nisam se ranije time zanimao, ali sam znao da se to može brzo i lako napraviti i evo da objasnim kako to izgleda. Za ovu priliku, iskoristio sam PHP DOM biblioteku i ideju sa ovog sajta.

Da biste uspešno pročitali XML fajl pomoću PHP-a i dobili HTML output, potrebno je pre svega da znate tačnu lokaciju do XML fajla koji želite da pročitate. Za WordPress, RSS možete videti na adresi: link_do_bloga/feed.
Za Drupal je to na: link_do_bloga/rss.xml (uzeo sam te dve platforme, zato što pomenuti sajtovi koriste upravo njih).

Kada otvorite preko brauzera te fajlove, videćete da se tu nalaze 10 poslednjih vesti koje ste objavili, a njihova struktura je sledeća (ovde su prikazane stvari koje nama trebaju):


<item>
 <title>Naslov najnovije vesti</title>
 <link>
 link_do_te_vesti
 </link>
 <pubDate>Tue, 27 Jul 2010 09:40:43 +0000</pubDate>
 <category>Internet</category>
 <description>
 Opis ove vesti...
 </description>
 </item>

PHP kod koji će pročitati ovo i konvertovati u HTML je:


<?php
 // instanciramo DOMDocument objekat i koristimo load metod za ucitavanje zeljenog XML-a
 $doc = new DOMDocument();
 $doc->load('http://balkan-handball.com/rss.xml');
 $count = 0;  // uveo sam brojac jer zelim samo 5 najnovijih vesti da prikazem, ne sve sto je u feed-u
 // za svaki item u XML-u uzimamo njegov naslov, link, kategoriju.
 foreach($doc->getElementsByTagName("item") as $item) {
 $title = $item->getElementsByTagName("title")->item(0)->nodeValue;
 $link = $item->getElementsByTagName("link")->item(0)->nodeValue;
 $category = $item->getElementsByTagName("category")->item(0)->nodeValue;
 if($count == 5) { break; }
 $count++;
 // konacno, ispisujemo ono sto zelimo
 echo "<p><strong>{$category}: </strong><a href=\"{$link}\">{$title}";
 }
 ?>

Veoma je slicno JavaScript-u, tako da ko zna taj jezik, neće imati nikakvih problema. Kada sam gledao Drupalov RSS feed, videh da sadrži i slike u sebi. To je poprilično korisno, ali ponekad može biti suvišno – na primer, kada želite da u sidebar-u pored naslova imate i početak (nekoliko desetina karaktera) teksta iz tog članka, bez ikakvih slika. Evo rešenja kojim možete zaobići slike iz feed-a (možda može i drugačije, ovo mi je palo na pamet):


$desc = $item->getElementsByTagName("description")->item(0)->nodeValue;
$cleaned_desc = preg_replace("/<img[^>]+\>/i", " ", html_entity_decode($desc));

S obzirom da u feed-u ne stoji običan tag, već HTML entitet,  moramo ga prvo konvertovati u karaktere, funkcijom html_entity_decode, a potom iskoristiti i preg_replace funkciju (patern sam našao na internetu, slab sam sa regEx-om) – ali dobro, bitno da ovo sasvim uredno funkcioniše.

Kada bih ispisivao i datum objave, svkako da bih izbacio ovo +0000 na kraju. Za to možete, naravno, iskoristiti substr funckiju i time dodatno poboljšati Vaš news ticker.
Takođe, može se još malo poraditi na dizajnu i atraktivnosti – ja nisam, zato što je Žika rekao da želi ovako. Na primer, da možete iskoristiti ovaj jQuery dodatak za vertikalno skrolovanje teksta – meni se jako dopao.
I za kraj, demo ovoga možete pogledati na sajtovima koje sam naveo na početku.

Promena adrese bloga!

Blog je dobio svoju novu adresu! Cini mi se da je ovako mnogo bolje. Prethviagrana adresa je bila poprilicno neozbiljna, a kada sam u to vreme poceo da pisem blog, nisam ni sanjao da ce me to toliko zanimati, pa sam i domen birao bezveze.

S obzirom da se situacija promenila, i da je ovaj blog dobio neku svoju pricu, od sada je na ovoj, ozbiljnijoj internet adresi!

Pozdrav.

JavaScript brojač karaktera u textarea, kao na Twitter-u i Last.FM-u!

Jutros sam, iz nekog razloga posle 100 godina otišao na Last.FM i ostavio jednom prijatelju poruku na wall. Video sam da je maksimalan broj karaktera koji možete napisati na Last.FM-u 1000, a pored textarea-e ima jedan lep, user-friendly brojač koliko ste slova iskoristili. Ukoliko pređete tih dozvoljenih 1000, tekst koji vas o tome obaveštava postaje crven, a submit dugme disablovano. S obzirom da sam se žešće smorio, rekoh ajd da napravim to sam, čisto da ubijem vreme. Evo rešenja:

HTML DEO:

<html>;
<head>
   <title>Brojac reci</title>
   <script src="script.js" type="text/javascript"></script>
   <style type="text/css">
	  h3 { color: gray; }
  </style>
</head>
<body>
   <form action="#" method="">
	   <textarea id="myText" rows="4" cols="50"></textarea><br />
	   <h3 id="textLengthInfo">0/16 chars used!</h3>
	   <input id="submit" type="submit" name="submit" value="Post!" />
   </form>
</body>
</html>

JavaScript:

window.onload = initAll;

//set maximum number of chars
var maxNumChars = 16;

function initAll() {
    var textBox = document.getElementById(&quot;myText&quot;);
    textBox.onkeyup = countChars;
}

function countChars() {
    var textLengthInfo = document.getElementById(&quot;textLengthInfo&quot;);
    var submitButton = document.getElementById(&quot;submit&quot;);
    currentNum = this.value.length;
    textLengthInfo.innerHTML = currentNum + &quot;/&quot; + maxNumChars +&quot; chars used!&quot;;
    if(currentNum &gt; maxNumChars) {
        textLengthInfo.style.color = &quot;red&quot;;
        textLengthInfo.style.fontWeight = &quot;bold&quot;;
        submitButton.disabled=true;
    } else {
        textLengthInfo.style.removeProperty(&quot;color&quot;);
        textLengthInfo.style.removeProperty(&quot;fontWeight&quot;);
        submitButton.disabled=false;
    }
}

Najprostija skripta, koju ste ikada videli u životu, zar ne? Ali, dobro, nekom će skratiti vreme da sam to napiše, sigurno. Evo, demo možete videti ovde.

U svakom slučaju, najveći razlog zbog kojeg sam postavio ovu skriptu ovde jeste problem koji ne uspevam da rešim. Naime, i na ovoj skripti, ali i na samom last.fm-u skripta se zbuni ukoliko korisnik ne kuca sam, već mišem paste-uje tekst – u tom slučaju, skript ne broji slova zato što, kao što se vidi, f-ja countChars() se poziva isključivo na onkeyup event.

Trenutno ne shvatam kako bih mogao da rešim taj problem, s obzirom da ne postoji neki handler-er  za paste event u JavaScript-u, a znam da je moguće jer na Twitter-u to radi. Postoji mogućnost da se iskoristi event onChange(). Međutim, problem je u tome što ovaj događaj detektuje problem u textarea tek nakon što ista izgubi fokus (tj, kada korisnik klikne bilo gde na strani izvan nje). Ukoliko neko zna kako bi problem mogao da se reši, bilo bi divno kada bi napisao to u komentaru.

Kako postaviti bilo koji font na web sajt? Rešenje – Cufon!

U  web dizajnu, tipografija igra veoma bitnu ulogu. Dobro odabran font, kao i njegova boja, veličina i razmak između redova garantuju veću ugodnost i preglednost našim posetiocima. Pored toga, tipografija presudno utiče na izgled samog sajta. Zato su dizajneri često inspirisani da ubacuju ne tako tipične i svakodnevne fontove (takozvane web-safe fontove).

Za one koji su novi u web dizajnu, web safe fontovi su oni za koje smo sigurni da ih svaki naš posetilac ima na svom kompjuteru. Ovo zato, jer posetilac neće videti font koji smo odredili u CSS-u ukoliko ga nema instaliranog na svom kompjuteru.

U praksi, najčešće želimo da imamo neki lep i interesantan font u headeru, footeru ili navigaciji. Prethodno opisani problem se može veoma lako rešiti – u Photoshop-u napravimo npr. header sa fontom koji želimo, pa onda to stavimo kao background. Time smo rešili svaki problem i svim posetiocima smo omogućili da vide font koji želimo. Međutim, do sada sam se dosta puta zapitao – da li postoji neko drugo rešenje? Uvek sam se pitao da li je moguće da u neki direktorijum sajta uploadujem font koji želim, pa da ga korisniku serviram JavaScript-om.

Otkrio sam nešto što se zove – Cufon. koji savršeno radi baš ono što želim, a to je:

1) uploadujem font na njihov server

2) font generator Cufon-a prebacuje taj font u poseban format

3) Cufon JavaScript čita taj format i prikazuje ga na strani.

Dakle, više nas ne interesuje da li korisnik ima instaliran font – sav posao odrađuje Cufon. Detaljne instrukcije oko upotrebe ovog sjajnog engine-a, možete naći u njegovoj dokumentaciji. Ili, ukoliko vam je lakše da učite gledajući video, to možete ovde uraditi. Demo – OVDE!

Zaista, kada pročitate/pogledate ovo, nema šanse da se ne snađete. Veoma je lako uploadovati font i napraviti sva neophodna podešavanja na njihovom sajtu, a isto tako, veoma je prosto embedovanje Cufona u Vaš sajt. Ono što je bitno naglasiti jeste da Cufon radi isključivo ako posetilac ima uključen JavaScript u brauzeru. Ukoliko to nije slučaj, na strani će se videti font koji je deklarisan u CSS-u za taj tekst. Još jedna bitna napomena – nije moguće selektovati/kopirati tekst koji je renderovan na strani pomoću Cufona. Ovo je, po meni, ne tako bitan nedostatak iz jednog jedinog razloga – obično se radi o malim delovima strane (npr, tekst u header-u), koji se može brzo i ručno otkucati.

Postoje još neke alternative Cufon-a, za koje sam otkrio nakon Cufon-a, iako se ispostavilo da je Cufon najkvalitetnije rešenje:

sIFR – problem sa njim je što pored JavaScript-a zahteva i Flash, zato što se bazira na njemu. Dosta je sporiji od Cufon-a, a ukoliko ima dosta teksta čiji se font menja, može doći do zakucavanja brauzera. Prednost u odnosu na Cufon je ta što je moguće selektovati konvertovan tekst.

@font-face – drugo rešenje, koje se ne bazira na JavaScript-u, već CSS3 je font-face. Ovo je baš ono što sam ja ustvari i mislio da može da se uradi pomoću JS-a. Ustvari, ovde to radi CSS3. Uploaduje se font koji se želi, deklariše u CSS fajlu taj font i adresa do njega, a zatim se klasično poziva za određeni html tag, takođe u CSS-u (videti link iznad za upotrebu). Problem sa ovim je što ovo CSS svojstvo  ne podržavaju svi brauzeri, posebno oni stariji.

Seminarski rad: Informacioni sistem menze – SSA, PMOV, relacioni model, baza u Access-u

Juče je moj tim (Milena Stojković, Milinka Tanjević, Milan Stojković i ja) imao odbranu dugo pravljenog seminarskog rada iz Uvoda u informacione sisteme. Rad je poprilično obiman, jer smo morali da uradimo sve ono što smo prešli na vežbama, a to je:

  1. Strukturna sistemska analiza (SSA), koja se sastoji iz dijagrama konteksta, prvog i drugog nivoa dekompozicije.
  2. Prošireni model objekti i veze (PMOV) gde smo morali da predstavimo sve dijagrame drugog nivoa dekompozicije.
  3. Relacioni model, koji smo napravili na osnovu PMOV-a, odnosno objekata koji se tamo pojavljuju, njihovih međusobnih veza i naravno, na osnovu kardinalnosti tih veza.
  4. Bazu podataka napravljenu u Microsoft Access-u 2007, koja ustvari predstavlja sintezu prethodnih tri tačkaka.
Evo i analize zahteva korisnika koju smo naveli u samom radu:

Potrebno je napraviti informacioni sistem za automatizaciju poslova studentskih restorana.

Deo ovog informaciog sistema su studenti, koji uplaćuju obroke preko svojih čip kartica, servis za obradu čip kartica koji omogućava uplaćivanje obroka na odnosno skidanje istih sa studentske kartice,  dobavljači hrane koji svakodnevno šalju svoje ponude kao i banke u kojima studentski restoran uplaćuje dnevni pazar.

Ceo sistem obezbeđuje veoma jasnu komunikaciju sa dobavljačima hrane. Nakon nestanka hrane u skladištima, zaposleni pretražuju kataloge dobavljača koji se čuvaju u sistemu kako bi videli ko je najpovoljniji, sa kim su najčešće poslovali itd. Šalju narudžbenice, čija kopija ostaje u sistemu; dobavljač na osnovu primljene narudžbenice prosleđuje fakturu koja se upoređuje sa narudžbenicom iz skladišta – ukoliko se ova dva dokumenta poklapaju, računovodstvo vrši uplatu na račun dobavljača. Dobavljač nakon toga šalje otpremnicu, koja se takođe čuva u sistemu, a nakon toga se i skladište hrane ažurira.

Sa druge strane, studenti su u dvojakoj interakciji sa informacionim sistemom – oni pre svega dopunjuju svoje kartice kako bi kasnije mogli da se hrane u restoranima. Svaki put kada student uzme obrok u restoranu, broj preostalih obroka na njegovoj kartici se smanji. Ovo, kao i dopuna kartica se vrši pomoću automatizovanog servisa za obradu čip kartica koji je deo našeg informacionog sistema.

Malopre pomenuto računovodstvo vrši uplate dobavljačima, ali da bi znali koje uplate mogu regulisati, prvo moraju napraviti upit stanja na svom računu. Informacioni sistem obezbeđuje ovo, kao i uplatu dnevnog pazara na račun u banci.

Evo i crteža (u radu ima preko 10 crteža) koje smo napravili u Microsoft Visio 2007 programu.

Informacioni sistem menze, dijagram konteksta

Za ovaj rad smo dobili čistu desetku.

Naredih dana ću postaviti ceo seminarski rad za download, kao i bazu.

Tutorial: Validacija Web forme pomocu JavaScript-a – Part 2

Dobro dоšli na drugi deo JavaScript tutorijala u kom ćemo nastaviti sa našim primerom validacije Web forme. U prvom delu sam objasnio kako naša skripta funkcioniše, uz napomenu da joj nedostaju određena poboljšanja kako bi bila sasvim funkcionalna i u skladu sa današnjim web standardima. Na primer, u ovom nastavku ćemo dodati funkcije za proveru:

1. da je korisnik čekirao select i radio dugmeta – ovo je sasvim opciono i možda vama ne treba forma koja ima i radio proveru u JavaScript-u, ali u ovom tutorialu će i to biti pokriveno.
2. da li je korisnik u dva input polja vezana za mail (mail i ponovljeni mail) ukucao istu email adresu
3. da li je email validan – da li sadrži određene karaktere za koje nije tipično da se javljaju u mail adresi, ili da li je korisnik ukucao @ npr.

Tako da će naša skripta na kraju izgledati ovako:

window.onload = initForms;

function initForms() {
 for (var i=0; i< document.forms.length; i++) {
 document.forms[i].onsubmit = function() {return validForm();}
 }
}

function validForm() {
 var allGood = true;
 var allTags = document.getElementsByTagName("*");

 for (var i=0; i<allTags.length; i++) {
 if (!validTag(allTags[i])) {
 allGood = false;
 }
 }
 return allGood;

 function validTag(thisTag) {
 var outClass = "";
 var allClasses = thisTag.className.split(" ");

 for (var j=0; j<allClasses.length; j++) {
 outClass += validBasedOnClass(allClasses[j]) + " ";
 }

 thisTag.className = outClass;

 if (outClass.indexOf("invalid") > -1) {
 invalidLabel(thisTag.parentNode);
 thisTag.focus();
 if (thisTag.nodeName == "INPUT") {
 thisTag.select();
 }
 return false;
 }
 return true;

 function validBasedOnClass(thisClass) {
 var classBack = "";

 switch(thisClass) {
 case "":
 case "invalid":
 break;
 case "reqd":
 if (allGood && thisTag.value == "") {
 classBack = "invalid ";
 }
 classBack += thisClass;
 break;
 case "radio":
 if (allGood && !radioPicked(thisTag.name)) {
 classBack = "invalid ";
 }
 classBack += thisClass;
 break;
 case "email":
 if (allGood && !validEmail(thisTag.value)) {
 classBack = "invalid ";
 }
 classBack += thisClass;
 break;
 default:
 if (allGood && !crossCheck(thisTag,thisClass)) {
 classBack = "invalid ";
 }
 classBack += thisClass;
 }
 return classBack;
 }

 function crossCheck(inTag,otherFieldID) {
 if (!document.getElementById(otherFieldID)) {
 return false;
 }
 return (inTag.value == document.getElementById(otherFieldID).value);
 }

 function radioPicked(radioName) {
 var radioSet = "";

 for (var k=0; k<document.forms.length; k++) {
 if (!radioSet) {
 radioSet = document.forms[k][radioName];
 }
 }
 if (!radioSet) return false;
 for (k=0; k<radioSet.length; k++) {
 if (radioSet[k].checked) {
 return true;
 }
 }
 return false;
 }

 function validEmail(email) {
 var invalidChars = " /:,;";

 if (email == "") {
 return false;
 }
 for (var k=0; k<invalidChars.length; k++) {
 var badChar = invalidChars.charAt(k);
 if (email.indexOf(badChar) > -1) {
 return false;
 }
 }
 var atPos = email.indexOf("@",1);
 if (atPos == -1) {
 return false;
 }
 if (email.indexOf("@",atPos+1) != -1) {
 return false;
 }
 var periodPos = email.indexOf(".",atPos);
 if (periodPos == -1) {
 return false;
 }

 return true;
 }

 function invalidLabel(parentTag) {
 if (parentTag.nodeName == "LABEL") {
 parentTag.className += " invalid";
 }
 }
 }
}

Krenimo redom! Kao što se primećuje, funkcija validBasedOnClass(thisClass) je dopunjena i sada omogućava još dve nove situacije: radio ili email klase.


function validBasedOnClass(thisClass) {
 var classBack = "";

 switch(thisClass) {
 case "":
 case "invalid":
 break;
 case "reqd":
 if (allGood && thisTag.value == "") {
 classBack = "invalid ";
 }
 classBack += thisClass;
 break;
 case "radio":
 if (allGood && !radioPicked(thisTag.name)) {
 classBack = "invalid ";
 }
 classBack += thisClass;
 break;
 case "email":
 if (allGood && !validEmail(thisTag.value)) {
 classBack = "invalid ";
 }
 classBack += thisClass;
 break;
 default:
 if (allGood && !crossCheck(thisTag,thisClass)) {
 classBack = "invalid ";
 }
 classBack += thisClass;
 }
 return classBack;
 }

Ukoliko je kao parametar (naziv klase) u ovu funkciju dospeo „radio“, pozvaćemo funkciju radioPicked(radioName), proslediti joj nov parametar – name atribut radio elementa u HTML strukturi dokumenta. Razjasniću malo tu funkciju:


function radioPicked(radioName) {
var radioSet = "";

for (var k=0; k<document.forms.length; k++) {
if (!radioSet) {
radioSet = document.forms[k][radioName];
}
}
if (!radioSet) return false;
for (k=0; k<radioSet.length; k++) {
if (radioSet[k].checked) {
return true;
}
}
return false;
}

Na početku smo deklairsali promenljivu radioSet i dodelili joj prazan string. Ulazimo u for loop i proveravamo sve forme koje imamo na dokumentu, jer kao što sam rekao u prvom delu ovog tutorijala, na strani možemo imati više formi. Mada, ukoliko pogledamo naš html kod, vidimo da u njemu imamo samo jednu formu, pa je ovaj loop za forme nepotreban. Mada, ukoliko se odlučite da stavite više formi na stranicu, ovo će biti svakako neophodan korak.

Zatim, u svakoj formi pronalazimo grupu radio element, uzimamo name atribut i upravo tu vrednost dodeljujemo našoj promenljivoj radioSet. Ukoliko uspemo da promenimo tu promenljivu (koja je definisana kao prazan string), to će značiti da smo našli neki radio element i samim tim možemo da nastavimo. Ali, ukoliko ne nađemo nijedan radio element na strani, radioSet neće dobiti novu vrednost, već će ostati prazan string, pa samim tim znamo da smo u problemu – mi na ovom primeru znamo da imamo radio element. Na kraju, proveravamo radio elemente koje smo „detektovali na dokumentu“ – da li su čekirani i na osnovu toga vraćamo vrednost true ili false.

Kada smo vratili true ili false kao vrednost te funkcije, pogledajmo šta se dešava dalje u funkciji validBasedOnClass() na osnovu ove vraćene vrednosti.

Ukoliko je false, classBack promenljiva postaje „invalid“. Šta to dalje implicira?

- funkcija validBasedOnClass() vraća vrednost invalid
- promenljiva outClass, koju ustvari čine stringovi koje vraća funkcija validBasedOnClass() će sadržati i string invalid.
- zbog toga, invalidTag() funkcija vraća false
- validForm() vraća false
- initForms() vraća false => Naša forma nije validna i neće biti dalje procesirana (u PHP-u npr), već će JavaScript uokviriti HTML element koji pravi problem i na taj način jasno staviti do znanja korisniku šta treba da ispravi.

Sve ovo smo već detaljno prešli u prvom tutorijalu – sada sam samo hteo da još jednom, po tezama prikažem šta se zaista dešava. Mene je logika u ovoj skripti oduševila, a posebno mi se dopada ta uzročno-posledična veza u hijerarhiji definisanih funkcija. Ukoliko najsitniji uslov nije ispunjen u nekom case-u npr, JavaScript zaustavlja dalje submitovanje forme.

Nakon male digresije, dolazimo i do poslednje stvari koje smo želeli da unapredimo – email input polje. Ovde morate dobro zapaziti kako izgleda html fajl. Ja ću namerno postaviti još jednom ovde, da bih vam ukazao na stvari koje morate primetiti kako biste razumeli kod.

label for="emailAddr">Enter your email address:&nbsp;&nbsp;&nbsp;&nbsp; <input id="emailAddr" type="text" size="30" class="reqd email" />
		</label></br />
		<label for="emailAddr2">Re-enter your email address:<input id="emailAddr2" type="text" size="30" class="reqd emailAddr" />
		</label>

Imamo dva input polja: Prvo gde će korisnik ukucati svoju adresu i drugo, u kojoj će korisnik ponovo ukucati tu adresu, koja naravno, mora biti ista kao i ova gornja. Ovo što ću sada napisati je jako, jako važno. Prvo input polje ima dva class atributa: reqd i email. Drugo ima reqd i emailAddr. Obratite sada specijalnu pažnju – emailAddr je id atribut našeg prvog input polja za email. Takođe, jedino emailAddr nismo definisali u našem switch statement-u. Iz tog razloga, kada ta klasa bude proveravana, ona će dospeti pod default u switch-u.

A pogledajmo šta se dešava u default-u:

default:
if (allGood && !crossCheck(thisTag,thisClass)) {
	classBack = "invalid ";
}
classBack += thisClass;

E, sada, pošto mi znamo da do defaulta može dospeti baš to input polje koje ima emailAddr klasu, ubacujemo u crossCheck funkciju njegov tag (input) i njegovu klasu (emailAddr). Pogledajmo sada šta se dešava u toj crossCheck funkciji.

function crossCheck(inTag,otherFieldID) {
	if (!document.getElementById(otherFieldID)) {
		return false;
	}
	return (inTag.value == document.getElementById(otherFieldID).value);
}

Sve se vidi ovde, ali hajde da prokomentarišem: tražimo element na našem dokumentu koji ima id emailAddr. Naravno, ukoliko ne uspemo da nađemo, vraćamo false. Ali, naravno da ćemo ga naći – to je naše prvo email input polje. Uzimamo njegovu vrednost i poredimo je sa vrednošću drugog email input polja i tu jednakost vraćamo (u vidu true, ili false).

Vratimo se ponovo na default. Ukoliko se vrednosti ova dva polja ne poklapaju, crossCheck vraća false, a naravno, to dalje implicira da će classBack promenljiva biti invalid. Na taj način smo na jedan sjajan način uspeli da proverimo da li je email isti u oba input polja. Sada nam ostaje još i poslednji korak – provera da li je email validan – da budemo sigurni da sadrži @, da @ nije na početku itd….

Pišemo novu funkciju, validEmai(email) i njoj prosleđujemo ono što je korisnik ukucao u to polje – thisTag.value. Meni lično je ovo veoma interesantno rešenje koje je smislila Dori Smith, jer sam prvi put video ovako nešto u programiranju – umesto niza loših karaktera, sastavila je string od loših karaktera i dodelila tu vrednost promenljivoj invalidChar. Dakle, to su neki karakteri koje mi ne želimo da dopustimo korisniku da ukuca u ovo input polje. Evo kako izgleda ta funkcija:

function validEmail(email) {
			var invalidChars = " /:,;";

			if (email == "") {
				return false;
			}
			for (var k=0; k<invalidChars.length; k++) {
				var badChar = invalidChars.charAt(k);
				if (email.indexOf(badChar) > -1) {
					return false;
				}
			}
			var atPos = email.indexOf("@",1);
			if (atPos == -1) {
				return false;
			}
			if (email.indexOf("@",atPos+1) != -1) {
				return false;
			}
			var periodPos = email.indexOf(".",atPos);
			if (periodPos == -1) {
				return false;
			}
			return true;
		}

1. (prvi IF) proveravamo da li je korisnik nešto ukucao. Ukoliko nije, vratićemo false.

2. (drugi IF) radimo jedan loop kroz email adresu tako što ćemo uvesti brojač k koji kreće od 0 do u ovom slučaju 6 (string invalidChars ima 6 karaktera) i definišemo badChar promenljivu koja će biti prvo razmak, zatim kosa crta ( / ), dve tačke ( : ) i tako dok ne prođe sve karaktere iz InvalidChars promenljive. Za to smo iskoristili već definisano charAt JavaScript funkciju koja radi upravo ovo što sam napisao – uzima karakter pod određenim rednim brojem iz stringa (koji karakter će uzeti, zavisi od brojača k), i zatim indexOf funkcijom proveravamo da li se taj karakter nalazi u email adresi – ukoliko da, indexOf će vratiti tačnu poziciju na kojoj se taj karakter nalazi, što će svakako biti veće od -1, jer u slučaju da se taj karakter prvi u email adresi, indexOf vraća 0 (ukoliko je drugi, indexOf vraća 1, treći – 2 itd). Ukoliko se to desi, vraćamo false.

3. (treći IF) proveravamo gde se nalazi @. Kao što znamo, u email adresi, @ simbol je negde između prvog i poslednjeg karaktera. To znači da ne sme biti ni na prvom, ni na poslednjem mestu. Zato ćemo to i proveriti – doduše, indexOf sada sadrži i drugi parametar, jedinicu. Taj parametar kaže indexOf funkciji odakle da krene da broji @ znak. Jedinica označava da treba da broji od drugog znaka. Mi proveravamo da li je @ na početku stringa. Ukoliko jeste, indexOf će vratiti -1, i zbog toga naravno vraćamo false.

4. (Četvrti IF), dalje, proveravamo da li se, kojim slučajem, u našoj adresi nalaze više od jednog at znaka. Dakle, pitamo da li se negde @ nalazi u stringu od pozicije atPos+1, tj od mesta gde smo pronašli već jedan karakter. Ukoliko postoji, indexOf() neće vratiti -1, pa onda znamo da email nije validan i vraćamo false.

5. (Peti IF) – još jedna bitna stvar kod svakog email-a je njegova struktura. partizan90@gmail.com je primer jedne email adrese. Kao što se vidi, tačka mora da se nalazi negde posle @ znaka. Zato uvodimo novu promenljivu periodPos i njoj dodeljujemo poziciju na kojoj se tačka nalazi počevši od atPos pozicije. Ukoliko je periodPos jednak -1, to znači da nismo našli tačku, pa je email nevalidan i vraćamo false.

Ukoliko je email adresa prošla sve ove naše testove, možemo pretpostaviti da je validna i vraćamo true. Mada i sama Dori Smith je napisala da je veoma teško 100% tačno utvrditi da je email adresa validna, jer bi za to trebalo linije i linije IF-ova…Nama to i nije cilj. Želimo da budemo sigurni da su osnovne stvari zadovoljene, a to smo definitivno i uspeli emailValid() funkcijom.

Ovim smo ujedno i završili JavaScript tutorijal vezan za temu validacije kontakt forme. Videli smo kako jednostavno, brzo i efikasno možemo staviti korisniku do znanja gde je pogrešio u popunjavanju kontakt forme pre nego što je cela forma prosleđena do nekog od server side jezika.Ali, to nikako ne znači da proveru treba prepustiti samo JavaScript-u. To bi bilo vrlo opasno i moglo bi ugroziti bezbednost web aplikacije, pre svega zato što je JavaScript client jezik i korisnik može itekako da se ponaša onako kako mi ne želimo. Zato bih skrenuo pažnju, da pored JavaScript provere obavezno radite i serverside proveru!

U nadi da vam se dopada tuorijal, srdačno vas pozdravljam i pozivam da pratite blog, jer će u budućnosti biti još IT tekstova i saveta.

Izbegavajte Notepad++ i njegov dodatak za online editovanje

Ko prati blog, začudiće se otkud sada ovakvog naslova, koji deluje krajnje kontradiktorno u odnosu na ovaj zapis, koji je nastao pre svega par meseci. Ali, da, ovo je moj najnoviji stav koji je nastao iz situacije koja mi se desila pre pola sata i glasi: Izbegavajte Notepad++ kao rešenje za direktno editovanje fajlova na Vašem serveru. Nemojte biti lenji kao ja, već uvek sačuvajte fajl koji želite da editujete, završite sa tim i onda ga polako i sigurno ponovo vratite nazad.

Evo kako glasi pričica koja me je na trenutak izvela iz takta i potstakla da ovo napišem:

S obzirom da sam angažovan na izradi i održavanju dela sajta za prijavljivanje na Case Study Show 2010. preko FONIS-a, često mi na mail stižu neke specifikacije  – šta dodatno treba unaprediti i slično, od koordinatora ovog projekta, sa FONIS-ove strane, Militarov Gorana. Međutim, kako je on otišao u Sloveniju, njegov zamenik je Mihajlovic Milan, koji je nastavio Goranov posao – komunicira sa koordinatorom iz ESTIEM-a i dalje prosleđuje meni njihove zahteve. Danas je on dobio jedan veoma jednostavan zadatak, koji je čak pokušao i sam da sredi, ali kako to nije išlo, preneo je posao meni. Naravno, mislio sam da ću to odraditi rutinski – pokrenuo Notepad++, zakačio se na FTP, izmenjao šta sam hteo i kliknuo da se fajl uploaduje.

E, tu sada nailazi komedija – glupi Telenor internet pukne usred uploadovanja fajla, Notepad++ izbaci da je fajl uploadovan (ipak!?). Ja zatvorim to, pogledam sajt, kada ono….Od onog fajla koji sam ja imao, ostalo je svega 20% – toliko je Notepad++ uspeo da uploaduje pre nego što je internet konekcija prekinuta.

Naravno, zgranuo sam se kada sam video šta se desilo. Backup nemam! Isuviše sam bio lenj da sačuvam kopije na kompu, već sam sve radio direktno, na serveru. Naš trud oko sajta propada.

Cimam odmah Milicu, koja je takođe radila sajt sa mnom, i očajnički je pitam da li ona ima backup. Ni ona, kao ni ja, nije sačuvala ništa! Zgranut još više kada sam to čuo, pomislio sam da će ovo biti neprespavana noć kako bih sve to što pre ponovo napravio, jer prijave za ovo takmičenje unajveće traju – sajt mora biti online.

Ne znam kojim čudom, Milan Mihajlović, koga sam malopre spomenuo, pre nego što je iscimao mene, pokušao je sam da doda to što je trebalo, ali kao i svi pametni ljudi, sačuvao kopiju pre menjanja!

Zahvaljujući tome, sve smo povratili vrlo brzo, a ja sam njemu do neba zahvalan. :D

Nakon ovoga, mislim da neću više nikada:

1) koristiti Notepad++ u ulozi FTP klijenta

2) raditi na nekom projektu, a da nemam kod sebe kopije.

Shvatio sam da Notepad++ nije osmišljen kao FTP program, već kao text-editor. Zato ću ga ubuduće tako i koristiti.

Kada bolje razmislim, u celoj situaciji krivica je ponajviše moja – nemam FTP klijenta, već mučim Notepad++ da i to izigrava iako sam u par navrata bio nezadovoljan što ne mogu da kačim i uploadujem slike preko istog. I nisam preduzeo apsolutno ništa. Pored toga, nisam se ni setio da backup-ujem fajlove. Možda je naslov ovog posta loš, ali generalno – želim da ko god pročita ovo, shvati da će mu se sigurno desiti nekada ovakva situacija i da iz svega izvuče pouku – pravite backup uvek i koristite programe u skladu sa njihovom namenom. I treća stvar, veoma bitna – nemojte uvek verovati dodacima za programe, kao što sam ja u ovom slučaju verovao FTP_Synchronize. Ovo bi bio najtačniji naslov ovog zapisa, ali u ljudskoj je prirodi da sve druge okrivljuje, samo ne sebe. :D