ugrás a tartalomhoz

Sablonkezelés jQuery alatt

Poetro · 2010. Május. 14. (P), 17.15
Sablonkezelés jQuery alatt

Szinte minden webes nyelv rendelkezik valamilyen sablonkezelő rendszerrel (template system), amivel a egyes blokkokat fel tudjuk tölteni változó tartalommal.

PHP-s körökben az egyik legelterjedtebb a Smarty, valamint a PHPTAL, Ruby esetén a szabványos könyvtár része az ERB csomag. A többi nyelvhez is elérhető, vagy már az alap függvénytár része a sablonok kezelése több kevesebb hozzáadott szolgáltatással.

Az alapvető követelmény minden esetben, hogy a sablonmotor a kapott sablonba beírja az átadott változókat. A változók helyének meghatározása és a behelyettesítés módja a sablonmotortól függ, ugyanakkor léteznek erre kvázi szabványok, ahogyan meg lehet határozni egy változó helyét. A JSP (Java Server Pages) JSTL sablonkezelője a ${változonév} formát preferálja, a perles Template Toolkit például a [% változónév %], a Smarty a {$változónév} formát és így tovább. Amiben hasonlítanak, hogy van valami határoló karaktersorozat és közöttük a változó neve.

JavaScript

Kedvenc nyelvünk, a JavaScript esetén sincs ez másként, itt is léteznek sablonkezelő motorok speciálisan egy adott keretrendszer köré csoportosítva. Ext JS esetén az Ext.Template szolgál segítségül, használata viszonylag egyszerű.

Ennél valamivel kifinomultabb a MooTools Mooml sablonkezelője, ahol JavaScripttel is lehet generálni a HTML sablont, és közvetlenül a DOM-ban is elhelyezhető <script type="text/mooml" name="sablon-neve">Sablon</script> formában. Természetesen a többi keretrendszer is kínál vagy már a rendszer részeként, vagy külső modulként sablonkezelőt.

jQuery sablonkezelők

jQuery esetén is elérhető rengeteg bővítmény. Ezek közül is fontosnak tartom azt, melyet John Resig, a jQuery megalkotója JavaScript Micro-Templating néven tett közzé; ezen alapszik a jQuery Micro Template plugin.

JavaScript Micro-Templating

A rendszer sokmindenre képes, viszont ezt érdekes megvalósítással teszi, ami nem feltétlenül szimpatikus több fejlesztő számára, akik úgy gondolják hogy az eval és társai maga a gonosz. Ugyanis a rendszer lényege, hogy new Function híváson keresztül a sablonból JavaScript kódot generál, aminek lehet biztonsági kockázata, viszont ha a sablon elkészült, akkor nagyon gyors, és a sablonban levő JavaScript kódot is képes lefuttatni. Álljon itt egy példa egy majdnem statikus sablonra:

  1. <div id="<%=id%>" class="<%=(i % 2 == 1 ? " even" : "odd")%>">  
  2.     <div class="alpha">  
  3.         <img src="<%=profile_image_url%>"/>  
  4.     </div>  
  5.     <div class="omega contents">  
  6.         <p><b><a href="/<%=from_user%>"><%=from_user%></a>:</b> <%=text%></p>  
  7.     </div>  
  8. </div>  

Mint látható, az első sorban a <div> id tulajdonsága a majdan átadott id változó értéke lesz, az osztálya pedig attól függően, hogy i páros-e vagy páratlan, even illetve odd értéket vehet fel. A nyelv szabályai viszonlag egyszerűek. A <% jelzi, hogy JavaScript kód következik, ha ezt = jel követi, akkor egy értéket fog beírni, egyébként pedig az azt követő JavaScript utasítássorozat fog lefutni, például:

  1. <% for (var i = 0; i < users.length; i++ ) { %>  
  2.     <li><a href="<%=users[i].url%>"><%=users[i].name%></a></li>  
  3. <% } %>  

Amennyiben a sablonunkat egy HTML elemben helyeztük el, akkor hivatkozhatunk rá annak azonosítójával, vagy átadhatjuk magát a sablont is. Például:

  1. <script type="text/html" id="link_tmpl">  
  2.     <a href="<%=link%>"><%=title%></a>  
  3. </script>  

Ezen HTML kód esetén a használat:

  1. tmpl('link_tmpl', {'link''http://weblabor.hu''title''Weblabor'});  

Az ehhez kapcsolódó jQuery bővítmény már nem rendelkezik ilyen szép kóddal, és igazából csak röviden szeretném bemutatni, mivel ugyanazt tudja mint az eredeti, csak szerintem rosszabbul.

  1. <div id="link_tmpl">  
  2.     <a href="<:=link:>"><%=title%></a>  
  3. </div>  

A kapcsolódó JavaScript kód pedig:

  1. $('#link_tmpl').drink({'link''http://weblabor.hu''title''Weblabor'});  

jQuery Templates

A jQuery Templates kicsit más alapokon nyugszik. A lényeg, hogy itt is reguláris kifejezésekkel zajlik a cserélés, de csak abban az esetben történik eval hívás, ha le is fordítjuk a cserélési procedúrát, ami sokat tud gyorsítani a sablon alkalmazása esetén, ugyanakkor nem tud vezérlési szerkezeteket.

Ami mégis előnye szerintem, hogy a változókon végrehajthatunk a sablonban függvényeket. Ezekkel testre szabhatjuk, hogy a változó milyen formán jelenjen meg, nem kell minden formáját előkészíteni, valamint a sablon építőjének sem kell ismernie a JavaScript sajátosságait, csak azokat a függvényeket, amiket alkalmaz.

Ezt demonstrálandó készítettem is egy kisebb mintaalkalmazást, ami több JavaScript „szépséget” is tartalmaz.

Flickr képkereső

Az alkalmazásunk egy keresést indít a Flickr azon képeire, melyek rendelkeznek egy megadott kulcsszóval. Magának a keresésnek a lebonyolításához jelen esetben Yahoo! Query Language-t fogunk használni, ezzel annak lehetőségeit is demonstrálva. A YQL eredményhalmazából egy listát fogunk képezni, amit majd jQuery Templates sablonok használatával fogunk a felhasználónak megmutatni.

Yahoo! Query Language

A YQL egy URL alapú lekérdező szolgáltatás, amivel a Yahoo!, és más szervezetek – akik YQL formában is elérhetővé tették adataikat –, adatbázisában kereshetünk. A Yahoo! esetében ez lehet maga a Web, a Yahoo! saját motorját használva, vagy más szolgáltatása, példánk kedvéért a Flickr.

A lekérdezésünk ebben az esetben a következőképpen néz ki:

  1. SELECT * FROM flickr.photos.info WHERE photo_id IN (SELECT id FROM flickr.photos.search(1, 10) WHERE tags = "cimke")  

Ezzel kikeressük azon Flickr fényképek információit, amik azonosítója megtalálható azon 1-től 10-ig terjedő fotó között, amelyek rendelkeznek a „cimke” címkével.

Az 1-től 10-ig azért lett felhasználva, hogy ha később például lapozót szeretnénk készíteni, könnyedén ki lehessen bővíteni az alkalmazásunkat, ne kelljen a lekérdezésünket is újraírni.

A lekérdezést a YQL-nek átadva egy XML dokumentumot vagy JSON-t kapunk, melyet feldolgozunk az alkalazásunk igényeinek megfelelően. A lekérdezés URL-je a következőképpen néz ki:

http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20flickr.photos.info%20where%20photo_id%20in%20(select%20id%20from%20flickr.photos.search(1,10)%20where%20tags%3D%22cimke%22)&format=json&callback=cbfunc

A q paraméter tartalmazza a lekérdezésünket, természetesen megfelelően kódolva, a format a visszatérés formáját (xml vagy json), valamint megadhatunk egy opcionális callback paramétert, ami JSONP esetén lesz hasznos.

Sablonok

Alkalmazásunk váza a következőképp néz ki:

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  2. <html xmlns="http://www.w3.org/1999/xhtml">  
  3.     <head>  
  4.         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
  5.         <title>jQuery template</title>  
  6.     </head>  
  7.     <body>  
  8.         <!-- Űrlap, ami majd a keresést végzi -->  
  9.         <form method="get" action="#">  
  10.             <label>Kulcsszó: <input type="text" /></label>  
  11.             <input type="submit" value="Keresés" />  
  12.         </form>  
  13.   
  14.         <div id="results" class="section">  
  15.             <!-- Ide kerülnek majd az eredmények -->  
  16.         </div>  
  17.   
  18.         <!-- Eredménylista sablon -->  
  19.         <script type="text/html" id="template-results">  
  20.             <![CDATA[ 
  21.                 <h3>Eredmények</h3> 
  22.                 <ul class="hfeed"></ul> 
  23.             ]]>  
  24.         </script>  
  25.   
  26.         <!-- "Nincs eredmény" sablon -->  
  27.         <script type="text/html" id="template-no-result">  
  28.             <![CDATA[ 
  29.                 <h3>Nincs eredmény</h3> 
  30.             ]]>  
  31.         </script>  
  32.   
  33.         <!-- Sablon az egyes képekhez -->  
  34.         <script type="text/html" id="template-image">  
  35.             <![CDATA[ 
  36.                 <li class="hentry"> 
  37.                     <h3 class="entry-title"> 
  38.                     <a href="${link:checkPlain}" title="${title:checkPlain}">${title:truncate(40,1)}</a> 
  39.                     </h3> 
  40.                     <p class="vcard"> 
  41.                         <a class="url fn" href="${authorURI:checkPlain}">${authorName}</a> 
  42.                         @ 
  43.                         <span class="published">${date}</span> 
  44.                     </p> 
  45.                     <div class="entry-content"> 
  46.                         <a href="${link:checkPlain}"> 
  47.                             <img src="${thumbnail:checkPlain}" alt="${title:checkPlain}" height="80" longdesc="${link:checkPlain}" /> 
  48.                         </a> 
  49.                         <div class="description" title="${description:checkPlain}"> 
  50.                             ${description:truncate(100,1)} 
  51.                         </div> 
  52.                     </div> 
  53.                 </li> 
  54.             ]]>  
  55.         </script>  
  56.   
  57.         <!-- Szükség van jQuery-re -->  
  58.         <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>  
  59.           
  60.         <!-- Szükség van jQuery Templates-re -->  
  61.         <script type="text/javascript" src="http://bitbucket.org/stanlemon/jquery-templates/raw/abe394368c73/jquery.template.js"></script>  
  62.     </body>  
  63. </html>  

Mint látható, a HTML dokumentumban létrehoztunk egy <form>-ot a keresésre, valamint deklaráltuk a sablonokat <script type="text/html" id="sablon-azonosito"></script> formában. Mivel a böngésző nem tud mit kezdeni a text/html formájú <script>-tel, ezért figyelmen kívül hagyja. A CDATA részt az érvényes HTML forma miatt raktam bele, igazából elhagyható, és csak XHTML formátum esetén van értelme.

A sablonokat ezek a CDATA részek tartalmazzák, és akkor térjünk is rá, hogyan kell a sablonokat értelmezni.

  1. <li class="hentry">  
  2.     <h3 class="entry-title">  
  3.         <a href="${link:checkPlain}" title="${title:checkPlain}">${title:truncate(40,1)}</a>  
  4.     </h3>  
  5.     <p class="vcard">  
  6.         <a class="url fn" href="${authorURI:checkPlain}">${authorName}</a>  
  7.         @  
  8.         <span class="published">${date}</span>  
  9.     </p>  
  10.     <div class="entry-content">  
  11.         <a href="${link:checkPlain}">  
  12.             <img src="${thumbnail:checkPlain}" alt="${title:checkPlain}" height="80" longdesc="${link:checkPlain}" />  
  13.         </a>  
  14.         <div class="description" title="${description:checkPlain}">  
  15.             ${description:truncate(100,1)}  
  16.         </div>  
  17.     </div>  
  18. </li>  

Ez egy hagyományos HTML, ugyanakkor vannak benne változók és azon végzett műveletek. A későbbiekben majd részletezem a műveleteket, a használt formátum ugyanakkor a következő: ${valtozonev[:muvelet[([paraméterek])]]}.

Azaz tartalmaz egy változónevet, amit majd a motor be fog helyettesíteni, opcionálisan azon végrehajthat egy műveletet, aminek opcionálisan átadhatunk paramétereket.

Legegyszerűbb forma tehát például a ${date}, ahol egyszerűen behelyettesítésre kerül majd a date változó. A ${link:checkPlain} esetében a link változón fogja végrehajtani a checkPlain műveletet, aminek nem adunk át paramétereket. Legbonyolultabb forma a ${description:truncate(100,1)} ahol a description változón lefut a truncate függvény, aminek átadunk két paramétert, a 100-at és az 1-et.

Fontos hangsúlyozni, hogy az átadott paraméterek sztringként fognak a függvényhez jutni, ezért előbb ét kell alakítani azokat, amennyiben nem sztringre van szükségünk.

Ahhoz, hogy kivegyük a sablont a HTML elemből, írtam egy kisebb jQuery plugint.

  1. $.fn.extend({'parseTemplate'function () {  
  2.     var templates = [];  
  3.   
  4.     if (this.length) {  
  5.         this.each(function () {  
  6.             templates.push(this.innerHTML.replace(/^[\n\r\t ]*<!\[CDATA\[([^\f]*)\]\]>[\n\r\t ]*$/, '$1'));  
  7.         });  
  8.   
  9.         return this.length == 1 ? templates[0] : templates;  
  10.     }  
  11.   
  12.     return '';  
  13. }});  

Igazából nem csinál sokat, csak kiveszi az elem tartalmát és amennyiben a tartalom CDATA-ban van, akkor kiveszi a CDATA tartalmát. Ha több elem van, akkor tömbként adja vissza a template-eket, ha csak egy elemet választottunk ki jQuery-vel, akkor pedig csak azt az egy sablont adja vissza sztringként. Használata egyszerűen: $('#template-image').parseTemplate();.

Változó műveletek

Korábban már említettem, hogy a sablonban levő változókon műveleteket lehet végrehajtani. A jQuery Templates plugin alapból csak egy substr() függvényt tartalmaz, de általában ennél többre van szükségünk. Ezért deklaráljuk a sablonunkban előforduló checkPlain() és a truncate() függvényünket. Mivel a jQuery Templates függvénytár kiterjeszthető, igen egyszerű dolgunk van.

  1. $.extend($.template.helpers, {  
  2.   
  3.     /** 
  4.      * Segédfüggvény, szöveget alakít Bool értékké. 
  5.      */  
  6.     _boolValue: function(value) {  
  7.         switch (value) {  
  8.             case 'false':  
  9.             case '0':  
  10.                 return false;  
  11.             case 'true':  
  12.             case '1':  
  13.                 return true;  
  14.             default:  
  15.                 return !!value;  
  16.         }  
  17.     },  
  18.   
  19.     /** 
  20.      * Megfelelő hosszúságúra vág egy szöveget. 
  21.      * 
  22.      * @param value 
  23.      *   A szöveg, amit vágni akarunk. 
  24.      * @param length 
  25.      *   A méret amire vágni szeretnénk. 
  26.      * @param wordSafe 
  27.      *   Szóhatáron vágjon-e. 
  28.      *   (Használjunk Bool-ra hasonlító értékeket 0 / 1 vagy true / false). 
  29.      * @return 
  30.      *   A méretre vágott szöveg. 
  31.      */  
  32.     truncate: function (value, length, wordSafe) {  
  33.         var text = String(value);  
  34.         wordSafe = this._boolValue(wordSafe);  
  35.   
  36.         if (text.length > length) {  
  37.             if (wordSafe) {  
  38.                 var lastSpace = text.lastIndexOf(' ', length);  
  39.                   
  40.                 // létezik a space ÉS nem a 0. pozícióban  
  41.                 text = (lastSpace > 0) ? text.substring(0, lastSpace) : text.substring(0, length);  
  42.             } else {  
  43.                 text = text.substring(0, length);  
  44.             }  
  45.   
  46.             text += '…';  
  47.         }  
  48.   
  49.         return text;  
  50.     },  
  51.   
  52.     /** 
  53.      * HTML szöveg speciális karaktereit kódolja, 
  54.      * így elemek tulajdonságaiban is szabadon fel lehet használni. 
  55.      * 
  56.      * @param value 
  57.      *   A szöveg, amiben kódolni kell a speciális karaktereket. 
  58.      * @return 
  59.      *   Kódolt szöveg. 
  60.      */  
  61.     checkPlain: function (value) {  
  62.         return value.replace(/[<>&"']/g, function (match) {  
  63.             switch (match) {  
  64.                 case '"':  
  65.                     return '"';  
  66.                 case "'":  
  67.                     return ''';  
  68.                 case '&':  
  69.                     return '&';  
  70.                 case '<':  
  71.                     return '<';  
  72.                 case '>':  
  73.                     return '>'  
  74.             }  
  75.   
  76.             return match;  
  77.         });  
  78.     },  
  79. });  

Amint látható, kiterjesztettük a $.template.helpers objektumot, ahol a jQuery Templates a változó műveleteit tárolja, és kibővítettük pár újabb művelettel.

A truncate() függvény a szöveget vágja megfelelő hosszúságúra, akár szóhatárt figyelembe véve is, a checkPlain() pedig a HTML-ben használt karaktereket kódolja.

A _boolValue() a függvények között igazából kakukktojás, mivel ez egy segédfüggvény, amire a többi sablonműveletünk támaszkodhat, amennyiben Bool értéket szeretne használni a kapott paraméterek között.

Alkalmazás

A jQuery Templates alkalmazása a következőképpen néz ki:

  1. Előkészítjük a sablonunkat var sablon = $.template('sablon', opciok); formában.
  2. Alkalmazzuk a sablonra a változókat. Ennek több módja létezik:
    • Szöveget generálunk a sablonból későbbi felhasználásra a sablon.apply(valtozok); formában
    • Beszúrjuk közvetlenül a HTML-be, akármelyik DOM manipuláló függvény segítségével, például:
      • $('body').html(sablon, valtozok);
      • $('body').append(sablon, valtozok);
      • $('#results').after(sablon, valtozok);
      • stb.

A tényleges alkalmazásunk pedig:

  1. (function ($) {  
  2.     // 'Globális' változók előkészítése  
  3.       
  4.     var flickrURL = $.template('http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20flickr.photos.info%20where%20photo_id%20in%20(select%20id%20from%20flickr.photos.search(${start}%2C${to})%20where%20tags%3D%22${query}%22)&format=json&callback=?', {'compile'true}),  
  5.       
  6.     parse = function (items) {  
  7.         // Feldolgozza a Flickr-től kaptott tömböt,  
  8.         // és a sablonnak szükséges objektumokat gyárt belőle.  
  9.           
  10.         return $.map(items, function (entry) {  
  11.             return {  
  12.                 'authorName':  entry.owner.realname || entry.owner.username,  
  13.                 'authorURI':   'http://www.flickr.com/photos/' + entry.owner.nsid,  
  14.                 'title':       entry.title || 'N/A',  
  15.                 'link':        entry.urls && entry.urls.url && entry.urls.url.content,  
  16.                 'thumbnail':   'http://farm' + entry.farm + '.static.flickr.com/' + entry.server + '/' + entry.id + '_' + entry.secret + '_t.jpg',  
  17.                 'description': entry.description || '',  
  18.                 'date':        entry.dates.taken  
  19.             };  
  20.         });  
  21.     };  
  22.   
  23.     // Ha készen áll a DOM, indulhat az alkalmazás  
  24.     $(function () {   
  25.         var imageTemplate = $.template($('#template-image').parseTemplate(), {'compile'true}),  
  26.         listTemplate      = $('#template-results').parseTemplate();  
  27.         noListTemplate    = $('#template-no-result').parseTemplate();  
  28.   
  29.         $('form:first').submit(function (event) {  
  30.             // Előkészítjük a paramétereket.  
  31.             var params = {  
  32.                 'start': 1,  
  33.                 'to':    10,  
  34.                 'query': encodeURIComponent($(':text'this).val())  
  35.             };  
  36.   
  37.             // Nem fog lefutni a form alapértelmezett submit eseménye.  
  38.             event.preventDefault();  
  39.   
  40.             // Csinálunk egy JSON(P) lekérdezést YQL-en keresztül a Flick-re,  
  41.             // és feldolgozzuk az eredményeket.  
  42.             $.getJSON(flickrURL.apply(params), function (data) {  
  43.                 var items = (  
  44.                     data.query &&                   // Megnézzük,  
  45.                     data.query.results &&           // hogy van-e eredmény,  
  46.                     data.query.results.photo &&     // azok fotók-e,  
  47.                     parse(data.query.results.photo) // és feldolgozzuk,  
  48.                 ) || [],                            // vagy üres tömmbel térünk vissza.  
  49.                 results = $('#results').empty(),    // Kiürítjük az eredménylistát.  
  50.                 list;                               // Lista.  
  51.   
  52.                 // Attól függően, hogy van-e eredmény megfelelő sablont választunk.  
  53.                 results.append(items.length ? listTemplate : noListTemplate);  
  54.                   
  55.                 if (items.length) {  
  56.                     // Vannak eredmények, feltöltjük a listát.  
  57.                     list = results.find('ul:first');  
  58.                       
  59.                     if (list.length) {  
  60.                         // Végigmegyünk az eredényeken, és berakjuk a listába.  
  61.                         $.each(items, function () {  
  62.                             // Mivel átadjuk a sablonnak a változókat,  
  63.                             // ezért az szépen fel lesz töltve.  
  64.                             list.append(imageTemplate, this);  
  65.                         });  
  66.                     }  
  67.                 }  
  68.             });  
  69.         });  
  70.     });  
  71. })(jQuery);  

A kód azoknak, akik nem szoktak hozza a jQuery-hez kicsit fura lehet, ezért részletezem. A függvényünkben elérhető lesz a jQuery $ néven. Erre igazából általában nincs szükség, azonban ha több keretrenszerrel dolgozunk egyszerre, akkor összeütközés lehet a változók tekintentében, ezt hivatott elkerülni a (function ($) {})(jQuery) forma, így a függvényen belül a $ biztosan a jQuery-nek felel meg, valamint a függvényben deklarált változók nem fogják beszennyezni a globális névteret.

Első változónk a flickrURL már maga is egy sablon, aminek átadhatunk 3 változót: start, to és query, ahol a start a lista első elemének indexe, a to az utolsóé, valamint a query, ami maga a keresés. A callback=? rész biztosítja, hogy a jQuery AJAX lekérdezés esetén JSONP-ként kezelje a kérést.

A parse nevű változónk egy függvény, ami a YQL lekérdezés által visszadott JSON tömböt dolgozza fel, és veszi ki változókba az elemeket, melyeket a sablonban majd felhasználunk.

A működés nem túl bonyolult. A <form> elküldése esetén nem az alapértelmezett művelet fog lefutni, hanem egy AJAX lekérdezés az előbb létrehozott flickrURL sablon elemeinek kitöltésőből kapott URL segítségével. Amikor visszatér az AJAX kérés a JSON eredénnyel, azt feldolgozzuk, hogy át tudjuk adni az előkészített sablonoknak. Annak függvényében, hogy volt-e találat, megjelenítjük a sablont.

Zárszó

Remélem sikerült rávilágítanom a sablonkezelés rejtelmeire, és arra, hogy a sablonok kezelésének nem csak a szerveroldalon van meg a helye, hanem a mai webes világban elterjedt AJAX-os weboldalak is sokat profitálhatnak belőle. Kezelésük általában nem bonyolult, igazából csak megszokás kérdése, és szerintem kényelmesebb, mint stringeket összefűzni minden egyes eredmény formázásához. A designerek is szabadabban tudnak mozogni, mivel meg tudják tervezni a kinézetet már a böngészőben HTML és CSS segítségével, nem szükséges nekik további JavaScript ismereteket elsajátítani.

 
Poetro arcképe
Poetro
1998 óta foglalkozik webfejlesztéssel, amikor is a HTML és a JavaScript világa elvarázsolta. Azóta jópár évet dolgozott reklámügynökségeknél, és nemzetközi hírportálok fejlesztésével. Legfőképpen Drupal fejlesztéssel, site buildinggel és JavaScripttel, azon belül is jQuery-vel és Node.js-sel foglalkozik.
1

Nagyon jó!

presidento · 2010. Május. 15. (Szo), 10.11
Jó a cikk, és milyen ötletes, hogy a JavaScript Micro Templating kódja is mikro méretű. :)
2

folytatás?

Dohány Tamás · 2010. Május. 15. (Szo), 17.25
jó cikk! lesz folytatása?
3

Folytatás

Poetro · 2010. Május. 18. (K), 20.06
Egyenlőre nem terveztem folytatást, de amennyiben elegendő igény mutatkozik, elgondolkodom a dolgon.
Addig is a fenti kódot élesben is ki lehet próbálni.
4

jQuery Template Proposal

Kevlar · 2010. Jún. 6. (V), 14.41
Éppen dolgoznak a jQuery-s srácok egy template módszeren:
http://forum.jquery.com/topic/jquery-templates-proposal

Itt ki is próbálható:
http://github.com/nje/jquery-tmpl