Fixed some words
[moodle.git] / lib / formslib.php
CommitLineData
da6f8763 1<?php
2/**
3 * formslib.php - library of classes for creating forms in Moodle, based on PEAR QuickForms.
4 * THIS IS NOT YET PART OF THE MOODLE API, IT IS HERE FOR TESTING ONLY
5 * @author Jamie Pratt
6 * @version $Id$
7 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
8 */
9
10//point pear include path to moodles lib/pear so that includes and requires will search there for files before anywhere else.
11if (FALSE===strstr(ini_get('include_path'), $CFG->libdir.'/pear' )){
12 ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include_path'));
13}
14require_once 'HTML/QuickForm.php';
15require_once 'HTML/QuickForm/DHTMLRulesTableless.php';
16require_once 'HTML/QuickForm/Renderer/Tableless.php';
17
864cc1de 18if ($CFG->debug >= DEBUG_ALL){
19 PEAR::setErrorHandling(PEAR_ERROR_PRINT);
20}
21
7f40a229 22class moodleform {
23 var $_form; // quickform object definition
24 var $_customdata; // globals workaround
25
26 function moodleform($action, $customdata=null, $method='post', $target='', $attributes=null) {
27 $form_name = rtrim(get_class($this), '_form');
28 $this->_customdata = $customdata;
29 $this->_form =& new MoodleQuickForm($form_name, $method, $action, $target, $attributes);
30
31 $this->definition();
32
33 $this->_form->addElement('hidden', 'sesskey', null); // automatic sesskey protection
34 $this->_form->setDefault('sesskey', sesskey());
35 $this->_form->addElement('hidden', '_qf__', null); // form submission marker
36 $this->_form->setDefault('_qf__', 1);
37
38 // we have to know all input types before processing submission ;-)
39 $this->_process_submission($method);
40
41 }
42
43 function _process_submission($method) {
44 $submission = array();
45 if ($method == 'post') {
46 if (!empty($_POST)) {
47 $submission = $_POST;
48 }
49 } else {
50 $submission = array_merge_recursive($_GET, $_POST); // emulate handling of parameters in xxxx_param()
51 }
52
53 // following trick is needed to enable proper sesskey checks when using GET forms
54 // the _qf__ serves as a marker that form was actually submitted
55 if (array_key_exists('_qf__', $submission) and $submission['_qf__'] == 1) {
56 if (!confirm_sesskey()) {
57 error('Incorrect sesskey submitted, form not accepted!');
58 }
59 } else {
60 $submission = array();
61 }
62
63 $this->_form->updateSubmission($submission);
64 }
65
66 function set_defaults($default_values, $slashed=false) {
67 if (is_object($default_values)) {
68 $default_values = (array)$default_values;
69 }
70 $filter = $slashed ? 'stripslashes' : NULL;
71 $this->_form->setDefaults($default_values, $filter);
72 }
73
74 function is_submitted() {
75 return $this->_form->isSubmitted();
76 }
77
78 function is_validated() {
79 static $validated = null;
80
81 if ($validated === null) {
82 $internal_val = $this->_form->validate();
e7dcb0fc 83 $moodle_val = $this->validation($this->_form->exportValues(null, true));
7f40a229 84 if ($moodle_val !== true) {
85 if (!empty($moodle_val)) {
86 foreach ($moodle_val as $element=>$msg) {
87 $this->_form->setElementError($element, $msg);
88 }
89 }
90 $moodle_val = false;
91 }
92 $validated = ($internal_val and $moodle_val);
93 }
94 return $validated;
95 }
96
97 function data_submitted($slashed=true) {
98 if ($this->is_submitted() and $this->is_validated()) {
99 $data = $this->_form->exportValues(null, $slashed);
100 if (empty($data)) {
101 return NULL;
102 } else {
103 return (object)$data;
104 }
105 } else {
106 return NULL;
107 }
108 }
109
110 function display() {
111 $this->_form->display();
112 }
113
114 // abstract method - always override
115 function definition() {
116 error('Abstract form_definition() method in class '.get_class($this).' must be overriden, please fix the code.');
117 }
118
119 // dummy stub method - override if needed
120 function validation($data) {
121 // return array of errors ("fieldname"=>"error message") or true if ok
122 return true;
123 }
124
125}
126
127class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
128 var $_types = array();
129
130
da6f8763 131 /**
132 * Class constructor - same parameters as HTML_QuickForm_DHTMLRulesTableless
133 * @param string $formName Form's name.
134 * @param string $method (optional)Form's method defaults to 'POST'
135 * @param string $action (optional)Form's action
136 * @param string $target (optional)Form's target defaults to none
137 * @param mixed $attributes (optional)Extra attributes for <form> tag
138 * @param bool $trackSubmit (optional)Whether to track if the form was submitted by adding a special hidden field
139 * @access public
140 */
7f40a229 141 function MoodleQuickForm($formName, $method, $action, $target='', $attributes=null){
da6f8763 142 global $CFG;
7f40a229 143
da6f8763 144 HTML_Common::HTML_Common($attributes);
da6f8763 145 $target = empty($target) ? array() : array('target' => $target);
146 //no 'name' atttribute for form in xhtml strict :
147 $attributes = array('action'=>$action, 'method'=>$method, 'id'=>$formName) + $target;
148 $this->updateAttributes($attributes);
da6f8763 149
7f40a229 150 //this is custom stuff for Moodle :
da6f8763 151 $oldclass= $this->getAttribute('class');
152 if (!empty($oldclass)){
153 $this->updateAttributes(array('class'=>$oldclass.' mform'));
154 }else {
80f962df 155 $this->updateAttributes(array('class'=>'mform'));
da6f8763 156 }
7f40a229 157 $this->_helpImageURL="$CFG->wwwroot/lib/form/req.gif";
158 $this->_reqHTML =
da6f8763 159 helpbutton('requiredelement', get_string('requiredelement', 'form'),'moodle',
160 true, false, '', true, '<img alt="'.get_string('requiredelement', 'form').'" src="'.
161 $this->_helpImageURL.'" />');
162 $this->setRequiredNote(get_string('denotesreq', 'form', $this->getReqHTML()));
163 }
7f40a229 164
165 function setType($elementname, $paramtype) {
166 $this->_types[$elementname] = $paramtype;
167 }
c56f1826 168 function setTypes($paramtypes) {
169 $this->_types = $paramtypes + $this->_types;
170 }
7f40a229 171 function updateSubmission($submission) {
172 if (empty($submission)) {
173 $this->_submitValues = array();
174 $this->_flagSubmitted = false;
175 } else {
176 foreach ($submission as $key=>$s) {
177 if (array_key_exists($key, $this->_types)) {
178 $submission[$key] = clean_param($s, $this->_types[$key]);
179 }
180 }
181 $this->_submitValues = $this->_recursiveFilter('stripslashes', $submission);
182 $this->_flagSubmitted = true;
183 }
184
185 // need to tell all elements that they need to update their value attribute.
186 foreach (array_keys($this->_elements) as $key) {
187 $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
188 }
189 }
190
da6f8763 191 function getReqHTML(){
192 return $this->_reqHTML;
193 }
7f40a229 194
195 /**
196 * Initializes a default form value
197 *
198 * @param string $elementname element name
199 * @param mixed $values values for that element name
200 * @param bool $slashed the default value is slashed
201 * @access public
202 * @return void
203 */
204 function setDefault($elementName, $defaultValue, $slashed=false){
205 $filter = $slashed ? 'stripslashes' : NULL;
206 $this->setDefaults(array($elementName=>$defaultValue), $filter);
207 } // end func setDefault
da6f8763 208 /**
c56f1826 209 * Add an array of buttons to the form
7f40a229 210 * @param array $buttons An associative array representing help button to attach to
da6f8763 211 * to the form. keys of array correspond to names of elements in form.
7f40a229 212 *
da6f8763 213 * @access public
214 */
42f248e6 215 function setHelpButtons($buttons, $suppresscheck=false){
7f40a229 216
c56f1826 217 foreach ($buttons as $elementname => $button){
218 $this->setHelpButton($elementname, $button, $suppresscheck);
da6f8763 219 }
220 }
c56f1826 221 /**
222 * Add a single button
223 *
224 * @param string $elementname name of the element to add the item to
225 * @param array $button - arguments to pass to setHelpButton
226 * @param boolean $suppresscheck - whether to throw an error if the element
227 * doesn't exist.
228 */
229 function setHelpButton($elementname, $button, $suppresscheck=false){
230 if (array_key_exists($elementname, $this->_elementIndex)){
231 //_elements has a numeric index, this code accesses the elements by name
232 $element=&$this->_elements[$this->_elementIndex[$elementname]];
233 if (method_exists($element, 'setHelpButton')){
234 $element->setHelpButton($button);
235 }else{
236 $a=new object();
237 $a->name=$element->getName();
238 $a->classname=get_class($element);
239 print_error('nomethodforaddinghelpbutton', 'form', '', $a);
240 }
241 }elseif (!$suppresscheck){
242 print_error('nonexistentformelements', 'form', '', $elementname);
243 }
244 }
7f40a229 245
42f248e6 246 function exportValues($elementList= null, $addslashes=true){
da6f8763 247 $unfiltered=parent::exportValues($elementList);
7f40a229 248 unset($unfiltered['sesskey']); // we do not need to return sesskey
249 unset($unfiltered['_qf__']); // we do not need the submission marker too
250
da6f8763 251 if ($addslashes){
42f248e6 252 return $this->_recursiveFilter('addslashes',$unfiltered);
da6f8763 253 } else {
254 return $unfiltered;
255 }
256 }
257}
258
259/**
7f40a229 260 * A renderer for MoodleQuickForm that only uses XHTML and CSS and no
da6f8763 261 * table tags, extends PEAR class HTML_QuickForm_Renderer_Tableless
7f40a229 262 *
da6f8763 263 * Stylesheet is part of standard theme and should be automatically included.
264 *
265 * @author Jamie Pratt <me@jamiep.org>
266 * @license gpl license
267 */
7f40a229 268class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
da6f8763 269
270 /**
271 * Element template array
272 * @var array
273 * @access private
274 */
275 var $_elementTemplates;
42f248e6 276
49c53687 277// uncomment templates below and edit formslib.php for
42f248e6 278// ol li containers for form items.
279
49c53687 280 /**
281 * Template used when opening a hidden fieldset
282 * (i.e. a fieldset that is opened when there is no header element)
283 * @var string
284 * @access private
285 */
286 var $_openHiddenFieldsetTemplate = "\n\t<fieldset class=\"hidden\">";
42f248e6 287// var $_openHiddenFieldsetTemplate = "\n\t<fieldset class=\"hidden\">\n\t\t<ol>";
288// /**
289// * Header Template string
290// * @var string
291// * @access private
292// */
7f40a229 293// var $_headerTemplate =
42f248e6 294// "\n\t\t<legend>{header}</legend>\n\t\t<ol>";
7f40a229 295// var $_headerTemplate =
49c53687 296// "\n\t\t<legend>{header}</legend>\n\t\t<ol>";
7f40a229 297
49c53687 298 /**
299 * Template used when closing a fieldset
300 * @var string
301 * @access private
302 */
303 var $_closeFieldsetTemplate = "\n\t\t</fieldset>";
42f248e6 304// var $_closeFieldsetTemplate = "\n\t\t</ol>\n\t</fieldset>";
305
49c53687 306 /**
307 * Required Note template string
308 * @var string
309 * @access private
310 */
7f40a229 311 var $_requiredNoteTemplate =
49c53687 312 "\n\t\t<div class=\"fdescription\">{requiredNote}</div>";
7f40a229 313
314 function MoodleQuickForm_Renderer(){
42f248e6 315 // switch next two lines for ol li containers for form items.
49c53687 316 // $this->_elementTemplates=array('default'=>"\n\t\t<li class=\"fitem\"><label>{label}{help}<!-- BEGIN required -->{req}<!-- END required --></label><div class=\"qfelement<!-- BEGIN error --> error<!-- END error --> {type}\"><!-- BEGIN error --><span class=\"error\">{error}</span><br /><!-- END error -->{element}</div></li>");
15fdf619 317 $this->_elementTemplates=array('default'=>"\n\t\t<div class=\"fitem\"><label>{label}{help}<!-- BEGIN required -->{req}<!-- END required --></label><div class=\"felement<!-- BEGIN error --> error<!-- END error --> {type}\"><!-- BEGIN error --><span class=\"error\">{error}</span><br /><!-- END error -->{element}</div></div>",
318 'fieldset'=>"\n\t\t<div class=\"fitem\"><label>{label}{help}<!-- BEGIN required -->{req}<!-- END required --></label><fieldset class=\"felement<!-- BEGIN error --> error<!-- END error --> {type}\"><!-- BEGIN error --><span class=\"error\">{error}</span><br /><!-- END error -->{element}</fieldset></div>");
da6f8763 319
320 parent::HTML_QuickForm_Renderer_Tableless();
321 }
7f40a229 322
da6f8763 323 function startForm(&$form){
324 $this->_reqHTML=$form->getReqHTML();
325 $this->_elementTemplates=str_replace('{req}', $this->_reqHTML, $this->_elementTemplates);
326 parent::startForm($form);
327 }
7f40a229 328
da6f8763 329 function startGroup(&$group, $required, $error){
330 if (method_exists($group, 'getElementTemplateType')){
e249661f 331 $html = $this->_elementTemplates[$group->getElementTemplateType()];
da6f8763 332 }else{
333 $html = $this->_elementTemplates['default'];
7f40a229 334
da6f8763 335 }
336 if (method_exists($group, 'getHelpButton')){
337 $html =str_replace('{help}', $group->getHelpButton(), $html);
338 }else{
339 $html =str_replace('{help}', '', $html);
7f40a229 340
da6f8763 341 }
49c53687 342 $html =str_replace('{type}', 'fgroup', $html);
7f40a229 343
da6f8763 344 $this->_templates[$group->getName()]=$html;
345 // Fix for bug in tableless quickforms that didn't allow you to stop a
346 // fieldset before a group of elements.
347 // if the element name indicates the end of a fieldset, close the fieldset
348 if ( in_array($group->getName(), $this->_stopFieldsetElements)
349 && $this->_fieldsetsOpen > 0
350 ) {
351 $this->_html .= $this->_closeFieldsetTemplate;
352 $this->_fieldsetsOpen--;
353 }
354 parent::startGroup($group, $required, $error);
355 }
7f40a229 356
da6f8763 357 function renderElement(&$element, $required, $error){
358 if (method_exists($element, 'getElementTemplateType')){
359 $html = $this->_elementTemplates[$element->getElementTemplateType()];
360 }else{
361 $html = $this->_elementTemplates['default'];
7f40a229 362
da6f8763 363 }
49c53687 364 $html =str_replace('{type}', 'f'.$element->getType(), $html);
da6f8763 365 if (method_exists($element, 'getHelpButton')){
366 $html=str_replace('{help}', $element->getHelpButton(), $html);
367 }else{
368 $html=str_replace('{help}', '', $html);
7f40a229 369
da6f8763 370 }
371 $this->_templates[$element->getName()]=$html;
230a910a 372 if (!is_null($element->getAttribute('id'))) {
373 $id = $element->getAttribute('id');
374 } else {
375 $id = $element->getName();
376 }
377 $element->updateAttributes(array('id'=>'id_'.$id));
da6f8763 378 parent::renderElement($element, $required, $error);
379 }
da6f8763 380}
381
da6f8763 382
7f40a229 383$GLOBALS['_HTML_QuickForm_default_renderer']=& new MoodleQuickForm_Renderer();
da6f8763 384
7f40a229 385MoodleQuickForm::registerElementType('checkbox', "$CFG->libdir/form/checkbox.php", 'MoodleQuickForm_checkbox');
386MoodleQuickForm::registerElementType('file', "$CFG->libdir/form/file.php", 'MoodleQuickForm_file');
387MoodleQuickForm::registerElementType('group', "$CFG->libdir/form/group.php", 'MoodleQuickForm_group');
388MoodleQuickForm::registerElementType('password', "$CFG->libdir/form/password.php", 'MoodleQuickForm_password');
389MoodleQuickForm::registerElementType('radio', "$CFG->libdir/form/radio.php", 'MoodleQuickForm_radio');
390MoodleQuickForm::registerElementType('select', "$CFG->libdir/form/select.php", 'MoodleQuickForm_select');
391MoodleQuickForm::registerElementType('text', "$CFG->libdir/form/text.php", 'MoodleQuickForm_text');
392MoodleQuickForm::registerElementType('textarea', "$CFG->libdir/form/textarea.php", 'MoodleQuickForm_textarea');
393MoodleQuickForm::registerElementType('date_selector', "$CFG->libdir/form/dateselector.php", 'MoodleQuickForm_date_selector');
394MoodleQuickForm::registerElementType('date_time_selector', "$CFG->libdir/form/datetimeselector.php", 'MoodleQuickForm_date_time_selector');
395MoodleQuickForm::registerElementType('htmleditor', "$CFG->libdir/form/htmleditor.php", 'MoodleQuickForm_htmleditor');
396MoodleQuickForm::registerElementType('static', "$CFG->libdir/form/static.php", 'MoodleQuickForm_static');
397MoodleQuickForm::registerElementType('hidden', "$CFG->libdir/form/hidden.php", 'MoodleQuickForm_hidden');
864cc1de 398
da6f8763 399?>