da6f8763 |
1 | <?php |
2 | /** |
3 | * formslib.php - library of classes for creating forms in Moodle, based on PEAR QuickForms. |
4 | * THIS IS NOT YET PART OF THE MOODLE API, IT IS HERE FOR TESTING ONLY |
5 | * @author Jamie Pratt |
6 | * @version $Id$ |
7 | * @license http://www.gnu.org/copyleft/gpl.html GNU Public License |
8 | */ |
9 | |
10 | //point pear include path to moodles lib/pear so that includes and requires will search there for files before anywhere else. |
11 | if (FALSE===strstr(ini_get('include_path'), $CFG->libdir.'/pear' )){ |
12 | ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include_path')); |
13 | } |
14 | require_once 'HTML/QuickForm.php'; |
15 | require_once 'HTML/QuickForm/DHTMLRulesTableless.php'; |
16 | require_once 'HTML/QuickForm/Renderer/Tableless.php'; |
17 | |
49292f8c |
18 | require_once $CFG->libdir.'/uploadlib.php'; |
19 | |
864cc1de |
20 | if ($CFG->debug >= DEBUG_ALL){ |
21 | PEAR::setErrorHandling(PEAR_ERROR_PRINT); |
22 | } |
23 | |
05f5c40c |
24 | /** |
25 | * Moodle specific wrapper that separates quickforms syntax from moodle code. |
26 | */ |
7f40a229 |
27 | class moodleform { |
49292f8c |
28 | var $_formname; // form name |
29 | var $_form; // quickform object definition |
30 | var $_customdata; // globals workaround |
31 | var $_upload_manager; // file upload manager |
7f40a229 |
32 | |
33 | function moodleform($action, $customdata=null, $method='post', $target='', $attributes=null) { |
5bc97c98 |
34 | $this->_formname = rtrim(get_class($this), '_form'); |
7f40a229 |
35 | $this->_customdata = $customdata; |
5bc97c98 |
36 | $this->_form =& new MoodleQuickForm($this->_formname, $method, $action, $target, $attributes); |
7f40a229 |
37 | |
38 | $this->definition(); |
39 | |
40 | $this->_form->addElement('hidden', 'sesskey', null); // automatic sesskey protection |
41 | $this->_form->setDefault('sesskey', sesskey()); |
5bc97c98 |
42 | $this->_form->addElement('hidden', '_qf__'.$this->_formname, null); // form submission marker |
43 | $this->_form->setDefault('_qf__'.$this->_formname, 1); |
44 | $this->_form->_setDefaultRuleMessages(); |
7f40a229 |
45 | |
46 | // we have to know all input types before processing submission ;-) |
47 | $this->_process_submission($method); |
48 | |
05f5c40c |
49 | // update form definition based on final data |
50 | $this->definition_after_data(); |
7f40a229 |
51 | } |
05f5c40c |
52 | |
2c412890 |
53 | /** |
54 | * To autofocus on first form element with error. |
55 | * |
56 | * @return string javascript to select form element with first error or |
5c52df67 |
57 | * first element if no errors. |
2c412890 |
58 | */ |
59 | function focus(){ |
60 | $form=$this->_form; |
5c52df67 |
61 | $elkeys=array_keys($form->_elementIndex); |
2c412890 |
62 | if (isset($form->_errors) && 0!=count($form->_errors)){ |
63 | $errorkeys=array_keys($form->_errors); |
2c412890 |
64 | $keyinorder=array_intersect($elkeys, $errorkeys); |
65 | $el='getElementById(\'id_'.array_shift($keyinorder).'\')'; |
66 | return $el; |
67 | } else{ |
5c52df67 |
68 | $el='getElementById(\'id_'.array_shift($elkeys).'\')'; |
69 | return $el; |
2c412890 |
70 | } |
71 | } |
7f40a229 |
72 | |
05f5c40c |
73 | /** |
74 | * Internal method. Alters submitted data to be suitable for quickforms processing. |
75 | * Must be called when the form is fully set up. |
76 | */ |
7f40a229 |
77 | function _process_submission($method) { |
78 | $submission = array(); |
79 | if ($method == 'post') { |
80 | if (!empty($_POST)) { |
81 | $submission = $_POST; |
82 | } |
83 | } else { |
84 | $submission = array_merge_recursive($_GET, $_POST); // emulate handling of parameters in xxxx_param() |
85 | } |
86 | |
87 | // following trick is needed to enable proper sesskey checks when using GET forms |
5bc97c98 |
88 | // the _qf__.$this->_formname serves as a marker that form was actually submitted |
89 | if (array_key_exists('_qf__'.$this->_formname, $submission) and $submission['_qf__'.$this->_formname] == 1) { |
7f40a229 |
90 | if (!confirm_sesskey()) { |
91 | error('Incorrect sesskey submitted, form not accepted!'); |
92 | } |
05f5c40c |
93 | $files = $_FILES; |
7f40a229 |
94 | } else { |
95 | $submission = array(); |
05f5c40c |
96 | $files = array(); |
7f40a229 |
97 | } |
98 | |
05f5c40c |
99 | $this->_form->updateSubmission($submission, $files); |
7f40a229 |
100 | } |
101 | |
05f5c40c |
102 | /** |
103 | * Internal method. Validates all uploaded files. |
104 | */ |
49292f8c |
105 | function _validate_files() { |
106 | if (empty($_FILES)) { |
107 | // we do not need to do any checks because no files were submitted |
108 | // TODO: find out why server side required rule does not work for uploaded files; |
109 | // testing is easily done by always returning true from this function and adding |
110 | // $mform->addRule('soubor', get_string('required'), 'required', null, 'server'); |
111 | // and submitting form without selected file |
112 | return true; |
113 | } |
114 | $errors = array(); |
115 | $mform =& $this->_form; |
116 | |
117 | // create default upload manager if not already created |
118 | if (empty($this->_upload_manager)) { |
119 | $this->_upload_manager = new upload_manager(); |
120 | } |
121 | |
122 | // check the files |
123 | $status = $this->_upload_manager->preprocess_files(); |
124 | |
125 | // now check that we really want each file |
126 | foreach ($_FILES as $elname=>$file) { |
127 | if ($mform->elementExists($elname) and $mform->getElementType($elname)=='file') { |
128 | $required = $mform->isElementRequired($elname); |
129 | if (!empty($this->_upload_manager->files[$elname]['uploadlog']) and empty($this->_upload_manager->files[$elname]['clear'])) { |
130 | if (!$required and $file['error'] == UPLOAD_ERR_NO_FILE) { |
131 | // file not uploaded and not required - ignore it |
132 | continue; |
133 | } |
134 | $errors[$elname] = $this->_upload_manager->files[$elname]['uploadlog']; |
135 | } |
136 | } else { |
137 | error('Incorrect upload attemp!'); |
138 | } |
139 | } |
140 | |
141 | // return errors if found |
142 | if ($status and 0 == count($errors)){ |
143 | return true; |
144 | } else { |
145 | return $errors; |
146 | } |
147 | } |
148 | |
05f5c40c |
149 | /** |
150 | * Use existing data as form defaults. Usually new entry defaults are stored directly in |
151 | * form definition (new entry form); this function is used to apply defaults for entries that already exist |
152 | * in database (edit entry form). |
153 | * |
154 | * @param mixed $default_values object or array of default values |
155 | * @param bool $slased true if magic quotes applied to data values |
156 | */ |
7f40a229 |
157 | function set_defaults($default_values, $slashed=false) { |
158 | if (is_object($default_values)) { |
159 | $default_values = (array)$default_values; |
160 | } |
161 | $filter = $slashed ? 'stripslashes' : NULL; |
162 | $this->_form->setDefaults($default_values, $filter); |
38f394b2 |
163 | //update form definition when data changed |
05f5c40c |
164 | $this->definition_after_data(); |
7f40a229 |
165 | } |
166 | |
05f5c40c |
167 | /** |
168 | * Check that form was submitted. Does not check validity of submitted data. |
169 | * |
170 | * @return bool true if form properly submitted |
171 | */ |
7f40a229 |
172 | function is_submitted() { |
173 | return $this->_form->isSubmitted(); |
174 | } |
175 | |
05f5c40c |
176 | /** |
177 | * Check that form data is valid. |
178 | * |
179 | * @return bool true if form data valid |
180 | */ |
7f40a229 |
181 | function is_validated() { |
49292f8c |
182 | static $validated = null; // one validation is enough |
7f40a229 |
183 | |
184 | if ($validated === null) { |
185 | $internal_val = $this->_form->validate(); |
e7dcb0fc |
186 | $moodle_val = $this->validation($this->_form->exportValues(null, true)); |
7f40a229 |
187 | if ($moodle_val !== true) { |
188 | if (!empty($moodle_val)) { |
189 | foreach ($moodle_val as $element=>$msg) { |
190 | $this->_form->setElementError($element, $msg); |
191 | } |
192 | } |
193 | $moodle_val = false; |
194 | } |
49292f8c |
195 | $file_val = $this->_validate_files(); |
196 | if ($file_val !== true) { |
197 | if (!empty($file_val)) { |
198 | foreach ($file_val as $element=>$msg) { |
199 | $this->_form->setElementError($element, $msg); |
200 | } |
201 | } |
202 | $file_val = false; |
203 | } |
204 | $validated = ($internal_val and $moodle_val and $file_val); |
7f40a229 |
205 | } |
206 | return $validated; |
207 | } |
208 | |
05f5c40c |
209 | /** |
210 | * Return submitted data if properly submitted. |
211 | * |
212 | * @param bool $slashed true means return data with addslashes applied |
213 | * @return object submitted data; NULL if not valid or not submitted |
214 | */ |
7f40a229 |
215 | function data_submitted($slashed=true) { |
216 | if ($this->is_submitted() and $this->is_validated()) { |
217 | $data = $this->_form->exportValues(null, $slashed); |
5bc97c98 |
218 | unset($data['sesskey']); // we do not need to return sesskey |
219 | unset($data['_qf__'.$this->_formname]); // we do not need the submission marker too |
7f40a229 |
220 | if (empty($data)) { |
221 | return NULL; |
222 | } else { |
223 | return (object)$data; |
224 | } |
225 | } else { |
226 | return NULL; |
227 | } |
228 | } |
229 | |
05f5c40c |
230 | /** |
231 | * Save verified uploaded files into directory. Upload process can be customised from definition() |
38f394b2 |
232 | * method by creating instance of upload manager and storing it in $this->_upload_form |
05f5c40c |
233 | * |
234 | * @param string $destination where to store uploaded files |
235 | * @return bool success |
236 | */ |
49292f8c |
237 | function save_files($destination) { |
238 | if (empty($this->_upload_manager)) { |
239 | return false; |
240 | } |
241 | if ($this->is_submitted() and $this->is_validated()) { |
242 | return $this->_upload_manager->save_files($destination); |
243 | } |
244 | return false; |
245 | } |
2b63df96 |
246 | |
05f5c40c |
247 | /** |
248 | * Print html form. |
249 | */ |
7f40a229 |
250 | function display() { |
251 | $this->_form->display(); |
252 | } |
253 | |
49292f8c |
254 | /** |
05f5c40c |
255 | * Abstract method - always override! |
49292f8c |
256 | * |
257 | * If you need special handling of uploaded files, create instance of $this->_upload_manager here. |
258 | */ |
7f40a229 |
259 | function definition() { |
260 | error('Abstract form_definition() method in class '.get_class($this).' must be overriden, please fix the code.'); |
261 | } |
2c412890 |
262 | |
c08ac016 |
263 | /** |
05f5c40c |
264 | * Dummy stub method - override if you need to setup the form depending on current |
265 | * values. This method is called after definition(), data submission and set_defaults(). |
266 | * All form setup that is dependent on form values should go in here. |
c08ac016 |
267 | */ |
268 | function definition_after_data(){ |
c08ac016 |
269 | } |
7f40a229 |
270 | |
05f5c40c |
271 | /** |
272 | * Dummy stub method - override if you needed to perform some extra validation. |
273 | * If there are errors return array of errors ("fieldname"=>"error message"), |
274 | * otherwise true if ok. |
38f394b2 |
275 | * |
05f5c40c |
276 | * @param array $data array of ("fieldname"=>value) of submitted data |
38f394b2 |
277 | * @return bool array of errors or true if ok |
05f5c40c |
278 | */ |
7f40a229 |
279 | function validation($data) { |
7f40a229 |
280 | return true; |
281 | } |
7f40a229 |
282 | } |
e2294b98 |
283 | /** |
284 | * For extra methods for form wrapper specific to be used for module add / update forms. |
285 | * |
286 | */ |
287 | class moodleform_mod extends moodleform { |
288 | function standard_coursemodule_elements(){ |
289 | $mform=$this->_form; |
290 | $mform->addElement('header', '', get_string('modstandardels', 'form')); |
291 | $mform->addElement('modgroupmode', 'groupmode', get_string('groupmode')); |
292 | $mform->setHelpButton('groupmode', array('groupmode', get_string('groupmode'))); |
293 | $mform->setType('groupmode', PARAM_INT); |
294 | |
295 | $mform->addElement('modvisible', 'visible', get_string('visible')); |
296 | $mform->setType('visible', PARAM_INT); |
297 | |
298 | $mform->addElement('hidden', 'course', 0); |
299 | $mform->setType('course', PARAM_INT); |
300 | |
301 | $mform->addElement('hidden', 'coursemodule', 0); |
302 | $mform->setType('coursemodule', PARAM_INT); |
303 | |
304 | $mform->addElement('hidden', 'section', 0); |
305 | $mform->setType('section', PARAM_INT); |
306 | |
307 | $mform->addElement('hidden', 'module', 0); |
308 | $mform->setType('module', PARAM_INT); |
309 | |
310 | $mform->addElement('hidden', 'modulename', ''); |
311 | $mform->setType('modulename', PARAM_SAFEDIR); |
312 | |
313 | $mform->addElement('hidden', 'instance', 0); |
314 | $mform->setType('instance', PARAM_INT); |
315 | |
316 | $mform->addElement('hidden', 'add', 0); |
317 | $mform->setType('add', PARAM_ALPHA); |
318 | |
319 | $mform->addElement('hidden', 'update', 0); |
320 | $mform->setType('update', PARAM_INT); |
321 | } |
322 | |
323 | function standard_coursemodule_elements_setup($course, $cm, $section){ |
324 | $this->modgroupmode_setup($course, $cm); |
325 | $this->modvisible_setup($course, $cm, $section); |
326 | } |
327 | function modgroupmode_setup($course, $cm){ |
328 | $this->set_defaults(array('groupmode'=>groupmode($course, $cm))); |
329 | |
330 | } |
331 | function modvisible_setup($course, $cm, $section){ |
332 | if ($cm) { |
333 | $visible = $cm->visible; |
334 | } else { |
335 | $visible = 1; |
336 | } |
337 | |
338 | if (!$cm) { // adding activity |
339 | //in this case $form->section is the section number, not the id |
340 | $hiddensection = !get_field('course_sections', 'visible', 'section', $section, 'course', $course->id); |
341 | } else { //updating activity |
342 | $hiddensection = !get_field('course_sections', 'visible', 'id', $section); |
343 | } |
344 | if ($hiddensection) { |
345 | $visible = 0; |
346 | } |
347 | $this->set_defaults(array('visible'=>$visible)); |
348 | } |
349 | |
350 | } |
7f40a229 |
351 | |
352 | class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless { |
353 | var $_types = array(); |
354 | |
355 | |
da6f8763 |
356 | /** |
357 | * Class constructor - same parameters as HTML_QuickForm_DHTMLRulesTableless |
358 | * @param string $formName Form's name. |
359 | * @param string $method (optional)Form's method defaults to 'POST' |
360 | * @param string $action (optional)Form's action |
361 | * @param string $target (optional)Form's target defaults to none |
362 | * @param mixed $attributes (optional)Extra attributes for <form> tag |
363 | * @param bool $trackSubmit (optional)Whether to track if the form was submitted by adding a special hidden field |
364 | * @access public |
365 | */ |
7f40a229 |
366 | function MoodleQuickForm($formName, $method, $action, $target='', $attributes=null){ |
da6f8763 |
367 | global $CFG; |
7f40a229 |
368 | |
da6f8763 |
369 | HTML_Common::HTML_Common($attributes); |
da6f8763 |
370 | $target = empty($target) ? array() : array('target' => $target); |
371 | //no 'name' atttribute for form in xhtml strict : |
372 | $attributes = array('action'=>$action, 'method'=>$method, 'id'=>$formName) + $target; |
373 | $this->updateAttributes($attributes); |
da6f8763 |
374 | |
7f40a229 |
375 | //this is custom stuff for Moodle : |
da6f8763 |
376 | $oldclass= $this->getAttribute('class'); |
377 | if (!empty($oldclass)){ |
378 | $this->updateAttributes(array('class'=>$oldclass.' mform')); |
379 | }else { |
80f962df |
380 | $this->updateAttributes(array('class'=>'mform')); |
da6f8763 |
381 | } |
7f40a229 |
382 | $this->_helpImageURL="$CFG->wwwroot/lib/form/req.gif"; |
383 | $this->_reqHTML = |
da6f8763 |
384 | helpbutton('requiredelement', get_string('requiredelement', 'form'),'moodle', |
385 | true, false, '', true, '<img alt="'.get_string('requiredelement', 'form').'" src="'. |
386 | $this->_helpImageURL.'" />'); |
387 | $this->setRequiredNote(get_string('denotesreq', 'form', $this->getReqHTML())); |
388 | } |
bb40325e |
389 | |
7f40a229 |
390 | function setType($elementname, $paramtype) { |
391 | $this->_types[$elementname] = $paramtype; |
392 | } |
49292f8c |
393 | |
c56f1826 |
394 | function setTypes($paramtypes) { |
395 | $this->_types = $paramtypes + $this->_types; |
396 | } |
49292f8c |
397 | |
398 | function updateSubmission($submission, $files) { |
399 | $this->_flagSubmitted = false; |
400 | |
7f40a229 |
401 | if (empty($submission)) { |
402 | $this->_submitValues = array(); |
7f40a229 |
403 | } else { |
404 | foreach ($submission as $key=>$s) { |
405 | if (array_key_exists($key, $this->_types)) { |
406 | $submission[$key] = clean_param($s, $this->_types[$key]); |
407 | } |
408 | } |
409 | $this->_submitValues = $this->_recursiveFilter('stripslashes', $submission); |
410 | $this->_flagSubmitted = true; |
411 | } |
412 | |
49292f8c |
413 | if (empty($files)) { |
414 | $this->_submitFiles = array(); |
415 | } else { |
416 | if (1 == get_magic_quotes_gpc()) { |
417 | foreach ($files as $elname=>$file) { |
418 | // dangerous characters in filenames are cleaned later in upload_manager |
419 | $files[$elname]['name'] = stripslashes($files[$elname]['name']); |
420 | } |
421 | } |
422 | $this->_submitFiles = $files; |
423 | $this->_flagSubmitted = true; |
424 | } |
425 | |
2c412890 |
426 | // need to tell all elements that they need to update their value attribute. |
427 | foreach (array_keys($this->_elements) as $key) { |
428 | $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this); |
429 | } |
7f40a229 |
430 | } |
431 | |
da6f8763 |
432 | function getReqHTML(){ |
433 | return $this->_reqHTML; |
434 | } |
7f40a229 |
435 | |
436 | /** |
437 | * Initializes a default form value |
438 | * |
439 | * @param string $elementname element name |
440 | * @param mixed $values values for that element name |
441 | * @param bool $slashed the default value is slashed |
442 | * @access public |
443 | * @return void |
444 | */ |
445 | function setDefault($elementName, $defaultValue, $slashed=false){ |
446 | $filter = $slashed ? 'stripslashes' : NULL; |
447 | $this->setDefaults(array($elementName=>$defaultValue), $filter); |
448 | } // end func setDefault |
da6f8763 |
449 | /** |
c56f1826 |
450 | * Add an array of buttons to the form |
7f40a229 |
451 | * @param array $buttons An associative array representing help button to attach to |
da6f8763 |
452 | * to the form. keys of array correspond to names of elements in form. |
7f40a229 |
453 | * |
da6f8763 |
454 | * @access public |
455 | */ |
42f248e6 |
456 | function setHelpButtons($buttons, $suppresscheck=false){ |
7f40a229 |
457 | |
c56f1826 |
458 | foreach ($buttons as $elementname => $button){ |
459 | $this->setHelpButton($elementname, $button, $suppresscheck); |
da6f8763 |
460 | } |
461 | } |
c56f1826 |
462 | /** |
463 | * Add a single button |
464 | * |
465 | * @param string $elementname name of the element to add the item to |
466 | * @param array $button - arguments to pass to setHelpButton |
467 | * @param boolean $suppresscheck - whether to throw an error if the element |
468 | * doesn't exist. |
469 | */ |
470 | function setHelpButton($elementname, $button, $suppresscheck=false){ |
471 | if (array_key_exists($elementname, $this->_elementIndex)){ |
472 | //_elements has a numeric index, this code accesses the elements by name |
473 | $element=&$this->_elements[$this->_elementIndex[$elementname]]; |
474 | if (method_exists($element, 'setHelpButton')){ |
475 | $element->setHelpButton($button); |
476 | }else{ |
477 | $a=new object(); |
478 | $a->name=$element->getName(); |
479 | $a->classname=get_class($element); |
480 | print_error('nomethodforaddinghelpbutton', 'form', '', $a); |
481 | } |
482 | }elseif (!$suppresscheck){ |
483 | print_error('nonexistentformelements', 'form', '', $elementname); |
2c412890 |
484 | } |
c56f1826 |
485 | } |
7f40a229 |
486 | |
42f248e6 |
487 | function exportValues($elementList= null, $addslashes=true){ |
da6f8763 |
488 | $unfiltered=parent::exportValues($elementList); |
7f40a229 |
489 | |
da6f8763 |
490 | if ($addslashes){ |
42f248e6 |
491 | return $this->_recursiveFilter('addslashes',$unfiltered); |
da6f8763 |
492 | } else { |
493 | return $unfiltered; |
494 | } |
495 | } |
5bc97c98 |
496 | /** |
497 | * Returns the client side validation script |
498 | * |
499 | * The code here was copied from HTML_QuickForm_DHTMLRulesTableless who copied it from HTML_QuickForm |
500 | * and slightly modified to run rules per-element |
501 | * Needed to override this because of an error with client side validation of grouped elements. |
502 | * |
503 | * @access public |
504 | * @return string Javascript to perform validation, empty string if no 'client' rules were added |
505 | */ |
506 | function getValidationScript() |
507 | { |
508 | if (empty($this->_rules) || empty($this->_attributes['onsubmit'])) { |
509 | return ''; |
510 | } |
511 | |
512 | include_once('HTML/QuickForm/RuleRegistry.php'); |
513 | $registry =& HTML_QuickForm_RuleRegistry::singleton(); |
514 | $test = array(); |
515 | $js_escape = array( |
516 | "\r" => '\r', |
517 | "\n" => '\n', |
518 | "\t" => '\t', |
519 | "'" => "\\'", |
520 | '"' => '\"', |
521 | '\\' => '\\\\' |
522 | ); |
523 | |
524 | foreach ($this->_rules as $elementName => $rules) { |
525 | foreach ($rules as $rule) { |
526 | if ('client' == $rule['validation']) { |
711af2ec |
527 | unset($element); //TODO: find out how to properly initialize it |
5bc97c98 |
528 | |
529 | $dependent = isset($rule['dependent']) && is_array($rule['dependent']); |
530 | $rule['message'] = strtr($rule['message'], $js_escape); |
531 | |
532 | if (isset($rule['group'])) { |
533 | $group =& $this->getElement($rule['group']); |
534 | // No JavaScript validation for frozen elements |
535 | if ($group->isFrozen()) { |
536 | continue 2; |
537 | } |
538 | $elements =& $group->getElements(); |
539 | foreach (array_keys($elements) as $key) { |
540 | if ($elementName == $group->getElementName($key)) { |
541 | $element =& $elements[$key]; |
542 | break; |
543 | } |
544 | } |
545 | } elseif ($dependent) { |
546 | $element = array(); |
547 | $element[] =& $this->getElement($elementName); |
548 | foreach ($rule['dependent'] as $idx => $elName) { |
549 | $element[] =& $this->getElement($elName); |
550 | } |
551 | } else { |
552 | $element =& $this->getElement($elementName); |
553 | } |
554 | // No JavaScript validation for frozen elements |
555 | if (is_object($element) && $element->isFrozen()) { |
556 | continue 2; |
557 | } elseif (is_array($element)) { |
558 | foreach (array_keys($element) as $key) { |
559 | if ($element[$key]->isFrozen()) { |
560 | continue 3; |
561 | } |
562 | } |
563 | } |
564 | // Fix for bug displaying errors for elements in a group |
565 | //$test[$elementName][] = $registry->getValidationScript($element, $elementName, $rule); |
566 | $test[$elementName][0][] = $registry->getValidationScript($element, $elementName, $rule); |
567 | $test[$elementName][1]=$element; |
568 | //end of fix |
569 | } |
570 | } |
571 | } |
572 | $js = ' |
573 | <script type="text/javascript"> |
574 | //<![CDATA[ |
575 | function qf_errorHandler(element, _qfMsg) { |
576 | div = element.parentNode; |
577 | if (_qfMsg != \'\') { |
578 | span = document.createElement("span"); |
579 | span.className = "error"; |
580 | span.appendChild(document.createTextNode(_qfMsg.substring(3))); |
581 | br = document.createElement("br"); |
582 | |
583 | var errorDiv = document.getElementById(element.name + \'_errorDiv\'); |
584 | if (!errorDiv) { |
585 | errorDiv = document.createElement("div"); |
586 | errorDiv.id = element.name + \'_errorDiv\'; |
587 | } |
588 | while (errorDiv.firstChild) { |
589 | errorDiv.removeChild(errorDiv.firstChild); |
590 | } |
2c412890 |
591 | |
5bc97c98 |
592 | errorDiv.insertBefore(br, errorDiv.firstChild); |
593 | errorDiv.insertBefore(span, errorDiv.firstChild); |
594 | element.parentNode.insertBefore(errorDiv, element.parentNode.firstChild); |
595 | |
596 | if (div.className.substr(div.className.length - 6, 6) != " error" |
597 | && div.className != "error") { |
598 | div.className += " error"; |
599 | } |
600 | |
601 | return false; |
602 | } else { |
603 | var errorDiv = document.getElementById(element.name + \'_errorDiv\'); |
604 | if (errorDiv) { |
605 | errorDiv.parentNode.removeChild(errorDiv); |
606 | } |
607 | |
608 | if (div.className.substr(div.className.length - 6, 6) == " error") { |
609 | div.className = div.className.substr(0, div.className.length - 6); |
610 | } else if (div.className == "error") { |
611 | div.className = ""; |
612 | } |
613 | |
614 | return true; |
615 | } |
616 | }'; |
617 | $validateJS = ''; |
618 | foreach ($test as $elementName => $jsandelement) { |
619 | // Fix for bug displaying errors for elements in a group |
620 | //unset($element); |
621 | list($jsArr,$element)=$jsandelement; |
622 | //end of fix |
623 | $js .= ' |
624 | function validate_' . $this->_attributes['id'] . '_' . $elementName . '(element) { |
625 | var value = \'\'; |
626 | var errFlag = new Array(); |
627 | var _qfGroups = {}; |
628 | var _qfMsg = \'\'; |
629 | var frm = element.parentNode; |
630 | while (frm && frm.nodeName != "FORM") { |
631 | frm = frm.parentNode; |
632 | } |
633 | ' . join("\n", $jsArr) . ' |
634 | return qf_errorHandler(element, _qfMsg); |
635 | } |
636 | '; |
637 | $validateJS .= ' |
638 | ret = validate_' . $this->_attributes['id'] . '_' . $elementName.'(frm.elements[\''.$elementName.'\']) && ret;'; |
639 | // Fix for bug displaying errors for elements in a group |
640 | //unset($element); |
641 | //$element =& $this->getElement($elementName); |
642 | //end of fix |
643 | $valFunc = 'validate_' . $this->_attributes['id'] . '_' . $elementName . '(this)'; |
644 | $onBlur = $element->getAttribute('onBlur'); |
645 | $onChange = $element->getAttribute('onChange'); |
646 | $element->updateAttributes(array('onBlur' => $onBlur . $valFunc, |
647 | 'onChange' => $onChange . $valFunc)); |
648 | } |
649 | $js .= ' |
650 | function validate_' . $this->_attributes['id'] . '(frm) { |
651 | var ret = true; |
652 | ' . $validateJS . '; |
653 | return ret; |
654 | } |
655 | //]]> |
656 | </script>'; |
657 | return $js; |
658 | } // end func getValidationScript |
659 | function _setDefaultRuleMessages(){ |
660 | foreach ($this->_rules as $field => $rulesarr){ |
661 | foreach ($rulesarr as $key => $rule){ |
662 | if ($rule['message']===null){ |
663 | $a=new object(); |
664 | $a->format=$rule['format']; |
665 | $str=get_string('err_'.$rule['type'], 'form', $a); |
666 | if (strpos($str, '[[')!==0){ |
667 | $this->_rules[$field][$key]['message']=$str; |
2c412890 |
668 | } |
5bc97c98 |
669 | } |
670 | } |
671 | } |
672 | } |
bb40325e |
673 | function getLockOptionStartScript(){ |
674 | |
675 | return ''; |
676 | } |
677 | function getLockOptionEndScript(){ |
678 | |
679 | return ''; |
680 | } |
681 | |
da6f8763 |
682 | } |
683 | |
684 | /** |
7f40a229 |
685 | * A renderer for MoodleQuickForm that only uses XHTML and CSS and no |
da6f8763 |
686 | * table tags, extends PEAR class HTML_QuickForm_Renderer_Tableless |
7f40a229 |
687 | * |
da6f8763 |
688 | * Stylesheet is part of standard theme and should be automatically included. |
689 | * |
690 | * @author Jamie Pratt <me@jamiep.org> |
691 | * @license gpl license |
692 | */ |
7f40a229 |
693 | class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{ |
da6f8763 |
694 | |
695 | /** |
696 | * Element template array |
697 | * @var array |
698 | * @access private |
699 | */ |
700 | var $_elementTemplates; |
42f248e6 |
701 | |
49c53687 |
702 | // uncomment templates below and edit formslib.php for |
42f248e6 |
703 | // ol li containers for form items. |
704 | |
49c53687 |
705 | /** |
706 | * Template used when opening a hidden fieldset |
707 | * (i.e. a fieldset that is opened when there is no header element) |
708 | * @var string |
709 | * @access private |
710 | */ |
711 | var $_openHiddenFieldsetTemplate = "\n\t<fieldset class=\"hidden\">"; |
42f248e6 |
712 | // var $_openHiddenFieldsetTemplate = "\n\t<fieldset class=\"hidden\">\n\t\t<ol>"; |
713 | // /** |
714 | // * Header Template string |
715 | // * @var string |
716 | // * @access private |
717 | // */ |
7f40a229 |
718 | // var $_headerTemplate = |
42f248e6 |
719 | // "\n\t\t<legend>{header}</legend>\n\t\t<ol>"; |
7f40a229 |
720 | // var $_headerTemplate = |
49c53687 |
721 | // "\n\t\t<legend>{header}</legend>\n\t\t<ol>"; |
7f40a229 |
722 | |
49c53687 |
723 | /** |
724 | * Template used when closing a fieldset |
725 | * @var string |
726 | * @access private |
727 | */ |
728 | var $_closeFieldsetTemplate = "\n\t\t</fieldset>"; |
42f248e6 |
729 | // var $_closeFieldsetTemplate = "\n\t\t</ol>\n\t</fieldset>"; |
730 | |
49c53687 |
731 | /** |
732 | * Required Note template string |
733 | * @var string |
734 | * @access private |
735 | */ |
7f40a229 |
736 | var $_requiredNoteTemplate = |
49c53687 |
737 | "\n\t\t<div class=\"fdescription\">{requiredNote}</div>"; |
7f40a229 |
738 | |
739 | function MoodleQuickForm_Renderer(){ |
42f248e6 |
740 | // switch next two lines for ol li containers for form items. |
49c53687 |
741 | // $this->_elementTemplates=array('default'=>"\n\t\t<li class=\"fitem\"><label>{label}{help}<!-- BEGIN required -->{req}<!-- END required --></label><div class=\"qfelement<!-- BEGIN error --> error<!-- END error --> {type}\"><!-- BEGIN error --><span class=\"error\">{error}</span><br /><!-- END error -->{element}</div></li>"); |
15fdf619 |
742 | $this->_elementTemplates=array('default'=>"\n\t\t<div class=\"fitem\"><label>{label}{help}<!-- BEGIN required -->{req}<!-- END required --></label><div class=\"felement<!-- BEGIN error --> error<!-- END error --> {type}\"><!-- BEGIN error --><span class=\"error\">{error}</span><br /><!-- END error -->{element}</div></div>", |
743 | 'fieldset'=>"\n\t\t<div class=\"fitem\"><label>{label}{help}<!-- BEGIN required -->{req}<!-- END required --></label><fieldset class=\"felement<!-- BEGIN error --> error<!-- END error --> {type}\"><!-- BEGIN error --><span class=\"error\">{error}</span><br /><!-- END error -->{element}</fieldset></div>"); |
da6f8763 |
744 | |
745 | parent::HTML_QuickForm_Renderer_Tableless(); |
746 | } |
7f40a229 |
747 | |
da6f8763 |
748 | function startForm(&$form){ |
749 | $this->_reqHTML=$form->getReqHTML(); |
750 | $this->_elementTemplates=str_replace('{req}', $this->_reqHTML, $this->_elementTemplates); |
751 | parent::startForm($form); |
752 | } |
7f40a229 |
753 | |
da6f8763 |
754 | function startGroup(&$group, $required, $error){ |
755 | if (method_exists($group, 'getElementTemplateType')){ |
e249661f |
756 | $html = $this->_elementTemplates[$group->getElementTemplateType()]; |
da6f8763 |
757 | }else{ |
758 | $html = $this->_elementTemplates['default']; |
7f40a229 |
759 | |
da6f8763 |
760 | } |
761 | if (method_exists($group, 'getHelpButton')){ |
762 | $html =str_replace('{help}', $group->getHelpButton(), $html); |
763 | }else{ |
764 | $html =str_replace('{help}', '', $html); |
7f40a229 |
765 | |
da6f8763 |
766 | } |
49c53687 |
767 | $html =str_replace('{type}', 'fgroup', $html); |
7f40a229 |
768 | |
da6f8763 |
769 | $this->_templates[$group->getName()]=$html; |
770 | // Fix for bug in tableless quickforms that didn't allow you to stop a |
771 | // fieldset before a group of elements. |
772 | // if the element name indicates the end of a fieldset, close the fieldset |
773 | if ( in_array($group->getName(), $this->_stopFieldsetElements) |
774 | && $this->_fieldsetsOpen > 0 |
775 | ) { |
776 | $this->_html .= $this->_closeFieldsetTemplate; |
777 | $this->_fieldsetsOpen--; |
778 | } |
779 | parent::startGroup($group, $required, $error); |
780 | } |
7f40a229 |
781 | |
da6f8763 |
782 | function renderElement(&$element, $required, $error){ |
783 | if (method_exists($element, 'getElementTemplateType')){ |
784 | $html = $this->_elementTemplates[$element->getElementTemplateType()]; |
785 | }else{ |
786 | $html = $this->_elementTemplates['default']; |
7f40a229 |
787 | |
da6f8763 |
788 | } |
49c53687 |
789 | $html =str_replace('{type}', 'f'.$element->getType(), $html); |
da6f8763 |
790 | if (method_exists($element, 'getHelpButton')){ |
791 | $html=str_replace('{help}', $element->getHelpButton(), $html); |
792 | }else{ |
793 | $html=str_replace('{help}', '', $html); |
7f40a229 |
794 | |
da6f8763 |
795 | } |
796 | $this->_templates[$element->getName()]=$html; |
230a910a |
797 | if (!is_null($element->getAttribute('id'))) { |
798 | $id = $element->getAttribute('id'); |
799 | } else { |
800 | $id = $element->getName(); |
801 | } |
802 | $element->updateAttributes(array('id'=>'id_'.$id)); |
da6f8763 |
803 | parent::renderElement($element, $required, $error); |
804 | } |
bb40325e |
805 | function finishForm(&$form){ |
806 | parent::finishForm($form); |
807 | // add a validation script |
808 | if ('' != ($script = $form->getLockOptionStartScript())) { |
809 | $this->_html = $script . "\n" . $this->_html; |
810 | } |
811 | if ('' != ($script = $form->getLockOptionEndScript())) { |
812 | $this->_html = $this->_html . "\n" . $script; |
813 | } |
814 | } |
da6f8763 |
815 | } |
816 | |
da6f8763 |
817 | |
7f40a229 |
818 | $GLOBALS['_HTML_QuickForm_default_renderer']=& new MoodleQuickForm_Renderer(); |
da6f8763 |
819 | |
7f40a229 |
820 | MoodleQuickForm::registerElementType('checkbox', "$CFG->libdir/form/checkbox.php", 'MoodleQuickForm_checkbox'); |
821 | MoodleQuickForm::registerElementType('file', "$CFG->libdir/form/file.php", 'MoodleQuickForm_file'); |
822 | MoodleQuickForm::registerElementType('group', "$CFG->libdir/form/group.php", 'MoodleQuickForm_group'); |
823 | MoodleQuickForm::registerElementType('password', "$CFG->libdir/form/password.php", 'MoodleQuickForm_password'); |
824 | MoodleQuickForm::registerElementType('radio', "$CFG->libdir/form/radio.php", 'MoodleQuickForm_radio'); |
825 | MoodleQuickForm::registerElementType('select', "$CFG->libdir/form/select.php", 'MoodleQuickForm_select'); |
826 | MoodleQuickForm::registerElementType('text', "$CFG->libdir/form/text.php", 'MoodleQuickForm_text'); |
827 | MoodleQuickForm::registerElementType('textarea', "$CFG->libdir/form/textarea.php", 'MoodleQuickForm_textarea'); |
828 | MoodleQuickForm::registerElementType('date_selector', "$CFG->libdir/form/dateselector.php", 'MoodleQuickForm_date_selector'); |
829 | MoodleQuickForm::registerElementType('date_time_selector', "$CFG->libdir/form/datetimeselector.php", 'MoodleQuickForm_date_time_selector'); |
830 | MoodleQuickForm::registerElementType('htmleditor', "$CFG->libdir/form/htmleditor.php", 'MoodleQuickForm_htmleditor'); |
effa85f4 |
831 | MoodleQuickForm::registerElementType('format', "$CFG->libdir/form/format.php", 'MoodleQuickForm_format'); |
7f40a229 |
832 | MoodleQuickForm::registerElementType('static', "$CFG->libdir/form/static.php", 'MoodleQuickForm_static'); |
833 | MoodleQuickForm::registerElementType('hidden', "$CFG->libdir/form/hidden.php", 'MoodleQuickForm_hidden'); |
e2294b98 |
834 | MoodleQuickForm::registerElementType('modvisible', "$CFG->libdir/form/modvisible.php", 'MoodleQuickForm_modvisible'); |
835 | MoodleQuickForm::registerElementType('modgroupmode', "$CFG->libdir/form/modgroupmode.php", 'MoodleQuickForm_modgroupmode'); |
864cc1de |
836 | |
da6f8763 |
837 | ?> |