date.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. <?php
  2. /**
  3. * @file
  4. * Webform module date component.
  5. */
  6. /**
  7. * Implements _webform_defaults_component().
  8. */
  9. function _webform_defaults_date() {
  10. return array(
  11. 'name' => '',
  12. 'form_key' => NULL,
  13. 'pid' => 0,
  14. 'weight' => 0,
  15. 'value' => '',
  16. 'mandatory' => 0,
  17. 'extra' => array(
  18. 'timezone' => 'user',
  19. 'start_date' => '-2 years',
  20. 'end_date' => '+2 years',
  21. 'year_textfield' => 0,
  22. 'datepicker' => 1,
  23. 'title_display' => 0,
  24. 'description' => '',
  25. 'private' => FALSE,
  26. ),
  27. );
  28. }
  29. /**
  30. * Implements _webform_theme_component().
  31. */
  32. function _webform_theme_date() {
  33. return array(
  34. 'webform_date' => array(
  35. 'render element' => 'element',
  36. 'file' => 'components/date.inc',
  37. ),
  38. 'webform_display_date' => array(
  39. 'render element' => 'element',
  40. 'file' => 'components/date.inc',
  41. ),
  42. 'webform_calendar' => array(
  43. 'variables' => array('component' => NULL, 'calendar_classes' => NULL),
  44. 'template' => 'templates/webform-calendar',
  45. ),
  46. );
  47. }
  48. /**
  49. * Implements _webform_edit_component().
  50. */
  51. function _webform_edit_date($component) {
  52. $form = array();
  53. $form['value'] = array(
  54. '#type' => 'textfield',
  55. '#title' => t('Default value'),
  56. '#default_value' => $component['value'],
  57. '#description' => t('The default value of the field.') . '<br />' . t('Accepts any date in any <a href="http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html">GNU Date Input Format</a>. Strings such as today, +2 months, and Dec 9 2004 are all valid.'),
  58. '#size' => 60,
  59. '#maxlength' => 127,
  60. '#weight' => 0,
  61. );
  62. $form['extra']['timezone'] = array(
  63. '#type' => 'radios',
  64. '#title' => t('Default value timezone'),
  65. '#default_value' => empty($component['extra']['timezone']) ? 'user' : $component['extra']['timezone'],
  66. '#description' => t('If using relative dates for a default value (e.g. "today") base the current day on this timezone.'),
  67. '#options' => array('user' => t('User timezone'), 'site' => t('Website timezone')),
  68. '#weight' => 2,
  69. '#access' => variable_get('configurable_timezones', 1),
  70. );
  71. $form['display']['datepicker'] = array(
  72. '#type' => 'checkbox',
  73. '#title' => t('Enable popup calendar'),
  74. '#default_value' => $component['extra']['datepicker'],
  75. '#description' => t('Enable a JavaScript date picker next to the date field.'),
  76. '#weight' => 2,
  77. '#parents' => array('extra', 'datepicker'),
  78. );
  79. $form['display']['year_textfield'] = array(
  80. '#type' => 'checkbox',
  81. '#title' => t('Use a textfield for year'),
  82. '#default_value' => $component['extra']['year_textfield'],
  83. '#description' => t('If checked, the generated date field will use a textfield for the year. Otherwise it will use a select list.'),
  84. '#weight' => 5,
  85. '#parents' => array('extra', 'year_textfield'),
  86. );
  87. $form['validation']['start_date'] = array(
  88. '#type' => 'textfield',
  89. '#title' => t('Start date'),
  90. '#default_value' => $component['extra']['start_date'],
  91. '#description' => t('The earliest date that may be entered into the field.') . ' ' . t('Accepts any date in any <a href="http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html">GNU Date Input Format</a>.'),
  92. '#size' => 30,
  93. '#weight' => 3,
  94. '#parents' => array('extra', 'start_date'),
  95. );
  96. $form['validation']['end_date'] = array(
  97. '#type' => 'textfield',
  98. '#title' => t('End date'),
  99. '#default_value' => $component['extra']['end_date'],
  100. '#description' => t('The latest date that may be entered into the field.') . ' ' . t('Accepts any date in any <a href="http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html">GNU Date Input Format</a>.'),
  101. '#size' => 30,
  102. '#weight' => 4,
  103. '#parents' => array('extra', 'end_date'),
  104. );
  105. return $form;
  106. }
  107. /**
  108. * Implements _webform_render_component().
  109. */
  110. function _webform_render_date($component, $value = NULL, $filter = TRUE) {
  111. $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
  112. $element = array(
  113. '#type' => 'date',
  114. '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
  115. '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
  116. '#weight' => $component['weight'],
  117. '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
  118. '#required' => $component['mandatory'],
  119. '#start_date' => trim($component['extra']['start_date']),
  120. '#end_date' => trim($component['extra']['end_date']),
  121. '#year_textfield' => $component['extra']['year_textfield'],
  122. '#default_value' => $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'],
  123. '#timezone' => $component['extra']['timezone'],
  124. '#process' => array('webform_expand_date'),
  125. '#theme' => 'webform_date',
  126. '#theme_wrappers' => array('webform_element'),
  127. '#element_validate' => array('webform_validate_date'),
  128. '#translatable' => array('title', 'description'),
  129. );
  130. if ($component['extra']['datepicker']) {
  131. $element['#datepicker'] = TRUE;
  132. $element['#attached'] = array(
  133. 'library' => array(
  134. array('system', 'ui.datepicker'),
  135. ),
  136. );
  137. }
  138. // Set the value from Webform.
  139. if (isset($value[0]) && $value[0] !== '') {
  140. $value = webform_date_array($value[0], 'date');
  141. $element['#default_value'] = $value;
  142. }
  143. return $element;
  144. }
  145. /**
  146. * Form API #process function for Webform date fields.
  147. */
  148. function webform_expand_date($element) {
  149. // Accept a string or array value for #default_value.
  150. if (!empty($element['#default_value']) && is_string($element['#default_value'])) {
  151. $timezone = $element['#timezone'] != 'user' ? NULL : 'user';
  152. $timestring = webform_strtodate('c', $element['#default_value'], $timezone);
  153. $element['#default_value'] = webform_date_array($timestring, 'date');
  154. }
  155. // Prevent an error in PHP 5.4 caused by core's treatment of the #value.
  156. if (isset($element['#value'])) {
  157. unset($element['#value']);
  158. }
  159. // Set defaults according to existing #default_value (set by Form API)
  160. if (isset($element['#default_value']['month']) || isset($element['#default_value']['day']) || isset($element['#default_value']['year'])) {
  161. $default_values = array(
  162. 'month' => $element['#default_value']['month'],
  163. 'day' => $element['#default_value']['day'],
  164. 'year' => $element['#default_value']['year'],
  165. );
  166. }
  167. else {
  168. $default_values = array(
  169. 'day' => NULL,
  170. 'month' => NULL,
  171. 'year' => NULL,
  172. );
  173. }
  174. // Let Drupal do it's normal expansion.
  175. $element = form_process_date($element);
  176. // Set default values.
  177. foreach ($default_values as $type => $value) {
  178. switch ($type) {
  179. case 'month':
  180. $none = t('Month');
  181. break;
  182. case 'day':
  183. $none = t('Day');
  184. break;
  185. case 'year':
  186. $none = t('Year');
  187. break;
  188. }
  189. unset($element[$type]['#value']);
  190. $element[$type]['#title'] = $none;
  191. $element[$type]['#title_display'] = 'invisible';
  192. $element[$type]['#default_value'] = isset($default_values[$type]) ? $default_values[$type] : NULL;
  193. $element[$type]['#options'] = array('' => $none) + $element[$type]['#options'];
  194. }
  195. // Convert relative dates to absolute ones.
  196. foreach (array('start_date', 'end_date') as $start_end) {
  197. $timezone = $element['#timezone'] != 'user' ? NULL : 'user';
  198. $date = webform_strtodate('Y-m-d', $element['#' . $start_end], $timezone);
  199. $element['#' . $start_end] = $date ? $date : '';
  200. }
  201. // Tweak the year field.
  202. if ($element['#year_textfield']) {
  203. $element['year']['#type'] = 'textfield';
  204. $element['year']['#size'] = 5;
  205. $element['year']['#maxlength'] = 4;
  206. unset($element['year']['#options']);
  207. }
  208. elseif ($element['#start_date'] || $element['#end_date']) {
  209. $start_year = $element['#start_date'] ? webform_strtodate('Y', $element['#start_date']) : webform_strtodate('Y', '-2 years');
  210. $end_year = $element['#end_date'] ? webform_strtodate('Y', $element['#end_date']) : webform_strtodate('Y', '+2 years');
  211. $element['year']['#options'] = array('' => t('Year')) + drupal_map_assoc(range($start_year, $end_year));
  212. }
  213. return $element;
  214. }
  215. /**
  216. * Theme a webform date element.
  217. */
  218. function theme_webform_date($variables) {
  219. $element = $variables['element'];
  220. $element['year']['#attributes']['class'][] = 'year';
  221. $element['month']['#attributes']['class'][] = 'month';
  222. $element['day']['#attributes']['class'][] = 'day';
  223. // Add error classes to all items within the element.
  224. if (form_get_error($element)) {
  225. $element['year']['#attributes']['class'][] = 'error';
  226. $element['month']['#attributes']['class'][] = 'error';
  227. $element['day']['#attributes']['class'][] = 'error';
  228. }
  229. $class = array('webform-container-inline');
  230. // Add the JavaScript calendar if available (provided by Date module package).
  231. if (!empty($element['#datepicker'])) {
  232. $class[] = 'webform-datepicker';
  233. $calendar_class = array('webform-calendar');
  234. if ($element['#start_date']) {
  235. $calendar_class[] = 'webform-calendar-start-' . $element['#start_date'];
  236. }
  237. if ($element['#end_date']) {
  238. $calendar_class[] = 'webform-calendar-end-' . $element['#end_date'];
  239. }
  240. $calendar_class[] ='webform-calendar-day-' . variable_get('date_first_day', 0);
  241. $calendar = theme('webform_calendar', array('component' => $element['#webform_component'], 'calendar_classes' => $calendar_class));
  242. }
  243. $output = '';
  244. $output .= '<div class="' . implode(' ', $class) . '">';
  245. $output .= drupal_render_children($element);
  246. $output .= isset($calendar) ? $calendar : '';
  247. $output .= '</div>';
  248. return $output;
  249. }
  250. /**
  251. * Element validation for Webform date fields.
  252. */
  253. function webform_validate_date($element, $form_state) {
  254. // Check if the user filled the required fields.
  255. foreach (array('day', 'month', 'year') as $field_type) {
  256. if (!is_numeric($element[$field_type]['#value']) && $element['#required']) {
  257. form_error($element, t('!name field is required.', array('!name' => $element['#title'])));
  258. return;
  259. }
  260. }
  261. if ($element['month']['#value'] !== '' || $element['day']['#value'] !== '' || $element['year']['#value'] !== '') {
  262. // Check for a valid date.
  263. if (!checkdate((int) $element['month']['#value'], (int) $element['day']['#value'], (int) $element['year']['#value'])) {
  264. form_error($element, t('Entered !name is not a valid date.', array('!name' => $element['#title'])));
  265. return;
  266. }
  267. // Create a timestamp of the entered value for comparison.
  268. $timestamp = strtotime($element['year']['#value'] . '-' . $element['month']['#value'] . '-' . $element['day']['#value']);
  269. $format = webform_date_format('short');
  270. // Flip start and end if needed.
  271. $date1 = strtotime($element['#start_date']);
  272. $date2 = strtotime($element['#end_date']);
  273. if ($date1 !== FALSE && $date2 !== FALSE) {
  274. $start_date = $date1 < $date2 ? $date1 : $date2;
  275. $end_date = $date1 > $date2 ? $date1 : $date2;
  276. }
  277. else {
  278. $start_date = $date1;
  279. $end_date = $date2;
  280. }
  281. // Check that the date is after the start date.
  282. if ($start_date !== FALSE) {
  283. if ($timestamp < $start_date) {
  284. form_error($element, t('The entered date must be @start_date or later.', array('@start_date' => date($format, $start_date))));
  285. }
  286. }
  287. // Check that the date is before the end date.
  288. if ($end_date !== FALSE) {
  289. if ($timestamp > $end_date) {
  290. form_error($element, t('The entered date must be @end_date or earlier.', array('@end_date' => date($format, $end_date))));
  291. }
  292. }
  293. }
  294. }
  295. /**
  296. * Implements _webform_submit_component().
  297. */
  298. function _webform_submit_date($component, $value) {
  299. // Convert the date to an ISO 8601 format.
  300. return ($value['year'] && $value['month'] && $value['day']) ? webform_date_string($value, 'date') : '';
  301. }
  302. /**
  303. * Implements _webform_display_component().
  304. */
  305. function _webform_display_date($component, $value, $format = 'html') {
  306. $value = webform_date_array(isset($value[0]) ? $value[0] : '', 'date');
  307. return array(
  308. '#title' => $component['name'],
  309. '#weight' => $component['weight'],
  310. '#theme' => 'webform_display_date',
  311. '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
  312. '#format' => $format,
  313. '#value' => $value,
  314. '#translatable' => array('title'),
  315. );
  316. }
  317. /**
  318. * Format the text output for this component.
  319. */
  320. function theme_webform_display_date($variables) {
  321. $element = $variables['element'];
  322. $output = ' ';
  323. if ($element['#value']['year'] && $element['#value']['month'] && $element['#value']['day']) {
  324. $timestamp = webform_strtotime($element['#value']['month'] . '/' . $element['#value']['day'] . '/' . $element['#value']['year']);
  325. $format = webform_date_format('medium');
  326. $output = format_date($timestamp, 'custom', $format, 'UTC');
  327. }
  328. return $output;
  329. }
  330. /**
  331. * Implements _webform_analysis_component().
  332. */
  333. function _webform_analysis_date($component, $sids = array()) {
  334. $query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
  335. ->fields('wsd', array('no', 'data'))
  336. ->condition('nid', $component['nid'])
  337. ->condition('cid', $component['cid'])
  338. ->orderBy('sid');
  339. if (count($sids)) {
  340. $query->condition('sid', $sids, 'IN');
  341. }
  342. $result = $query->execute();
  343. $dates = array();
  344. $submissions = 0;
  345. foreach ($result as $row) {
  346. $submissions++;
  347. if ($row['data']) {
  348. $dates[] = webform_date_array($row['data']);
  349. }
  350. }
  351. // Display stats.
  352. $nonblanks = count($dates);
  353. $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
  354. $rows[1] = array(t('User entered value'), $nonblanks);
  355. return $rows;
  356. }
  357. /**
  358. * Implements _webform_table_component().
  359. */
  360. function _webform_table_date($component, $value) {
  361. if ($value[0]) {
  362. $timestamp = webform_strtotime($value[0]);
  363. $format = webform_date_format('short');
  364. return format_date($timestamp, 'custom', $format, 'UTC');
  365. }
  366. else {
  367. return '';
  368. }
  369. }
  370. /**
  371. * Implements _webform_csv_headers_component().
  372. */
  373. function _webform_csv_headers_date($component, $export_options) {
  374. $header = array();
  375. $header[0] = '';
  376. $header[1] = '';
  377. $header[2] = $component['name'];
  378. return $header;
  379. }
  380. /**
  381. * Implements _webform_csv_data_component().
  382. */
  383. function _webform_csv_data_date($component, $export_options, $value) {
  384. if ($value[0]) {
  385. $timestamp = webform_strtotime($value[0]);
  386. $format = webform_date_format('short');
  387. return format_date($timestamp, 'custom', $format, 'UTC');
  388. }
  389. else {
  390. return '';
  391. }
  392. }