da1320da |
1 | <?php // $Id$ |
da6f8763 |
2 | /** |
3 | * formslib.php - library of classes for creating forms in Moodle, based on PEAR QuickForms. |
da1320da |
4 | * |
5 | * To use formslib then you will want to create a new file purpose_form.php eg. edit_form.php |
6 | * and you want to name your class something like {modulename}_{purpose}_form. Your class will |
7 | * extend moodleform overriding abstract classes definition and optionally defintion_after_data |
8 | * and validation. |
9 | * |
10 | * See examples of use of this library in course/edit.php and course/edit_form.php |
11 | * |
12 | * A few notes : |
13 | * form defintion is used for both printing of form and processing and should be the same |
14 | * for both or you may lose some submitted data which won't be let through. |
15 | * you should be using setType for every form element except select, radio or checkbox |
16 | * elements, these elements clean themselves. |
17 | * |
18 | * |
da6f8763 |
19 | * @author Jamie Pratt |
20 | * @version $Id$ |
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU Public License |
22 | */ |
23 | |
24 | //point pear include path to moodles lib/pear so that includes and requires will search there for files before anywhere else. |
25 | if (FALSE===strstr(ini_get('include_path'), $CFG->libdir.'/pear' )){ |
26 | ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include_path')); |
27 | } |
28 | require_once 'HTML/QuickForm.php'; |
29 | require_once 'HTML/QuickForm/DHTMLRulesTableless.php'; |
30 | require_once 'HTML/QuickForm/Renderer/Tableless.php'; |
31 | |
49292f8c |
32 | require_once $CFG->libdir.'/uploadlib.php'; |
33 | |
864cc1de |
34 | if ($CFG->debug >= DEBUG_ALL){ |
35 | PEAR::setErrorHandling(PEAR_ERROR_PRINT); |
36 | } |
37 | |
05f5c40c |
38 | /** |
da1320da |
39 | * Moodle specific wrapper that separates quickforms syntax from moodle code. You won't directly |
40 | * use this class you should write a class defintion which extends this class or a more specific |
41 | * subclass such a moodleform_mod for each form you want to display and/or process with formslib. |
42 | * |
43 | * You will write your own definition() method which performs the form set up. |
05f5c40c |
44 | */ |
7f40a229 |
45 | class moodleform { |
49292f8c |
46 | var $_formname; // form name |
3c7656b4 |
47 | /** |
48 | * quickform object definition |
49 | * |
50 | * @var MoodleQuickForm |
51 | */ |
52 | var $_form; |
53 | /** |
54 | * globals workaround |
55 | * |
56 | * @var array |
57 | */ |
58 | var $_customdata; |
59 | /** |
60 | * file upload manager |
61 | * |
62 | * @var upload_manager |
63 | */ |
64 | var $_upload_manager; // |
7f40a229 |
65 | |
ebd3c7ac |
66 | /** |
67 | * Array of buttons that if pressed do not result in the processing of the form. |
68 | * |
69 | * @var array |
70 | */ |
71 | var $_nosubmitbuttons=array(); |
72 | |
da1320da |
73 | /** |
74 | * The constructor function calls the abstract function definition() and it will then |
75 | * process and clean and attempt to validate incoming data. |
76 | * |
77 | * It will call your custom validate method to validate data and will also check any rules |
78 | * you have specified in definition using addRule |
79 | * |
80 | * The name of the form (id attribute of the form) is automatically generated depending on |
81 | * the name you gave the class extending moodleform. You should call your class something |
82 | * like |
83 | * |
84 | * @param string $action the action attribute for the form. |
85 | * @param array $customdata if your form defintion method needs access to data such as $course |
86 | * $cm, etc. to construct the form definition then pass it in this array. You can |
87 | * use globals for somethings. |
88 | * @param string $method if you set this to anything other than 'post' then _GET and _POST will |
89 | * be merged and used as incoming data to the form. |
90 | * @param string $target target frame for form submission. You will rarely use this. Don't use |
91 | * it if you don't need to as the target attribute is deprecated in xhtml |
92 | * strict. |
93 | * @param mixed $attributes you can pass a string of html attributes here or an array. |
94 | * @return moodleform |
95 | */ |
7f40a229 |
96 | function moodleform($action, $customdata=null, $method='post', $target='', $attributes=null) { |
5bc97c98 |
97 | $this->_formname = rtrim(get_class($this), '_form'); |
7f40a229 |
98 | $this->_customdata = $customdata; |
5bc97c98 |
99 | $this->_form =& new MoodleQuickForm($this->_formname, $method, $action, $target, $attributes); |
7f40a229 |
100 | |
101 | $this->definition(); |
102 | |
103 | $this->_form->addElement('hidden', 'sesskey', null); // automatic sesskey protection |
104 | $this->_form->setDefault('sesskey', sesskey()); |
5bc97c98 |
105 | $this->_form->addElement('hidden', '_qf__'.$this->_formname, null); // form submission marker |
106 | $this->_form->setDefault('_qf__'.$this->_formname, 1); |
107 | $this->_form->_setDefaultRuleMessages(); |
7f40a229 |
108 | |
109 | // we have to know all input types before processing submission ;-) |
110 | $this->_process_submission($method); |
111 | |
05f5c40c |
112 | // update form definition based on final data |
113 | $this->definition_after_data(); |
7f40a229 |
114 | } |
05f5c40c |
115 | |
2c412890 |
116 | /** |
da1320da |
117 | * To autofocus on first form element or first element with error. |
2c412890 |
118 | * |
119 | * @return string javascript to select form element with first error or |
da1320da |
120 | * first element if no errors. Use this as a parameter |
121 | * when calling print_header |
2c412890 |
122 | */ |
123 | function focus(){ |
9403060a |
124 | $form =& $this->_form; |
5c52df67 |
125 | $elkeys=array_keys($form->_elementIndex); |
9403060a |
126 | if (isset($form->_errors) && 0 != count($form->_errors)){ |
127 | $errorkeys = array_keys($form->_errors); |
128 | $elkeys = array_intersect($elkeys, $errorkeys); |
2c412890 |
129 | } |
9403060a |
130 | $names=null; |
131 | while (!$names){ |
132 | $el = array_shift($elkeys); |
133 | $names=$form->_getElNamesRecursive($el); |
134 | } |
135 | $name=array_shift($names); |
136 | $focus='forms[\''.$this->_form->getAttribute('id').'\'].elements[\''.$name.'\']'; |
137 | return $focus; |
138 | } |
7f40a229 |
139 | |
05f5c40c |
140 | /** |
141 | * Internal method. Alters submitted data to be suitable for quickforms processing. |
142 | * Must be called when the form is fully set up. |
143 | */ |
7f40a229 |
144 | function _process_submission($method) { |
145 | $submission = array(); |
146 | if ($method == 'post') { |
147 | if (!empty($_POST)) { |
148 | $submission = $_POST; |
149 | } |
150 | } else { |
151 | $submission = array_merge_recursive($_GET, $_POST); // emulate handling of parameters in xxxx_param() |
152 | } |
153 | |
154 | // following trick is needed to enable proper sesskey checks when using GET forms |
5bc97c98 |
155 | // the _qf__.$this->_formname serves as a marker that form was actually submitted |
156 | if (array_key_exists('_qf__'.$this->_formname, $submission) and $submission['_qf__'.$this->_formname] == 1) { |
7f40a229 |
157 | if (!confirm_sesskey()) { |
158 | error('Incorrect sesskey submitted, form not accepted!'); |
159 | } |
05f5c40c |
160 | $files = $_FILES; |
7f40a229 |
161 | } else { |
162 | $submission = array(); |
05f5c40c |
163 | $files = array(); |
7f40a229 |
164 | } |
165 | |
05f5c40c |
166 | $this->_form->updateSubmission($submission, $files); |
7f40a229 |
167 | } |
168 | |
05f5c40c |
169 | /** |
170 | * Internal method. Validates all uploaded files. |
171 | */ |
49292f8c |
172 | function _validate_files() { |
173 | if (empty($_FILES)) { |
174 | // we do not need to do any checks because no files were submitted |
175 | // TODO: find out why server side required rule does not work for uploaded files; |
176 | // testing is easily done by always returning true from this function and adding |
177 | // $mform->addRule('soubor', get_string('required'), 'required', null, 'server'); |
178 | // and submitting form without selected file |
179 | return true; |
180 | } |
181 | $errors = array(); |
182 | $mform =& $this->_form; |
183 | |
184 | // create default upload manager if not already created |
185 | if (empty($this->_upload_manager)) { |
186 | $this->_upload_manager = new upload_manager(); |
187 | } |
188 | |
189 | // check the files |
190 | $status = $this->_upload_manager->preprocess_files(); |
191 | |
192 | // now check that we really want each file |
193 | foreach ($_FILES as $elname=>$file) { |
194 | if ($mform->elementExists($elname) and $mform->getElementType($elname)=='file') { |
195 | $required = $mform->isElementRequired($elname); |
196 | if (!empty($this->_upload_manager->files[$elname]['uploadlog']) and empty($this->_upload_manager->files[$elname]['clear'])) { |
197 | if (!$required and $file['error'] == UPLOAD_ERR_NO_FILE) { |
198 | // file not uploaded and not required - ignore it |
199 | continue; |
200 | } |
201 | $errors[$elname] = $this->_upload_manager->files[$elname]['uploadlog']; |
202 | } |
203 | } else { |
204 | error('Incorrect upload attemp!'); |
205 | } |
206 | } |
207 | |
208 | // return errors if found |
209 | if ($status and 0 == count($errors)){ |
210 | return true; |
211 | } else { |
212 | return $errors; |
213 | } |
214 | } |
215 | |
05f5c40c |
216 | /** |
da1320da |
217 | * Load in existing data as form defaults. Usually new entry defaults are stored directly in |
218 | * form definition (new entry form); this function is used to load in data where values |
219 | * already exist and data is being edited (edit entry form). |
05f5c40c |
220 | * |
221 | * @param mixed $default_values object or array of default values |
222 | * @param bool $slased true if magic quotes applied to data values |
223 | */ |
7f40a229 |
224 | function set_defaults($default_values, $slashed=false) { |
225 | if (is_object($default_values)) { |
226 | $default_values = (array)$default_values; |
227 | } |
228 | $filter = $slashed ? 'stripslashes' : NULL; |
229 | $this->_form->setDefaults($default_values, $filter); |
38f394b2 |
230 | //update form definition when data changed |
05f5c40c |
231 | $this->definition_after_data(); |
7f40a229 |
232 | } |
233 | |
c80a13c7 |
234 | /** |
235 | * Set maximum allowed uploaded file size. |
236 | * Must be used BEFORE creating of file element! |
237 | * |
238 | * @param object $course |
ebd3c7ac |
239 | * @param object $modbytes - max size limit defined in module |
c80a13c7 |
240 | */ |
241 | function set_max_file_size($course=null, $modbytes=0) { |
242 | global $CFG, $COURSE; |
243 | |
244 | if (empty($course->id)) { |
245 | $course = $COURSE; |
246 | } |
247 | |
248 | $maxbytes = get_max_upload_file_size($CFG->maxbytes, $course->maxbytes, $modbytes); |
249 | $this->_form->setMaxFileSize($maxbytes); |
250 | } |
251 | |
05f5c40c |
252 | /** |
253 | * Check that form was submitted. Does not check validity of submitted data. |
254 | * |
255 | * @return bool true if form properly submitted |
256 | */ |
7f40a229 |
257 | function is_submitted() { |
258 | return $this->_form->isSubmitted(); |
259 | } |
260 | |
05f5c40c |
261 | /** |
262 | * Check that form data is valid. |
263 | * |
264 | * @return bool true if form data valid |
265 | */ |
7f40a229 |
266 | function is_validated() { |
49292f8c |
267 | static $validated = null; // one validation is enough |
7f40a229 |
268 | |
269 | if ($validated === null) { |
270 | $internal_val = $this->_form->validate(); |
e7dcb0fc |
271 | $moodle_val = $this->validation($this->_form->exportValues(null, true)); |
7f40a229 |
272 | if ($moodle_val !== true) { |
273 | if (!empty($moodle_val)) { |
274 | foreach ($moodle_val as $element=>$msg) { |
275 | $this->_form->setElementError($element, $msg); |
276 | } |
277 | } |
278 | $moodle_val = false; |
279 | } |
49292f8c |
280 | $file_val = $this->_validate_files(); |
281 | if ($file_val !== true) { |
282 | if (!empty($file_val)) { |
283 | foreach ($file_val as $element=>$msg) { |
284 | $this->_form->setElementError($element, $msg); |
285 | } |
286 | } |
287 | $file_val = false; |
288 | } |
289 | $validated = ($internal_val and $moodle_val and $file_val); |
7f40a229 |
290 | } |
291 | return $validated; |
292 | } |
293 | |
05f5c40c |
294 | /** |
da1320da |
295 | * Return submitted data if properly submitted or returns NULL if validation fails or |
296 | * if there is no submitted data. |
05f5c40c |
297 | * |
298 | * @param bool $slashed true means return data with addslashes applied |
299 | * @return object submitted data; NULL if not valid or not submitted |
300 | */ |
7f40a229 |
301 | function data_submitted($slashed=true) { |
ebd3c7ac |
302 | foreach ($this->_nosubmitbuttons as $nosubmitbutton){ |
303 | if (optional_param($nosubmitbutton, 0, PARAM_TEXT)){ |
304 | return NULL; |
305 | } |
306 | } |
7f40a229 |
307 | if ($this->is_submitted() and $this->is_validated()) { |
308 | $data = $this->_form->exportValues(null, $slashed); |
5bc97c98 |
309 | unset($data['sesskey']); // we do not need to return sesskey |
310 | unset($data['_qf__'.$this->_formname]); // we do not need the submission marker too |
7f40a229 |
311 | if (empty($data)) { |
312 | return NULL; |
313 | } else { |
314 | return (object)$data; |
315 | } |
316 | } else { |
317 | return NULL; |
318 | } |
319 | } |
320 | |
05f5c40c |
321 | /** |
322 | * Save verified uploaded files into directory. Upload process can be customised from definition() |
38f394b2 |
323 | * method by creating instance of upload manager and storing it in $this->_upload_form |
05f5c40c |
324 | * |
325 | * @param string $destination where to store uploaded files |
326 | * @return bool success |
327 | */ |
49292f8c |
328 | function save_files($destination) { |
329 | if (empty($this->_upload_manager)) { |
330 | return false; |
331 | } |
332 | if ($this->is_submitted() and $this->is_validated()) { |
333 | return $this->_upload_manager->save_files($destination); |
334 | } |
335 | return false; |
336 | } |
2b63df96 |
337 | |
05f5c40c |
338 | /** |
339 | * Print html form. |
340 | */ |
7f40a229 |
341 | function display() { |
342 | $this->_form->display(); |
343 | } |
344 | |
49292f8c |
345 | /** |
05f5c40c |
346 | * Abstract method - always override! |
49292f8c |
347 | * |
348 | * If you need special handling of uploaded files, create instance of $this->_upload_manager here. |
349 | */ |
7f40a229 |
350 | function definition() { |
351 | error('Abstract form_definition() method in class '.get_class($this).' must be overriden, please fix the code.'); |
352 | } |
2c412890 |
353 | |
c08ac016 |
354 | /** |
05f5c40c |
355 | * Dummy stub method - override if you need to setup the form depending on current |
356 | * values. This method is called after definition(), data submission and set_defaults(). |
357 | * All form setup that is dependent on form values should go in here. |
c08ac016 |
358 | */ |
359 | function definition_after_data(){ |
c08ac016 |
360 | } |
7f40a229 |
361 | |
05f5c40c |
362 | /** |
363 | * Dummy stub method - override if you needed to perform some extra validation. |
364 | * If there are errors return array of errors ("fieldname"=>"error message"), |
365 | * otherwise true if ok. |
38f394b2 |
366 | * |
05f5c40c |
367 | * @param array $data array of ("fieldname"=>value) of submitted data |
38f394b2 |
368 | * @return bool array of errors or true if ok |
05f5c40c |
369 | */ |
7f40a229 |
370 | function validation($data) { |
7f40a229 |
371 | return true; |
372 | } |
ebd3c7ac |
373 | |
374 | function _register_no_submit_button($addfieldsname){ |
375 | $this->_nosubmitbuttons[]=$addfieldsname; |
376 | } |
377 | |
616b549a |
378 | /** |
379 | * Method to add a repeating group of elements to a form. |
380 | * |
381 | * @param array $elementobjs Array of elements or groups of elements that are to be repeated |
382 | * @param integer $repeats no of times to repeat elements initially |
383 | * @param array $options Array of options to apply to elements. Array keys are element names. |
384 | * This is an array of arrays. The second sets of keys are the option types |
385 | * for the elements : |
386 | * 'default' - default value is value |
387 | * 'type' - PARAM_* constant is value |
388 | * 'helpbutton' - helpbutton params array is value |
389 | * 'disabledif' - last three moodleform::disabledIf() |
390 | * params are value as an array |
391 | * @param string $repeathiddenname name for hidden element storing no of repeats in this form |
392 | * @param string $addfieldsname name for button to add more fields |
393 | * @param int $addfieldsno how many fields to add at a time |
394 | * @param array $addstring array of params for get_string for name of button, $a is no of fields that |
395 | * will be added. |
396 | */ |
ebd3c7ac |
397 | function repeat_elements($elementobjs, $repeats, $options, $repeathiddenname, $addfieldsname, $addfieldsno=5, $addstring=array('addfields', 'form')){ |
398 | $repeats = optional_param($repeathiddenname, $repeats, PARAM_INT); |
399 | $addfields = optional_param($addfieldsname, '', PARAM_TEXT); |
400 | if (!empty($addfields)){ |
401 | $repeats += $addfieldsno; |
402 | } |
403 | $this->_register_no_submit_button($addfieldsname); |
404 | $mform =& $this->_form; |
405 | $mform->addElement('hidden', $repeathiddenname, $repeats); |
406 | //value not to be overridden by submitted value |
407 | $mform->setConstants(array($repeathiddenname=>$repeats)); |
408 | for ($i=0; $i<$repeats; $i++) { |
409 | foreach ($elementobjs as $elementobj){ |
410 | $elementclone=clone($elementobj); |
411 | $name=$elementclone->getName(); |
412 | $elementclone->setName($name."[$i]"); |
413 | if (is_a($elementclone, 'HTML_QuickForm_header')){ |
414 | $value=$elementclone->_text; |
415 | $elementclone->setValue($value.' '.($i+1)); |
416 | |
417 | } |
418 | $mform->addElement($elementclone); |
419 | } |
420 | } |
421 | for ($i=0; $i<$repeats; $i++) { |
422 | foreach ($options as $elementname => $elementoptions){ |
423 | $pos=strpos($elementname, '['); |
424 | if ($pos!==FALSE){ |
425 | $realelementname = substr($elementname, 0, $pos+1)."[$i]"; |
426 | $realelementname .= substr($elementname, $pos+1); |
427 | }else { |
428 | $realelementname = $elementname."[$i]"; |
429 | } |
430 | foreach ($elementoptions as $option => $params){ |
431 | |
432 | switch ($option){ |
433 | case 'default' : |
434 | $mform->setDefault($realelementname, $params); |
435 | break; |
436 | case 'type' : |
437 | $mform->setType($realelementname, $params); |
438 | break; |
439 | case 'helpbutton' : |
440 | $mform->setHelpButton($realelementname, $params); |
441 | break; |
442 | case 'disabledif' : |
443 | $mform->disabledIf($realelementname, $params[0], $params[1], $params[2]); |
444 | break; |
445 | |
446 | } |
447 | } |
448 | } |
449 | } |
450 | $mform->addElement('submit', $addfieldsname, get_string('addfields', 'form', $addfieldsno), |
451 | array('onclick'=>'this.form.submit();'));//need this to bypass client validation |
452 | |
453 | $renderer =& $mform->defaultRenderer(); |
454 | $renderer->addStopFieldsetElements($addfieldsname); |
455 | |
456 | } |
7f40a229 |
457 | } |
458 | |
da1320da |
459 | /** |
460 | * You never extend this class directly. The class methods of this class are available from |
461 | * the private $this->_form property on moodleform and it's children. You generally only |
462 | * call methods on this class from within abstract methods that you override on moodleform such |
463 | * as definition and definition_after_data |
464 | * |
465 | */ |
7f40a229 |
466 | class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless { |
467 | var $_types = array(); |
50ef8eb9 |
468 | var $_dependencies = array(); |
7f40a229 |
469 | |
470 | |
da6f8763 |
471 | /** |
472 | * Class constructor - same parameters as HTML_QuickForm_DHTMLRulesTableless |
473 | * @param string $formName Form's name. |
474 | * @param string $method (optional)Form's method defaults to 'POST' |
475 | * @param string $action (optional)Form's action |
476 | * @param string $target (optional)Form's target defaults to none |
477 | * @param mixed $attributes (optional)Extra attributes for <form> tag |
478 | * @param bool $trackSubmit (optional)Whether to track if the form was submitted by adding a special hidden field |
479 | * @access public |
480 | */ |
7f40a229 |
481 | function MoodleQuickForm($formName, $method, $action, $target='', $attributes=null){ |
da6f8763 |
482 | global $CFG; |
7f40a229 |
483 | |
da6f8763 |
484 | HTML_Common::HTML_Common($attributes); |
da6f8763 |
485 | $target = empty($target) ? array() : array('target' => $target); |
486 | //no 'name' atttribute for form in xhtml strict : |
487 | $attributes = array('action'=>$action, 'method'=>$method, 'id'=>$formName) + $target; |
488 | $this->updateAttributes($attributes); |
da6f8763 |
489 | |
7f40a229 |
490 | //this is custom stuff for Moodle : |
da6f8763 |
491 | $oldclass= $this->getAttribute('class'); |
492 | if (!empty($oldclass)){ |
493 | $this->updateAttributes(array('class'=>$oldclass.' mform')); |
494 | }else { |
80f962df |
495 | $this->updateAttributes(array('class'=>'mform')); |
da6f8763 |
496 | } |
7f40a229 |
497 | $this->_helpImageURL="$CFG->wwwroot/lib/form/req.gif"; |
3d685169 |
498 | $this->_reqHTML = '<img alt="'.get_string('requiredelement', 'form').'" src="'.$this->_helpImageURL.'" />'; |
499 | $this->setRequiredNote(get_string('denotesreq', 'form', |
da6f8763 |
500 | helpbutton('requiredelement', get_string('requiredelement', 'form'),'moodle', |
3d685169 |
501 | true, false, '', true, '<img alt="'.get_string('requiredelement', 'form').'" src="'. |
502 | $this->_helpImageURL.'" />'))); |
da6f8763 |
503 | } |
bb40325e |
504 | |
da1320da |
505 | /** |
506 | * Should be used for all elements of a form except for select, radio and checkboxes which |
507 | * clean their own data. |
508 | * |
509 | * @param string $elementname |
510 | * @param integer $paramtype use the constants PARAM_*. |
511 | * * PARAM_CLEAN is deprecated and you should try to use a more specific type. |
512 | * * PARAM_TEXT should be used for cleaning data that is expected to be plain text. |
513 | * It will strip all html tags. But will still let tags for multilang support |
514 | * through. |
515 | * * PARAM_RAW means no cleaning whatsoever, it is used mostly for data from the |
516 | * html editor. Data from the editor is later cleaned before display using |
517 | * format_text() function. PARAM_RAW can also be used for data that is validated |
518 | * by some other way or printed by p() or s(). |
519 | * * PARAM_INT should be used for integers. |
520 | * * PARAM_ACTION is an alias of PARAM_ALPHA and is used for hidden fields specifying |
521 | * form actions. |
522 | */ |
7f40a229 |
523 | function setType($elementname, $paramtype) { |
524 | $this->_types[$elementname] = $paramtype; |
525 | } |
49292f8c |
526 | |
da1320da |
527 | /** |
528 | * See description of setType above. This can be used to set several types at once. |
529 | * |
530 | * @param array $paramtypes |
531 | */ |
c56f1826 |
532 | function setTypes($paramtypes) { |
533 | $this->_types = $paramtypes + $this->_types; |
534 | } |
49292f8c |
535 | |
536 | function updateSubmission($submission, $files) { |
537 | $this->_flagSubmitted = false; |
538 | |
7f40a229 |
539 | if (empty($submission)) { |
540 | $this->_submitValues = array(); |
7f40a229 |
541 | } else { |
542 | foreach ($submission as $key=>$s) { |
543 | if (array_key_exists($key, $this->_types)) { |
544 | $submission[$key] = clean_param($s, $this->_types[$key]); |
545 | } |
546 | } |
547 | $this->_submitValues = $this->_recursiveFilter('stripslashes', $submission); |
548 | $this->_flagSubmitted = true; |
549 | } |
550 | |
49292f8c |
551 | if (empty($files)) { |
552 | $this->_submitFiles = array(); |
553 | } else { |
554 | if (1 == get_magic_quotes_gpc()) { |
555 | foreach ($files as $elname=>$file) { |
556 | // dangerous characters in filenames are cleaned later in upload_manager |
557 | $files[$elname]['name'] = stripslashes($files[$elname]['name']); |
558 | } |
559 | } |
560 | $this->_submitFiles = $files; |
561 | $this->_flagSubmitted = true; |
562 | } |
563 | |
2c412890 |
564 | // need to tell all elements that they need to update their value attribute. |
565 | foreach (array_keys($this->_elements) as $key) { |
566 | $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this); |
567 | } |
7f40a229 |
568 | } |
569 | |
da6f8763 |
570 | function getReqHTML(){ |
571 | return $this->_reqHTML; |
572 | } |
7f40a229 |
573 | |
574 | /** |
da1320da |
575 | * Initializes a default form value. Used to specify the default for a new entry where |
576 | * no data is loaded in using moodleform::set_defaults() |
7f40a229 |
577 | * |
578 | * @param string $elementname element name |
579 | * @param mixed $values values for that element name |
580 | * @param bool $slashed the default value is slashed |
581 | * @access public |
582 | * @return void |
583 | */ |
584 | function setDefault($elementName, $defaultValue, $slashed=false){ |
585 | $filter = $slashed ? 'stripslashes' : NULL; |
586 | $this->setDefaults(array($elementName=>$defaultValue), $filter); |
587 | } // end func setDefault |
da6f8763 |
588 | /** |
c56f1826 |
589 | * Add an array of buttons to the form |
7f40a229 |
590 | * @param array $buttons An associative array representing help button to attach to |
da6f8763 |
591 | * to the form. keys of array correspond to names of elements in form. |
7f40a229 |
592 | * |
da6f8763 |
593 | * @access public |
594 | */ |
d4fe14d3 |
595 | function setHelpButtons($buttons, $suppresscheck=false, $function='helpbutton'){ |
7f40a229 |
596 | |
c56f1826 |
597 | foreach ($buttons as $elementname => $button){ |
d4fe14d3 |
598 | $this->setHelpButton($elementname, $button, $suppresscheck, $function); |
da6f8763 |
599 | } |
600 | } |
c56f1826 |
601 | /** |
da1320da |
602 | * Add a single button. |
c56f1826 |
603 | * |
604 | * @param string $elementname name of the element to add the item to |
d4fe14d3 |
605 | * @param array $button - arguments to pass to function $function |
c56f1826 |
606 | * @param boolean $suppresscheck - whether to throw an error if the element |
607 | * doesn't exist. |
d4fe14d3 |
608 | * @param string $function - function to generate html from the arguments in $button |
c56f1826 |
609 | */ |
d4fe14d3 |
610 | function setHelpButton($elementname, $button, $suppresscheck=false, $function='helpbutton'){ |
c56f1826 |
611 | if (array_key_exists($elementname, $this->_elementIndex)){ |
612 | //_elements has a numeric index, this code accesses the elements by name |
613 | $element=&$this->_elements[$this->_elementIndex[$elementname]]; |
614 | if (method_exists($element, 'setHelpButton')){ |
d4fe14d3 |
615 | $element->setHelpButton($button, $function); |
c56f1826 |
616 | }else{ |
617 | $a=new object(); |
618 | $a->name=$element->getName(); |
619 | $a->classname=get_class($element); |
620 | print_error('nomethodforaddinghelpbutton', 'form', '', $a); |
621 | } |
622 | }elseif (!$suppresscheck){ |
623 | print_error('nonexistentformelements', 'form', '', $elementname); |
2c412890 |
624 | } |
c56f1826 |
625 | } |
7f40a229 |
626 | |
42f248e6 |
627 | function exportValues($elementList= null, $addslashes=true){ |
da6f8763 |
628 | $unfiltered=parent::exportValues($elementList); |
7f40a229 |
629 | |
da6f8763 |
630 | if ($addslashes){ |
42f248e6 |
631 | return $this->_recursiveFilter('addslashes',$unfiltered); |
da6f8763 |
632 | } else { |
633 | return $unfiltered; |
634 | } |
635 | } |
5bc97c98 |
636 | /** |
637 | * Returns the client side validation script |
638 | * |
639 | * The code here was copied from HTML_QuickForm_DHTMLRulesTableless who copied it from HTML_QuickForm |
640 | * and slightly modified to run rules per-element |
641 | * Needed to override this because of an error with client side validation of grouped elements. |
642 | * |
643 | * @access public |
644 | * @return string Javascript to perform validation, empty string if no 'client' rules were added |
645 | */ |
646 | function getValidationScript() |
647 | { |
648 | if (empty($this->_rules) || empty($this->_attributes['onsubmit'])) { |
649 | return ''; |
650 | } |
651 | |
652 | include_once('HTML/QuickForm/RuleRegistry.php'); |
653 | $registry =& HTML_QuickForm_RuleRegistry::singleton(); |
654 | $test = array(); |
655 | $js_escape = array( |
656 | "\r" => '\r', |
657 | "\n" => '\n', |
658 | "\t" => '\t', |
659 | "'" => "\\'", |
660 | '"' => '\"', |
661 | '\\' => '\\\\' |
662 | ); |
663 | |
664 | foreach ($this->_rules as $elementName => $rules) { |
665 | foreach ($rules as $rule) { |
666 | if ('client' == $rule['validation']) { |
da1320da |
667 | unset($element); //TODO: find out how to properly initialize it |
5bc97c98 |
668 | |
669 | $dependent = isset($rule['dependent']) && is_array($rule['dependent']); |
670 | $rule['message'] = strtr($rule['message'], $js_escape); |
671 | |
672 | if (isset($rule['group'])) { |
673 | $group =& $this->getElement($rule['group']); |
674 | // No JavaScript validation for frozen elements |
675 | if ($group->isFrozen()) { |
676 | continue 2; |
677 | } |
678 | $elements =& $group->getElements(); |
679 | foreach (array_keys($elements) as $key) { |
680 | if ($elementName == $group->getElementName($key)) { |
681 | $element =& $elements[$key]; |
682 | break; |
683 | } |
684 | } |
685 | } elseif ($dependent) { |
686 | $element = array(); |
687 | $element[] =& $this->getElement($elementName); |
688 | foreach ($rule['dependent'] as $idx => $elName) { |
689 | $element[] =& $this->getElement($elName); |
690 | } |
691 | } else { |
692 | $element =& $this->getElement($elementName); |
693 | } |
694 | // No JavaScript validation for frozen elements |
695 | if (is_object($element) && $element->isFrozen()) { |
696 | continue 2; |
697 | } elseif (is_array($element)) { |
698 | foreach (array_keys($element) as $key) { |
699 | if ($element[$key]->isFrozen()) { |
700 | continue 3; |
701 | } |
702 | } |
703 | } |
704 | // Fix for bug displaying errors for elements in a group |
705 | //$test[$elementName][] = $registry->getValidationScript($element, $elementName, $rule); |
706 | $test[$elementName][0][] = $registry->getValidationScript($element, $elementName, $rule); |
707 | $test[$elementName][1]=$element; |
708 | //end of fix |
709 | } |
710 | } |
711 | } |
712 | $js = ' |
713 | <script type="text/javascript"> |
714 | //<![CDATA[ |
715 | function qf_errorHandler(element, _qfMsg) { |
716 | div = element.parentNode; |
717 | if (_qfMsg != \'\') { |
718 | span = document.createElement("span"); |
719 | span.className = "error"; |
720 | span.appendChild(document.createTextNode(_qfMsg.substring(3))); |
721 | br = document.createElement("br"); |
722 | |
723 | var errorDiv = document.getElementById(element.name + \'_errorDiv\'); |
724 | if (!errorDiv) { |
725 | errorDiv = document.createElement("div"); |
726 | errorDiv.id = element.name + \'_errorDiv\'; |
727 | } |
728 | while (errorDiv.firstChild) { |
729 | errorDiv.removeChild(errorDiv.firstChild); |
730 | } |
2c412890 |
731 | |
5bc97c98 |
732 | errorDiv.insertBefore(br, errorDiv.firstChild); |
733 | errorDiv.insertBefore(span, errorDiv.firstChild); |
734 | element.parentNode.insertBefore(errorDiv, element.parentNode.firstChild); |
735 | |
736 | if (div.className.substr(div.className.length - 6, 6) != " error" |
737 | && div.className != "error") { |
738 | div.className += " error"; |
739 | } |
740 | |
741 | return false; |
742 | } else { |
743 | var errorDiv = document.getElementById(element.name + \'_errorDiv\'); |
744 | if (errorDiv) { |
745 | errorDiv.parentNode.removeChild(errorDiv); |
746 | } |
747 | |
748 | if (div.className.substr(div.className.length - 6, 6) == " error") { |
749 | div.className = div.className.substr(0, div.className.length - 6); |
750 | } else if (div.className == "error") { |
751 | div.className = ""; |
752 | } |
753 | |
754 | return true; |
755 | } |
756 | }'; |
757 | $validateJS = ''; |
758 | foreach ($test as $elementName => $jsandelement) { |
759 | // Fix for bug displaying errors for elements in a group |
760 | //unset($element); |
761 | list($jsArr,$element)=$jsandelement; |
762 | //end of fix |
763 | $js .= ' |
764 | function validate_' . $this->_attributes['id'] . '_' . $elementName . '(element) { |
765 | var value = \'\'; |
766 | var errFlag = new Array(); |
767 | var _qfGroups = {}; |
768 | var _qfMsg = \'\'; |
769 | var frm = element.parentNode; |
770 | while (frm && frm.nodeName != "FORM") { |
771 | frm = frm.parentNode; |
772 | } |
773 | ' . join("\n", $jsArr) . ' |
774 | return qf_errorHandler(element, _qfMsg); |
775 | } |
776 | '; |
777 | $validateJS .= ' |
778 | ret = validate_' . $this->_attributes['id'] . '_' . $elementName.'(frm.elements[\''.$elementName.'\']) && ret;'; |
779 | // Fix for bug displaying errors for elements in a group |
780 | //unset($element); |
781 | //$element =& $this->getElement($elementName); |
782 | //end of fix |
783 | $valFunc = 'validate_' . $this->_attributes['id'] . '_' . $elementName . '(this)'; |
784 | $onBlur = $element->getAttribute('onBlur'); |
785 | $onChange = $element->getAttribute('onChange'); |
786 | $element->updateAttributes(array('onBlur' => $onBlur . $valFunc, |
787 | 'onChange' => $onChange . $valFunc)); |
788 | } |
789 | $js .= ' |
790 | function validate_' . $this->_attributes['id'] . '(frm) { |
791 | var ret = true; |
792 | ' . $validateJS . '; |
793 | return ret; |
794 | } |
795 | //]]> |
796 | </script>'; |
797 | return $js; |
798 | } // end func getValidationScript |
799 | function _setDefaultRuleMessages(){ |
800 | foreach ($this->_rules as $field => $rulesarr){ |
801 | foreach ($rulesarr as $key => $rule){ |
802 | if ($rule['message']===null){ |
803 | $a=new object(); |
804 | $a->format=$rule['format']; |
805 | $str=get_string('err_'.$rule['type'], 'form', $a); |
806 | if (strpos($str, '[[')!==0){ |
807 | $this->_rules[$field][$key]['message']=$str; |
2c412890 |
808 | } |
5bc97c98 |
809 | } |
810 | } |
811 | } |
812 | } |
bb40325e |
813 | |
d01a38cb |
814 | function getLockOptionEndScript(){ |
50ef8eb9 |
815 | $js = '<script type="text/javascript" language="javascript">'."\n"; |
816 | $js .= "var ".$this->getAttribute('id')."items= {"; |
817 | foreach ($this->_dependencies as $dependentOn => $elements){ |
818 | $js .= $dependentOn.' : {dependents :['; |
819 | foreach ($elements as $element){ |
820 | $js.="'".$element['dependent']."', "; |
821 | } |
822 | $js=rtrim($js, ', '); |
823 | $js .= "],\n"; |
e24b7f85 |
824 | $js .= "condition : '{$element['condition']}',\n"; |
825 | $js .= "value : '{$element['value']}'},\n"; |
50ef8eb9 |
826 | |
827 | }; |
828 | $js=rtrim($js, ",\n"); |
829 | $js .= '};'."\n"; |
d01a38cb |
830 | $js .="lockoptionsallsetup('".$this->getAttribute('id')."');\n"; |
50ef8eb9 |
831 | $js .='</script>'."\n"; |
832 | return $js; |
bb40325e |
833 | } |
d01a38cb |
834 | |
835 | function _getElNamesRecursive(&$element, $group=null){ |
836 | if ($group==null){ |
9403060a |
837 | $el = $this->getElement($element); |
d01a38cb |
838 | } else { |
9403060a |
839 | $el = &$element; |
d01a38cb |
840 | } |
841 | if (is_a($el, 'HTML_QuickForm_group')){ |
9403060a |
842 | $group = $el; |
843 | $elsInGroup = $group->getElements(); |
844 | $elNames = array(); |
d01a38cb |
845 | foreach ($elsInGroup as $elInGroup){ |
846 | $elNames = array_merge($elNames, $this->_getElNamesRecursive($elInGroup, $group)); |
847 | } |
848 | }else{ |
9403060a |
849 | if ($group != null){ |
850 | $elNames = array($group->getElementName($el->getName())); |
851 | } elseif (is_a($el, 'HTML_QuickForm_header')) { |
852 | return null; |
2dbd6409 |
853 | } elseif (method_exists($el, 'getPrivateName')) { |
854 | return array($el->getPrivateName()); |
d01a38cb |
855 | } else { |
9403060a |
856 | $elNames = array($el->getName()); |
d01a38cb |
857 | } |
858 | } |
859 | return $elNames; |
860 | |
50ef8eb9 |
861 | } |
6e372b25 |
862 | /** |
863 | * Adds a dependency for $elementName which will be disabled if $condition is met. |
9403060a |
864 | * If $condition = 'notchecked' (default) then the condition is that the $dependentOn element |
865 | * is not checked. If $condition = 'checked' then the condition is that the $dependentOn element |
6e372b25 |
866 | * is checked. If $condition is something else then it is checked to see if the value |
867 | * of the $dependentOn element is equal to $condition. |
868 | * |
869 | * @param string $elementName the name of the element which will be disabled |
870 | * @param string $dependentOn the name of the element whose state will be checked for |
871 | * condition |
872 | * @param string $condition the condition to check |
873 | */ |
e24b7f85 |
874 | function disabledIf($elementName, $dependentOn, $condition = 'notchecked', $value=null){ |
9403060a |
875 | $dependents = $this->_getElNamesRecursive($elementName); |
d01a38cb |
876 | foreach ($dependents as $dependent){ |
9403060a |
877 | if ($dependent != $dependentOn) { |
878 | $this->_dependencies[$dependentOn][] = array('dependent'=>$dependent, |
e24b7f85 |
879 | 'condition'=>$condition, 'value'=>$value); |
abf11956 |
880 | } |
50ef8eb9 |
881 | } |
bb40325e |
882 | } |
da6f8763 |
883 | } |
884 | |
e24b7f85 |
885 | |
da6f8763 |
886 | /** |
7f40a229 |
887 | * A renderer for MoodleQuickForm that only uses XHTML and CSS and no |
da6f8763 |
888 | * table tags, extends PEAR class HTML_QuickForm_Renderer_Tableless |
7f40a229 |
889 | * |
da6f8763 |
890 | * Stylesheet is part of standard theme and should be automatically included. |
891 | * |
892 | * @author Jamie Pratt <me@jamiep.org> |
893 | * @license gpl license |
894 | */ |
7f40a229 |
895 | class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{ |
da6f8763 |
896 | |
897 | /** |
898 | * Element template array |
899 | * @var array |
900 | * @access private |
901 | */ |
902 | var $_elementTemplates; |
42f248e6 |
903 | |
49c53687 |
904 | // uncomment templates below and edit formslib.php for |
42f248e6 |
905 | // ol li containers for form items. |
906 | |
49c53687 |
907 | /** |
908 | * Template used when opening a hidden fieldset |
909 | * (i.e. a fieldset that is opened when there is no header element) |
910 | * @var string |
911 | * @access private |
912 | */ |
913 | var $_openHiddenFieldsetTemplate = "\n\t<fieldset class=\"hidden\">"; |
42f248e6 |
914 | // var $_openHiddenFieldsetTemplate = "\n\t<fieldset class=\"hidden\">\n\t\t<ol>"; |
915 | // /** |
916 | // * Header Template string |
917 | // * @var string |
918 | // * @access private |
919 | // */ |
7f40a229 |
920 | // var $_headerTemplate = |
42f248e6 |
921 | // "\n\t\t<legend>{header}</legend>\n\t\t<ol>"; |
7f40a229 |
922 | // var $_headerTemplate = |
49c53687 |
923 | // "\n\t\t<legend>{header}</legend>\n\t\t<ol>"; |
7f40a229 |
924 | |
49c53687 |
925 | /** |
926 | * Template used when closing a fieldset |
927 | * @var string |
928 | * @access private |
929 | */ |
930 | var $_closeFieldsetTemplate = "\n\t\t</fieldset>"; |
42f248e6 |
931 | // var $_closeFieldsetTemplate = "\n\t\t</ol>\n\t</fieldset>"; |
932 | |
49c53687 |
933 | /** |
934 | * Required Note template string |
935 | * @var string |
936 | * @access private |
937 | */ |
7f40a229 |
938 | var $_requiredNoteTemplate = |
49c53687 |
939 | "\n\t\t<div class=\"fdescription\">{requiredNote}</div>"; |
7f40a229 |
940 | |
941 | function MoodleQuickForm_Renderer(){ |
42f248e6 |
942 | // switch next two lines for ol li containers for form items. |
49c53687 |
943 | // $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>"); |
30e113f4 |
944 | $this->_elementTemplates = array('default'=>"\n\t\t<div class=\"fitem\"><span class=\"fitemtitle\"><label>{label}<!-- BEGIN required -->{req}<!-- END required --></label>{help}</span><div class=\"felement<!-- BEGIN error --> error<!-- END error --> {type}\"><!-- BEGIN error --><span class=\"error\">{error}</span><br /><!-- END error -->{element}</div></div>", |
945 | 'fieldset'=>"\n\t\t<div class=\"fitem\"><span class=\"fitemtitle\"><label>{label}<!-- BEGIN required -->{req}<!-- END required --></label>{help}</span><fieldset class=\"felement<!-- BEGIN error --> error<!-- END error --> {type}\"><!-- BEGIN error --><span class=\"error\">{error}</span><br /><!-- END error -->{element}</fieldset></div>"); |
da6f8763 |
946 | |
947 | parent::HTML_QuickForm_Renderer_Tableless(); |
948 | } |
7f40a229 |
949 | |
da6f8763 |
950 | function startForm(&$form){ |
9403060a |
951 | $this->_reqHTML = $form->getReqHTML(); |
952 | $this->_elementTemplates = str_replace('{req}', $this->_reqHTML, $this->_elementTemplates); |
da6f8763 |
953 | parent::startForm($form); |
954 | } |
7f40a229 |
955 | |
da6f8763 |
956 | function startGroup(&$group, $required, $error){ |
957 | if (method_exists($group, 'getElementTemplateType')){ |
e249661f |
958 | $html = $this->_elementTemplates[$group->getElementTemplateType()]; |
da6f8763 |
959 | }else{ |
960 | $html = $this->_elementTemplates['default']; |
7f40a229 |
961 | |
da6f8763 |
962 | } |
963 | if (method_exists($group, 'getHelpButton')){ |
964 | $html =str_replace('{help}', $group->getHelpButton(), $html); |
965 | }else{ |
966 | $html =str_replace('{help}', '', $html); |
7f40a229 |
967 | |
da6f8763 |
968 | } |
49c53687 |
969 | $html =str_replace('{type}', 'fgroup', $html); |
7f40a229 |
970 | |
da6f8763 |
971 | $this->_templates[$group->getName()]=$html; |
972 | // Fix for bug in tableless quickforms that didn't allow you to stop a |
973 | // fieldset before a group of elements. |
974 | // if the element name indicates the end of a fieldset, close the fieldset |
975 | if ( in_array($group->getName(), $this->_stopFieldsetElements) |
976 | && $this->_fieldsetsOpen > 0 |
977 | ) { |
978 | $this->_html .= $this->_closeFieldsetTemplate; |
979 | $this->_fieldsetsOpen--; |
980 | } |
981 | parent::startGroup($group, $required, $error); |
982 | } |
7f40a229 |
983 | |
da6f8763 |
984 | function renderElement(&$element, $required, $error){ |
985 | if (method_exists($element, 'getElementTemplateType')){ |
986 | $html = $this->_elementTemplates[$element->getElementTemplateType()]; |
987 | }else{ |
988 | $html = $this->_elementTemplates['default']; |
7f40a229 |
989 | |
da6f8763 |
990 | } |
49c53687 |
991 | $html =str_replace('{type}', 'f'.$element->getType(), $html); |
da6f8763 |
992 | if (method_exists($element, 'getHelpButton')){ |
9403060a |
993 | $html = str_replace('{help}', $element->getHelpButton(), $html); |
da6f8763 |
994 | }else{ |
9403060a |
995 | $html = str_replace('{help}', '', $html); |
7f40a229 |
996 | |
da6f8763 |
997 | } |
9403060a |
998 | $this->_templates[$element->getName()] = $html; |
230a910a |
999 | if (!is_null($element->getAttribute('id'))) { |
1000 | $id = $element->getAttribute('id'); |
1001 | } else { |
1002 | $id = $element->getName(); |
1003 | } |
1004 | $element->updateAttributes(array('id'=>'id_'.$id)); |
da6f8763 |
1005 | parent::renderElement($element, $required, $error); |
1006 | } |
bb40325e |
1007 | function finishForm(&$form){ |
1008 | parent::finishForm($form); |
d01a38cb |
1009 | // add a lockoptions script |
bb40325e |
1010 | if ('' != ($script = $form->getLockOptionEndScript())) { |
1011 | $this->_html = $this->_html . "\n" . $script; |
1012 | } |
1013 | } |
da6f8763 |
1014 | } |
1015 | |
da6f8763 |
1016 | |
9403060a |
1017 | $GLOBALS['_HTML_QuickForm_default_renderer'] =& new MoodleQuickForm_Renderer(); |
da6f8763 |
1018 | |
7f40a229 |
1019 | MoodleQuickForm::registerElementType('checkbox', "$CFG->libdir/form/checkbox.php", 'MoodleQuickForm_checkbox'); |
1020 | MoodleQuickForm::registerElementType('file', "$CFG->libdir/form/file.php", 'MoodleQuickForm_file'); |
1021 | MoodleQuickForm::registerElementType('group', "$CFG->libdir/form/group.php", 'MoodleQuickForm_group'); |
1022 | MoodleQuickForm::registerElementType('password', "$CFG->libdir/form/password.php", 'MoodleQuickForm_password'); |
1023 | MoodleQuickForm::registerElementType('radio', "$CFG->libdir/form/radio.php", 'MoodleQuickForm_radio'); |
1024 | MoodleQuickForm::registerElementType('select', "$CFG->libdir/form/select.php", 'MoodleQuickForm_select'); |
1025 | MoodleQuickForm::registerElementType('text', "$CFG->libdir/form/text.php", 'MoodleQuickForm_text'); |
1026 | MoodleQuickForm::registerElementType('textarea', "$CFG->libdir/form/textarea.php", 'MoodleQuickForm_textarea'); |
1027 | MoodleQuickForm::registerElementType('date_selector', "$CFG->libdir/form/dateselector.php", 'MoodleQuickForm_date_selector'); |
1028 | MoodleQuickForm::registerElementType('date_time_selector', "$CFG->libdir/form/datetimeselector.php", 'MoodleQuickForm_date_time_selector'); |
1029 | MoodleQuickForm::registerElementType('htmleditor', "$CFG->libdir/form/htmleditor.php", 'MoodleQuickForm_htmleditor'); |
effa85f4 |
1030 | MoodleQuickForm::registerElementType('format', "$CFG->libdir/form/format.php", 'MoodleQuickForm_format'); |
7f40a229 |
1031 | MoodleQuickForm::registerElementType('static', "$CFG->libdir/form/static.php", 'MoodleQuickForm_static'); |
1032 | MoodleQuickForm::registerElementType('hidden', "$CFG->libdir/form/hidden.php", 'MoodleQuickForm_hidden'); |
e2294b98 |
1033 | MoodleQuickForm::registerElementType('modvisible', "$CFG->libdir/form/modvisible.php", 'MoodleQuickForm_modvisible'); |
1034 | MoodleQuickForm::registerElementType('modgroupmode', "$CFG->libdir/form/modgroupmode.php", 'MoodleQuickForm_modgroupmode'); |
e0f40684 |
1035 | MoodleQuickForm::registerElementType('selectyesno', "$CFG->libdir/form/selectyesno.php", 'MoodleQuickForm_selectyesno'); |
d4fe14d3 |
1036 | MoodleQuickForm::registerElementType('modgrade', "$CFG->libdir/form/modgrade.php", 'MoodleQuickForm_modgrade'); |
4ea75041 |
1037 | MoodleQuickForm::registerElementType('submit', "$CFG->libdir/form/submit.php", 'MoodleQuickForm_submit'); |
3c7656b4 |
1038 | MoodleQuickForm::registerElementType('button', "$CFG->libdir/form/button.php", 'MoodleQuickForm_button'); |
1039 | MoodleQuickForm::registerElementType('choosecoursefile', "$CFG->libdir/form/choosecoursefile.php", 'MoodleQuickForm_choosecoursefile'); |
864cc1de |
1040 | |
da6f8763 |
1041 | ?> |