2009-05-25 08:27:25 +00:00
< ? php
2009-11-01 11:31:16 +00:00
// This file is part of Moodle - http://moodle.org/
//
2009-05-25 08:27:25 +00:00
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
2009-11-01 11:31:16 +00:00
//
2009-05-25 08:27:25 +00:00
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
2006-09-24 17:04:51 +00:00
/**
* formslib . php - library of classes for creating forms in Moodle , based on PEAR QuickForms .
2006-11-12 07:28:13 +00:00
*
* To use formslib then you will want to create a new file purpose_form . php eg . edit_form . php
* and you want to name your class something like { modulename } _ { purpose } _form . Your class will
* extend moodleform overriding abstract classes definition and optionally defintion_after_data
* and validation .
*
* See examples of use of this library in course / edit . php and course / edit_form . php
*
* A few notes :
2010-07-25 13:35:05 +00:00
* form definition is used for both printing of form and processing and should be the same
2006-11-12 07:28:13 +00:00
* for both or you may lose some submitted data which won ' t be let through .
* you should be using setType for every form element except select , radio or checkbox
* elements , these elements clean themselves .
*
2012-01-06 16:38:06 +08:00
* @ package core_form
* @ copyright 2006 Jamie Pratt < me @ jamiep . org >
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2006-09-24 17:04:51 +00:00
*/
2010-07-25 13:35:05 +00:00
defined ( 'MOODLE_INTERNAL' ) || die ();
/** setup.php includes our hacked pear libs first */
2006-09-24 17:04:51 +00:00
require_once 'HTML/QuickForm.php' ;
require_once 'HTML/QuickForm/DHTMLRulesTableless.php' ;
require_once 'HTML/QuickForm/Renderer/Tableless.php' ;
2011-07-27 16:24:49 +08:00
require_once 'HTML/QuickForm/Rule.php' ;
2006-09-24 17:04:51 +00:00
2008-09-21 21:29:41 +00:00
require_once $CFG -> libdir . '/filelib.php' ;
2006-11-09 08:38:40 +00:00
2012-01-06 16:38:06 +08:00
/**
* EDITOR_UNLIMITED_FILES - hard - coded value for the 'maxfiles' option
*/
2009-03-30 10:01:39 +00:00
define ( 'EDITOR_UNLIMITED_FILES' , - 1 );
2006-12-19 07:03:08 +00:00
/**
* Callback called when PEAR throws an error
*
* @ param PEAR_Error $error
*/
function pear_handle_error ( $error ){
echo '<strong>' . $error -> GetMessage () . '</strong> ' . $error -> getUserInfo ();
echo '<br /> <strong>Backtrace </strong>:' ;
print_object ( $error -> backtrace );
}
2013-08-10 22:46:49 +02:00
if ( $CFG -> debugdeveloper ) {
2012-03-18 18:39:37 +01:00
//TODO: this is a wrong place to init PEAR!
$GLOBALS [ '_PEAR_default_error_mode' ] = PEAR_ERROR_CALLBACK ;
$GLOBALS [ '_PEAR_default_error_options' ] = 'pear_handle_error' ;
2006-09-25 11:08:44 +00:00
}
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Initalize javascript for date type form element
2009-11-01 11:31:16 +00:00
*
2012-01-06 16:38:06 +08:00
* @ staticvar bool $done make sure it gets initalize once .
2010-08-04 09:13:27 +00:00
* @ global moodle_page $PAGE
2009-05-25 08:27:25 +00:00
*/
2009-03-13 09:56:53 +00:00
function form_init_date_js () {
ajaxlib/require_js: MDL-16693 $PAGE->requires->... deprecates require_js etc.
There is a new implementation of require_js in lib/deprecatedlib.php,
based on $PAGE->requires.
There were a few other recently introduced functions in lib/weblib.php,
namely print_js_call, print_delayed_js_call, print_js_config and
standard_js_config. These have been removed, since they were never in
a stable branch, and all the places that used them have been changed
to use the newer $PAGE->requires->... methods.
get_require_js_code is also gone, and the evil places that were calling
it, even though it is an internal function, have been fixed.
Also, I made some minor improvements to the code I committed yesterday
for MDL-16695.
All that remains is to update all the places in core code that are
still using require_js.
(This commit also fixes the problem where the admin tree would not
start with the right categories expanded.)
2009-06-12 12:13:07 +00:00
global $PAGE ;
2009-03-13 09:56:53 +00:00
static $done = false ;
if ( ! $done ) {
2015-10-15 10:03:59 +01:00
$calendar = \core_calendar\type_factory :: get_calendar_instance ();
2010-08-04 09:13:27 +00:00
$module = 'moodle-form-dateselector' ;
$function = 'M.form.dateselector.init_date_selectors' ;
2012-06-28 16:27:04 +08:00
$config = array ( array (
2015-10-15 10:03:59 +01:00
'firstdayofweek' => $calendar -> get_starting_weekday (),
2012-09-20 17:18:33 +08:00
'mon' => date_format_string ( strtotime ( " Monday " ), '%a' , 99 ),
'tue' => date_format_string ( strtotime ( " Tuesday " ), '%a' , 99 ),
'wed' => date_format_string ( strtotime ( " Wednesday " ), '%a' , 99 ),
'thu' => date_format_string ( strtotime ( " Thursday " ), '%a' , 99 ),
'fri' => date_format_string ( strtotime ( " Friday " ), '%a' , 99 ),
'sat' => date_format_string ( strtotime ( " Saturday " ), '%a' , 99 ),
'sun' => date_format_string ( strtotime ( " Sunday " ), '%a' , 99 ),
'january' => date_format_string ( strtotime ( " January 1 " ), '%B' , 99 ),
'february' => date_format_string ( strtotime ( " February 1 " ), '%B' , 99 ),
'march' => date_format_string ( strtotime ( " March 1 " ), '%B' , 99 ),
'april' => date_format_string ( strtotime ( " April 1 " ), '%B' , 99 ),
'may' => date_format_string ( strtotime ( " May 1 " ), '%B' , 99 ),
'june' => date_format_string ( strtotime ( " June 1 " ), '%B' , 99 ),
'july' => date_format_string ( strtotime ( " July 1 " ), '%B' , 99 ),
'august' => date_format_string ( strtotime ( " August 1 " ), '%B' , 99 ),
'september' => date_format_string ( strtotime ( " September 1 " ), '%B' , 99 ),
'october' => date_format_string ( strtotime ( " October 1 " ), '%B' , 99 ),
'november' => date_format_string ( strtotime ( " November 1 " ), '%B' , 99 ),
'december' => date_format_string ( strtotime ( " December 1 " ), '%B' , 99 )
2012-06-28 16:27:04 +08:00
));
2010-08-04 09:13:27 +00:00
$PAGE -> requires -> yui_module ( $module , $function , $config );
2009-03-13 09:56:53 +00:00
$done = true ;
}
}
2006-12-28 09:32:45 +00:00
2006-11-09 10:42:44 +00:00
/**
2012-01-06 16:38:06 +08:00
* Wrapper that separates quickforms syntax from moodle code
*
2006-11-12 07:28:13 +00:00
* Moodle specific wrapper that separates quickforms syntax from moodle code . You won ' t directly
2007-12-04 10:35:25 +00:00
* use this class you should write a class definition which extends this class or a more specific
2006-11-12 07:28:13 +00:00
* subclass such a moodleform_mod for each form you want to display and / or process with formslib .
*
* You will write your own definition () method which performs the form set up .
2009-05-25 08:27:25 +00:00
*
2012-01-06 16:38:06 +08:00
* @ package core_form
* @ copyright 2006 Jamie Pratt < me @ jamiep . org >
2009-05-25 08:27:25 +00:00
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2012-01-06 16:38:06 +08:00
* @ todo MDL - 19380 rethink the file scanning
2006-11-09 10:42:44 +00:00
*/
2009-07-16 10:38:15 +00:00
abstract class moodleform {
2012-01-06 16:38:06 +08:00
/** @var string name of the form */
2008-07-31 22:15:30 +00:00
protected $_formname ; // form name
2012-01-06 16:38:06 +08:00
/** @var MoodleQuickForm quickform object definition */
2008-07-31 22:15:30 +00:00
protected $_form ;
2012-01-06 16:38:06 +08:00
/** @var array globals workaround */
2008-07-31 22:15:30 +00:00
protected $_customdata ;
2012-01-06 16:38:06 +08:00
/** @var object definition_after_data executed flag */
2008-07-31 22:15:30 +00:00
protected $_definition_finalized = false ;
2006-11-24 12:20:26 +00:00
2006-11-12 07:28:13 +00:00
/**
* The constructor function calls the abstract function definition () and it will then
* process and clean and attempt to validate incoming data .
*
* It will call your custom validate method to validate data and will also check any rules
* you have specified in definition using addRule
*
* The name of the form ( id attribute of the form ) is automatically generated depending on
* the name you gave the class extending moodleform . You should call your class something
* like
*
2007-08-03 13:08:05 +00:00
* @ param mixed $action the action attribute for the form . If empty defaults to auto detect the
2012-01-06 16:38:06 +08:00
* current url . If a moodle_url object then outputs params as hidden variables .
* @ param mixed $customdata if your form defintion method needs access to data such as $course
* $cm , etc . to construct the form definition then pass it in this array . You can
* use globals for somethings .
2006-11-12 07:28:13 +00:00
* @ param string $method if you set this to anything other than 'post' then _GET and _POST will
* be merged and used as incoming data to the form .
* @ param string $target target frame for form submission . You will rarely use this . Don ' t use
2012-01-06 16:38:06 +08:00
* it if you don ' t need to as the target attribute is deprecated in xhtml strict .
2006-11-12 07:28:13 +00:00
* @ param mixed $attributes you can pass a string of html attributes here or an array .
2009-05-25 08:27:25 +00:00
* @ param bool $editable
2006-11-12 07:28:13 +00:00
*/
2015-11-05 17:01:34 +08:00
public function __construct ( $action = null , $customdata = null , $method = 'post' , $target = '' , $attributes = null , $editable = true ) {
2012-05-15 15:22:31 +02:00
global $CFG , $FULLME ;
2012-07-21 19:23:44 +02:00
// no standard mform in moodle should allow autocomplete with the exception of user signup
if ( empty ( $attributes )) {
$attributes = array ( 'autocomplete' => 'off' );
} else if ( is_array ( $attributes )) {
$attributes [ 'autocomplete' ] = 'off' ;
} else {
if ( strpos ( $attributes , 'autocomplete' ) === false ) {
$attributes .= ' autocomplete="off" ' ;
2011-12-30 14:13:35 +01:00
}
}
2006-12-19 07:03:08 +00:00
if ( empty ( $action )){
2012-05-15 15:22:31 +02:00
// do not rely on PAGE->url here because dev often do not setup $actualurl properly in admin_externalpage_setup()
$action = strip_querystring ( $FULLME );
if ( ! empty ( $CFG -> sslproxy )) {
// return only https links when using SSL proxy
$action = preg_replace ( '/^http:/' , 'https:' , $action , 1 );
}
//TODO: use following instead of FULLME - see MDL-33015
//$action = strip_querystring(qualified_me());
2006-12-19 07:03:08 +00:00
}
2011-07-08 13:59:12 +08:00
// Assign custom data first, so that get_form_identifier can use it.
2006-10-12 07:33:57 +00:00
$this -> _customdata = $customdata ;
2011-07-08 13:59:12 +08:00
$this -> _formname = $this -> get_form_identifier ();
2009-07-02 14:58:41 +00:00
$this -> _form = new MoodleQuickForm ( $this -> _formname , $method , $action , $target , $attributes );
2007-08-03 13:08:05 +00:00
if ( ! $editable ){
$this -> _form -> hardFreeze ();
}
2006-10-12 07:33:57 +00:00
2015-07-21 08:01:49 +00:00
// HACK to prevent browsers from automatically inserting the user's password into the wrong fields.
$element = $this -> _form -> addElement ( 'hidden' );
$element -> setType ( 'password' );
2006-10-12 07:33:57 +00:00
$this -> definition ();
$this -> _form -> addElement ( 'hidden' , 'sesskey' , null ); // automatic sesskey protection
2009-09-26 17:07:08 +00:00
$this -> _form -> setType ( 'sesskey' , PARAM_RAW );
2006-10-12 07:33:57 +00:00
$this -> _form -> setDefault ( 'sesskey' , sesskey ());
2006-10-14 12:32:31 +00:00
$this -> _form -> addElement ( 'hidden' , '_qf__' . $this -> _formname , null ); // form submission marker
2009-09-26 17:07:08 +00:00
$this -> _form -> setType ( '_qf__' . $this -> _formname , PARAM_RAW );
2006-10-14 12:32:31 +00:00
$this -> _form -> setDefault ( '_qf__' . $this -> _formname , 1 );
$this -> _form -> _setDefaultRuleMessages ();
2006-10-12 07:33:57 +00:00
// we have to know all input types before processing submission ;-)
$this -> _process_submission ( $method );
}
2006-11-09 10:42:44 +00:00
2015-11-05 17:01:34 +08:00
/**
* Old syntax of class constructor . Deprecated in PHP7 .
*
* @ deprecated since Moodle 3.1
*/
public function moodleform ( $action = null , $customdata = null , $method = 'post' , $target = '' , $attributes = null , $editable = true ) {
debugging ( 'Use of class name as constructor is deprecated' , DEBUG_DEVELOPER );
self :: __construct ( $action , $customdata , $method , $target , $attributes , $editable );
}
2011-07-08 13:59:12 +08:00
/**
* It should returns unique identifier for the form .
* Currently it will return class name , but in case two same forms have to be
* rendered on same page then override function to get unique form identifier .
* e . g This is used on multiple self enrollments page .
*
* @ return string form identifier .
*/
protected function get_form_identifier () {
2014-11-13 16:20:16 +08:00
$class = get_class ( $this );
return preg_replace ( '/[^a-z0-9_]/i' , '_' , $class );
2011-07-08 13:59:12 +08:00
}
2006-10-24 11:05:50 +00:00
/**
2006-11-12 07:28:13 +00:00
* To autofocus on first form element or first element with error .
2006-10-24 11:05:50 +00:00
*
2007-03-16 01:46:17 +00:00
* @ param string $name if this is set then the focus is forced to a field with this name
2012-01-06 16:38:06 +08:00
* @ return string javascript to select form element with first error or
* first element if no errors . Use this as a parameter
* when calling print_header
2006-10-24 11:05:50 +00:00
*/
2007-11-12 17:12:35 +00:00
function focus ( $name = NULL ) {
2006-11-22 15:58:07 +00:00
$form =& $this -> _form ;
2007-11-12 17:12:35 +00:00
$elkeys = array_keys ( $form -> _elementIndex );
$error = false ;
2006-11-22 15:58:07 +00:00
if ( isset ( $form -> _errors ) && 0 != count ( $form -> _errors )){
$errorkeys = array_keys ( $form -> _errors );
$elkeys = array_intersect ( $elkeys , $errorkeys );
2007-11-12 17:12:35 +00:00
$error = true ;
2006-10-24 11:05:50 +00:00
}
2007-11-12 17:12:35 +00:00
if ( $error or empty ( $name )) {
$names = array ();
while ( empty ( $names ) and ! empty ( $elkeys )) {
$el = array_shift ( $elkeys );
$names = $form -> _getElNamesRecursive ( $el );
}
if ( ! empty ( $names )) {
$name = array_shift ( $names );
}
2007-03-16 01:46:17 +00:00
}
2007-11-12 17:12:35 +00:00
$focus = '' ;
if ( ! empty ( $name )) {
$focus = 'forms[\'' . $form -> getAttribute ( 'id' ) . '\'].elements[\'' . $name . '\']' ;
2006-11-22 15:58:07 +00:00
}
2007-11-12 17:12:35 +00:00
2006-11-22 15:58:07 +00:00
return $focus ;
}
2006-10-12 07:33:57 +00:00
2006-11-09 10:42:44 +00:00
/**
* Internal method . Alters submitted data to be suitable for quickforms processing .
* Must be called when the form is fully set up .
2009-05-25 08:27:25 +00:00
*
2012-01-06 16:38:06 +08:00
* @ param string $method name of the method which alters submitted data
2006-11-09 10:42:44 +00:00
*/
2006-10-12 07:33:57 +00:00
function _process_submission ( $method ) {
$submission = array ();
if ( $method == 'post' ) {
if ( ! empty ( $_POST )) {
2013-11-18 10:50:26 +08:00
$submission = $_POST ;
2006-10-12 07:33:57 +00:00
}
} else {
2013-11-18 10:50:26 +08:00
$submission = $_GET ;
merge_query_params ( $submission , $_POST ); // Emulate handling of parameters in xxxx_param().
2006-10-12 07:33:57 +00:00
}
// following trick is needed to enable proper sesskey checks when using GET forms
2006-10-14 12:32:31 +00:00
// the _qf__.$this->_formname serves as a marker that form was actually submitted
if ( array_key_exists ( '_qf__' . $this -> _formname , $submission ) and $submission [ '_qf__' . $this -> _formname ] == 1 ) {
2006-10-12 07:33:57 +00:00
if ( ! confirm_sesskey ()) {
2008-09-08 02:35:22 +00:00
print_error ( 'invalidsesskey' );
2006-10-12 07:33:57 +00:00
}
2006-11-09 10:42:44 +00:00
$files = $_FILES ;
2006-10-12 07:33:57 +00:00
} else {
$submission = array ();
2006-11-09 10:42:44 +00:00
$files = array ();
2006-10-12 07:33:57 +00:00
}
2013-03-22 16:38:10 +08:00
$this -> detectMissingSetType ();
2006-10-12 07:33:57 +00:00
2006-11-09 10:42:44 +00:00
$this -> _form -> updateSubmission ( $submission , $files );
2006-10-12 07:33:57 +00:00
}
2013-08-28 09:18:42 +12:00
/**
2013-11-18 10:50:26 +08:00
* Internal method - should not be used anywhere .
* @ deprecated since 2.6
* @ return array $_POST .
2013-08-28 09:18:42 +12:00
*/
protected function _get_post_params () {
2013-11-18 10:50:26 +08:00
return $_POST ;
2013-08-28 09:18:42 +12:00
}
2006-11-09 10:42:44 +00:00
/**
2010-07-14 08:40:48 +00:00
* Internal method . Validates all old - style deprecated uploaded files .
* The new way is to upload files via repository api .
2009-11-01 11:31:16 +00:00
*
2012-01-06 16:38:06 +08:00
* @ param array $files list of files to be validated
2009-05-25 08:27:25 +00:00
* @ return bool | array Success or an array of errors
2006-11-09 10:42:44 +00:00
*/
2007-09-26 19:25:50 +00:00
function _validate_files ( & $files ) {
2008-07-31 22:15:30 +00:00
global $CFG , $COURSE ;
2007-09-26 19:25:50 +00:00
$files = array ();
2006-11-09 08:38:40 +00:00
if ( empty ( $_FILES )) {
// we do not need to do any checks because no files were submitted
2007-09-26 19:25:50 +00:00
// note: server side rules do not work for files - use custom verification in validate() instead
2006-11-09 08:38:40 +00:00
return true ;
}
2008-07-31 22:15:30 +00:00
$errors = array ();
$filenames = array ();
2006-11-09 08:38:40 +00:00
// now check that we really want each file
foreach ( $_FILES as $elname => $file ) {
2008-07-31 22:15:30 +00:00
$required = $this -> _form -> isElementRequired ( $elname );
2007-09-26 19:25:50 +00:00
2008-07-31 22:15:30 +00:00
if ( $file [ 'error' ] == 4 and $file [ 'size' ] == 0 ) {
if ( $required ) {
$errors [ $elname ] = get_string ( 'required' );
2006-11-09 08:38:40 +00:00
}
2008-07-31 22:15:30 +00:00
unset ( $_FILES [ $elname ]);
continue ;
}
2008-09-21 21:29:41 +00:00
if ( ! empty ( $file [ 'error' ])) {
$errors [ $elname ] = file_get_upload_error ( $file [ 'error' ]);
2008-07-31 22:15:30 +00:00
unset ( $_FILES [ $elname ]);
continue ;
}
if ( ! is_uploaded_file ( $file [ 'tmp_name' ])) {
// TODO: improve error message
$errors [ $elname ] = get_string ( 'error' );
unset ( $_FILES [ $elname ]);
continue ;
}
if ( ! $this -> _form -> elementExists ( $elname ) or ! $this -> _form -> getElementType ( $elname ) == 'file' ) {
// hmm, this file was not requested
unset ( $_FILES [ $elname ]);
continue ;
}
2014-02-18 09:22:30 +08:00
// NOTE: the viruses are scanned in file picker, no need to deal with them here.
2008-07-31 22:15:30 +00:00
$filename = clean_param ( $_FILES [ $elname ][ 'name' ], PARAM_FILE );
if ( $filename === '' ) {
// TODO: improve error message - wrong chars
$errors [ $elname ] = get_string ( 'error' );
unset ( $_FILES [ $elname ]);
continue ;
2006-11-09 08:38:40 +00:00
}
2008-07-31 22:15:30 +00:00
if ( in_array ( $filename , $filenames )) {
// TODO: improve error message - duplicate name
$errors [ $elname ] = get_string ( 'error' );
unset ( $_FILES [ $elname ]);
continue ;
}
$filenames [] = $filename ;
$_FILES [ $elname ][ 'name' ] = $filename ;
$files [ $elname ] = $_FILES [ $elname ][ 'tmp_name' ];
2006-11-09 08:38:40 +00:00
}
// return errors if found
2008-07-31 22:15:30 +00:00
if ( count ( $errors ) == 0 ){
2006-11-09 08:38:40 +00:00
return true ;
2007-09-26 19:25:50 +00:00
2006-11-09 08:38:40 +00:00
} else {
2007-09-26 19:25:50 +00:00
$files = array ();
2006-11-09 08:38:40 +00:00
return $errors ;
}
}
2011-09-26 11:02:44 +08:00
/**
* Internal method . Validates filepicker and filemanager files if they are
* set as required fields . Also , sets the error message if encountered one .
*
2012-01-06 16:38:06 +08:00
* @ return bool | array with errors
2011-09-26 11:02:44 +08:00
*/
protected function validate_draft_files () {
global $USER ;
$mform =& $this -> _form ;
$errors = array ();
//Go through all the required elements and make sure you hit filepicker or
//filemanager element.
foreach ( $mform -> _rules as $elementname => $rules ) {
$elementtype = $mform -> getElementType ( $elementname );
//If element is of type filepicker then do validation
if (( $elementtype == 'filepicker' ) || ( $elementtype == 'filemanager' )){
//Check if rule defined is required rule
foreach ( $rules as $rule ) {
if ( $rule [ 'type' ] == 'required' ) {
$draftid = ( int ) $mform -> getSubmitValue ( $elementname );
$fs = get_file_storage ();
2012-07-25 16:25:55 +08:00
$context = context_user :: instance ( $USER -> id );
2011-09-26 11:02:44 +08:00
if ( ! $files = $fs -> get_area_files ( $context -> id , 'user' , 'draft' , $draftid , 'id DESC' , false )) {
$errors [ $elementname ] = $rule [ 'message' ];
}
}
}
}
}
2012-07-09 20:50:35 +01:00
// Check all the filemanager elements to make sure they do not have too many
// files in them.
foreach ( $mform -> _elements as $element ) {
if ( $element -> _type == 'filemanager' ) {
$maxfiles = $element -> getMaxfiles ();
if ( $maxfiles > 0 ) {
$draftid = ( int ) $element -> getValue ();
$fs = get_file_storage ();
$context = context_user :: instance ( $USER -> id );
$files = $fs -> get_area_files ( $context -> id , 'user' , 'draft' , $draftid , '' , false );
if ( count ( $files ) > $maxfiles ) {
$errors [ $element -> getName ()] = get_string ( 'err_maxfiles' , 'form' , $maxfiles );
}
}
}
}
2011-09-26 11:02:44 +08:00
if ( empty ( $errors )) {
return true ;
} else {
return $errors ;
}
}
2006-11-09 10:42:44 +00:00
/**
2006-11-12 07:28:13 +00:00
* Load in existing data as form defaults . Usually new entry defaults are stored directly in
* form definition ( new entry form ); this function is used to load in data where values
* already exist and data is being edited ( edit entry form ) .
2006-11-09 10:42:44 +00:00
*
2008-06-09 16:53:30 +00:00
* note : $slashed param removed
*
2012-01-06 16:38:06 +08:00
* @ param stdClass | array $default_values object or array of default values
2006-11-09 10:42:44 +00:00
*/
2008-06-09 16:53:30 +00:00
function set_data ( $default_values ) {
2006-10-12 07:33:57 +00:00
if ( is_object ( $default_values )) {
$default_values = ( array ) $default_values ;
}
2008-06-09 16:53:30 +00:00
$this -> _form -> setDefaults ( $default_values );
2006-10-12 07:33:57 +00:00
}
2006-11-09 10:42:44 +00:00
/**
* Check that form was submitted . Does not check validity of submitted data .
*
* @ return bool true if form properly submitted
*/
2006-10-12 07:33:57 +00:00
function is_submitted () {
return $this -> _form -> isSubmitted ();
}
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Checks if button pressed is not for submitting the form
*
* @ staticvar bool $nosubmit keeps track of no submit button
* @ return bool
2009-05-25 08:27:25 +00:00
*/
2006-12-19 07:03:08 +00:00
function no_submit_button_pressed (){
static $nosubmit = null ; // one check is enough
if ( ! is_null ( $nosubmit )){
return $nosubmit ;
}
$mform =& $this -> _form ;
$nosubmit = false ;
2006-12-28 09:32:45 +00:00
if ( ! $this -> is_submitted ()){
return false ;
}
2006-12-19 07:03:08 +00:00
foreach ( $mform -> _noSubmitButtons as $nosubmitbutton ){
if ( optional_param ( $nosubmitbutton , 0 , PARAM_RAW )){
$nosubmit = true ;
break ;
}
}
return $nosubmit ;
}
2006-11-09 10:42:44 +00:00
/**
* Check that form data is valid .
2012-02-21 12:39:35 +13:00
* You should almost always use this , rather than { @ link validate_defined_fields }
2006-11-09 10:42:44 +00:00
*
* @ return bool true if form data valid
*/
2006-10-12 07:33:57 +00:00
function is_validated () {
2007-08-03 13:08:05 +00:00
//finalize the form definition before any processing
if ( ! $this -> _definition_finalized ) {
$this -> _definition_finalized = true ;
$this -> definition_after_data ();
}
2009-06-02 10:39:21 +00:00
return $this -> validate_defined_fields ();
}
/**
* Validate the form .
*
2012-02-21 12:39:35 +13:00
* You almost always want to call { @ link is_validated } instead of this
* because it calls { @ link definition_after_data } first , before validating the form ,
2009-06-02 10:39:21 +00:00
* which is what you want in 99 % of cases .
*
* This is provided as a separate function for those special cases where
* you want the form validated before definition_after_data is called
* for example , to selectively add new elements depending on a no_submit_button press ,
* but only when the form is valid when the no_submit_button is pressed ,
*
2012-01-06 16:38:06 +08:00
* @ param bool $validateonnosubmit optional , defaults to false . The default behaviour
* is NOT to validate the form when a no submit button has been pressed .
* pass true here to override this behaviour
2009-06-02 10:39:21 +00:00
*
* @ return bool true if form data valid
*/
function validate_defined_fields ( $validateonnosubmit = false ) {
static $validated = null ; // one validation is enough
$mform =& $this -> _form ;
if ( $this -> no_submit_button_pressed () && empty ( $validateonnosubmit )){
2007-01-10 05:05:26 +00:00
return false ;
} elseif ( $validated === null ) {
2006-12-04 10:55:50 +00:00
$internal_val = $mform -> validate ();
2007-09-26 19:25:50 +00:00
$files = array ();
$file_val = $this -> _validate_files ( $files );
2011-09-26 11:02:44 +08:00
//check draft files for validation and flag them if required files
//are not in draft area.
$draftfilevalue = $this -> validate_draft_files ();
if ( $file_val !== true && $draftfilevalue !== true ) {
$file_val = array_merge ( $file_val , $draftfilevalue );
} else if ( $draftfilevalue !== true ) {
$file_val = $draftfilevalue ;
} //default is file_val, so no need to assign.
2007-09-26 19:25:50 +00:00
if ( $file_val !== true ) {
if ( ! empty ( $file_val )) {
foreach ( $file_val as $element => $msg ) {
$mform -> setElementError ( $element , $msg );
}
}
$file_val = false ;
}
2008-09-07 13:30:46 +00:00
$data = $mform -> exportValues ();
2007-09-26 19:25:50 +00:00
$moodle_val = $this -> validation ( $data , $files );
2007-11-23 22:15:07 +00:00
if (( is_array ( $moodle_val ) && count ( $moodle_val ) !== 0 )) {
// non-empty array means errors
foreach ( $moodle_val as $element => $msg ) {
$mform -> setElementError ( $element , $msg );
2006-10-12 07:33:57 +00:00
}
2007-11-23 22:15:07 +00:00
$moodle_val = false ;
} else {
// anything else means validation ok
$moodle_val = true ;
2006-10-12 07:33:57 +00:00
}
2007-09-26 19:25:50 +00:00
2006-11-09 08:38:40 +00:00
$validated = ( $internal_val and $moodle_val and $file_val );
2006-10-12 07:33:57 +00:00
}
2007-01-10 05:05:26 +00:00
return $validated ;
2006-10-12 07:33:57 +00:00
}
2006-12-04 09:36:30 +00:00
/**
* Return true if a cancel button has been pressed resulting in the form being submitted .
*
2012-01-06 16:38:06 +08:00
* @ return bool true if a cancel button has been pressed
2006-12-04 09:36:30 +00:00
*/
function is_cancelled (){
$mform =& $this -> _form ;
2006-12-19 07:03:08 +00:00
if ( $mform -> isSubmitted ()){
foreach ( $mform -> _cancelButtons as $cancelbutton ){
if ( optional_param ( $cancelbutton , 0 , PARAM_RAW )){
return true ;
}
2006-12-04 09:36:30 +00:00
}
}
return false ;
}
2006-11-09 10:42:44 +00:00
/**
2006-11-12 07:28:13 +00:00
* Return submitted data if properly submitted or returns NULL if validation fails or
* if there is no submitted data .
2008-07-31 22:15:30 +00:00
*
2008-06-09 16:53:30 +00:00
* note : $slashed param removed
2006-11-09 10:42:44 +00:00
*
2011-03-17 20:43:35 +01:00
* @ return object submitted data ; NULL if not valid or not submitted or cancelled
2006-11-09 10:42:44 +00:00
*/
2008-06-09 16:53:30 +00:00
function get_data () {
2006-12-04 09:36:30 +00:00
$mform =& $this -> _form ;
2006-12-04 10:55:50 +00:00
2011-03-17 20:43:35 +01:00
if ( ! $this -> is_cancelled () and $this -> is_submitted () and $this -> is_validated ()) {
2008-06-09 16:53:30 +00:00
$data = $mform -> exportValues ();
2006-10-14 12:32:31 +00:00
unset ( $data [ 'sesskey' ]); // we do not need to return sesskey
unset ( $data [ '_qf__' . $this -> _formname ]); // we do not need the submission marker too
2006-10-12 07:33:57 +00:00
if ( empty ( $data )) {
return NULL ;
} else {
return ( object ) $data ;
}
} else {
return NULL ;
}
}
2007-08-03 13:08:05 +00:00
/**
* Return submitted data without validation or NULL if there is no submitted data .
2008-06-09 16:53:30 +00:00
* note : $slashed param removed
2007-08-03 13:08:05 +00:00
*
* @ return object submitted data ; NULL if not submitted
*/
2008-06-09 16:53:30 +00:00
function get_submitted_data () {
2007-08-03 13:08:05 +00:00
$mform =& $this -> _form ;
if ( $this -> is_submitted ()) {
2008-06-09 16:53:30 +00:00
$data = $mform -> exportValues ();
2007-08-03 13:08:05 +00:00
unset ( $data [ 'sesskey' ]); // we do not need to return sesskey
unset ( $data [ '_qf__' . $this -> _formname ]); // we do not need the submission marker too
if ( empty ( $data )) {
return NULL ;
} else {
return ( object ) $data ;
}
} else {
return NULL ;
}
}
2006-11-09 10:42:44 +00:00
/**
* Save verified uploaded files into directory . Upload process can be customised from definition ()
2009-05-25 08:27:25 +00:00
*
2012-01-06 16:38:06 +08:00
* @ deprecated since Moodle 2.0
* @ todo MDL - 31294 remove this api
* @ see moodleform :: save_stored_file ()
* @ see moodleform :: save_file ()
* @ param string $destination path where file should be stored
2009-05-25 08:27:25 +00:00
* @ return bool Always false
2006-11-09 10:42:44 +00:00
*/
2006-11-09 08:38:40 +00:00
function save_files ( $destination ) {
2008-07-31 22:15:30 +00:00
debugging ( 'Not used anymore, please fix code! Use save_stored_file() or save_file() instead' );
2006-11-09 08:38:40 +00:00
return false ;
}
2006-11-07 08:48:18 +00:00
2006-12-28 21:21:44 +00:00
/**
2008-07-31 22:15:30 +00:00
* Returns name of uploaded file .
2009-05-25 08:27:25 +00:00
*
2012-01-06 16:38:06 +08:00
* @ param string $elname first element if null
* @ return string | bool false in case of failure , string if ok
2006-12-28 21:21:44 +00:00
*/
2008-07-31 22:15:30 +00:00
function get_new_filename ( $elname = null ) {
2008-09-07 13:30:46 +00:00
global $USER ;
2008-07-31 22:15:30 +00:00
if ( ! $this -> is_submitted () or ! $this -> is_validated ()) {
return false ;
}
if ( is_null ( $elname )) {
if ( empty ( $_FILES )) {
return false ;
}
reset ( $_FILES );
$elname = key ( $_FILES );
}
2008-09-07 13:30:46 +00:00
if ( empty ( $elname )) {
return false ;
}
$element = $this -> _form -> getElement ( $elname );
2010-06-08 03:09:14 +00:00
if ( $element instanceof MoodleQuickForm_filepicker || $element instanceof MoodleQuickForm_filemanager ) {
2008-09-07 13:30:46 +00:00
$values = $this -> _form -> exportValues ( $elname );
if ( empty ( $values [ $elname ])) {
return false ;
}
$draftid = $values [ $elname ];
$fs = get_file_storage ();
2012-07-25 16:25:55 +08:00
$context = context_user :: instance ( $USER -> id );
2010-07-03 13:37:13 +00:00
if ( ! $files = $fs -> get_area_files ( $context -> id , 'user' , 'draft' , $draftid , 'id DESC' , false )) {
2008-09-07 13:30:46 +00:00
return false ;
}
$file = reset ( $files );
return $file -> get_filename ();
}
2008-07-31 22:15:30 +00:00
if ( ! isset ( $_FILES [ $elname ])) {
return false ;
}
return $_FILES [ $elname ][ 'name' ];
2006-12-28 21:21:44 +00:00
}
2007-09-26 16:53:26 +00:00
/**
2008-07-31 22:15:30 +00:00
* Save file to standard filesystem
2009-05-25 08:27:25 +00:00
*
2008-07-31 22:15:30 +00:00
* @ param string $elname name of element
* @ param string $pathname full path name of file
* @ param bool $override override file if exists
* @ return bool success
2007-09-26 16:53:26 +00:00
*/
2008-07-31 22:15:30 +00:00
function save_file ( $elname , $pathname , $override = false ) {
2008-09-07 13:30:46 +00:00
global $USER ;
2007-09-26 16:53:26 +00:00
2008-09-07 13:30:46 +00:00
if ( ! $this -> is_submitted () or ! $this -> is_validated ()) {
2007-09-26 16:53:26 +00:00
return false ;
}
2008-07-31 22:15:30 +00:00
if ( file_exists ( $pathname )) {
if ( $override ) {
if ( !@ unlink ( $pathname )) {
return false ;
}
} else {
return false ;
}
}
2008-09-07 13:30:46 +00:00
$element = $this -> _form -> getElement ( $elname );
2010-06-08 03:09:14 +00:00
if ( $element instanceof MoodleQuickForm_filepicker || $element instanceof MoodleQuickForm_filemanager ) {
2008-09-07 13:30:46 +00:00
$values = $this -> _form -> exportValues ( $elname );
if ( empty ( $values [ $elname ])) {
return false ;
}
$draftid = $values [ $elname ];
$fs = get_file_storage ();
2012-07-25 16:25:55 +08:00
$context = context_user :: instance ( $USER -> id );
2010-07-03 13:37:13 +00:00
if ( ! $files = $fs -> get_area_files ( $context -> id , 'user' , 'draft' , $draftid , 'id DESC' , false )) {
2008-09-07 13:30:46 +00:00
return false ;
}
$file = reset ( $files );
return $file -> copy_content_to ( $pathname );
} else if ( isset ( $_FILES [ $elname ])) {
return copy ( $_FILES [ $elname ][ 'tmp_name' ], $pathname );
2008-07-31 22:15:30 +00:00
}
2008-09-07 13:30:46 +00:00
return false ;
2008-07-31 22:15:30 +00:00
}
2010-07-11 11:43:15 +00:00
/**
* Returns a temporary file , do not forget to delete after not needed any more .
*
2012-01-06 16:38:06 +08:00
* @ param string $elname name of the elmenet
* @ return string | bool either string or false
2010-07-11 11:43:15 +00:00
*/
function save_temp_file ( $elname ) {
if ( ! $this -> get_new_filename ( $elname )) {
return false ;
}
2011-09-10 10:43:49 +02:00
if ( ! $dir = make_temp_directory ( 'forms' )) {
2010-07-11 11:43:15 +00:00
return false ;
}
if ( ! $tempfile = tempnam ( $dir , 'tempup_' )) {
return false ;
}
if ( ! $this -> save_file ( $elname , $tempfile , true )) {
// something went wrong
@ unlink ( $tempfile );
return false ;
}
return $tempfile ;
}
2010-06-08 03:09:14 +00:00
/**
2010-06-10 09:58:45 +00:00
* Get draft files of a form element
* This is a protected method which will be used only inside moodleforms
*
* @ param string $elname name of element
2012-01-06 16:38:06 +08:00
* @ return array | bool | null
2010-06-10 09:58:45 +00:00
*/
protected function get_draft_files ( $elname ) {
global $USER ;
if ( ! $this -> is_submitted ()) {
return false ;
}
$element = $this -> _form -> getElement ( $elname );
if ( $element instanceof MoodleQuickForm_filepicker || $element instanceof MoodleQuickForm_filemanager ) {
$values = $this -> _form -> exportValues ( $elname );
if ( empty ( $values [ $elname ])) {
return false ;
}
$draftid = $values [ $elname ];
$fs = get_file_storage ();
2012-07-25 16:25:55 +08:00
$context = context_user :: instance ( $USER -> id );
2010-07-03 13:37:13 +00:00
if ( ! $files = $fs -> get_area_files ( $context -> id , 'user' , 'draft' , $draftid , 'id DESC' , false )) {
2010-06-10 09:58:45 +00:00
return null ;
}
return $files ;
}
return null ;
}
2008-07-31 22:15:30 +00:00
/**
* Save file to local filesystem pool
2009-05-25 08:27:25 +00:00
*
2008-07-31 22:15:30 +00:00
* @ param string $elname name of element
2012-01-06 16:38:06 +08:00
* @ param int $newcontextid id of context
* @ param string $newcomponent name of the component
* @ param string $newfilearea name of file area
* @ param int $newitemid item id
* @ param string $newfilepath path of file where it get stored
* @ param string $newfilename use specified filename , if not specified name of uploaded file used
* @ param bool $overwrite overwrite file if exists
* @ param int $newuserid new userid if required
2008-07-31 22:15:30 +00:00
* @ return mixed stored_file object or false if error ; may throw exception if duplicate found
*/
2010-07-03 13:37:13 +00:00
function save_stored_file ( $elname , $newcontextid , $newcomponent , $newfilearea , $newitemid , $newfilepath = '/' ,
2008-09-03 05:14:24 +00:00
$newfilename = null , $overwrite = false , $newuserid = null ) {
2008-09-02 09:46:29 +00:00
global $USER ;
2008-07-31 22:15:30 +00:00
if ( ! $this -> is_submitted () or ! $this -> is_validated ()) {
2007-09-26 19:25:50 +00:00
return false ;
2008-07-31 22:15:30 +00:00
}
2007-09-26 19:25:50 +00:00
2008-09-02 09:46:29 +00:00
if ( empty ( $newuserid )) {
$newuserid = $USER -> id ;
2007-09-26 19:25:50 +00:00
}
2007-09-26 16:53:26 +00:00
2008-09-07 13:30:46 +00:00
$element = $this -> _form -> getElement ( $elname );
$fs = get_file_storage ();
2008-07-31 22:15:30 +00:00
2008-09-07 13:30:46 +00:00
if ( $element instanceof MoodleQuickForm_filepicker ) {
$values = $this -> _form -> exportValues ( $elname );
if ( empty ( $values [ $elname ])) {
return false ;
}
$draftid = $values [ $elname ];
2012-07-25 16:25:55 +08:00
$context = context_user :: instance ( $USER -> id );
2010-07-03 13:37:13 +00:00
if ( ! $files = $fs -> get_area_files ( $context -> id , 'user' , 'draft' , $draftid , 'id DESC' , false )) {
2008-09-07 13:30:46 +00:00
return false ;
}
$file = reset ( $files );
if ( is_null ( $newfilename )) {
$newfilename = $file -> get_filename ();
}
2008-07-31 22:15:30 +00:00
2008-09-07 13:30:46 +00:00
if ( $overwrite ) {
2010-07-03 13:37:13 +00:00
if ( $oldfile = $fs -> get_file ( $newcontextid , $newcomponent , $newfilearea , $newitemid , $newfilepath , $newfilename )) {
2008-09-07 13:30:46 +00:00
if ( ! $oldfile -> delete ()) {
return false ;
}
2008-09-02 09:46:29 +00:00
}
}
2010-07-03 13:37:13 +00:00
$file_record = array ( 'contextid' => $newcontextid , 'component' => $newcomponent , 'filearea' => $newfilearea , 'itemid' => $newitemid ,
2008-09-07 13:30:46 +00:00
'filepath' => $newfilepath , 'filename' => $newfilename , 'userid' => $newuserid );
return $fs -> create_file_from_storedfile ( $file_record , $file );
2008-09-02 09:46:29 +00:00
2008-09-07 13:30:46 +00:00
} else if ( isset ( $_FILES [ $elname ])) {
$filename = is_null ( $newfilename ) ? $_FILES [ $elname ][ 'name' ] : $newfilename ;
2008-07-31 22:15:30 +00:00
2008-09-07 13:30:46 +00:00
if ( $overwrite ) {
2010-07-03 13:37:13 +00:00
if ( $oldfile = $fs -> get_file ( $newcontextid , $newcomponent , $newfilearea , $newitemid , $newfilepath , $newfilename )) {
2008-09-07 13:30:46 +00:00
if ( ! $oldfile -> delete ()) {
return false ;
}
}
2008-09-02 09:46:29 +00:00
}
2008-09-07 13:30:46 +00:00
2010-07-03 13:37:13 +00:00
$file_record = array ( 'contextid' => $newcontextid , 'component' => $newcomponent , 'filearea' => $newfilearea , 'itemid' => $newitemid ,
2008-09-07 13:30:46 +00:00
'filepath' => $newfilepath , 'filename' => $newfilename , 'userid' => $newuserid );
return $fs -> create_file_from_pathname ( $file_record , $_FILES [ $elname ][ 'tmp_name' ]);
2008-09-02 09:46:29 +00:00
}
return false ;
2008-07-31 22:15:30 +00:00
}
/**
* Get content of uploaded file .
2009-05-25 08:27:25 +00:00
*
2012-01-06 16:38:06 +08:00
* @ param string $elname name of file upload element
* @ return string | bool false in case of failure , string if ok
2008-07-31 22:15:30 +00:00
*/
function get_file_content ( $elname ) {
2008-09-07 13:30:46 +00:00
global $USER ;
2008-07-31 22:15:30 +00:00
if ( ! $this -> is_submitted () or ! $this -> is_validated ()) {
return false ;
}
2008-09-07 13:30:46 +00:00
$element = $this -> _form -> getElement ( $elname );
2010-06-08 03:09:14 +00:00
if ( $element instanceof MoodleQuickForm_filepicker || $element instanceof MoodleQuickForm_filemanager ) {
2008-09-07 13:30:46 +00:00
$values = $this -> _form -> exportValues ( $elname );
if ( empty ( $values [ $elname ])) {
return false ;
}
$draftid = $values [ $elname ];
$fs = get_file_storage ();
2012-07-25 16:25:55 +08:00
$context = context_user :: instance ( $USER -> id );
2010-07-03 13:37:13 +00:00
if ( ! $files = $fs -> get_area_files ( $context -> id , 'user' , 'draft' , $draftid , 'id DESC' , false )) {
2008-09-07 13:30:46 +00:00
return false ;
}
$file = reset ( $files );
return $file -> get_content ();
} else if ( isset ( $_FILES [ $elname ])) {
return file_get_contents ( $_FILES [ $elname ][ 'tmp_name' ]);
2007-09-26 16:53:26 +00:00
}
2008-07-31 22:15:30 +00:00
2008-09-07 13:30:46 +00:00
return false ;
2007-09-26 16:53:26 +00:00
}
2006-11-09 10:42:44 +00:00
/**
* Print html form .
*/
2006-10-12 07:33:57 +00:00
function display () {
2007-08-03 13:08:05 +00:00
//finalize the form definition if not yet done
if ( ! $this -> _definition_finalized ) {
$this -> _definition_finalized = true ;
$this -> definition_after_data ();
}
2013-03-22 16:38:10 +08:00
2006-10-12 07:33:57 +00:00
$this -> _form -> display ();
}
2013-03-27 17:15:23 +00:00
/**
* Renders the html form ( same as display , but returns the result ) .
*
* Note that you can only output this rendered result once per page , as
* it contains IDs which must be unique .
*
* @ return string HTML code for the form
*/
public function render () {
ob_start ();
$this -> display ();
$out = ob_get_contents ();
ob_end_clean ();
return $out ;
}
2006-11-09 08:38:40 +00:00
/**
2012-01-06 16:38:06 +08:00
* Form definition . Abstract method - always override !
2006-11-09 08:38:40 +00:00
*/
2009-07-16 10:38:15 +00:00
protected abstract function definition ();
2006-10-24 11:05:50 +00:00
2006-10-16 12:07:44 +00:00
/**
2006-11-09 10:42:44 +00:00
* Dummy stub method - override if you need to setup the form depending on current
2007-01-12 18:52:09 +00:00
* values . This method is called after definition (), data submission and set_data () .
2006-11-09 10:42:44 +00:00
* All form setup that is dependent on form values should go in here .
2006-10-16 12:07:44 +00:00
*/
function definition_after_data (){
}
2006-10-12 07:33:57 +00:00
2006-11-09 10:42:44 +00:00
/**
* Dummy stub method - override if you needed to perform some extra validation .
* If there are errors return array of errors ( " fieldname " => " error message " ),
* otherwise true if ok .
2006-11-09 10:43:26 +00:00
*
2007-09-26 19:25:50 +00:00
* Server side rules do not work for uploaded files , implement serverside rules here if needed .
*
2006-11-09 10:42:44 +00:00
* @ param array $data array of ( " fieldname " => value ) of submitted data
2007-09-26 19:25:50 +00:00
* @ param array $files array of uploaded files " element_name " => tmp_file_path
2007-11-23 22:15:07 +00:00
* @ return array of " element_name " => " error_description " if there are errors ,
2012-01-06 16:38:06 +08:00
* or an empty array if everything is OK ( true allowed for backwards compatibility too ) .
2006-11-09 10:42:44 +00:00
*/
2007-09-26 19:25:50 +00:00
function validation ( $data , $files ) {
2007-11-20 15:08:05 +00:00
return array ();
2006-10-12 07:33:57 +00:00
}
2006-11-24 12:20:26 +00:00
2011-11-17 16:42:13 +00:00
/**
2012-02-21 12:39:35 +13:00
* Helper used by { @ link repeat_elements ()} .
2012-01-06 16:38:06 +08:00
*
2011-11-17 16:42:13 +00:00
* @ param int $i the index of this element .
* @ param HTML_QuickForm_element $elementclone
2011-11-23 11:47:06 +08:00
* @ param array $namecloned array of names
2011-11-17 16:42:13 +00:00
*/
function repeat_elements_fix_clone ( $i , $elementclone , & $namecloned ) {
$name = $elementclone -> getName ();
$namecloned [] = $name ;
if ( ! empty ( $name )) {
$elementclone -> setName ( $name . " [ $i ] " );
}
if ( is_a ( $elementclone , 'HTML_QuickForm_header' )) {
$value = $elementclone -> _text ;
$elementclone -> setValue ( str_replace ( '{no}' , ( $i + 1 ), $value ));
2012-06-25 15:15:20 +01:00
} else if ( is_a ( $elementclone , 'HTML_QuickForm_submit' ) || is_a ( $elementclone , 'HTML_QuickForm_button' )) {
$elementclone -> setValue ( str_replace ( '{no}' , ( $i + 1 ), $elementclone -> getValue ()));
2011-11-17 16:42:13 +00:00
} else {
$value = $elementclone -> getLabel ();
$elementclone -> setLabel ( str_replace ( '{no}' , ( $i + 1 ), $value ));
}
}
2006-11-24 12:33:53 +00:00
/**
* Method to add a repeating group of elements to a form .
*
* @ param array $elementobjs Array of elements or groups of elements that are to be repeated
2012-01-06 16:38:06 +08:00
* @ param int $repeats no of times to repeat elements initially
2013-11-27 13:35:11 +00:00
* @ param array $options a nested array . The first array key is the element name .
* the second array key is the type of option to set , and depend on that option ,
* the value takes different forms .
* 'default' - default value to set . Can include '{no}' which is replaced by the repeat number .
* 'type' - PARAM_ * type .
* 'helpbutton' - array containing the helpbutton params .
* 'disabledif' - array containing the disabledIf () arguments after the element name .
* 'rule' - array containing the addRule arguments after the element name .
* 'expanded' - whether this section of the form should be expanded by default . ( Name be a header element . )
* 'advanced' - whether this element is hidden by 'Show more ...' .
2006-11-24 12:33:53 +00:00
* @ param string $repeathiddenname name for hidden element storing no of repeats in this form
* @ param string $addfieldsname name for button to add more fields
* @ param int $addfieldsno how many fields to add at a time
2007-01-07 12:46:47 +00:00
* @ param string $addstring name of button , { no } is replaced by no of blanks that will be added .
2012-01-06 16:38:06 +08:00
* @ param bool $addbuttoninside if true , don ' t call closeHeaderBefore ( $addfieldsname ) . Default false .
2006-12-19 07:03:08 +00:00
* @ return int no of repeats of element in this page
2006-11-24 12:33:53 +00:00
*/
2007-10-09 15:44:06 +00:00
function repeat_elements ( $elementobjs , $repeats , $options , $repeathiddenname ,
$addfieldsname , $addfieldsno = 5 , $addstring = null , $addbuttoninside = false ){
2007-01-07 12:46:47 +00:00
if ( $addstring === null ){
$addstring = get_string ( 'addfields' , 'form' , $addfieldsno );
} else {
$addstring = str_ireplace ( '{no}' , $addfieldsno , $addstring );
}
2006-11-24 12:20:26 +00:00
$repeats = optional_param ( $repeathiddenname , $repeats , PARAM_INT );
$addfields = optional_param ( $addfieldsname , '' , PARAM_TEXT );
if ( ! empty ( $addfields )){
$repeats += $addfieldsno ;
}
$mform =& $this -> _form ;
2006-12-19 07:03:08 +00:00
$mform -> registerNoSubmitButton ( $addfieldsname );
2006-11-24 12:20:26 +00:00
$mform -> addElement ( 'hidden' , $repeathiddenname , $repeats );
2009-09-26 17:07:08 +00:00
$mform -> setType ( $repeathiddenname , PARAM_INT );
2006-11-24 12:20:26 +00:00
//value not to be overridden by submitted value
$mform -> setConstants ( array ( $repeathiddenname => $repeats ));
2009-03-18 07:08:18 +00:00
$namecloned = array ();
for ( $i = 0 ; $i < $repeats ; $i ++ ) {
2006-11-24 12:20:26 +00:00
foreach ( $elementobjs as $elementobj ){
2008-10-13 11:52:35 +00:00
$elementclone = fullclone ( $elementobj );
2011-11-17 16:42:13 +00:00
$this -> repeat_elements_fix_clone ( $i , $elementclone , $namecloned );
2006-11-24 12:20:26 +00:00
2011-11-17 16:42:13 +00:00
if ( $elementclone instanceof HTML_QuickForm_group && ! $elementclone -> _appendName ) {
foreach ( $elementclone -> getElements () as $el ) {
$this -> repeat_elements_fix_clone ( $i , $el , $namecloned );
}
$elementclone -> setLabel ( str_replace ( '{no}' , $i + 1 , $elementclone -> getLabel ()));
2006-11-24 12:20:26 +00:00
}
2007-01-18 11:21:10 +00:00
2006-11-24 12:20:26 +00:00
$mform -> addElement ( $elementclone );
}
}
for ( $i = 0 ; $i < $repeats ; $i ++ ) {
foreach ( $options as $elementname => $elementoptions ){
$pos = strpos ( $elementname , '[' );
if ( $pos !== FALSE ){
2012-05-02 13:20:40 +08:00
$realelementname = substr ( $elementname , 0 , $pos ) . " [ $i ] " ;
$realelementname .= substr ( $elementname , $pos );
2006-11-24 12:20:26 +00:00
} else {
$realelementname = $elementname . " [ $i ] " ;
}
foreach ( $elementoptions as $option => $params ){
switch ( $option ){
case 'default' :
2012-03-05 18:22:33 +00:00
$mform -> setDefault ( $realelementname , str_replace ( '{no}' , $i + 1 , $params ));
2006-11-24 12:20:26 +00:00
break ;
case 'helpbutton' :
2010-07-29 07:54:30 +00:00
$params = array_merge ( array ( $realelementname ), $params );
call_user_func_array ( array ( & $mform , 'addHelpButton' ), $params );
2006-11-24 12:20:26 +00:00
break ;
case 'disabledif' :
2009-03-18 07:08:18 +00:00
foreach ( $namecloned as $num => $name ){
if ( $params [ 0 ] == $name ){
$params [ 0 ] = $params [ 0 ] . " [ $i ] " ;
break ;
}
}
2007-01-10 05:05:26 +00:00
$params = array_merge ( array ( $realelementname ), $params );
call_user_func_array ( array ( & $mform , 'disabledIf' ), $params );
break ;
case 'rule' :
if ( is_string ( $params )){
$params = array ( null , $params , null , 'client' );
}
$params = array_merge ( array ( $realelementname ), $params );
call_user_func_array ( array ( & $mform , 'addRule' ), $params );
2006-11-24 12:20:26 +00:00
break ;
2013-05-10 12:05:43 +08:00
case 'type' :
$mform -> setType ( $realelementname , $params );
2011-12-07 11:56:34 +08:00
break ;
2013-02-07 20:44:17 +00:00
2013-03-12 15:05:17 +08:00
case 'expanded' :
$mform -> setExpanded ( $realelementname , $params );
2013-02-07 20:44:17 +00:00
break ;
case 'advanced' :
$mform -> setAdvanced ( $realelementname , $params );
2013-02-07 14:13:36 +00:00
break ;
2006-11-24 12:20:26 +00:00
}
}
}
}
2007-01-07 12:46:47 +00:00
$mform -> addElement ( 'submit' , $addfieldsname , $addstring );
2006-12-19 07:03:08 +00:00
2007-10-09 15:44:06 +00:00
if ( ! $addbuttoninside ) {
$mform -> closeHeaderBefore ( $addfieldsname );
}
2006-11-24 12:20:26 +00:00
2006-12-14 12:44:10 +00:00
return $repeats ;
2006-11-24 12:20:26 +00:00
}
2007-12-04 10:35:25 +00:00
/**
* Adds a link / button that controls the checked state of a group of checkboxes .
2009-05-25 08:27:25 +00:00
*
2012-01-06 16:38:06 +08:00
* @ param int $groupid The id of the group of advcheckboxes this element controls
2011-03-16 10:33:16 +00:00
* @ param string $text The text of the link . Defaults to selectallornone ( " select all/none " )
2012-01-06 16:38:06 +08:00
* @ param array $attributes associative array of HTML attributes
* @ param int $originalValue The original general state of the checkboxes before the user first clicks this element
2007-12-04 10:35:25 +00:00
*/
2011-03-16 10:33:16 +00:00
function add_checkbox_controller ( $groupid , $text = null , $attributes = null , $originalValue = 0 ) {
2012-03-06 12:06:59 +08:00
global $CFG , $PAGE ;
2011-03-16 10:33:16 +00:00
2012-03-09 14:15:02 +08:00
// Name of the controller button
$checkboxcontrollername = 'nosubmit_checkbox_controller' . $groupid ;
$checkboxcontrollerparam = 'checkbox_controller' . $groupid ;
$checkboxgroupclass = 'checkboxgroup' . $groupid ;
2011-03-16 10:33:16 +00:00
// Set the default text if none was specified
2007-12-04 10:35:25 +00:00
if ( empty ( $text )) {
$text = get_string ( 'selectallornone' , 'form' );
}
$mform = $this -> _form ;
2012-03-14 14:38:08 +13:00
$selectvalue = optional_param ( $checkboxcontrollerparam , null , PARAM_INT );
2012-03-09 14:15:02 +08:00
$contollerbutton = optional_param ( $checkboxcontrollername , null , PARAM_ALPHAEXT );
2007-12-04 10:35:25 +00:00
2012-03-14 14:38:08 +13:00
$newselectvalue = $selectvalue ;
if ( is_null ( $selectvalue )) {
$newselectvalue = $originalValue ;
2012-03-09 14:15:02 +08:00
} else if ( ! is_null ( $contollerbutton )) {
2012-03-14 14:38:08 +13:00
$newselectvalue = ( int ) ! $selectvalue ;
2007-12-04 10:35:25 +00:00
}
2012-03-09 14:15:02 +08:00
// set checkbox state depending on orignal/submitted value by controoler button
2012-03-14 14:38:08 +13:00
if ( ! is_null ( $contollerbutton ) || is_null ( $selectvalue )) {
2012-03-09 14:15:02 +08:00
foreach ( $mform -> _elements as $element ) {
if (( $element instanceof MoodleQuickForm_advcheckbox ) &&
2012-03-22 10:28:39 +08:00
$element -> getAttribute ( 'class' ) == $checkboxgroupclass &&
! $element -> isFrozen ()) {
2012-03-14 14:38:08 +13:00
$mform -> setConstants ( array ( $element -> getName () => $newselectvalue ));
2012-03-09 14:15:02 +08:00
}
}
}
2007-12-04 10:35:25 +00:00
2012-03-14 14:38:08 +13:00
$mform -> addElement ( 'hidden' , $checkboxcontrollerparam , $newselectvalue , array ( 'id' => " id_ " . $checkboxcontrollerparam ));
2012-03-09 14:15:02 +08:00
$mform -> setType ( $checkboxcontrollerparam , PARAM_INT );
2012-03-14 14:38:08 +13:00
$mform -> setConstants ( array ( $checkboxcontrollerparam => $newselectvalue ));
2008-07-31 22:15:30 +00:00
2012-03-06 12:06:59 +08:00
$PAGE -> requires -> yui_module ( 'moodle-form-checkboxcontroller' , 'M.form.checkboxcontroller' ,
array (
array ( 'groupid' => $groupid ,
2012-03-09 14:15:02 +08:00
'checkboxclass' => $checkboxgroupclass ,
'checkboxcontroller' => $checkboxcontrollerparam ,
'controllerbutton' => $checkboxcontrollername )
2012-03-06 12:06:59 +08:00
)
);
require_once ( " $CFG->libdir /form/submit.php " );
2012-03-09 14:15:02 +08:00
$submitlink = new MoodleQuickForm_submit ( $checkboxcontrollername , $attributes );
2008-07-31 22:15:30 +00:00
$mform -> addElement ( $submitlink );
2012-03-09 14:15:02 +08:00
$mform -> registerNoSubmitButton ( $checkboxcontrollername );
$mform -> setDefault ( $checkboxcontrollername , $text );
2007-12-04 10:35:25 +00:00
}
2006-12-19 07:03:08 +00:00
/**
2006-12-28 15:43:47 +00:00
* Use this method to a cancel and submit button to the end of your form . Pass a param of false
2006-12-19 07:03:08 +00:00
* if you don ' t want a cancel button in your form . If you have a cancel button make sure you
* check for it being pressed using is_cancelled () and redirecting if it is true before trying to
2007-01-12 18:52:09 +00:00
* get data with get_data () .
2006-12-19 07:03:08 +00:00
*
2012-01-06 16:38:06 +08:00
* @ param bool $cancel whether to show cancel button , default true
2006-12-19 07:03:08 +00:00
* @ param string $submitlabel label for submit button , defaults to get_string ( 'savechanges' )
*/
2006-12-28 15:43:47 +00:00
function add_action_buttons ( $cancel = true , $submitlabel = null ){
2006-12-19 07:03:08 +00:00
if ( is_null ( $submitlabel )){
$submitlabel = get_string ( 'savechanges' );
}
$mform =& $this -> _form ;
2006-12-28 15:43:47 +00:00
if ( $cancel ){
//when two elements we need a group
2006-12-19 07:03:08 +00:00
$buttonarray = array ();
$buttonarray [] = & $mform -> createElement ( 'submit' , 'submitbutton' , $submitlabel );
2006-12-28 15:43:47 +00:00
$buttonarray [] = & $mform -> createElement ( 'cancel' );
2006-12-19 07:03:08 +00:00
$mform -> addGroup ( $buttonarray , 'buttonar' , '' , array ( ' ' ), false );
2007-08-03 13:08:05 +00:00
$mform -> closeHeaderBefore ( 'buttonar' );
2006-12-19 07:03:08 +00:00
} else {
//no group needed
$mform -> addElement ( 'submit' , 'submitbutton' , $submitlabel );
2007-08-03 13:08:05 +00:00
$mform -> closeHeaderBefore ( 'submitbutton' );
2006-12-19 07:03:08 +00:00
}
}
2010-05-18 07:58:45 +00:00
/**
2010-05-22 19:10:44 +00:00
* Adds an initialisation call for a standard JavaScript enhancement .
2010-05-18 07:58:45 +00:00
*
* This function is designed to add an initialisation call for a JavaScript
2010-05-22 19:10:44 +00:00
* enhancement that should exist within javascript - static M . form . init_ { enhancementname } .
2010-05-18 07:58:45 +00:00
*
* Current options :
* - Selectboxes
* - smartselect : Turns a nbsp indented select box into a custom drop down
* control that supports multilevel and category selection .
* $enhancement = 'smartselect' ;
* $options = array ( 'selectablecategories' => true | false )
*
2012-01-06 16:38:06 +08:00
* @ since Moodle 2.0
* @ param string | element $element form element for which Javascript needs to be initalized
* @ param string $enhancement which init function should be called
* @ param array $options options passed to javascript
* @ param array $strings strings for javascript
2010-05-18 07:58:45 +00:00
*/
function init_javascript_enhancement ( $element , $enhancement , array $options = array (), array $strings = null ) {
global $PAGE ;
if ( is_string ( $element )) {
$element = $this -> _form -> getElement ( $element );
2010-08-19 05:43:06 +00:00
}
2010-05-18 07:58:45 +00:00
if ( is_object ( $element )) {
$element -> _generateId ();
$elementid = $element -> getAttribute ( 'id' );
$PAGE -> requires -> js_init_call ( 'M.form.init_' . $enhancement , array ( $elementid , $options ));
if ( is_array ( $strings )) {
foreach ( $strings as $string ) {
if ( is_array ( $string )) {
2015-12-14 12:43:03 +08:00
call_user_func_array ( array ( $PAGE -> requires , 'string_for_js' ), $string );
2010-05-18 07:58:45 +00:00
} else {
$PAGE -> requires -> string_for_js ( $string , 'moodle' );
}
}
}
}
}
2010-08-19 05:43:06 +00:00
/**
* Returns a JS module definition for the mforms JS
2012-01-06 16:38:06 +08:00
*
2010-08-19 05:43:06 +00:00
* @ return array
*/
public static function get_js_module () {
global $CFG ;
return array (
'name' => 'mform' ,
'fullpath' => '/lib/form/form.js' ,
2013-01-24 14:28:40 +00:00
'requires' => array ( 'base' , 'node' )
2010-08-19 05:43:06 +00:00
);
}
2013-03-22 16:38:10 +08:00
/**
* Detects elements with missing setType () declerations .
*
* Finds elements in the form which should a PARAM_ type set and throws a
* developer debug warning for any elements without it . This is to reduce the
* risk of potential security issues by developers mistakenly forgetting to set
* the type .
*
* @ return void
*/
private function detectMissingSetType () {
2013-08-10 22:46:49 +02:00
global $CFG ;
if ( ! $CFG -> debugdeveloper ) {
2013-03-22 16:38:10 +08:00
// Only for devs.
return ;
}
$mform = $this -> _form ;
foreach ( $mform -> _elements as $element ) {
2013-05-08 15:51:54 +08:00
$group = false ;
$elements = array ( $element );
if ( $element -> getType () == 'group' ) {
$group = $element ;
$elements = $element -> getElements ();
}
foreach ( $elements as $index => $element ) {
switch ( $element -> getType ()) {
case 'hidden' :
case 'text' :
case 'url' :
if ( $group ) {
$name = $group -> getElementName ( $index );
} else {
$name = $element -> getName ();
}
$key = $name ;
$found = array_key_exists ( $key , $mform -> _types );
// For repeated elements we need to look for
// the "main" type, not for the one present
// on each repetition. All the stuff in formslib
// (repeat_elements(), updateSubmission()... seems
// to work that way.
while ( ! $found && strrpos ( $key , '[' ) !== false ) {
$pos = strrpos ( $key , '[' );
$key = substr ( $key , 0 , $pos );
$found = array_key_exists ( $key , $mform -> _types );
}
if ( ! $found ) {
debugging ( " Did you remember to call setType() for ' $name '? " .
'Defaulting to PARAM_RAW cleaning.' , DEBUG_DEVELOPER );
}
break ;
}
2013-03-22 16:38:10 +08:00
}
}
}
2013-06-20 13:18:42 +07:00
/**
* Used by tests to simulate submitted form data submission from the user .
*
* For form fields where no data is submitted the default for that field as set by set_data or setDefault will be passed to
* get_data .
*
* This method sets $_POST or $_GET and $_FILES with the data supplied . Our unit test code empties all these
* global arrays after each test .
*
* @ param array $simulatedsubmitteddata An associative array of form values ( same format as $_POST ) .
* @ param array $simulatedsubmittedfiles An associative array of files uploaded ( same format as $_FILES ) . Can be omitted .
* @ param string $method 'post' or 'get' , defaults to 'post' .
* @ param null $formidentifier the default is to use the class name for this class but you may need to provide
* a different value here for some forms that are used more than once on the
* same page .
*/
public static function mock_submit ( $simulatedsubmitteddata , $simulatedsubmittedfiles = array (), $method = 'post' ,
$formidentifier = null ) {
$_FILES = $simulatedsubmittedfiles ;
if ( $formidentifier === null ) {
$formidentifier = get_called_class ();
}
$simulatedsubmitteddata [ '_qf__' . $formidentifier ] = 1 ;
$simulatedsubmitteddata [ 'sesskey' ] = sesskey ();
if ( strtolower ( $method ) === 'get' ) {
$_GET = $simulatedsubmitteddata ;
} else {
$_POST = $simulatedsubmitteddata ;
}
}
2006-10-12 07:33:57 +00:00
}
2006-11-12 07:28:13 +00:00
/**
2012-01-06 16:38:06 +08:00
* MoodleQuickForm implementation
*
2006-11-12 07:28:13 +00:00
* You never extend this class directly . The class methods of this class are available from
2007-12-04 10:35:25 +00:00
* the private $this -> _form property on moodleform and its children . You generally only
2006-11-12 07:28:13 +00:00
* call methods on this class from within abstract methods that you override on moodleform such
* as definition and definition_after_data
*
2012-01-06 16:38:06 +08:00
* @ package core_form
* @ category form
* @ copyright 2006 Jamie Pratt < me @ jamiep . org >
2009-05-25 08:27:25 +00:00
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2006-11-12 07:28:13 +00:00
*/
2006-10-12 07:33:57 +00:00
class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
2012-01-06 16:38:06 +08:00
/** @var array type (PARAM_INT, PARAM_TEXT etc) of element value */
2006-10-12 07:33:57 +00:00
var $_types = array ();
2012-01-06 16:38:06 +08:00
/** @var array dependent state for the element/'s */
2006-11-21 09:17:46 +00:00
var $_dependencies = array ();
2012-01-06 16:38:06 +08:00
/** @var array Array of buttons that if pressed do not result in the processing of the form. */
2006-12-04 09:36:30 +00:00
var $_noSubmitButtons = array ();
2012-01-06 16:38:06 +08:00
/** @var array Array of buttons that if pressed do not result in the processing of the form. */
2006-12-04 09:36:30 +00:00
var $_cancelButtons = array ();
2006-10-12 07:33:57 +00:00
2012-01-06 16:38:06 +08:00
/** @var array Array whose keys are element names. If the key exists this is a advanced element */
2006-12-14 12:44:10 +00:00
var $_advancedElements = array ();
2013-02-07 14:13:36 +00:00
/**
2013-03-13 18:30:27 +08:00
* Array whose keys are element names and values are the desired collapsible state .
* True for collapsed , False for expanded . If not present , set to default in
* { @ link self :: accept ()} .
2013-02-07 14:13:36 +00:00
*
* @ var array
*/
var $_collapsibleElements = array ();
/**
* Whether to enable shortforms for this form
*
* @ var boolean
*/
var $_disableShortforms = false ;
2012-10-05 17:12:11 +01:00
/** @var bool whether to automatically initialise M.formchangechecker for this form. */
protected $_use_form_change_checker = true ;
2006-12-28 09:32:45 +00:00
/**
2010-05-22 19:10:44 +00:00
* The form name is derived from the class name of the wrapper minus the trailing form
2012-01-06 16:38:06 +08:00
* It is a name with words joined by underscores whereas the id attribute is words joined by underscores .
* @ var string
2006-12-28 09:32:45 +00:00
*/
var $_formName = '' ;
2007-07-06 04:03:51 +00:00
2007-08-03 13:08:05 +00:00
/**
2012-01-06 16:38:06 +08:00
* String with the html for hidden params passed in as part of a moodle_url
* object for the action . Output in the form .
2007-08-03 13:08:05 +00:00
* @ var string
*/
var $_pageparams = '' ;
2006-09-24 17:04:51 +00:00
/**
* Class constructor - same parameters as HTML_QuickForm_DHTMLRulesTableless
2009-05-25 08:27:25 +00:00
*
2012-01-06 16:38:06 +08:00
* @ staticvar int $formcounter counts number of forms
* @ param string $formName Form ' s name .
* @ param string $method Form 's method defaults to ' POST '
* @ param string | moodle_url $action Form ' s action
* @ param string $target ( optional ) Form ' s target defaults to none
* @ param mixed $attributes ( optional ) Extra attributes for < form > tag
2006-09-24 17:04:51 +00:00
*/
2015-11-05 17:01:34 +08:00
public function __construct ( $formName , $method , $action , $target = '' , $attributes = null ) {
2009-07-01 04:11:52 +00:00
global $CFG , $OUTPUT ;
2007-01-27 19:56:08 +00:00
2007-01-07 12:46:47 +00:00
static $formcounter = 1 ;
2006-10-12 07:33:57 +00:00
2015-12-10 13:37:57 +08:00
// TODO MDL-52313 Replace with the call to parent::__construct().
2015-11-05 17:01:34 +08:00
HTML_Common :: __construct ( $attributes );
2006-09-24 17:04:51 +00:00
$target = empty ( $target ) ? array () : array ( 'target' => $target );
2006-12-28 09:32:45 +00:00
$this -> _formName = $formName ;
2007-08-03 13:08:05 +00:00
if ( is_a ( $action , 'moodle_url' )){
2010-01-17 09:06:55 +00:00
$this -> _pageparams = html_writer :: input_hidden_params ( $action );
2010-01-17 09:37:30 +00:00
$action = $action -> out_omit_querystring ();
2007-08-03 13:08:05 +00:00
} else {
$this -> _pageparams = '' ;
}
2012-09-13 14:48:01 +08:00
// No 'name' atttribute for form in xhtml strict :
$attributes = array ( 'action' => $action , 'method' => $method , 'accept-charset' => 'utf-8' ) + $target ;
if ( is_null ( $this -> getAttribute ( 'id' ))) {
$attributes [ 'id' ] = 'mform' . $formcounter ;
}
2007-01-07 12:46:47 +00:00
$formcounter ++ ;
2006-09-24 17:04:51 +00:00
$this -> updateAttributes ( $attributes );
2012-09-13 14:48:01 +08:00
// This is custom stuff for Moodle :
2006-09-24 17:04:51 +00:00
$oldclass = $this -> getAttribute ( 'class' );
if ( ! empty ( $oldclass )){
$this -> updateAttributes ( array ( 'class' => $oldclass . ' mform' ));
} else {
2006-09-26 09:42:42 +00:00
$this -> updateAttributes ( array ( 'class' => 'mform' ));
2006-09-24 17:04:51 +00:00
}
2009-12-16 21:50:45 +00:00
$this -> _reqHTML = '<img class="req" title="' . get_string ( 'requiredelement' , 'form' ) . '" alt="' . get_string ( 'requiredelement' , 'form' ) . '" src="' . $OUTPUT -> pix_url ( 'req' ) . '" />' ;
$this -> _advancedHTML = '<img class="adv" title="' . get_string ( 'advancedelement' , 'form' ) . '" alt="' . get_string ( 'advancedelement' , 'form' ) . '" src="' . $OUTPUT -> pix_url ( 'adv' ) . '" />' ;
$this -> setRequiredNote ( get_string ( 'somefieldsrequired' , 'form' , '<img alt="' . get_string ( 'requiredelement' , 'form' ) . '" src="' . $OUTPUT -> pix_url ( 'req' ) . '" />' ));
2006-12-14 12:44:10 +00:00
}
2015-11-05 17:01:34 +08:00
/**
* Old syntax of class constructor . Deprecated in PHP7 .
*
* @ deprecated since Moodle 3.1
*/
public function MoodleQuickForm ( $formName , $method , $action , $target = '' , $attributes = null ) {
debugging ( 'Use of class name as constructor is deprecated' , DEBUG_DEVELOPER );
self :: __construct ( $formName , $method , $action , $target , $attributes );
}
2006-12-19 07:03:08 +00:00
/**
* Use this method to indicate an element in a form is an advanced field . If items in a form
* are marked as advanced then 'Hide/Show Advanced' buttons will automatically be displayed in the
* form so the user can decide whether to display advanced form controls .
*
* If you set a header element to advanced then all elements it contains will also be set as advanced .
*
* @ param string $elementName group or element name ( not the element name of something inside a group ) .
2012-01-06 16:38:06 +08:00
* @ param bool $advanced default true sets the element to advanced . False removes advanced mark .
2006-12-19 07:03:08 +00:00
*/
2013-03-13 18:30:27 +08:00
function setAdvanced ( $elementName , $advanced = true ) {
2006-12-19 07:03:08 +00:00
if ( $advanced ){
$this -> _advancedElements [ $elementName ] = '' ;
} elseif ( isset ( $this -> _advancedElements [ $elementName ])) {
unset ( $this -> _advancedElements [ $elementName ]);
}
}
2013-02-07 14:13:36 +00:00
/**
* Use this method to indicate that the fieldset should be shown as expanded .
* The method is applicable to header elements only .
*
2013-03-12 15:05:17 +08:00
* @ param string $headername header element name
2013-02-07 14:13:36 +00:00
* @ param boolean $expanded default true sets the element to expanded . False makes the element collapsed .
2013-03-13 18:30:27 +08:00
* @ param boolean $ignoreuserstate override the state regardless of the state it was on when
* the form was submitted .
2013-03-12 15:05:17 +08:00
* @ return void
2013-02-07 14:13:36 +00:00
*/
2013-03-13 18:30:27 +08:00
function setExpanded ( $headername , $expanded = true , $ignoreuserstate = false ) {
2013-03-12 17:18:00 +08:00
if ( empty ( $headername )) {
return ;
}
2013-03-12 15:05:17 +08:00
$element = $this -> getElement ( $headername );
if ( $element -> getType () != 'header' ) {
debugging ( 'Cannot use setExpanded on non-header elements' , DEBUG_DEVELOPER );
return ;
}
if ( ! $headerid = $element -> getAttribute ( 'id' )) {
$element -> _generateId ();
$headerid = $element -> getAttribute ( 'id' );
}
if ( $this -> getElementType ( 'mform_isexpanded_' . $headerid ) === false ) {
2013-03-13 18:30:27 +08:00
// See if the form has been submitted already.
2013-02-07 20:44:17 +00:00
$formexpanded = optional_param ( 'mform_isexpanded_' . $headerid , - 1 , PARAM_INT );
2013-03-13 18:30:27 +08:00
if ( ! $ignoreuserstate && $formexpanded != - 1 ) {
2013-03-12 15:05:17 +08:00
// Override expanded state with the form variable.
2013-02-07 14:13:36 +00:00
$expanded = $formexpanded ;
}
2013-03-12 15:05:17 +08:00
// Create the form element for storing expanded state.
2013-02-07 20:44:17 +00:00
$this -> addElement ( 'hidden' , 'mform_isexpanded_' . $headerid );
$this -> setType ( 'mform_isexpanded_' . $headerid , PARAM_INT );
2013-03-12 15:05:17 +08:00
$this -> setConstant ( 'mform_isexpanded_' . $headerid , ( int ) $expanded );
2013-02-07 14:13:36 +00:00
}
2013-03-12 15:05:17 +08:00
$this -> _collapsibleElements [ $headername ] = ! $expanded ;
2013-02-07 14:13:36 +00:00
}
/**
2013-01-24 14:28:40 +00:00
* Use this method to add show more / less status element required for passing
* over the advanced elements visibility status on the form submission .
2006-12-19 07:03:08 +00:00
*
2013-02-11 10:11:20 +08:00
* @ param string $headerName header element name .
2013-01-24 14:28:40 +00:00
* @ param boolean $showmore default false sets the advanced elements to be hidden .
2006-12-19 07:03:08 +00:00
*/
2013-02-07 20:44:17 +00:00
function addAdvancedStatusElement ( $headerid , $showmore = false ){
2013-02-11 10:11:20 +08:00
// Add extra hidden element to store advanced items state for each section.
2013-02-07 20:44:17 +00:00
if ( $this -> getElementType ( 'mform_showmore_' . $headerid ) === false ) {
2013-02-11 10:11:20 +08:00
// See if we the form has been submitted already.
2013-02-07 20:44:17 +00:00
$formshowmore = optional_param ( 'mform_showmore_' . $headerid , - 1 , PARAM_INT );
2013-01-24 14:28:40 +00:00
if ( ! $showmore && $formshowmore != - 1 ) {
2013-02-11 10:11:20 +08:00
// Override showmore state with the form variable.
2013-01-24 14:28:40 +00:00
$showmore = $formshowmore ;
2006-12-19 07:03:08 +00:00
}
2013-02-11 10:11:20 +08:00
// Create the form element for storing advanced items state.
2013-02-07 20:44:17 +00:00
$this -> addElement ( 'hidden' , 'mform_showmore_' . $headerid );
$this -> setType ( 'mform_showmore_' . $headerid , PARAM_INT );
$this -> setConstant ( 'mform_showmore_' . $headerid , ( int ) $showmore );
2006-12-19 07:03:08 +00:00
}
2006-12-14 12:44:10 +00:00
}
2012-01-06 16:38:06 +08:00
2013-02-11 10:11:20 +08:00
/**
* This function has been deprecated . Show advanced has been replaced by
* " Show more.../Show less... " in the shortforms javascript module .
*
* @ deprecated since Moodle 2.5
* @ param bool $showadvancedNow if true will show advanced elements .
*/
function setShowAdvanced ( $showadvancedNow = null ){
debugging ( 'Call to deprecated function setShowAdvanced. See "Show more.../Show less..." in shortforms yui module.' );
}
/**
* This function has been deprecated . Show advanced has been replaced by
* " Show more.../Show less... " in the shortforms javascript module .
*
* @ deprecated since Moodle 2.5
* @ return bool ( Always false )
*/
function getShowAdvanced (){
debugging ( 'Call to deprecated function setShowAdvanced. See "Show more.../Show less..." in shortforms yui module.' );
return false ;
}
2012-01-06 16:38:06 +08:00
/**
2013-01-24 14:28:40 +00:00
* Use this method to indicate that the form will not be using shortforms .
2012-01-06 16:38:06 +08:00
*
2013-01-24 14:28:40 +00:00
* @ param boolean $disable default true , controls if the shortforms are disabled .
2012-01-06 16:38:06 +08:00
*/
2013-01-24 14:28:40 +00:00
function setDisableShortforms ( $disable = true ) {
$this -> _disableShortforms = $disable ;
2006-12-14 12:44:10 +00:00
}
2012-10-05 17:12:11 +01:00
/**
* Call this method if you don ' t want the formchangechecker JavaScript to be
* automatically initialised for this form .
*/
public function disable_form_change_checker () {
$this -> _use_form_change_checker = false ;
}
2006-12-14 12:44:10 +00:00
2012-10-05 17:12:11 +01:00
/**
* If you have called { @ link disable_form_change_checker ()} then you can use
* this method to re - enable it . It is enabled by default , so normally you don ' t
* need to call this .
*/
public function enable_form_change_checker () {
$this -> _use_form_change_checker = true ;
}
/**
* @ return bool whether this form should automatically initialise
* formchangechecker for itself .
*/
public function is_form_change_checker_enabled () {
return $this -> _use_form_change_checker ;
}
/**
2006-12-14 12:44:10 +00:00
* Accepts a renderer
*
2012-01-06 16:38:06 +08:00
* @ param HTML_QuickForm_Renderer $renderer An HTML_QuickForm_Renderer object
2006-12-14 12:44:10 +00:00
*/
2007-11-12 17:12:35 +00:00
function accept ( & $renderer ) {
2006-12-14 12:44:10 +00:00
if ( method_exists ( $renderer , 'setAdvancedElements' )){
2013-02-07 14:13:36 +00:00
//Check for visible fieldsets where all elements are advanced
2006-12-14 12:44:10 +00:00
//and mark these headers as advanced as well.
2013-02-07 14:13:36 +00:00
//Also mark all elements in a advanced header as advanced.
2006-12-14 12:44:10 +00:00
$stopFields = $renderer -> getStopFieldSetElements ();
$lastHeader = null ;
$lastHeaderAdvanced = false ;
$anyAdvanced = false ;
2013-01-24 14:28:40 +00:00
$anyError = false ;
2006-12-14 12:44:10 +00:00
foreach ( array_keys ( $this -> _elements ) as $elementIndex ){
$element =& $this -> _elements [ $elementIndex ];
2007-11-12 17:12:35 +00:00
// if closing header and any contained element was advanced then mark it as advanced
2006-12-14 12:44:10 +00:00
if ( $element -> getType () == 'header' || in_array ( $element -> getName (), $stopFields )){
2013-02-07 20:44:17 +00:00
if ( $anyAdvanced && ! is_null ( $lastHeader )) {
$lastHeader -> _generateId ();
2006-12-14 12:44:10 +00:00
$this -> setAdvanced ( $lastHeader -> getName ());
2013-02-07 20:44:17 +00:00
$this -> addAdvancedStatusElement ( $lastHeader -> getAttribute ( 'id' ), $anyError );
2006-12-14 12:44:10 +00:00
}
$lastHeaderAdvanced = false ;
2007-11-12 17:12:35 +00:00
unset ( $lastHeader );
$lastHeader = null ;
2006-12-14 12:44:10 +00:00
} elseif ( $lastHeaderAdvanced ) {
$this -> setAdvanced ( $element -> getName ());
}
2007-11-12 17:12:35 +00:00
2006-12-14 12:44:10 +00:00
if ( $element -> getType () == 'header' ){
$lastHeader =& $element ;
$anyAdvanced = false ;
2013-01-24 14:28:40 +00:00
$anyError = false ;
2006-12-14 12:44:10 +00:00
$lastHeaderAdvanced = isset ( $this -> _advancedElements [ $element -> getName ()]);
} elseif ( isset ( $this -> _advancedElements [ $element -> getName ()])){
$anyAdvanced = true ;
2013-01-24 14:28:40 +00:00
if ( isset ( $this -> _errors [ $element -> getName ()])) {
$anyError = true ;
}
2006-12-14 12:44:10 +00:00
}
}
2007-11-12 17:12:35 +00:00
// the last header may not be closed yet...
if ( $anyAdvanced && ! is_null ( $lastHeader )){
$this -> setAdvanced ( $lastHeader -> getName ());
2013-02-07 20:44:17 +00:00
$lastHeader -> _generateId ();
$this -> addAdvancedStatusElement ( $lastHeader -> getAttribute ( 'id' ), $anyError );
2007-11-12 17:12:35 +00:00
}
2006-12-14 12:44:10 +00:00
$renderer -> setAdvancedElements ( $this -> _advancedElements );
2013-02-07 14:13:36 +00:00
}
2013-03-13 18:30:27 +08:00
if ( method_exists ( $renderer , 'setCollapsibleElements' ) && ! $this -> _disableShortforms ) {
// Count the number of sections.
$headerscount = 0 ;
foreach ( array_keys ( $this -> _elements ) as $elementIndex ){
$element =& $this -> _elements [ $elementIndex ];
if ( $element -> getType () == 'header' ) {
$headerscount ++ ;
}
}
$anyrequiredorerror = false ;
2013-02-07 14:13:36 +00:00
$headercounter = 0 ;
2013-03-13 18:30:27 +08:00
$headername = null ;
2013-02-07 14:13:36 +00:00
foreach ( array_keys ( $this -> _elements ) as $elementIndex ){
$element =& $this -> _elements [ $elementIndex ];
2013-03-13 18:30:27 +08:00
2013-03-12 12:20:33 +08:00
if ( $element -> getType () == 'header' ) {
2013-02-07 14:13:36 +00:00
$headercounter ++ ;
2013-03-13 18:30:27 +08:00
$element -> _generateId ();
$headername = $element -> getName ();
$anyrequiredorerror = false ;
} else if ( in_array ( $element -> getName (), $this -> _required ) || isset ( $this -> _errors [ $element -> getName ()])) {
$anyrequiredorerror = true ;
} else {
// Do not reset $anyrequiredorerror to false because we do not want any other element
// in this header (fieldset) to possibly revert the state given.
2013-02-07 14:13:36 +00:00
}
2013-03-12 12:20:33 +08:00
2013-03-13 18:30:27 +08:00
if ( $element -> getType () == 'header' ) {
if ( $headercounter === 1 && ! isset ( $this -> _collapsibleElements [ $headername ])) {
// By default the first section is always expanded, except if a state has already been set.
$this -> setExpanded ( $headername , true );
} else if (( $headercounter === 2 && $headerscount === 2 ) && ! isset ( $this -> _collapsibleElements [ $headername ])) {
// The second section is always expanded if the form only contains 2 sections),
// except if a state has already been set.
2013-03-12 12:20:33 +08:00
$this -> setExpanded ( $headername , true );
2013-02-07 14:13:36 +00:00
}
2013-03-13 18:30:27 +08:00
} else if ( $anyrequiredorerror ) {
// If any error or required field are present within the header, we need to expand it.
$this -> setExpanded ( $headername , true , true );
} else if ( ! isset ( $this -> _collapsibleElements [ $headername ])) {
// Define element as collapsed by default.
$this -> setExpanded ( $headername , false );
2013-02-07 14:13:36 +00:00
}
}
2013-03-13 18:30:27 +08:00
2013-02-07 14:13:36 +00:00
// Pass the array to renderer object.
2013-03-12 15:05:17 +08:00
$renderer -> setCollapsibleElements ( $this -> _collapsibleElements );
2006-12-14 12:44:10 +00:00
}
parent :: accept ( $renderer );
}
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Adds one or more element names that indicate the end of a fieldset
*
* @ param string $elementName name of the element
2009-05-25 08:27:25 +00:00
*/
2006-12-14 12:44:10 +00:00
function closeHeaderBefore ( $elementName ){
$renderer =& $this -> defaultRenderer ();
$renderer -> addStopFieldsetElements ( $elementName );
2006-09-24 17:04:51 +00:00
}
2006-11-08 06:22:58 +00:00
2006-11-12 07:28:13 +00:00
/**
* Should be used for all elements of a form except for select , radio and checkboxes which
* clean their own data .
*
* @ param string $elementname
2012-01-06 16:38:06 +08:00
* @ param int $paramtype defines type of data contained in element . Use the constants PARAM_ *.
2012-02-21 12:39:35 +13:00
* { @ link lib / moodlelib . php } for defined parameter types
2006-11-12 07:28:13 +00:00
*/
2006-10-12 07:33:57 +00:00
function setType ( $elementname , $paramtype ) {
$this -> _types [ $elementname ] = $paramtype ;
}
2006-11-09 08:38:40 +00:00
2006-11-12 07:28:13 +00:00
/**
2012-01-06 16:38:06 +08:00
* This can be used to set several types at once .
2006-11-12 07:28:13 +00:00
*
2012-01-06 16:38:06 +08:00
* @ param array $paramtypes types of parameters .
* @ see MoodleQuickForm :: setType
2006-11-12 07:28:13 +00:00
*/
2006-10-12 14:15:59 +00:00
function setTypes ( $paramtypes ) {
$this -> _types = $paramtypes + $this -> _types ;
}
2006-11-09 08:38:40 +00:00
2013-05-08 15:50:33 +08:00
/**
* Return the type ( s ) to use to clean an element .
*
* In the case where the element has an array as a value , we will try to obtain a
* type defined for that specific key , and recursively until done .
*
* This method does not work reverse , you cannot pass a nested element and hoping to
* fallback on the clean type of a parent . This method intends to be used with the
* main element , which will generate child types if needed , not the other way around .
*
* Example scenario :
*
* You have defined a new repeated element containing a text field called 'foo' .
* By default there will always be 2 occurence of 'foo' in the form . Even though
* you 've set the type on ' foo ' to be PARAM_INT , for some obscure reason , you want
* the first value of 'foo' , to be PARAM_FLOAT , which you set using setType :
* $mform -> setType ( 'foo[0]' , PARAM_FLOAT ) .
*
* Now if you call this method passing 'foo' , along with the submitted values of 'foo' :
* array ( 0 => '1.23' , 1 => '10' ), you will get an array telling you that the key 0 is a
* FLOAT and 1 is an INT . If you had passed 'foo[1]' , along with its value '10' , you would
2013-05-10 08:34:59 +08:00
* get the default clean type returned ( param $default ) .
2013-05-08 15:50:33 +08:00
*
* @ param string $elementname name of the element .
* @ param mixed $value value that should be cleaned .
2013-05-10 08:34:59 +08:00
* @ param int $default default constant value to be returned ( PARAM_ ... )
2013-05-08 15:50:33 +08:00
* @ return string | array constant value or array of constant values ( PARAM_ ... )
*/
public function getCleanType ( $elementname , $value , $default = PARAM_RAW ) {
$type = $default ;
if ( array_key_exists ( $elementname , $this -> _types )) {
$type = $this -> _types [ $elementname ];
}
if ( is_array ( $value )) {
$default = $type ;
$type = array ();
foreach ( $value as $subkey => $subvalue ) {
$typekey = " $elementname " . " [ $subkey ] " ;
if ( array_key_exists ( $typekey , $this -> _types )) {
$subtype = $this -> _types [ $typekey ];
} else {
$subtype = $default ;
}
if ( is_array ( $subvalue )) {
$type [ $subkey ] = $this -> getCleanType ( $typekey , $subvalue , $subtype );
} else {
$type [ $subkey ] = $subtype ;
}
}
}
return $type ;
}
/**
* Return the cleaned value using the passed type ( s ) .
*
* @ param mixed $value value that has to be cleaned .
* @ param int | array $type constant value to use to clean ( PARAM_ ... ), typically returned by { @ link self :: getCleanType ()} .
* @ return mixed cleaned up value .
*/
public function getCleanedValue ( $value , $type ) {
if ( is_array ( $type ) && is_array ( $value )) {
foreach ( $type as $key => $param ) {
$value [ $key ] = $this -> getCleanedValue ( $value [ $key ], $param );
}
} else if ( ! is_array ( $type ) && ! is_array ( $value )) {
$value = clean_param ( $value , $type );
} else if ( ! is_array ( $type ) && is_array ( $value )) {
$value = clean_param_array ( $value , $type , true );
} else {
2013-05-10 08:34:59 +08:00
throw new coding_exception ( 'Unexpected type or value received in MoodleQuickForm::getCleanedValue()' );
2013-05-08 15:50:33 +08:00
}
return $value ;
}
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Updates submitted values
*
* @ param array $submission submitted values
* @ param array $files list of files
2009-05-25 08:27:25 +00:00
*/
2006-11-09 08:38:40 +00:00
function updateSubmission ( $submission , $files ) {
$this -> _flagSubmitted = false ;
2006-10-12 07:33:57 +00:00
if ( empty ( $submission )) {
$this -> _submitValues = array ();
} else {
2013-05-08 15:50:33 +08:00
foreach ( $submission as $key => $s ) {
$type = $this -> getCleanType ( $key , $s );
$submission [ $key ] = $this -> getCleanedValue ( $s , $type );
2006-10-12 07:33:57 +00:00
}
2008-06-09 16:53:30 +00:00
$this -> _submitValues = $submission ;
2006-10-12 07:33:57 +00:00
$this -> _flagSubmitted = true ;
}
2006-11-09 08:38:40 +00:00
if ( empty ( $files )) {
$this -> _submitFiles = array ();
} else {
$this -> _submitFiles = $files ;
$this -> _flagSubmitted = true ;
}
2006-10-24 11:05:50 +00:00
// need to tell all elements that they need to update their value attribute.
foreach ( array_keys ( $this -> _elements ) as $key ) {
$this -> _elements [ $key ] -> onQuickFormEvent ( 'updateValue' , null , $this );
}
2006-10-12 07:33:57 +00:00
}
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Returns HTML for required elements
*
2009-05-25 08:27:25 +00:00
* @ return string
*/
2006-09-24 17:04:51 +00:00
function getReqHTML (){
return $this -> _reqHTML ;
}
2009-11-01 11:31:16 +00:00
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Returns HTML for advanced elements
*
2009-05-25 08:27:25 +00:00
* @ return string
*/
2006-12-14 12:44:10 +00:00
function getAdvancedHTML (){
return $this -> _advancedHTML ;
}
2006-10-12 07:33:57 +00:00
/**
2006-11-12 07:28:13 +00:00
* Initializes a default form value . Used to specify the default for a new entry where
2007-01-12 18:52:09 +00:00
* no data is loaded in using moodleform :: set_data ()
2006-10-12 07:33:57 +00:00
*
2008-06-09 16:53:30 +00:00
* note : $slashed param removed
*
2012-01-06 16:38:06 +08:00
* @ param string $elementName element name
* @ param mixed $defaultValue values for that element name
2006-10-12 07:33:57 +00:00
*/
2008-06-09 16:53:30 +00:00
function setDefault ( $elementName , $defaultValue ){
$this -> setDefaults ( array ( $elementName => $defaultValue ));
2012-01-06 16:38:06 +08:00
}
2010-04-10 09:10:08 +00:00
/**
2010-04-13 21:51:49 +00:00
* Add a help button to element , only one button per element is allowed .
*
2010-04-30 09:57:32 +00:00
* This is new , simplified and preferable method of setting a help icon on form elements .
* It uses the new $OUTPUT -> help_icon () .
*
* Typically , you will provide the same identifier and the component as you have used for the
* label of the element . The string identifier with the _help suffix added is then used
* as the help string .
*
2010-04-13 21:51:49 +00:00
* There has to be two strings defined :
* 1 / get_string ( $identifier , $component ) - the title of the help page
2010-04-23 07:46:35 +00:00
* 2 / get_string ( $identifier . '_help' , $component ) - the actual help page text
2010-04-10 09:10:08 +00:00
*
2012-01-06 16:38:06 +08:00
* @ since Moodle 2.0
2010-04-10 09:10:08 +00:00
* @ param string $elementname name of the element to add the item to
2010-05-22 19:10:44 +00:00
* @ param string $identifier help string identifier without _help suffix
2010-04-30 09:57:32 +00:00
* @ param string $component component name to look the help string in
* @ param string $linktext optional text to display next to the icon
2012-01-06 16:38:06 +08:00
* @ param bool $suppresscheck set to true if the element may not exist
2010-04-10 09:10:08 +00:00
*/
2010-04-13 21:51:49 +00:00
function addHelpButton ( $elementname , $identifier , $component = 'moodle' , $linktext = '' , $suppresscheck = false ) {
global $OUTPUT ;
2010-04-10 09:10:08 +00:00
if ( array_key_exists ( $elementname , $this -> _elementIndex )) {
2010-05-20 06:26:40 +00:00
$element = $this -> _elements [ $this -> _elementIndex [ $elementname ]];
$element -> _helpbutton = $OUTPUT -> help_icon ( $identifier , $component , $linktext );
2010-04-10 09:10:08 +00:00
} else if ( ! $suppresscheck ) {
debugging ( get_string ( 'nonexistentformelements' , 'form' , $elementname ));
}
}
2008-10-13 19:39:27 +00:00
/**
2010-05-22 19:10:44 +00:00
* Set constant value not overridden by _POST or _GET
2008-10-13 19:39:27 +00:00
* note : this does not work for complex names with [] :- (
2009-05-25 08:27:25 +00:00
*
2008-10-13 19:39:27 +00:00
* @ param string $elname name of element
* @ param mixed $value
*/
function setConstant ( $elname , $value ) {
$this -> _constantValues = HTML_QuickForm :: arrayMerge ( $this -> _constantValues , array ( $elname => $value ));
$element =& $this -> getElement ( $elname );
$element -> onQuickFormEvent ( 'updateValue' , null , $this );
}
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* export submitted values
*
* @ param string $elementList list of elements in form
* @ return array
2009-05-25 08:27:25 +00:00
*/
2008-06-09 16:53:30 +00:00
function exportValues ( $elementList = null ){
2007-01-12 04:36:02 +00:00
$unfiltered = array ();
if ( null === $elementList ) {
// iterate over all elements, calling their exportValue() methods
foreach ( array_keys ( $this -> _elements ) as $key ) {
2012-08-30 15:42:54 +08:00
if ( $this -> _elements [ $key ] -> isFrozen () && ! $this -> _elements [ $key ] -> _persistantFreeze ) {
$varname = $this -> _elements [ $key ] -> _attributes [ 'name' ];
$value = '' ;
// If we have a default value then export it.
if ( isset ( $this -> _defaultValues [ $varname ])) {
2012-11-22 15:20:38 +00:00
$value = $this -> prepare_fixed_value ( $varname , $this -> _defaultValues [ $varname ]);
2012-08-30 15:42:54 +08:00
}
2007-01-12 04:36:02 +00:00
} else {
$value = $this -> _elements [ $key ] -> exportValue ( $this -> _submitValues , true );
}
if ( is_array ( $value )) {
// This shit throws a bogus warning in PHP 4.3.x
$unfiltered = HTML_QuickForm :: arrayMerge ( $unfiltered , $value );
}
}
} else {
if ( ! is_array ( $elementList )) {
$elementList = array_map ( 'trim' , explode ( ',' , $elementList ));
}
foreach ( $elementList as $elementName ) {
$value = $this -> exportValue ( $elementName );
2012-03-18 18:39:37 +01:00
if ( @ PEAR :: isError ( $value )) {
2007-01-12 04:36:02 +00:00
return $value ;
}
2008-09-07 13:30:46 +00:00
//oh, stock QuickFOrm was returning array of arrays!
$unfiltered = HTML_QuickForm :: arrayMerge ( $unfiltered , $value );
2007-01-12 04:36:02 +00:00
}
}
2006-10-12 07:33:57 +00:00
2011-02-02 10:33:16 +00:00
if ( is_array ( $this -> _constantValues )) {
$unfiltered = HTML_QuickForm :: arrayMerge ( $unfiltered , $this -> _constantValues );
}
2008-06-09 16:53:30 +00:00
return $unfiltered ;
2006-09-24 17:04:51 +00:00
}
2012-01-06 16:38:06 +08:00
2012-11-22 15:20:38 +00:00
/**
* This is a bit of a hack , and it duplicates the code in
* HTML_QuickForm_element :: _prepareValue , but I could not think of a way or
* reliably calling that code . ( Think about date selectors , for example . )
* @ param string $name the element name .
* @ param mixed $value the fixed value to set .
* @ return mixed the appropriate array to add to the $unfiltered array .
*/
protected function prepare_fixed_value ( $name , $value ) {
if ( null === $value ) {
return null ;
} else {
if ( ! strpos ( $name , '[' )) {
return array ( $name => $value );
} else {
$valueAry = array ();
$myIndex = " [' " . str_replace ( array ( ']' , '[' ), array ( '' , " '][' " ), $name ) . " '] " ;
eval ( " \$ valueAry $myIndex = \$ value; " );
return $valueAry ;
}
}
}
2006-12-28 09:32:45 +00:00
/**
* Adds a validation rule for the given field
*
* If the element is in fact a group , it will be considered as a whole .
* To validate grouped elements as separated entities ,
* use addGroupRule instead of addRule .
*
2012-01-06 16:38:06 +08:00
* @ param string $element Form element name
* @ param string $message Message to display for invalid data
* @ param string $type Rule type , use getRegisteredRules () to get types
* @ param string $format ( optional ) Required for extra rule data
* @ param string $validation ( optional ) Where to perform validation : " server " , " client "
* @ param bool $reset Client - side validation : reset the form element to its original value if there is an error ?
* @ param bool $force Force the rule to be applied , even if the target form element does not exist
2006-12-28 09:32:45 +00:00
*/
function addRule ( $element , $message , $type , $format = null , $validation = 'server' , $reset = false , $force = false )
{
parent :: addRule ( $element , $message , $type , $format , $validation , $reset , $force );
if ( $validation == 'client' ) {
$this -> updateAttributes ( array ( 'onsubmit' => 'try { var myValidator = validate_' . $this -> _formName . '; } catch(e) { return true; } return myValidator(this);' ));
}
2012-01-06 16:38:06 +08:00
}
2006-12-28 09:32:45 +00:00
/**
* Adds a validation rule for the given group of elements
*
* Only groups with a name can be assigned a validation rule
* Use addGroupRule when you need to validate elements inside the group .
* Use addRule if you need to validate the group as a whole . In this case ,
* the same rule will be applied to all elements in the group .
* Use addRule if you need to validate the group against a function .
*
2012-01-06 16:38:06 +08:00
* @ param string $group Form group name
* @ param array | string $arg1 Array for multiple elements or error message string for one element
* @ param string $type ( optional ) Rule type use getRegisteredRules () to get types
* @ param string $format ( optional ) Required for extra rule data
* @ param int $howmany ( optional ) How many valid elements should be in the group
* @ param string $validation ( optional ) Where to perform validation : " server " , " client "
* @ param bool $reset Client - side : whether to reset the element ' s value to its original state if validation failed .
2006-12-28 09:32:45 +00:00
*/
function addGroupRule ( $group , $arg1 , $type = '' , $format = null , $howmany = 0 , $validation = 'server' , $reset = false )
{
parent :: addGroupRule ( $group , $arg1 , $type , $format , $howmany , $validation , $reset );
if ( is_array ( $arg1 )) {
2007-01-21 10:32:42 +00:00
foreach ( $arg1 as $rules ) {
2006-12-28 09:32:45 +00:00
foreach ( $rules as $rule ) {
$validation = ( isset ( $rule [ 3 ]) && 'client' == $rule [ 3 ]) ? 'client' : 'server' ;
if ( 'client' == $validation ) {
$this -> updateAttributes ( array ( 'onsubmit' => 'try { var myValidator = validate_' . $this -> _formName . '; } catch(e) { return true; } return myValidator(this);' ));
}
}
}
} elseif ( is_string ( $arg1 )) {
if ( $validation == 'client' ) {
2007-01-21 10:32:42 +00:00
$this -> updateAttributes ( array ( 'onsubmit' => 'try { var myValidator = validate_' . $this -> _formName . '; } catch(e) { return true; } return myValidator(this);' ));
2006-12-28 09:32:45 +00:00
}
}
2012-01-06 16:38:06 +08:00
}
2006-12-28 09:32:45 +00:00
2006-10-14 12:32:31 +00:00
/**
* Returns the client side validation script
*
* The code here was copied from HTML_QuickForm_DHTMLRulesTableless who copied it from HTML_QuickForm
* and slightly modified to run rules per - element
* Needed to override this because of an error with client side validation of grouped elements .
*
2012-01-06 16:38:06 +08:00
* @ return string Javascript to perform validation , empty string if no 'client' rules were added
2006-10-14 12:32:31 +00:00
*/
function getValidationScript ()
{
if ( empty ( $this -> _rules ) || empty ( $this -> _attributes [ 'onsubmit' ])) {
return '' ;
}
include_once ( 'HTML/QuickForm/RuleRegistry.php' );
$registry =& HTML_QuickForm_RuleRegistry :: singleton ();
$test = array ();
$js_escape = array (
" \r " => '\r' ,
" \n " => '\n' ,
" \t " => '\t' ,
" ' " => " \\ ' " ,
'"' => '\"' ,
'\\' => '\\\\'
);
foreach ( $this -> _rules as $elementName => $rules ) {
foreach ( $rules as $rule ) {
if ( 'client' == $rule [ 'validation' ]) {
2006-11-12 07:28:13 +00:00
unset ( $element ); //TODO: find out how to properly initialize it
2006-10-14 12:32:31 +00:00
$dependent = isset ( $rule [ 'dependent' ]) && is_array ( $rule [ 'dependent' ]);
$rule [ 'message' ] = strtr ( $rule [ 'message' ], $js_escape );
if ( isset ( $rule [ 'group' ])) {
$group =& $this -> getElement ( $rule [ 'group' ]);
// No JavaScript validation for frozen elements
if ( $group -> isFrozen ()) {
continue 2 ;
}
$elements =& $group -> getElements ();
foreach ( array_keys ( $elements ) as $key ) {
if ( $elementName == $group -> getElementName ( $key )) {
$element =& $elements [ $key ];
break ;
}
}
} elseif ( $dependent ) {
$element = array ();
$element [] =& $this -> getElement ( $elementName );
2007-01-21 10:32:42 +00:00
foreach ( $rule [ 'dependent' ] as $elName ) {
2006-10-14 12:32:31 +00:00
$element [] =& $this -> getElement ( $elName );
}
} else {
$element =& $this -> getElement ( $elementName );
}
// No JavaScript validation for frozen elements
if ( is_object ( $element ) && $element -> isFrozen ()) {
continue 2 ;
} elseif ( is_array ( $element )) {
foreach ( array_keys ( $element ) as $key ) {
if ( $element [ $key ] -> isFrozen ()) {
continue 3 ;
}
}
}
2011-08-31 14:25:34 +08:00
//for editor element, [text] is appended to the name.
2013-10-15 14:30:33 +01:00
$fullelementname = $elementName ;
2011-08-31 14:25:34 +08:00
if ( $element -> getType () == 'editor' ) {
2013-10-15 14:30:33 +01:00
$fullelementname .= '[text]' ;
2011-08-31 14:25:34 +08:00
//Add format to rule as moodleform check which format is supported by browser
//it is not set anywhere... So small hack to make sure we pass it down to quickform
if ( is_null ( $rule [ 'format' ])) {
$rule [ 'format' ] = $element -> getFormat ();
}
2011-08-19 14:22:09 +09:30
}
2011-08-31 14:25:34 +08:00
// Fix for bug displaying errors for elements in a group
2013-10-15 14:30:33 +01:00
$test [ $fullelementname ][ 0 ][] = $registry -> getValidationScript ( $element , $fullelementname , $rule );
$test [ $fullelementname ][ 1 ] = $element ;
2006-10-14 12:32:31 +00:00
//end of fix
}
}
}
2007-04-23 16:19:25 +00:00
// Fix for MDL-9524. If you don't do this, then $element may be left as a reference to one of the fields in
// the form, and then that form field gets corrupted by the code that follows.
unset ( $element );
2006-10-14 12:32:31 +00:00
$js = '
< script type = " text/javascript " >
//<![CDATA[
2006-12-04 22:00:47 +00:00
var skipClientValidation = false ;
2015-05-11 10:18:51 +08:00
function qf_errorHandler ( element , _qfMsg , escapedName ) {
2006-10-14 12:32:31 +00:00
div = element . parentNode ;
2011-08-02 12:17:44 +08:00
if (( div == undefined ) || ( element . name == undefined )) {
//no checking can be done for undefined elements so let server handle it.
return true ;
}
2006-10-14 12:32:31 +00:00
if ( _qfMsg != \ ' \ ' ) {
2015-05-11 10:18:51 +08:00
var errorSpan = document . getElementById ( \ ' id_error_\ ' + escapedName );
2006-12-05 14:27:24 +00:00
if ( ! errorSpan ) {
errorSpan = document . createElement ( " span " );
2015-05-11 10:18:51 +08:00
errorSpan . id = \ ' id_error_\ ' + escapedName ;
2006-12-05 21:43:33 +00:00
errorSpan . className = " error " ;
2006-12-05 21:48:44 +00:00
element . parentNode . insertBefore ( errorSpan , element . parentNode . firstChild );
2013-08-12 11:03:53 +08:00
document . getElementById ( errorSpan . id ) . setAttribute ( \ ' TabIndex\ ' , \ ' 0 \ ' );
document . getElementById ( errorSpan . id ) . focus ();
2006-10-14 12:32:31 +00:00
}
2006-12-05 21:48:44 +00:00
2006-12-05 14:27:24 +00:00
while ( errorSpan . firstChild ) {
errorSpan . removeChild ( errorSpan . firstChild );
2006-10-14 12:32:31 +00:00
}
2006-10-24 11:05:50 +00:00
2006-12-05 14:27:24 +00:00
errorSpan . appendChild ( document . createTextNode ( _qfMsg . substring ( 3 )));
2006-10-14 12:32:31 +00:00
if ( div . className . substr ( div . className . length - 6 , 6 ) != " error "
2013-08-12 11:03:53 +08:00
&& div . className != " error " ) {
div . className += " error " ;
linebreak = document . createElement ( " br " );
2013-08-21 14:58:50 +08:00
linebreak . className = " error " ;
2015-05-11 10:18:51 +08:00
linebreak . id = \ ' id_error_break_\ ' + escapedName ;
2013-08-12 11:03:53 +08:00
errorSpan . parentNode . insertBefore ( linebreak , errorSpan . nextSibling );
2006-10-14 12:32:31 +00:00
}
return false ;
} else {
2015-05-11 10:18:51 +08:00
var errorSpan = document . getElementById ( \ ' id_error_\ ' + escapedName );
2006-12-05 14:27:24 +00:00
if ( errorSpan ) {
errorSpan . parentNode . removeChild ( errorSpan );
2006-10-14 12:32:31 +00:00
}
2015-05-11 10:18:51 +08:00
var linebreak = document . getElementById ( \ ' id_error_break_\ ' + escapedName );
2013-08-21 14:58:50 +08:00
if ( linebreak ) {
linebreak . parentNode . removeChild ( linebreak );
}
2006-10-14 12:32:31 +00:00
if ( div . className . substr ( div . className . length - 6 , 6 ) == " error " ) {
div . className = div . className . substr ( 0 , div . className . length - 6 );
} else if ( div . className == " error " ) {
div . className = " " ;
}
return true ;
}
} ' ;
$validateJS = '' ;
foreach ( $test as $elementName => $jsandelement ) {
// Fix for bug displaying errors for elements in a group
//unset($element);
list ( $jsArr , $element ) = $jsandelement ;
//end of fix
2010-09-17 22:44:53 +00:00
$escapedElementName = preg_replace_callback (
2012-11-14 01:03:14 -05:00
'/[_\[\]-]/' ,
2010-09-17 22:44:53 +00:00
create_function ( '$matches' , 'return sprintf("_%2x",ord($matches[0]));' ),
$elementName );
2006-10-14 12:32:31 +00:00
$js .= '
2015-05-11 10:18:51 +08:00
function validate_ ' . $this->_formName . ' _ ' . $escapedElementName . ' ( element , escapedName ) {
2011-08-02 12:17:44 +08:00
if ( undefined == element ) {
//required element was not found, then let form be submitted without client side validation
return true ;
}
2006-10-14 12:32:31 +00:00
var value = \ ' \ ' ;
var errFlag = new Array ();
var _qfGroups = {};
var _qfMsg = \ ' \ ' ;
var frm = element . parentNode ;
2011-08-02 12:17:44 +08:00
if (( undefined != element . name ) && ( frm != undefined )) {
while ( frm && frm . nodeName . toUpperCase () != " FORM " ) {
frm = frm . parentNode ;
}
' . join("\n", $jsArr) . '
2015-05-11 10:18:51 +08:00
return qf_errorHandler ( element , _qfMsg , escapedName );
2011-08-02 12:17:44 +08:00
} else {
//element name should be defined else error msg will not be displayed.
return true ;
2006-10-14 12:32:31 +00:00
}
}
' ;
$validateJS .= '
2015-05-11 10:18:51 +08:00
ret = validate_ ' . $this->_formName . ' _ ' . $escapedElementName.' ( frm . elements [ \ '' . $elementName . '\'], \'' . $escapedElementName . ' \ ' ) && ret ;
2007-03-12 06:43:24 +00:00
if ( ! ret && ! first_focus ) {
first_focus = true ;
2015-08-20 10:36:59 +08:00
Y . use ( \ ' moodle - core - event\ ' , function () {
Y . Global . fire ( M . core . globalEvents . FORM_ERROR , { formid : \ '' . $this -> _attributes [ 'id' ] . ' \ ' ,
elementid : \ 'id_error_' . $escapedElementName . ' \ ' });
document . getElementById ( \ 'id_error_' . $escapedElementName . ' \ ' ) . focus ();
});
2007-03-12 06:43:24 +00:00
}
' ;
2007-08-03 13:08:05 +00:00
2006-10-14 12:32:31 +00:00
// Fix for bug displaying errors for elements in a group
//unset($element);
//$element =& $this->getElement($elementName);
//end of fix
2015-05-11 10:18:51 +08:00
$valFunc = 'validate_' . $this -> _formName . '_' . $escapedElementName . '(this, \'' . $escapedElementName . '\')' ;
2006-10-14 12:32:31 +00:00
$onBlur = $element -> getAttribute ( 'onBlur' );
$onChange = $element -> getAttribute ( 'onChange' );
$element -> updateAttributes ( array ( 'onBlur' => $onBlur . $valFunc ,
'onChange' => $onChange . $valFunc ));
}
2006-12-05 14:27:24 +00:00
// do not rely on frm function parameter, because htmlarea breaks it when overloading the onsubmit method
2006-10-14 12:32:31 +00:00
$js .= '
2006-12-28 09:32:45 +00:00
function validate_ ' . $this->_formName . ' ( frm ) {
2006-12-04 22:00:47 +00:00
if ( skipClientValidation ) {
return true ;
}
2006-10-14 12:32:31 +00:00
var ret = true ;
2007-08-03 13:08:05 +00:00
2006-12-05 13:21:40 +00:00
var frm = document . getElementById ( \ '' . $this -> _attributes [ 'id' ] . ' \ ' )
2007-03-12 06:43:24 +00:00
var first_focus = false ;
2006-10-14 12:32:31 +00:00
' . $validateJS . ' ;
return ret ;
}
//]]>
</ script > ' ;
return $js ;
} // end func getValidationScript
2012-01-06 16:38:06 +08:00
/**
* Sets default error message
*/
2006-10-14 12:32:31 +00:00
function _setDefaultRuleMessages (){
foreach ( $this -> _rules as $field => $rulesarr ){
foreach ( $rulesarr as $key => $rule ){
if ( $rule [ 'message' ] === null ){
2010-09-21 08:07:44 +00:00
$a = new stdClass ();
2006-10-14 12:32:31 +00:00
$a -> format = $rule [ 'format' ];
$str = get_string ( 'err_' . $rule [ 'type' ], 'form' , $a );
if ( strpos ( $str , '[[' ) !== 0 ){
$this -> _rules [ $field ][ $key ][ 'message' ] = $str ;
2006-10-24 11:05:50 +00:00
}
2006-10-14 12:32:31 +00:00
}
}
}
}
2006-11-08 06:22:58 +00:00
2012-01-06 16:38:06 +08:00
/**
* Get list of attributes which have dependencies
*
* @ return array
*/
2010-08-19 05:43:06 +00:00
function getLockOptionObject (){
$result = array ();
2007-01-12 09:38:02 +00:00
foreach ( $this -> _dependencies as $dependentOn => $conditions ){
2010-08-19 05:43:06 +00:00
$result [ $dependentOn ] = array ();
2007-01-12 09:38:02 +00:00
foreach ( $conditions as $condition => $values ) {
2010-08-19 05:43:06 +00:00
$result [ $dependentOn ][ $condition ] = array ();
2007-01-12 09:38:02 +00:00
foreach ( $values as $value => $dependents ) {
2010-08-19 05:43:06 +00:00
$result [ $dependentOn ][ $condition ][ $value ] = array ();
2007-01-12 09:38:02 +00:00
$i = 0 ;
foreach ( $dependents as $dependent ) {
$elements = $this -> _getElNamesRecursive ( $dependent );
2007-11-12 17:12:35 +00:00
if ( empty ( $elements )) {
// probably element inside of some group
$elements = array ( $dependent );
}
2007-01-12 09:38:02 +00:00
foreach ( $elements as $element ) {
if ( $element == $dependentOn ) {
continue ;
}
2010-08-19 05:43:06 +00:00
$result [ $dependentOn ][ $condition ][ $value ][] = $element ;
2007-01-12 09:38:02 +00:00
}
2006-12-09 11:42:57 +00:00
}
}
2006-11-21 09:17:46 +00:00
}
2007-01-12 09:38:02 +00:00
}
2010-08-19 05:43:06 +00:00
return array ( $this -> getAttribute ( 'id' ), $result );
2006-11-08 06:22:58 +00:00
}
2006-11-22 08:53:35 +00:00
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Get names of element or elements in a group .
*
* @ param HTML_QuickForm_group | element $element element group or element object
2009-05-25 08:27:25 +00:00
* @ return array
*/
2007-11-12 17:12:35 +00:00
function _getElNamesRecursive ( $element ) {
if ( is_string ( $element )) {
2007-08-03 13:08:05 +00:00
if ( ! $this -> elementExists ( $element )) {
return array ();
}
2007-11-12 17:12:35 +00:00
$element = $this -> getElement ( $element );
2006-11-22 08:53:35 +00:00
}
2007-11-12 17:12:35 +00:00
if ( is_a ( $element , 'HTML_QuickForm_group' )) {
$elsInGroup = $element -> getElements ();
2006-11-22 15:58:07 +00:00
$elNames = array ();
2006-11-22 08:53:35 +00:00
foreach ( $elsInGroup as $elInGroup ){
2007-11-24 13:37:07 +00:00
if ( is_a ( $elInGroup , 'HTML_QuickForm_group' )) {
// not sure if this would work - groups nested in groups
$elNames = array_merge ( $elNames , $this -> _getElNamesRecursive ( $elInGroup ));
} else {
$elNames [] = $element -> getElementName ( $elInGroup -> getName ());
}
2006-11-22 08:53:35 +00:00
}
2007-11-12 17:12:35 +00:00
} else if ( is_a ( $element , 'HTML_QuickForm_header' )) {
return array ();
} else if ( is_a ( $element , 'HTML_QuickForm_hidden' )) {
return array ();
2011-11-17 11:29:25 +00:00
} else if ( method_exists ( $element , 'getPrivateName' ) &&
! ( $element instanceof HTML_QuickForm_advcheckbox )) {
// The advcheckbox element implements a method called getPrivateName,
// but in a way that is not compatible with the generic API, so we
// have to explicitly exclude it.
2007-11-12 17:12:35 +00:00
return array ( $element -> getPrivateName ());
} else {
$elNames = array ( $element -> getName ());
2006-11-22 08:53:35 +00:00
}
2007-11-12 17:12:35 +00:00
return $elNames ;
2006-11-21 09:17:46 +00:00
}
2007-11-12 17:12:35 +00:00
2006-11-21 09:33:48 +00:00
/**
* Adds a dependency for $elementName which will be disabled if $condition is met .
2006-11-22 15:58:07 +00:00
* If $condition = 'notchecked' ( default ) then the condition is that the $dependentOn element
* is not checked . If $condition = 'checked' then the condition is that the $dependentOn element
2007-09-25 14:40:49 +00:00
* is checked . If $condition is something else ( like " eq " for equals ) then it is checked to see if the value
* of the $dependentOn element is $condition ( such as equal ) to $value .
2006-11-21 09:33:48 +00:00
*
2013-05-06 14:35:04 +08:00
* When working with multiple selects , the dependentOn has to be the real name of the select , meaning that
* it will most likely end up with '[]' . Also , the value should be an array of required values , or a string
* containing the values separated by pipes : array ( 'red' , 'blue' ) or 'red|blue' .
*
2006-11-21 09:33:48 +00:00
* @ param string $elementName the name of the element which will be disabled
2012-01-06 16:38:06 +08:00
* @ param string $dependentOn the name of the element whose state will be checked for condition
2006-11-21 09:33:48 +00:00
* @ param string $condition the condition to check
2006-12-04 09:36:30 +00:00
* @ param mixed $value used in conjunction with condition .
2006-11-21 09:33:48 +00:00
*/
2013-05-06 14:35:04 +08:00
function disabledIf ( $elementName , $dependentOn , $condition = 'notchecked' , $value = '1' ) {
// Multiple selects allow for a multiple selection, we transform the array to string here as
// an array cannot be used as a key in an associative array.
if ( is_array ( $value )) {
$value = implode ( '|' , $value );
}
2007-01-12 09:38:02 +00:00
if ( ! array_key_exists ( $dependentOn , $this -> _dependencies )) {
$this -> _dependencies [ $dependentOn ] = array ();
}
if ( ! array_key_exists ( $condition , $this -> _dependencies [ $dependentOn ])) {
$this -> _dependencies [ $dependentOn ][ $condition ] = array ();
}
if ( ! array_key_exists ( $value , $this -> _dependencies [ $dependentOn ][ $condition ])) {
$this -> _dependencies [ $dependentOn ][ $condition ][ $value ] = array ();
}
$this -> _dependencies [ $dependentOn ][ $condition ][ $value ][] = $elementName ;
2006-11-08 06:22:58 +00:00
}
2007-01-12 09:38:02 +00:00
2012-01-06 16:38:06 +08:00
/**
* Registers button as no submit button
*
* @ param string $buttonname name of the button
*/
2006-12-19 07:03:08 +00:00
function registerNoSubmitButton ( $buttonname ){
$this -> _noSubmitButtons [] = $buttonname ;
}
2007-01-12 09:38:02 +00:00
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Checks if button is a no submit button , i . e it doesn ' t submit form
*
* @ param string $buttonname name of the button to check
* @ return bool
2009-05-25 08:27:25 +00:00
*/
2006-12-19 07:03:08 +00:00
function isNoSubmitButton ( $buttonname ){
return ( array_search ( $buttonname , $this -> _noSubmitButtons ) !== FALSE );
2006-12-04 09:36:30 +00:00
}
2007-01-12 09:38:02 +00:00
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Registers a button as cancel button
*
* @ param string $addfieldsname name of the button
2009-05-25 08:27:25 +00:00
*/
2006-12-04 09:36:30 +00:00
function _registerCancelButton ( $addfieldsname ){
$this -> _cancelButtons [] = $addfieldsname ;
}
2012-01-06 16:38:06 +08:00
2007-01-12 06:19:39 +00:00
/**
* Displays elements without HTML input tags .
* This method is different to freeze () in that it makes sure no hidden
2008-10-13 19:39:27 +00:00
* elements are included in the form .
* Note : If you want to make sure the submitted value is ignored , please use setDefaults () .
2007-01-12 06:19:39 +00:00
*
2007-01-25 17:59:46 +00:00
* This function also removes all previously defined rules .
*
2012-01-06 16:38:06 +08:00
* @ param string | array $elementList array or string of element ( s ) to be frozen
* @ return object | bool if element list is not empty then return error object , else true
2007-01-12 06:19:39 +00:00
*/
function hardFreeze ( $elementList = null )
{
if ( ! isset ( $elementList )) {
$this -> _freezeAll = true ;
$elementList = array ();
} else {
if ( ! is_array ( $elementList )) {
$elementList = preg_split ( '/[ ]*,[ ]*/' , $elementList );
}
$elementList = array_flip ( $elementList );
}
foreach ( array_keys ( $this -> _elements ) as $key ) {
$name = $this -> _elements [ $key ] -> getName ();
if ( $this -> _freezeAll || isset ( $elementList [ $name ])) {
$this -> _elements [ $key ] -> freeze ();
$this -> _elements [ $key ] -> setPersistantFreeze ( false );
unset ( $elementList [ $name ]);
2007-01-25 17:59:46 +00:00
// remove all rules
$this -> _rules [ $name ] = array ();
// if field is required, remove the rule
$unset = array_search ( $name , $this -> _required );
if ( $unset !== false ) {
unset ( $this -> _required [ $unset ]);
}
2007-01-12 06:19:39 +00:00
}
}
if ( ! empty ( $elementList )) {
2012-04-15 17:02:26 +02:00
return self :: raiseError ( null , QUICKFORM_NONEXIST_ELEMENT , null , E_USER_WARNING , " Nonexistant element(s): ' " . implode ( " ', ' " , array_keys ( $elementList )) . " ' in HTML_QuickForm::freeze() " , 'HTML_QuickForm_Error' , true );
2007-01-12 06:19:39 +00:00
}
return true ;
2007-08-03 13:08:05 +00:00
}
2012-01-06 16:38:06 +08:00
2007-08-03 13:08:05 +00:00
/**
* Hard freeze all elements in a form except those whose names are in $elementList or hidden elements in a form .
*
* This function also removes all previously defined rules of elements it freezes .
*
2012-01-06 16:38:06 +08:00
* @ throws HTML_QuickForm_Error
* @ param array $elementList array or string of element ( s ) not to be frozen
* @ return bool returns true
2007-08-03 13:08:05 +00:00
*/
function hardFreezeAllVisibleExcept ( $elementList )
{
$elementList = array_flip ( $elementList );
foreach ( array_keys ( $this -> _elements ) as $key ) {
$name = $this -> _elements [ $key ] -> getName ();
$type = $this -> _elements [ $key ] -> getType ();
2007-05-28 00:46:11 +00:00
2007-08-03 13:08:05 +00:00
if ( $type == 'hidden' ){
// leave hidden types as they are
} elseif ( ! isset ( $elementList [ $name ])) {
$this -> _elements [ $key ] -> freeze ();
$this -> _elements [ $key ] -> setPersistantFreeze ( false );
// remove all rules
$this -> _rules [ $name ] = array ();
// if field is required, remove the rule
$unset = array_search ( $name , $this -> _required );
if ( $unset !== false ) {
unset ( $this -> _required [ $unset ]);
}
}
}
return true ;
}
2012-01-06 16:38:06 +08:00
2007-08-03 13:08:05 +00:00
/**
* Tells whether the form was already submitted
*
* This is useful since the _submitFiles and _submitValues arrays
* may be completely empty after the trackSubmit value is removed .
*
* @ return bool
*/
function isSubmitted ()
{
return parent :: isSubmitted () && ( ! $this -> isFrozen ());
}
2006-09-24 17:04:51 +00:00
}
/**
2012-01-06 16:38:06 +08:00
* MoodleQuickForm renderer
*
2006-10-12 07:33:57 +00:00
* A renderer for MoodleQuickForm that only uses XHTML and CSS and no
2006-09-24 17:04:51 +00:00
* table tags , extends PEAR class HTML_QuickForm_Renderer_Tableless
2006-10-12 07:33:57 +00:00
*
2006-09-24 17:04:51 +00:00
* Stylesheet is part of standard theme and should be automatically included .
*
2012-01-06 16:38:06 +08:00
* @ package core_form
* @ copyright 2007 Jamie Pratt < me @ jamiep . org >
2009-05-25 08:27:25 +00:00
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2006-09-24 17:04:51 +00:00
*/
2006-10-12 07:33:57 +00:00
class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless {
2006-09-24 17:04:51 +00:00
2012-01-06 16:38:06 +08:00
/** @var array Element template array */
2006-09-24 17:04:51 +00:00
var $_elementTemplates ;
2012-01-06 16:38:06 +08:00
2006-09-27 19:12:52 +00:00
/**
2012-01-06 16:38:06 +08:00
* Template used when opening a hidden fieldset
* ( i . e . a fieldset that is opened when there is no header element )
* @ var string
*/
2007-08-03 13:28:03 +00:00
var $_openHiddenFieldsetTemplate = " \n \t <fieldset class= \" hidden \" ><div> " ;
2012-01-06 16:38:06 +08:00
/** @var string Header Template string */
2006-12-14 12:44:10 +00:00
var $_headerTemplate =
2013-01-24 14:28:40 +00:00
" \n \t \t <legend class= \" ftoggler \" > { header}</legend> \n \t \t <div class= \" fcontainer clearfix \" > \n \t \t " ;
2006-10-12 07:33:57 +00:00
2012-01-06 16:38:06 +08:00
/** @var string Template used when opening a fieldset */
2014-02-04 11:55:14 +08:00
var $_openFieldsetTemplate = " \n \t <fieldset class= \" { classes} \" { id}> " ;
2007-01-30 18:44:23 +00:00
2012-01-06 16:38:06 +08:00
/** @var string Template used when closing a fieldset */
2007-08-03 13:28:03 +00:00
var $_closeFieldsetTemplate = " \n \t \t </div></fieldset> " ;
2006-09-27 16:00:19 +00:00
2012-01-06 16:38:06 +08:00
/** @var string Required Note template string */
2006-10-12 07:33:57 +00:00
var $_requiredNoteTemplate =
2007-01-13 04:54:44 +00:00
" \n \t \t <div class= \" fdescription required \" > { requiredNote}</div> " ;
2013-03-14 17:54:14 +08:00
2013-03-27 09:47:02 +08:00
/**
* Collapsible buttons string template .
*
* Note that the < span > will be converted as a link . This is done so that the link is not yet clickable
* until the Javascript has been fully loaded .
*
* @ var string
*/
2013-03-14 17:54:14 +08:00
var $_collapseButtonsTemplate =
2013-03-27 09:47:02 +08:00
" \n \t <div class= \" collapsible-actions \" ><span class= \" collapseexpand \" > { strexpandall}</span></div> " ;
2013-03-14 17:54:14 +08:00
2013-02-07 14:13:36 +00:00
/**
* Array whose keys are element names . If the key exists this is a advanced element
*
* @ var array
*/
2006-12-14 12:44:10 +00:00
var $_advancedElements = array ();
2013-02-07 14:13:36 +00:00
/**
* Array whose keys are element names and the the boolean values reflect the current state . If the key exists this is a collapsible element .
*
* @ var array
*/
var $_collapsibleElements = array ();
2013-03-14 17:54:14 +08:00
/**
* @ var string Contains the collapsible buttons to add to the form .
*/
var $_collapseButtons = '' ;
2012-01-06 16:38:06 +08:00
/**
* Constructor
*/
2015-11-05 17:01:34 +08:00
public function __construct () {
2006-09-27 16:00:19 +00:00
// switch next two lines for ol li containers for form items.
2007-01-13 04:24:15 +00:00
// $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>');
2007-01-10 05:05:26 +00:00
$this -> _elementTemplates = array (
2015-08-12 13:23:08 +08:00
'default' => " \n \t \t " . '<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type} {emptylabel}" {aria-live}><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} </label>{help}</div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error" tabindex="0">{error}</span><br /><!-- END error -->{element}</div></div>' ,
2007-01-13 04:24:15 +00:00
2012-05-28 11:05:49 +08:00
'actionbuttons' => " \n \t \t " . '<div id="{id}" class="fitem fitem_actionbuttons fitem_{type}"><div class="felement {type}">{element}</div></div>' ,
2015-08-12 13:23:08 +08:00
'fieldset' => " \n \t \t " . '<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type} {emptylabel}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} </label>{help}</div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error" tabindex="0">{error}</span><br /><!-- END error -->{element}</fieldset></div>' ,
2007-08-03 13:08:05 +00:00
2015-08-12 13:23:08 +08:00
'static' => " \n \t \t " . '<div class="fitem {advanced} {emptylabel}"><div class="fitemtitle"><div class="fstaticlabel">{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} {help}</div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error" tabindex="0">{error}</span><br /><!-- END error -->{element}</div></div>' ,
2007-07-06 04:03:51 +00:00
2013-11-26 12:54:44 +08:00
'warning' => " \n \t \t " . '<div class="fitem {advanced} {emptylabel}">{element}</div>' ,
2008-09-02 12:14:58 +00:00
2007-08-03 13:08:05 +00:00
'nodisplay' => '' );
2006-09-24 17:04:51 +00:00
2015-11-05 17:01:34 +08:00
parent :: __construct ();
}
/**
* Old syntax of class constructor . Deprecated in PHP7 .
*
* @ deprecated since Moodle 3.1
*/
public function MoodleQuickForm_Renderer () {
debugging ( 'Use of class name as constructor is deprecated' , DEBUG_DEVELOPER );
self :: __construct ();
2006-09-24 17:04:51 +00:00
}
2006-10-12 07:33:57 +00:00
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Set element ' s as adavance element
*
* @ param array $elements form elements which needs to be grouped as advance elements .
2009-05-25 08:27:25 +00:00
*/
2006-12-14 12:44:10 +00:00
function setAdvancedElements ( $elements ){
$this -> _advancedElements = $elements ;
}
2013-02-07 14:13:36 +00:00
/**
* Setting collapsible elements
*
* @ param array $elements
*/
function setCollapsibleElements ( $elements ) {
$this -> _collapsibleElements = $elements ;
}
2013-02-11 10:11:20 +08:00
2006-12-14 12:44:10 +00:00
/**
* What to do when starting the form
*
2012-01-06 16:38:06 +08:00
* @ param MoodleQuickForm $form reference of the form
2006-12-14 12:44:10 +00:00
*/
2006-09-24 17:04:51 +00:00
function startForm ( & $form ){
2012-01-23 11:36:53 +00:00
global $PAGE ;
2006-11-22 15:58:07 +00:00
$this -> _reqHTML = $form -> getReqHTML ();
$this -> _elementTemplates = str_replace ( '{req}' , $this -> _reqHTML , $this -> _elementTemplates );
2006-12-14 12:44:10 +00:00
$this -> _advancedHTML = $form -> getAdvancedHTML ();
2013-03-14 17:54:14 +08:00
$this -> _collapseButtons = '' ;
2013-02-07 14:13:36 +00:00
$formid = $form -> getAttribute ( 'id' );
2006-09-24 17:04:51 +00:00
parent :: startForm ( $form );
2007-08-03 13:08:05 +00:00
if ( $form -> isFrozen ()){
$this -> _formTemplate = " \n <div class= \" mform frozen \" > \n { content} \n </div> " ;
} else {
2013-03-14 17:54:14 +08:00
$this -> _formTemplate = " \n <form { attributes}> \n \t <div style= \" display: none; \" > { hidden}</div> \n { collapsebtns} \n { content} \n </form> " ;
2007-08-03 13:08:05 +00:00
$this -> _hiddenHtml .= $form -> _pageparams ;
}
2012-10-05 17:12:11 +01:00
if ( $form -> is_form_change_checker_enabled ()) {
$PAGE -> requires -> yui_module ( 'moodle-core-formchangechecker' ,
'M.core_formchangechecker.init' ,
array ( array (
2013-02-07 14:13:36 +00:00
'formid' => $formid
2012-10-05 17:12:11 +01:00
))
);
$PAGE -> requires -> string_for_js ( 'changesmadereallygoaway' , 'moodle' );
}
2013-02-07 20:44:17 +00:00
if ( ! empty ( $this -> _collapsibleElements )) {
2013-03-14 17:54:14 +08:00
if ( count ( $this -> _collapsibleElements ) > 1 ) {
$this -> _collapseButtons = $this -> _collapseButtonsTemplate ;
$this -> _collapseButtons = str_replace ( '{strexpandall}' , get_string ( 'expandall' ), $this -> _collapseButtons );
2013-03-27 09:47:02 +08:00
$PAGE -> requires -> strings_for_js ( array ( 'collapseall' , 'expandall' ), 'moodle' );
2013-03-14 17:54:14 +08:00
}
2013-02-07 14:13:36 +00:00
$PAGE -> requires -> yui_module ( 'moodle-form-shortforms' , 'M.form.shortforms' , array ( array ( 'formid' => $formid )));
}
2013-02-11 10:11:20 +08:00
if ( ! empty ( $this -> _advancedElements )){
2013-01-24 14:28:40 +00:00
$PAGE -> requires -> strings_for_js ( array ( 'showmore' , 'showless' ), 'form' );
$PAGE -> requires -> yui_module ( 'moodle-form-showadvanced' , 'M.form.showadvanced' , array ( array ( 'formid' => $formid )));
}
2006-09-24 17:04:51 +00:00
}
2009-11-01 11:31:16 +00:00
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Create advance group of elements
*
2009-05-25 08:27:25 +00:00
* @ param object $group Passed by reference
2012-01-06 16:38:06 +08:00
* @ param bool $required if input is required field
* @ param string $error error message to display
2009-05-25 08:27:25 +00:00
*/
2006-09-24 17:04:51 +00:00
function startGroup ( & $group , $required , $error ){
2012-01-31 17:10:51 +00:00
// Make sure the element has an id.
$group -> _generateId ();
2006-09-24 17:04:51 +00:00
if ( method_exists ( $group , 'getElementTemplateType' )){
2006-09-27 16:07:37 +00:00
$html = $this -> _elementTemplates [ $group -> getElementTemplateType ()];
2006-09-24 17:04:51 +00:00
} else {
$html = $this -> _elementTemplates [ 'default' ];
2006-10-12 07:33:57 +00:00
2006-09-24 17:04:51 +00:00
}
2013-01-24 14:28:40 +00:00
2006-12-14 12:44:10 +00:00
if ( isset ( $this -> _advancedElements [ $group -> getName ()])){
2013-01-24 14:28:40 +00:00
$html = str_replace ( ' {advanced}' , ' advanced' , $html );
2006-12-14 12:44:10 +00:00
$html = str_replace ( '{advancedimg}' , $this -> _advancedHTML , $html );
} else {
$html = str_replace ( ' {advanced}' , '' , $html );
$html = str_replace ( '{advancedimg}' , '' , $html );
}
2006-09-24 17:04:51 +00:00
if ( method_exists ( $group , 'getHelpButton' )){
$html = str_replace ( '{help}' , $group -> getHelpButton (), $html );
} else {
$html = str_replace ( '{help}' , '' , $html );
}
2012-01-31 17:10:51 +00:00
$html = str_replace ( '{id}' , 'fgroup_' . $group -> getAttribute ( 'id' ), $html );
2006-12-05 14:27:24 +00:00
$html = str_replace ( '{name}' , $group -> getName (), $html );
2006-09-27 19:12:52 +00:00
$html = str_replace ( '{type}' , 'fgroup' , $html );
2013-11-26 12:54:44 +08:00
$emptylabel = '' ;
if ( $group -> getLabel () == '' ) {
$emptylabel = 'femptylabel' ;
}
$html = str_replace ( '{emptylabel}' , $emptylabel , $html );
2006-10-12 07:33:57 +00:00
2006-09-24 17:04:51 +00:00
$this -> _templates [ $group -> getName ()] = $html ;
// Fix for bug in tableless quickforms that didn't allow you to stop a
// fieldset before a group of elements.
// if the element name indicates the end of a fieldset, close the fieldset
if ( in_array ( $group -> getName (), $this -> _stopFieldsetElements )
&& $this -> _fieldsetsOpen > 0
) {
$this -> _html .= $this -> _closeFieldsetTemplate ;
$this -> _fieldsetsOpen -- ;
}
parent :: startGroup ( $group , $required , $error );
}
2013-02-11 10:11:20 +08:00
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Renders element
*
* @ param HTML_QuickForm_element $element element
* @ param bool $required if input is required field
* @ param string $error error message to display
2009-05-25 08:27:25 +00:00
*/
2006-09-24 17:04:51 +00:00
function renderElement ( & $element , $required , $error ){
MDL-30168 formslib: untangle automatic id generation.
Previously, we had overridden the _generateId method in almost all
subclasses; and then we mostly, but not always; ignored the value that
was generated there, and instead generated new (nicer) values in
MoodleQuickForm_Renderer::renderElement. Of course, that is not really a
logical place to (re)generate ids.
I have fixed the code so that the _generateId method now uses the 'nice
id' algorithm from renderElement. This should make the whole code flow
more logical.
This make all our overriding of _generateId unnecessary.
We do need a special _generateId for radio buttons, because you often
have different radio buttons with the same name but different values.
This change should only change the ids on radio, checkbox and
advcheckbox elements. Previously, those were essentially random, so I
don't think anyone could have been relying on the particular values.
This commit also has new unit tests, first to test the basic _generateId
algorithm, and then to create and render an example form (including some
tricky things like repeat_elements) and chech the acutal ids in the
generated HTML.
2011-12-19 18:22:28 +00:00
// Make sure the element has an id.
$element -> _generateId ();
2007-01-08 15:53:17 +00:00
//adding stuff to place holders in template
2008-07-31 22:15:30 +00:00
//check if this is a group element first
2008-07-09 10:26:13 +00:00
if (( $this -> _inGroup ) and ! empty ( $this -> _groupElementTemplate )) {
2008-09-26 07:24:31 +00:00
// so it gets substitutions for *each* element
2009-12-18 07:42:54 +00:00
$html = $this -> _groupElementTemplate ;
2008-07-09 10:26:13 +00:00
}
elseif ( method_exists ( $element , 'getElementTemplateType' )){
2006-09-24 17:04:51 +00:00
$html = $this -> _elementTemplates [ $element -> getElementTemplateType ()];
} else {
$html = $this -> _elementTemplates [ 'default' ];
2006-12-14 12:44:10 +00:00
}
if ( isset ( $this -> _advancedElements [ $element -> getName ()])){
2013-03-28 12:12:38 +08:00
$html = str_replace ( ' {advanced}' , ' advanced' , $html );
$html = str_replace ( ' {aria-live}' , ' aria-live="polite"' , $html );
2006-12-14 12:44:10 +00:00
} else {
2013-03-28 12:12:38 +08:00
$html = str_replace ( ' {advanced}' , '' , $html );
$html = str_replace ( ' {aria-live}' , '' , $html );
2006-12-14 12:44:10 +00:00
}
if ( isset ( $this -> _advancedElements [ $element -> getName ()]) || $element -> getName () == 'mform_showadvanced' ){
$html = str_replace ( '{advancedimg}' , $this -> _advancedHTML , $html );
} else {
$html = str_replace ( '{advancedimg}' , '' , $html );
2006-09-24 17:04:51 +00:00
}
2012-01-31 17:10:51 +00:00
$html = str_replace ( '{id}' , 'fitem_' . $element -> getAttribute ( 'id' ), $html );
2006-09-27 19:12:52 +00:00
$html = str_replace ( '{type}' , 'f' . $element -> getType (), $html );
2006-12-05 14:27:24 +00:00
$html = str_replace ( '{name}' , $element -> getName (), $html );
2013-11-26 12:54:44 +08:00
$emptylabel = '' ;
if ( $element -> getLabel () == '' ) {
$emptylabel = 'femptylabel' ;
}
$html = str_replace ( '{emptylabel}' , $emptylabel , $html );
2006-09-24 17:04:51 +00:00
if ( method_exists ( $element , 'getHelpButton' )){
2006-11-22 15:58:07 +00:00
$html = str_replace ( '{help}' , $element -> getHelpButton (), $html );
2006-09-24 17:04:51 +00:00
} else {
2006-11-22 15:58:07 +00:00
$html = str_replace ( '{help}' , '' , $html );
2006-10-12 07:33:57 +00:00
2006-09-24 17:04:51 +00:00
}
2008-07-09 10:26:13 +00:00
if (( $this -> _inGroup ) and ! empty ( $this -> _groupElementTemplate )) {
$this -> _groupElementTemplate = $html ;
2007-09-18 09:35:44 +00:00
}
2008-07-09 10:26:13 +00:00
elseif ( ! isset ( $this -> _templates [ $element -> getName ()])) {
$this -> _templates [ $element -> getName ()] = $html ;
2008-07-31 22:15:30 +00:00
}
2006-09-24 17:04:51 +00:00
parent :: renderElement ( $element , $required , $error );
}
2006-12-14 12:44:10 +00:00
2009-05-25 08:27:25 +00:00
/**
2012-01-06 16:38:06 +08:00
* Called when visiting a form , after processing all form elements
* Adds required note , form attributes , validation javascript and form content .
*
2010-08-19 05:43:06 +00:00
* @ global moodle_page $PAGE
2012-01-06 16:38:06 +08:00
* @ param moodleform $form Passed by reference
2009-05-25 08:27:25 +00:00
*/
2006-11-08 06:22:58 +00:00
function finishForm ( & $form ){
2010-08-19 05:43:06 +00:00
global $PAGE ;
2007-08-03 13:08:05 +00:00
if ( $form -> isFrozen ()){
$this -> _hiddenHtml = '' ;
}
2006-11-08 06:22:58 +00:00
parent :: finishForm ( $form );
2013-03-14 17:54:14 +08:00
$this -> _html = str_replace ( '{collapsebtns}' , $this -> _collapseButtons , $this -> _html );
2010-08-19 05:43:06 +00:00
if ( ! $form -> isFrozen ()) {
$args = $form -> getLockOptionObject ();
if ( count ( $args [ 1 ]) > 0 ) {
2011-09-26 15:35:27 +08:00
$PAGE -> requires -> js_init_call ( 'M.form.initFormDependencies' , $args , true , moodleform :: get_js_module ());
2010-08-19 05:43:06 +00:00
}
2006-11-08 06:22:58 +00:00
}
}
2006-12-14 12:44:10 +00:00
/**
* Called when visiting a header element
*
2012-01-06 16:38:06 +08:00
* @ param HTML_QuickForm_header $header An HTML_QuickForm_header element being visited
2010-08-19 05:43:06 +00:00
* @ global moodle_page $PAGE
2006-12-14 12:44:10 +00:00
*/
2009-06-15 05:37:57 +00:00
function renderHeader ( & $header ) {
global $PAGE ;
2009-06-29 01:58:11 +00:00
2013-02-07 20:44:17 +00:00
$header -> _generateId ();
2006-12-14 12:44:10 +00:00
$name = $header -> getName ();
2013-02-07 20:44:17 +00:00
$id = empty ( $name ) ? '' : ' id="' . $header -> getAttribute ( 'id' ) . '"' ;
2006-12-14 12:44:10 +00:00
if ( is_null ( $header -> _text )) {
$header_html = '' ;
} elseif ( ! empty ( $name ) && isset ( $this -> _templates [ $name ])) {
$header_html = str_replace ( '{header}' , $header -> toHtml (), $this -> _templates [ $name ]);
} else {
$header_html = str_replace ( '{header}' , $header -> toHtml (), $this -> _headerTemplate );
}
if ( $this -> _fieldsetsOpen > 0 ) {
$this -> _html .= $this -> _closeFieldsetTemplate ;
$this -> _fieldsetsOpen -- ;
}
2013-02-11 10:11:20 +08:00
// Define collapsible classes for fieldsets.
2013-03-13 11:14:20 +08:00
$arialive = '' ;
2013-02-07 14:13:36 +00:00
$fieldsetclasses = array ( 'clearfix' );
2013-03-12 15:05:17 +08:00
if ( isset ( $this -> _collapsibleElements [ $header -> getName ()])) {
2013-02-07 14:13:36 +00:00
$fieldsetclasses [] = 'collapsible' ;
2013-03-12 15:05:17 +08:00
if ( $this -> _collapsibleElements [ $header -> getName ()]) {
2013-02-07 14:13:36 +00:00
$fieldsetclasses [] = 'collapsed' ;
}
2006-12-14 12:44:10 +00:00
}
2013-02-07 14:13:36 +00:00
2013-01-24 14:28:40 +00:00
if ( isset ( $this -> _advancedElements [ $name ])){
$fieldsetclasses [] = 'containsadvancedelements' ;
}
2013-02-07 14:13:36 +00:00
$openFieldsetTemplate = str_replace ( '{id}' , $id , $this -> _openFieldsetTemplate );
$openFieldsetTemplate = str_replace ( '{classes}' , join ( ' ' , $fieldsetclasses ), $openFieldsetTemplate );
2006-12-14 12:44:10 +00:00
$this -> _html .= $openFieldsetTemplate . $header_html ;
$this -> _fieldsetsOpen ++ ;
2012-01-06 16:38:06 +08:00
}
2006-12-14 12:44:10 +00:00
2012-01-06 16:38:06 +08:00
/**
* Return Array of element names that indicate the end of a fieldset
*
* @ return array
*/
2006-12-14 12:44:10 +00:00
function getStopFieldsetElements (){
return $this -> _stopFieldsetElements ;
}
2006-09-24 17:04:51 +00:00
}
2011-07-27 16:24:49 +08:00
/**
* Required elements validation
2012-01-06 16:38:06 +08:00
*
2011-07-27 16:24:49 +08:00
* This class overrides QuickForm validation since it allowed space or empty tag as a value
2012-01-06 16:38:06 +08:00
*
* @ package core_form
* @ category form
* @ copyright 2006 Jamie Pratt < me @ jamiep . org >
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2011-07-27 16:24:49 +08:00
*/
class MoodleQuickForm_Rule_Required extends HTML_QuickForm_Rule {
/**
* Checks if an element is not empty .
* This is a server - side validation , it works for both text fields and editor fields
*
2012-01-06 16:38:06 +08:00
* @ param string $value Value to check
* @ param int | string | array $options Not used yet
* @ return bool true if value is not empty
2011-07-27 16:24:49 +08:00
*/
function validate ( $value , $options = null ) {
global $CFG ;
if ( is_array ( $value ) && array_key_exists ( 'text' , $value )) {
$value = $value [ 'text' ];
}
2012-01-15 13:37:53 +01:00
if ( is_array ( $value )) {
// nasty guess - there has to be something in the array, hopefully nobody invents arrays in arrays
$value = implode ( '' , $value );
}
2011-07-27 16:24:49 +08:00
$stripvalues = array (
'#</?(?!img|canvas|hr).*?>#im' , // all tags except img, canvas and hr
2014-10-15 11:26:52 +08:00
'#(\xc2\xa0|\s| )#' , // Any whitespaces actually.
2011-07-27 16:24:49 +08:00
);
if ( ! empty ( $CFG -> strictformsrequired )) {
$value = preg_replace ( $stripvalues , '' , ( string ) $value );
}
if (( string ) $value == '' ) {
return false ;
}
return true ;
}
/**
* This function returns Javascript code used to build client - side validation .
* It checks if an element is not empty .
*
2012-01-06 16:38:06 +08:00
* @ param int $format format of data which needs to be validated .
2011-07-27 16:24:49 +08:00
* @ return array
*/
2011-08-31 14:25:34 +08:00
function getValidationScript ( $format = null ) {
2011-07-27 16:24:49 +08:00
global $CFG ;
if ( ! empty ( $CFG -> strictformsrequired )) {
2011-08-31 14:25:34 +08:00
if ( ! empty ( $format ) && $format == FORMAT_HTML ) {
2015-02-24 17:35:32 +00:00
return array ( '' , " { jsVar}.replace(/(<(?!img|hr|canvas)[^>]*>)| | \ s+/ig, '') == '' " );
2011-08-31 14:25:34 +08:00
} else {
return array ( '' , " { jsVar}.replace(/^ \ s+ $ /g, '') == '' " );
}
2011-07-27 16:24:49 +08:00
} else {
return array ( '' , " { jsVar} == '' " );
}
}
}
2009-05-25 08:27:25 +00:00
/**
* @ global object $GLOBALS [ '_HTML_QuickForm_default_renderer' ]
* @ name $_HTML_QuickForm_default_renderer
*/
2009-07-02 14:58:41 +00:00
$GLOBALS [ '_HTML_QuickForm_default_renderer' ] = new MoodleQuickForm_Renderer ();
2006-09-24 17:04:51 +00:00
2009-05-25 08:27:25 +00:00
/** Please keep this list in alphabetical order. */
2009-01-14 09:58:12 +00:00
MoodleQuickForm :: registerElementType ( 'advcheckbox' , " $CFG->libdir /form/advcheckbox.php " , 'MoodleQuickForm_advcheckbox' );
2015-09-18 10:48:19 +08:00
MoodleQuickForm :: registerElementType ( 'autocomplete' , " $CFG->libdir /form/autocomplete.php " , 'MoodleQuickForm_autocomplete' );
2009-01-14 09:58:12 +00:00
MoodleQuickForm :: registerElementType ( 'button' , " $CFG->libdir /form/button.php " , 'MoodleQuickForm_button' );
MoodleQuickForm :: registerElementType ( 'cancel' , " $CFG->libdir /form/cancel.php " , 'MoodleQuickForm_cancel' );
2009-11-05 07:06:09 +00:00
MoodleQuickForm :: registerElementType ( 'searchableselector' , " $CFG->libdir /form/searchableselector.php " , 'MoodleQuickForm_searchableselector' );
2006-10-12 07:33:57 +00:00
MoodleQuickForm :: registerElementType ( 'checkbox' , " $CFG->libdir /form/checkbox.php " , 'MoodleQuickForm_checkbox' );
2009-01-14 09:58:12 +00:00
MoodleQuickForm :: registerElementType ( 'date_selector' , " $CFG->libdir /form/dateselector.php " , 'MoodleQuickForm_date_selector' );
MoodleQuickForm :: registerElementType ( 'date_time_selector' , " $CFG->libdir /form/datetimeselector.php " , 'MoodleQuickForm_date_time_selector' );
2009-03-10 06:46:34 +00:00
MoodleQuickForm :: registerElementType ( 'duration' , " $CFG->libdir /form/duration.php " , 'MoodleQuickForm_duration' );
2009-01-14 09:58:12 +00:00
MoodleQuickForm :: registerElementType ( 'editor' , " $CFG->libdir /form/editor.php " , 'MoodleQuickForm_editor' );
2008-11-19 20:27:18 +00:00
MoodleQuickForm :: registerElementType ( 'filemanager' , " $CFG->libdir /form/filemanager.php " , 'MoodleQuickForm_filemanager' );
2008-07-31 02:51:28 +00:00
MoodleQuickForm :: registerElementType ( 'filepicker' , " $CFG->libdir /form/filepicker.php " , 'MoodleQuickForm_filepicker' );
2011-10-12 15:01:53 +08:00
MoodleQuickForm :: registerElementType ( 'grading' , " $CFG->libdir /form/grading.php " , 'MoodleQuickForm_grading' );
2006-10-12 07:33:57 +00:00
MoodleQuickForm :: registerElementType ( 'group' , " $CFG->libdir /form/group.php " , 'MoodleQuickForm_group' );
2009-01-14 09:58:12 +00:00
MoodleQuickForm :: registerElementType ( 'header' , " $CFG->libdir /form/header.php " , 'MoodleQuickForm_header' );
MoodleQuickForm :: registerElementType ( 'hidden' , " $CFG->libdir /form/hidden.php " , 'MoodleQuickForm_hidden' );
MoodleQuickForm :: registerElementType ( 'htmleditor' , " $CFG->libdir /form/htmleditor.php " , 'MoodleQuickForm_htmleditor' );
2012-12-07 17:09:26 +08:00
MoodleQuickForm :: registerElementType ( 'listing' , " $CFG->libdir /form/listing.php " , 'MoodleQuickForm_listing' );
2009-01-14 09:58:12 +00:00
MoodleQuickForm :: registerElementType ( 'modgrade' , " $CFG->libdir /form/modgrade.php " , 'MoodleQuickForm_modgrade' );
MoodleQuickForm :: registerElementType ( 'modvisible' , " $CFG->libdir /form/modvisible.php " , 'MoodleQuickForm_modvisible' );
2006-10-12 07:33:57 +00:00
MoodleQuickForm :: registerElementType ( 'password' , " $CFG->libdir /form/password.php " , 'MoodleQuickForm_password' );
2007-08-03 13:08:05 +00:00
MoodleQuickForm :: registerElementType ( 'passwordunmask' , " $CFG->libdir /form/passwordunmask.php " , 'MoodleQuickForm_passwordunmask' );
2009-01-14 09:58:12 +00:00
MoodleQuickForm :: registerElementType ( 'questioncategory' , " $CFG->libdir /form/questioncategory.php " , 'MoodleQuickForm_questioncategory' );
2006-10-12 07:33:57 +00:00
MoodleQuickForm :: registerElementType ( 'radio' , " $CFG->libdir /form/radio.php " , 'MoodleQuickForm_radio' );
2009-01-14 09:58:12 +00:00
MoodleQuickForm :: registerElementType ( 'recaptcha' , " $CFG->libdir /form/recaptcha.php " , 'MoodleQuickForm_recaptcha' );
2006-10-12 07:33:57 +00:00
MoodleQuickForm :: registerElementType ( 'select' , " $CFG->libdir /form/select.php " , 'MoodleQuickForm_select' );
2007-08-03 13:08:05 +00:00
MoodleQuickForm :: registerElementType ( 'selectgroups' , " $CFG->libdir /form/selectgroups.php " , 'MoodleQuickForm_selectgroups' );
2009-01-14 09:58:12 +00:00
MoodleQuickForm :: registerElementType ( 'selectwithlink' , " $CFG->libdir /form/selectwithlink.php " , 'MoodleQuickForm_selectwithlink' );
MoodleQuickForm :: registerElementType ( 'selectyesno' , " $CFG->libdir /form/selectyesno.php " , 'MoodleQuickForm_selectyesno' );
MoodleQuickForm :: registerElementType ( 'static' , " $CFG->libdir /form/static.php " , 'MoodleQuickForm_static' );
MoodleQuickForm :: registerElementType ( 'submit' , " $CFG->libdir /form/submit.php " , 'MoodleQuickForm_submit' );
2007-12-04 10:35:25 +00:00
MoodleQuickForm :: registerElementType ( 'submitlink' , " $CFG->libdir /form/submitlink.php " , 'MoodleQuickForm_submitlink' );
2009-01-15 09:24:45 +00:00
MoodleQuickForm :: registerElementType ( 'tags' , " $CFG->libdir /form/tags.php " , 'MoodleQuickForm_tags' );
2006-10-12 07:33:57 +00:00
MoodleQuickForm :: registerElementType ( 'text' , " $CFG->libdir /form/text.php " , 'MoodleQuickForm_text' );
MoodleQuickForm :: registerElementType ( 'textarea' , " $CFG->libdir /form/textarea.php " , 'MoodleQuickForm_textarea' );
2009-10-13 08:31:50 +00:00
MoodleQuickForm :: registerElementType ( 'url' , " $CFG->libdir /form/url.php " , 'MoodleQuickForm_url' );
2008-09-02 12:14:58 +00:00
MoodleQuickForm :: registerElementType ( 'warning' , " $CFG->libdir /form/warning.php " , 'MoodleQuickForm_warning' );
2011-07-27 16:24:49 +08:00
MoodleQuickForm :: registerRule ( 'required' , null , 'MoodleQuickForm_Rule_Required' , " $CFG->libdir /formslib.php " );