From e240a0000a9e75e66191234cd34281643bb392d4 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Fri, 1 Feb 2019 19:50:41 +1100 Subject: [PATCH] MDL-53140 forms: Added the float form element to the form API --- lib/form/float.php | 187 ++++++++++++++++++ lib/form/tests/float_test.php | 99 ++++++++++ lib/formslib.php | 1 + lib/upgrade.txt | 1 + .../core_form/element-float-inline.mustache | 1 + .../core_form/element-float.mustache | 1 + 6 files changed, 290 insertions(+) create mode 100644 lib/form/float.php create mode 100644 lib/form/tests/float_test.php create mode 100644 theme/boost/templates/core_form/element-float-inline.mustache create mode 100644 theme/boost/templates/core_form/element-float.mustache diff --git a/lib/form/float.php b/lib/form/float.php new file mode 100644 index 00000000000..8f375c2b986 --- /dev/null +++ b/lib/form/float.php @@ -0,0 +1,187 @@ +. + + +/** + * Float type form element + * + * Contains HTML class for a float type element + * + * @package core_form + * @category form + * @copyright 2019 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->libdir . '/form/text.php'); + +/** + * Float type form element. + * + * This is preferred over the text element when working with float numbers, and takes care of the fact that different languages + * may use different symbols as the decimal separator. + * Using this element, submitted float numbers will be automatically translated from the localised format into the computer format, + * and vice versa when they are being displayed. + * + * @copyright 2019 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class MoodleQuickForm_float extends MoodleQuickForm_text { + + /** + * MoodleQuickForm_float constructor. + * + * @param string $elementName (optional) name of the float field + * @param string $elementLabel (optional) float field label + * @param string $attributes (optional) Either a typical HTML attribute string or an associative array + */ + public function __construct($elementName = null, $elementLabel = null, $attributes = null) { + parent::__construct($elementName, $elementLabel, $attributes); + $this->_type = 'float'; + } + + /** + * Called by HTML_QuickForm whenever form event is made on this element. + * + * @param string $event Name of event + * @param mixed $arg event arguments + * @param object $caller calling object + * @return bool + */ + public function onQuickFormEvent($event, $arg, &$caller) { + switch ($event) { + case 'updateValue': + if ($value = $this->_findValue($caller->_constantValues)) { + $value = $this->format_float($value); + } + if (null === $value) { + $value = $this->_findValue($caller->_submitValues); + if (null === $value) { + if ($value = $this->_findValue($caller->_defaultValues)) { + $value = $this->format_float($value); + } + } + } + if (null !== $value) { + parent::setValue($value); + } + return true; + case 'createElement': + $caller->setType($arg[0], PARAM_RAW_TRIMMED); + default: + return parent::onQuickFormEvent($event, $arg, $caller); + } + } + + /** + * Checks that the submitted value is a valid float number. + * + * @param string $value The localised float number that is submitted. + * @return string|null Validation error message or null. + */ + public function validateSubmitValue($value) { + if (false === unformat_float($value, true)) { + return get_string('err_numeric', 'core_form'); + } + } + + /** + * Sets the value of the form element. + * + * @param string $value Default value of the form element + */ + public function setValue($value) { + $value = $this->format_float($value); + parent::setValue($value); + } + + /** + * Returns the value of the form element. + * + * @return false|float + */ + public function getValue() { + $value = parent::getValue(); + if ($value) { + $value = unformat_float($value, true); + } + return $value; + } + + /** + * Returns a 'safe' element's value. + * + * @param array $submitValues array of submitted values to search + * @param bool $assoc whether to return the value as associative array + * @return mixed + */ + public function exportValue(&$submitValues, $assoc = false) { + $value = $this->_findValue($submitValues); + if (null === $value) { + $value = $this->getValue(); + } else if ($value) { + $value = unformat_float($value, true); + } + return $this->_prepareValue($value, $assoc); + } + + /** + * Used by getFrozenHtml() to pass the element's value if _persistantFreeze is on. + * + * @return string + */ + public function _getPersistantData() { + if (!$this->_persistantFreeze) { + return ''; + } else { + $id = $this->getAttribute('id'); + if (isset($id)) { + // Id of persistant input is different then the actual input. + $id = array('id' => $id . '_persistant'); + } else { + $id = array(); + } + + return '_getAttrString(array( + 'type' => 'hidden', + 'name' => $this->getAttribute('name'), + 'value' => $this->getAttribute('value') + ) + $id) . ' />'; + } + } + + /** + * Given a float, prints it nicely. + * This function reserves the number of decimal places. + * + * @param float|null $value The float number to format + * @return string Localised float + */ + private function format_float($value) { + if (is_numeric($value)) { + if ($value > 0) { + $decimals = strlen($value) - strlen(floor($value)) - 1; + } else { + $decimals = strlen($value) - strlen(ceil($value)) - 1; + } + $value = format_float($value, $decimals); + } + return $value; + } +} diff --git a/lib/form/tests/float_test.php b/lib/form/tests/float_test.php new file mode 100644 index 00000000000..edb72fb1e87 --- /dev/null +++ b/lib/form/tests/float_test.php @@ -0,0 +1,99 @@ +. + +/** + * Unit tests for float form element. + * + * @package core_form + * @category test + * @copyright 2019 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->libdir . '/form/float.php'); + +/** + * Unit tests for MoodleQuickForm_float + * + * Contains test cases for testing MoodleQuickForm_float + * + * @package core_form + * @copyright 2019 Shamim Rezaie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class core_form_float_testcase extends advanced_testcase { + + /** + * Define a local decimal separator. + * + * It is not possible to directly change the result of get_string in + * a unit test. Instead, we create a language pack for language 'xx' in + * dataroot and make langconfig.php with the string we need to change. + * The example separator used here is 'X'. + */ + protected function define_local_decimal_separator() { + global $SESSION, $CFG; + + $SESSION->lang = 'xx'; + $langconfig = "dataroot . '/lang/xx'; + check_dir_exists($langfolder); + file_put_contents($langfolder . '/langconfig.php', $langconfig); + } + + /** + * Testcase to check generated timestamp + */ + public function test_exportValue() { + $element = new MoodleQuickForm_float('testel'); + + $value = ['testel' => 3.14]; + $this->assertEquals(3.14, $element->exportValue($value)); + + $value = ['testel' => '3.14']; + $this->assertEquals(3.14, $element->exportValue($value)); + + $value = ['testel' => '-3.14']; + $this->assertEquals(-3.14, $element->exportValue($value)); + + $value = ['testel' => '3.14blah']; + $this->assertEquals(false, $element->exportValue($value)); + + $value = ['testel' => 'blah']; + $this->assertEquals(false, $element->exportValue($value)); + + // Tests with a localised decimal separator. + $this->define_local_decimal_separator(); + + $value = ['testel' => 3.14]; + $this->assertEquals(3.14, $element->exportValue($value)); + + $value = ['testel' => '3X14']; + $this->assertEquals(3.14, $element->exportValue($value)); + + $value = ['testel' => '-3X14']; + $this->assertEquals(-3.14, $element->exportValue($value)); + + $value = ['testel' => '3X14blah']; + $this->assertEquals(false, $element->exportValue($value)); + + $value = ['testel' => 'blah']; + $this->assertEquals(false, $element->exportValue($value)); + } +} diff --git a/lib/formslib.php b/lib/formslib.php index 9e2c96f0190..c37fd3e670e 100644 --- a/lib/formslib.php +++ b/lib/formslib.php @@ -3241,6 +3241,7 @@ MoodleQuickForm::registerElementType('editor', "$CFG->libdir/form/editor.php", ' MoodleQuickForm::registerElementType('filemanager', "$CFG->libdir/form/filemanager.php", 'MoodleQuickForm_filemanager'); MoodleQuickForm::registerElementType('filepicker', "$CFG->libdir/form/filepicker.php", 'MoodleQuickForm_filepicker'); MoodleQuickForm::registerElementType('filetypes', "$CFG->libdir/form/filetypes.php", 'MoodleQuickForm_filetypes'); +MoodleQuickForm::registerElementType('float', "$CFG->libdir/form/float.php", 'MoodleQuickForm_float'); MoodleQuickForm::registerElementType('grading', "$CFG->libdir/form/grading.php", 'MoodleQuickForm_grading'); MoodleQuickForm::registerElementType('group', "$CFG->libdir/form/group.php", 'MoodleQuickForm_group'); MoodleQuickForm::registerElementType('header', "$CFG->libdir/form/header.php", 'MoodleQuickForm_header'); diff --git a/lib/upgrade.txt b/lib/upgrade.txt index d73a1fe4616..30dbd057adb 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -48,6 +48,7 @@ is disabled). * The following functions have been updated to support the new usage: - make_pluginfile_url - file_rewrite_pluginfile_urls +* New mform element 'float' handles localised floating point numbers. === 3.6 === diff --git a/theme/boost/templates/core_form/element-float-inline.mustache b/theme/boost/templates/core_form/element-float-inline.mustache new file mode 100644 index 00000000000..ab31355a494 --- /dev/null +++ b/theme/boost/templates/core_form/element-float-inline.mustache @@ -0,0 +1 @@ +{{> core_form/element-text-inline }} diff --git a/theme/boost/templates/core_form/element-float.mustache b/theme/boost/templates/core_form/element-float.mustache new file mode 100644 index 00000000000..b7270e2ef71 --- /dev/null +++ b/theme/boost/templates/core_form/element-float.mustache @@ -0,0 +1 @@ +{{> core_form/element-text }} -- 2.43.0