From c6a4c409349205ad462b3edc16ffdba7f5effb16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hans-J=C3=BCrgen=20Tappe?=
There are two possibilities now to create an eTemplate:
-<?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>
+<?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>
The tags / widget-names and attributes / parameters used are as close as possible to XUL. For more
information about XUL refer to www.xulplanet.com or the Mozilla docs
@@ -95,22 +95,22 @@ information about XUL refer to www.xulplanet.
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: Like XUL the eTemplate-xml-files are quite strict with the xml-syntax:
-
+ different template syntax to fill in content from a variable: <label value="?label"/>
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.
+ and reference to the content by the id / name-field of each widget.
-
@@ -161,12 +161,12 @@ implement only a subset of XUL. Here are the main differences:
+ In the html-UI this is rendered as <input ...>
Options has 3 comma-separated fields:
xml: size: the length in chars of the input-field
xml: maxlength: the maximum length of the input
@@ -410,12 +410,12 @@ implement only a subset of XUL. Here are the main differences:
Options has 3 comma-separated fields:
xml: min: minimum value, default none, empty values are Ok, as long as needed is not set
@@ -425,12 +425,12 @@ implement only a subset of XUL. Here are the main differences:
Options has 4 comma-separated fields:
xml: min: minimum value, default none, empty values are Ok, as long as needed is not set
@@ -441,12 +441,12 @@ implement only a subset of XUL. Here are the main differences:
+ In the html-UI this is rendered as <textarea ...>.
Options has 2 comma-separated fields:
xml: cols: the width of the field in chars
xml: rows: the number of rows
@@ -454,12 +454,12 @@ implement only a subset of XUL. Here are the main differences:
+ In the html-UI this is rendered as <textarea ...> and the HTMLarea javascript editor is used.
Options has 5 comma-separated fields:
xml: mode: {ascii|simple|extended|advanced}
xml: height: height of htmlarea
@@ -470,15 +470,15 @@ implement only a subset of XUL. Here are the main differences:
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 + In the html-UI this is rendered as <input type="checkbox" ...>. +
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 form::name( ) function translate the name used in the template into the name used in the form. 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!
@@ -491,12 +491,12 @@ implement only a subset of XUL. Here are the main differences:
- needed: if set and the user has JavaScript enabled the button is renderd as a link around the label
+ needed: 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.
Options xml: image, ro_image: 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)
@@ -523,35 +523,35 @@ implement only a subset of XUL. Here are the main differences:
+ <menulist>
+ <menupopup id="name" options="Select one" />
+ </menulist>
multiselect: options > 1
- <listbox rows="#"/>
+ <listbox rows="#"/>
Examples for predefined selectboxes:
- <listbox type="select-cat" rows="5"/>
- <menulist>
- <menupopup type="select-account" options="All,both,2"/>
- </menulist>
+ <listbox type="select-cat" rows="5"/>
+ <menulist>
+ <menupopup type="select-account" options="All,both,2"/>
+ </menulist>
+ Options in the editor: if set and > 1 the selectbox is a multiselection with options number of lines
xml: rows: only for <listbox>: number of rows to show
xml options: only for <menupopup/>: textual label for a first Row, e.g. 'All' or 'None' (id will be ''), additional attr see sub-types
@@ -621,7 +621,7 @@ implement only a subset of XUL. Here are the main differences:
as you expect by the name- <date type="date-time"/>
- <date type="date-timeonly" options="H:i"/>
- <date type="date-houronly"/>
- <date type="date-duration"/> + <date options="Y-m-d,1"/>
+ <date type="date-time"/>
+ <date type="date-timeonly" options="H:i"/>
+ <date type="date-houronly"/>
+ <date type="date-duration"/>
Duration a floating point input with an optional selectbox for the unit (hours or days)
@@ -689,18 +689,18 @@ implement only a subset of XUL. Here are the main differences:
- <hbox span="all">
- <widget ...>
- <widget ...>
- </hbox>
- <box orient="horizontal">
- <widget ...>
- <widget ...>
- </box>
+ <vbox>
+ <widget ...>
+ <widget ...>
+ </vbox>
+ <hbox span="all">
+ <widget ...>
+ <widget ...>
+ </hbox>
+ <box orient="horizontal">
+ <widget ...>
+ <widget ...>
+ </box>
+ <groupbox>
+ <caption label="Legend"/>
+ <widget ...>
+ <widget ...>
+ </groupbox>
+ display custom fields: the fields can be configured with admin.customfields.edit&appname={app}
The indexes of the custom fields in content are prefixed with a hash (#).
$content[$id] = array( // I = value set by the app, 0 = value on return / output - 'get_rows' => // I method/callback to request the data for the rows eg. 'notes.bo.get_rows' - 'filter_label' => // I label for filter (optional) - 'filter_help' => // I help-msg for filter (optional) - 'no_filter' => True// I disable the 1. filter - 'no_filter2' => True// I disable the 2. filter (params are the same as for filter) - 'no_cat' => True// I disable the cat-selectbox - 'cat_app' => // I application the cat's should be from, default app in get_rows - 'template' => // I template to use for the rows, if not set via options - 'header_left' => // I template to show left of the range-value, left-aligned (optional) - 'header_right' => // I template to show right of the range-value, right-aligned (optional) - 'bottom_too' => True// I show the nextmatch-line (arrows, filters, search, ...) again after the rows - 'never_hide' => True// I never hide the nextmatch-line if less then maxmatch entrie - 'lettersearch' => True// I show a lettersearch - 'searchletter' => // I0 active letter of the lettersearch or false for [all] - 'start' => // IO position in list - 'num_rows' => // IO number of rows to show, defaults to maxmatches from the general prefs - 'cat_id' => // IO category, if not 'no_cat' => True - 'search' => // IO search pattern - 'order' => // IO name of the column to sort after (optional for the sortheaders) - 'sort' => // IO direction of the sort: 'ASC' or 'DESC' - 'col_filter' => // IO array of column-name value pairs (optional for the filterheaders) - 'filter' => // IO filter, if not 'no_filter' => True - 'filter_no_lang' => True// I set no_lang for filter (=dont translate the options) - 'filter_onchange'=> 'this.form.submit();'// I onChange action for filter, default: this.form.submit(); - 'filter2' => // IO filter2, if not 'no_filter2' => True - 'filter2_no_lang'=> True// I set no_lang for filter2 (=dont translate the options) - 'filter2_onchange'=> 'this.form.submit();'// I onChange action for filter, default: this.form.submit(); - 'rows' => // O content set by callback - 'total' => // O the total number of entries - 'sel_options' => // O additional or changed sel_options set by the callback and merged into $tmpl->sel_options - 'no_columnselection' => // I turns off the columnselection completly, turned on by default - 'columnselection-pref' => // I name of the preference (plus 'nextmatch-' prefix), default = template-name - 'default_cols' => // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns - 'options-selectcols' => // 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. + 'get_rows' => // I method/callback to request the data for the rows eg. 'notes.bo.get_rows' + 'filter_label' => // I label for filter (optional) + 'filter_help' => // I help-msg for filter (optional) + 'no_filter' => True// I disable the 1. filter + 'no_filter2' => True// I disable the 2. filter (params are the same as for filter) + 'no_cat' => True// I disable the cat-selectbox + 'cat_app' => // I application the cat's should be from, default app in get_rows + 'template' => // I template to use for the rows, if not set via options + 'header_left' => // I template to show left of the range-value, left-aligned (optional) + 'header_right' => // I template to show right of the range-value, right-aligned (optional) + 'bottom_too' => True// I show the nextmatch-line (arrows, filters, search, ...) again after the rows + 'never_hide' => True// I never hide the nextmatch-line if less then maxmatch entrie + 'lettersearch' => True// I show a lettersearch + 'searchletter' => // I0 active letter of the lettersearch or false for [all] + 'start' => // IO position in list + 'num_rows' => // IO number of rows to show, defaults to maxmatches from the general prefs + 'cat_id' => // IO category, if not 'no_cat' => True + 'search' => // IO search pattern + 'order' => // IO name of the column to sort after (optional for the sortheaders) + 'sort' => // IO direction of the sort: 'ASC' or 'DESC' + 'col_filter' => // IO array of column-name value pairs (optional for the filterheaders) + 'filter' => // IO filter, if not 'no_filter' => True + 'filter_no_lang' => True// I set no_lang for filter (=dont translate the options) + 'filter_onchange'=> 'this.form.submit();'// I onChange action for filter, default: this.form.submit(); + 'filter2' => // IO filter2, if not 'no_filter2' => True + 'filter2_no_lang'=> True// I set no_lang for filter2 (=dont translate the options) + 'filter2_onchange'=> 'this.form.submit();'// I onChange action for filter, default: this.form.submit(); + 'rows' => // O content set by callback + 'total' => // O the total number of entries + 'sel_options' => // O additional or changed sel_options set by the callback and merged into $tmpl->sel_options + 'no_columnselection' => // I turns off the columnselection completly, turned on by default + 'columnselection-pref' => // I name of the preference (plus 'nextmatch-' prefix), default = template-name + 'default_cols' => // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns + 'options-selectcols' => // 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, + 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). - 'return' => // IO allows to return something from the get_rows function if $query is a var-param! - 'csv_fields' => // 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) + 'return' => // IO allows to return something from the get_rows function if $query is a var-param! + 'csv_fields' => // 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) ); /* * example: the get_rows function from notes.bo.get_rows (has to be in public_functions !) */ -function get_rows($query,&$rows,&$readonlys) +function get_rows($query,&$rows,&$readonlys) { - $rows = $this->read($query['start'],$query['search'],$query['filter'],$query['cat_id']); + $rows = $this->read($query['start'],$query['search'],$query['filter'],$query['cat_id']); if (!is_array($rows)) { $rows = array( ); @@ -863,16 +863,16 @@ function get_rows($query,&$rows,&$readonlys) $readonlys = array( ); // set readonlys to enable/disable our edit/delete-buttons while (list($n,$note) = each($rows)) { - if (!$this->check_perms($this->grants[$note['owner_id']],PHPGW_ACL_EDIT)) + 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)) + if (!$this->check_perms($this->grants[$note['owner_id']],PHPGW_ACL_DELETE)) { $readonlys["delete[$note[id]]"] = True; } } - return $this->total_records; + return $this->total_records; } /* @@ -882,35 +882,35 @@ function index($content = 0) { if (!is_array($content)) { - $content = array('nm' => $this->session_data); // restore settings from the session + $content = array('nm' => $this->session_data); // restore settings from the session } if (isset($content['nm']['rows'])) // one of the buttons in the rows is pressed { - $this->session_data = $values['nm']; // save the settings in the session - unset($this->session_data['rows']); // we dont want to save the content of the rows - $this->save_sessiondata(); + $this->session_data = $values['nm']; // save the settings in the session + unset($this->session_data['rows']); // we dont want to save the content of the rows + $this->save_sessiondata(); if (isset($values['nm']['rows']['edit'])) { list($id) = each($values['nm']['rows']['edit']); - return $this->edit($id); + return $this->edit($id); } elseif (isset($values['nm']['rows']['delete'])) { list($id) = each($values['nm']['rows']['delete']); - return $this->delete($id); + return $this->delete($id); } } $values['nm']['options-filter'] = array ( // set up the data for our filter - 'all' => 'Show all', - 'public' => 'Only yours', - 'private' => 'Private' + 'all' => 'Show all', + 'public' => 'Only yours', + 'private' => 'Private' ); $values['nm']['get_rows'] = 'notes.bo.get_rows'; $values['nm']['no_filter2'] = True; // disable the 2. filter - $this->tpl->read('notes.index'); - $this->tpl->exec('notes.ui.index',$values); + $this->tpl->read('notes.index'); + $this->tpl->exec('notes.ui.index',$values); }
Nextmatch-
FilterHeader
Nextmatch-
Custom FilterHeader
Nextmatch-
AccountFilter
- <nextmatch type="nextmatch-filterheader" id="col-name"/>
- <nextmatch type="nextmatch-customfilter" id="col-name" options="select-precent"/>
- <nextmatch type="nextmatch-accountfilter" id="col-name"/> + <nextmatch type="nextmatch-sortheader" id="col-name" options="DESC" label="ColLabel"/>
+ <nextmatch type="nextmatch-filterheader" id="col-name"/>
+ <nextmatch type="nextmatch-customfilter" id="col-name" options="select-precent"/>
+ <nextmatch type="nextmatch-accountfilter" id="col-name"/>
nextmatch-
filterheader
nextmatch-
customfilter
nextmatch-
accountfilter
nextmatch-
header
@@ -943,7 +943,7 @@ function index($content = 0) 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.
nextmatch-accountfilter
- The Accountfilter allows to select users (via the prefered user-selection-method) to filter by them.
+ The Accountfilter allows to select users (via the prefered user-selection-method) to filter by them.
It's identical to a nextmatch-customfilter with options="select-account".
nextmatch-header
Just a header-label for a nextmatch column. It names the column for the column for the column-selection (in difference to the label).
@@ -956,9 +956,9 @@ function index($content = 0)
- <link type="link-list" id="name"/>
- <link type="link-string" id="name"/>
+ <link type="link-to" id="name"/>
+ <link type="link-list" id="name"/>
+ <link type="link-string" id="name"/>
link-list
link-string
Also, make sure that the declared methods are implemented and methods from the UI class are listed in its $public_methods attribute:
class ui_myapp { var $public_methods = array( - 'view' => true, - 'add' => true + 'view' => true, + 'add' => true ); ... } @@ -1021,14 +1021,14 @@ class ui_myapp {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 +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.
Options can be found under the "AJAX Select options" section of the pop-up.
Data Source: the list options, can be any function that can provide data for a nextmatch widget.
Title Source: 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.
ID Field: 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.
Result row template: (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.
-Link: (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.
+Link: (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.
Icon: (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.