<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>eGroupWare: eTemplate-reference</title> <!-- $Id$ --> <style type="text/css"> <!-- pre { font-family: monospace; background-color: #e0e0e0; padding: 2mm; border-width: thin; border-style: solid; border-color: black; white-space: pre; } span { color: darkblue; font-family: sans-serife; } li { margin-top: 5px; } body { background-color: white; color: black; } table { border: 1px solid black; border-collapse: collapse; } --> </style> </head> <body> <h1>eTemplate-reference - Templates and Dialog-Editor for eGroupWare</h1> <h3>by Ralf Becker <a href="#" onClick="document.location='mai'+'lto:RalfBecker'+unescape('%40')+'outdoor-training'+unescape('%2E')+'de'; return false;">RalfBecker AT outdoor-training DOT de</a></h3> <p>A reference documentation about the new eTemplates and the <a href="#reference">syntax and parameters</a> of the several widgets.</p> <hr> <h1>Introduction - The concept of the eTemplates</h1> <p>As I already covered this in the <a href="etemplate.html">Tutorial</a>, I like would suggest to have a look there if your are not familiar with the overal concept.</p> <p>There are two possibilities now to create an eTemplate:</p> <ol> <li>Use the eTemplate-Editor (as descript in the <a href="etemplate.html">Tutorial</a>) to interactivly design your template.</li> <li>Write a xml-file in a Syntax similar to XUL (the mozilla UI-interface definition language) and import it into the database with the eTemplate-Editor</li> </ol> <hr> <h1>The xml-interface to the eTemplates</h1> <p>The eTemplates-Editor can import and export now eTemplates as xml-files. Here is short example showing an eTemplate from the example app in the <a href="etemplate.html">Tutorial</a> (here are screenshots of the template in the <a href="editor.gif">editor</a> and the <a href="show.gif">show-function</a>):</p> <pre> <?xml version="1.0"?> <!-- $Id$ --> <overlay> <template id="et_media.edit" template="" lang="" group="" version=""> <grid width="100%"> <columns> <column/> <column/> <column/> <column/> </columns> <rows> <row> <description options="ib" span="all" value="eTemplates MediaDB" no_lang="1" id="msg"/> </row> <row> <hrule span="all"/> </row> <row> <description span="all"/> </row> <row> <description value="Name"/> <textbox size="100" maxlength="100" span="all" id="name" statustext="here goes the name of the publication / record"/> </row> <row> <description value="Author"/> <textbox size="100" maxlength="100" span="all" id="author" statustext="please use Name, First Name"/> </row> <row> <description value="Type"/> <menulist span="all" statustext="select the type fitting most"> <menupopup id="type"/> </menulist> </row> <row> <description value="Description"/> <textbox ="" cols="3" rows="100" span="all" id="descr" statustext="we have a fulltext search using that description"/> </row> <row> <description span="all"/> </row> <row> <button label="Read" id="read" statustext="reads or searches for entries matching the criteria above"/> <button label="Save" id="save" statustext="saves the change to the db"/> <button label="Cancel" id="cancel" statustext="clears the form, without changing anything"/> <button label="Delete" id="delete" statustext="deletes an entry"/> </row> </rows> </grid> </template> </overlay> </pre> <p>The tags / widget-names and attributes / parameters used are as close as possible to XUL. For more information about XUL refer to <a href="http://www.xulplanet.com">www.xulplanet.com</a> or the Mozilla docs <a href="http://www.mozilla.org/xpfe/xulref/">www.mozilla.org/xpfe/xulref/</a>.</p> <p>Please keep in mind that the xml-files used to store the eTemplates are only similar to XUL and implement only a subset of XUL. Here are the main differences:</p> <ul> <li>only certain widgets and widget attributes are implemented</li> <li>xul-files can contain the actual content or refer to it via a datasources (RDF's) and use a different template syntax to fill in content from a variable: <label value="?label"/><br /> eTemplates get there content from an array passed to the exec or show-function of the template-object and reference to the content by the id / name-field of each widget.</li> <li>xul-files can contain an unlimited number of nested elements, the xml-root-node of an eTemplates has to be an overlay, containing multiple (non-xul) <template>'s. That templates can contain now (HEAD) a tree of other widgets, but not other templates direct. You can use <template id="app.template_name" /> to load an other template by its name.</i></li> </ul> <p>Like XUL the eTemplate-xml-files are quite strict with the xml-syntax:</p> <ul> <li>All tags and attributes must be written in lowercase</li> <li>All strings must be double quoted, like id="string"</li> <li>Every XUL widget must use close tags (either <tag></tag> or <tag/>) to be well-formed</li> <li>All attributes must have a value, no <tag attr> it has to be <tag attr="1"></li> </ul> <hr> <a name="reference"></a> <h1>Syntax and Parameter reference</h1> <h2>Standard parametes / attributes for <a href="#widgets">all widgets</a></h2> <table border=1> <tr> <th>Name in Editor</th> <th>xml attr</th> <th>xul</th> <th>internal name</th> <th>description of the attribut<th> </tr> <tr> <td><b>Type</b></td> <td>type<br /><i>(only for<br />sub-types)</td> <td>no</td> <td>type</td> <td> The type of the widget is stored in the tag itself, some widgets have sub-types (unknow to XUL). In that case the subtype is stored in the type attribut.<br /> The Type / tag has to be either the name of a standard eTemplate-widget or of an already existing <a href="#extensions">extension</a>. </td> </tr> <tr> <td><b>Name</b></td> <td>id</td> <td>yes</td> <td>name</td> <td> A string to locate the content for the widget in the content array (index) to show the dialog and for the returned content. Can be left blank or be obmitted as xml-attribut if the widget needs no content.<p> The name can contain the following variables, which gets expanded before they are used as array index (for an example see the <a href="etemplate.html">Tutorial</a>):<br /> <table> <tr> <td><b>$c</b></td> <td>the column-number (starting with 0, if you have a header, data-cells start at 1)</td> </tr><tr> <td><b>$col</b></td> <td>the column-letter: 'A', 'B', 'C', ...</td> </tr><tr> <td><b>$row</b></td> <td>the row-number (starting with 0, if you have a header, data-cells start at 1)</td> </tr><tr> <td><b>$cont</b></td> <td>the content-array the (sub-)template, on auto-repeated row's this could eg. be used to generate button-names with id-values in it: "del[$cont[id]]" expands to "del[123]", if $cont = array('id' => 123)</td> </tr><tr> <td><b>$row_cont</b></td> <td>the sub-array indexed by $row of the content-array, on auto-repeated row's this could eg. be used to generate button-names with id-values in it: "del[$row_cont[id]]" expands to "del[123]", if $cont = array('1' => array('id' => 123),'2' => array('id' => 456)) and $row = 1</td> </tr><tr> <td><b>$c_<br />$col_<br />$row_</b></td> <td>are the respective values of the previous template-inclusion, eg. the column-headers in the eTemplate-editor are templates itself, to show the column-name in the header you can not use $col as it will be constant as it is always the same col in the header-template, what you want is the value of the previous template-inclusion.</td> </tr> </table> </td> </tr> <tr> <td><b>Label</b></td> <td>label</td> <td>no</td> <td>label</td> <td> The label is displayed by default in front (for radiobuttons behind) each widget (if not empty). If you want to specify a different position, use a '%s' in the label, which gets replaced by the widget itself. Eg. '%s Name' to have the label Name behind a checkbox. The label can contain variables, as descript for name. If the label starts with a '@' it is replaced by the value of the content-array at this index (with the '@'-removed and after expanding the variables).<br /> <b>Note</b>: The label gets always translated, if its longer than 1 char! If this is not disired, use a label widget, place the not-to-translate label in the content-array <u>and</u> check NoTranslation or set the xml attribute no_lang. </td> </tr> <tr> <td><b>Help</b></td> <td>statustext</td> <td>yes</td> <td>help</td> <td> This text / help-message is displayed in the status-bar of the browser when the widget gets focus (or as tooltip for buttons or general in gtk). If the user has JavaScript switched off, the help-texts get NOT submitted, as this is detected. If the helptext starts with a '@' it is replaced by the value of the content-array at this index (with the '@'-removed and after expanding the variables). </td> </tr> <tr> <td><b>Options</b></td> <td>?</td> <td>?</td> <td>size</td> <td> This attribute controls certain aspects of the different widgets. It's meaning and xml / xul-values are document with the widgets. If the options-string starts with a '@' it is replaced by the value of the content-array at this index (with the '@'-removed and after expanding the variables). </td> </tr> <tr> <td><b>NoTranslation</b></td> <td>no_lang</td> <td>no</td> <td>no_lang</td> <td> If checked the content of the widget and the label gets NOT translated.<br /> The helptext of a widget is always translated. </td> </tr> <tr> <td><b>needed</b></td> <td>needed</td> <td>no</td> <td>needed</td> <td> If checked (xml-attr: needed="1") the etemplates will reprompt the user if he left the widget / field empty.<br /> </td> </tr> <tr> <td><b>Readonly</b></td> <td>readonly</td> <td>yes</td> <td>readonly</td> <td> If checked (xml-attr: readonly="true") the widget will NOT be editable. If it is not supported by the browser, the etemplate-class makes shure that no changes / content is transmitted back to the app. Only applicable to widgets with input capabilities. Readonly Buttons get removed from the dialog, like they where disabled. The readonly attribute could be set on runtime via a readonly-array sublied to the exec or show function of the class, the value on index=name/id has to be true to make a widget readonly. </td> </tr> <tr> <td><b>Disabled</b></td> <td>disabled</td> <td>yes</td> <td>disabled</td> <td> If checked (xml-attr: disabled="true") the widget will NOT be shown. For buttons this could be archived on runtime via setting them readonly. </td> </tr> <tr> <td><b>onChange</b></td> <td>onchange</td> <td>?</td> <td>onchange</td> <td> If checked (xml-attr: onchange="1") and the contet of the widget is changed by the user, the form will be submitted. Via xml or by a program other values can be set (not in the editor at the moment and this is not compatible with the phpGTK implementation of the eTemplates). </td> </tr> <tr> <td><b>Span, Class</b></td> <td>span<br />class</td> <td>span: no<br />class: yes</td> <td>span</td> <td> In the editor and internaly this field contains two comma-separated values:<p> <b>span</b>: how many cell a widget should span (default is one), the special value of 'all' can be used to indicate it should span all remaining cells of a row. This is not supported by xul-grid's at the moment, but is planned to be.<p> <b>class</b>: the CSS class for the widget. If the class-string starts with a '@' it is replaced by the value of the content-array at this index (with the '@'-removed and after expanding the variables). </td> </tr> <tr> <td><b>Align</b></td> <td>align</td> <td>yes</td> <td>align</td> <td> Can be set to 'left' (default), 'center' or 'right'. </td> </tr> <tr> <td><b>Width, Disabled</b><br />column-attr.</td> <td>width</td> <td>yes</td> <td>row[0][#]</td> <td> Can be set to a percentage (eg. '10%'), a number of pixels or ... </td> </tr> <tr> <td><b>Height, Disabled</b><br />row-attr.</td> <td>height</td> <td>yes</td> <td>row[0][h#]</td> <td> Can be set to a percentage (eg. '10%'), a number of pixels or ... </td> </tr> <tr> <td><b>Disabled</b><br />column-attr.<br />row-attr.</td> <td>disabled</td> <td>no</td> <td>disabled</td> <td> Syntax: <b>[!]{@name|value}[={@name2|value2}]</b><br /> Disables (=dont show it) a row/column if a certain criteria is (not (=!)) meet.<br /> If no '=...' / 2. value is given, the test is made on the first value being not empty, else the test is made by comparing the two values. Instead of a value you can give a name as an index into the content prefixed by @. Examples:<br /> <b>!@data</b> disables row/col if value of data is empty, <br /> <b>@val=false</b> disables if value of val is equal to (the string) 'false' </td> </tr> <tr> <td><b>Class, Valign</b><br />row-attr.</td> <td>class<br />valign</td> <td>both: yes</td> <td>row[0][c#]</td> <td> In the editor and internaly this field contains two comma-separated values:<p> <b>class</b>: the CSS class for the row, there are 4 predefined css-classes: nmh: next-match-header-background, nmr: alternating next-match-row-background which gets replaced by the etemplate class with nmr0 or nmr1.<p> <b>valign</b>: vertical alignment of the widgets in the row: 'top', 'middle' (default) or 'bottom' </td> </tr> <tr> <td><b>blurText</b></td> <td>blur</td> <td>no</td> <td>blur</td> <td> This text get displayed if an input-field is empty <u>and</u> does not have the input-focus (blur). It can be used to show a default value or a kind of help-text.<br /> If it contains a text (eg. 'Search...'), this text is run through lang(), if it contains a reference to the content array (eg. '@blur_text') it does <u>not</u> get translated. </td> </tr> </table> <a name="widgets"> <h2>standard widgets and extensions of the eTemplates</h2> <table border="1"> <tr> <th>Widget Name<br />in Editor</th> <th>xml tag</th> <th>xul</th> <th>internal name</th> <th>description of the widget<th> </tr> <tr> <td><b>Label</b></td> <td><description /></td> <td>yes</td> <td>label</td> <td> <b>a textual label</b><br /> The content is taken from the content-array but it can have an own label from the label attribute too.<p> <b>Options</b> has 5 comma-separated fields:<br /> <b>1.</b> if it contains a 'i' and/or a 'b' the content (not the label) is rendered in italic and/or bold.<br /> <b>2.</b> link: if set to a menuaction string or an array with get-params (via the content-arry), a link to that methode = app.class.method is put around the label<br /> <b>3.</b> if set URLs in the content get activated<br /> <b>4.</b> name of form-element the label is for: gives focus to that element if the label gets clicked<br /> <b>5.</b> target for the link, eg. _blank<br /> <b>6.</b> width<i>x</i>height if a popup should be used for the link, eg. 600x400<br /> <b>7.</b> title<i>x</i>title for the link </td> </tr> <tr> <td><b>Text</b></td> <td><textbox /></td> <td>yes</td> <td>text</td> <td> <b>a single-line input field for text</b><br /> In the html-UI this is rendered as <input ...><p> <b>Options</b> has 3 comma-separated fields:<br /> xml: <b>size</b>: the length in chars of the input-field<br /> xml: <b>maxlength</b>: the maximum length of the input<br /> xml: <b>validator</b>: perl regular expression to validate the input (kommas are allowed in the expression) </td> </tr> <tr> <td><b>Integer</b></td> <td><textbox<br />type="int" /></td> <td>?</td> <td>int</td> <td> <b>a input-field to enter an integer</b><br /> In the html-UI this is rendered as <input ...>. <i>The input-validation is done at the moment only on server-side, clientside validation and input-restriction to only numbers is planed.</i><p> <b>Options</b> has 3 comma-separated fields:<br /> xml: <b>min</b>: minimum value, default none, empty values are Ok, as long as <b>needed</b> is not set<br /> xml: <b>max</b>: maximum value, default none, empty values are Ok, as long as <b>needed</b> is not set<br /> xml: <b>size</b>: the length in chars of the input-field, default 5 </td> </tr> <tr> <td><b>Float</b></td> <td><textbox<br />type="float"/></td> <td>?</td> <td>float</td> <td> <b>a input-field to enter a float</b><br /> In the html-UI this is rendered as <input ...>. <i>The input-validation is done at the moment only on server-side, clientside validation and input-restriction to only numbers is planed.</i><p> <b>Options</b> has 4 comma-separated fields:<br /> xml: <b>min</b>: minimum value, default none, empty values are Ok, as long as <b>needed</b> is not set<br /> xml: <b>max</b>: maximum value, default none, empty values are Ok, as long as <b>needed</b> is not set<br /> xml: <b>size</b>: the length in chars of the input-field, default 5 xml: <b>precision</b>: precision of the float number, default maximum </td> </tr> <tr> <td><b>Textarea</b></td> <td><textbox<br />multiline="true" /></td> <td>yes</td> <td>textarea</td> <td> <b>a multiline input-field for text</b><br /> In the html-UI this is rendered as <textarea ...>.<p> <b>Options</b> has 2 comma-separated fields:<br /> xml: <b>cols</b>: the width of the field in chars<br /> xml: <b>rows</b>: the number of rows </td> </tr> <tr> <td><b>Formatted Text</b><br />(HTML)</td> <td><htmlarea /></td> <td>no</td> <td>htmlarea</td> <td> <b>a multiline input-field for formatted (HTML) text</b><br /> In the html-UI this is rendered as <textarea ...> and the HTMLarea javascript editor is used.<p> <b>Options</b> has 5 comma-separated fields:<br /> xml: <b>mode</b>: {ascii|simple|extended|advanced}<br /> xml: <b>height</b>: height of htmlarea<br /> xml: <b>width</b>: width of htmlarea<br /> xml: <b>toolbar</b>: {true|false} show toolbar<br /> xml: <b>base_href</b>: if passed activates the browser for images at the path (relative to the docroot </td> </tr> <tr> <td><b>Checkbox</b></td> <td><checkbox /></td> <td>yes</td> <td>checkbox</td> <td> <b>a widget that can be checked or unchecked</b><br /> In the html-UI this is rendered as <input type="checkbox" ...>. <p>Multiple checkboxes can have an identical name ending with [], in that case the value will be an array with the set_value's of the checked boxes. You can use a button with a custom javascript onclick action of eg. "toggle_all(this.form,form::name('nm[rows][checkbox][]')); return false;" and a set_value of "$row_cont[id]" to toggle all checkboxes in the lines of a nextmatch widget. The <b>form::name( )</b> function translate the name used in the template into the name used in the form. <i>If the button is an image-button, check needed to render it as button and not as image with link, which has no this.form property!</i></p> <b>Options</b>: [set_value][,unset_value[,ro_true[,ro_false]]]<br /> <b>set_value</b>: which value in the content represents the checked state, default=1<br /> <b>unset_value</b>: value in the content representing the unchecked state, default=0<br /> <b>ro_true</b>: what should be displayed for a readonly checked box, default=x<br /> <b>ro_false</b>: display for an unchecked box, can be set to 'disable', to not display the widget (incl. label), default is empty </td> </tr> <tr> <td><b>Radiobutton</b></td> <td><radio /></td> <td>?</td> <td>radio</td> <td> <b>a widget in a group of which only one can be checked</b><br /> In the html-UI this is rendered as <input type="radio" ...><br /> Unlike XUL (and like html) the radio-buttons are grouped by giving them the same name / id.<br /> <b>Options</b>: [set_value][,ro_true[,ro_false]]<br /> <b>set_value</b>: which value in the content represents the checked state, default=1<br /> <b>ro_true</b>: what should be displayed for a readonly checked box, default=x<br /> <b>ro_false</b>: display for an unchecked box, can be set to 'disable', to not display the widget (incl. label), default is empty If the value of the content array at index name/id matches <b>set_value</b> the radiobutton is marked 'checked'. </td> </tr> <tr> <td><b>Submitbutton</b></td> <td><button image="img.gif" ro_image="img-grey.gif" /></td> <td>yes</td> <td>button</td> <td> <b>a button to submit the form / end the dialog</b><br /> In the html-UI this is rendered as <input type="submit" ...>.<br /> If a button is set readonly (via seting its id in the $readonlys array passed to exec) it is not rendered at all (if no ro_image is given), like it would be disabled.<p> <b>needed</b>: if set and the user has JavaScript enabled the button is renderd as a link around the label and a hidden input to set id if the link is clicked.<br /> <b>Options</b> xml: <b>image, ro_image</b>: Image to use instead of a Button with a label. There will be no button around the image. If a ro_image is given (separated by a comma in the editors options) it will be used if the button is set readonly (else the button is no rendered at all) . <b>onclick</b>: specify some java-script to be called if the button gets pressed/clicked: <br /> a) general javascript: "window.close();"<br /> b) confirmation: "return window.confirm('<message>');" (message get run through lang()!)<br /> c) popup: app.class.func&id=$cont[id],target(default _blank),width (default 600),height (default 450) You can use $cont[<name>] or $row_cont[<name>] (note no quotes!) to pass further information to the popup via the content array.) </td> </tr> <tr> <td><b>Button</b></td> <td><buttononly image="img.gif" ro_image="img-grey.gif" /></td> <td>no</td> <td>buttononly</a> <td> <b>a button</b><br /> Same as <b>Submitbutton</b> but it is rendered as <input type="button" ...> in the html-UI </td> </tr> <tr> <td><b>Horizonatal Rule</b></td> <td><hrule /></td> <td>no</td> <td>hrule</td> <td> <b>a horizontal rule / line</b><br /> In the html-UI this is rendered as <hr ...><br /> <b>Options</b> can contain a width of the rule, default is 100% </td> </tr> <tr> <td><b>Template</b></td> <td><template id="app.name" content="subarr" /></td> <td>yes</td> <td>template</td> <td> <b>a separate eTemplate to be loaded into this cell</b><br /> <b>Name</b> xml: <b>id</b>: the name of the etemplate to load<br /> <b>Options</b> xml: <b>content</b>: if set, the template uses an own sub-array of the content array indexed by the value of this field (if not the full content-array is used). Variables like $row can be used as descript for the general attribute Name. </td> </tr> <tr> <td><b>Image</b></td> <td><image src="foo.gif" label="Get a foo" options="app.class.method" /></td> <td>yes</td> <td>image</td> <td> <b>shows an image</b><br /> <b>Label</b> xml: <b>label</b>: the label is shown as tooltip (like html-title)<br /> <b>Name</b> xml: <b>src</b>: the name of the image to load, the image is search in the apps template-dirs<br /> <b>Options</b> xml: <b>options</b>: up to 4 comma-separated values:<br /> <b>1.</b> link to a methode = app.class.method for the image<br /> <b>2.</b> target for the link, eg. _blank<br /> <b>3.</b> imagemap<br /> <b>4.</b> width<i>x</i>height if a popup should be used for the link, eg. 600x400<br /> </td> </tr> <tr> <td><b>Selectbox</b></td> <td> <menulist><br /> <menupopup id="name" options="Select one" /><br /> </menulist><p> <i>multiselect: <b>options</b> > 1</i><br /> <listbox rows="#"/><p> <i>Examples for predefined selectboxes</i>:<p> <listbox type="select-cat" rows="5"/><p> <menulist><br /> <menupopup type="select-account" options="All,both,2"/><br /> </menulist><p> </td> <td>yes</td> <td>select</td> <td> <b>shows a selectbox</b><br /> The content of the selectbox / the options have to be in an array which can be in 2 locations: <ol> <li>in $content["options-$name"]</li> <li>or in an separate array only for select-box-options under the index name, this array is passed to the exec or show function of the etemplate-class</li> </ol> <b>Options</b> <i>in the editor</i>: if set and > 1 the selectbox is a multiselection with options number of lines<p> xml: <b>rows</b>: <i>only for <listbox></i>: number of rows to show<p> xml <b>options</b>: <i>only for <menupopup/></i>: textual label for a first Row, e.g. 'All' or 'None' (id will be ''), additional attr see sub-types<p> xml: <b>type</b>: can be set to get several predefined select-contents, in that case you dont need to set the content as descripted above (if set it too its in front of the predefined rows): <br /> <b>select-cat</b>:<br /> Select an eGW category, determined by the options-field:<br /> ,{no_global_cats},{extra_style_multiselct},{cat_app(default:current app)}<br /> <b>select-account</b>:<br /> Select a user and/or group, determined by the options-field:<br /> ,{accounts(default)|groups|both},{''(phpgw-default)|0(only lid)|1(only names)|2(both)}<br /> <b>select-percent, select-priority, select-access, select-country, select-state</b>:<br /> as you expect by the name<br /> <b>select-year, select-month, select-day</b>:<br /> options for year: ,start,end (start and end can be a number of years from now or if > 100 a absolut year)<br /> <b>select-number</b>:<br /> Select a number out of a range specified by the options-field:<br /> ,{start (default=1)},{end (incl., default=10)},{decrement (default={padding zeros}1)},{suffix}.<br /> Example with padding zeros: options=',0,59,05' will give values: 00, 05, 10, ..., 55 (like you would use it for minutes in a time-field). The suffix get's added to the label of each option.<br /> <b>select-dow</b>:<br /> Select one or multiple weekdays, keys are as defined in MCAL_M_... (1=Sun, 2=Mon, 4=Tue, ...)<br /> <b>select-app</b>:<br /> Select an application, availible options: ,{''=user enabled(default)|installed|all)} </td> </tr> <tr> <td><b>FileUpload</b></td> <td> <file id="name"/><br /> </td> <td>no</td> <td>file</td> <td> <b>Input and Button to select a file for uploading</b><br /> Returns the file-name of the uploaded file in the servers tmp-dir (the webserver needs to have a writable tmp-dir) plus, if javascript is enabled, the local filename of the client as "${name}_path". </td> </tr> <tr> <td><b>Date</b></td> <td> <date options="Y-m-d,1"/><p> <date type="date-time"/><p> <date type="date-timeonly" options="H:i"/><p> <date type="date-houronly"/><p> <date type="date-duration"/> </td> <td>no</td> <td>date</td> <td> <b>Date-/Time-input</b> via selectboxes or a field for the year<br /> The order of the input-fields is determined by the prefs of the user.<br /> <b>Options</b>: [datetime-storage-format] [,&1=year-no-selectbox|&2=today-button|&4=one-min-steps|&8=ro-suppress-0h0]<br /> <b>datetime-storage-format</b> is the format, in which the date is stored in the variable: empty means an unix-timestamp (in GMT), or a string containing the letters <b>Y</b>, <b>m</b>, <b>d</b>, <b>H</b>, <b>i</b> plus separators, eg. 'Y-m-d': 2002-12-31. The storage format for times is always 24h or timestamp with date 1.1.1970 (if no date used). (This has nothing to do with the format of the display, which is only determined by the users preferences.)<br /> <b>year-no-selectbox</b> if set (&1) an int-widget (input-field) is used instead of a select-year widget.<br /> <b>today-button</b>: if set (&2) a [Today] button is displayed which sets the fields to the up-to-date date (via javascript)<br /> <b>one-min-steps</b>: if set (&4) the minute-selectbox uses one minutes steps, default 5min steps<br /> <b>ro-suppress-0h0</b>: if set (&8) the time is suppressed for readonly and a time of 0h0<br /> <b>day-of-week-prefix</b>: if set (&16) readonly dates get prefixed with the day of week<br /> <b>week-number-prefix</b>: if set (&32) readonly dates get prefixed with lang('Wk') & weeknumber<br /> <b>Sub-widgets</b>: <b>date-time</b>: a date and a time and <b>date-timeonly</b> or <b>date-houronly</b>: only a time / hour<br /> These widgets allow the input of times too or only, they use 12h am/pm or 24h format as specified in the user prefs.<br /> <i>If readonly is set, this widget can be used to display a date, without the need to convert it.</i><p> <b>Duration</b> a floating point input with an optional selectbox for the unit (hours or days)<br> <b>Options</b>: [duration-storage-format] [,[duration-display][,hours_per_day]]<br /> <b>duration-storage-format</b>: 'h' = hours (float), 'd' = days (float), default minutes (integer)<br /> <b>duration-display</b>: 'd' = days, 'h' = hours, 'dh' = days or hours with selectbox, optional '%' allows to enter a percentage<br /> <b>hours_per_day</b>: conversation between hours and (working) day, default 8 <b>hours_per_day</b>: conversation between hours and (working) day, default 8 </td> </tr> <tr> <td><b>VBox, HBox, Box</b></td> <td> <vbox><br /> <widget ...><br /> <widget ...><br /> </vbox><p> <hbox span="all"><br /> <widget ...><br /> <widget ...><br /> </hbox><p> <box orient="horizontal"><br /> <widget ...><br /> <widget ...><br /> </box> </td> <td>yes</td> <td>vbox, hbox, box</td> <td> vertical or horizontal <b>container</b> for child widgets. This is useful if one needs more widgets or widgets outside the column- / row-order of a grid. HBox or VBox is rendered as Grid/html:table with only one row or colum. Box is rendered as a html:div containing all child-widgets. Disabled child-cells are completly left out (no empty cells or rows get generated).<p> <b>Options</b> <i>in the editor</i>: the number of cells in the box (does NOT need to be set in xml).<br /> <b>orient</b>: horizontal, vertical or none (means h/vbox as expected and no table for boxes) <b>cellpadding,cellspacing</b>: known table-options <b>keepEmpty</b>: if true, empty cells (lines or rows) are kept, otherwise they are completly removed </td> </tr> <tr> <td><b>GroupBox</b></td> <td> <groupbox><br /> <caption label="Legend"/><br /> <widget ...><br /> <widget ...><br /> </groupbox><p> </td> <td>yes</td> <td>groupbox</td> <td> container to visualy <b>group other widgets</b> by putting a border around them.<br /> The upper line may contain a legend. The widgets are ordered vertical, like a VBox. Disabled child-cells are completly left out (no empty cells or rows get generated).<p> <b>Options</b> <i>in the editor</i>: the number of cells in the box (does NOT need to be set in xml).<br /> <b>orient</b>: horizontal, vertical or none (defaults to vertical) <b>options</b>: cellpadding,cellspacing of the table </td> </tr> <tr> <td><b>Tabs</b></td> <td> <tabbox id="name"><br /> <tabs><br /> <tab label="Tab 1" statustext="Help"/><br /> ...<br /> </tabs><br /> <tabpanels><br /> <grid id="app.name.tab1"/><br /> ...<br /> </tabpanels><br /> </tabbox> </td> <td>yes</td> <td>tab</td> <td> <b>shows a tab-widget</b><br /> The tab-widget is implemented as an extension, as html does not have a tab-widget.<p> The following fields / attributes are in the Editor and internaly in the class separeted by '|', in the xml/xul-file the are attributes of each tab- or grid-tag:<br /> <b>Label</b> xml: <b>label</b>: the labels of the tabs eg. 'Tab 1|Tab 2|Tab 3'<br /> <b>Help</b> xml: <b>statustext</b>: of the tabs<br /> <b>Name</b> xml: <b>id</b>: the names/ids of the eTemplates/grid's to fill the bodies of the tabs, if the name contains no '.', it will be prefixed with the name of the template the widget is in plus a '.' </td> </tr> <tr> <td><b>Manual</b></td> <td> <manual> </td> <td>no</td> <td>manual</td> <td> <b>open the online help</b>: displays a small manual icon.<p> <b>Name</b> xml: <b>id</b>: optional name of the manual page (as index into $content or direct). If no manual page is given, the link included the referer as _GET param. </td> </tr> <tr> <td><b>Custom fields</b></td> <td> <custom_fields> </td> <td>no</td> <td>custom_fields</td> <td> <b>display custom fields</b>: the fields can be configured with admin.customfields.edit&appname={app}<p> The indexes of the custom fields in content are prefixed with a hash (#). </td> </tr> <tr> <td><b>NextMatch</b></td> <td> <nextmatch options="notes.index.rows" id="nm"/> </td> <td>yes</td> <td>tab</td> <td> <b>shows a table with some selectboxes, a search-field and arrows to scroll the table</b><br /> The nextmatch-widget is implemented as an extension.<p> <b>Options</b> xml: <b>options</b>: name of the template to display the rows<br /> <b>Name</b> xml: <b>id</b>: index into the content-array, it need to be pre-set with some information for the nextmatch widget and it returns its content with it: </td> <tr> <td colspan="5"> <pre> $content[$id] = array( <span>// I = value set by the app, 0 = value on return / output</span> 'get_rows' => <span>// I method/callback to request the data for the rows eg. 'notes.bo.get_rows'</span> 'filter_label' => <span>// I label for filter (optional)</span> 'filter_help' => <span>// I help-msg for filter (optional)</span> 'no_filter' => True<span>// I disable the 1. filter</span> 'no_filter2' => True<span>// I disable the 2. filter (params are the same as for filter)</span> 'no_cat' => True<span>// I disable the cat-selectbox</span> 'cat_app' => <span>// I application the cat's should be from, default app in get_rows</span> 'template' => <span>// I template to use for the rows, if not set via options</span> 'header_left' => <span>// I template to show left of the range-value, left-aligned (optional)</span> 'header_right' => <span>// I template to show right of the range-value, right-aligned (optional)</span> 'bottom_too' => True<span>// I show the nextmatch-line (arrows, filters, search, ...) again after the rows</span> 'never_hide' => True<span>// I never hide the nextmatch-line if less then maxmatch entrie</span> 'lettersearch' => True<span>// I show a lettersearch</span> 'searchletter' => <span>// I0 active letter of the lettersearch or false for [all]</span> 'start' => <span>// IO position in list</span> 'num_rows' => <span>// IO number of rows to show, defaults to maxmatches from the general prefs</span> 'cat_id' => <span>// IO category, if not 'no_cat' => True</span> 'search' => <span>// IO search pattern</span> 'order' => <span>// IO name of the column to sort after (optional for the sortheaders)</span> 'sort' => <span>// IO direction of the sort: 'ASC' or 'DESC'</span> 'col_filter' => <span>// IO array of column-name value pairs (optional for the filterheaders)</span> 'filter' => <span>// IO filter, if not 'no_filter' => True</span> 'filter_no_lang' => True<span>// I set no_lang for filter (=dont translate the options)</span> 'filter_onchange'=> 'this.form.submit();'<span>// I onChange action for filter, default: this.form.submit();</span> 'filter2' => <span>// IO filter2, if not 'no_filter2' => True</span> 'filter2_no_lang'=> True<span>// I set no_lang for filter2 (=dont translate the options)</span> 'filter2_onchange'=> 'this.form.submit();'<span>// I onChange action for filter, default: this.form.submit();</span> 'rows' => <span>// O content set by callback</span> 'total' => <span>// O the total number of entries</span> 'sel_options' => <span>// O additional or changed sel_options set by the callback and merged into $tmpl->sel_options</span> 'no_columnselection' => <span>// I turns off the columnselection completly, turned on by default</span> 'columnselection-pref' => <span>// I name of the preference (plus 'nextmatch-' prefix), default = template-name</span> 'default_cols' => <span>// I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns</span> 'options-selectcols' => <span>// I array with name/label pairs for the column-selection, this gets autodetected by default. A name => false hides the column from the column-selection. To completely hide a column, you need to use the Grid column attributes - disabled in eTemplate, and have your get_rows function set a key that matches. For example, if your column name is private_phone, use the eTemplate editor to set column disabled to @no_private_phone, and have your get_rows function set $rows['no_private_phone'] = true (or some calculated condition). </span> 'return' => <span>// IO allows to return something from the get_rows function if $query is a var-param!</span> 'csv_fields' => <span>// I false=disable csv export, true or unset=enable it with auto-detected fieldnames, or array with name=>label or name=>array('label'=>label,'type'=>type) pairs (type is a eT widget-type)</span> ); <span>/* * example: the get_rows function from notes.bo.get_rows (has to be in public_functions !) */</span> function get_rows($query,&$rows,&$readonlys) { $rows = $this->read($query['start'],$query['search'],$query['filter'],$query['cat_id']); if (!is_array($rows)) { $rows = array( ); } $readonlys = array( ); <span>// set readonlys to enable/disable our edit/delete-buttons</span> while (list($n,$note) = each($rows)) { if (!$this->check_perms($this->grants[$note['owner_id']],PHPGW_ACL_EDIT)) { $readonlys["edit[$note[id]]"] = True; } if (!$this->check_perms($this->grants[$note['owner_id']],PHPGW_ACL_DELETE)) { $readonlys["delete[$note[id]]"] = True; } } return $this->total_records; } <span>/* * Example how the nextmatch-widget is used in notes.ui.index: */</span> function index($content = 0) { if (!is_array($content)) { $content = array('nm' => $this->session_data); <span>// restore settings from the session</span> } if (isset($content['nm']['rows'])) <span>// one of the buttons in the rows is pressed</span> { $this->session_data = $values['nm']; <span>// save the settings in the session</span> unset($this->session_data['rows']); <span>// we dont want to save the content of the rows</span> $this->save_sessiondata(); if (isset($values['nm']['rows']['edit'])) { list($id) = each($values['nm']['rows']['edit']); return $this->edit($id); } elseif (isset($values['nm']['rows']['delete'])) { list($id) = each($values['nm']['rows']['delete']); return $this->delete($id); } } $values['nm']['options-filter'] = array ( <span>// set up the data for our filter</span> 'all' => 'Show all', 'public' => 'Only yours', 'private' => 'Private' ); $values['nm']['get_rows'] = 'notes.bo.get_rows'; $values['nm']['no_filter2'] = True; <span>// disable the 2. filter</span> $this->tpl->read('notes.index'); $this->tpl->exec('notes.ui.index',$values); } </pre> </td> </tr> <tr> <td><b>Nextmatch-<br />SortHeader</b><p><b>Nextmatch-<br />FilterHeader</b><p><b>Nextmatch-<br />Custom FilterHeader</b><p><b>Nextmatch-<br />AccountFilter</b></td> <td> <nextmatch type="nextmatch-sortheader" id="col-name" options="DESC" label="ColLabel"/><p> <nextmatch type="nextmatch-filterheader" id="col-name"/><p> <nextmatch type="nextmatch-customfilter" id="col-name" options="select-precent"/><p> <nextmatch type="nextmatch-accountfilter" id="col-name"/> </td> <td>no</td> <td>nextmatch-<br />sortheader<p>nextmatch-<br />filterheader<p>nextmatch-<br />customfilter<p>nextmatch-<br />accountfilter<p>nextmatch-<br />header</td> <td> These widget are an optional part of the nextmatch widget.<p> <b>nextmatch-sortheader</b><br /> Widget to be placed as a colum-header in the headerline of a nextmatch-template. It allows, by clicking on it, to order the lines of the nextmatch after a certain column. The column-name is given as <b>name</b> (xml:id) the <b>label</b> is show as a link of button (no javascript). One can specify a default sorting: <b>options</b>={DESC|ASC} (default=ASC), to be used when the header is clicked for the first time. Consecutive click on the header change the sorting direction, indicated by a little up- or down-arrow. As a second comma-separated parameter one can specify an extra label for the column-selection.<p> <b>nextmatch-filterheader</b><br /> Widget to allow to show only certain row, which match a selected filter-value. The column-name is given as <b>name</b> (xml:id), the options of the displayed selectbox need to be set as for an ordinary selectbox (eg. in the options parameter to the uietemplate::exec function). If no extra-label is given in options, lang('all') will be used for the empty value, which means no filter activ. An (optional) <b>label</b> can be given and is also used for the column-selection.<p> <b>nextmatch-customfilter</b><br /> The custom filterheader allows to use other (select-)widgets to filter by them. They have to be specified as the first parameter in the comma-separated options attribute. In all other aspects it is identical to the filterheader.<p> <b>nextmatch-accountfilter</b><br /> The Accountfilter allows to select users (via the prefered user-selection-method) to filter by them. It's identical to a <b>nextmatch-customfilter</b> with options="select-account".<p> <b>nextmatch-header</b><br /> Just a header-label for a nextmatch column. It names the column for the column for the column-selection (in difference to the label). The name is used to hide the column (with a 'no_' prefix) and as the name for the preference. A different label for the column-selection preference can be specified via the option field.<p> <i><u>Note</u>:</i> All four widgets interoperate with the nextmatch-widget which passes the set values as part if the query-parameter to its get_rows function, they are <u>not</u> returned in the rows sub-array. </td> </tr> <tr> <td><b>LinkWidgets</b></td> <td> <link type="link-to" id="name"/><p> <link type="link-list" id="name"/><p> <link type="link-string" id="name"/><p> </td> <td>no</td> <td>link-to<p>link-list<p>link-string</td> <td> These widgets are the UI-part of the link-class ({bo|so}link) in the API.<p> eGroupWare has a linking system that lets you link two records from different apps together.<p> For example, you can link the addressbook entry of the person you're meeting with to the meeting on your calendar, or an infolog entry for the phone call you made to postpone the meeting.<p> To display links in your own application, you should use the LinkList group of widgets.<p> <b>link-list</b><br /> Widget to shows the links to an entry and a Unlink Button for each link. <p> It needs an array with two entries. If you name the LinkList widget 'links', you need: </p> <pre> $data['links']['to_app'] = 'myapp'; $data['links']['to_id'] = $record_id; </pre> <p>This will display links where the $record_id record of myapp is one side of the link. Make sure that both variables are properly defined before the form template gets executed. <p><b>link-to</b><br /> Widget to make a links to other entries of link-aware apps and to attach files.<p> <i><u>Note</u>:</i> Both Widgets can be used on the same template with the <u>same</u> name. They share the content of the variable with that name, which contains just the id of the entry in the current app.<p> <b>link-string</b><br /> Comma-separated list of link-titles with a link to its view-method, value is like the return of bolink::get_links().<p> <hr> Before you can use a link to your application, you need to specify some information in a 'search_link' hook.<p> In your setup.inc.php, you need to point $setup_info['myapp']['hooks']['search_link'] to a function that will return an array: <p> <pre>return array( 'query' => 'myapp.bo_myapp.link_query', // A function that takes a search string // and returns a list of matching records 'title' => 'myapp.bo_myapp.link_title', // A function that takes an id from one side // of a link and returns a string for that entry 'view' => array('menuaction'=>'myapp.ui_myapp.link_view'), // Function to view a link, may be an existing view function 'view_id' => 'link_id', // name of the id variable provided to the view function above 'add' => array('menuaction' => 'myapp.ui_myapp.new_entry'), // Function to add a new entry ); </pre> <p>Also, make sure that the declared methods are implemented and methods from the UI class are listed in its $public_methods attribute: <pre> class ui_myapp { var $public_methods = array( 'view' => true, 'add' => true ); ... } </pre> </td> </tr> <tr> <td><b>Ajax Select</b></td> <td></td><td></td><td>ajax_select</td> <td> <p>The Ajax Select is a Combo Box. It lets the user type anything they want, and choose from a list of options that are presented below. The user is not limited to the choices, but there is some checking done. If what they type returns several results, and they don't choose one, for example. You can reject any values you don't like in your UI code. It is best used where you might normally want to use a selectbox but your list of data is too large. You can have several on one page, but the name must be different for each.</p> <p><b>Options</b> can be found under the "AJAX Select options" section of the pop-up. </p> <p><b>Data Source</b>: the list options, can be any function that can provide data for a nextmatch widget.</p> <p><b>Title Source</b>: When an option from the list is selected, the text in the search function is replaced with the result of this function. The ID Field is passed. link_title() functions work well.</p> <p><b>ID Field</b>: Data Source is expected to return an array as for a nextmatch, with several columns. This is the key of the column you actually want returned for a value.</p> <p><b>Result row template</b>: (Optional) You can provide a custom eTemplate to use for the list options. It should be constructed similarly to a row template for a nextmatch, and will be repeated for each option.</p> <p><b>Link</b>: (Optional) If the field is read-only, and Link is provided, the widget will turn into a link. Link should look like: perp_ap.ui_perp_supplier.edit&supplier_id=${cont[supplier_id]} where ID Field is supplier_id.</p> <p><b>Icon</b>: (Optional) An icon placed to the left of the search box, to help indicate what the user is searching (addresses, suppliers, etc.). It will be automatically resized.</p> </td> </tr> </table> <h3>One remark about cross-site-scripting</h3> The following eTemplate Widgets are parsing its content before displaying through <b>htmlspecialchars()</b> to correctly display the content and to gard against malecious data (like scripts etc.): <ul> <li>Label</li> <li>Text, Textarea</li> <li>Integer, Float</li> <li>SelectBoxes (it's options-strings)</li> <li>LinkWidgets: link-to, link-list, link-string</li> </ul> This is done in most cases by the underlaying html-class and not direct in eTemplate. <p> <hr> <a name="extensions"> <h1>How to implement new widgets / extensions to the eTemplates?</h1> <p>The eTemplates have an interface to extend them with new widgets. These widgets are php-classes, can use eTemplates to define the UI of the new widget and are stored in the eTemplate's inc-dir or the inc-dir of a eGroupWare application. The editor and the etemplate-class autoload the existing extensions.</p> <i>I have made more <a href="etemplate.html">documentation about the interface</a> available. For additional information, have a look for the source of the existing extensions.</i> <h2>please <a href="#" onClick="document.location='mai'+'lto:RalfBecker'+unescape('%40')+'outdoor-training'+unescape('%2E')+'de'; return false;">contact me</a> if you have further questions or comments about the eTemplates</h2> </body> </html>