PageRenderTime 50ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/form/datetimeselector.php

http://github.com/moodle/moodle
PHP | 338 lines | 191 code | 23 blank | 124 comment | 36 complexity | 4e4f82f9e75230b896dcf0c6356a419c MD5 | raw file
Possible License(s): MIT, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, Apache-2.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Group of date and time input element
  18. *
  19. * Contains class for a group of elements used to input a date and time.
  20. *
  21. * @package core_form
  22. * @copyright 2006 Jamie Pratt <me@jamiep.org>
  23. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24. */
  25. global $CFG;
  26. require_once($CFG->libdir . '/form/group.php');
  27. require_once($CFG->libdir . '/formslib.php');
  28. /**
  29. * Element used to input a date and time.
  30. *
  31. * Class for a group of elements used to input a date and time.
  32. *
  33. * @package core_form
  34. * @category form
  35. * @copyright 2006 Jamie Pratt <me@jamiep.org>
  36. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37. */
  38. class MoodleQuickForm_date_time_selector extends MoodleQuickForm_group {
  39. /**
  40. * Options for the element.
  41. *
  42. * startyear => int start of range of years that can be selected
  43. * stopyear => int last year that can be selected
  44. * defaulttime => default time value if the field is currently not set
  45. * timezone => int|float|string (optional) timezone modifier used for edge case only.
  46. * If not specified, then date is caclulated based on current user timezone.
  47. * Note: dst will be calculated for string timezones only
  48. * {@link http://docs.moodle.org/dev/Time_API#Timezone}
  49. * step => step to increment minutes by
  50. * optional => if true, show a checkbox beside the date to turn it on (or off)
  51. * @var array
  52. */
  53. protected $_options = array();
  54. /**
  55. * @var array These complement separators, they are appended to the resultant HTML.
  56. */
  57. protected $_wrap = array('', '');
  58. /**
  59. * @var null|bool Keeps track of whether the date selector was initialised using createElement
  60. * or addElement. If true, createElement was used signifying the element has been
  61. * added to a group - see MDL-39187.
  62. */
  63. protected $_usedcreateelement = true;
  64. /**
  65. * Class constructor
  66. *
  67. * @param string $elementName Element's name
  68. * @param mixed $elementLabel Label(s) for an element
  69. * @param array $options Options to control the element's display
  70. * @param mixed $attributes Either a typical HTML attribute string or an associative array
  71. */
  72. public function __construct($elementName = null, $elementLabel = null, $options = array(), $attributes = null) {
  73. // Get the calendar type used - see MDL-18375.
  74. $calendartype = \core_calendar\type_factory::get_calendar_instance();
  75. $this->_options = array('startyear' => $calendartype->get_min_year(), 'stopyear' => $calendartype->get_max_year(),
  76. 'defaulttime' => 0, 'timezone' => 99, 'step' => 1, 'optional' => false);
  77. // TODO MDL-52313 Replace with the call to parent::__construct().
  78. HTML_QuickForm_element::__construct($elementName, $elementLabel, $attributes);
  79. $this->_persistantFreeze = true;
  80. $this->_appendName = true;
  81. $this->_type = 'date_time_selector';
  82. // set the options, do not bother setting bogus ones
  83. if (is_array($options)) {
  84. foreach ($options as $name => $value) {
  85. if (isset($this->_options[$name])) {
  86. if (is_array($value) && is_array($this->_options[$name])) {
  87. $this->_options[$name] = @array_merge($this->_options[$name], $value);
  88. } else {
  89. $this->_options[$name] = $value;
  90. }
  91. }
  92. }
  93. }
  94. }
  95. /**
  96. * Old syntax of class constructor. Deprecated in PHP7.
  97. *
  98. * @deprecated since Moodle 3.1
  99. */
  100. public function MoodleQuickForm_date_time_selector($elementName = null, $elementLabel = null, $options = array(), $attributes = null) {
  101. debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
  102. self::__construct($elementName, $elementLabel, $options, $attributes);
  103. }
  104. /**
  105. * This will create date group element constisting of day, month and year.
  106. *
  107. * @access private
  108. */
  109. function _createElements() {
  110. global $OUTPUT;
  111. // Get the calendar type used - see MDL-18375.
  112. $calendartype = \core_calendar\type_factory::get_calendar_instance();
  113. for ($i = 0; $i <= 23; $i++) {
  114. $hours[$i] = sprintf("%02d", $i);
  115. }
  116. for ($i = 0; $i < 60; $i += $this->_options['step']) {
  117. $minutes[$i] = sprintf("%02d", $i);
  118. }
  119. $this->_elements = array();
  120. $dateformat = $calendartype->get_date_order($this->_options['startyear'], $this->_options['stopyear']);
  121. if (right_to_left()) { // Display time to the right of date, in RTL mode.
  122. $this->_elements[] = $this->createFormElement('select', 'minute', get_string('minute', 'form'),
  123. $minutes, $this->getAttributes(), true);
  124. $this->_elements[] = $this->createFormElement('select', 'hour', get_string('hour', 'form'),
  125. $hours, $this->getAttributes(), true);
  126. // Reverse date element (Should be: Day, Month, Year), in RTL mode.
  127. $dateformat = array_reverse($dateformat);
  128. }
  129. foreach ($dateformat as $key => $date) {
  130. // E_STRICT creating elements without forms is nasty because it internally uses $this
  131. $this->_elements[] = $this->createFormElement('select', $key, get_string($key, 'form'), $date, $this->getAttributes(), true);
  132. }
  133. if (!right_to_left()) { // Display time to the left of date, in LTR mode.
  134. $this->_elements[] = $this->createFormElement('select', 'hour', get_string('hour', 'form'), $hours,
  135. $this->getAttributes(), true);
  136. $this->_elements[] = $this->createFormElement('select', 'minute', get_string('minute', 'form'), $minutes,
  137. $this->getAttributes(), true);
  138. }
  139. // The YUI2 calendar only supports the gregorian calendar type so only display the calendar image if this is being used.
  140. if ($calendartype->get_name() === 'gregorian') {
  141. $image = $OUTPUT->pix_icon('i/calendar', get_string('calendar', 'calendar'), 'moodle');
  142. $this->_elements[] = $this->createFormElement('link', 'calendar',
  143. null, '#', $image,
  144. array('class' => 'visibleifjs'));
  145. }
  146. // If optional we add a checkbox which the user can use to turn if on
  147. if ($this->_options['optional']) {
  148. $this->_elements[] = $this->createFormElement('checkbox', 'enabled', null, get_string('enable'), $this->getAttributes(), true);
  149. }
  150. foreach ($this->_elements as $element){
  151. if (method_exists($element, 'setHiddenLabel')){
  152. $element->setHiddenLabel(true);
  153. }
  154. }
  155. }
  156. /**
  157. * Called by HTML_QuickForm whenever form event is made on this element
  158. *
  159. * @param string $event Name of event
  160. * @param mixed $arg event arguments
  161. * @param object $caller calling object
  162. * @return bool
  163. */
  164. function onQuickFormEvent($event, $arg, &$caller) {
  165. $this->setMoodleForm($caller);
  166. switch ($event) {
  167. case 'updateValue':
  168. // Constant values override both default and submitted ones
  169. // default values are overriden by submitted.
  170. $value = $this->_findValue($caller->_constantValues);
  171. if (null === $value) {
  172. // If no boxes were checked, then there is no value in the array
  173. // yet we don't want to display default value in this case.
  174. if ($caller->isSubmitted() && !$caller->is_new_repeat($this->getName())) {
  175. $value = $this->_findValue($caller->_submitValues);
  176. } else {
  177. $value = $this->_findValue($caller->_defaultValues);
  178. }
  179. }
  180. $requestvalue=$value;
  181. if ($value == 0) {
  182. $value = $this->_options['defaulttime'];
  183. if (!$value) {
  184. $value = time();
  185. }
  186. }
  187. if (!is_array($value)) {
  188. $calendartype = \core_calendar\type_factory::get_calendar_instance();
  189. $currentdate = $calendartype->timestamp_to_date_array($value, $this->_options['timezone']);
  190. // Round minutes to the previous multiple of step.
  191. $currentdate['minutes'] -= $currentdate['minutes'] % $this->_options['step'];
  192. $value = array(
  193. 'minute' => $currentdate['minutes'],
  194. 'hour' => $currentdate['hours'],
  195. 'day' => $currentdate['mday'],
  196. 'month' => $currentdate['mon'],
  197. 'year' => $currentdate['year']);
  198. // If optional, default to off, unless a date was provided.
  199. if ($this->_options['optional']) {
  200. $value['enabled'] = $requestvalue != 0;
  201. }
  202. } else {
  203. $value['enabled'] = isset($value['enabled']);
  204. }
  205. if (null !== $value) {
  206. $this->setValue($value);
  207. }
  208. break;
  209. case 'createElement':
  210. if (isset($arg[2]['optional']) && $arg[2]['optional']) {
  211. // When using the function addElement, rather than createElement, we still
  212. // enter this case, making this check necessary.
  213. if ($this->_usedcreateelement) {
  214. $caller->disabledIf($arg[0] . '[day]', $arg[0] . '[enabled]');
  215. $caller->disabledIf($arg[0] . '[month]', $arg[0] . '[enabled]');
  216. $caller->disabledIf($arg[0] . '[year]', $arg[0] . '[enabled]');
  217. $caller->disabledIf($arg[0] . '[hour]', $arg[0] . '[enabled]');
  218. $caller->disabledIf($arg[0] . '[minute]', $arg[0] . '[enabled]');
  219. } else {
  220. $caller->disabledIf($arg[0], $arg[0] . '[enabled]');
  221. }
  222. }
  223. return parent::onQuickFormEvent($event, $arg, $caller);
  224. break;
  225. case 'addElement':
  226. $this->_usedcreateelement = false;
  227. return parent::onQuickFormEvent($event, $arg, $caller);
  228. break;
  229. default:
  230. return parent::onQuickFormEvent($event, $arg, $caller);
  231. }
  232. }
  233. /**
  234. * Returns HTML for advchecbox form element.
  235. *
  236. * @return string
  237. */
  238. function toHtml() {
  239. include_once('HTML/QuickForm/Renderer/Default.php');
  240. $renderer = new HTML_QuickForm_Renderer_Default();
  241. $renderer->setElementTemplate('{element}');
  242. parent::accept($renderer);
  243. $html = $this->_wrap[0];
  244. if ($this->_usedcreateelement) {
  245. $html .= html_writer::tag('span', $renderer->toHtml(), array('class' => 'fdate_time_selector'));
  246. } else {
  247. $html .= $renderer->toHtml();
  248. }
  249. $html .= $this->_wrap[1];
  250. return $html;
  251. }
  252. /**
  253. * Accepts a renderer
  254. *
  255. * @param HTML_QuickForm_Renderer $renderer An HTML_QuickForm_Renderer object
  256. * @param bool $required Whether a group is required
  257. * @param string $error An error message associated with a group
  258. */
  259. function accept(&$renderer, $required = false, $error = null) {
  260. form_init_date_js();
  261. $renderer->renderElement($this, $required, $error);
  262. }
  263. /**
  264. * Export for template
  265. *
  266. * @param renderer_base $output
  267. * @return array|stdClass
  268. */
  269. public function export_for_template(renderer_base $output) {
  270. form_init_date_js();
  271. return parent::export_for_template($output);
  272. }
  273. /**
  274. * Output a timestamp. Give it the name of the group.
  275. *
  276. * @param array $submitValues values submitted.
  277. * @param bool $assoc specifies if returned array is associative
  278. * @return array
  279. */
  280. function exportValue(&$submitValues, $assoc = false) {
  281. $valuearray = array();
  282. foreach ($this->_elements as $element){
  283. $thisexport = $element->exportValue($submitValues[$this->getName()], true);
  284. if ($thisexport!=null){
  285. $valuearray += $thisexport;
  286. }
  287. }
  288. if (count($valuearray)){
  289. if($this->_options['optional']) {
  290. // If checkbox is on, the value is zero, so go no further
  291. if(empty($valuearray['enabled'])) {
  292. return $this->_prepareValue(0, $assoc);
  293. }
  294. }
  295. // Get the calendar type used - see MDL-18375.
  296. $calendartype = \core_calendar\type_factory::get_calendar_instance();
  297. $gregoriandate = $calendartype->convert_to_gregorian($valuearray['year'],
  298. $valuearray['month'],
  299. $valuearray['day'],
  300. $valuearray['hour'],
  301. $valuearray['minute']);
  302. $value = make_timestamp($gregoriandate['year'],
  303. $gregoriandate['month'],
  304. $gregoriandate['day'],
  305. $gregoriandate['hour'],
  306. $gregoriandate['minute'],
  307. 0,
  308. $this->_options['timezone'],
  309. true);
  310. return $this->_prepareValue($value, $assoc);
  311. } else {
  312. return null;
  313. }
  314. }
  315. }