Martin Cohen Intype, dizajn, vývoj a somári Odoberať RSS

Kategória: Web

Sága o inštalácii YUIDoc

Ani som nechcel tento článok napísať, lebože iba keď si tým obhyzdným peklom jeden prejde, pochopí že stav alarmujúci jest.

YUIDoc je semä hada britského, čiže potrebujete Python. Okrem toho jačí po 4 daľších knižniciach. Bez command prompt cez nasledovné neprejdete.

Python 2.6

  1. Stiahnite si Python 2.6.5 Windows installer
  2. Nainštalujte. Doporučujem nemeniť cieľovú cestu a horko prijať čo má inštalátor prednastavené, inak sa môžete dostať do slušných sračiek.
  3. Do PATH si pridajte C:\Python26 a C:\Python26\Scripts.

setuptools

setuptools je balíček, ktorý zjednodušuje sťahovanie a inštaláciu ostatných balíčkov pre Python.

  1. Stiahnite si setuptools-0.6c11.win32-py2.6.exe. Bacha aby ste fakt stiahli verziu py2.6, inak budú problémy.
  2. Nainštalujte.

Ostatné závislosti pre YUIDoc

  1. Spustite command prompt a postupne nainštalujte každý z nasledujúcich balíčkov. Pokiaľ by vám systém protestoval, že použitý easy_install nevie nájsť, skúste nasledové spúšťať z adresára C:\Python26\Scripts.
  2. easy_install Pygments
  3. easy_install SimpleJSON
  4. easy_install Cheetah

Mne v bode 4. Cheetah zlyhal na tom, že si nevedel nájsť práve stiahnutý inštalátor pre Markdown:

...
Downloading http://sourceforge.net/projects/python-markdown/files/markdown/2.0.3/Markdown-2.0.3.win32.exe/download
Processing download
error: Couldn't find a setup script in c:\docume~1\martin~1.bal\locals~1\temp\easy_install-ad29ft\download

Pre istotu som teda Markdown stiahol a nainštaloval samostatne. Sám netuším či to má význam.

YUIDoc

Stiahnite si YUI Doc. Niekam ho rozbaľte (ideálne keď cesta nebude obsahovať medzery v názvoch súborov). Ja mám napríklad adresár D:\work\libraries kde mám rôzne podobné taľafatky. Z neho mám urobený samostatný disk takto:

subst L: D:\work\libraries

Baťák sa mi spúšťa po štarte, takže L: mám vždy po ruke.

YUIDoc má v sebe ukážkový spúšťačno-konfigurujúci L:\yuidoc\bin\example.bat ktorý si je potrebné niekam skopírovať a upraviť podľa potreby. A pretože YUIDoc vo verzii 1.0.0b1 používa deprecated modul Sets som si urobil ešte malú úpravu na poslednom riadku, ktorá zakáže veselé DeprecatedWarning ňuf-ňuf správičky. Tu máte môj generate.bat:

@ECHO OFF

REM ##########################################################################

REM The location of your yuidoc install
SET yuidoc_home="l:\yuidoc"

REM The location of the files to parse.  Parses subdirectories, but will fail if
REM there are duplicate file names in these directories.  You can specify multiple
REM source trees:
REM      SET parser_in="c:\home\www\yahoo.dev\src\js c:\home\www\Event.dev\src"
SET parser_in=""

REM The location to output the parser data.  This output is a file containing a
REM json string, and copies of the parsed files.
SET parser_out="..\..\temp\doc"

REM The directory to put the html file outputted by the generator
SET generator_out="..\..\dist\doc"

REM The location of the template files.  Any subdirectories here will be copied
REM verbatim to the destination directory.
SET template="%yuidoc_home%\template"

REM The project version that will be displayed in the documentation.
SET version="1.0.0"

REM The version of YUI the project uses.
SET yuiversion="2"

python -W ignore::DeprecationWarning %yuidoc_home%\bin\yuidoc.py %parser_in% -p %parser_out% -o %generator_out% -t %template% -v %version% -Y %yuiversion%

Popis jednotlivých parametrov je v dodávke celkom jasný. Pre úplnosť uvediem ešte štruktúru môjho projektu:

  • dev\js Obsahuje moje JS súbory a aj uvedený generate.bat, ktorý z toho adresára spúšťam (bacha, uvedené cesty sú relatívne k tomuto adresáru).
  • dist\doc Sem sa mi vyleje dokumentácia v HTML.
  • temp\doc Sem tratí YUIDoc dočasné súbory.

Mľaskavo vychutnávajte.

JavaScript zvnútra 1/4: Dedičnosť objektov

Veľa zmätku nastalo okolo JavaScriptu. Jeho neobyčajné vlastnosti veľa nás radšej ignoruje, akoby mali pariť uzlinami. Našli sme si miesto toho zázračné formulky, ktoré nám pomáhajú priepasť prekonávať. Navyše, množstvo zdrojov uvádza nekompletné, či dokonca nesprávne postupy. Špecifikácia nie je veľkým pomocníkom a k tomu všetkému sú tu rozdiely medzi implementáciami.

Všetci vieme:

  • JavaScript má prototypovú dedičnost.
  • Na dedenie je vlastnosť prototype.
  • Na inštancovanie objektu používame funkcie, ktoré sa podobajú ako na triedy, tak na konštruktory.

a strácame sa:

  • Čo je to prototypová dedičnost?
  • Akú úlohu hrá vlastnosť prototype v dedičnosti?
  • Ako funguje inštancovanie objektu z konštruktora?

Dedičnosť medzi objektami

Prototypová dedičnost, byť termín nesprávny, vhodný sťa metafora jest. (Používať budem i termíny ako napríklad „trieda“, ktoré nie sú tak celkom správne v kontexte JavaScriptu).

Na spodku zázrakov JavaScriptu je dedičnosť medzi objektami (nemýliť s triedami). Na to aby sme pochopili ako funguje dedenie tried, je dobré vedieť ako môže jeden objekt dediť od druhého. Príklad:

var fruit = { taste: "sweet" };
var apple = { color: "red" };

// Čil zázrak snaň sa!

alert( apple.taste ); // => "sweet"

Zázrak, ktorý sa musí stať je prepojenie objektov apple a fruit. Čiže ak sa spýtam na apple.taste, JavaScript musí vedieť, že ak taste nie je definovaná pre apple tak sa musí pozrieť na fruit.

Existuje vlastnosť každého objektu v JavaScripte, o ktorej nám súčasné implementácie viac-menej mlčia. Všetci sme už počuli o vlastnosti prototype, málo je však počut o __proto__. Je to preto, že __proto__ je v špecifikácii ECMAScript 262 označená ako interná (skrytá) a nemali by sme teda na ňu ako programátori šahať. (Špecifikácia hovorí o tejto vlastnosti ako o [[Prototype]]).

I napriek tomu dve JavaScriptové implementácie (SpiderMonkey od Mozilly a V8 od Google) ju sprístupňujú a pomenúvajú __proto__ (budem teda používať toto pomenovanie). Rád by som tu zdôraznil, že ide o neštandardnú internú vlastnosť, ale nám veľmi dobre poslúži na pochopenie toho čo sa v JavaScripte de­je.

Oný zázrak je teda v tom, že apple.__proto__ nastavíme na fruit:

var fruit = { taste: "sweet" };
var apple = { color: "red" };

apple.__proto__ = fruit;

alert( apple.taste ); // => "sweet"

→ Vyskúšajte

Objekt apple dedí od fruit, vďaka vlastnosti __proto__. Ak sa spýtame na hodnotu vlastnosti taste, JavaScript sa ju pokúsi nájsť na objekte apple. Ak ju objekt apple nemá, mrkne sa do objektu apple.__proto__, ak ani tam nič, tak apple.__proto__.__proto__atď. V našom prípade sa zastaví na apple.__proto__, pretože ukazuje na objekt fruit a ten vlastnosť taste má.

Ak chcem objektu apple zmeniť chuť na "sour", nič mi nebráni. Objekt fruit bude stále sladký:

apple.taste = "sour";
alert( apple.taste ); // => "sour"
alert( fruit.taste ); // => "sweet"

→ Vyskúšajte

V tomto momente apple dostáva vlastný taste a JavaScript už nemusí snoriť po __proto__ aby ju našiel.

Je dôležité si uvedomiť, že s __proto__ sa za normálnych okolností nestretneme. Budeme dokonca nútení ho nepoužívať, pretože nie je definovaný vo všetkých implementáciách. V tejto sérii slúži hlavne na vysvetlenie vnútorných pochodov v JavaScripte.

Ďalšia časť:

JavaScript zvnútra 2/4: Konštruktory

Tento článok je pokračovaním série o dedičnosti v JavaScripte:

Predsa však, bežnejšia, dostupnejšia a bezpečnejšia forma dedičnosti ako tá čisto objektová je pomocou konštruktorov. Kým sa dostanem k samotnej dedičnosti, nutno jest pochopiť konštruktory.

Konštruktor je objekt triedy Function, teda funkcia:

function Fruit( color )
{
  this.color = color;
}

var apple = new Fruit( "red" );

alert(apple.color); // => "red"

→ Vyskúšajte

Tým sme vytvorili objekt apple, inštanciu Fruit, ktorý má vlastnosť color nastavenú na red. Za operátorom new sedí kus kódu, ktorý okrem iného zavolá funkciu Fruit tak, že jej nastaví this na apple. Asi takto:

// Vytvorí obyčajný objekt
var apple = new Object();
// Zavolá nad ním metódu Fruit
Fruit.call( apple, "red" );

alert( apple.color ); // => "red"

→ Vyskúšajte

Pomocou konštruktora teda pripravíme objekt tým, že mu nastavíme základné vlastnosti. (Špecifikácia ECMAScript 262 tento proces popisuje detailne v sekcii 13.2.2.)

Metódy

Pridajme metódu yellColor, ktorá zareve farbu. Prvé čo nás napadne je:

function Fruit( color )
{
  this.color = color;
  this.yellColor = function() // Toto je fakt že zle
  {
    alert( this.color );
  };
}

var apple = new Fruit( "red" );

apple.yellColor(); // => "red"

→ Vyskúšajte

Kód nám síce funguje, nie že nie. Predstavme si ale, že chceme vytvoriť celé vrece červeného ovocia. Povedzme takých 100ks:

var bag = [];
for( var i = 0; i < 100; i++ )
{
  bag.push( new Fruit( "red" ) );
}

Pre každú jednu inštanciu vytvoríme jeho vlastnú metódu, čím si úspešne zahrávame s časom a nárokmi na pamäť. Skúsme si rozpísať čo sa vlastne deje:

var bag = [];
for( var i = 0; i < 100; i++ )
{
  var apple = new Object();
  apple.color = "red";
  apple.yellColor = function()
  {
    alert( this.color );
  }

  bag.push( apple );
}

Vytvárať kvôli 100ks ovocia 100ks metód je celkom luxus, ktorý si môžeme dovoliť iba málokedy. A nie je to len o rýchlosti a pamäti. Ak by sme takýto kód nechali v našej knižnici a pre jeden z desiatich projektov by sme potrebovali vypisovať farbu ovocia napríklad do konzoly (console.log), neostáva nám iba vytvoriť novú vetvu kódu s iným konštruktorom.

Riešením je definovať metódy na prototype konštruktora (v ďalšej časti).

Ďalšie časti:

JavaScript zvnútra 3/4: Prototyp konštruktora

Tento článok je pokračovaním série o dedičnosti v JavaScripte:

Oveľa lepšie, ako pchať metódy priamo do konštruktora, je na to využiť jeho vlastnosť prototype. Robí sa to takto:

function Fruit( color )
{
  this.color = color;
}

Fruit.prototype.yellColor = function()
{
  alert( this.color );
};

var apple = new Fruit( "red" );
apple.yellColor(); // => "red"

→ Vyskúšajte

Každá funkcia má vlastnosť prototype. Pri inštancovaní operátorom new JavaScript nastaví novému objektu jeho spomínanú vlastnosť __proto__ na prototype konštruktora. Čiže na pozadí volania var apple = new Fruit( "red" ); sa udeje niečo takéto:

// Vytvorí obycajný objekt
var apple = new Object();
// Nastaví __proto__ na prototyp konštruktora
apple.__proto__ = Fruit.prototype;
// Zavolá nad apple metódu Fruit
Fruit.call(apple, "red");

apple.yellColor(); // => "red"

→ Vyskúšajte

Metóda yellColor() nie je nastavená priamo inštancii, a preto sa JavaScript pozrie na jeho __proto__, ktorý ukazuje na Fruit.prototype a tam ju bezpečne nájde a vykoná.

V príklade z minulej časti sme ukazovali na problém 100ks ovocia. Ak to skúsime teraz, uvidíme, že funkcia yellColor() je iba jedna, pre všetky inštancie spoločná:

Ak by sme chceli prinútiť všetky inštancie vypisovať svoje farby do konzoly, stačí zmeniť prototyp konštruktora, trebárs aj v inej knižnici, či v projektovo-závislom kóde:

Fruit.prototype.yellColor = function()
{
  console.log(this.color);
}

apple.yellColor(); // => "red" ale tentokrát už do konzoly

→ Vyskúšajte

V ďalšej časti o tom ako funguje dedičnosť medzi triedami.

Ďalšie časti:

JavaScript zvnútra 4/4: Dedičnosť medzi triedami

Tento článok je pokračovaním série o dedičnosti v JavaScripte:

Ako vyrobiť triedu Apple, ktorá bude dediť od Fruit? Vieme ako bude vyzerať Fruit a zhruba ako Apple:

function Fruit( color )
{
  this.color = color;
}

Fruit.prototype.yellColor = function()
{
  alert( this.color );
}

function Apple( color )
{
  // Zavoláme konštruktor Fruit, aby inštancii nastavil farbu
  Fruit.call( this, color );
}

var apple = new Apple("red");
apple.yellColor();
// Uncaught TypeError:
// Object #<an Apple> has no method 'yellColor'

A teraz ako to spojiť? Chceme aby objekt vytvorený triedou Apple videl na metódu Fruit.prototype.yellColor(). Budeme navzájom prepájať prototype vlastnosti. Niekoho môže napadnúť toto:

Apple.prototype = Fruit.prototype;

Lenže v tom prípade by sme prídávaním, či úpravou Apple.prototype priamo prepisovali aj Fruit.prototype a to nechceme. V prvej časti sme použili __proto__, to môžeme aj teraz:

// Čokoľvek definované vo Fruit.prototype bude
// viditeľné i v Apple.prototype
Apple.prototype.__proto__ = Fruit.prototype;

→ Vyskúšajte

Ale ako bolo písané v prvej časti tiež: __proto__ nie je štandardnou súčasťou implementácii. Vieme ho ale simulovať tak, že medzi Apple a Fruit strčíme ešte jeden pomocný konštruktor, jeho prototyp a inštanciu:

// Vytvoríme pomocný primitívny konštruktor `Q`
function Q() {};
// Jeho prototyp nastavíme na prototyp rodičovskej triedy `Fruit`
Q.prototype = Fruit.prototype;
// A prototyp detskej triedy nastavíme na novú inštanciu triedy `Q`
Apple.prototype = new Q;
// Opravíme referenciu na konštruktor (inak by ukazovala na Q)
Apple.prototype.constructor = Apple;

→ Vyskúšajte

Diagram síce vyzerá hnusoprskne, ale v skutočnosti je tých krokov podstatne menej. K Fruit.prototype sa totiž JavaScript dostane už v druhom kroku: (new Q).__proto__, pretože (new Q).__proto__ == Q.prototype == Fruit.prototype.

Keď rozpíšeme riadok Apple.prototype = new Q; podľa toho čo už o operátore new vieme, zistíme, že JavaScript nám vlastnosť __proto__ nastaví tak ako by sme radi:

function Q() {};
Q.prototype = Fruit.prototype;
Apple.prototype = new Object();
Apple.prototype.__proto__ = Q.prototype;

→ Vyskúšajte

Treba si dávať pozor iba na to, že tento kód nám prepíše celý Apple.prototype a preto je dôležité ho volať predtým ako začneme do neho nastavovať metódy. Celokus, kde Apple dedí od Fruit bez použitia __proto__ vypadá takto:

function Fruit( color )
{
  this.color = color;
}

Fruit.prototype.yellColor = function()
{
  alert( this.color );
}

function Apple( color )
{
  // Zavoláme konštruktor Fruit, aby inštancii nastavil farbu
  Fruit.call(this, color);
}

// Vytvoríme pomocný primitívny konštruktor `Q`
function Q() {};
// Jeho prototyp nastavíme na prototyp rodičovskej triedy `Fruit`
Q.prototype = Fruit.prototype;
// A prototyp detskej triedy nastavíme na novú inštanciu triedy `Q`
Apple.prototype = new Q;
// Opravíme referenciu na konštruktor (inak by ukazovala na Q)
Apple.prototype.constructor = Apple;

Apple.prototype.fallOnNewtonsHead = function()
//...

Pochopiteľne je možné si napísať jednoduchú funkciu, ktorá dedenie urobí krajšie. Takto:

function extends( Child, Parent )
{
  function Q() {};
  Q.prototype = Parent.prototype;
  Child.prototype = new Q;
  Child.prototype.constructor = Child;
}

extends( Apple, Fruit );

var apple = new Apple("red");
apple.yellColor(); // => "red"

→ Vyskúšajte

Príklad funguje i keď inštancia apple nemá zadefinovanú metódu yellColor(). Tá je definovaná až na triede Fruit. JavaScript si ju však veselo nájde postupným prechádzaním __proto__:

// JS sa najprv pozrie na objekt apple
apple
// Ak tam nie je, tak na jeho __proto__, ktoré ukazuje na Apple.prototype a to na q.prototype
apple.__proto__            = Apple.prototype
// Ak tam nie je, tak na jeho __proto__, ktoré ukazuje na Q.prototype a to zase na Fruit.prototype
apple.__proto__.__proto__  = Apple.prototype.__proto__ = Q.prototype = Fruit.prototype

Celé to však nie je iba o tom, aby JavaScript vedel danú vlastnosť nájsť. Ide aj o možnosť zistiť o inštanciu akej triedy ide. Na to slúži operátor instanceof. Objekt apple teda bude inštanciou ako Apple, tak Fruit:

// Je apple inštanciou Apple?
alert( apple instanceof Apple ); // => true
// Je apple inštanciou Fruit?
alert( apple instanceof Fruit ); // => true

→ Vyskúšajte

V súčasnosti už existuje množstvo článkov o tom, ako si zjednodušiť dedenie, či používať kopu ďalších pekných a užítočných postupov známych z iných jazykov. Úlohou tohto článku bolo odkryť čo sa deje pod kapotou. Ostatné je už na vašej chuti.

Doporučujem sa mrknúť na nedávnu trojsériu od Daniela Steigerwalda na Zdrojáku.

Predchádzajúce časti:

Intoru Forms: ElasticContainer

Jednou z vecí na ktorú som sa tešil pri implementácii Intoru Forms je práve ElasticContainer (asi dočasný názov). V Nette totiž nie je možné urobiť kontajner s dynamickým počtom polí (ochrchlať sa to dá, ale je to škaradé).

Prvým príkladom budiž prílohy. Ak chcem dať užívateľovi možnosť pridať niekoľko príloh do formuláru, neviem vopred počet políčok, ten sa nastaví až u klienta. ElasticContainer to rieši tak, že svoje detské políčka nastaví až pri prijatí hodnôt. Každé políčko je klon nejakého vopred definovaného poľa – tzv. prototypu.

Ak chcem prílohy, urobím:

$form->add( 'files', new ElasticContainer( new File ) );

Ak chcem tagy, urobím:

$form->add( 'tags', new ElasticContainer( new String ) );

Ak chcem na prototype validácie, urobím validácie na prototype:

$form->add( 'emails', new ElasticContainer( new String ) )
  ->getPrototype()
    ->validates('email');

Validátorom count nad ElasticContainer môžem obmedziť počet políčok:

$form->add( 'emails', new ElasticContainer( new String ) )
  ->validates( 'count', 3, 10 )
  ->getPrototype()
    ->validates('email');

Hodnoty získam a nastavím volaním get/setValue:

$c = $form->add( 'tags', new ElasticContainer( new String ) );
//...
$c->setValue( array('apple', '', 'juice', NULL, 'banana') );
//...
$c->getValue(); // => array('apple', 'juice', 'banana')

Šablona je potom jednoduchá:

{foreach $container as $field}
  {form:text $field}
{/foreach}

Vypíše všetky nastavené políčka, minimálne a maximálne však toľko koľko sa nastavilo cez ElasticContainer::setMinimum/setMaximum alebo cez $container->validates( 'count', $minimum, $maximum ).

Menej ukecané formuláre v Nette

Centi dnes dostal nápad na vylepšenie nášho FormHelper na vykreslovanie Intoru formulárov v Nette. A myslím, že to bol dobrý nápad. Povážte: doteraz sme boli nútení opakovane vymenovávať pre ktoré políčko ideme vykreslovať popisok, chybky a samotný widget:

{form $form}
  {form:label $form['document']['title']}Titulok{/form:label}
  {form:error $form['document']['title']}
  {form:text $form['document']['title'], 'width' => '100%'}
{/form}

Po novom sa veci značne zjednodušujú, vďaka párovému Latte helperu {form:with ...} a pár ďalším novinkám:

{form $form}

  {form:label 'document/title' }
  {form:error 'document/title' }
  {form:text  'document/title', 'width' => '100%'}

  {* --- alebo --- *}

  {form:with 'document/title'}
    {form:label}
    {form:error}
    {form:text 'width' => '100%'}
  {/form:with}

  {* --- alebo --- *}

  {form:with 'document'}
    {form:label 'title'}
    {form:error 'title'}
    {form:text  'title', 'width' => '100%'}
  {/form:with}

  {* --- alebo --- *}

  {form:with 'document'}
    {form:with 'title'}
      {form:label}
      {form:error}
      {form:text 'width' => '100%'}
    {/form:with}
  {/form:with}

{/form}

Všetky varianty sa dajú miešať jedna cez druhú a použiť to čo príde lepšie. Tu je ukážka kúsku z editora užívateľa:

{form:with 'email'}
  <tr>
    <th class="w-min">{form:label}E-mail:{/form:label}</th>
    <td>
      {form:error 'class' => 'mb-s w-text'}
      {form:text 'width' => '30em'}
    </td>
  </tr>
{/form:with}

<tr>
  <th class="w-min va-t">{form:label 'password'}Password{/form:label}</th>
  <td>
    <div class="mb-s">
      {form:error 'password'}
      {form:password 'password', 'width' => '15em', 'autocomplete' => 'off'}
    </div>
    <div>
      {form:error 'password_confirmation'}
      {form:password 'password_confirmation', 'width' => '15em', 'autocomplete' => 'off'}
    </div>
  </td>
</tr>

Inakšie Formuláre v Nette

Nájsť recept na správnu, rozširovateľnú a relatívne pohodlnú implementáciu formulárového modulu dá fakt zabrať. Pre Nette ujo Grudl síce vykročil, ale ja som to skúsil inak. Z fleku exámpl:

$document = new Container;
$document['title'] = new String;
$document['body'] = new Text;

Formulár z tohto pohľadu je definícia hodnôt a ich validácii. Ako si pozorní určite všimli, formulár nedefinuje názvy políčok, ani atribúty ako class, id, rows či cols. To všetko nechávam na šablonku. Čo nás zaujíma sú typy hodnôt ktoré očakávame: polia, reťazce, dátumy, súbory, atp. Nad týmito primitívnymi typmi následne fungujú validácie a filtre.

Hodnoty

Hodnoty sa čítajú z poľa hodnôt a je im jedno či je to POST, databáza, súbor alebo obyčajné pole. Na každom políčku je k dispozícii dvojička metód getValue a setValue, ktoré pracujú s obyčajnými poľami.

Integrácia s Nette

Klasickú formulárovú funkčnosť a integráciu do Nette zabezpečuje doplnková trieda Form. Form rieši komunikáciu s prezentérom, získavanie a distribúciu HTTP dát do políčok, nastavovanie action, či method atribútov. Form v sebe zapúzdruje inštanciu triedy Container, čiže zvonku sa javí prirodzene:

$form = new Form;
$form['document'] = new Container;
$form['document']['title'] = new String;
$form['document']['body'] = new Text;

if( $form->isSubmitted() )
{
        if( !$form->hasErrors() )
        {
                // Save data
        }
}
else
{
        $form['document']->setValue( array
        (
                'title' => 'Default title',
                'body' => 'Default body'
        ));
}

Šablony

Na zjednodušenie práce mám FormHelper, ktorý drobnosti so šablonou rieši za mňa. V žiadnom prípade sa však nesnaží definovať niečo navyše, výstupom sú holé políčka s nastavenými tými najnutnejšími atribútmi:

{widget:label $form['document']['title']}Titulok{/widget:label}
{widget:message:error $form['document']['title']}
{widget:text $form['document']['title'], 'width' => '100%'}

{widget:label $form['document']['body']}Body{/widget:label}
{widget:message:error $form['document']['body']}
{widget:text:area $form['document']['body'], 'rows' => 5, 'cols' => 40}

Až v šablone sa priraďuje políčku jeho vzhľad, spôsob rozloženia prvkov. Je to síce pracnejšie ako s ConventionalRenderer z Nette Forms, ale zato máte plnú voľnosť. FormHelper tiež zverejňuje funkcie na generovanie `name, id, style, ktoré sa dajú ľahko využiť pre písanie vlastných widgetov.

Políčka

Okrem obligátnych skalárnych, modul má aj komplikovanejšie políčka. Jedným z nich je ElasticContainer a pomôže ak UI vyžaduje pridávať vopred neurčený počet príloh, e-mailov, alebo tagov (každý v samostatnom políčku).

$form['emails'] = new ElasticContainer( function() {
        $prototype = new String;
        $prototype->validates( 'email' );
        return $prototype;
});

Základná sada políčok by mala stačiť na všetko, ak však chcete, nič vám nebráni si nadefinovať vlastnú triedu ktorá dedí od Field.

Validácie

Validácie to vie samozrejme tiež:

$form->validates( 'children', array
(
        'document/title' => array
        (
                'presence' => true,
                'length' => array( 'minimum' => 3 )
        ),

        'document/body' => array
        (
                'presence' => true
        )
));

Validácie je možné viazať na rodičovské, ale aj na detské políčka. Horný príklad je možné zapísať hneď niekoľkými spôsobmi:

// Naviazanim na 'document'; rodica 'title' a 'body' policok

$form['document']->validates( 'children', array
(
        'title' => array
        (
                'presence' => true,
                'length' => array( 'minimum' => 3 )
        ),

        'body' => array
        (
                'presence' => true
        )
));

// --- alebo naviazanim na samotne policko s pouzitim pola

$form['document']['title']->validates( array
(
        'presence' => true,
        'length' => array( 'minimum' => 3 )
));

$form['document']['body']->validates( array
(
        'presence' => true
));

// --- alebo postupnym volanim metody validates

$form['document']['title']
        ->validates( 'presence' )
        ->validates( 'length', array( 'minimum' => 3 ) );

$form['document']['body']
        ->validates( 'presence' );

Modul so sebou nesie niekoľko základných validátorov (presence, length, format, email, url, custom, children,…), a je samozrejme možné si dodefinovať vlastné. Mapa string → validátor je definovaná v triede Validator\Registry. Ak si chcete pridať vlastný, stačí vytvoriť funkciu a zaregistrovať ju:

$form['password'] = new Container;
$form['password']['first'] = new String;
$form['password']['second'] = new String;

function validatesPasswordConfirmation( $field, $options )
{
        if( $field['first']->getValue() != $field['second']->getValue() )
        {
                $field->addError( 'Passwords do not match.' );
                return false;
        }
        return true;
}

Validator\Registry::register( 'password_confirmation', 'validatesPasswordConfirmation' );

$form['password']->validates( 'password_confirmation' );

Registrovať sa dá aj lambda funkcia:

Validator\Registry::register( 'password_confirmation', function( $field, $options )
{
        if( $field['first']->getValue() != $field['second']->getValue() )
        {
                $field->addError( 'Passwords do not match.' );
                return false;
        }
        return true;
});

Ak potrebujete špeciálnu validáciu, možete použiť lambda funkciu priamo:

$form['password'] = new Container;
$form['password']['first'] = new String;
$form['password']['second'] = new String;

$form['password']->validates( function( $field )
{
        if( $field['first']->getValue() != $field['second']->getValue() )
        {
                $field->addError( 'Passwords do not match.' );
                return false;
        }
        return true;
});

Celý vtip je v tom, že si validačné pravidlá naviažete tam kde potrebujete. V tomto prípade zapúzdrujem obe heslá do jedného kontajneru a tým pádom si môžem zjednodušiť validáciu. Nerobí mi ale problém to urobiť aj bez kontajnéru.

Čo s tým?

Modul nie je zatiaľ verejný, keďže ho nemám plne nasadený a ustálený. Rád by som zistil, či sa aspoň niekomu zdá byť úžitočný. Mne to už teraz ušetrilo kopu nervov.

Google Reader: Pošlite ich všetkých do!

Fičúrka Google Reader-u Send To je podobná ako oné … FeedFlares od FeedBurneru; na rozdiel od nej však pridáva akcie pre vás a ku všetkému čo čítate. Vyzerá to ako toto:

Ak to chcete, tak to máte v Settings → Send To, v úvode je celkom fajnová ponuka (aj Twitter tam je), a úplne dolu, milí moji, tak úplne dolu je odkaz Create a custom link a ten oklikajte. No a pre pridanie napríklad Evernote vyplňte onen formulárik nasledovne:

Name
Evernote
URL
http://s.evernote.com/grclip?url=${url}&title=${title}
Icon URL
http://www.evernote.com/favicon.ico

Lifehacker.com má podobných odkazov hojno, tak si choďte!

RSS: Nakŕmťe si RSS-ko sociálnym žiarením

FeedBurner skrz Google je môj lokaj už niekoľko blogov. Že mu ostanem pánom i naďalej potvrdzuje jeho riešenie môjho problému: ako pridať k článkom v RSS odkazy na komentáre a prípadné sociálne zariadenia typu Twitter či menej obľúbený Facebook; Žrádlopálič tieto nazýva Žrádložiary alebo aj FeedFlares.

Vo FeedBurner-i je táto možnosť ukrytá pod Optimize → FeedFlare. Tam nájdete necelú dvadsiatku oficiálných fakieľ a keby sa vám málilo, záľaha ich je v katalógu či inde. A keby ani to nezasýtilo, môžete si vytvoriť svoje vlastné, ako ja.

FeedFlare je kratučký XML dokument. Na odoslanie článku na Twitter s použítím služby TwitThis.com to máte takto:

<FeedFlareUnit>
        <Catalog>
                <Title>Poslať na Twitter</Title>
                <Description>Poslať na Twitter cez TwitThis</Description>
        </Catalog>
        <FeedFlare>
                <Text>Poslať na Twitter</Text>
                <Link href="http://twitthis.com/twit?url=${link}&amp;title=${title}"/>
        </FeedFlare>
</FeedFlareUnit>

XML dokument šupnite niekam na web. Tento môj je k dispozícii na

http://tools.martincohen.info/feed_flares/sk-SK/twit_this.xml

V nastaveniach na FeedBurner-i (Optimize → FeedFlare) vložte URL do políčka pod zoznamom:

Pomágajte tlačítko Add New Flare:

Prvé zaškrtávatko je pre povolenie zobrazenia v RSS feede (In Feed), to druhé je pre zobrazenie vo widgete (On Site), ktorý si môžete nechať vygenerovať dolu na stránke. Zaškrťte príslušné políčko (In Feed):

Nezabudnite nové nastavenie uložiť.

Tým že ide o prostý text/xml môžete XML-ká generovať aj na strane serveru a vytvoriť tzv. dynamický FeedFlare. Nemusíte sa ani obmedzovať na odkazy a môžete generovať iba texty. To všetko je zdokumentované na webe FeedBurneru.

© Martin Cohen. Hnané WordPress–om. Formátované Texy–nou.