Commit | Line | Data |
---|---|---|
ba21c9d4 | 1 | <?php |
117bd748 PS |
2 | // This file is part of Moodle - http://moodle.org/ |
3 | // | |
ba21c9d4 | 4 | // Moodle is free software: you can redistribute it and/or modify |
5 | // it under the terms of the GNU General Public License as published by | |
6 | // the Free Software Foundation, either version 3 of the License, or | |
7 | // (at your option) any later version. | |
8 | // | |
9 | // Moodle is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
117bd748 | 13 | // |
ba21c9d4 | 14 | // You should have received a copy of the GNU General Public License |
15 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
da6f8763 | 17 | /** |
18 | * formslib.php - library of classes for creating forms in Moodle, based on PEAR QuickForms. | |
da1320da | 19 | * |
20 | * To use formslib then you will want to create a new file purpose_form.php eg. edit_form.php | |
21 | * and you want to name your class something like {modulename}_{purpose}_form. Your class will | |
22 | * extend moodleform overriding abstract classes definition and optionally defintion_after_data | |
23 | * and validation. | |
24 | * | |
25 | * See examples of use of this library in course/edit.php and course/edit_form.php | |
26 | * | |
27 | * A few notes : | |
78bfb562 | 28 | * form definition is used for both printing of form and processing and should be the same |
da1320da | 29 | * for both or you may lose some submitted data which won't be let through. |
30 | * you should be using setType for every form element except select, radio or checkbox | |
31 | * elements, these elements clean themselves. | |
32 | * | |
33 | * | |
78bfb562 PS |
34 | * @copyright Jamie Pratt <me@jamiep.org> |
35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
36 | * @package core | |
37 | * @subpackage form | |
da6f8763 | 38 | */ |
39 | ||
78bfb562 PS |
40 | defined('MOODLE_INTERNAL') || die(); |
41 | ||
42 | /** setup.php includes our hacked pear libs first */ | |
da6f8763 | 43 | require_once 'HTML/QuickForm.php'; |
44 | require_once 'HTML/QuickForm/DHTMLRulesTableless.php'; | |
45 | require_once 'HTML/QuickForm/Renderer/Tableless.php'; | |
7b5702b6 | 46 | require_once 'HTML/QuickForm/Rule.php'; |
da6f8763 | 47 | |
a83ad946 | 48 | require_once $CFG->libdir.'/filelib.php'; |
49292f8c | 49 | |
832e13f1 | 50 | define('EDITOR_UNLIMITED_FILES', -1); |
51 | ||
a23f0aaf | 52 | /** |
53 | * Callback called when PEAR throws an error | |
54 | * | |
55 | * @param PEAR_Error $error | |
56 | */ | |
57 | function pear_handle_error($error){ | |
58 | echo '<strong>'.$error->GetMessage().'</strong> '.$error->getUserInfo(); | |
59 | echo '<br /> <strong>Backtrace </strong>:'; | |
60 | print_object($error->backtrace); | |
61 | } | |
62 | ||
66491cf1 | 63 | if (!empty($CFG->debug) and $CFG->debug >= DEBUG_ALL){ |
a23f0aaf | 64 | PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'pear_handle_error'); |
864cc1de | 65 | } |
66 | ||
ba21c9d4 | 67 | /** |
117bd748 | 68 | * |
ba21c9d4 | 69 | * @staticvar bool $done |
e5473854 | 70 | * @global moodle_page $PAGE |
ba21c9d4 | 71 | */ |
8e7cebb0 | 72 | function form_init_date_js() { |
cf615522 | 73 | global $PAGE; |
8e7cebb0 | 74 | static $done = false; |
75 | if (!$done) { | |
e5473854 SH |
76 | $module = 'moodle-form-dateselector'; |
77 | $function = 'M.form.dateselector.init_date_selectors'; | |
78 | $config = array(array('firstdayofweek'=>get_string('firstdayofweek', 'langconfig'))); | |
79 | $PAGE->requires->yui_module($module, $function, $config); | |
8e7cebb0 | 80 | $done = true; |
81 | } | |
82 | } | |
f07b9627 | 83 | |
05f5c40c | 84 | /** |
da1320da | 85 | * Moodle specific wrapper that separates quickforms syntax from moodle code. You won't directly |
6073a598 | 86 | * use this class you should write a class definition which extends this class or a more specific |
da1320da | 87 | * subclass such a moodleform_mod for each form you want to display and/or process with formslib. |
88 | * | |
89 | * You will write your own definition() method which performs the form set up. | |
ba21c9d4 | 90 | * |
91 | * @package moodlecore | |
92 | * @copyright Jamie Pratt <me@jamiep.org> | |
93 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
05f5c40c | 94 | */ |
afd63fe5 | 95 | abstract class moodleform { |
ba21c9d4 | 96 | /** @var string */ |
172dd12c | 97 | protected $_formname; // form name |
3c7656b4 | 98 | /** |
99 | * quickform object definition | |
100 | * | |
572dd8ec | 101 | * @var MoodleQuickForm MoodleQuickForm |
3c7656b4 | 102 | */ |
172dd12c | 103 | protected $_form; |
3c7656b4 | 104 | /** |
105 | * globals workaround | |
106 | * | |
107 | * @var array | |
108 | */ | |
172dd12c | 109 | protected $_customdata; |
4f51f48f | 110 | /** |
111 | * definition_after_data executed flag | |
ba21c9d4 | 112 | * @var object definition_finalized |
4f51f48f | 113 | */ |
172dd12c | 114 | protected $_definition_finalized = false; |
ebd3c7ac | 115 | |
da1320da | 116 | /** |
117 | * The constructor function calls the abstract function definition() and it will then | |
118 | * process and clean and attempt to validate incoming data. | |
119 | * | |
120 | * It will call your custom validate method to validate data and will also check any rules | |
121 | * you have specified in definition using addRule | |
122 | * | |
123 | * The name of the form (id attribute of the form) is automatically generated depending on | |
124 | * the name you gave the class extending moodleform. You should call your class something | |
125 | * like | |
126 | * | |
4f51f48f | 127 | * @param mixed $action the action attribute for the form. If empty defaults to auto detect the |
128 | * current url. If a moodle_url object then outputs params as hidden variables. | |
da1320da | 129 | * @param array $customdata if your form defintion method needs access to data such as $course |
130 | * $cm, etc. to construct the form definition then pass it in this array. You can | |
131 | * use globals for somethings. | |
132 | * @param string $method if you set this to anything other than 'post' then _GET and _POST will | |
133 | * be merged and used as incoming data to the form. | |
134 | * @param string $target target frame for form submission. You will rarely use this. Don't use | |
135 | * it if you don't need to as the target attribute is deprecated in xhtml | |
136 | * strict. | |
137 | * @param mixed $attributes you can pass a string of html attributes here or an array. | |
ba21c9d4 | 138 | * @param bool $editable |
139 | * @return object moodleform | |
da1320da | 140 | */ |
4f51f48f | 141 | function moodleform($action=null, $customdata=null, $method='post', $target='', $attributes=null, $editable=true) { |
6e9989db PS |
142 | global $CFG; |
143 | if (empty($CFG->xmlstrictheaders)) { | |
144 | // no standard mform in moodle should allow autocomplete with the exception of user signup | |
145 | // this is valid attribute in html5, sorry, we have to ignore validation errors in legacy xhtml 1.0 | |
48cbe43d PS |
146 | if (empty($attributes)) { |
147 | $attributes = array('autocomplete'=>'off'); | |
148 | } else if (is_array($attributes)) { | |
6e9989db | 149 | $attributes['autocomplete'] = 'off'; |
48cbe43d PS |
150 | } else { |
151 | if (strpos($attributes, 'autocomplete') === false) { | |
152 | $attributes .= ' autocomplete="off" '; | |
153 | } | |
6e9989db PS |
154 | } |
155 | } | |
156 | ||
a23f0aaf | 157 | if (empty($action)){ |
158 | $action = strip_querystring(qualified_me()); | |
159 | } | |
3a70ccb8 | 160 | // Assign custom data first, so that get_form_identifier can use it. |
7f40a229 | 161 | $this->_customdata = $customdata; |
3a70ccb8 RT |
162 | $this->_formname = $this->get_form_identifier(); |
163 | ||
66491cf1 | 164 | $this->_form = new MoodleQuickForm($this->_formname, $method, $action, $target, $attributes); |
4f51f48f | 165 | if (!$editable){ |
166 | $this->_form->hardFreeze(); | |
167 | } | |
7f40a229 | 168 | |
169 | $this->definition(); | |
170 | ||
171 | $this->_form->addElement('hidden', 'sesskey', null); // automatic sesskey protection | |
d18e0fe6 | 172 | $this->_form->setType('sesskey', PARAM_RAW); |
7f40a229 | 173 | $this->_form->setDefault('sesskey', sesskey()); |
5bc97c98 | 174 | $this->_form->addElement('hidden', '_qf__'.$this->_formname, null); // form submission marker |
d18e0fe6 | 175 | $this->_form->setType('_qf__'.$this->_formname, PARAM_RAW); |
5bc97c98 | 176 | $this->_form->setDefault('_qf__'.$this->_formname, 1); |
177 | $this->_form->_setDefaultRuleMessages(); | |
7f40a229 | 178 | |
179 | // we have to know all input types before processing submission ;-) | |
180 | $this->_process_submission($method); | |
7f40a229 | 181 | } |
05f5c40c | 182 | |
3a70ccb8 RT |
183 | /** |
184 | * It should returns unique identifier for the form. | |
185 | * Currently it will return class name, but in case two same forms have to be | |
186 | * rendered on same page then override function to get unique form identifier. | |
187 | * e.g This is used on multiple self enrollments page. | |
188 | * | |
189 | * @return string form identifier. | |
190 | */ | |
191 | protected function get_form_identifier() { | |
192 | return get_class($this); | |
193 | } | |
194 | ||
2c412890 | 195 | /** |
da1320da | 196 | * To autofocus on first form element or first element with error. |
2c412890 | 197 | * |
8dec2253 | 198 | * @param string $name if this is set then the focus is forced to a field with this name |
199 | * | |
2c412890 | 200 | * @return string javascript to select form element with first error or |
da1320da | 201 | * first element if no errors. Use this as a parameter |
202 | * when calling print_header | |
2c412890 | 203 | */ |
46f3921e | 204 | function focus($name=NULL) { |
9403060a | 205 | $form =& $this->_form; |
46f3921e | 206 | $elkeys = array_keys($form->_elementIndex); |
207 | $error = false; | |
9403060a | 208 | if (isset($form->_errors) && 0 != count($form->_errors)){ |
209 | $errorkeys = array_keys($form->_errors); | |
210 | $elkeys = array_intersect($elkeys, $errorkeys); | |
46f3921e | 211 | $error = true; |
2c412890 | 212 | } |
46f3921e | 213 | |
214 | if ($error or empty($name)) { | |
215 | $names = array(); | |
216 | while (empty($names) and !empty($elkeys)) { | |
217 | $el = array_shift($elkeys); | |
218 | $names = $form->_getElNamesRecursive($el); | |
219 | } | |
220 | if (!empty($names)) { | |
221 | $name = array_shift($names); | |
222 | } | |
8dec2253 | 223 | } |
46f3921e | 224 | |
225 | $focus = ''; | |
226 | if (!empty($name)) { | |
227 | $focus = 'forms[\''.$form->getAttribute('id').'\'].elements[\''.$name.'\']'; | |
9403060a | 228 | } |
46f3921e | 229 | |
9403060a | 230 | return $focus; |
231 | } | |
7f40a229 | 232 | |
05f5c40c | 233 | /** |
234 | * Internal method. Alters submitted data to be suitable for quickforms processing. | |
235 | * Must be called when the form is fully set up. | |
ba21c9d4 | 236 | * |
237 | * @param string $method | |
05f5c40c | 238 | */ |
7f40a229 | 239 | function _process_submission($method) { |
240 | $submission = array(); | |
241 | if ($method == 'post') { | |
242 | if (!empty($_POST)) { | |
243 | $submission = $_POST; | |
244 | } | |
245 | } else { | |
246 | $submission = array_merge_recursive($_GET, $_POST); // emulate handling of parameters in xxxx_param() | |
247 | } | |
248 | ||
249 | // following trick is needed to enable proper sesskey checks when using GET forms | |
5bc97c98 | 250 | // the _qf__.$this->_formname serves as a marker that form was actually submitted |
251 | if (array_key_exists('_qf__'.$this->_formname, $submission) and $submission['_qf__'.$this->_formname] == 1) { | |
7f40a229 | 252 | if (!confirm_sesskey()) { |
c3f9ee10 | 253 | print_error('invalidsesskey'); |
7f40a229 | 254 | } |
05f5c40c | 255 | $files = $_FILES; |
7f40a229 | 256 | } else { |
257 | $submission = array(); | |
05f5c40c | 258 | $files = array(); |
7f40a229 | 259 | } |
260 | ||
05f5c40c | 261 | $this->_form->updateSubmission($submission, $files); |
7f40a229 | 262 | } |
263 | ||
05f5c40c | 264 | /** |
f728d49b PS |
265 | * Internal method. Validates all old-style deprecated uploaded files. |
266 | * The new way is to upload files via repository api. | |
117bd748 | 267 | * |
ba21c9d4 | 268 | * @global object |
269 | * @global object | |
270 | * @param array $files | |
271 | * @return bool|array Success or an array of errors | |
05f5c40c | 272 | */ |
89489cfe | 273 | function _validate_files(&$files) { |
172dd12c | 274 | global $CFG, $COURSE; |
275 | ||
89489cfe | 276 | $files = array(); |
277 | ||
49292f8c | 278 | if (empty($_FILES)) { |
279 | // we do not need to do any checks because no files were submitted | |
89489cfe | 280 | // note: server side rules do not work for files - use custom verification in validate() instead |
49292f8c | 281 | return true; |
282 | } | |
49292f8c | 283 | |
172dd12c | 284 | $errors = array(); |
285 | $filenames = array(); | |
49292f8c | 286 | |
287 | // now check that we really want each file | |
288 | foreach ($_FILES as $elname=>$file) { | |
172dd12c | 289 | $required = $this->_form->isElementRequired($elname); |
89489cfe | 290 | |
172dd12c | 291 | if ($file['error'] == 4 and $file['size'] == 0) { |
292 | if ($required) { | |
293 | $errors[$elname] = get_string('required'); | |
49292f8c | 294 | } |
172dd12c | 295 | unset($_FILES[$elname]); |
296 | continue; | |
297 | } | |
298 | ||
a83ad946 | 299 | if (!empty($file['error'])) { |
300 | $errors[$elname] = file_get_upload_error($file['error']); | |
172dd12c | 301 | unset($_FILES[$elname]); |
302 | continue; | |
303 | } | |
304 | ||
305 | if (!is_uploaded_file($file['tmp_name'])) { | |
306 | // TODO: improve error message | |
307 | $errors[$elname] = get_string('error'); | |
308 | unset($_FILES[$elname]); | |
309 | continue; | |
310 | } | |
311 | ||
312 | if (!$this->_form->elementExists($elname) or !$this->_form->getElementType($elname)=='file') { | |
313 | // hmm, this file was not requested | |
314 | unset($_FILES[$elname]); | |
315 | continue; | |
316 | } | |
317 | ||
318 | /* | |
f728d49b | 319 | // TODO: rethink the file scanning MDL-19380 |
172dd12c | 320 | if ($CFG->runclamonupload) { |
321 | if (!clam_scan_moodle_file($_FILES[$elname], $COURSE)) { | |
322 | $errors[$elname] = $_FILES[$elname]['uploadlog']; | |
323 | unset($_FILES[$elname]); | |
324 | continue; | |
325 | } | |
326 | } | |
327 | */ | |
328 | $filename = clean_param($_FILES[$elname]['name'], PARAM_FILE); | |
329 | if ($filename === '') { | |
330 | // TODO: improve error message - wrong chars | |
331 | $errors[$elname] = get_string('error'); | |
332 | unset($_FILES[$elname]); | |
333 | continue; | |
49292f8c | 334 | } |
172dd12c | 335 | if (in_array($filename, $filenames)) { |
336 | // TODO: improve error message - duplicate name | |
337 | $errors[$elname] = get_string('error'); | |
338 | unset($_FILES[$elname]); | |
339 | continue; | |
340 | } | |
341 | $filenames[] = $filename; | |
342 | $_FILES[$elname]['name'] = $filename; | |
343 | ||
344 | $files[$elname] = $_FILES[$elname]['tmp_name']; | |
49292f8c | 345 | } |
346 | ||
347 | // return errors if found | |
172dd12c | 348 | if (count($errors) == 0){ |
49292f8c | 349 | return true; |
89489cfe | 350 | |
49292f8c | 351 | } else { |
89489cfe | 352 | $files = array(); |
49292f8c | 353 | return $errors; |
354 | } | |
355 | } | |
356 | ||
c6aa3670 RT |
357 | /** |
358 | * Internal method. Validates filepicker and filemanager files if they are | |
359 | * set as required fields. Also, sets the error message if encountered one. | |
360 | * | |
361 | * @return bool/array with errors | |
362 | */ | |
363 | protected function validate_draft_files() { | |
364 | global $USER; | |
365 | $mform =& $this->_form; | |
366 | ||
367 | $errors = array(); | |
368 | //Go through all the required elements and make sure you hit filepicker or | |
369 | //filemanager element. | |
370 | foreach ($mform->_rules as $elementname => $rules) { | |
371 | $elementtype = $mform->getElementType($elementname); | |
372 | //If element is of type filepicker then do validation | |
373 | if (($elementtype == 'filepicker') || ($elementtype == 'filemanager')){ | |
374 | //Check if rule defined is required rule | |
375 | foreach ($rules as $rule) { | |
376 | if ($rule['type'] == 'required') { | |
377 | $draftid = (int)$mform->getSubmitValue($elementname); | |
378 | $fs = get_file_storage(); | |
379 | $context = get_context_instance(CONTEXT_USER, $USER->id); | |
380 | if (!$files = $fs->get_area_files($context->id, 'user', 'draft', $draftid, 'id DESC', false)) { | |
381 | $errors[$elementname] = $rule['message']; | |
382 | } | |
383 | } | |
384 | } | |
385 | } | |
386 | } | |
387 | if (empty($errors)) { | |
388 | return true; | |
389 | } else { | |
390 | return $errors; | |
391 | } | |
392 | } | |
393 | ||
05f5c40c | 394 | /** |
da1320da | 395 | * Load in existing data as form defaults. Usually new entry defaults are stored directly in |
396 | * form definition (new entry form); this function is used to load in data where values | |
397 | * already exist and data is being edited (edit entry form). | |
05f5c40c | 398 | * |
294ce987 | 399 | * note: $slashed param removed |
400 | * | |
05f5c40c | 401 | * @param mixed $default_values object or array of default values |
05f5c40c | 402 | */ |
294ce987 | 403 | function set_data($default_values) { |
7f40a229 | 404 | if (is_object($default_values)) { |
405 | $default_values = (array)$default_values; | |
406 | } | |
294ce987 | 407 | $this->_form->setDefaults($default_values); |
7f40a229 | 408 | } |
409 | ||
ba21c9d4 | 410 | /** |
f728d49b | 411 | * @deprecated |
ba21c9d4 | 412 | */ |
feaf5d06 | 413 | function set_upload_manager($um=false) { |
f728d49b | 414 | debugging('Old file uploads can not be used any more, please use new filepicker element'); |
c80a13c7 | 415 | } |
416 | ||
05f5c40c | 417 | /** |
418 | * Check that form was submitted. Does not check validity of submitted data. | |
419 | * | |
420 | * @return bool true if form properly submitted | |
421 | */ | |
7f40a229 | 422 | function is_submitted() { |
423 | return $this->_form->isSubmitted(); | |
424 | } | |
425 | ||
ba21c9d4 | 426 | /** |
427 | * @staticvar bool $nosubmit | |
428 | */ | |
a23f0aaf | 429 | function no_submit_button_pressed(){ |
430 | static $nosubmit = null; // one check is enough | |
431 | if (!is_null($nosubmit)){ | |
432 | return $nosubmit; | |
433 | } | |
434 | $mform =& $this->_form; | |
435 | $nosubmit = false; | |
f07b9627 | 436 | if (!$this->is_submitted()){ |
437 | return false; | |
438 | } | |
a23f0aaf | 439 | foreach ($mform->_noSubmitButtons as $nosubmitbutton){ |
440 | if (optional_param($nosubmitbutton, 0, PARAM_RAW)){ | |
441 | $nosubmit = true; | |
442 | break; | |
443 | } | |
444 | } | |
445 | return $nosubmit; | |
446 | } | |
447 | ||
448 | ||
05f5c40c | 449 | /** |
450 | * Check that form data is valid. | |
6bba6dbb | 451 | * You should almost always use this, rather than {@see validate_defined_fields} |
05f5c40c | 452 | * |
ba21c9d4 | 453 | * @staticvar bool $validated |
05f5c40c | 454 | * @return bool true if form data valid |
455 | */ | |
7f40a229 | 456 | function is_validated() { |
4f51f48f | 457 | //finalize the form definition before any processing |
458 | if (!$this->_definition_finalized) { | |
459 | $this->_definition_finalized = true; | |
460 | $this->definition_after_data(); | |
461 | } | |
462 | ||
6bba6dbb | 463 | return $this->validate_defined_fields(); |
464 | } | |
465 | ||
466 | /** | |
467 | * Validate the form. | |
468 | * | |
469 | * You almost always want to call {@see is_validated} instead of this | |
470 | * because it calls {@see definition_after_data} first, before validating the form, | |
471 | * which is what you want in 99% of cases. | |
472 | * | |
473 | * This is provided as a separate function for those special cases where | |
474 | * you want the form validated before definition_after_data is called | |
475 | * for example, to selectively add new elements depending on a no_submit_button press, | |
476 | * but only when the form is valid when the no_submit_button is pressed, | |
477 | * | |
478 | * @param boolean $validateonnosubmit optional, defaults to false. The default behaviour | |
479 | * is NOT to validate the form when a no submit button has been pressed. | |
480 | * pass true here to override this behaviour | |
481 | * | |
482 | * @return bool true if form data valid | |
483 | */ | |
484 | function validate_defined_fields($validateonnosubmit=false) { | |
485 | static $validated = null; // one validation is enough | |
486 | $mform =& $this->_form; | |
487 | if ($this->no_submit_button_pressed() && empty($validateonnosubmit)){ | |
9aa022fe | 488 | return false; |
489 | } elseif ($validated === null) { | |
3ba2c187 | 490 | $internal_val = $mform->validate(); |
89489cfe | 491 | |
492 | $files = array(); | |
493 | $file_val = $this->_validate_files($files); | |
c6aa3670 RT |
494 | //check draft files for validation and flag them if required files |
495 | //are not in draft area. | |
496 | $draftfilevalue = $this->validate_draft_files(); | |
497 | ||
498 | if ($file_val !== true && $draftfilevalue !== true) { | |
499 | $file_val = array_merge($file_val, $draftfilevalue); | |
500 | } else if ($draftfilevalue !== true) { | |
501 | $file_val = $draftfilevalue; | |
502 | } //default is file_val, so no need to assign. | |
503 | ||
89489cfe | 504 | if ($file_val !== true) { |
505 | if (!empty($file_val)) { | |
506 | foreach ($file_val as $element=>$msg) { | |
507 | $mform->setElementError($element, $msg); | |
508 | } | |
509 | } | |
510 | $file_val = false; | |
511 | } | |
512 | ||
4287fc0d | 513 | $data = $mform->exportValues(); |
89489cfe | 514 | $moodle_val = $this->validation($data, $files); |
a78890d5 | 515 | if ((is_array($moodle_val) && count($moodle_val)!==0)) { |
516 | // non-empty array means errors | |
517 | foreach ($moodle_val as $element=>$msg) { | |
518 | $mform->setElementError($element, $msg); | |
7f40a229 | 519 | } |
a78890d5 | 520 | $moodle_val = false; |
521 | ||
522 | } else { | |
523 | // anything else means validation ok | |
524 | $moodle_val = true; | |
7f40a229 | 525 | } |
89489cfe | 526 | |
49292f8c | 527 | $validated = ($internal_val and $moodle_val and $file_val); |
7f40a229 | 528 | } |
9aa022fe | 529 | return $validated; |
7f40a229 | 530 | } |
531 | ||
19110c57 | 532 | /** |
533 | * Return true if a cancel button has been pressed resulting in the form being submitted. | |
534 | * | |
535 | * @return boolean true if a cancel button has been pressed | |
536 | */ | |
537 | function is_cancelled(){ | |
538 | $mform =& $this->_form; | |
a23f0aaf | 539 | if ($mform->isSubmitted()){ |
540 | foreach ($mform->_cancelButtons as $cancelbutton){ | |
541 | if (optional_param($cancelbutton, 0, PARAM_RAW)){ | |
542 | return true; | |
543 | } | |
19110c57 | 544 | } |
545 | } | |
546 | return false; | |
547 | } | |
548 | ||
05f5c40c | 549 | /** |
da1320da | 550 | * Return submitted data if properly submitted or returns NULL if validation fails or |
551 | * if there is no submitted data. | |
172dd12c | 552 | * |
294ce987 | 553 | * note: $slashed param removed |
05f5c40c | 554 | * |
d2b322ae | 555 | * @return object submitted data; NULL if not valid or not submitted or cancelled |
05f5c40c | 556 | */ |
294ce987 | 557 | function get_data() { |
19110c57 | 558 | $mform =& $this->_form; |
3ba2c187 | 559 | |
d2b322ae | 560 | if (!$this->is_cancelled() and $this->is_submitted() and $this->is_validated()) { |
294ce987 | 561 | $data = $mform->exportValues(); |
5bc97c98 | 562 | unset($data['sesskey']); // we do not need to return sesskey |
563 | unset($data['_qf__'.$this->_formname]); // we do not need the submission marker too | |
7f40a229 | 564 | if (empty($data)) { |
565 | return NULL; | |
566 | } else { | |
567 | return (object)$data; | |
568 | } | |
569 | } else { | |
570 | return NULL; | |
571 | } | |
572 | } | |
573 | ||
4f51f48f | 574 | /** |
575 | * Return submitted data without validation or NULL if there is no submitted data. | |
294ce987 | 576 | * note: $slashed param removed |
4f51f48f | 577 | * |
4f51f48f | 578 | * @return object submitted data; NULL if not submitted |
579 | */ | |
294ce987 | 580 | function get_submitted_data() { |
4f51f48f | 581 | $mform =& $this->_form; |
582 | ||
583 | if ($this->is_submitted()) { | |
294ce987 | 584 | $data = $mform->exportValues(); |
4f51f48f | 585 | unset($data['sesskey']); // we do not need to return sesskey |
586 | unset($data['_qf__'.$this->_formname]); // we do not need the submission marker too | |
587 | if (empty($data)) { | |
588 | return NULL; | |
589 | } else { | |
590 | return (object)$data; | |
591 | } | |
592 | } else { | |
593 | return NULL; | |
594 | } | |
595 | } | |
596 | ||
05f5c40c | 597 | /** |
598 | * Save verified uploaded files into directory. Upload process can be customised from definition() | |
172dd12c | 599 | * NOTE: please use save_stored_file() or save_file() |
ba21c9d4 | 600 | * |
601 | * @return bool Always false | |
05f5c40c | 602 | */ |
49292f8c | 603 | function save_files($destination) { |
172dd12c | 604 | debugging('Not used anymore, please fix code! Use save_stored_file() or save_file() instead'); |
49292f8c | 605 | return false; |
606 | } | |
2b63df96 | 607 | |
feaf5d06 | 608 | /** |
172dd12c | 609 | * Returns name of uploaded file. |
ba21c9d4 | 610 | * |
611 | * @global object | |
172dd12c | 612 | * @param string $elname, first element if null |
feaf5d06 | 613 | * @return mixed false in case of failure, string if ok |
614 | */ | |
172dd12c | 615 | function get_new_filename($elname=null) { |
4287fc0d | 616 | global $USER; |
617 | ||
172dd12c | 618 | if (!$this->is_submitted() or !$this->is_validated()) { |
619 | return false; | |
620 | } | |
621 | ||
622 | if (is_null($elname)) { | |
623 | if (empty($_FILES)) { | |
624 | return false; | |
625 | } | |
626 | reset($_FILES); | |
627 | $elname = key($_FILES); | |
628 | } | |
4287fc0d | 629 | |
630 | if (empty($elname)) { | |
631 | return false; | |
632 | } | |
633 | ||
634 | $element = $this->_form->getElement($elname); | |
635 | ||
0022e2d7 | 636 | if ($element instanceof MoodleQuickForm_filepicker || $element instanceof MoodleQuickForm_filemanager) { |
4287fc0d | 637 | $values = $this->_form->exportValues($elname); |
638 | if (empty($values[$elname])) { | |
639 | return false; | |
640 | } | |
641 | $draftid = $values[$elname]; | |
642 | $fs = get_file_storage(); | |
643 | $context = get_context_instance(CONTEXT_USER, $USER->id); | |
64f93798 | 644 | if (!$files = $fs->get_area_files($context->id, 'user', 'draft', $draftid, 'id DESC', false)) { |
4287fc0d | 645 | return false; |
646 | } | |
647 | $file = reset($files); | |
648 | return $file->get_filename(); | |
649 | } | |
650 | ||
172dd12c | 651 | if (!isset($_FILES[$elname])) { |
652 | return false; | |
653 | } | |
654 | ||
655 | return $_FILES[$elname]['name']; | |
feaf5d06 | 656 | } |
657 | ||
b6b1d1ca | 658 | /** |
172dd12c | 659 | * Save file to standard filesystem |
ba21c9d4 | 660 | * |
661 | * @global object | |
172dd12c | 662 | * @param string $elname name of element |
663 | * @param string $pathname full path name of file | |
664 | * @param bool $override override file if exists | |
665 | * @return bool success | |
b6b1d1ca | 666 | */ |
172dd12c | 667 | function save_file($elname, $pathname, $override=false) { |
4287fc0d | 668 | global $USER; |
b6b1d1ca | 669 | |
4287fc0d | 670 | if (!$this->is_submitted() or !$this->is_validated()) { |
b6b1d1ca | 671 | return false; |
672 | } | |
172dd12c | 673 | if (file_exists($pathname)) { |
674 | if ($override) { | |
675 | if (!@unlink($pathname)) { | |
676 | return false; | |
677 | } | |
678 | } else { | |
679 | return false; | |
680 | } | |
681 | } | |
4287fc0d | 682 | |
683 | $element = $this->_form->getElement($elname); | |
684 | ||
0022e2d7 | 685 | if ($element instanceof MoodleQuickForm_filepicker || $element instanceof MoodleQuickForm_filemanager) { |
4287fc0d | 686 | $values = $this->_form->exportValues($elname); |
687 | if (empty($values[$elname])) { | |
688 | return false; | |
689 | } | |
690 | $draftid = $values[$elname]; | |
691 | $fs = get_file_storage(); | |
692 | $context = get_context_instance(CONTEXT_USER, $USER->id); | |
64f93798 | 693 | if (!$files = $fs->get_area_files($context->id, 'user', 'draft', $draftid, 'id DESC', false)) { |
4287fc0d | 694 | return false; |
695 | } | |
696 | $file = reset($files); | |
697 | ||
698 | return $file->copy_content_to($pathname); | |
699 | ||
700 | } else if (isset($_FILES[$elname])) { | |
701 | return copy($_FILES[$elname]['tmp_name'], $pathname); | |
172dd12c | 702 | } |
703 | ||
4287fc0d | 704 | return false; |
172dd12c | 705 | } |
706 | ||
edfd6a5e PS |
707 | /** |
708 | * Returns a temporary file, do not forget to delete after not needed any more. | |
709 | * | |
710 | * @param string $elname | |
711 | * @return string or false | |
712 | */ | |
713 | function save_temp_file($elname) { | |
714 | if (!$this->get_new_filename($elname)) { | |
715 | return false; | |
716 | } | |
af9b1444 | 717 | if (!$dir = make_temp_directory('forms')) { |
edfd6a5e PS |
718 | return false; |
719 | } | |
720 | if (!$tempfile = tempnam($dir, 'tempup_')) { | |
721 | return false; | |
722 | } | |
723 | if (!$this->save_file($elname, $tempfile, true)) { | |
724 | // something went wrong | |
725 | @unlink($tempfile); | |
726 | return false; | |
727 | } | |
728 | ||
729 | return $tempfile; | |
730 | } | |
731 | ||
0022e2d7 | 732 | /** |
d3d98a3a DC |
733 | * Get draft files of a form element |
734 | * This is a protected method which will be used only inside moodleforms | |
735 | * | |
736 | * @global object $USER | |
737 | * @param string $elname name of element | |
738 | * @return array | |
739 | */ | |
740 | protected function get_draft_files($elname) { | |
741 | global $USER; | |
742 | ||
743 | if (!$this->is_submitted()) { | |
744 | return false; | |
745 | } | |
746 | ||
747 | $element = $this->_form->getElement($elname); | |
748 | ||
749 | if ($element instanceof MoodleQuickForm_filepicker || $element instanceof MoodleQuickForm_filemanager) { | |
750 | $values = $this->_form->exportValues($elname); | |
751 | if (empty($values[$elname])) { | |
752 | return false; | |
753 | } | |
754 | $draftid = $values[$elname]; | |
755 | $fs = get_file_storage(); | |
756 | $context = get_context_instance(CONTEXT_USER, $USER->id); | |
64f93798 | 757 | if (!$files = $fs->get_area_files($context->id, 'user', 'draft', $draftid, 'id DESC', false)) { |
d3d98a3a DC |
758 | return null; |
759 | } | |
760 | return $files; | |
761 | } | |
762 | return null; | |
763 | } | |
764 | ||
172dd12c | 765 | /** |
766 | * Save file to local filesystem pool | |
ba21c9d4 | 767 | * |
768 | * @global object | |
172dd12c | 769 | * @param string $elname name of element |
924ddb15 | 770 | * @param int $newcontextid |
771 | * @param string $newfilearea | |
772 | * @param string $newfilepath | |
773 | * @param string $newfilename - use specified filename, if not specified name of uploaded file used | |
49583e9e | 774 | * @param bool $overwrite - overwrite file if exists |
924ddb15 | 775 | * @param int $newuserid - new userid if required |
172dd12c | 776 | * @return mixed stored_file object or false if error; may throw exception if duplicate found |
777 | */ | |
64f93798 | 778 | function save_stored_file($elname, $newcontextid, $newcomponent, $newfilearea, $newitemid, $newfilepath='/', |
49583e9e | 779 | $newfilename=null, $overwrite=false, $newuserid=null) { |
924ddb15 | 780 | global $USER; |
781 | ||
172dd12c | 782 | if (!$this->is_submitted() or !$this->is_validated()) { |
89489cfe | 783 | return false; |
172dd12c | 784 | } |
89489cfe | 785 | |
924ddb15 | 786 | if (empty($newuserid)) { |
787 | $newuserid = $USER->id; | |
89489cfe | 788 | } |
b6b1d1ca | 789 | |
4287fc0d | 790 | $element = $this->_form->getElement($elname); |
791 | $fs = get_file_storage(); | |
172dd12c | 792 | |
4287fc0d | 793 | if ($element instanceof MoodleQuickForm_filepicker) { |
794 | $values = $this->_form->exportValues($elname); | |
795 | if (empty($values[$elname])) { | |
796 | return false; | |
797 | } | |
798 | $draftid = $values[$elname]; | |
799 | $context = get_context_instance(CONTEXT_USER, $USER->id); | |
64f93798 | 800 | if (!$files = $fs->get_area_files($context->id, 'user' ,'draft', $draftid, 'id DESC', false)) { |
4287fc0d | 801 | return false; |
802 | } | |
803 | $file = reset($files); | |
804 | if (is_null($newfilename)) { | |
805 | $newfilename = $file->get_filename(); | |
806 | } | |
172dd12c | 807 | |
4287fc0d | 808 | if ($overwrite) { |
64f93798 | 809 | if ($oldfile = $fs->get_file($newcontextid, $newcomponent, $newfilearea, $newitemid, $newfilepath, $newfilename)) { |
4287fc0d | 810 | if (!$oldfile->delete()) { |
811 | return false; | |
812 | } | |
924ddb15 | 813 | } |
814 | } | |
815 | ||
64f93798 | 816 | $file_record = array('contextid'=>$newcontextid, 'component'=>$newcomponent, 'filearea'=>$newfilearea, 'itemid'=>$newitemid, |
4287fc0d | 817 | 'filepath'=>$newfilepath, 'filename'=>$newfilename, 'userid'=>$newuserid); |
818 | return $fs->create_file_from_storedfile($file_record, $file); | |
924ddb15 | 819 | |
4287fc0d | 820 | } else if (isset($_FILES[$elname])) { |
821 | $filename = is_null($newfilename) ? $_FILES[$elname]['name'] : $newfilename; | |
172dd12c | 822 | |
4287fc0d | 823 | if ($overwrite) { |
64f93798 | 824 | if ($oldfile = $fs->get_file($newcontextid, $newcomponent, $newfilearea, $newitemid, $newfilepath, $newfilename)) { |
4287fc0d | 825 | if (!$oldfile->delete()) { |
826 | return false; | |
827 | } | |
828 | } | |
924ddb15 | 829 | } |
4287fc0d | 830 | |
64f93798 | 831 | $file_record = array('contextid'=>$newcontextid, 'component'=>$newcomponent, 'filearea'=>$newfilearea, 'itemid'=>$newitemid, |
4287fc0d | 832 | 'filepath'=>$newfilepath, 'filename'=>$newfilename, 'userid'=>$newuserid); |
833 | return $fs->create_file_from_pathname($file_record, $_FILES[$elname]['tmp_name']); | |
924ddb15 | 834 | } |
835 | ||
836 | return false; | |
172dd12c | 837 | } |
838 | ||
839 | /** | |
840 | * Get content of uploaded file. | |
ba21c9d4 | 841 | * |
842 | * @global object | |
172dd12c | 843 | * @param $element name of file upload element |
844 | * @return mixed false in case of failure, string if ok | |
845 | */ | |
846 | function get_file_content($elname) { | |
4287fc0d | 847 | global $USER; |
848 | ||
172dd12c | 849 | if (!$this->is_submitted() or !$this->is_validated()) { |
850 | return false; | |
851 | } | |
852 | ||
4287fc0d | 853 | $element = $this->_form->getElement($elname); |
854 | ||
0022e2d7 | 855 | if ($element instanceof MoodleQuickForm_filepicker || $element instanceof MoodleQuickForm_filemanager) { |
4287fc0d | 856 | $values = $this->_form->exportValues($elname); |
857 | if (empty($values[$elname])) { | |
858 | return false; | |
859 | } | |
860 | $draftid = $values[$elname]; | |
861 | $fs = get_file_storage(); | |
862 | $context = get_context_instance(CONTEXT_USER, $USER->id); | |
64f93798 | 863 | if (!$files = $fs->get_area_files($context->id, 'user', 'draft', $draftid, 'id DESC', false)) { |
4287fc0d | 864 | return false; |
865 | } | |
866 | $file = reset($files); | |
867 | ||
868 | return $file->get_content(); | |
869 | ||
870 | } else if (isset($_FILES[$elname])) { | |
871 | return file_get_contents($_FILES[$elname]['tmp_name']); | |
b6b1d1ca | 872 | } |
172dd12c | 873 | |
4287fc0d | 874 | return false; |
b6b1d1ca | 875 | } |
876 | ||
05f5c40c | 877 | /** |
878 | * Print html form. | |
879 | */ | |
7f40a229 | 880 | function display() { |
4f51f48f | 881 | //finalize the form definition if not yet done |
882 | if (!$this->_definition_finalized) { | |
883 | $this->_definition_finalized = true; | |
884 | $this->definition_after_data(); | |
885 | } | |
7f40a229 | 886 | $this->_form->display(); |
887 | } | |
888 | ||
49292f8c | 889 | /** |
05f5c40c | 890 | * Abstract method - always override! |
49292f8c | 891 | */ |
afd63fe5 | 892 | protected abstract function definition(); |
2c412890 | 893 | |
c08ac016 | 894 | /** |
05f5c40c | 895 | * Dummy stub method - override if you need to setup the form depending on current |
beac4717 | 896 | * values. This method is called after definition(), data submission and set_data(). |
05f5c40c | 897 | * All form setup that is dependent on form values should go in here. |
c08ac016 | 898 | */ |
899 | function definition_after_data(){ | |
c08ac016 | 900 | } |
7f40a229 | 901 | |
05f5c40c | 902 | /** |
903 | * Dummy stub method - override if you needed to perform some extra validation. | |
904 | * If there are errors return array of errors ("fieldname"=>"error message"), | |
905 | * otherwise true if ok. | |
38f394b2 | 906 | * |
89489cfe | 907 | * Server side rules do not work for uploaded files, implement serverside rules here if needed. |
908 | * | |
05f5c40c | 909 | * @param array $data array of ("fieldname"=>value) of submitted data |
89489cfe | 910 | * @param array $files array of uploaded files "element_name"=>tmp_file_path |
a78890d5 | 911 | * @return array of "element_name"=>"error_description" if there are errors, |
912 | * or an empty array if everything is OK (true allowed for backwards compatibility too). | |
05f5c40c | 913 | */ |
89489cfe | 914 | function validation($data, $files) { |
13ccb7bd | 915 | return array(); |
7f40a229 | 916 | } |
ebd3c7ac | 917 | |
fa2fa5c6 TH |
918 | /** |
919 | * Helper used by {@link repeat_elements()}. | |
920 | * @param int $i the index of this element. | |
921 | * @param HTML_QuickForm_element $elementclone | |
03848c45 | 922 | * @param array $namecloned array of names |
fa2fa5c6 TH |
923 | */ |
924 | function repeat_elements_fix_clone($i, $elementclone, &$namecloned) { | |
925 | $name = $elementclone->getName(); | |
926 | $namecloned[] = $name; | |
927 | ||
928 | if (!empty($name)) { | |
929 | $elementclone->setName($name."[$i]"); | |
930 | } | |
931 | ||
932 | if (is_a($elementclone, 'HTML_QuickForm_header')) { | |
933 | $value = $elementclone->_text; | |
934 | $elementclone->setValue(str_replace('{no}', ($i+1), $value)); | |
935 | ||
936 | } else { | |
937 | $value=$elementclone->getLabel(); | |
938 | $elementclone->setLabel(str_replace('{no}', ($i+1), $value)); | |
939 | } | |
940 | } | |
941 | ||
616b549a | 942 | /** |
943 | * Method to add a repeating group of elements to a form. | |
944 | * | |
945 | * @param array $elementobjs Array of elements or groups of elements that are to be repeated | |
946 | * @param integer $repeats no of times to repeat elements initially | |
947 | * @param array $options Array of options to apply to elements. Array keys are element names. | |
948 | * This is an array of arrays. The second sets of keys are the option types | |
949 | * for the elements : | |
950 | * 'default' - default value is value | |
951 | * 'type' - PARAM_* constant is value | |
952 | * 'helpbutton' - helpbutton params array is value | |
953 | * 'disabledif' - last three moodleform::disabledIf() | |
954 | * params are value as an array | |
955 | * @param string $repeathiddenname name for hidden element storing no of repeats in this form | |
956 | * @param string $addfieldsname name for button to add more fields | |
957 | * @param int $addfieldsno how many fields to add at a time | |
271ffe3f | 958 | * @param string $addstring name of button, {no} is replaced by no of blanks that will be added. |
6f3b54c8 | 959 | * @param boolean $addbuttoninside if true, don't call closeHeaderBefore($addfieldsname). Default false. |
a23f0aaf | 960 | * @return int no of repeats of element in this page |
616b549a | 961 | */ |
6f3b54c8 | 962 | function repeat_elements($elementobjs, $repeats, $options, $repeathiddenname, |
963 | $addfieldsname, $addfieldsno=5, $addstring=null, $addbuttoninside=false){ | |
271ffe3f | 964 | if ($addstring===null){ |
965 | $addstring = get_string('addfields', 'form', $addfieldsno); | |
966 | } else { | |
967 | $addstring = str_ireplace('{no}', $addfieldsno, $addstring); | |
968 | } | |
ebd3c7ac | 969 | $repeats = optional_param($repeathiddenname, $repeats, PARAM_INT); |
970 | $addfields = optional_param($addfieldsname, '', PARAM_TEXT); | |
971 | if (!empty($addfields)){ | |
972 | $repeats += $addfieldsno; | |
973 | } | |
ebd3c7ac | 974 | $mform =& $this->_form; |
a23f0aaf | 975 | $mform->registerNoSubmitButton($addfieldsname); |
ebd3c7ac | 976 | $mform->addElement('hidden', $repeathiddenname, $repeats); |
d18e0fe6 | 977 | $mform->setType($repeathiddenname, PARAM_INT); |
ebd3c7ac | 978 | //value not to be overridden by submitted value |
979 | $mform->setConstants(array($repeathiddenname=>$repeats)); | |
414f7bee | 980 | $namecloned = array(); |
981 | for ($i = 0; $i < $repeats; $i++) { | |
ebd3c7ac | 982 | foreach ($elementobjs as $elementobj){ |
985f0ddd | 983 | $elementclone = fullclone($elementobj); |
fa2fa5c6 | 984 | $this->repeat_elements_fix_clone($i, $elementclone, $namecloned); |
ebd3c7ac | 985 | |
fa2fa5c6 TH |
986 | if ($elementclone instanceof HTML_QuickForm_group && !$elementclone->_appendName) { |
987 | foreach ($elementclone->getElements() as $el) { | |
988 | $this->repeat_elements_fix_clone($i, $el, $namecloned); | |
989 | } | |
990 | $elementclone->setLabel(str_replace('{no}', $i + 1, $elementclone->getLabel())); | |
ebd3c7ac | 991 | } |
7b41a4a9 | 992 | |
ebd3c7ac | 993 | $mform->addElement($elementclone); |
994 | } | |
995 | } | |
996 | for ($i=0; $i<$repeats; $i++) { | |
997 | foreach ($options as $elementname => $elementoptions){ | |
998 | $pos=strpos($elementname, '['); | |
999 | if ($pos!==FALSE){ | |
1000 | $realelementname = substr($elementname, 0, $pos+1)."[$i]"; | |
1001 | $realelementname .= substr($elementname, $pos+1); | |
1002 | }else { | |
1003 | $realelementname = $elementname."[$i]"; | |
1004 | } | |
1005 | foreach ($elementoptions as $option => $params){ | |
1006 | ||
1007 | switch ($option){ | |
1008 | case 'default' : | |
1009 | $mform->setDefault($realelementname, $params); | |
1010 | break; | |
ebd3c7ac | 1011 | case 'helpbutton' : |
cd188086 DM |
1012 | $params = array_merge(array($realelementname), $params); |
1013 | call_user_func_array(array(&$mform, 'addHelpButton'), $params); | |
ebd3c7ac | 1014 | break; |
1015 | case 'disabledif' : | |
414f7bee | 1016 | foreach ($namecloned as $num => $name){ |
1017 | if ($params[0] == $name){ | |
1018 | $params[0] = $params[0]."[$i]"; | |
1019 | break; | |
1020 | } | |
1021 | } | |
9aa022fe | 1022 | $params = array_merge(array($realelementname), $params); |
1023 | call_user_func_array(array(&$mform, 'disabledIf'), $params); | |
1024 | break; | |
1025 | case 'rule' : | |
1026 | if (is_string($params)){ | |
1027 | $params = array(null, $params, null, 'client'); | |
1028 | } | |
1029 | $params = array_merge(array($realelementname), $params); | |
1030 | call_user_func_array(array(&$mform, 'addRule'), $params); | |
ebd3c7ac | 1031 | break; |
51070abc RT |
1032 | case 'type' : |
1033 | //Type should be set only once | |
1034 | if (!isset($mform->_types[$elementname])) { | |
1035 | $mform->setType($elementname, $params); | |
1036 | } | |
1037 | break; | |
ebd3c7ac | 1038 | } |
1039 | } | |
1040 | } | |
1041 | } | |
271ffe3f | 1042 | $mform->addElement('submit', $addfieldsname, $addstring); |
a23f0aaf | 1043 | |
6f3b54c8 | 1044 | if (!$addbuttoninside) { |
1045 | $mform->closeHeaderBefore($addfieldsname); | |
1046 | } | |
ebd3c7ac | 1047 | |
19194f82 | 1048 | return $repeats; |
ebd3c7ac | 1049 | } |
6073a598 | 1050 | |
1051 | /** | |
1052 | * Adds a link/button that controls the checked state of a group of checkboxes. | |
ba21c9d4 | 1053 | * |
1054 | * @global object | |
6073a598 | 1055 | * @param int $groupid The id of the group of advcheckboxes this element controls |
d8e7d1a0 | 1056 | * @param string $text The text of the link. Defaults to selectallornone ("select all/none") |
6073a598 | 1057 | * @param array $attributes associative array of HTML attributes |
1058 | * @param int $originalValue The original general state of the checkboxes before the user first clicks this element | |
1059 | */ | |
d8e7d1a0 | 1060 | function add_checkbox_controller($groupid, $text = null, $attributes = null, $originalValue = 0) { |
6073a598 | 1061 | global $CFG; |
d8e7d1a0 ARN |
1062 | |
1063 | // Set the default text if none was specified | |
6073a598 | 1064 | if (empty($text)) { |
1065 | $text = get_string('selectallornone', 'form'); | |
1066 | } | |
1067 | ||
1068 | $mform = $this->_form; | |
1069 | $select_value = optional_param('checkbox_controller'. $groupid, null, PARAM_INT); | |
1070 | ||
1071 | if ($select_value == 0 || is_null($select_value)) { | |
1072 | $new_select_value = 1; | |
1073 | } else { | |
1074 | $new_select_value = 0; | |
1075 | } | |
1076 | ||
1077 | $mform->addElement('hidden', "checkbox_controller$groupid"); | |
d18e0fe6 | 1078 | $mform->setType("checkbox_controller$groupid", PARAM_INT); |
6073a598 | 1079 | $mform->setConstants(array("checkbox_controller$groupid" => $new_select_value)); |
172dd12c | 1080 | |
6073a598 | 1081 | $checkbox_controller_name = 'nosubmit_checkbox_controller' . $groupid; |
1082 | $mform->registerNoSubmitButton($checkbox_controller_name); | |
172dd12c | 1083 | |
6073a598 | 1084 | // Prepare Javascript for submit element |
1085 | $js = "\n//<![CDATA[\n"; | |
1086 | if (!defined('HTML_QUICKFORM_CHECKBOXCONTROLLER_EXISTS')) { | |
1087 | $js .= <<<EOS | |
1088 | function html_quickform_toggle_checkboxes(group) { | |
775fd4f1 | 1089 | var checkboxes = document.getElementsByClassName('checkboxgroup' + group); |
6073a598 | 1090 | var newvalue = false; |
1091 | var global = eval('html_quickform_checkboxgroup' + group + ';'); | |
1092 | if (global == 1) { | |
172dd12c | 1093 | eval('html_quickform_checkboxgroup' + group + ' = 0;'); |
6073a598 | 1094 | newvalue = ''; |
1095 | } else { | |
172dd12c | 1096 | eval('html_quickform_checkboxgroup' + group + ' = 1;'); |
6073a598 | 1097 | newvalue = 'checked'; |
1098 | } | |
1099 | ||
1100 | for (i = 0; i < checkboxes.length; i++) { | |
172dd12c | 1101 | checkboxes[i].checked = newvalue; |
6073a598 | 1102 | } |
1103 | } | |
1104 | EOS; | |
1105 | define('HTML_QUICKFORM_CHECKBOXCONTROLLER_EXISTS', true); | |
1106 | } | |
1107 | $js .= "\nvar html_quickform_checkboxgroup$groupid=$originalValue;\n"; | |
172dd12c | 1108 | |
6073a598 | 1109 | $js .= "//]]>\n"; |
172dd12c | 1110 | |
6073a598 | 1111 | require_once("$CFG->libdir/form/submitlink.php"); |
1112 | $submitlink = new MoodleQuickForm_submitlink($checkbox_controller_name, $attributes); | |
1113 | $submitlink->_js = $js; | |
1114 | $submitlink->_onclick = "html_quickform_toggle_checkboxes($groupid); return false;"; | |
172dd12c | 1115 | $mform->addElement($submitlink); |
6073a598 | 1116 | $mform->setDefault($checkbox_controller_name, $text); |
1117 | } | |
1118 | ||
a23f0aaf | 1119 | /** |
1d284fbd | 1120 | * Use this method to a cancel and submit button to the end of your form. Pass a param of false |
a23f0aaf | 1121 | * if you don't want a cancel button in your form. If you have a cancel button make sure you |
1122 | * check for it being pressed using is_cancelled() and redirecting if it is true before trying to | |
beac4717 | 1123 | * get data with get_data(). |
a23f0aaf | 1124 | * |
1125 | * @param boolean $cancel whether to show cancel button, default true | |
a23f0aaf | 1126 | * @param string $submitlabel label for submit button, defaults to get_string('savechanges') |
1127 | */ | |
1d284fbd | 1128 | function add_action_buttons($cancel = true, $submitlabel=null){ |
a23f0aaf | 1129 | if (is_null($submitlabel)){ |
1130 | $submitlabel = get_string('savechanges'); | |
1131 | } | |
1132 | $mform =& $this->_form; | |
1d284fbd | 1133 | if ($cancel){ |
1134 | //when two elements we need a group | |
a23f0aaf | 1135 | $buttonarray=array(); |
1136 | $buttonarray[] = &$mform->createElement('submit', 'submitbutton', $submitlabel); | |
1d284fbd | 1137 | $buttonarray[] = &$mform->createElement('cancel'); |
a23f0aaf | 1138 | $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false); |
4f51f48f | 1139 | $mform->closeHeaderBefore('buttonar'); |
a23f0aaf | 1140 | } else { |
1141 | //no group needed | |
1142 | $mform->addElement('submit', 'submitbutton', $submitlabel); | |
4f51f48f | 1143 | $mform->closeHeaderBefore('submitbutton'); |
a23f0aaf | 1144 | } |
1145 | } | |
572dd8ec SH |
1146 | |
1147 | /** | |
2836e77d | 1148 | * Adds an initialisation call for a standard JavaScript enhancement. |
572dd8ec SH |
1149 | * |
1150 | * This function is designed to add an initialisation call for a JavaScript | |
2836e77d | 1151 | * enhancement that should exist within javascript-static M.form.init_{enhancementname}. |
572dd8ec SH |
1152 | * |
1153 | * Current options: | |
1154 | * - Selectboxes | |
1155 | * - smartselect: Turns a nbsp indented select box into a custom drop down | |
1156 | * control that supports multilevel and category selection. | |
1157 | * $enhancement = 'smartselect'; | |
1158 | * $options = array('selectablecategories' => true|false) | |
1159 | * | |
1160 | * @since 2.0 | |
1161 | * @param string|element $element | |
1162 | * @param string $enhancement | |
1163 | * @param array $options | |
1164 | * @param array $strings | |
1165 | */ | |
1166 | function init_javascript_enhancement($element, $enhancement, array $options=array(), array $strings=null) { | |
1167 | global $PAGE; | |
1168 | if (is_string($element)) { | |
1169 | $element = $this->_form->getElement($element); | |
c7e3e61c | 1170 | } |
572dd8ec SH |
1171 | if (is_object($element)) { |
1172 | $element->_generateId(); | |
1173 | $elementid = $element->getAttribute('id'); | |
1174 | $PAGE->requires->js_init_call('M.form.init_'.$enhancement, array($elementid, $options)); | |
1175 | if (is_array($strings)) { | |
1176 | foreach ($strings as $string) { | |
1177 | if (is_array($string)) { | |
1178 | call_user_method_array('string_for_js', $PAGE->requires, $string); | |
1179 | } else { | |
1180 | $PAGE->requires->string_for_js($string, 'moodle'); | |
1181 | } | |
1182 | } | |
1183 | } | |
1184 | } | |
1185 | } | |
c7e3e61c SH |
1186 | |
1187 | /** | |
1188 | * Returns a JS module definition for the mforms JS | |
1189 | * @return array | |
1190 | */ | |
1191 | public static function get_js_module() { | |
1192 | global $CFG; | |
1193 | return array( | |
1194 | 'name' => 'mform', | |
1195 | 'fullpath' => '/lib/form/form.js', | |
1196 | 'requires' => array('base', 'node'), | |
1197 | 'strings' => array( | |
1198 | array('showadvanced', 'form'), | |
1199 | array('hideadvanced', 'form') | |
1200 | ) | |
1201 | ); | |
1202 | } | |
7f40a229 | 1203 | } |
1204 | ||
da1320da | 1205 | /** |
1206 | * You never extend this class directly. The class methods of this class are available from | |
6073a598 | 1207 | * the private $this->_form property on moodleform and its children. You generally only |
da1320da | 1208 | * call methods on this class from within abstract methods that you override on moodleform such |
1209 | * as definition and definition_after_data | |
1210 | * | |
ba21c9d4 | 1211 | * @package moodlecore |
1212 | * @copyright Jamie Pratt <me@jamiep.org> | |
1213 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
da1320da | 1214 | */ |
7f40a229 | 1215 | class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless { |
ba21c9d4 | 1216 | /** @var array */ |
7f40a229 | 1217 | var $_types = array(); |
50ef8eb9 | 1218 | var $_dependencies = array(); |
19110c57 | 1219 | /** |
1220 | * Array of buttons that if pressed do not result in the processing of the form. | |
1221 | * | |
1222 | * @var array | |
1223 | */ | |
1224 | var $_noSubmitButtons=array(); | |
1225 | /** | |
1226 | * Array of buttons that if pressed do not result in the processing of the form. | |
1227 | * | |
1228 | * @var array | |
1229 | */ | |
1230 | var $_cancelButtons=array(); | |
7f40a229 | 1231 | |
19194f82 | 1232 | /** |
1233 | * Array whose keys are element names. If the key exists this is a advanced element | |
1234 | * | |
1235 | * @var array | |
1236 | */ | |
1237 | var $_advancedElements = array(); | |
1238 | ||
1239 | /** | |
1240 | * Whether to display advanced elements (on page load) | |
1241 | * | |
1242 | * @var boolean | |
1243 | */ | |
1244 | var $_showAdvanced = null; | |
1245 | ||
f07b9627 | 1246 | /** |
2836e77d | 1247 | * The form name is derived from the class name of the wrapper minus the trailing form |
f07b9627 | 1248 | * It is a name with words joined by underscores whereas the id attribute is words joined by |
1249 | * underscores. | |
1250 | * | |
1251 | * @var unknown_type | |
1252 | */ | |
1253 | var $_formName = ''; | |
43914931 | 1254 | |
4f51f48f | 1255 | /** |
1256 | * String with the html for hidden params passed in as part of a moodle_url object for the action. Output in the form. | |
1257 | * | |
1258 | * @var string | |
1259 | */ | |
1260 | var $_pageparams = ''; | |
1261 | ||
da6f8763 | 1262 | /** |
1263 | * Class constructor - same parameters as HTML_QuickForm_DHTMLRulesTableless | |
ba21c9d4 | 1264 | * |
1265 | * @global object | |
1266 | * @staticvar int $formcounter | |
da6f8763 | 1267 | * @param string $formName Form's name. |
1268 | * @param string $method (optional)Form's method defaults to 'POST' | |
4f51f48f | 1269 | * @param mixed $action (optional)Form's action - string or moodle_url |
da6f8763 | 1270 | * @param string $target (optional)Form's target defaults to none |
1271 | * @param mixed $attributes (optional)Extra attributes for <form> tag | |
da6f8763 | 1272 | * @access public |
1273 | */ | |
7f40a229 | 1274 | function MoodleQuickForm($formName, $method, $action, $target='', $attributes=null){ |
96705c33 | 1275 | global $CFG, $OUTPUT; |
dcf6d93c | 1276 | |
271ffe3f | 1277 | static $formcounter = 1; |
7f40a229 | 1278 | |
da6f8763 | 1279 | HTML_Common::HTML_Common($attributes); |
da6f8763 | 1280 | $target = empty($target) ? array() : array('target' => $target); |
f07b9627 | 1281 | $this->_formName = $formName; |
4f51f48f | 1282 | if (is_a($action, 'moodle_url')){ |
6ea66ff3 | 1283 | $this->_pageparams = html_writer::input_hidden_params($action); |
eb788065 | 1284 | $action = $action->out_omit_querystring(); |
4f51f48f | 1285 | } else { |
1286 | $this->_pageparams = ''; | |
1287 | } | |
da6f8763 | 1288 | //no 'name' atttribute for form in xhtml strict : |
1327f08e | 1289 | $attributes = array('action'=>$action, 'method'=>$method, |
1290 | 'accept-charset'=>'utf-8', 'id'=>'mform'.$formcounter) + $target; | |
271ffe3f | 1291 | $formcounter++; |
da6f8763 | 1292 | $this->updateAttributes($attributes); |
da6f8763 | 1293 | |
7f40a229 | 1294 | //this is custom stuff for Moodle : |
da6f8763 | 1295 | $oldclass= $this->getAttribute('class'); |
1296 | if (!empty($oldclass)){ | |
1297 | $this->updateAttributes(array('class'=>$oldclass.' mform')); | |
1298 | }else { | |
80f962df | 1299 | $this->updateAttributes(array('class'=>'mform')); |
da6f8763 | 1300 | } |
b5d0cafc PS |
1301 | $this->_reqHTML = '<img class="req" title="'.get_string('requiredelement', 'form').'" alt="'.get_string('requiredelement', 'form').'" src="'.$OUTPUT->pix_url('req') .'" />'; |
1302 | $this->_advancedHTML = '<img class="adv" title="'.get_string('advancedelement', 'form').'" alt="'.get_string('advancedelement', 'form').'" src="'.$OUTPUT->pix_url('adv') .'" />'; | |
1303 | $this->setRequiredNote(get_string('somefieldsrequired', 'form', '<img alt="'.get_string('requiredelement', 'form').'" src="'.$OUTPUT->pix_url('req') .'" />')); | |
19194f82 | 1304 | } |
1305 | ||
a23f0aaf | 1306 | /** |
1307 | * Use this method to indicate an element in a form is an advanced field. If items in a form | |
1308 | * are marked as advanced then 'Hide/Show Advanced' buttons will automatically be displayed in the | |
1309 | * form so the user can decide whether to display advanced form controls. | |
1310 | * | |
1311 | * If you set a header element to advanced then all elements it contains will also be set as advanced. | |
1312 | * | |
1313 | * @param string $elementName group or element name (not the element name of something inside a group). | |
1314 | * @param boolean $advanced default true sets the element to advanced. False removes advanced mark. | |
1315 | */ | |
1316 | function setAdvanced($elementName, $advanced=true){ | |
1317 | if ($advanced){ | |
1318 | $this->_advancedElements[$elementName]=''; | |
1319 | } elseif (isset($this->_advancedElements[$elementName])) { | |
1320 | unset($this->_advancedElements[$elementName]); | |
1321 | } | |
1322 | if ($advanced && $this->getElementType('mform_showadvanced_last')===false){ | |
1323 | $this->setShowAdvanced(); | |
1324 | $this->registerNoSubmitButton('mform_showadvanced'); | |
1325 | ||
1326 | $this->addElement('hidden', 'mform_showadvanced_last'); | |
d18e0fe6 | 1327 | $this->setType('mform_showadvanced_last', PARAM_INT); |
a23f0aaf | 1328 | } |
1329 | } | |
1330 | /** | |
1331 | * Set whether to show advanced elements in the form on first displaying form. Default is not to | |
1332 | * display advanced elements in the form until 'Show Advanced' is pressed. | |
1333 | * | |
1334 | * You can get the last state of the form and possibly save it for this user by using | |
1335 | * value 'mform_showadvanced_last' in submitted data. | |
1336 | * | |
1337 | * @param boolean $showadvancedNow | |
1338 | */ | |
1339 | function setShowAdvanced($showadvancedNow = null){ | |
1340 | if ($showadvancedNow === null){ | |
1341 | if ($this->_showAdvanced !== null){ | |
1342 | return; | |
1343 | } else { //if setShowAdvanced is called without any preference | |
1344 | //make the default to not show advanced elements. | |
f07b9627 | 1345 | $showadvancedNow = get_user_preferences( |
1346 | moodle_strtolower($this->_formName.'_showadvanced', 0)); | |
a23f0aaf | 1347 | } |
a23f0aaf | 1348 | } |
1349 | //value of hidden element | |
1350 | $hiddenLast = optional_param('mform_showadvanced_last', -1, PARAM_INT); | |
1351 | //value of button | |
1352 | $buttonPressed = optional_param('mform_showadvanced', 0, PARAM_RAW); | |
1353 | //toggle if button pressed or else stay the same | |
1354 | if ($hiddenLast == -1) { | |
1355 | $next = $showadvancedNow; | |
1356 | } elseif ($buttonPressed) { //toggle on button press | |
1357 | $next = !$hiddenLast; | |
1358 | } else { | |
1359 | $next = $hiddenLast; | |
1360 | } | |
1361 | $this->_showAdvanced = $next; | |
f07b9627 | 1362 | if ($showadvancedNow != $next){ |
1363 | set_user_preference($this->_formName.'_showadvanced', $next); | |
1364 | } | |
a23f0aaf | 1365 | $this->setConstants(array('mform_showadvanced_last'=>$next)); |
19194f82 | 1366 | } |
1367 | function getShowAdvanced(){ | |
1368 | return $this->_showAdvanced; | |
1369 | } | |
1370 | ||
19194f82 | 1371 | |
1372 | /** | |
1373 | * Accepts a renderer | |
1374 | * | |
ba21c9d4 | 1375 | * @param object $renderer HTML_QuickForm_Renderer An HTML_QuickForm_Renderer object |
19194f82 | 1376 | * @access public |
1377 | * @return void | |
1378 | */ | |
46f3921e | 1379 | function accept(&$renderer) { |
19194f82 | 1380 | if (method_exists($renderer, 'setAdvancedElements')){ |
1381 | //check for visible fieldsets where all elements are advanced | |
1382 | //and mark these headers as advanced as well. | |
1383 | //And mark all elements in a advanced header as advanced | |
1384 | $stopFields = $renderer->getStopFieldSetElements(); | |
1385 | $lastHeader = null; | |
1386 | $lastHeaderAdvanced = false; | |
1387 | $anyAdvanced = false; | |
1388 | foreach (array_keys($this->_elements) as $elementIndex){ | |
1389 | $element =& $this->_elements[$elementIndex]; | |
46f3921e | 1390 | |
1391 | // if closing header and any contained element was advanced then mark it as advanced | |
19194f82 | 1392 | if ($element->getType()=='header' || in_array($element->getName(), $stopFields)){ |
46f3921e | 1393 | if ($anyAdvanced && !is_null($lastHeader)){ |
19194f82 | 1394 | $this->setAdvanced($lastHeader->getName()); |
1395 | } | |
1396 | $lastHeaderAdvanced = false; | |
46f3921e | 1397 | unset($lastHeader); |
1398 | $lastHeader = null; | |
19194f82 | 1399 | } elseif ($lastHeaderAdvanced) { |
1400 | $this->setAdvanced($element->getName()); | |
1401 | } | |
46f3921e | 1402 | |
19194f82 | 1403 | if ($element->getType()=='header'){ |
1404 | $lastHeader =& $element; | |
1405 | $anyAdvanced = false; | |
1406 | $lastHeaderAdvanced = isset($this->_advancedElements[$element->getName()]); | |
1407 | } elseif (isset($this->_advancedElements[$element->getName()])){ | |
1408 | $anyAdvanced = true; | |
1409 | } | |
1410 | } | |
46f3921e | 1411 | // the last header may not be closed yet... |
1412 | if ($anyAdvanced && !is_null($lastHeader)){ | |
1413 | $this->setAdvanced($lastHeader->getName()); | |
1414 | } | |
19194f82 | 1415 | $renderer->setAdvancedElements($this->_advancedElements); |
19194f82 | 1416 | |
19194f82 | 1417 | } |
1418 | parent::accept($renderer); | |
1419 | } | |
1420 | ||
ba21c9d4 | 1421 | /** |
1422 | * @param string $elementName | |
1423 | */ | |
19194f82 | 1424 | function closeHeaderBefore($elementName){ |
1425 | $renderer =& $this->defaultRenderer(); | |
1426 | $renderer->addStopFieldsetElements($elementName); | |
da6f8763 | 1427 | } |
bb40325e | 1428 | |
da1320da | 1429 | /** |
1430 | * Should be used for all elements of a form except for select, radio and checkboxes which | |
1431 | * clean their own data. | |
1432 | * | |
1433 | * @param string $elementname | |
1434 | * @param integer $paramtype use the constants PARAM_*. | |
1435 | * * PARAM_CLEAN is deprecated and you should try to use a more specific type. | |
1436 | * * PARAM_TEXT should be used for cleaning data that is expected to be plain text. | |
1437 | * It will strip all html tags. But will still let tags for multilang support | |
1438 | * through. | |
1439 | * * PARAM_RAW means no cleaning whatsoever, it is used mostly for data from the | |
1440 | * html editor. Data from the editor is later cleaned before display using | |
1441 | * format_text() function. PARAM_RAW can also be used for data that is validated | |
1442 | * by some other way or printed by p() or s(). | |
1443 | * * PARAM_INT should be used for integers. | |
1444 | * * PARAM_ACTION is an alias of PARAM_ALPHA and is used for hidden fields specifying | |
1445 | * form actions. | |
1446 | */ | |
7f40a229 | 1447 | function setType($elementname, $paramtype) { |
1448 | $this->_types[$elementname] = $paramtype; | |
1449 | } | |
49292f8c | 1450 | |
da1320da | 1451 | /** |
1452 | * See description of setType above. This can be used to set several types at once. | |
1453 | * | |
1454 | * @param array $paramtypes | |
1455 | */ | |
c56f1826 | 1456 | function setTypes($paramtypes) { |
1457 | $this->_types = $paramtypes + $this->_types; | |
1458 | } | |
49292f8c | 1459 | |
ba21c9d4 | 1460 | /** |
1461 | * @param array $submission | |
1462 | * @param array $files | |
1463 | */ | |
49292f8c | 1464 | function updateSubmission($submission, $files) { |
1465 | $this->_flagSubmitted = false; | |
1466 | ||
7f40a229 | 1467 | if (empty($submission)) { |
1468 | $this->_submitValues = array(); | |
7f40a229 | 1469 | } else { |
1470 | foreach ($submission as $key=>$s) { | |
1471 | if (array_key_exists($key, $this->_types)) { | |
18bd7573 | 1472 | $type = $this->_types[$key]; |
78fcdb5f | 1473 | } else { |
18bd7573 PS |
1474 | $type = PARAM_RAW; |
1475 | } | |
1476 | if (is_array($s)) { | |
1477 | $submission[$key] = clean_param_array($s, $type, true); | |
1478 | } else { | |
1479 | $submission[$key] = clean_param($s, $type); | |
7f40a229 | 1480 | } |
1481 | } | |
294ce987 | 1482 | $this->_submitValues = $submission; |
7f40a229 | 1483 | $this->_flagSubmitted = true; |
1484 | } | |
1485 | ||
49292f8c | 1486 | if (empty($files)) { |
1487 | $this->_submitFiles = array(); | |
1488 | } else { | |
49292f8c | 1489 | $this->_submitFiles = $files; |
1490 | $this->_flagSubmitted = true; | |
1491 | } | |
1492 | ||
2c412890 | 1493 | // need to tell all elements that they need to update their value attribute. |
1494 | foreach (array_keys($this->_elements) as $key) { | |
1495 | $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this); | |
1496 | } | |
7f40a229 | 1497 | } |
1498 | ||
ba21c9d4 | 1499 | /** |
1500 | * @return string | |
1501 | */ | |
da6f8763 | 1502 | function getReqHTML(){ |
1503 | return $this->_reqHTML; | |
1504 | } | |
117bd748 | 1505 | |
ba21c9d4 | 1506 | /** |
1507 | * @return string | |
1508 | */ | |
19194f82 | 1509 | function getAdvancedHTML(){ |
1510 | return $this->_advancedHTML; | |
1511 | } | |
1512 | ||
7f40a229 | 1513 | /** |
da1320da | 1514 | * Initializes a default form value. Used to specify the default for a new entry where |
beac4717 | 1515 | * no data is loaded in using moodleform::set_data() |
7f40a229 | 1516 | * |
294ce987 | 1517 | * note: $slashed param removed |
1518 | * | |
7f40a229 | 1519 | * @param string $elementname element name |
1520 | * @param mixed $values values for that element name | |
7f40a229 | 1521 | * @access public |
1522 | * @return void | |
1523 | */ | |
294ce987 | 1524 | function setDefault($elementName, $defaultValue){ |
1525 | $this->setDefaults(array($elementName=>$defaultValue)); | |
7f40a229 | 1526 | } // end func setDefault |
da6f8763 | 1527 | /** |
c56f1826 | 1528 | * Add an array of buttons to the form |
7f40a229 | 1529 | * @param array $buttons An associative array representing help button to attach to |
da6f8763 | 1530 | * to the form. keys of array correspond to names of elements in form. |
c9a2cdf8 | 1531 | * @deprecated since Moodle 2.0 - use addHelpButton() call on each element manually |
ba21c9d4 | 1532 | * @param bool $suppresscheck |
1533 | * @param string $function | |
da6f8763 | 1534 | * @access public |
1535 | */ | |
d4fe14d3 | 1536 | function setHelpButtons($buttons, $suppresscheck=false, $function='helpbutton'){ |
7f40a229 | 1537 | |
c9a2cdf8 DM |
1538 | debugging('function moodle_form::setHelpButtons() is deprecated'); |
1539 | //foreach ($buttons as $elementname => $button){ | |
1540 | // $this->setHelpButton($elementname, $button, $suppresscheck, $function); | |
1541 | //} | |
da6f8763 | 1542 | } |
c56f1826 | 1543 | /** |
da1320da | 1544 | * Add a single button. |
c56f1826 | 1545 | * |
ff95caa8 | 1546 | * @deprecated use addHelpButton() instead |
c56f1826 | 1547 | * @param string $elementname name of the element to add the item to |
ba21c9d4 | 1548 | * @param array $button arguments to pass to function $function |
1549 | * @param boolean $suppresscheck whether to throw an error if the element | |
c56f1826 | 1550 | * doesn't exist. |
d4fe14d3 | 1551 | * @param string $function - function to generate html from the arguments in $button |
ba21c9d4 | 1552 | * @param string $function |
c56f1826 | 1553 | */ |
4bcc5118 | 1554 | function setHelpButton($elementname, $buttonargs, $suppresscheck=false, $function='helpbutton'){ |
642816a6 | 1555 | global $OUTPUT; |
cde9bee8 DM |
1556 | |
1557 | debugging('function moodle_form::setHelpButton() is deprecated'); | |
4bcc5118 | 1558 | if ($function !== 'helpbutton') { |
b65d2720 | 1559 | //debugging('parameter $function in moodle_form::setHelpButton() is not supported any more'); |
4bcc5118 PS |
1560 | } |
1561 | ||
1562 | $buttonargs = (array)$buttonargs; | |
1563 | ||
1564 | if (array_key_exists($elementname, $this->_elementIndex)) { | |
c56f1826 | 1565 | //_elements has a numeric index, this code accesses the elements by name |
4bcc5118 | 1566 | $element = $this->_elements[$this->_elementIndex[$elementname]]; |
642816a6 | 1567 | |
4bcc5118 PS |
1568 | $page = isset($buttonargs[0]) ? $buttonargs[0] : null; |
1569 | $text = isset($buttonargs[1]) ? $buttonargs[1] : null; | |
1570 | $module = isset($buttonargs[2]) ? $buttonargs[2] : 'moodle'; | |
1571 | $linktext = isset($buttonargs[3]) ? $buttonargs[3] : false; | |
1572 | ||
596509e4 | 1573 | $element->_helpbutton = $OUTPUT->old_help_icon($page, $text, $module, $linktext); |
642816a6 | 1574 | |
4bcc5118 | 1575 | } else if (!$suppresscheck) { |
c56f1826 | 1576 | print_error('nonexistentformelements', 'form', '', $elementname); |
2c412890 | 1577 | } |
c56f1826 | 1578 | } |
7f40a229 | 1579 | |
53a78cef | 1580 | /** |
259c165d PS |
1581 | * Add a help button to element, only one button per element is allowed. |
1582 | * | |
ff95caa8 DM |
1583 | * This is new, simplified and preferable method of setting a help icon on form elements. |
1584 | * It uses the new $OUTPUT->help_icon(). | |
1585 | * | |
1586 | * Typically, you will provide the same identifier and the component as you have used for the | |
1587 | * label of the element. The string identifier with the _help suffix added is then used | |
1588 | * as the help string. | |
1589 | * | |
259c165d PS |
1590 | * There has to be two strings defined: |
1591 | * 1/ get_string($identifier, $component) - the title of the help page | |
5435c9dc | 1592 | * 2/ get_string($identifier.'_help', $component) - the actual help page text |
53a78cef | 1593 | * |
ff95caa8 | 1594 | * @since 2.0 |
53a78cef | 1595 | * @param string $elementname name of the element to add the item to |
2836e77d | 1596 | * @param string $identifier help string identifier without _help suffix |
ff95caa8 DM |
1597 | * @param string $component component name to look the help string in |
1598 | * @param string $linktext optional text to display next to the icon | |
1599 | * @param boolean $suppresscheck set to true if the element may not exist | |
53a78cef PS |
1600 | * @return void |
1601 | */ | |
259c165d PS |
1602 | function addHelpButton($elementname, $identifier, $component = 'moodle', $linktext = '', $suppresscheck = false) { |
1603 | global $OUTPUT; | |
53a78cef | 1604 | if (array_key_exists($elementname, $this->_elementIndex)) { |
af140288 DC |
1605 | $element = $this->_elements[$this->_elementIndex[$elementname]]; |
1606 | $element->_helpbutton = $OUTPUT->help_icon($identifier, $component, $linktext); | |
53a78cef PS |
1607 | } else if (!$suppresscheck) { |
1608 | debugging(get_string('nonexistentformelements', 'form', $elementname)); | |
1609 | } | |
1610 | } | |
1611 | ||
cc444336 | 1612 | /** |
2836e77d | 1613 | * Set constant value not overridden by _POST or _GET |
cc444336 | 1614 | * note: this does not work for complex names with [] :-( |
ba21c9d4 | 1615 | * |
cc444336 | 1616 | * @param string $elname name of element |
1617 | * @param mixed $value | |
1618 | * @return void | |
1619 | */ | |
1620 | function setConstant($elname, $value) { | |
1621 | $this->_constantValues = HTML_QuickForm::arrayMerge($this->_constantValues, array($elname=>$value)); | |
1622 | $element =& $this->getElement($elname); | |
1623 | $element->onQuickFormEvent('updateValue', null, $this); | |
1624 | } | |
1625 | ||
ba21c9d4 | 1626 | /** |
1627 | * @param string $elementList | |
1628 | */ | |
294ce987 | 1629 | function exportValues($elementList = null){ |
0ffb4cc7 | 1630 | $unfiltered = array(); |
1631 | if (null === $elementList) { | |
1632 | // iterate over all elements, calling their exportValue() methods | |
98af2d1d | 1633 | $emptyarray = array(); |
0ffb4cc7 | 1634 | foreach (array_keys($this->_elements) as $key) { |
1635 | if ($this->_elements[$key]->isFrozen() && !$this->_elements[$key]->_persistantFreeze){ | |
98af2d1d | 1636 | $value = $this->_elements[$key]->exportValue($emptyarray, true); |
0ffb4cc7 | 1637 | } else { |
1638 | $value = $this->_elements[$key]->exportValue($this->_submitValues, true); | |
1639 | } | |
1640 | ||
1641 | if (is_array($value)) { | |
1642 | // This shit throws a bogus warning in PHP 4.3.x | |
1643 | $unfiltered = HTML_QuickForm::arrayMerge($unfiltered, $value); | |
1644 | } | |
1645 | } | |
1646 | } else { | |
1647 | if (!is_array($elementList)) { | |
1648 | $elementList = array_map('trim', explode(',', $elementList)); | |
1649 | } | |
1650 | foreach ($elementList as $elementName) { | |
1651 | $value = $this->exportValue($elementName); | |
1652 | if (PEAR::isError($value)) { | |
1653 | return $value; | |
1654 | } | |
4287fc0d | 1655 | //oh, stock QuickFOrm was returning array of arrays! |
1656 | $unfiltered = HTML_QuickForm::arrayMerge($unfiltered, $value); | |
0ffb4cc7 | 1657 | } |
1658 | } | |
7f40a229 | 1659 | |
f1f70bd4 DC |
1660 | if (is_array($this->_constantValues)) { |
1661 | $unfiltered = HTML_QuickForm::arrayMerge($unfiltered, $this->_constantValues); | |
1662 | } | |
1663 | ||
294ce987 | 1664 | return $unfiltered; |
da6f8763 | 1665 | } |
f07b9627 | 1666 | /** |
1667 | * Adds a validation rule for the given field | |
1668 | * | |
1669 | * If the element is in fact a group, it will be considered as a whole. | |
1670 | * To validate grouped elements as separated entities, | |
1671 | * use addGroupRule instead of addRule. | |
1672 | * | |
1673 | * @param string $element Form element name | |
1674 | * @param string $message Message to display for invalid data | |
1675 | * @param string $type Rule type, use getRegisteredRules() to get types | |
1676 | * @param string $format (optional)Required for extra rule data | |
1677 | * @param string $validation (optional)Where to perform validation: "server", "client" | |
1678 | * @param boolean $reset Client-side validation: reset the form element to its original value if there is an error? | |
1679 | * @param boolean $force Force the rule to be applied, even if the target form element does not exist | |
f07b9627 | 1680 | * @access public |
f07b9627 | 1681 | */ |
1682 | function addRule($element, $message, $type, $format=null, $validation='server', $reset = false, $force = false) | |
1683 | { | |
1684 | parent::addRule($element, $message, $type, $format, $validation, $reset, $force); | |
1685 | if ($validation == 'client') { | |
1686 | $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_formName . '; } catch(e) { return true; } return myValidator(this);')); | |
1687 | } | |
1688 | ||
1689 | } // end func addRule | |
1690 | /** | |
1691 | * Adds a validation rule for the given group of elements | |
1692 | * | |
1693 | * Only groups with a name can be assigned a validation rule | |
1694 | * Use addGroupRule when you need to validate elements inside the group. | |
1695 | * Use addRule if you need to validate the group as a whole. In this case, | |
1696 | * the same rule will be applied to all elements in the group. | |
1697 | * Use addRule if you need to validate the group against a function. | |
1698 | * | |
1699 | * @param string $group Form group name | |
1700 | * @param mixed $arg1 Array for multiple elements or error message string for one element | |
1701 | * @param string $type (optional)Rule type use getRegisteredRules() to get types | |
1702 | * @param string $format (optional)Required for extra rule data | |
1703 | * @param int $howmany (optional)How many valid elements should be in the group | |
1704 | * @param string $validation (optional)Where to perform validation: "server", "client" | |
1705 | * @param bool $reset Client-side: whether to reset the element's value to its original state if validation failed. | |
f07b9627 | 1706 | * @access public |
f07b9627 | 1707 | */ |
1708 | function addGroupRule($group, $arg1, $type='', $format=null, $howmany=0, $validation = 'server', $reset = false) | |
1709 | { | |
1710 | parent::addGroupRule($group, $arg1, $type, $format, $howmany, $validation, $reset); | |
1711 | if (is_array($arg1)) { | |
3a298174 | 1712 | foreach ($arg1 as $rules) { |
f07b9627 | 1713 | foreach ($rules as $rule) { |
1714 | $validation = (isset($rule[3]) && 'client' == $rule[3])? 'client': 'server'; | |
1715 | ||
1716 | if ('client' == $validation) { | |
1717 | $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_formName . '; } catch(e) { return true; } return myValidator(this);')); | |
1718 | } | |
1719 | } | |
1720 | } | |
1721 | } elseif (is_string($arg1)) { | |
1722 | ||
1723 | if ($validation == 'client') { | |
3a298174 | 1724 | $this->updateAttributes(array('onsubmit' => 'try { var myValidator = validate_' . $this->_formName . '; } catch(e) { return true; } return myValidator(this);')); |
f07b9627 | 1725 | } |
1726 | } | |
1727 | } // end func addGroupRule | |
1728 | ||
1729 | // }}} | |
5bc97c98 | 1730 | /** |
1731 | * Returns the client side validation script | |
1732 | * | |
1733 | * The code here was copied from HTML_QuickForm_DHTMLRulesTableless who copied it from HTML_QuickForm | |
1734 | * and slightly modified to run rules per-element | |
1735 | * Needed to override this because of an error with client side validation of grouped elements. | |
1736 | * | |
1737 | * @access public | |
1738 | * @return string Javascript to perform validation, empty string if no 'client' rules were added | |
1739 | */ | |
1740 | function getValidationScript() | |
1741 | { | |
1742 | if (empty($this->_rules) || empty($this->_attributes['onsubmit'])) { | |
1743 | return ''; | |
1744 | } | |
1745 | ||
1746 | include_once('HTML/QuickForm/RuleRegistry.php'); | |
1747 | $registry =& HTML_QuickForm_RuleRegistry::singleton(); | |
1748 | $test = array(); | |
1749 | $js_escape = array( | |
1750 | "\r" => '\r', | |
1751 | "\n" => '\n', | |
1752 | "\t" => '\t', | |
1753 | "'" => "\\'", | |
1754 | '"' => '\"', | |
1755 | '\\' => '\\\\' | |
1756 | ); | |
1757 | ||
1758 | foreach ($this->_rules as $elementName => $rules) { | |
1759 | foreach ($rules as $rule) { | |
1760 | if ('client' == $rule['validation']) { | |
da1320da | 1761 | unset($element); //TODO: find out how to properly initialize it |
5bc97c98 | 1762 | |
1763 | $dependent = isset($rule['dependent']) && is_array($rule['dependent']); | |
1764 | $rule['message'] = strtr($rule['message'], $js_escape); | |
1765 | ||
1766 | if (isset($rule['group'])) { | |
1767 | $group =& $this->getElement($rule['group']); | |
1768 | // No JavaScript validation for frozen elements | |
1769 | if ($group->isFrozen()) { | |
1770 | continue 2; | |
1771 | } | |
1772 | $elements =& $group->getElements(); | |
1773 | foreach (array_keys($elements) as $key) { | |
1774 | if ($elementName == $group->getElementName($key)) { | |
1775 | $element =& $elements[$key]; | |
1776 | break; | |
1777 | } | |
1778 | } | |
1779 | } elseif ($dependent) { | |
1780 | $element = array(); | |
1781 | $element[] =& $this->getElement($elementName); | |
3a298174 | 1782 | foreach ($rule['dependent'] as $elName) { |
5bc97c98 | 1783 | $element[] =& $this->getElement($elName); |
1784 | } | |
1785 | } else { | |
1786 | $element =& $this->getElement($elementName); | |
1787 | } | |
1788 | // No JavaScript validation for frozen elements | |
1789 | if (is_object($element) && $element->isFrozen()) { | |
1790 | continue 2; | |
1791 | } elseif (is_array($element)) { | |
1792 | foreach (array_keys($element) as $key) { | |
1793 | if ($element[$key]->isFrozen()) { | |
1794 | continue 3; | |
1795 | } | |
1796 | } | |
1797 | } | |
ab978b38 RT |
1798 | //for editor element, [text] is appended to the name. |
1799 | if ($element->getType() == 'editor') { | |
56728202 | 1800 | $elementName .= '[text]'; |
ab978b38 RT |
1801 | //Add format to rule as moodleform check which format is supported by browser |
1802 | //it is not set anywhere... So small hack to make sure we pass it down to quickform | |
1803 | if (is_null($rule['format'])) { | |
1804 | $rule['format'] = $element->getFormat(); | |
1805 | } | |
56728202 | 1806 | } |
ab978b38 | 1807 | // Fix for bug displaying errors for elements in a group |
5bc97c98 | 1808 | $test[$elementName][0][] = $registry->getValidationScript($element, $elementName, $rule); |
1809 | $test[$elementName][1]=$element; | |
1810 | //end of fix | |
1811 | } | |
1812 | } | |
1813 | } | |
7c77033f | 1814 | |
1815 | // Fix for MDL-9524. If you don't do this, then $element may be left as a reference to one of the fields in | |
1816 | // the form, and then that form field gets corrupted by the code that follows. | |
1817 | unset($element); | |
1818 | ||
5bc97c98 | 1819 | $js = ' |
1820 | <script type="text/javascript"> | |
1821 | //<![CDATA[ | |
1cbb09f1 | 1822 | |
1823 | var skipClientValidation = false; | |
1824 | ||
5bc97c98 | 1825 | function qf_errorHandler(element, _qfMsg) { |
1826 | div = element.parentNode; | |
b29c9b05 RT |
1827 | |
1828 | if ((div == undefined) || (element.name == undefined)) { | |
1829 | //no checking can be done for undefined elements so let server handle it. | |
1830 | return true; | |
1831 | } | |
1832 | ||
5bc97c98 | 1833 | if (_qfMsg != \'\') { |
e35c9eeb | 1834 | var errorSpan = document.getElementById(\'id_error_\'+element.name); |
e7004d05 | 1835 | if (!errorSpan) { |
1836 | errorSpan = document.createElement("span"); | |
e35c9eeb | 1837 | errorSpan.id = \'id_error_\'+element.name; |
1838 | errorSpan.className = "error"; | |
fed13a5e | 1839 | element.parentNode.insertBefore(errorSpan, element.parentNode.firstChild); |
5bc97c98 | 1840 | } |
fed13a5e | 1841 | |
e7004d05 | 1842 | while (errorSpan.firstChild) { |
1843 | errorSpan.removeChild(errorSpan.firstChild); | |
5bc97c98 | 1844 | } |
2c412890 | 1845 | |
e7004d05 | 1846 | errorSpan.appendChild(document.createTextNode(_qfMsg.substring(3))); |
e35c9eeb | 1847 | errorSpan.appendChild(document.createElement("br")); |
5bc97c98 | 1848 | |
1849 | if (div.className.substr(div.className.length - 6, 6) != " error" | |
1850 | && div.className != "error") { | |
1851 | div.className += " error"; | |
1852 | } | |
1853 | ||
1854 | return false; | |
1855 | } else { | |
e35c9eeb | 1856 | var errorSpan = document.getElementById(\'id_error_\'+element.name); |
e7004d05 | 1857 | if (errorSpan) { |
1858 | errorSpan.parentNode.removeChild(errorSpan); | |
5bc97c98 | 1859 | } |
1860 | ||
1861 | if (div.className.substr(div.className.length - 6, 6) == " error") { | |
1862 | div.className = div.className.substr(0, div.className.length - 6); | |
1863 | } else if (div.className == "error") { | |
1864 | div.className = ""; | |
1865 | } | |
1866 | ||
1867 | return true; | |
1868 | } | |
1869 | }'; | |
1870 | $validateJS = ''; | |
1871 | foreach ($test as $elementName => $jsandelement) { | |
1872 | // Fix for bug displaying errors for elements in a group | |
1873 | //unset($element); | |
1874 | list($jsArr,$element)=$jsandelement; | |
1875 | //end of fix | |
8af229fe DM |
1876 | $escapedElementName = preg_replace_callback( |
1877 | '/[_\[\]]/', | |
1878 | create_function('$matches', 'return sprintf("_%2x",ord($matches[0]));'), | |
1879 | $elementName); | |
5bc97c98 | 1880 | $js .= ' |
8af229fe | 1881 | function validate_' . $this->_formName . '_' . $escapedElementName . '(element) { |
b29c9b05 RT |
1882 | if (undefined == element) { |
1883 | //required element was not found, then let form be submitted without client side validation | |
1884 | return true; | |
1885 | } | |
5bc97c98 | 1886 | var value = \'\'; |
1887 | var errFlag = new Array(); | |
1888 | var _qfGroups = {}; | |
1889 | var _qfMsg = \'\'; | |
1890 | var frm = element.parentNode; | |
b29c9b05 RT |
1891 | if ((undefined != element.name) && (frm != undefined)) { |
1892 | while (frm && frm.nodeName.toUpperCase() != "FORM") { | |
1893 | frm = frm.parentNode; | |
1894 | } | |
1895 | ' . join("\n", $jsArr) . ' | |
1896 | return qf_errorHandler(element, _qfMsg); | |
1897 | } else { | |
1898 | //element name should be defined else error msg will not be displayed. | |
1899 | return true; | |
5bc97c98 | 1900 | } |
5bc97c98 | 1901 | } |
1902 | '; | |
1903 | $validateJS .= ' | |
8af229fe | 1904 | ret = validate_' . $this->_formName . '_' . $escapedElementName.'(frm.elements[\''.$elementName.'\']) && ret; |
2ef7c374 | 1905 | if (!ret && !first_focus) { |
1906 | first_focus = true; | |
1907 | frm.elements[\''.$elementName.'\'].focus(); | |
1908 | } | |
1909 | '; | |
4f51f48f | 1910 | |
5bc97c98 | 1911 | // Fix for bug displaying errors for elements in a group |
1912 | //unset($element); | |
1913 | //$element =& $this->getElement($elementName); | |
1914 | //end of fix | |
8af229fe | 1915 | $valFunc = 'validate_' . $this->_formName . '_' . $escapedElementName . '(this)'; |
5bc97c98 | 1916 | $onBlur = $element->getAttribute('onBlur'); |
1917 | $onChange = $element->getAttribute('onChange'); | |
1918 | $element->updateAttributes(array('onBlur' => $onBlur . $valFunc, | |
1919 | 'onChange' => $onChange . $valFunc)); | |
1920 | } | |
e7004d05 | 1921 | // do not rely on frm function parameter, because htmlarea breaks it when overloading the onsubmit method |
5bc97c98 | 1922 | $js .= ' |
f07b9627 | 1923 | function validate_' . $this->_formName . '(frm) { |
1cbb09f1 | 1924 | if (skipClientValidation) { |
1925 | return true; | |
1926 | } | |
5bc97c98 | 1927 | var ret = true; |
4f51f48f | 1928 | |
0befbdfd | 1929 | var frm = document.getElementById(\''. $this->_attributes['id'] .'\') |
2ef7c374 | 1930 | var first_focus = false; |
5bc97c98 | 1931 | ' . $validateJS . '; |
1932 | return ret; | |
1933 | } | |
1934 | //]]> | |
1935 | </script>'; | |
1936 | return $js; | |
1937 | } // end func getValidationScript | |
1938 | function _setDefaultRuleMessages(){ | |
1939 | foreach ($this->_rules as $field => $rulesarr){ | |
1940 | foreach ($rulesarr as $key => $rule){ | |
1941 | if ($rule['message']===null){ | |
365a5941 | 1942 | $a=new stdClass(); |
5bc97c98 | 1943 | $a->format=$rule['format']; |
1944 | $str=get_string('err_'.$rule['type'], 'form', $a); | |
1945 | if (strpos($str, '[[')!==0){ | |
1946 | $this->_rules[$field][$key]['message']=$str; | |
2c412890 | 1947 | } |
5bc97c98 | 1948 | } |
1949 | } | |
1950 | } | |
1951 | } | |
bb40325e | 1952 | |
c7e3e61c SH |
1953 | function getLockOptionObject(){ |
1954 | $result = array(); | |
dd07bbac | 1955 | foreach ($this->_dependencies as $dependentOn => $conditions){ |
c7e3e61c | 1956 | $result[$dependentOn] = array(); |
dd07bbac | 1957 | foreach ($conditions as $condition=>$values) { |
c7e3e61c | 1958 | $result[$dependentOn][$condition] = array(); |
dd07bbac | 1959 | foreach ($values as $value=>$dependents) { |
c7e3e61c | 1960 | $result[$dependentOn][$condition][$value] = array(); |
dd07bbac | 1961 | $i = 0; |
1962 | foreach ($dependents as $dependent) { | |
1963 | $elements = $this->_getElNamesRecursive($dependent); | |
46f3921e | 1964 | if (empty($elements)) { |
1965 | // probably element inside of some group | |
1966 | $elements = array($dependent); | |
1967 | } | |
dd07bbac | 1968 | foreach($elements as $element) { |
1969 | if ($element == $dependentOn) { | |
1970 | continue; | |
1971 | } | |
c7e3e61c | 1972 | $result[$dependentOn][$condition][$value][] = $element; |
dd07bbac | 1973 | } |
11f260f4 | 1974 | } |
1975 | } | |
50ef8eb9 | 1976 | } |
dd07bbac | 1977 | } |
c7e3e61c | 1978 | return array($this->getAttribute('id'), $result); |
bb40325e | 1979 | } |
d01a38cb | 1980 | |
ba21c9d4 | 1981 | /** |
1982 | * @param mixed $element | |
1983 | * @return array | |
1984 | */ | |
46f3921e | 1985 | function _getElNamesRecursive($element) { |
1986 | if (is_string($element)) { | |
4f51f48f | 1987 | if (!$this->elementExists($element)) { |
1988 | return array(); | |
1989 | } | |
46f3921e | 1990 | $element = $this->getElement($element); |
d01a38cb | 1991 | } |
46f3921e | 1992 | |
1993 | if (is_a($element, 'HTML_QuickForm_group')) { | |
1994 | $elsInGroup = $element->getElements(); | |
9403060a | 1995 | $elNames = array(); |
d01a38cb | 1996 | foreach ($elsInGroup as $elInGroup){ |
e850ec48 | 1997 | if (is_a($elInGroup, 'HTML_QuickForm_group')) { |
1998 | // not sure if this would work - groups nested in groups | |
1999 | $elNames = array_merge($elNames, $this->_getElNamesRecursive($elInGroup)); | |
2000 | } else { | |
2001 | $elNames[] = $element->getElementName($elInGroup->getName()); | |
2002 | } | |
d01a38cb | 2003 | } |
46f3921e | 2004 | |
2005 | } else if (is_a($element, 'HTML_QuickForm_header')) { | |
2006 | return array(); | |
2007 | ||
2008 | } else if (is_a($element, 'HTML_QuickForm_hidden')) { | |
2009 | return array(); | |
2010 | ||
8f6384a9 TH |
2011 | } else if (method_exists($element, 'getPrivateName') && |
2012 | !($element instanceof HTML_QuickForm_advcheckbox)) { | |
2013 | // The advcheckbox element implements a method called getPrivateName, | |
2014 | // but in a way that is not compatible with the generic API, so we | |
2015 | // have to explicitly exclude it. | |
46f3921e | 2016 | return array($element->getPrivateName()); |
2017 | ||
2018 | } else { | |
2019 | $elNames = array($element->getName()); | |
d01a38cb | 2020 | } |
d01a38cb | 2021 | |
46f3921e | 2022 | return $elNames; |
50ef8eb9 | 2023 | } |
46f3921e | 2024 | |
6e372b25 | 2025 | /** |
2026 | * Adds a dependency for $elementName which will be disabled if $condition is met. | |
9403060a | 2027 | * If $condition = 'notchecked' (default) then the condition is that the $dependentOn element |
2028 | * is not checked. If $condition = 'checked' then the condition is that the $dependentOn element | |
31a6c06c | 2029 | * is checked. If $condition is something else (like "eq" for equals) then it is checked to see if the value |
2030 | * of the $dependentOn element is $condition (such as equal) to $value. | |
6e372b25 | 2031 | * |
2032 | * @param string $elementName the name of the element which will be disabled | |
2033 | * @param string $dependentOn the name of the element whose state will be checked for | |
2034 | * condition | |
2035 | * @param string $condition the condition to check | |
19110c57 | 2036 | * @param mixed $value used in conjunction with condition. |
6e372b25 | 2037 | */ |
dd07bbac | 2038 | function disabledIf($elementName, $dependentOn, $condition = 'notchecked', $value='1'){ |
2039 | if (!array_key_exists($dependentOn, $this->_dependencies)) { | |
2040 | $this->_dependencies[$dependentOn] = array(); | |
2041 | } | |
2042 | if (!array_key_exists($condition, $this->_dependencies[$dependentOn])) { | |
2043 | $this->_dependencies[$dependentOn][$condition] = array(); | |
2044 | } | |
2045 | if (!array_key_exists($value, $this->_dependencies[$dependentOn][$condition])) { | |
2046 | $this->_dependencies[$dependentOn][$condition][$value] = array(); | |
2047 | } | |
2048 | $this->_dependencies[$dependentOn][$condition][$value][] = $elementName; | |
bb40325e | 2049 | } |
dd07bbac | 2050 | |
a23f0aaf | 2051 | function registerNoSubmitButton($buttonname){ |
2052 | $this->_noSubmitButtons[]=$buttonname; | |
2053 | } | |
dd07bbac | 2054 | |
ba21c9d4 | 2055 | /** |
2056 | * @param string $buttonname | |
2057 | * @return mixed | |
2058 | */ | |
a23f0aaf | 2059 | function isNoSubmitButton($buttonname){ |
2060 | return (array_search($buttonname, $this->_noSubmitButtons)!==FALSE); | |
19110c57 | 2061 | } |
dd07bbac | 2062 | |
ba21c9d4 | 2063 | /** |
2064 | * @param string $buttonname | |
2065 | */ | |
19110c57 | 2066 | function _registerCancelButton($addfieldsname){ |
2067 | $this->_cancelButtons[]=$addfieldsname; | |
2068 | } | |
acc9c3e0 | 2069 | /** |
2070 | * Displays elements without HTML input tags. | |
2071 | * This method is different to freeze() in that it makes sure no hidden | |
cc444336 | 2072 | * elements are included in the form. |
2073 | * Note: If you want to make sure the submitted value is ignored, please use setDefaults(). | |
acc9c3e0 | 2074 | * |
4af06dda | 2075 | * This function also removes all previously defined rules. |
2076 | * | |
acc9c3e0 | 2077 | * @param mixed $elementList array or string of element(s) to be frozen |
acc9c3e0 | 2078 | * @access public |
acc9c3e0 | 2079 | */ |
2080 | function hardFreeze($elementList=null) | |
2081 | { | |
2082 | if (!isset($elementList)) { | |
2083 | $this->_freezeAll = true; | |
2084 | $elementList = array(); | |
2085 | } else { | |
2086 | if (!is_array($elementList)) { | |
2087 | $elementList = preg_split('/[ ]*,[ ]*/', $elementList); | |
2088 | } | |
2089 | $elementList = array_flip($elementList); | |
2090 | } | |
2091 | ||
2092 | foreach (array_keys($this->_elements) as $key) { | |
2093 | $name = $this->_elements[$key]->getName(); | |
2094 | if ($this->_freezeAll || isset($elementList[$name])) { | |
2095 | $this->_elements[$key]->freeze(); | |
2096 | $this->_elements[$key]->setPersistantFreeze(false); | |
2097 | unset($elementList[$name]); | |
4af06dda | 2098 | |
2099 | // remove all rules | |
2100 | $this->_rules[$name] = array(); | |
2101 | // if field is required, remove the rule | |
2102 | $unset = array_search($name, $this->_required); | |
2103 | if ($unset !== false) { | |
2104 | unset($this->_required[$unset]); | |
2105 | } | |
acc9c3e0 | 2106 | } |
2107 | } | |
2108 | ||
2109 | if (!empty($elementList)) { | |
2110 | return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Nonexistant element(s): '" . implode("', '", array_keys($elementList)) . "' in HTML_QuickForm::freeze()", 'HTML_QuickForm_Error', true); | |
2111 | } | |
2112 | return true; | |
4f51f48f | 2113 | } |
2114 | /** | |
2115 | * Hard freeze all elements in a form except those whose names are in $elementList or hidden elements in a form. | |
2116 | * | |
2117 | * This function also removes all previously defined rules of elements it freezes. | |
2118 | * | |
ba21c9d4 | 2119 | * throws HTML_QuickForm_Error |
2120 | * | |
4f51f48f | 2121 | * @param array $elementList array or string of element(s) not to be frozen |
4f51f48f | 2122 | * @access public |
4f51f48f | 2123 | */ |
2124 | function hardFreezeAllVisibleExcept($elementList) | |
2125 | { | |
2126 | $elementList = array_flip($elementList); | |
2127 | foreach (array_keys($this->_elements) as $key) { | |
2128 | $name = $this->_elements[$key]->getName(); | |
2129 | $type = $this->_elements[$key]->getType(); | |
56015454 | 2130 | |
4f51f48f | 2131 | if ($type == 'hidden'){ |
2132 | // leave hidden types as they are | |
2133 | } elseif (!isset($elementList[$name])) { | |
2134 | $this->_elements[$key]->freeze(); | |
2135 | $this->_elements[$key]->setPersistantFreeze(false); | |
2136 | ||
2137 | // remove all rules | |
2138 | $this->_rules[$name] = array(); | |
2139 | // if field is required, remove the rule | |
2140 | $unset = array_search($name, $this->_required); | |
2141 | if ($unset !== false) { | |
2142 | unset($this->_required[$unset]); | |
2143 | } | |
2144 | } | |
2145 | } | |
2146 | return true; | |
2147 | } | |
2148 | /** | |
2149 | * Tells whether the form was already submitted | |
2150 | * | |
2151 | * This is useful since the _submitFiles and _submitValues arrays | |
2152 | * may be completely empty after the trackSubmit value is removed. | |
2153 | * | |
2154 | * @access public | |
2155 | * @return bool | |
2156 | */ | |
2157 | function isSubmitted() | |
2158 | { | |
2159 | return parent::isSubmitted() && (!$this->isFrozen()); | |
2160 | } | |
da6f8763 | 2161 | } |
2162 | ||
e24b7f85 | 2163 | |
da6f8763 | 2164 | /** |
7f40a229 | 2165 | * A renderer for MoodleQuickForm that only uses XHTML and CSS and no |
da6f8763 | 2166 | * table tags, extends PEAR class HTML_QuickForm_Renderer_Tableless |
7f40a229 | 2167 | * |
da6f8763 | 2168 | * Stylesheet is part of standard theme and should be automatically included. |
2169 | * | |
ba21c9d4 | 2170 | * @package moodlecore |
2171 | * @copyright Jamie Pratt <me@jamiep.org> | |
2172 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
da6f8763 | 2173 | */ |
7f40a229 | 2174 | class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{ |
da6f8763 | 2175 | |
2176 | /** | |
2177 | * Element template array | |
2178 | * @var array | |
2179 | * @access private | |
2180 | */ | |
2181 | var $_elementTemplates; | |
49c53687 | 2182 | /** |
2183 | * Template used when opening a hidden fieldset | |
2184 | * (i.e. a fieldset that is opened when there is no header element) | |
2185 | * @var string | |
2186 | * @access private | |
2187 | */ | |
c02345e3 | 2188 | var $_openHiddenFieldsetTemplate = "\n\t<fieldset class=\"hidden\"><div>"; |
19194f82 | 2189 | /** |
2190 | * Header Template string | |
2191 | * @var string | |
2192 | * @access private | |
2193 | */ | |
2194 | var $_headerTemplate = | |
c02345e3 | 2195 | "\n\t\t<legend class=\"ftoggler\">{header}</legend>\n\t\t<div class=\"advancedbutton\">{advancedimg}{button}</div><div class=\"fcontainer clearfix\">\n\t\t"; |
7f40a229 | 2196 | |
49c53687 | 2197 | /** |
bc9ec4a6 | 2198 | * Template used when opening a fieldset |
2199 | * @var string | |
2200 | * @access private | |
2201 | */ | |
2202 | var $_openFieldsetTemplate = "\n\t<fieldset class=\"clearfix\" {id}>"; | |
2203 | ||
2204 | /** | |
49c53687 | 2205 | * Template used when closing a fieldset |
2206 | * @var string | |
2207 | * @access private | |
2208 | */ | |
c02345e3 | 2209 | var $_closeFieldsetTemplate = "\n\t\t</div></fieldset>"; |
42f248e6 | 2210 | |
49c53687 | 2211 | /** |
2212 | * Required Note template string | |
2213 | * @var string | |
2214 | * @access private | |
2215 | */ | |
7f40a229 | 2216 | var $_requiredNoteTemplate = |
6ba2c73d | 2217 | "\n\t\t<div class=\"fdescription required\">{requiredNote}</div>"; |
7f40a229 | 2218 | |
19194f82 | 2219 | var $_advancedElements = array(); |
2220 | ||
2221 | /** | |
2222 | * Whether to display advanced elements (on page load) | |
2223 | * | |
2224 | * @var integer 1 means show 0 means hide | |
2225 | */ | |
2226 | var $_showAdvanced; | |
2227 | ||
7f40a229 | 2228 | function MoodleQuickForm_Renderer(){ |
42f248e6 | 2229 | // switch next two lines for ol li containers for form items. |
49c7f3a8 | 2230 | // $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>'); |
9aa022fe | 2231 | $this->_elementTemplates = array( |
0f3f6fed | 2232 | 'default'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></div>', |
49c7f3a8 | 2233 | |
0f3f6fed | 2234 | 'fieldset'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</fieldset></div>', |
4f51f48f | 2235 | |
f9f9be73 | 2236 | 'static'=>"\n\t\t".'<div class="fitem {advanced}"><div class="fitemtitle"><div class="fstaticlabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</label></div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element} </div></div>', |
43914931 | 2237 | |
1ae1941e | 2238 | 'warning'=>"\n\t\t".'<div class="fitem {advanced}">{element}</div>', |
2239 | ||
4f51f48f | 2240 | 'nodisplay'=>''); |
da6f8763 | 2241 | |
2242 | parent::HTML_QuickForm_Renderer_Tableless(); | |
2243 | } | |
7f40a229 | 2244 | |
ba21c9d4 | 2245 | /** |
2246 | * @param array $elements | |
2247 | */ | |
19194f82 | 2248 | function setAdvancedElements($elements){ |
2249 | $this->_advancedElements = $elements; | |
2250 | } | |
2251 | ||
2252 | /** | |
2253 | * What to do when starting the form | |
2254 | * | |
ba21c9d4 | 2255 | * @param object $form MoodleQuickForm |
19194f82 | 2256 | */ |
da6f8763 | 2257 | function startForm(&$form){ |
9403060a | 2258 | $this->_reqHTML = $form->getReqHTML(); |
2259 | $this->_elementTemplates = str_replace('{req}', $this->_reqHTML, $this->_elementTemplates); | |
19194f82 | 2260 | $this->_advancedHTML = $form->getAdvancedHTML(); |
2261 | $this->_showAdvanced = $form->getShowAdvanced(); | |
da6f8763 | 2262 | parent::startForm($form); |
4f51f48f | 2263 | if ($form->isFrozen()){ |
2264 | $this->_formTemplate = "\n<div class=\"mform frozen\">\n{content}\n</div>"; | |
2265 | } else { | |
0524b1d9 | 2266 | $this->_formTemplate = "\n<form{attributes}>\n\t<div style=\"display: none;\">{hidden}</div>\n{content}\n</form>"; |
4f51f48f | 2267 | $this->_hiddenHtml .= $form->_pageparams; |
2268 | } | |
2269 | ||
2270 | ||
da6f8763 | 2271 | } |
117bd748 | 2272 | |
ba21c9d4 | 2273 | /** |
2274 | * @param object $group Passed by reference | |
2275 | * @param mixed $required | |
2276 | * @param mixed $error | |
2277 | */ | |
da6f8763 | 2278 | function startGroup(&$group, $required, $error){ |
0f3f6fed AF |
2279 | // Make sure the element has an id. |
2280 | $group->_generateId(); | |
2281 | ||
da6f8763 | 2282 | if (method_exists($group, 'getElementTemplateType')){ |
e249661f | 2283 | $html = $this->_elementTemplates[$group->getElementTemplateType()]; |
da6f8763 | 2284 | }else{ |
2285 | $html = $this->_elementTemplates['default']; | |
7f40a229 | 2286 | |
da6f8763 | 2287 | } |
19194f82 | 2288 | if ($this->_showAdvanced){ |
2289 | $advclass = ' advanced'; | |
2290 | } else { | |
2291 | $advclass = ' advanced hide'; | |
2292 | } | |
2293 | if (isset($this->_advancedElements[$group->getName()])){ | |
2294 | $html =str_replace(' {advanced}', $advclass, $html); | |
2295 | $html =str_replace('{advancedimg}', $this->_advancedHTML, $html); | |
2296 | } else { | |
2297 | $html =str_replace(' {advanced}', '', $html); | |
2298 | $html =str_replace('{advancedimg}', '', $html); | |
2299 | } | |
da6f8763 | 2300 | if (method_exists($group, 'getHelpButton')){ |
2301 | $html =str_replace('{help}', $group->getHelpButton(), $html); | |
2302 | }else{ | |
2303 | $html =str_replace('{help}', '', $html); | |
da6f8763 | 2304 | } |
0f3f6fed | 2305 | $html =str_replace('{id}', 'fgroup_' . $group->getAttribute('id'), $html); |
e7004d05 | 2306 | $html =str_replace('{name}', $group->getName(), $html); |
49c53687 | 2307 | $html =str_replace('{type}', 'fgroup', $html); |
7f40a229 | 2308 | |
da6f8763 | 2309 | $this->_templates[$group->getName()]=$html; |
2310 | // Fix for bug in tableless quickforms that didn't allow you to stop a | |
2311 | // fieldset before a group of elements. | |
2312 | // if the element name indicates the end of a fieldset, close the fieldset | |
2313 | if ( in_array($group->getName(), $this->_stopFieldsetElements) | |
2314 | && $this->_fieldsetsOpen > 0 | |
2315 | ) { | |
2316 | $this->_html .= $this->_closeFieldsetTemplate; | |
2317 | $this->_fieldsetsOpen--; | |
2318 | } | |
2319 | parent::startGroup($group, $required, $error); | |
2320 | } | |
ba21c9d4 | 2321 | /** |
2322 | * @param object $element | |
2323 | * @param mixed $required | |
2324 | * @param mixed $error | |
2325 | */ | |
da6f8763 | 2326 | function renderElement(&$element, $required, $error){ |
820b41e3 TH |
2327 | // Make sure the element has an id. |
2328 | $element->_generateId(); | |
86aab05c | 2329 | |
2330 | //adding stuff to place holders in template | |
172dd12c | 2331 | //check if this is a group element first |
906ebc4b | 2332 | if (($this->_inGroup) and !empty($this->_groupElementTemplate)) { |
3493eb15 | 2333 | // so it gets substitutions for *each* element |
c07b5ad4 | 2334 | $html = $this->_groupElementTemplate; |
906ebc4b | 2335 | } |
2336 | elseif (method_exists($element, 'getElementTemplateType')){ | |
da6f8763 | 2337 | $html = $this->_elementTemplates[$element->getElementTemplateType()]; |
2338 | }else{ | |
2339 | $html = $this->_elementTemplates['default']; | |
19194f82 | 2340 | } |
2341 | if ($this->_showAdvanced){ | |
2342 | $advclass = ' advanced'; | |
2343 | } else { | |
2344 | $advclass = ' advanced hide'; | |
2345 | } | |
2346 | if (isset($this->_advancedElements[$element->getName()])){ | |
2347 | $html =str_replace(' {advanced}', $advclass, $html); | |
2348 | } else { | |
2349 | $html =str_replace(' {advanced}', '', $html); | |
2350 | } | |
2351 | if (isset($this->_advancedElements[$element->getName()])||$element->getName() == 'mform_showadvanced'){ | |
2352 | $html =str_replace('{advancedimg}', $this->_advancedHTML, $html); | |
2353 | } else { | |
2354 | $html =str_replace('{advancedimg}', '', $html); | |
da6f8763 | 2355 | } |
0f3f6fed | 2356 | $html =str_replace('{id}', 'fitem_' . $element->getAttribute('id'), $html); |
49c53687 | 2357 | $html =str_replace('{type}', 'f'.$element->getType(), $html); |
e7004d05 | 2358 | $html =str_replace('{name}', $element->getName(), $html); |
da6f8763 | 2359 | if (method_exists($element, 'getHelpButton')){ |
9403060a | 2360 | $html = str_replace('{help}', $element->getHelpButton(), $html); |
da6f8763 | 2361 | }else{ |
9403060a | 2362 | $html = str_replace('{help}', '', $html); |
7f40a229 | 2363 | |
da6f8763 | 2364 | } |
906ebc4b | 2365 | if (($this->_inGroup) and !empty($this->_groupElementTemplate)) { |
2366 | $this->_groupElementTemplate = $html; | |
41b6d001 | 2367 | } |
906ebc4b | 2368 | elseif (!isset($this->_templates[$element->getName()])) { |
2369 | $this->_templates[$element->getName()] = $html; | |
172dd12c | 2370 | } |
2371 | ||
da6f8763 | 2372 | parent::renderElement($element, $required, $error); |
2373 | } | |
19194f82 | 2374 | |
ba21c9d4 | 2375 | /** |
c7e3e61c | 2376 | * @global moodle_page $PAGE |
ba21c9d4 | 2377 | * @param object $form Passed by reference |
2378 | */ | |
bb40325e | 2379 | function finishForm(&$form){ |
c7e3e61c | 2380 | global $PAGE; |
4f51f48f | 2381 | if ($form->isFrozen()){ |
2382 | $this->_hiddenHtml = ''; | |
2383 | } | |
bb40325e | 2384 | parent::finishForm($form); |
c7e3e61c SH |
2385 | if (!$form->isFrozen()) { |
2386 | $args = $form->getLockOptionObject(); | |
2387 | if (count($args[1]) > 0) { | |
63d5c4ac | 2388 | $PAGE->requires->js_init_call('M.form.initFormDependencies', $args, true, moodleform::get_js_module()); |
c7e3e61c | 2389 | } |
bb40325e | 2390 | } |
2391 | } | |
19194f82 | 2392 | /** |
2393 | * Called when visiting a header element | |
2394 | * | |
ba21c9d4 | 2395 | * @param object $header An HTML_QuickForm_header element being visited |
19194f82 | 2396 | * @access public |
2397 | * @return void | |
c7e3e61c | 2398 | * @global moodle_page $PAGE |
19194f82 | 2399 | */ |
c28bf5c9 | 2400 | function renderHeader(&$header) { |
2401 | global $PAGE; | |
9262d2d3 | 2402 | |
19194f82 | 2403 | $name = $header->getName(); |
2404 | ||
2405 | $id = empty($name) ? '' : ' id="' . $name . '"'; | |
78354cec | 2406 | $id = preg_replace(array('/\]/', '/\[/'), array('', '_'), $id); |
19194f82 | 2407 | if (is_null($header->_text)) { |
2408 | $header_html = ''; | |
2409 | } elseif (!empty($name) && isset($this->_templates[$name])) { | |
2410 | $header_html = str_replace('{header}', $header->toHtml(), $this->_templates[$name]); | |
2411 | } else { | |
2412 | $header_html = str_replace('{header}', $header->toHtml(), $this->_headerTemplate); | |
2413 | } | |
2414 | ||
2415 | if (isset($this->_advancedElements[$name])){ | |
2416 | $header_html =str_replace('{advancedimg}', $this->_advancedHTML, $header_html); | |
c7e3e61c SH |
2417 | $elementName='mform_showadvanced'; |
2418 | if ($this->_showAdvanced==0){ | |
2419 | $buttonlabel = get_string('showadvanced', 'form'); | |
2420 | } else { | |
2421 | $buttonlabel = get_string('hideadvanced', 'form'); | |
2422 | } | |
2423 | $button = '<input name="'.$elementName.'" class="showadvancedbtn" value="'.$buttonlabel.'" type="submit" />'; | |
2424 | $PAGE->requires->js_init_call('M.form.initShowAdvanced', array(), false, moodleform::get_js_module()); | |
2425 | $header_html = str_replace('{button}', $button, $header_html); | |
19194f82 | 2426 | } else { |
2427 | $header_html =str_replace('{advancedimg}', '', $header_html); | |
7c9b1d31 | 2428 | $header_html = str_replace('{button}', '', $header_html); |
19194f82 | 2429 | } |
2430 | ||
2431 | if ($this->_fieldsetsOpen > 0) { | |
2432 | $this->_html .= $this->_closeFieldsetTemplate; | |
2433 | $this->_fieldsetsOpen--; | |
2434 | } | |
2435 | ||
2436 | $openFieldsetTemplate = str_replace('{id}', $id, $this->_openFieldsetTemplate); | |
2437 | if ($this->_showAdvanced){ | |
2438 | $advclass = ' class="advanced"'; | |
2439 | } else { | |
2440 | $advclass = ' class="advanced hide"'; | |
2441 | } | |
2442 | if (isset($this->_advancedElements[$name])){ | |
2443 | $openFieldsetTemplate = str_replace('{advancedclass}', $advclass, $openFieldsetTemplate); | |
2444 | } else { | |
2445 | $openFieldsetTemplate = str_replace('{advancedclass}', '', $openFieldsetTemplate); | |
2446 | } | |
2447 | $this->_html .= $openFieldsetTemplate . $header_html; | |
2448 | $this->_fieldsetsOpen++; | |
2449 | } // end func renderHeader | |
2450 | ||
2451 | function getStopFieldsetElements(){ | |
2452 | return $this->_stopFieldsetElements; | |
2453 | } | |
da6f8763 | 2454 | } |
2455 | ||
7b5702b6 MG |
2456 | /** |
2457 | * Required elements validation | |
2458 | * This class overrides QuickForm validation since it allowed space or empty tag as a value | |
2459 | */ | |
2460 | class MoodleQuickForm_Rule_Required extends HTML_QuickForm_Rule { | |
2461 | /** | |
2462 | * Checks if an element is not empty. | |
2463 | * This is a server-side validation, it works for both text fields and editor fields | |
2464 | * | |
2465 | * @param string $value Value to check | |
2466 | * @param mixed $options Not used yet | |
2467 | * @return boolean true if value is not empty | |
2468 | */ | |
2469 | function validate($value, $options = null) { | |
2470 | global $CFG; | |
2471 | if (is_array($value) && array_key_exists('text', $value)) { | |
2472 | $value = $value['text']; | |
2473 | } | |
b85b25eb PS |
2474 | if (is_array($value)) { |
2475 | // nasty guess - there has to be something in the array, hopefully nobody invents arrays in arrays | |
2476 | $value = implode('', $value); | |
2477 | } | |
7b5702b6 MG |
2478 | $stripvalues = array( |
2479 | '#</?(?!img|canvas|hr).*?>#im', // all tags except img, canvas and hr | |
2480 | '#(\xc2|\xa0|\s| )#', //any whitespaces actually | |
2481 | ); | |
2482 | if (!empty($CFG->strictformsrequired)) { | |
2483 | $value = preg_replace($stripvalues, '', (string)$value); | |
2484 | } | |
2485 | if ((string)$value == '') { | |
2486 | return false; | |
2487 | } | |
2488 | return true; | |
2489 | } | |
2490 | ||
2491 | /** | |
2492 | * This function returns Javascript code used to build client-side validation. | |
2493 | * It checks if an element is not empty. | |
7b5702b6 | 2494 | * |
ab978b38 | 2495 | * @param int $format |
7b5702b6 MG |
2496 | * @return array |
2497 | */ | |
ab978b38 | 2498 | function getValidationScript($format = null) { |
7b5702b6 MG |
2499 | global $CFG; |
2500 | if (!empty($CFG->strictformsrequired)) { | |
ab978b38 RT |
2501 | if (!empty($format) && $format == FORMAT_HTML) { |
2502 | return array('', "{jsVar}.replace(/(<[^img|hr|canvas]+>)| |\s+/ig, '') == ''"); | |
2503 | } else { | |
2504 | return array('', "{jsVar}.replace(/^\s+$/g, '') == ''"); | |
2505 | } | |
7b5702b6 MG |
2506 | } else { |
2507 | return array('', "{jsVar} == ''"); | |
2508 | } | |
2509 | } | |
2510 | } | |
2511 | ||
ba21c9d4 | 2512 | /** |
2513 | * @global object $GLOBALS['_HTML_QuickForm_default_renderer'] | |
2514 | * @name $_HTML_QuickForm_default_renderer | |
2515 | */ | |
66491cf1 | 2516 | $GLOBALS['_HTML_QuickForm_default_renderer'] = new MoodleQuickForm_Renderer(); |
da6f8763 | 2517 | |
ba21c9d4 | 2518 | /** Please keep this list in alphabetical order. */ |
c583482c | 2519 | MoodleQuickForm::registerElementType('advcheckbox', "$CFG->libdir/form/advcheckbox.php", 'MoodleQuickForm_advcheckbox'); |
2520 | MoodleQuickForm::registerElementType('button', "$CFG->libdir/form/button.php", 'MoodleQuickForm_button'); | |
2521 | MoodleQuickForm::registerElementType('cancel', "$CFG->libdir/form/cancel.php", 'MoodleQuickForm_cancel'); | |
09179b78 | 2522 | MoodleQuickForm::registerElementType('searchableselector', "$CFG->libdir/form/searchableselector.php", 'MoodleQuickForm_searchableselector'); |
7f40a229 | 2523 | MoodleQuickForm::registerElementType('checkbox', "$CFG->libdir/form/checkbox.php", 'MoodleQuickForm_checkbox'); |
c583482c | 2524 | MoodleQuickForm::registerElementType('date_selector', "$CFG->libdir/form/dateselector.php", 'MoodleQuickForm_date_selector'); |
2525 | MoodleQuickForm::registerElementType('date_time_selector', "$CFG->libdir/form/datetimeselector.php", 'MoodleQuickForm_date_time_selector'); | |
32fa2272 | 2526 | MoodleQuickForm::registerElementType('duration', "$CFG->libdir/form/duration.php", 'MoodleQuickForm_duration'); |
c583482c | 2527 | MoodleQuickForm::registerElementType('editor', "$CFG->libdir/form/editor.php", 'MoodleQuickForm_editor'); |
7f40a229 | 2528 | MoodleQuickForm::registerElementType('file', "$CFG->libdir/form/file.php", 'MoodleQuickForm_file'); |
241431cd | 2529 | MoodleQuickForm::registerElementType('filemanager', "$CFG->libdir/form/filemanager.php", 'MoodleQuickForm_filemanager'); |
c5704ec6 | 2530 | MoodleQuickForm::registerElementType('filepicker', "$CFG->libdir/form/filepicker.php", 'MoodleQuickForm_filepicker'); |
c583482c | 2531 | MoodleQuickForm::registerElementType('format', "$CFG->libdir/form/format.php", 'MoodleQuickForm_format'); |
6798c63e | 2532 | MoodleQuickForm::registerElementType('grading', "$CFG->libdir/form/grading.php", 'MoodleQuickForm_grading'); |
7f40a229 | 2533 | MoodleQuickForm::registerElementType('group', "$CFG->libdir/form/group.php", 'MoodleQuickForm_group'); |
c583482c | 2534 | MoodleQuickForm::registerElementType('header', "$CFG->libdir/form/header.php", 'MoodleQuickForm_header'); |
2535 | MoodleQuickForm::registerElementType('hidden', "$CFG->libdir/form/hidden.php", 'MoodleQuickForm_hidden'); | |
2536 | MoodleQuickForm::registerElementType('htmleditor', "$CFG->libdir/form/htmleditor.php", 'MoodleQuickForm_htmleditor'); | |
2537 | MoodleQuickForm::registerElementType('modgrade', "$CFG->libdir/form/modgrade.php", 'MoodleQuickForm_modgrade'); | |
2538 | MoodleQuickForm::registerElementType('modvisible', "$CFG->libdir/form/modvisible.php", 'MoodleQuickForm_modvisible'); | |
7f40a229 | 2539 | MoodleQuickForm::registerElementType('password', "$CFG->libdir/form/password.php", 'MoodleQuickForm_password'); |
4f51f48f | 2540 | MoodleQuickForm::registerElementType('passwordunmask', "$CFG->libdir/form/passwordunmask.php", 'MoodleQuickForm_passwordunmask'); |
c583482c | 2541 | MoodleQuickForm::registerElementType('questioncategory', "$CFG->libdir/form/questioncategory.php", 'MoodleQuickForm_questioncategory'); |
7f40a229 | 2542 | MoodleQuickForm::registerElementType('radio', "$CFG->libdir/form/radio.php", 'MoodleQuickForm_radio'); |
c583482c | 2543 | MoodleQuickForm::registerElementType('recaptcha', "$CFG->libdir/form/recaptcha.php", 'MoodleQuickForm_recaptcha'); |
7f40a229 | 2544 | MoodleQuickForm::registerElementType('select', "$CFG->libdir/form/select.php", 'MoodleQuickForm_select'); |
4f51f48f | 2545 | MoodleQuickForm::registerElementType('selectgroups', "$CFG->libdir/form/selectgroups.php", 'MoodleQuickForm_selectgroups'); |
c583482c | 2546 | MoodleQuickForm::registerElementType('selectwithlink', "$CFG->libdir/form/selectwithlink.php", 'MoodleQuickForm_selectwithlink'); |
2547 | MoodleQuickForm::registerElementType('selectyesno', "$CFG->libdir/form/selectyesno.php", 'MoodleQuickForm_selectyesno'); | |
2548 | MoodleQuickForm::registerElementType('static', "$CFG->libdir/form/static.php", 'MoodleQuickForm_static'); | |
2549 | MoodleQuickForm::registerElementType('submit', "$CFG->libdir/form/submit.php", 'MoodleQuickForm_submit'); | |
6073a598 | 2550 | MoodleQuickForm::registerElementType('submitlink', "$CFG->libdir/form/submitlink.php", 'MoodleQuickForm_submitlink'); |
9f1c9dfc | 2551 | MoodleQuickForm::registerElementType('tags', "$CFG->libdir/form/tags.php", 'MoodleQuickForm_tags'); |
7f40a229 | 2552 | MoodleQuickForm::registerElementType('text', "$CFG->libdir/form/text.php", 'MoodleQuickForm_text'); |
2553 | MoodleQuickForm::registerElementType('textarea', "$CFG->libdir/form/textarea.php", 'MoodleQuickForm_textarea'); | |
1a03384f | 2554 | MoodleQuickForm::registerElementType('url', "$CFG->libdir/form/url.php", 'MoodleQuickForm_url'); |
1ae1941e | 2555 | MoodleQuickForm::registerElementType('warning', "$CFG->libdir/form/warning.php", 'MoodleQuickForm_warning'); |
7b5702b6 MG |
2556 | |
2557 | MoodleQuickForm::registerRule('required', null, 'MoodleQuickForm_Rule_Required', "$CFG->libdir/formslib.php"); |