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. |
11 | if (FALSE===strstr(ini_get('include_path'), $CFG->libdir.'/pear' )){ |
12 | ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include_path')); |
13 | } |
14 | require_once 'HTML/QuickForm.php'; |
15 | require_once 'HTML/QuickForm/DHTMLRulesTableless.php'; |
16 | require_once 'HTML/QuickForm/Renderer/Tableless.php'; |
17 | |
864cc1de |
18 | if ($CFG->debug >= DEBUG_ALL){ |
19 | PEAR::setErrorHandling(PEAR_ERROR_PRINT); |
20 | } |
21 | |
7f40a229 |
22 | class 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 | |
127 | class 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 |
268 | class 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 |
385 | MoodleQuickForm::registerElementType('checkbox', "$CFG->libdir/form/checkbox.php", 'MoodleQuickForm_checkbox'); |
386 | MoodleQuickForm::registerElementType('file', "$CFG->libdir/form/file.php", 'MoodleQuickForm_file'); |
387 | MoodleQuickForm::registerElementType('group', "$CFG->libdir/form/group.php", 'MoodleQuickForm_group'); |
388 | MoodleQuickForm::registerElementType('password', "$CFG->libdir/form/password.php", 'MoodleQuickForm_password'); |
389 | MoodleQuickForm::registerElementType('radio', "$CFG->libdir/form/radio.php", 'MoodleQuickForm_radio'); |
390 | MoodleQuickForm::registerElementType('select', "$CFG->libdir/form/select.php", 'MoodleQuickForm_select'); |
391 | MoodleQuickForm::registerElementType('text', "$CFG->libdir/form/text.php", 'MoodleQuickForm_text'); |
392 | MoodleQuickForm::registerElementType('textarea', "$CFG->libdir/form/textarea.php", 'MoodleQuickForm_textarea'); |
393 | MoodleQuickForm::registerElementType('date_selector', "$CFG->libdir/form/dateselector.php", 'MoodleQuickForm_date_selector'); |
394 | MoodleQuickForm::registerElementType('date_time_selector', "$CFG->libdir/form/datetimeselector.php", 'MoodleQuickForm_date_time_selector'); |
395 | MoodleQuickForm::registerElementType('htmleditor', "$CFG->libdir/form/htmleditor.php", 'MoodleQuickForm_htmleditor'); |
396 | MoodleQuickForm::registerElementType('static', "$CFG->libdir/form/static.php", 'MoodleQuickForm_static'); |
397 | MoodleQuickForm::registerElementType('hidden', "$CFG->libdir/form/hidden.php", 'MoodleQuickForm_hidden'); |
864cc1de |
398 | |
da6f8763 |
399 | ?> |