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