Archiv rubriky: js

javascript

Fotoalbum v NETTE (flickr style)

Již delší dobu plánuji, že přepíšu dávno nevyhovující fotoalbum oddílu BVÚ.

Nevýhody současného alba:
Viditelné:

  • malé náhledy (generuje je aplikace)
  • v případě aktualizace fotek, není dostupné
  • závislost na datumu souboru (pokud se nepovedlo nahrání, bylo tam nesmyslné datum)

Neviditelné:

  • složité nahrávání fotek (přes již prastarou aplikaci Olympus Camedia Photoalbum)
  • proprietální databáze Olympus Camedia Photoalbum postavená na MS ACCESS 1997, bez rozumné možnosti rozšíření
  • nesnadná správa stránek v prostředí MS – ASP (VB SCRIPT)
  • závislost na datumu souboru – musel se dodržovat speciální postup jinak se o datum přišlo, případně se musel synchronizovat s EXIF informacemi

Co čekám od nového alba:
Vyditelné:

  • rozumné rozhraní odpovídající době
  • možnost větší interakce se stránkami – TOPování fotek, komentáře, TAGy, …
  • větší propojení stránek oddílu (www, stream, fotoalbum)

Neviditelné:

  • sjednocení platforem webů
  • moderní programátorské prostředí (NETTE, jQuery)
  • lepší správa, menší závislost na proprietálním prostředí

Požadavky na nové fotoalbum:
Vyditelné:

  • rychlost
  • přístupnost
  • maximální orientace na prohlížení fotek – je to fotoalbum že!

Neviditelné:

  • minimální závislost na databázi
  • maximální jednoduchost nahrávání fotek

Pro představu uvedu postupy nahrávání fotek:
Postaru:

  • stáhnout fotky v něčem co nemění datumy souborů
  • protřídit
  • zmenšit v něčem co nemění datumy souborů
  • zabalit do ZIP archívu – aby při nahrávání na FTP se nezměnily datumy souborů
  • nahrát archiv na FTP
  • přes vzdálenou plochu na serveru v aplikaci Olympus Camedia Photoalbum vytvořit složku – od otevření aplikace je fotoalbum na webu nedostupné, jelikož si aplikace drží výhradní přístup
  • najít na disku vytvořenou složku (stromová struktura má formát: /ALBUM/001/001/038/019/)
  • nakopírovat fotky z archivu
  • otevřít vytvořené album ve Olympus Camedia Photoalbum – dojde k pomalému vytvoření náhledu a indexaci fotek
  • dříve se ještě v rámci speciální aplikace řešily publikované fotky, to již před časem odpadlo…
  • velké originály popsat a zazálohovat
  • Nově:

    • stáhnout fotky
    • protřídit
    • nahrát na FTP do pojmenované složky (tady ještě uvažuji o použití SAMBA protokolu a ukládání fotek na Windows share, který je pro běžné uživatele dostupnější)

    Úspora kroků je zřejmá!

    Na co se můžete těšit v dalších kapitolách?

    • zpracování fotek – od nahrání až po prezentaci
    • prezentace fotek na celou obrazovku prohlížeče – kdo zná flickr ví o čem píšu

    Jak neotravovat uživatele s antispamem? – realizace s podporou NETTE

    V článku jsem nastínil, jak chránit webový formulář antispamem bez zbytečné interakce uživatelů.

    Jak to ale propojit s NETTE a jeho generací formulářů.

    Příklad je napsán bez použití kompletního frameworku. Používám NETTE jen jako knihovnu.

    PHP:

    include_once $_SERVER['DOCUMENT_ROOT'] . '/_libs/nette.min.php';
     
    use	Nette\Mail\Message,
    	Nette\Forms\Form;
     
    // vytvoření formuláře		
    $form = new Form;
    $form->addText('jmeno', 'Jméno a příjmení *:')
    	->setRequired('Zadejte prosím jméno');
    $form->addText('mail', 'E-mail:');
    $form->addText('tel', 'Telefon:')
    	->addConditionOn($form['mail'], Form::EQUAL, '')
    		->addRule(Form::FILLED, 'Zadejte prosím alespoň jeden z kontaktů');
     
    $form['mail']->addConditionOn($form['tel'], Form::EQUAL, '')
    	->addRule(Form::FILLED, 'Zadejte prosím alespoň jeden z kontaktů')
    	->addRule(Form::EMAIL, 'E-mail nemá správný formát');
     
    $form->addSelect('zajem', 'Mám zájem o:', array('sádrokartony, rekonstrukce' => 'sádrokartony, rekonstrukce', 'malby, nátěry' => 'malby, nátěry', 'ostatní' => 'ostatní'));
    $form->addTextArea('pozn', 'Poznámka:', 40, 4);
     
    // antispam
    // Nelze řešit přes RAND, jelikož po odeslání by se nám hodnoty změnily, toto beru jako zajímavé "konstanty", které mají platnost jeden den.
    // Nápady jak toto lépe řešit uvítám v diskuzi.
    $c1 = date('j')+3;
    $c2 = date('N')+2;
    $s = $c1 + $c2;
    $form->addText('soucet', sprintf('Zadejte součet %s+%s *:', $c1, $c2))
    	->setRequired('Je třeba zadat součet jako ochranu proti SPAMu')
    	->addRule(Form::EQUAL, 'Je třeba zadat součet jako ochranu proti SPAMu', $s);
    $form->addHidden('c1', $c1);
    $form->addHidden('c2', $c2);
    $form->addSubmit('send', 'Odeslat');
     
    // zpracování formuláře po odeslání
    if ($form->isSuccess()) {
    	$val = $form->getValues();
    	$mail = new Message;
     
    	$from = ($val['mail'] == '') ? 'Z webu <web @nejaky-web.cz>' : $val['jmeno'] . ' < ' . $val['mail'] . '>';
    	$mail->setFrom($from)
    		->addTo('Info <info @nejaky-web.cz>')
    		->setSubject('Poptávka z webu')
    		->setBody(sprintf("Dobrý den,\nJméno: %s\nE-mail: %s\nTelefon: %s\nZájem o: %s\nPoznámka:\n%s", $val['jmeno'], $val['mail'], $val['tel'], $val['zajem'], $val['pozn']))
    		->send();
     
    	// nesouvisí s příkladem - vložíme poděkování
    	include $_SERVER['DOCUMENT_ROOT'] . '/templates/formular-odeslan.php';
    } else {
    	echo $form;
    }

    Vypíchnu raději bokem samotnou podstatu antispamového řešení:

    // antispam
    // Nelze řešit přes RAND, jelikož po odeslání by se nám hodnoty změnily, toto beru jako zajímavé "konstanty", které mají platnost jeden den.
    // Nápady jak toto lépe řešit uvítám v diskuzi.
    $c1 = date('j')+3;
    $c2 = date('N')+2;
    $s = $c1 + $c2;
    $form->addText('soucet', sprintf('Zadejte součet %s+%s *:', $c1, $c2))
    	->setRequired('Je třeba zadat součet jako ochranu proti SPAMu')
    	->addRule(Form::EQUAL, 'Je třeba zadat součet jako ochranu proti SPAMu', $s);
    $form->addHidden('c1', $c1);
    $form->addHidden('c2', $c2)

    Obslužný JS, který nám v případě zapnutého JS skryje antispamový prvek

    <script type="text/javascript">
    	document.getElementById("frm-soucet").value = parseInt(document.getElementById("frm-c1").value) + parseInt(document.getElementById("frm-c2").value);
    	document.getElementById("frm-soucet").parentNode.parentNode.style.display = "none"; // musíme se dostat až ke značce TR
    </script>

    Zamezní propagace submitu odeslání vnořeného formuláře

    Pokud potřebujeme vyvolávat submit událost vnořeného formuláře a zároveň omezit odeslání vnějšího, tak musíme použít následující postup.
    Pro názornost máme následující příklad:

    <form id="frm">
    	<!-- nějaké formulářové pole -->
    	<!-- kus HTML -->
    	<!-- následuje INPUT, který se odesílá pomocí AJAXu, jak na click, tak na klávesu enter -->
    	<input name="zprava" id="zprava" type="text" />
    	<input type="button" id="sb_submit" value="Odeslat" />
    	<!-- kus HTML -->
    </form>

    A pomocí následujícího JavaScriptu docílíme kýžené funkcionality.

    $(function() {
    	var enter = false;		// pomocná proměnná
    	$('#frm').submit(function(e) {
    		if (enter) {		// pokud byl stisknut enter v poli, které nesouvisí s hlavním formulářem (viz nastavení níže) ...
           			enter = false;	// ... proměnou vynulujeme pro další použití ...
           			return false;	// ... tak odeslání vnějšího formuláře neprovádíme
    		}
    	});
     
    	// odeslání na stisk klávesy enter
    	$('#zprava').keydown(function(e) {
    		if (e.keyCode == 13) {	// došlo ke zmáčknutí klávesy enter
    			enter = true;	// nastavíme pomocnou proměnou na TRUE
    			send();		// odešleme data
    		}
    	});
     
    	// odeslání na událost onClick
    	$('#sb_submit').click(function(e) {
    		send();
    	});
    });

    Jak neotravovat uživatele s antispamem?

    Známe to všichni. Chceme se registrovat na nějaký web, jít do internetového bankovnictví, odeslat objednávku v eshopu, přispět do diskuze a vyskočí na nás jen těžko čitelná slátanina různě pokrouceného textu. Ano první popisovaná možnost je dneska velmi oblíbená captcha.
    Captcha

    A světe div se. Ve většině případů je toto řešení zbytečné a příliš obtěžující… Jaké má dneska vývojář další možnosti? Existuje možnost zabránit SPAMu a zároveň, aby to uživatele nijak neobtěžovalo? Zkusím projít dneska běžně používané řešení a pak odpovědět na položené otázku.

    Polidštěné antispamy, vyžadující interakci uživatele

    Vyžádání si opisu textu:
    Antispam opis textu
    Vybrání odpovídající možnosti:
    Antispam výběr dne.
    Vybrání odpovídajícího obrázku:
    Antispam select images
    Nicméně tyto antispamy opět vyžadují spolupráci uživatele a s nadsázkou i jisté znalosti.

    Další metodou je na komentáře nasadit nějaký klasický antispam, jaký známe například z emailů. Tuto možnost využívá například i plugin Akismet pro publikační systém WordPress (používá ho i tento blog). Tento systém funguje na principu, že nebrání spamovacím robotům v tom příspěvek založit (což chválím – uživateli nehází klacky pod nohy), ale následnou analýzou se snaží identifikovat, zda příspěvek zobrazí či ne. Tady je ale na druhou stranu potřebná interakce administrátora, což může být na serveru, který je v centru dění dost obtěžující.
    Wordpress Akismet

    Dokonalé antispamové řešení
    Využijeme základu z prvního polidštěného příkladu:
    Antispam opis textu
    HTML:

    <p id="antispam">
        Ochrana proti spamu. Napište prosím číslo dvacet-čtyři: 
        <input type="text" name="robot" value="" id="antispaminput"/>
    </p>

    Ale doplníme to následujícím Javascriptovým kódem:

    document.getElementById("antispaminput").value = "24";
    document.getElementById("antispam").style.display = "none";

    případně v jQuery:

    $("antispaminput").val(24);
    $("antispam").css('display', 'none');

    ten způsobí, že se pole automaticky vyplní a zároveň skryje. Uživatel má pocit, že žádný antispam neřeší, ale na pozadí ho za něho řeší prohlížeč. Pokud ale uživatel (prohlížeč) nepodporuje Javascript (vlastnost webových robotů), tak mu políčko zůstane zobrazeno a musí touto kontrolou projít.

    Proč tedy je tak moderní „otravovat“ uživatele luštěním a vyplňováním pokřivených znaků?

    Automatické dotahování údajů o podnikatelích z databáze ARES

    Někde na internetu jsem viděl jak po zadání IČ se zbytek údajů o živnostníkovi/firmě dotáhl sám. A jelikož jsem si chtěl o tuto možnost rozšířit i své personální účetnictví, tak jsem pátral jak na to.

    O databázi ARES jsem se dozvěděl již dříve, ale nikdy jsem se nedostal k samotné implementaci. Až dneska jsem narazil na článek Radka Hulána, řešící přesně toto a tak jsem si řekl, že se na to podívám.

    Zdroj dat: Databáze ARES
    Script: MyEGO blog

    Script po úpravě na straně serveru (jedná se o NETTE akci):

    public function handleLoadInfo($IC) {
    	$this->payload->firma = array();
        	// dá se vybrat hned z několika zdrojů dle potřeby http://wwwinfo.mfcr.cz/ares/ares_xml.html.cz#k3
    	define('ARES','http://wwwinfo.mfcr.cz/cgi-bin/ares/darv_bas.cgi?ico=');
    	$ico = intval($IC);
    	// nemohl jsem použít kvůli omezení na serveru, nahradil jsem pomocí CURL
    	//$file = @file_get_contents(ARES.$ico);
    	if ($curl = curl_init(ARES.$ico)) {
    		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    		$content = curl_exec($curl);
    		//$info = curl_getinfo($curl);
    		curl_close($curl);
    		$xml = @simplexml_load_string($content);
    	}
    	$a = array();
    	if (isset($xml)) {
    		$ns = $xml->getDocNamespaces();
    		$data = $xml->children($ns['are']);
    		$el = $data->children($ns['D'])->VBAS;
    		if (strval($el->ICO) == $ico) {
    			$a['ico'] 	= strval($el->ICO);
    			$a['dic'] 	= strval($el->DIC);
    			$a['firma'] = strval($el->OF);
    			$a['ulice']	= strval($el->AA->NU).' '.strval($el->AA->CD).'/'.strval($el->AA->CO);
    			$a['mesto']	= strval($el->AA->N).'-'.strval($el->AA->NCO);
    			$a['psc']	= strval($el->AA->PSC);
    			$a['stav'] 	= 'ok';
    		} else {
    			$a['stav'] 	= 'IČ firmy nebylo nalezeno';
    		}
    	} else {
    		$a['stav'] 	= 'Databáze ARES není dostupná';
    	}
    	$this->payload->firma = $a;
    	$this->sendPayload();
    }

    Script po úpravě na straně uživatele:

    <script type="text/javascript">
        <!--
    	$('#frmkontakt-IC').change(function(event) {
    		$.getJSON({link loadInfo!}, {'IC': $('#frmkontakt-IC').val()}, function(payload) {
    			if (payload.firma.stav == 'ok') {
    				$('input[name=DIC]').val(payload.firma.dic);
    				$('input[name=prijmeni]').val(payload.firma.firma);
    				$('input[name=ulice]').val(payload.firma.ulice);
    				$('input[name=mesto]').val(payload.firma.mesto);
    				$('input[name=psc]').val(payload.firma.psc);
    			} else {
    				alert(payload.firma.stav);
    			}
    		});
    	});
    	-->
    </script>

    Chtělo by to ještě doladit o podmínky kdy co a jak vypisovat, spojovat (číslo orientační a popisné, město a čtvrť, atd.), ale jako referenční implementace to je dobrý základ.

    Validní náhrada target=“_blank“ v xHTML

    Čím nahradit klasický odkaz s otevíráním do nového okna?

    Validní zápis v HTML, ale nevalidní v xHTML :(

    <a href="http://jankocmanek.cz/" target="_blank">jankocmanek.cz</a>

    Já na toto používám JavaScript, lépe řečeno jQuery knihovnu, která smazává rozdíly mezi interpretací jednotlivých konstrukci napříč prohlížeči.

    ...
    <script type="text/javascript" src="jquery-1.3.2.min.js"></script>
    <script type="text/javascript">
    $(function(){
        $("a[href^='http://']").click(function() {
            return!window.open(this.href,'_blank');
        });
    });
    </script>
    ...
    <a href="http://jankocmanek.cz/">jankocmanek.cz</a>

    Proč to vypadá takto se dozvíte v dokumentaci jQuery, sekce selectory.