date_repeat.module

  1. cis7 sites/all/modules/ulmus/date/date_repeat/date_repeat.module
  2. cle7 sites/all/modules/ulmus/date/date_repeat/date_repeat.module
  3. ecd7 sites/all/modules/ulmus/date/date_repeat/date_repeat.module
  4. elmsmedia7 sites/all/modules/ulmus/date/date_repeat/date_repeat.module
  5. harmony7 sites/all/modules/ulmus/date/date_repeat/date_repeat.module
  6. icor7 sites/all/modules/ulmus/date/date_repeat/date_repeat.module
  7. meedjum_blog7 sites/all/modules/ulmus/date/date_repeat/date_repeat.module
  8. mooc7 sites/all/modules/ulmus/date/date_repeat/date_repeat.module

This module creates a form element that allows users to select repeat rules for a date, and reworks the result into an iCal RRULE string that can be stored in the database.

The module also parses iCal RRULEs to create an array of dates that meet their criteria.

Other modules can use this API to add self-validating form elements to their dates, and identify dates that meet the RRULE criteria.

Functions

Namesort descending Description
date_repeat_calc Analyze a RRULE and return dates that match it.
date_repeat_days_ordered Shift the array of iCal day names into the right order for a specific week start day.
date_repeat_dow2day Translate a day of week position to the iCal day name.
date_repeat_dow_count_options Helper function for BYDAY options.
date_repeat_dow_day_options Helper function for FREQ options.
date_repeat_dow_day_options_abbr Helper function for FREQ options.
date_repeat_dow_day_options_ordered
date_repeat_dow_day_untranslated
date_repeat_dow_options Helper function for BYDAY options.
date_repeat_element_info Implements hook_element_info().
date_repeat_form_element_radios_process Process function for 'date_repeat_form_element_radios'.
date_repeat_freq_options Helper function for FREQ options.
date_repeat_interval_options
date_repeat_rrule_description Build a description of an iCal rule.
date_repeat_rrule_process Generate the repeat rule setting form.
date_repeat_split_rrule Parse an iCal rule into a parsed RRULE array and an EXDATE array.
date_repeat_theme

File

sites/all/modules/ulmus/date/date_repeat/date_repeat.module
View source
  1. <?php
  2. /**
  3. * @file
  4. *
  5. * This module creates a form element that allows users to select
  6. * repeat rules for a date, and reworks the result into an iCal
  7. * RRULE string that can be stored in the database.
  8. *
  9. * The module also parses iCal RRULEs to create an array of dates
  10. * that meet their criteria.
  11. *
  12. * Other modules can use this API to add self-validating form elements
  13. * to their dates, and identify dates that meet the RRULE criteria.
  14. *
  15. */
  16. /**
  17. * Implements hook_element_info().
  18. */
  19. function date_repeat_element_info() {
  20. $type['date_repeat_rrule'] = array(
  21. '#input' => TRUE,
  22. '#process' => array('date_repeat_rrule_process'),
  23. '#element_validate' => array('date_repeat_rrule_validate'),
  24. '#theme_wrappers' => array('date_repeat_rrule'),
  25. );
  26. $type['date_repeat_form_element_radios'] = array(
  27. '#input' => TRUE,
  28. '#process' => array('date_repeat_form_element_radios_process'),
  29. '#theme_wrappers' => array('radios'),
  30. '#pre_render' => array('form_pre_render_conditional_form_element'),
  31. );
  32. if (module_exists('ctools')) {
  33. $type['date_repeat_rrule']['#pre_render'] = array('ctools_dependent_pre_render');
  34. }
  35. return $type;
  36. }
  37. function date_repeat_theme() {
  38. return array(
  39. 'date_repeat_current_exceptions' => array('render element' => 'element'),
  40. 'date_repeat_current_additions' => array('render element' => 'element'),
  41. 'date_repeat_rrule' => array('render element' => 'element'),
  42. );
  43. }
  44. /**
  45. * Helper function for FREQ options.
  46. */
  47. function date_repeat_freq_options() {
  48. return array(
  49. 'DAILY' => t('Daily', array(), array('context' => 'datetime_singular')),
  50. 'WEEKLY' => t('Weekly', array(), array('context' => 'datetime_singular')),
  51. 'MONTHLY' => t('Monthly', array(), array('context' => 'datetime_singular')),
  52. 'YEARLY' => t('Yearly', array(), array('context' => 'datetime_singular')),
  53. );
  54. }
  55. function date_repeat_interval_options() {
  56. $options = range(0, 366);
  57. unset($options[0]);
  58. return $options;
  59. }
  60. /**
  61. * Helper function for FREQ options.
  62. *
  63. * Translated and untranslated arrays of the iCal day of week names.
  64. * We need the untranslated values for date_modify(), translated
  65. * values when displayed to user.
  66. */
  67. function date_repeat_dow_day_options($translated = TRUE) {
  68. return array(
  69. 'SU' => $translated ? t('Sunday', array(), array('context' => 'day_name')) : 'Sunday',
  70. 'MO' => $translated ? t('Monday', array(), array('context' => 'day_name')) : 'Monday',
  71. 'TU' => $translated ? t('Tuesday', array(), array('context' => 'day_name')) : 'Tuesday',
  72. 'WE' => $translated ? t('Wednesday', array(), array('context' => 'day_name')) : 'Wednesday',
  73. 'TH' => $translated ? t('Thursday', array(), array('context' => 'day_name')) : 'Thursday',
  74. 'FR' => $translated ? t('Friday', array(), array('context' => 'day_name')) : 'Friday',
  75. 'SA' => $translated ? t('Saturday', array(), array('context' => 'day_name')) : 'Saturday',
  76. );
  77. }
  78. /**
  79. * Helper function for FREQ options.
  80. *
  81. * Translated and untranslated arrays of the iCal abbreviated day of week names.
  82. */
  83. function date_repeat_dow_day_options_abbr($translated = TRUE, $length = 3) {
  84. $return = array();
  85. switch ($length) {
  86. case 1:
  87. $context = 'day_abbr1';
  88. break;
  89. case 2:
  90. $context = 'day_abbr2';
  91. break;
  92. default:
  93. $context = '';
  94. break;
  95. }
  96. foreach (date_repeat_dow_day_untranslated() as $key => $day) {
  97. $return[$key] = $translated ? t(substr($day, 0, $length), array(), array('context' => $context)) : substr($day, 0, $length);
  98. }
  99. return $return;
  100. }
  101. function date_repeat_dow_day_untranslated() {
  102. static $date_repeat_weekdays;
  103. if (empty($date_repeat_weekdays)) {
  104. $date_repeat_weekdays = array('SU' => 'Sunday', 'MO' => 'Monday', 'TU' => 'Tuesday',
  105. 'WE' => 'Wednesday', 'TH' => 'Thursday', 'FR' => 'Friday',
  106. 'SA' => 'Saturday');
  107. }
  108. return $date_repeat_weekdays;
  109. }
  110. function date_repeat_dow_day_options_ordered($weekdays) {
  111. $day_keys = array_keys($weekdays);
  112. $day_values = array_values($weekdays);
  113. for ($i = 1; $i <= variable_get('date_first_day', 0); $i++) {
  114. $last_key = array_shift($day_keys);
  115. array_push($day_keys, $last_key);
  116. $last_value = array_shift($day_values);
  117. array_push($day_values, $last_value);
  118. }
  119. $weekdays = array_combine($day_keys, $day_values);
  120. return $weekdays;
  121. }
  122. /**
  123. * Helper function for BYDAY options.
  124. */
  125. function date_repeat_dow_count_options() {
  126. return array('' => t('Every', array(), array('context' => 'date_order'))) + date_order_translated();
  127. }
  128. /**
  129. * Helper function for BYDAY options.
  130. *
  131. * Creates options like -1SU and 2TU
  132. */
  133. function date_repeat_dow_options() {
  134. $options = array();
  135. foreach (date_repeat_dow_count_options() as $count_key => $count_value) {
  136. foreach (date_repeat_dow_day_options() as $dow_key => $dow_value) {
  137. $options[$count_key . $dow_key] = $count_value . ' ' . $dow_value;
  138. }
  139. }
  140. return $options;
  141. }
  142. /**
  143. * Translate a day of week position to the iCal day name.
  144. *
  145. * Used with date_format($date, 'w') or get_variable('date_first_day'),
  146. * which return 0 for Sunday, 1 for Monday, etc.
  147. *
  148. * dow 2 becomes 'TU', dow 3 becomes 'WE', and so on.
  149. */
  150. function date_repeat_dow2day($dow) {
  151. $days_of_week = array_keys(date_repeat_dow_day_options(FALSE));
  152. return $days_of_week[$dow];
  153. }
  154. /**
  155. * Shift the array of iCal day names into the right order
  156. * for a specific week start day.
  157. */
  158. function date_repeat_days_ordered($week_start_day) {
  159. $days = array_flip(array_keys(date_repeat_dow_day_options(FALSE)));
  160. $start_position = $days[$week_start_day];
  161. $keys = array_flip($days);
  162. if ($start_position > 0) {
  163. for ($i = 1; $i <= $start_position; $i++) {
  164. $last = array_shift($keys);
  165. array_push($keys, $last);
  166. }
  167. }
  168. return $keys;
  169. }
  170. /**
  171. * Build a description of an iCal rule.
  172. *
  173. * Constructs a human-readable description of the rule.
  174. */
  175. function date_repeat_rrule_description($rrule, $format = 'D M d Y') {
  176. // Empty or invalid value.
  177. if (empty($rrule) || !strstr($rrule, 'RRULE')) {
  178. return;
  179. }
  180. module_load_include('inc', 'date_api', 'date_api_ical');
  181. module_load_include('inc', 'date_repeat', 'date_repeat_calc');
  182. $parts = date_repeat_split_rrule($rrule);
  183. $additions = $parts[2];
  184. $exceptions = $parts[1];
  185. $rrule = $parts[0];
  186. if ($rrule['FREQ'] == 'NONE') {
  187. return;
  188. }
  189. // Make sure there will be an empty description for any unused parts.
  190. $description = array(
  191. '!interval' => '',
  192. '!byday' => '',
  193. '!bymonth' => '',
  194. '!count' => '',
  195. '!until' => '',
  196. '!except' => '',
  197. '!additional' => '',
  198. '!week_starts_on' => '',
  199. );
  200. $interval = date_repeat_interval_options();
  201. switch ($rrule['FREQ']) {
  202. case 'WEEKLY':
  203. $description['!interval'] = format_plural($rrule['INTERVAL'], 'every week', 'every @count weeks') . ' ';
  204. break;
  205. case 'MONTHLY':
  206. $description['!interval'] = format_plural($rrule['INTERVAL'], 'every month', 'every @count months') . ' ';
  207. break;
  208. case 'YEARLY':
  209. $description['!interval'] = format_plural($rrule['INTERVAL'], 'every year', 'every @count years') . ' ';
  210. break;
  211. default:
  212. $description['!interval'] = format_plural($rrule['INTERVAL'], 'every day', 'every @count days') . ' ';
  213. break;
  214. }
  215. if (!empty($rrule['BYDAY'])) {
  216. $days = date_repeat_dow_day_options();
  217. $counts = date_repeat_dow_count_options();
  218. $results = array();
  219. foreach ($rrule['BYDAY'] as $byday) {
  220. // Get the numeric part of the BYDAY option, i.e. +3 from +3MO.
  221. $day = substr($byday, -2);
  222. $count = str_replace($day, '', $byday);
  223. if (!empty($count)) {
  224. // See if there is a 'pretty' option for this count, i.e. +1 => First.
  225. $order = array_key_exists($count, $counts) ? strtolower($counts[$count]) : $count;
  226. $results[] = trim(t('!repeats_every_interval on the !date_order !day_of_week', array('!repeats_every_interval ' => '', '!date_order' => $order, '!day_of_week' => $days[$day])));
  227. }
  228. else {
  229. $results[] = trim(t('!repeats_every_interval every !day_of_week', array('!repeats_every_interval ' => '', '!day_of_week' => $days[$day])));
  230. }
  231. }
  232. $description['!byday'] = implode(' ' . t('and') . ' ', $results);
  233. }
  234. if (!empty($rrule['BYMONTH'])) {
  235. if (sizeof($rrule['BYMONTH']) < 12) {
  236. $results = array();
  237. $months = date_month_names();
  238. foreach ($rrule['BYMONTH'] as $month) {
  239. $results[] = $months[$month];
  240. }
  241. if (!empty($rrule['BYMONTHDAY'])) {
  242. $description['!bymonth'] = trim(t('!repeats_every_interval on the !month_days of !month_names', array('!repeats_every_interval ' => '', '!month_days' => implode(', ', $rrule['BYMONTHDAY']), '!month_names' => implode(', ', $results))));
  243. }
  244. else {
  245. $description['!bymonth'] = trim(t('!repeats_every_interval on !month_names', array('!repeats_every_interval ' => '', '!month_names' => implode(', ', $results))));
  246. }
  247. }
  248. }
  249. if ($rrule['INTERVAL'] < 1) {
  250. $rrule['INTERVAL'] = 1;
  251. }
  252. if (!empty($rrule['COUNT'])) {
  253. $description['!count'] = trim(t('!repeats_every_interval !count times', array('!repeats_every_interval ' => '', '!count' => $rrule['COUNT'])));
  254. }
  255. if (!empty($rrule['UNTIL'])) {
  256. $until = date_ical_date($rrule['UNTIL'], 'UTC');
  257. date_timezone_set($until, date_default_timezone_object());
  258. $description['!until'] = trim(t('!repeats_every_interval until !until_date', array('!repeats_every_interval ' => '', '!until_date' => date_format_date($until, 'custom', $format))));
  259. }
  260. if ($exceptions) {
  261. $values = array();
  262. foreach ($exceptions as $exception) {
  263. $except = date_ical_date($exception, 'UTC');
  264. date_timezone_set($except, date_default_timezone_object());
  265. $values[] = date_format_date($except, 'custom', $format);
  266. }
  267. $description['!except'] = trim(t('!repeats_every_interval except !except_dates', array('!repeats_every_interval ' => '', '!except_dates' => implode(', ', $values))));
  268. }
  269. if (!empty($rrule['WKST'])) {
  270. $day_names = date_repeat_dow_day_options();
  271. $description['!week_starts_on'] = trim(t('!repeats_every_interval where the week start on !day_of_week', array('!repeats_every_interval ' => '', '!day_of_week' => $day_names[trim($rrule['WKST'])])));
  272. }
  273. if ($additions) {
  274. $values = array();
  275. foreach ($additions as $addition) {
  276. $add = date_ical_date($addition, 'UTC');
  277. date_timezone_set($add, date_default_timezone_object());
  278. $values[] = date_format_date($add, 'custom', $format);
  279. }
  280. $description['!additional'] = trim(t('Also includes !additional_dates.', array('!additional_dates' => implode(', ', $values))));
  281. }
  282. return t('Repeats !interval !bymonth !byday !count !until !except. !additional', $description);
  283. }
  284. /**
  285. * Parse an iCal rule into a parsed RRULE array and an EXDATE array.
  286. */
  287. function date_repeat_split_rrule($rrule) {
  288. $parts = explode("\n", str_replace("\r\n", "\n", $rrule));
  289. $rrule = array();
  290. $exceptions = array();
  291. $additions = array();
  292. $additions = array();
  293. foreach ($parts as $part) {
  294. if (strstr($part, 'RRULE')) {
  295. $RRULE = str_replace('RRULE:', '', $part);
  296. $rrule = (array) date_ical_parse_rrule('RRULE:', $RRULE);
  297. }
  298. elseif (strstr($part, 'EXDATE')) {
  299. $EXDATE = str_replace('EXDATE:', '', $part);
  300. $exceptions = (array) date_ical_parse_exceptions('EXDATE:', $EXDATE);
  301. unset($exceptions['DATA']);
  302. }
  303. elseif (strstr($part, 'RDATE')) {
  304. $RDATE = str_replace('RDATE:', '', $part);
  305. $additions = (array) date_ical_parse_exceptions('RDATE:', $RDATE);
  306. unset($additions['DATA']);
  307. }
  308. }
  309. return array($rrule, $exceptions, $additions);
  310. }
  311. /**
  312. * Analyze a RRULE and return dates that match it.
  313. */
  314. function date_repeat_calc($rrule, $start, $end, $exceptions = array(), $timezone = NULL, $additions = array()) {
  315. module_load_include('inc', 'date_repeat', 'date_repeat_calc');
  316. return _date_repeat_calc($rrule, $start, $end, $exceptions, $timezone, $additions);
  317. }
  318. /**
  319. * Generate the repeat rule setting form.
  320. */
  321. function date_repeat_rrule_process($element, &$form_state, $form) {
  322. module_load_include('inc', 'date_repeat', 'date_repeat_form');
  323. return _date_repeat_rrule_process($element, $form_state, $form);
  324. }
  325. /**
  326. * Process function for 'date_repeat_form_element_radios'.
  327. */
  328. function date_repeat_form_element_radios_process($element) {
  329. $childrenkeys = element_children($element);
  330. if (count($element['#options']) &&
  331. count($element['#options']) == count($childrenkeys)) {
  332. $weight = 0;
  333. $children = array();
  334. $classes = isset($element['#div_classes']) ?
  335. $element['#div_classes'] : array();
  336. foreach ($childrenkeys as $childkey) {
  337. $children[$childkey] = $element[$childkey];
  338. unset($element[$childkey]);
  339. }
  340. foreach ($element['#options'] as $key => $choice) {
  341. $currentchildkey = array_shift($childrenkeys);
  342. $weight += 0.001;
  343. $class = array_shift($classes);
  344. $element += array($key => array());
  345. $parents_for_id = array_merge($element['#parents'], array($key));
  346. $element[$key] += array(
  347. '#prefix' => '<div' . ($class ? " class=\"{$class}\"" : '') . '>',
  348. '#type' => 'radio',
  349. '#title' => $choice,
  350. '#title_display' => 'invisible',
  351. '#return_value' => $key,
  352. '#default_value' => isset($element['#default_value']) ?
  353. $element['#default_value'] : NULL,
  354. '#attributes' => $element['#attributes'],
  355. '#parents' => $element['#parents'],
  356. '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)),
  357. '#ajax' => isset($element['#ajax']) ? $element['ajax'] : NULL,
  358. '#weight' => $weight,
  359. '#theme_wrappers' => array(),
  360. '#suffix' => ' ',
  361. );
  362. $child = $children[$currentchildkey];
  363. $weight += 0.001;
  364. $child['#weight'] = $weight;
  365. $child['#title_display'] = 'invisible';
  366. $child['#suffix'] = (!empty($child['#suffix']) ? $child['#suffix'] : '') .
  367. '</div>';
  368. $child['#parents'] = $element['#parents'];
  369. array_pop($child['#parents']);
  370. array_push($child['#parents'], $currentchildkey);
  371. $element_prototype = element_info($child['#type']);
  372. $old_wrappers = array();
  373. if (isset($child['#theme_wrappers'])) {
  374. $old_wrappers += $child['#theme_wrappers'];
  375. }
  376. if (isset($element_prototype['#theme_wrappers'])) {
  377. $old_wrappers += $element_prototype['#theme_wrappers'];
  378. }
  379. $child['#theme_wrappers'] = array();
  380. foreach ($old_wrappers as $wrapper) {
  381. if ($wrapper != 'form_element') {
  382. $child['#theme_wrappers'][] = $wrapper;
  383. }
  384. }
  385. $element[$currentchildkey] = $child;
  386. }
  387. }
  388. return $element;
  389. }
Error | ELMSLN API

Error

×

Error message

  • Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/elmsln_community/api.elmsln.org/includes/common.inc:2791) in drupal_send_headers() (line 1499 of /var/www/html/elmsln_community/api.elmsln.org/includes/bootstrap.inc).
  • Error: Call to undefined function apc_delete() in DrupalAPCCache->clear() (line 289 of /var/www/html/elmsln_community/api.elmsln.org/sites/all/modules/apc/drupal_apc_cache.inc).
The website encountered an unexpected error. Please try again later.