_____ _________ ________ ___ ___ _________ ________ / __/ \_ ____/ \ ) | | | | \_ ____/ \ ) \__ \ | _)_ | __ _/ | | | | | _)_ | __ _/ ___\ \ | \ | | \ \ \ \_/ / | \ | | \ \ solutions \____/ /_____ / /_/ \ \ \ / /_____ / /_/ \ \ \/ \/ \_/ \/ \/ (c) Lada 'Ray' Lostak (c) Orcave (c) 2002-2005 Content: Server Thin Client Library History: 05/18/2002 Ray - initial version 12/18/2004 Ray - PHP part of STLC moved out into CBS Template engine --------------- Template is text file, which creates 'output' (for example HTML). It communciates with script by 'variables', 'arrays' and 'functions'. Template directions stars with { and end by pair }. Inside can be commands, simple variable refs, macros references, etc. Tags doesn't remove any blanks or doesn't insert any additional blanks. One exception are commands. Commands remves _ALL_ blanks before and after, if there are not present any other characters. It works only within 'one line'. To be open, not ALL commands are remoing blanks. Usually, commands like if/else/include are doing that. Commands like tcell, ... are not skipping. So, generaly, commands generating some 'output' doesn't skip any blanks. Example: some text {command ...} continues ----> some text continues [ofsource, command can generate some text] some text {command ...} [new line] continues ----> some textcontinues some text {command ...} ----> some text continues continues some text {!command ...} [new line] [new line] continues ----> some text{new line} continues All directives have to be placed at one physical line. 1.0 General ----------- TPL engine includes 'internal' and 'external' functions. Internal functions are called by {:function param} External {*function param} External functions are added to TPL engine by calling script or can be added by library. TPL library is added to TPL engine by: {:lib lib_name} This command adds into TPL engine given 'library'. Library have full control over TPL engine, can 'learn' some tables/variables/macros, add functions, whatecer. System administrator have to install libraries. TPL engine can use powerfull macros. Macros are referenced by {!macro params} Default 'command' is to refence variable {varname} -> expands to value of 'varname' Language string is referenced by {@lng_id} -> translated and expand into text Comment - everything to EOL (including) is ignored: {// comment Many commands support 'quit' mode, which doesn't generate 'error' - for example if referenced variable doesn't exists. Use: {?.... where ... is 'original' command. Example: {?varname} {?:if varname=} If you need to use { symbol, double it {{ 1.1 Variables --------------- Any text references inside template as {NAME} is replaced by value sets by script. Example: Script exports 'AUTHOR'. And it sets AUTHOR to 'Orcave inc.' Author {AUTHOR} ---> Author Orcave inc. No blanks are skipped around {..} tags. Template can 'self' learn variables. Value, which template learns override original value. {:learn var_name value} If value includes HTML tags, they are converted to html entities. There is also one way how to reference variable value: {:var name} This is identical to {name} but usefull sometimes. 1.2 Tables ------------- Script can export tables. In this case, template have to create 'loop' to print all table context. Its format: {:tloop table_name [loop_name]} inner loop {:tloop} This set of code 'executes' inner loop for every table row. If loop_name not given, table_name used by default. table_name is required for nested loops with same datas. Table value can be referenced by {:tval col_name[@loop_name]} where col_name is 'name' of requested column from table (column name). It is required if table hold more columns. If name not given, most 'inner' table loop is used. General table commands: {:tlen table_name} expand into integer - total table rows {:trow loop_name} expand into integer - current "row" Example: PHP script exports table 'powers' which have 2 columns - 'num' and 'power'. We want to print it into table. Template will look: {:tloop powers} {:tloop}
OrderNumberPower>
{:trow powers}{:tval num}{:tval power}
1.2.1 Accessing table data -------------------------- Table cell can be directly accessed by tcell command: {:tcell table col val_to_find col_to_return default_value} searchs 'table' for row, where column 'col' will be equal 'to val_to_find' and will return colum 'col_to_return' of matched row. If no row found, it returns 'default_value' If you want to access some cell by its row number, you can use command tcellrow {:tcellrow table row_number_from_zero column_to_return default_val} If exists specified line and column, its value is returned. If not, default value is used instead. Similar way can be replaced cell value: {:tset table col val_to_find col1=val1&col2=val2&....} All rows matching 'col=val_to_find' sets col1 to val1,col2 to val2 and so one. Tables rows can be deleted by using command trowdel: {:trowdel table col value} All rows, where 'col' is equal to 'value' are deleted. Table columns can be created on fly. There exists command trowexp which creates column from expreesion: {:trowexp table col expression} For each row of 'table' is processed 'expression' and stored co new column 'col'. Expression can include other column names and operator : +-/* Examle: name price quantity price_tot ------------------------ --------- beer1 20 2 {:trowexp table pricetot price*quantity} 40 beer2 50 4 will add column 'pricetot': 200 beer3 10 1 will add column 'pricetot': 10 Whole column in table can be also compuer by expression: {:tcolewxp table expression} This command expands into result of adding expression processed to each table row. Example: Look at previous table (columns: name/price/quantity/proce_tot). Command {:tcolexp table price_tot} will expand to '250' {:tcolexp table price_tot*2} will expand to '500' Table can be also cleaned - all rows (and columns) will be deleted: {:tclean table} There also way how to glue 2 tables togeher. Imagine, you have table A and B. Both are connected by key: {:tglue dst src col} Every row of table dst is enhaced about columns in table src. 'col' is column name, which connects both tables. It is like JOIN in database. If table src doesn't include row referenced by dst, it is DELETED from dst table. Example: imagine table above (table1) and new table2: name developer address ---------------------------------- beer1 Krusovice Krusovicka 123 beer2 Gambrinus Ceske pivovary a.s. {:tglue table1 table2 name) will CHANGE 'table1' to: name price quantity price_tot developer address -------------------------------------------------------------------- beer1 20 2 40 Krusovice Krusovicka 123 beer2 50 4 200 Gambrinus Ceske pivovary a.s. table row with 'beer3' were deleted, because there was no record found in table2. if you will exchange table1/table2, new table will include all beers inside. Tables can by simply copyied over: {:tcopy dst src} Table can be searched for specified cell: {:tcheck table col value} If table includes row in column 'col' with value 'value', then command expands to 1. Otherwise 0. Example: {:tcheck beers developer Krusovice} expands to 1 {:tcheck beers developer Gambac} expands to 0 Cells can be connected together into list by: {:tlist table col} List is divided by , Example: {:tlist beers developer} will expands into "Krusovice,Gambrinus" Runtime can be also inserted rows of tables :tinsert tablename params and :tset tablename column value params tinsert commands inserts new row into tablename. If table doesn't exists, it is created. tset sets particular rows in table, which meet condition 'column=value'. If more rows matchs given conditions, ALL rows are processed by 'params'. Params are parameters, from which are sets columns and their value. It uses URL form, that is col=val&col2=val2&and so one. Example: {:tinsert mytable name=Krusovice&kind=beer&price=20} {:tinsert mytable name=Whiskey&kind=hard&price=99} {:tset mytable name Krusovice price=22} will create following table: name kind price ------------------------------------ Krusovice beer 22 Whiskery hard 99 For self learning bigger tables exists 'multi learn' command, whcih also allows to learn nested tables. Its form: {:tinsertm tablename} col = val [new line us used as colum delimiter] col2 = val col3 { [sub table] col1 = val col2 = val } col4 { col1,col2 [sub table with 'list' as column datas, ',' used as value delimiter] val,val [new line separate RECORDS] } col5 = val col6 = {:exec "{var 1}" "{var 2}"} {:tinsertm} Both modes also know enhanced format of "tablename". Table should be simple table name (like previous examples) or tablename.column:columncompare.value tablename.column.column2:column.value:column2.value2 If this enhanced form is used, TPL engine inserts new row in subtable 'column' (or sub-sub). Table column 'columncompare' is searched for 'value' and if found, new row is inserted in the searched column row. Example: {:tinsertm mytable.exporters:name.Krusovice} name=some_exporter address=some_address {:tisertm} This example will search table 'mytable' and it will try to locate row, where 'name' is set to 'Krusovice'. In this row, it will insert new record (name/address) to column called 'exportes' tinsert & tinsertm automaticlaly entities datas. If you want to usnert RAW datas (x-site scripting !) use raw form of these 2 commnads: :tisertraw :tinsertrawm All parametres and using are exactly same, except entiting of datas. 1.2.2 Accessing tree related data --------------------------------- Data into table can be access as 'tree' strucutre. It is required to have '2' columns, one unique 'id' and second 'parent'. Their meaning are usual. Visualising tree - {:ttree} commands Table tree - {:ttree img1,img2,size,x,link,nodes} This command allows generating 'tree' structure (from table records). It uses folowing parametres: img1 - path to 'tree' icons, * in name is replaced by required 'tree' item 0 empty 1 line down 2 line down-left 3 line down+left 4 line down-left and + 5 line down+left and + 6 line down-left and - 7 line down+left and - img2 - like previous, but used for 'icons' size - icon size (width=height) x translate order for 'img2', X offsets: 0 default folder 1 default item link - | divided 2 parts: first: folder related second: item related Available contents: "click:exec" - 'exec' after L click "rclick:exec" - 'exec' after R click navigation +- "..." - default 'navigation' (open/close/...) - '...' are 'base' parametres item/folder "ref:link" - link (autoamticly added 'treenodes') "..." - nothing nodes - optinal, name of 'treenodes' (default: treenodes) If you need to wipe out a part of tree structure, you can use command: {:ttreenodes dst src[.parent[.id]] [start] [depth]} This commands creates table 'dst' with rows which coresponds to rows from 'src', starting by node 'start' (root by default) and goes into depth (1 by default). If parent is not given, 'parent' is used. Similar for id. Getting 'path' in tree is also trivial: {:ttreenodes dst src[.parent[.id]] node} Like previous command, except it returns rows (root to depth way) which are required to walk from root node to tree 'node'. Including. Rows can be sorted as 'tree' byu using: {:ttreesort table id_col parent_col} 1.2.3. Miscellaneous functions ------------------------------ Table can be sorted, using {:tsort} command. {:tsort col1} {:tsort col1 col2...} Nothing to add :) Table also allows 'automatic' positions dections. Function is called 'tpos' {:tpos loop_name} This command 'expands' to flags - set of letters. Letters can be combined together. Known flags: s - start of table (first row) e - end of table (last row) u - upper lines (first to last but one) b - bottom (second to last) m - middle (all out of first and last) Table example: Flags +-------+-------------------+ | 12 | somedata | su +-------+-------------------+ | 34 | somedata | ubm +-------+-------------------+ | 45 | somedata | ubm +-------+-------------------+ | 56 | somedata | ubm +-------+-------------------+ | 12 | somedata | ubm +-------+-------------------+ | 44 | somedata | e b +-------+-------------------+ It can be used in conjuction with {:if to easy generation of header/footers/.... See also :if for '#=' equal command. 1.3 User macros --------------- Teplate can define macro. Its form: {:macro name ....} where 'name' is macro identifier and EVERYTHING after ONE blank and closing { is 'body of macro'. Macro is referenced by {!name} Example: {:macro test my big body} some text with {!test} macro ref ---> some text with my big body macro ref Macro can use parametres. Parametres count are not checked in any way. In macro body, you can use '@@1' for reference first parameter, '@@2' for second, etc. While referencing macro, just simply make spaces between parametres. Parametres are between closing } and macro name. Example: {:macro test My macro with param1: @@1 and param2: @@2} and use {!test sex beer) will end as My macro with param1: sex and param2: beer There is no way how to pass parameter which includes space. Use   or similar if required. Macro can be defined without initial valie assigment. Its form: {:macro macro_name } Space between macro name and ending } is required. Macro body can't include special characters: new line { or } backslah - \ If you need to use some of these special chars, make it by following table: { -> \{ } -> \} new line -> \n \ -> \\ Macro can also execute next command (any) or call different macro/etc. Be aware of recursions ! Example of multi command process: {:macro text_id 0001} {:macro put_text_id My text ID is \{!text_id\}\{:macroinc text_id\}} learned as -> My text ID is {!text_id}{:macroinc text_id} _BUT_ without \{ \} -> My text ID is 001 {!put_text_id) -> My text ID is 0001 {!put_text_id) -> My text ID is 0002 {!put_text_id) -> My text ID is 0003 {!put_text_id) -> My text ID is 0004 See {:macroinc} for more details. See, that second directive uses \{ \} instead of direct { }. It is because parser can't derermine, if you mean END or just 'some bracket'. 1.3.1 Macros on fly ------------------- Template allows redefinning macros on fly. It means, you can re-define macro after its definition. THere are few special which helps. {:macroinc macro_name} This cimmand 'increases' numeric value of given macro. It assumes, macro value consits of two parts - name and numerical ID - for example: Picture0001. '0' is used as delimiter. Macro keeps length of numeric part. Separating 0 is required -> it is not possible to do for example. one number based ID - like Picture0, because after first increation, command will not be abble to deremine where numerical part start. Example: {:macro test Pic0001} {:macroinc test} -> macro will be Pic0002 {:macroinc test} -> macro will be Pic0002 {:macroinc test} -> macro will be Pic0003 etc. This is iseful for example, when you're generating code, where inside one macro body you have to use some 'id' and next time 'different'. {:macroadd macro_name what_to_add} {:macroaddpar macro_name what_to_add} Command works similar to previous, except it adds to macro body 'what_to_add'. List is can be comma (,) separated - if user 'macroaddpar' version {:macro test beer} {:macroadd test &sex} -> macro will be "beer&sex" {:macroaddpar test water} -> macro will be "beer&sex,water" etc. Example - let's look how it can help in real word. Imagine you're generating menu on fly, and you have to generate 'mouse over' buttons (using java script). We will use from script functions: MM_swapImgRestore,MM_swapImage. How to fully automatize ? First define 'id' {:macro mm_img_id img_0001} Then define container, which we will use for 'preload' images (see down). Set to empty value. {:macro mm_img_preload } // and our macro - first parameter nomral image, second mouse over. {:macro mm_img \{:macroinc mm_img_id\}\{:macroadd mm_img_preload '@@2'\}} Use: {!mm_img images/normal.png images/mouse_ober.png} Verry simple and powerfull. How it works ? Macro generates proper script using 'current id'. Then it increases 'id' and store 'mouse over' file name to container. But there is small problem. 'preload' executed BEFORE tempalte executes real HTML code. So, see next command which solves our problem. 1.3.2 Macro replace ------------------- Sometimes you need to 'store' some results to HTML after template generates page. FOr example, when macros creates 'list' of used parametres. This command allows to repalce ANY text in template by some macro body. {:macrorep macro_name text_name} macro_name is name of macro, which replaces 'text_name' within WHOLE generated output. You can use this commadn also as regular search & replace: {:macro replace } {:macrorep replace } Above commands replaces in generated output by
. Only generated contents is processed. It doesn't work 'to future'. some text is here {:macro replace nice_text} {:macrorep replace text} some other text is here This piece of code replaces only FIRST line to "some nice_text is here". Example: Imagine we're creating list of used 'mouse over' images. It will be stored in mm_img_preload. Normally, we want to put onLoad=(...) in some script or at tag. real contents So, as you can see, if we will not use post-replace, we code will not work, because container at tag is empty. None image were generated yet. So, how to do ? real contents .... {:macrorep mm_img_preload ___PRELOAD___} And this works :o) Just make sure, you select unique text identifier for replace, in this case. 1.3.3. Multiline macros ----------------------- Multiline macros work similar way like normal macros. The only difference are tags: {:mmacro macro_name} Body of macro with more lines {:mmacro} 1.4 Including ------------- Template can include any other templates in separate files. Be aware of recursions. Command form: {:include path_to_file} Included file 'shares' all variables - macros, variables, tables, etc. File can be included in loops. If you want to 'end' current included file execution, use {:return} This commands skip entire remaining contents of current file and returns to 'caller'. 1.5 Conditions -------------- Template can change its contens in dependency on conditions. Condition can test 'variable' exported by script, or 'macro'. Contruct: {:if !macro=value} or {:if variable=value} statement {:endif} Or form with else block: {:ife !macro=value} or {:if variable=value} statement {:else} statement {:endif} Value is taken from equal (=) up to > AS IS. Including spaces, blank characters, etc. Instead of equal can be used non equal operator !=. Example: {:ife design=blue} {:else} {:endif} Additional condition test is '#='. Its form is string#=letters_to_test This condition becomes true, of 'string' includes one or more letters_to_test. Its main purpose is to test 'flags' (see :tpos for example) 1.6 Comments ------------ It is recomended to use tempalte commets rather HTML one, because temaplte engine removes comments. Comment starts with {// and end with EOL. Example:
{// this is my comment Will expand to As you can see, blanks around text are stripped out. It is recomended to use 'clever' language ID's. Last thing to explain is how to use some file. By command {:lng file} where file is language file with contents showed above. In our case, we will use {:lng test.lng} Real multilanguage have to be done with support of script side. Script can 'read' proper language, so, template will not include anything (and german ppl will see german text and english english). Or script can export variable, which template can use in IF statement and include proper file(s). 1.9. Debug ---------- Debug commands are useful sometimes :) Sends directly text to browser: {:echo text} Dump all tables/functions/variables/macros avilable in the moment: {:dump} {:dump params} If params is not given (empty), it shows list of all known thigns. Params is a list of following words: xxx - dump object 'xxx' - including its FULL BODY (e.g. show table contents) $tables - show tables $vars - show variables $macros - show macros $fns - show functions $parse_stack - show call stack Close current request (directly exits all scripts !) {:exit} 1.10. Text formatting --------------------- noblanks - skips all next physical blanks in TPL source url - format 'parameter' as valid URL - parameter should start with : for 'command' invoke. 1.11. Nested execution ---------------------- Sometimes it is necessary to use various substitutes (variables, other commands, ...) There are '2' form of nested template execution. First, 'contents' of nested exution is processed by TPL engine and then processed again to render output. Of the contetns are used as parameters, they are not processed again, but passed to function instead. 1.11.1. Direct nested execution ------------------------------- General form: {>body with another TPL commands producing new commands which may pvberlap on more lines<} {>single nestec execution example<} Everything inside 'body' is processed line NORMAL tpl and its output is again processed as part of TPL output. If you want to render '{' to output, user '{{' or '}}' Example: Assume table: Name Color ======================= Red FF0000 Green 00FF00 Blue 0000FF and variables: styleRed -> RED styleGreen -> GREEN styleBlue -> BLUE And following TPL: {>> {:tloop table} {{style{:tval Name}}} - have color {:tval Color} {:tloop} <<} This will 'generate' {styleRed} - have color FF000 {styleGreen} - have color 00FF0 {styleBlue} - have color 000FF Which will be processed to final output: RED - have color FF000 GREEN - have color 00FF0 BLUE - have color 000FF 1.11.2. Command parameter inner execution ----------------------------------------- For simpler execution of internal commands and external functions can be used shorter form. Its general form is {:command >params<} or {*function >params<} There is no other difference beween direct form, except outptu is used as 'parameter' for given command. New lines in the body are converted to SPACES. > have to follow immediatelly after command/function name. Example: Assumme variable 'color' having value 'green' or 'red' and variable named nameRed (RED) and nameGreen (GREEN). {:learn >result {:ife color=red}RED{:else}NOT RED !!!{:endif}<} Will produce output {:learn result RED} or {:learn result NOT RED !!!} So, in the result it will learn 'result' variable with 'RED' or 'NOT RED !!!' string. 1.2. XML support ---------------- xml.create name xml_body vytvore XML strom pojmenovany 'name' z 'xml_body', xml_body MUSI byt validni, jinak se generje warning xml.free uvolni XML strom a pamet je k dispozici pro dalsi uziti Pokud prikaz vyzaduje parametr xml, pak je minen prave XML strom. Pokid prikaz vyzaduje parametr element, pak je mieno jmeno elementu Pozor - XML je _CaSe_ sensitive. 1.2.1 kontextove zavisle prikazy -------------------------------- Nasledujici prikazy jsou kontextove zavisle a funguje jen pri prochazeni stromu, transforamci a podobne. Pokud budou pouzity mimo tento kontext, generuji warning. Po pocitani/testovani elementu, se pocita od 0 a ignoruje se aktualni element (nezapocitava se). Funguje vzdy pro 'posledni' (nejvnitrnejsi) akci u XML. xml.elemNest element typ pocita pocet vyskytu elementu. Typ je nepovinny paramtr. Pokud schazi, pak je pouzito 'parents'. Vyznam parametru typ: parents - pocita vyskyt tagu i vsech parentu az do rootu prevsiblings - vyskyt elementu ve vsech elementech pred aktualnim, vcetne jeho nadrazenych prevs - vyskyt elementu pred aktualnim (pouze v aktualnim levelu) xml.elemExists element typ vraci 0 ci 1 v zavislosti na tom, zda se dany element vyskutuje v zadanem miste. Typ je nepovinny, pokud neni zadan, je brano 'childs'. Vyznam parametru typ: childs - vsechny child elementy parent - parent elementu parents - jakykoliv z rodicovskych (vsech) elementu prevsiblings - vsechny predchozi elementy vcetne nadrazenych nexts - vsechny nasledujici elementy v aktualni urovni prevs - vsechny predchozi elementy v aktualni urovni level - vsechny elementy (vyjma aktualniho) v aktualni urovni xml.elemChildType vraci 'typ' child elementu: none - zadny child combined - text+elementy text - pouze textove elementy element - elementy Prikaz testuje vsechny child elementy daneho elementu xml.elemValue vraci 'value' elementu. Value elementu je dostupna pouze pro elementy typu text. Priklad: Toto je value elementu xml.elemExecute zpracuje child elementy. Prikaz ma vyznam jen pokud se child elementy nezpracovavaji automaticky (napr. pri transforamcnim pravidle s kombinaci flagu own_childs). Pokud se prikaz vola ikdyz jsou childy zpracovavany 2x, budou na vystup predany take 2x. xml.attrValue xml attr_name vrati hodnotu atributu z elementu xml.attrExists atr_name vrati 0 ci 1 v zavislosti na tom, ma-li dany element atribut 'attr_name' 1.2.2 XML transformace ---------------------- Tranforamce funguje tak, ze je postupne prochazen cely XML strom. Pro kazdy tag se hleda transforamcni pavidlo, ktera se sdruzuji to skupin (tj. transformace). Pravidla jsou prohledava PRESNE v tom poradi, v jakem jsou registrovana, pokud se nezavola nejaky prikaz na jejich preskupeni. Kazde pravidlo na condition, ktere dale urcuje zda je pravidlo v dany okamzik platne ci nikoliv. Jeho vyhodnocovani se provadi u kazdeho tagu. Pokud je pravidlo shledano validnim, tak se provede 'body' pravidla. Po te se provedou veskere transformace child elementu, Pokud si pravidlo natsavilo flag 'own_childs' tak se automaticky neprovadi child elementy a je na pravidle, jak s nimi naloze. Pro provede body a pripadne child elementu se vola bodyclose. Textove elementy (napr. toto je textovy element) se pouze primo prodavaji na vystup. Pokud se pro dany element nenajde zadne pravidlo, element se z vystupu bezezbytku a vcetne svych childu odstrani. xml.transformCreate xlt vytvori transformaci pojmenovanou 'xlt' xml.transformRuleAdd xlt element flags condition body bodyclose prida pravidlo do 'xlt' transformace element - jmeno elementu (JEDNOHO) flags - flagy pravidla, carkou odeleny seznam own_childs - pravidlo samo zpracovava sve childy condition - expression pro vyhodnoceni - pravidlo je platne pouze pokud je expression nenulovy body - TLP kod namisto open tagu bodyclose - TPL kod namisto closing tagu xml.transform xml xlt provede tranforamce nad stromem xml a pravidly xlt, vysledej je vystup prikazu 3.0. NEW TEMPLATE ENGINE ------------------------ Blech. Takze jedeeeem. Budu popisovat jen rozdily, protoze jinak vse suztalo stejne. Nejdrive prikazy. Skriptne se deli do skupin, odeluji se teckama. Pokud neni zadna skupina, tak je to 'globlani' prikaz. Obycejne knihovny delaji prikazy s prefixem sveho jmeno. Napr. knihovna 'menu' bude mit prikazy menu.abc a pod. Neorzilsuje se nijak vestavenej a externi prikaz. novy prikaz parametry stara TPL coment -------------------------------------------------------------------------------------- var n :var vypise hodnotu variable learn n?S :learn nauci novou variable if `S :if proste if else :else endif :endif return :return ukonci 'aktualni' soubor exit :exit ukonci vsechny fajly include S :include includne jinej fajl eval S vypocita 'expression' lib n?n :lib vlozi 'knihovnu' (pripavy k pouziti) text.urlencode S :url de/encode URL text.urldecode S - output.replace sS :macrorep replace v jiz vygenerovanem textu lng.load S :lng nahraje LNG fajl tree.nodes nn?ii :ttreenodes vrati nody ze stromu tree.path nni?i :ttreepath vrati cestu k node tree.prepare n :tsorttree pripravi tabulku aby odpovidala 'stromu' (seradi zaznamy a pod) tree.renderrow ssisssss :ttree vyrendruhe 'radku' stromu pri vykreslvoani table.loop ?ns :tloop table.val n :tval table.len n :tlen table.pos nn :tpos table.row n :trow table.nrow ni :tnrow table.create n?ii :tcreate vytvori tabulku table.clean n :tclean smaze tabulku table.check nnS :tcheck otestuje zda-li existuje zaznam table.set nnsS :tset setne cell table.cell nnsn?S :tcell vrati cell table.cellrow nin?S :tcellrow vrati cell podle radky table.rowexp nnS :trowexp zpracuje 'radkovy' vyraz table.colexp nS :tcolexp zpracuje 'sloupcovy' vyraz table.rowdel nnS :trowdel smaze radku table.insert nS :tinsert table.insertm n :tisnertm table.insertsubm nnns :tinsertm insert do 'tabulky' - subtabulka table.list nn?s :tlist prevede tabulku do listu table.glue nnn?n :tglue spoji tabulky table.sift nnS do DST tabulky narve vsechny radky ze SRC vyhovujici danemu expressionu table.copy nn :tcopy table.sort ns?ss :tsort macro.learn n?S :macro macro.learnm n?s :mmacro macro.learnstart n :xmacrob macro.learnend n :xmacroe macro.learnsub ns?s :xmacros macro.inc n :macroinc macro.add nS :macroadd macro.addpar nS :macroaddpar macro.ref n?ssssssssss string.escape S da \ pred ridici znaky ala \"' a pod. funguje i na HTML entitied retezec - tedy &#'; a pod. CBS prikazy cbs.redir S *redir cbs.link S *link cbs.linke S *linke cbs.linka ?S *linka cbs.linkae S *linkae cbs.access S *access cbs.dataPrepareTypes n *preparedataypes Dopisu jindy cbs.data_writter www. Existuji i zkratky prikazu: {!xx} je adekvatni {:macro.ref xx} Jinak vse zustalo zachovano. Generalni rozdily: comandy ala {:table.insert} RVOU kdyz rtabulka neexistuje. Stare ji tise vytvorili. poradne chybove halseni (kde, co a cesta) jine parametry (viz nize) if je opravdovej VYRAZ (viz nize) jine komentare jina zprava 'blank spaces' jine preskakovani 'tagu co nejsou tagy' - staci za nim mit mezeru ci preradit \ -> \} tagy PUZIVATELKY DEFINOVATELNE - defaultne { } Parametry --------- Komandy beoru parametry DLE typy. Poradi a typy je vise uvedeno. ? znamena, ze vsechny DALSI prikazy jsou 'volitelne'. n name - alias s string S string az do KONCE TAGU - musi sedet pary { a } - pokud je tam nejaky tag, automaticky se provede substituce TPL prikazu i integer Parametry MUZOU a NEMUSI byt uzavirany do " ci '. Pokud je parametr uzavren do " pak se vnitrek tohoto retzece PROVEDE. Pokud do ' tak se NEPROVEDE a preda se tak jak je. string MUSI byt uzavren do " ci ' pokud obsahuje jine nez dovolene znaky. Tech je celkem dost - :.+ a podobne. Nicmene, nejsou tam znaky jako mezera, tagy jako takove, " a tak dale. Uvnitr " ma specialni vyznam znak \ - pokud za ti mnasleduje ' " jsou prevedeny na odpovidajici znak, znaky r n jsou pak konce radku. t je tabulator. Pokud PRVNI znak parametru neni " ci ' tak se priapdne dalsi tyto znaku (pokud to dany typ dovoluje) berou tak jak jsou bez dalsich zmen. Parametry se odeluji jednou a vice mezeramy. Tolik seda teorie a ted praxe. Prikaz table.val bere 'n' - tedy alias. Muzeme zapsat: {:table.val sloupec} {:table.val "sloupec"} {:table.val 'table.val'} {:table.val table.val } {:table.val "{variable}"} - je adekvatni zapisu {:table.val hodnota_variable} NEMUZEME zapsat: {:table.val '{variable}'} -> {variable} NENI alias zapis "{variable}" zaroven selze, pokud hodnota variable NENI 'alias' vnorene prikazy "{:command \"{:command2 par2}\"}" "{:command \"{:command2 \\\"{:command3 par2}\\\"\"}" output.replace ma 2 parametry: sS retezec a retezec do konce tagu. muzeme zapsat {:output.replace } {:output.replace '' ''} (stejne jako prechozi) {:output.replace '' {!macro}} nahradi tim co je v makru 'macro' {:output.replace "" '{!macro}'} nahradi za {!macro} {:output.replace 'neco s " uvnitr' za neco jineho s " ci '} zdroj: je neco s " uvnitr cil: za neco jineho s " ci ' nemuzeme zapsat {:output.replace source s mezerou } 'source' se nahradi za 's mezerou ' - nutno pouzit " ci ' {:output.replace source text s {nejakym tagem} -> nesedi pary tagu - kazdy { ma } v S parametru -> musi se prepsat 'text s {nejakym tagem' (ikdyby to TPL vzalo, tak by to selkalo protoze '{nejakym' neni platny TPL prikaz} {:output.replace "neco kde je {xx{" za neco jineho TPL selze {xx{ neni platny TPL prikaz - nutne pouzit ' ne " ! Pozor na S - specilani u prikazu, ktere maji jen jedno S 'svadi' k chybam !!! {:if "aa"="bb"} -> SPATNE !!! PRVNI znak parametru je " -> parametr bude: aa"="bb -> zpracovani expression hodi chybu Tato situace nastava pouze u expressionu a lze rezit jednouse pouzitim zpetncyh apostrofu ` - tu jsou adekvatni normlanimu ', ale fungujou jen v rexpression a na parametry nemaji vliv. Pokud se ` objevy v expressionu v ' tak se 'ignoguje' (jako kdyby tam nebyl) Je mozne napsat {:if {:tval abc}='abc'} {:if {:tval abc}=abc} {:if {:tval abc}={xxx}} a tak dale. Je nutne si uvedomit, ze jedna vec je 'precteni parametru' a druhe je zpracovani expressionu, ten ma take sve pravidla (viz nize) Komentare ---------- {- komentaro do konce radku {-- multiline komentar klidne na jeden a vice radku --} Komentare muzou byt vnorene, pocet - na zacatku musi odpovidat poctu - na konci VSE OK: {--- debug {:prikazy} {--{:prikaz}--} ---} SPATNE: {-- debug {:prikazy} {--{:prikaz}--} --} zde komentar konci jiz po prvnim --} - sice zadna chyba nenastane, ale .... Expression ---------- Podporovane operatory (ciselne) + - / * ( ) < > <= >= = klasicke operatory - co dodat ? + - negace/kladne cislo: 1--2 1+-2 1++2 && || AND/OR - logycky. 1 && 4 -> 1 1 || 3 -> 1 0 || 2 -> 2 & | AND/OR - bitove 1 & 4 -> 0 1 | 3 -> 3 0 | 2 -> 2 ~ bitova negace ~1 -> 0xffffffff (decimane nevim :) << >> bitovy posun 1 << 3 -> 8 (00001 -> 01000) ! logicke ne !1 -> 0 !23 -> 0 !0 -> 1 % zbytek po deleni 5 % 2 -> 1 Funknce (lze dodat dle potreb) mod mod(5,2) zbytek po deleni bits bits(a,b) pocita biti mezi a,b (offsety na bity) Podporovane operator - retezcove < > <= >= = klasicke operatory - co dodat ? + soucet retezcu Funknce vzdy musi byt ve formatu 'jmeno(parametry)' Pokud operator potrebuje VICE operandu, VZDY musi vsehny byt pritomne NENI mozny zapis '!=3' -> chyba Nektere operatory vyzaduji jeden operand (! ~ + - a pod.) Operandy mohou byt CISLA a RETEZCE. Vysledek vyrazu je CISLO nebo RETEZEC. Pokud je vyraz pouzit v IFu tak IF je 'platny' pokud se vrati NENULOVE cislo nebo NEPRAZDNY retezec. {:if 1!=2} znamena tedy: operator != pro 1 2 (ciselny), vysledek bude 1 -> if se provede Mixovani typu. Parser zpracovava operatory zleva. Dokud je to mozne, tak NEMENI typ. Pokud JEDEN z operatoru bude retezec, pak se druhy operator automaticky na retezec prevede. Vysledek pak bdue retezec. Priorita je smoazrejmosti. Priority operatoru (ov nejvetsi po nejmensi) Priklady: abc+xyz+56+1 abcxyz561 1+100+abc 101abc 1+2*3 7 1+2*3*(4*5+mod(10,4)) 133 HAHA HAHA 123 123 !(1=2) 1 `1`!=-2--3 0 -> 1!=-2--3 -> 1!=1 !(`xyz`!="xyz") 1 {test}='this is test' 1 (pokud je variable 'test' nastavena na retezec, ...) Retezce Retezec NEMUSI byt v " ci ' ci ` pokud osbahuje 'povolene' znaky - to jest: pisminka, cisla, . : ? @ mezi " a ' neni defacto zadny rozdil. Pozor na \ u " ktere se chova stejne jako u parametru. - PROBLEMY s vyrazem Na prvni pohled bezvadny vyraz: {:if {var}!=''} selze pokud bude 'var' PRAZNDY retezec. Pripadne kdyz bude obsahovat napr. 'aa='.... Proc ? 'TPL' parser jako parametr vezme: {var}!='' Protoze je to S parametr prozene to TPL enginem. Vznikne !='' priapdne aa=!='' Tento vysledke se prada prikazu IF, ktery zavola expression. A je tu chyba. Toto se resi pomoci ` operatoru. Jak funguje ? ` je v epxressionu to same jako '. Rozdil je jediny - pokud se mezi ` ` objevy CISLO, bere se jako CISLO - ne jako retezec !!! '1'+1 11 `1`+1 2 'a'+1 a1 `a`+1 a1 To je jediny rozdil. Pokud se zpracovava prikaz IF (nikdy jindy !!!) tak prikazy: table.val var (a tedy i {xxx}) (a dalsi) provedou 'enclosing' do `. To znamena, ze pokud bude obsahovat jine znaky nez CISLA, tak se ozavre do ` Prikaz: {:if {var}!=''} z prechozi casti se zmeni na ``!='' `aa=`!='' A vse bude v poradku. Toto implicitni chovani jde zrusit pomoci * - koamdn flagu (stejne jako ?) Pak lze udelat: {:learn oper =} {:if {test} {*oper} 'this is test'}... Bez te * by se 'oper' (v nasem pripade =) prevedlo na `=` a byl by problem. ======================================================================================================================= That's all folks :o) Ray
.... 1.7 Exit -------- Sometimes is required debug template and immediatelly send to browser result and quit parsing. You can use {:exit} command for these purposes. Command doesn't have any real use, except debug. There is also possible to 'exit' only current file, but continue other includes. For this purposes ther is built in command {:return} 1.8 Multilanguage support ------------------------- Template support languages. How it works ? All text are written in SEPARATE file. More languages means, you have more files (english, deutch, ...). Format of file is following: ----test.lng cut here---- @@language_id@@ body can start here and continues @@language_id2@@ or can be just one-line based @@language_id3@@ or for larger text you can use any lines you want ----test.lng cur here---- By directive {@language_id} you reference language string. So, in our case, code: {@language_id3}or for larger text you can use any lines you want