Actions

Difference between revisions of "Developer Area/Core Subsystems/Form API (Pieforms)/Form APIElements"

From Mahara Wiki

< Developer Area‎ | Core Subsystems‎ | Form API (Pieforms)
(Created page with "<div class="toolbar"><br /> There are many elements that can be used in the form API, and it's easy to write new ones if necessary. This page describes the API for creating your …")
 
Line 1: Line 1:
 
<div class="toolbar"><br /> There are many elements that can be used in the form API, and it's easy to write new ones if necessary. This page describes the API for creating your own types, and details how each of the current types work.</div><div id="section_1">
 
<div class="toolbar"><br /> There are many elements that can be used in the form API, and it's easy to write new ones if necessary. This page describes the API for creating your own types, and details how each of the current types work.</div><div id="section_1">
  
=== <br /> The element API ===
+
===<br /> The element API===
  
 
Elements are stored in <code>lib/form/elements/*.php</code>, the filename being the name of the element as it should be referred to in the <code>type</code> section of the element array. The files should follow the library template as defined in [http://old.eduforge.org/wiki/wiki/mahara/wiki?pagename=BasicPHPFileTemplates BasicPHPFileTemplates]. The subpackage name should be "form-element".
 
Elements are stored in <code>lib/form/elements/*.php</code>, the filename being the name of the element as it should be referred to in the <code>type</code> section of the element array. The files should follow the library template as defined in [http://old.eduforge.org/wiki/wiki/mahara/wiki?pagename=BasicPHPFileTemplates BasicPHPFileTemplates]. The subpackage name should be "form-element".
Line 9: Line 9:
 
<div id="section_2">
 
<div id="section_2">
  
==== form_render_$type($element, Form $form) ====
+
====form_render_$type($element, Form $form)====
  
 
This function returns the HTML to build the element. It takes the element array to build and the form the element is to be built for as arguments. There are some helper methods available for populating common attributes of any widgets in the element, such as tabindex, name, id etc.
 
This function returns the HTML to build the element. It takes the element array to build and the form the element is to be built for as arguments. There are some helper methods available for populating common attributes of any widgets in the element, such as tabindex, name, id etc.
Line 15: Line 15:
 
Here is the form_render_text function, which renders a standard
 
Here is the form_render_text function, which renders a standard
  
  element: <div class="plugin tightenable"><code><font color="#000000"> <font color="#ff8000">/**<br /> * Provides a basic text field input.<br /> *<br /> * @param array $element The element to render<br /> * @param Form  $form    The form to render the element for<br /> * @return string        The HTML for the element<br /> */<br /></font><font color="#007700">function </font><font color="#0000bb">form_render_text</font><font color="#007700">(</font><font color="#0000bb">$element</font><font color="#007700">, </font><font color="#0000bb">$form</font><font color="#007700">) {<br />     return </font><font color="#dd0000">'         </font><font color="#007700">. </font><font color="#0000bb">Form</font><font color="#007700"><nowiki>::</nowiki></font><font color="#0000bb">element_attributes</font><font color="#007700">(</font><font color="#0000bb">$element</font><font color="#007700">)<br />         . </font><font color="#dd0000">' value="' </font><font color="#007700">. </font><font color="#0000bb">hsc</font><font color="#007700">(</font><font color="#0000bb">$form</font><font color="#007700">-&gt;</font><font color="#0000bb">get_value</font><font color="#007700">(</font><font color="#0000bb">$element</font><font color="#007700">)) . </font><font color="#dd0000">'"&gt;'</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /></font> </font> </code></div>
+
  element: <div class="plugin tightenable"><code><font color="#000000"> <font color="#ff8000">/**<br /> * Provides a basic text field input.<br /> *<br /> * @param array $element The element to render<br /> * @param Form  $form    The form to render the element for<br /> * @return string        The HTML for the element<br /> */<br /></font><font color="#007700">function </font><font color="#0000bb">form_render_text</font><font color="#007700">(</font><font color="#0000bb">$element</font><font color="#007700">, </font><font color="#0000bb">$form</font><font color="#007700">) {<br />     return </font><font color="#dd0000">'         </font><font color="#007700">. </font><font color="#0000bb">Form</font><font color="#007700">::</font><font color="#0000bb">element_attributes</font><font color="#007700">(</font><font color="#0000bb">$element</font><font color="#007700">)<br />         . </font><font color="#dd0000">' value="' </font><font color="#007700">. </font><font color="#0000bb">hsc</font><font color="#007700">(</font><font color="#0000bb">$form</font><font color="#007700">-&gt;</font><font color="#0000bb">get_value</font><font color="#007700">(</font><font color="#0000bb">$element</font><font color="#007700">)) . </font><font color="#dd0000">'"&gt;'</font><font color="#007700">;<br /> }<br /></font> </font> </code></div>
  
 
In this function you can see the use of the two methods that help with creating attributes for the element - the static method <code>Form::element_attributes</code> and the method <code>$form-&gt;get_value</code>.
 
In this function you can see the use of the two methods that help with creating attributes for the element - the static method <code>Form::element_attributes</code> and the method <code>$form-&gt;get_value</code>.
Line 50: Line 50:
 
</div><div id="section_3">
 
</div><div id="section_3">
  
==== form_get_value_$type($element, Form $form) ====
+
====form_get_value_$type($element, Form $form)====
  
 
This function is optional, and defines behaviour for getting the value of the $element from the request. This allows elements to do things like return a synthesised value if they are composed of many form widgets. For example, the 'date' element consists of three dropdown boxes, but the <code>form_get_value_date</code> function gets those value and returns a unix timestamp.
 
This function is optional, and defines behaviour for getting the value of the $element from the request. This allows elements to do things like return a synthesised value if they are composed of many form widgets. For example, the 'date' element consists of three dropdown boxes, but the <code>form_get_value_date</code> function gets those value and returns a unix timestamp.
Line 58: Line 58:
 
</div><div id="section_4">
 
</div><div id="section_4">
  
==== form_get_value_js_$type($element, Form $form) ====
+
====form_get_value_js_$type($element, Form $form)====
  
 
This function is optional. When forms are [http://old.eduforge.org/wiki/wiki/mahara/wiki?pagename=FormAPIAJAXForms submitted by AJAX], the value of each element needs to be retrieved via javascript to be placed in the request. By default, <code>document.forms[formname].elements[elementname].value</code> is used for the value, which works for most standard elements, however some elements (like the date picker) may be comprised of multiple values that need to be sent. This function gives these elements a way to specify the javascript required.
 
This function is optional. When forms are [http://old.eduforge.org/wiki/wiki/mahara/wiki?pagename=FormAPIAJAXForms submitted by AJAX], the value of each element needs to be retrieved via javascript to be placed in the request. By default, <code>document.forms[formname].elements[elementname].value</code> is used for the value, which works for most standard elements, however some elements (like the date picker) may be comprised of multiple values that need to be sent. This function gives these elements a way to specify the javascript required.
Line 66: Line 66:
 
The javascript returns needs to populate the javascript array field <code>data['elementname']</code> with the correct value. Here is an example for the 'radio' element:
 
The javascript returns needs to populate the javascript array field <code>data['elementname']</code> with the correct value. Here is an example for the 'radio' element:
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#007700">function </font><font color="#0000bb">form_get_value_js_radio</font><font color="#007700">(</font><font color="#0000bb">$element</font><font color="#007700">, </font><font color="#0000bb">Form $form</font><font color="#007700">) {<br />     </font><font color="#0000bb">$formname </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">$form</font><font color="#007700">-&gt;</font><font color="#0000bb">get_name</font><font color="#007700">();<br />     </font><font color="#0000bb">$name </font><font color="#007700"><nowiki>= </nowiki></font><font color="#0000bb">$element</font><font color="#007700">[</font><font color="#dd0000">'name'</font><font color="#007700">];<br />     return &lt;&lt; </font><font color="#0000bb">    var radio = document.forms</font><font color="#007700">[</font><font color="#0000bb">'$formname'</font><font color="#007700">]</font><font color="#0000bb">.elements</font><font color="#007700">[</font><font color="#0000bb">'$name'</font><font color="#007700">]</font><font color="#0000bb"><nowiki>;</nowiki><br />     for (var i = 0; i &lt; radio.length; i++) </font><font color="#007700">{</font><font color="#0000bb"><br />         if (radio</font><font color="#007700">[</font><font color="#0000bb">i</font><font color="#007700">]</font><font color="#0000bb">.checked) </font><font color="#007700">{</font><font color="#0000bb"><br />             data</font><font color="#007700">[</font><font color="#0000bb">'$name'</font><font color="#007700">]</font><font color="#0000bb"> = radio</font><font color="#007700">[</font><font color="#0000bb">i</font><font color="#007700">]</font><font color="#0000bb">.value;<br />             break;<br />         </font><font color="#007700">}</font><font color="#0000bb"><br />     </font><font color="#007700">}</font><font color="#0000bb"><br /><br /></font><font color="#007700">EOF;<br /> }<br /></font> </font> </code></div>
+
<div class="plugin tightenable"><code><font color="#000000"> <font color="#007700">function </font><font color="#0000bb">form_get_value_js_radio</font><font color="#007700">(</font><font color="#0000bb">$element</font><font color="#007700">, </font><font color="#0000bb">Form $form</font><font color="#007700">) {<br />     </font><font color="#0000bb">$formname </font><font color="#007700">= </font><font color="#0000bb">$form</font><font color="#007700">-&gt;</font><font color="#0000bb">get_name</font><font color="#007700">();<br />     </font><font color="#0000bb">$name </font><font color="#007700">= </font><font color="#0000bb">$element</font><font color="#007700">[</font><font color="#dd0000">'name'</font><font color="#007700">];<br />     return &lt;&lt; </font><font color="#0000bb">    var radio = document.forms</font><font color="#007700">[</font><font color="#0000bb">'$formname'</font><font color="#007700">]</font><font color="#0000bb">.elements</font><font color="#007700">[</font><font color="#0000bb">'$name'</font><font color="#007700">]</font><font color="#0000bb">;<br />     for (var i = 0; i &lt; radio.length; i++) </font><font color="#007700">{</font><font color="#0000bb"><br />         if (radio</font><font color="#007700">[</font><font color="#0000bb">i</font><font color="#007700">]</font><font color="#0000bb">.checked) </font><font color="#007700">{</font><font color="#0000bb"><br />             data</font><font color="#007700">[</font><font color="#0000bb">'$name'</font><font color="#007700">]</font><font color="#0000bb"> = radio</font><font color="#007700">[</font><font color="#0000bb">i</font><font color="#007700">]</font><font color="#0000bb">.value;<br />             break;<br />         </font><font color="#007700">}</font><font color="#0000bb"><br />     </font><font color="#007700">}</font><font color="#0000bb"><br /><br /></font><font color="#007700">EOF;<br /> }<br /></font> </font> </code></div>
  
 
'''NOTE:''' The javascript needs to make the data array have the values that are expected by the <code>form_get_value_$type</code> function (if there is one), or have the same type of value that would otherwise be expected by a user of the element in a non AJAX form.
 
'''NOTE:''' The javascript needs to make the data array have the values that are expected by the <code>form_get_value_$type</code> function (if there is one), or have the same type of value that would otherwise be expected by a user of the element in a non AJAX form.
Line 72: Line 72:
 
</div><div id="section_5">
 
</div><div id="section_5">
  
==== form_render_${type}_set_attributes ====
+
====form_render_${type}_set_attributes====
  
 
This function is optional, and takes an element of its type and returns the element. This is a hook so that the elements can change, add or delete various indexes from the element, or do validation.
 
This function is optional, and takes an element of its type and returns the element. This is a hook so that the elements can change, add or delete various indexes from the element, or do validation.
Line 78: Line 78:
 
Example:
 
Example:
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#007700">function </font><font color="#0000bb">form_render_select_set_attributes</font><font color="#007700">(</font><font color="#0000bb">$element</font><font color="#007700">) {<br />     </font><font color="#0000bb">$element</font><font color="#007700">[</font><font color="#dd0000">'rules'</font><font color="#007700">][</font><font color="#dd0000">'validateoptions'</font><font color="#007700">] = </font><font color="#0000bb">true</font><font color="#007700"><nowiki>;</nowiki><br />     return </font><font color="#0000bb">$element</font><font color="#007700"><nowiki>;</nowiki><br /> }<br /></font> </font> </code></div>
+
<div class="plugin tightenable"><code><font color="#000000"> <font color="#007700">function </font><font color="#0000bb">form_render_select_set_attributes</font><font color="#007700">(</font><font color="#0000bb">$element</font><font color="#007700">) {<br />     </font><font color="#0000bb">$element</font><font color="#007700">[</font><font color="#dd0000">'rules'</font><font color="#007700">][</font><font color="#dd0000">'validateoptions'</font><font color="#007700">] = </font><font color="#0000bb">true</font><font color="#007700">;<br />     return </font><font color="#0000bb">$element</font><font color="#007700">;<br /> }<br /></font> </font> </code></div>
  
 
In this example, all select element automatically have the 'validateoptions' rule applied to them, which ensures that the only options that can be submitted come from the options inserted into the select to start with.
 
In this example, all select element automatically have the 'validateoptions' rule applied to them, which ensures that the only options that can be submitted come from the options inserted into the select to start with.
Line 84: Line 84:
 
</div></div><div id="section_6">
 
</div></div><div id="section_6">
  
=== Elements ===
+
===Elements===
  
 
The following section lists all of the supported elements and their behaviour.
 
The following section lists all of the supported elements and their behaviour.
Line 90: Line 90:
 
<div id="section_7">
 
<div id="section_7">
  
==== cancel ====
+
====cancel====
  
 
The cancel element is for a cancel button. When pressed, the cancel callback will be called, rather than the sumbit one, and no validation will take place.
 
The cancel element is for a cancel button. When pressed, the cancel callback will be called, rather than the sumbit one, and no validation will take place.
Line 98: Line 98:
 
</div><div id="section_8">
 
</div><div id="section_8">
  
==== checkbox ====
+
====checkbox====
  
 
This renders a simple checkbox, and automatically handles how checkbox values are not sent if they are not checked on form submission.
 
This renders a simple checkbox, and automatically handles how checkbox values are not sent if they are not checked on form submission.
Line 106: Line 106:
 
</div><div id="section_9">
 
</div><div id="section_9">
  
==== date ====
+
====date====
  
 
This renders three select boxes, for choosing the year, month and day. Later on, it may render a calendar picker.
 
This renders three select boxes, for choosing the year, month and day. Later on, it may render a calendar picker.
Line 114: Line 114:
 
The following configuration indexes apply to the date element:
 
The following configuration indexes apply to the date element:
  
* '''minyear'''<nowiki>: The smallest year that should be in the 'year' dropdown</nowiki>
+
* '''minyear''': The smallest year that should be in the 'year' dropdown
* '''maxyear'''<nowiki>: The largest year that should be in the 'year' dropdown</nowiki>
+
* '''maxyear''': The largest year that should be in the 'year' dropdown
  
 
The date element supports 'value' and 'defaultvalue' also, both of which should be an array in the form <code>array($year, $month, $day)</code>.
 
The date element supports 'value' and 'defaultvalue' also, both of which should be an array in the form <code>array($year, $month, $day)</code>.
Line 121: Line 121:
 
</div><div id="section_10">
 
</div><div id="section_10">
  
==== fieldset ====
+
====fieldset====
  
 
This renders a group of elements inside an HTML
 
This renders a group of elements inside an HTML
Line 133: Line 133:
 
</div><div id="section_11">
 
</div><div id="section_11">
  
==== file ====
+
====file====
  
 
This renders a basic
 
This renders a basic
Line 139: Line 139:
 
. Most likely broken right now when retrieving the value, harass Nigel about it if you need it. </div><div id="section_12">
 
. Most likely broken right now when retrieving the value, harass Nigel about it if you need it. </div><div id="section_12">
  
==== hidden ====
+
====hidden====
  
 
This renders a
 
This renders a
Line 149: Line 149:
 
</div><div id="section_13">
 
</div><div id="section_13">
  
==== password ====
+
====password====
  
 
This renders an
 
This renders an
Line 155: Line 155:
 
  element. This does not listen to 'defaultvalue' for security reasons, but its handling of values may need to be revamped later. </div><div id="section_14">
 
  element. This does not listen to 'defaultvalue' for security reasons, but its handling of values may need to be revamped later. </div><div id="section_14">
  
==== radio ====
+
====radio====
  
 
This renders a series of
 
This renders a series of
Line 161: Line 161:
 
  elements. The radio buttons should be specified in the 'options' index, in the form $value =&gt; $text. </div><div id="section_15">
 
  elements. The radio buttons should be specified in the 'options' index, in the form $value =&gt; $text. </div><div id="section_15">
  
==== select ====
+
====select====
  
 
This renders a
 
This renders a
Line 173: Line 173:
 
Example:
 
Example:
  
<div class="plugin tightenable"><code><font color="#000000"> <font color="#dd0000">'select' </font><font color="#007700"><nowiki>=&gt; array(</nowiki><br />         </font><font color="#dd0000">'type' </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#dd0000">'select'</font><font color="#007700">,<br />         </font><font color="#dd0000">'title' </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'select'</font><font color="#007700">),<br />         </font><font color="#dd0000">'options' </font><font color="#007700"><nowiki>=&gt; array(</nowiki><br />             </font><font color="#0000bb">1 </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'onebanana'</font><font color="#007700">),<br />             </font><font color="#0000bb">2 </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'twobananas'</font><font color="#007700">),<br />             </font><font color="#0000bb">3 </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'threebananas'</font><font color="#007700">)<br />         ),<br />         </font><font color="#dd0000">'defaultvalue' </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#0000bb">2<br />     </font><font color="#007700">)<br /><br /></font><font color="#ff8000">// a multiple select<br />     </font><font color="#dd0000">'multiselect' </font><font color="#007700"><nowiki>=&gt; array(</nowiki><br />         </font><font color="#dd0000">'type' </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#dd0000">'select'</font><font color="#007700">,<br />         </font><font color="#dd0000">'title' </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'select'</font><font color="#007700">),<br />         </font><font color="#dd0000">'multiple' </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#0000bb">true</font><font color="#007700">,<br />         </font><font color="#dd0000">'options' </font><font color="#007700"><nowiki>=&gt; array(</nowiki><br />             </font><font color="#0000bb">1 </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'onebanana'</font><font color="#007700">),<br />             </font><font color="#0000bb">2 </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'twobananas'</font><font color="#007700">),<br />             </font><font color="#0000bb">3 </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'threebananas'</font><font color="#007700">)<br />         ),<br />         </font><font color="#dd0000">'defaultvalue' </font><font color="#007700"><nowiki>=&gt; array(</nowiki></font><font color="#0000bb">2</font><font color="#007700">, </font><font color="#0000bb">3</font><font color="#007700">),<br />         </font><font color="#dd0000">'size' </font><font color="#007700"><nowiki>=&gt; </nowiki></font><font color="#0000bb">3<br />     </font><font color="#007700">)<br /></font> </font> </code></div></div><div id="section_16">
+
<div class="plugin tightenable"><code><font color="#000000"> <font color="#dd0000">'select' </font><font color="#007700">=&gt; array(<br />         </font><font color="#dd0000">'type' </font><font color="#007700">=&gt; </font><font color="#dd0000">'select'</font><font color="#007700">,<br />         </font><font color="#dd0000">'title' </font><font color="#007700">=&gt; </font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'select'</font><font color="#007700">),<br />         </font><font color="#dd0000">'options' </font><font color="#007700">=&gt; array(<br />             </font><font color="#0000bb">1 </font><font color="#007700">=&gt; </font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'onebanana'</font><font color="#007700">),<br />             </font><font color="#0000bb">2 </font><font color="#007700">=&gt; </font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'twobananas'</font><font color="#007700">),<br />             </font><font color="#0000bb">3 </font><font color="#007700">=&gt; </font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'threebananas'</font><font color="#007700">)<br />         ),<br />         </font><font color="#dd0000">'defaultvalue' </font><font color="#007700">=&gt; </font><font color="#0000bb">2<br />     </font><font color="#007700">)<br /><br /></font><font color="#ff8000">// a multiple select<br />     </font><font color="#dd0000">'multiselect' </font><font color="#007700">=&gt; array(<br />         </font><font color="#dd0000">'type' </font><font color="#007700">=&gt; </font><font color="#dd0000">'select'</font><font color="#007700">,<br />         </font><font color="#dd0000">'title' </font><font color="#007700">=&gt; </font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'select'</font><font color="#007700">),<br />         </font><font color="#dd0000">'multiple' </font><font color="#007700">=&gt; </font><font color="#0000bb">true</font><font color="#007700">,<br />         </font><font color="#dd0000">'options' </font><font color="#007700">=&gt; array(<br />             </font><font color="#0000bb">1 </font><font color="#007700">=&gt; </font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'onebanana'</font><font color="#007700">),<br />             </font><font color="#0000bb">2 </font><font color="#007700">=&gt; </font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'twobananas'</font><font color="#007700">),<br />             </font><font color="#0000bb">3 </font><font color="#007700">=&gt; </font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'threebananas'</font><font color="#007700">)<br />         ),<br />         </font><font color="#dd0000">'defaultvalue' </font><font color="#007700">=&gt; array(</font><font color="#0000bb">2</font><font color="#007700">, </font><font color="#0000bb">3</font><font color="#007700">),<br />         </font><font color="#dd0000">'size' </font><font color="#007700">=&gt; </font><font color="#0000bb">3<br />     </font><font color="#007700">)<br /></font> </font> </code></div></div><div id="section_16">
  
==== submit ====
+
====submit====
  
 
This renders an
 
This renders an
Line 181: Line 181:
 
  element. Clicking one of these buttons will submit the form, and trigger the validation and submission callbacks (the submission one only if the validation succeeds). </div><div id="section_17">
 
  element. Clicking one of these buttons will submit the form, and trigger the validation and submission callbacks (the submission one only if the validation succeeds). </div><div id="section_17">
  
==== submitcancel ====
+
====submitcancel====
  
 
This renders a submit button and a cancel button next to one another. The cancel function will need to be called '${formname}_cancel_submit'.
 
This renders a submit button and a cancel button next to one another. The cancel function will need to be called '${formname}_cancel_submit'.
Line 187: Line 187:
 
</div><div id="section_18">
 
</div><div id="section_18">
  
==== textarea ====
+
====textarea====
  
 
This renders a
 
This renders a

Revision as of 15:13, 11 May 2011


There are many elements that can be used in the form API, and it's easy to write new ones if necessary. This page describes the API for creating your own types, and details how each of the current types work.


The element API

Elements are stored in lib/form/elements/*.php, the filename being the name of the element as it should be referred to in the type section of the element array. The files should follow the library template as defined in BasicPHPFileTemplates. The subpackage name should be "form-element".

The file must contain one mandatory function, and some optional functions.

form_render_$type($element, Form $form)

This function returns the HTML to build the element. It takes the element array to build and the form the element is to be built for as arguments. There are some helper methods available for populating common attributes of any widgets in the element, such as tabindex, name, id etc.

Here is the form_render_text function, which renders a standard

element:
/**
* Provides a basic text field input.
*
* @param array $element The element to render
* @param Form  $form    The form to render the element for
* @return string        The HTML for the element
*/
function form_render_text($element, $form) {
    return
'         . Form::element_attributes($element)
        .
' value="' . hsc($form->get_value($element)) . '">';
}

In this function you can see the use of the two methods that help with creating attributes for the element - the static method Form::element_attributes and the method $form->get_value.

Form::element_attributes takes the element that the function was passed, and returns a standard HTML attribute string. This allows all elements to instantly support the following attributes without having to do any work:

  • accesskey
  • class
  • dir
  • disabled
  • id
  • lang
  • maxlength (only if a maxlength rule is declared on the element)
  • name
  • onclick
  • readonly
  • size
  • style
  • tabindex

The second paramter to element_attributes is an array of elements to ignore when building the attribute string. So if your elements do not use some, remove them this way.

The "value" attribute is not included, as how the value for an element is put into the HTML varies quite significantly depending on the element, and is also form dependent if the form has been submitted.

$form->get_value is how you get the value for the element. This takes into account the following things, in order:

  • Whether a callback function to get the value has been defined (see below)
  • Whether the 'value' key of the $element array has been specified
  • Whether the value has been submitted with the form
  • Whether the 'defaultvalue' key of the $element array has been specified

Ignoring the first option temporarily, this allows people to specify a 'value' attribute that becomes the value regardless of whether the element is changed when the form is posted, which is useful for hidden elements, form submit buttons and markup. It also allows them to set a default value, which will be overridden by any submitted data.

form_get_value_$type($element, Form $form)

This function is optional, and defines behaviour for getting the value of the $element from the request. This allows elements to do things like return a synthesised value if they are composed of many form widgets. For example, the 'date' element consists of three dropdown boxes, but the form_get_value_date function gets those value and returns a unix timestamp.

Elements implementing this should probably support 'value' and 'defaultvalue' in the same way as the behaviour above.

form_get_value_js_$type($element, Form $form)

This function is optional. When forms are submitted by AJAX, the value of each element needs to be retrieved via javascript to be placed in the request. By default, document.forms[formname].elements[elementname].value is used for the value, which works for most standard elements, however some elements (like the date picker) may be comprised of multiple values that need to be sent. This function gives these elements a way to specify the javascript required.

The alternative to having to specify this function (and also the PHP-based form_get_value_$type function), is to make the element serialise its value to a hidden input field named after the element, which is possible with a little javascript magic. This sidesteps the need for these functions, at the cost of making the element unusable for those with javascript turned off. Given that Mahara requires javascript however, that cost is eradicated.

The javascript returns needs to populate the javascript array field data['elementname'] with the correct value. Here is an example for the 'radio' element:

function form_get_value_js_radio($element, Form $form) {
    
$formname = $form->get_name();
    
$name = $element['name'];
    return <<
    var radio = document.forms['$formname'].elements['$name'];
    for (var i = 0; i < radio.length; i++)
{
        if (radio
[i].checked) {
            data
['$name'] = radio[i].value;
            break;
        
}
    
}

EOF;
}

NOTE: The javascript needs to make the data array have the values that are expected by the form_get_value_$type function (if there is one), or have the same type of value that would otherwise be expected by a user of the element in a non AJAX form.

form_render_${type}_set_attributes

This function is optional, and takes an element of its type and returns the element. This is a hook so that the elements can change, add or delete various indexes from the element, or do validation.

Example:

function form_render_select_set_attributes($element) {
    
$element['rules']['validateoptions'] = true;
    return
$element;
}

In this example, all select element automatically have the 'validateoptions' rule applied to them, which ensures that the only options that can be submitted come from the options inserted into the select to start with.

Elements

The following section lists all of the supported elements and their behaviour.

cancel

The cancel element is for a cancel button. When pressed, the cancel callback will be called, rather than the sumbit one, and no validation will take place.

It takes no special configuration values.

checkbox

This renders a simple checkbox, and automatically handles how checkbox values are not sent if they are not checked on form submission.

If the 'value' index is not empty, the checkbox is assumed to be checked. The checkbox element also has a 'checked' index, which behaves like the 'defaultvalue' index otherwise would. (note for later, this might be changed for consistency depending on developers' opinion).

date

This renders three select boxes, for choosing the year, month and day. Later on, it may render a calendar picker.

The value returned is a unix timestamp representation of the selected date.

The following configuration indexes apply to the date element:

  • minyear: The smallest year that should be in the 'year' dropdown
  • maxyear: The largest year that should be in the 'year' dropdown

The date element supports 'value' and 'defaultvalue' also, both of which should be an array in the form array($year, $month, $day).

fieldset

This renders a group of elements inside an HTML

element. The elements to render inside are specified by the 'elements' index.

Rather than have a 'title', fieldsets have a 'legend' index, which is used to render the fieldset legend.

Fieldsets do not have any of the other standard attributes, such as IDs or names, tab indexes etc.

file

This renders a basic

. Most likely broken right now when retrieving the value, harass Nigel about it if you need it.

hidden

This renders a

element for scalars, or multiple elements if the value is an array. This allows arrays to be transparently passed around between pages, which is incredibly useful for things like the transient login form, or for select elements that have are multiple selects.

Possibly contains more attributes than necessary when rendered right now, but that will not affect its general usage.

password

This renders an

element. This does not listen to 'defaultvalue' for security reasons, but its handling of values may need to be revamped later.

radio

This renders a series of

elements. The radio buttons should be specified in the 'options' index, in the form $value => $text.

select

This renders a

dropdown list, and supports multiple selections. The options should be specified in the 'options' index in the form $value => $text.

If there is only one option in the list, by default it will be "collapsed", so that only the readable version of the option is displayed, and a hidden input element will contain the value. If you wish to disable this behaviour, set the 'collapseifoneoption' field to false.

If the element is a multiple select, set the 'multiple' index to true. You can also set the size of the select using the 'size' attribute.

Example:

'select' => array(
        
'type' => 'select',
        
'title' => get_string('select'),
        
'options' => array(
            
1 => get_string('onebanana'),
            
2 => get_string('twobananas'),
            
3 => get_string('threebananas')
        ),
        
'defaultvalue' => 2
    
)

// a multiple select
    
'multiselect' => array(
        
'type' => 'select',
        
'title' => get_string('select'),
        
'multiple' => true,
        
'options' => array(
            
1 => get_string('onebanana'),
            
2 => get_string('twobananas'),
            
3 => get_string('threebananas')
        ),
        
'defaultvalue' => array(2, 3),
        
'size' => 3
    
)

submit

This renders an

element. Clicking one of these buttons will submit the form, and trigger the validation and submission callbacks (the submission one only if the validation succeeds).

submitcancel

This renders a submit button and a cancel button next to one another. The cancel function will need to be called '${formname}_cancel_submit'.

textarea

This renders a

. You can set the size either by using 'rows'/'cols', or 'width'/'height' (specified in pixels). If width and height are used, a value for rows and columns is automatically synthesised, to preserve HTML compliance.</p>

</div><div id="section_19"><h4 class="editable">text</h4>
<p class="tightenable">This renders a basic <input type="text"> element, that works exactly as expected.</p>
</div><div id="section_20"><h4 class="editable">wysiwyg</h4>
<p class="tightenable">In future, this will render a wysiwyg textarea based on the users' preferences. For now, it just renders a textarea.</p>
</div><div id="section_21"><h4 class="editable">userlist</h4>
<p class="tightenable">This renders an element that allows selection of a subset of users of Mahara. It it rendered as two multiselect boxes coupled with a search feature, and users move "potential" users from the left box to the box on the right (selected members).</p>
<p class="tightenable">This element does <strong>NOT</strong> honour the 'value' attribute, nor any of the standard attributes (given it is a multi-element type element). It does however honour the 'defaultvalue' attribute.</p>
<p class="tightenable">Values passed to this element (via defaultvalue) and returned by the element (after a post/get) are <strong>always</strong> arrays (possibly the empty array) of user ids.</p>
<p class="tightenable">If 'filter' is set to false, the select box used to choose groups/communities for filtering is displayed.</p>
<p class="tightenable">If the 'required' rule is set, there must be at least one 'value' in the right hand side select list upon submission.</p>
<p class="tightenable">Example:</p>
<code><font color="#000000"> <font color="#dd0000">'userlist' </font><font color="#007700">=> array(<br />
        </font><font color="#dd0000">'type' </font><font color="#007700">=> </font><font color="#dd0000">'userlist'</font><font color="#007700">,<br />
        </font><font color="#dd0000">'title' </font><font color="#007700">=> </font><font color="#0000bb">get_string</font><font color="#007700">(</font><font color="#dd0000">'userlist'</font><font color="#007700">)<br />
        </font><font color="#dd0000">'defaultvalue' </font><font color="#007700">=> array(</font><font color="#0000bb">1</font><font color="#007700">, </font><font color="#0000bb">2</font><font color="#007700">, </font><font color="#0000bb">5</font><font color="#007700">),<br />
        </font><font color="#dd0000">'filter' </font><font color="#007700">=> </font><font color="#0000bb">false</font><font color="#007700">,<br />
        </font><font color="#dd0000">'rules' </font><font color="#007700">=> array(</font><font color="#dd0000">'required' </font><font color="#007700">=> </font><font color="#0000bb">true</font><font color="#007700">)<br />
    )<br />
);</font></font></code></div></div></html>