DateRangePicker.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * Form element to select a range of dates (with popup datepicker).
  5. */
  6. class DateRangePicker extends HTML_QuickForm_text
  7. {
  8. /**
  9. * DateRangePicker constructor.
  10. *
  11. * @param string $elementName
  12. * @param string|array $elementLabel
  13. * @param array $attributes
  14. */
  15. public function __construct($elementName, $elementLabel = null, $attributes = null)
  16. {
  17. if (!isset($attributes['id'])) {
  18. $attributes['id'] = $elementName;
  19. }
  20. $attributes['class'] = 'form-control';
  21. parent::__construct($elementName, $elementLabel, $attributes);
  22. $this->_appendName = true;
  23. $this->_type = 'date_range_picker';
  24. }
  25. /**
  26. * @return string
  27. */
  28. public function toHtml()
  29. {
  30. $js = $this->getElementJS();
  31. $this->removeAttribute('format');
  32. $this->removeAttribute('timepicker');
  33. $this->removeAttribute('validate_format');
  34. return $js.parent::toHtml();
  35. }
  36. /**
  37. * @param string $value
  38. */
  39. public function setValue($value)
  40. {
  41. $this->updateAttributes(
  42. [
  43. 'value' => $value,
  44. ]
  45. );
  46. }
  47. /**
  48. * @param array $dateRange
  49. *
  50. * @return array
  51. */
  52. public function parseDateRange($dateRange)
  53. {
  54. $dateRange = Security::remove_XSS($dateRange);
  55. $dates = explode('/', $dateRange);
  56. $dates = array_map('trim', $dates);
  57. $start = isset($dates[0]) ? $dates[0] : '';
  58. $end = isset($dates[1]) ? $dates[1] : '';
  59. $pattern = 'yyyy-MM-dd HH:mm';
  60. if ('false' === $this->getAttribute('timePicker') &&
  61. false === strpos($this->getAttribute('format'), 'HH:mm')) {
  62. $pattern = 'yyyy-MM-dd';
  63. }
  64. $formatter = new IntlDateFormatter(
  65. 'en',
  66. IntlDateFormatter::NONE,
  67. IntlDateFormatter::NONE,
  68. 'UTC',
  69. IntlDateFormatter::GREGORIAN,
  70. $pattern
  71. );
  72. $resultStart = $formatter->format($formatter->parse($start));
  73. $resultEnd = $formatter->format($formatter->parse($end));
  74. return [
  75. 'start' => $resultStart,
  76. 'end' => $resultEnd,
  77. ];
  78. }
  79. /**
  80. * @param array $dates result of parseDateRange()
  81. *
  82. * @return bool
  83. */
  84. public function validateDates($dates, $format = null)
  85. {
  86. if (empty($dates['start']) || empty($dates['end'])) {
  87. return false;
  88. }
  89. $format = $format ? $format : 'Y-m-d H:i';
  90. $d = DateTime::createFromFormat($format, $dates['start']);
  91. $resultStart = $d && $d->format($format) == $dates['start'];
  92. $d = DateTime::createFromFormat($format, $dates['end']);
  93. $resultEnd = $d && $d->format($format) == $dates['end'];
  94. if (!$resultStart || !$resultEnd) {
  95. return false;
  96. }
  97. return true;
  98. }
  99. /**
  100. * @param mixed $value
  101. * @param array $submitValues
  102. * @param array $errors
  103. *
  104. * @return string
  105. */
  106. public function getSubmitValue($value, &$submitValues, &$errors)
  107. {
  108. /** @var DateRangePicker $element */
  109. $elementName = $this->getName();
  110. $parsedDates = $this->parseDateRange($value);
  111. $validateFormat = $this->getAttribute('validate_format');
  112. if (!$this->validateDates($parsedDates, $validateFormat)) {
  113. $errors[$elementName] = get_lang('Validate dates');
  114. }
  115. $submitValues[$elementName.'_start'] = $parsedDates['start'];
  116. $submitValues[$elementName.'_end'] = $parsedDates['end'];
  117. return $value;
  118. }
  119. /**
  120. * Get the necessary javascript for this datepicker.
  121. *
  122. * @return string
  123. */
  124. private function getElementJS()
  125. {
  126. $js = null;
  127. $id = $this->getAttribute('id');
  128. $dateRange = $this->getAttribute('value');
  129. $defaultDates = null;
  130. if (!empty($dateRange)) {
  131. $dates = $this->parseDateRange($dateRange);
  132. $defaultDates = "
  133. startDate: '".$dates['start']."',
  134. endDate: '".$dates['end']."', ";
  135. }
  136. $minDate = null;
  137. $minDateValue = Security::remove_XSS($this->getAttribute('minDate'));
  138. if (!empty($minDateValue)) {
  139. $minDate = "
  140. minDate: '{$minDateValue}',
  141. ";
  142. }
  143. $maxDate = null;
  144. $maxDateValue = Security::remove_XSS($this->getAttribute('maxDate'));
  145. if (!empty($maxDateValue)) {
  146. $maxDate = "
  147. maxDate: '{$maxDateValue}',
  148. ";
  149. }
  150. $format = 'YYYY-MM-DD HH:mm';
  151. $formatValue = Security::remove_XSS($this->getAttribute('format'));
  152. if (!empty($formatValue)) {
  153. $format = $formatValue;
  154. }
  155. $timePicker = 'true';
  156. $timePickerValue = Security::remove_XSS($this->getAttribute('timePicker'));
  157. if (!empty($timePickerValue)) {
  158. $timePicker = 'false';
  159. }
  160. // timeFormat: 'hh:mm'
  161. $js .= "<script>
  162. $(function() {
  163. $('#$id').daterangepicker({
  164. timePicker: $timePicker,
  165. timePickerIncrement: 30,
  166. timePicker12Hour: false,
  167. $defaultDates
  168. $maxDate
  169. $minDate
  170. ranges: {
  171. '".addslashes(get_lang('Today'))."': [moment(), moment()],
  172. '".addslashes(get_lang('Yesterday'))."': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
  173. '".addslashes(get_lang('This month'))."': [moment().startOf('month'), moment().endOf('month')],
  174. '".addslashes(get_lang('Last month'))."': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
  175. '".addslashes(get_lang('This week'))."': [moment().weekday(1), moment().weekday(5)],
  176. '".addslashes(get_lang('Next Week'))."': [moment().weekday(8), moment().weekday(12)]
  177. },
  178. //showDropdowns : true,
  179. locale: {
  180. separator: ' / ',
  181. format: '$format',
  182. applyLabel: '".addslashes(get_lang('Validate'))."',
  183. cancelLabel: '".addslashes(get_lang('Cancel'))."',
  184. fromLabel: '".addslashes(get_lang('From'))."',
  185. toLabel: '".addslashes(get_lang('Until'))."',
  186. customRangeLabel: '".addslashes(get_lang('Custom range'))."',
  187. }
  188. });
  189. $('#$id').on('change', function() {
  190. var myPickedDates = $('#$id').val().split('/');
  191. var {$id}_start = myPickedDates[0].trim();
  192. var {$id}_end = myPickedDates[1].trim();
  193. $('input[name={$id}_start]').val({$id}_start);
  194. $('input[name={$id}_end]').val({$id}_end);
  195. });
  196. });
  197. </script>";
  198. return $js;
  199. }
  200. }