date_repeat_form.inc 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  1. <?php
  2. /**
  3. * @file
  4. * Code to add a date repeat selection form to a date field and create
  5. * an iCal RRULE from the chosen selections.
  6. *
  7. * Moved to a separate file since it is not used on most pages
  8. * so the code is not parsed unless needed.
  9. *
  10. * Currently implemented:
  11. * INTERVAL, UNTIL, EXDATE, RDATE, BYDAY, BYMONTHDAY, BYMONTH,
  12. * YEARLY, MONTHLY, WEEKLY, DAILY
  13. *
  14. * Currently not implemented:
  15. *
  16. * BYYEARDAY, MINUTELY, HOURLY, SECONDLY, BYMINUTE, BYHOUR, BYSECOND
  17. * These could be implemented in the future.
  18. *
  19. * COUNT
  20. * The goal of this module is to create a way we can parse an iCal
  21. * RRULE and pull out just dates for a specified date range, for
  22. * instance with a date that repeats daily for several years, we might
  23. * want to only be able to pull out the dates for the current year.
  24. *
  25. * Adding COUNT to the rules we create makes it impossible to do that
  26. * without parsing and computing the whole range of dates that the rule
  27. * will create. COUNT is left off of the user form completely for this
  28. * reason.
  29. *
  30. * BYSETPOS
  31. * Seldom used anywhere, so no reason to complicated the code.
  32. */
  33. /**
  34. * Generate the repeat setting form.
  35. */
  36. function _date_repeat_rrule_process($element, &$form_state, $form) {
  37. // If the RRULE field is not visible to the user,
  38. // needs no processing or validation.
  39. // The Date field module is not adding this element to forms
  40. // if the field is hidden,
  41. // this test is just in case some other module attempts to do so.
  42. if (date_hidden_element($element)) {
  43. return $element;
  44. }
  45. module_load_include('inc', 'date_api', 'date_api_ical');
  46. if (empty($element['#date_repeat_widget'])) {
  47. $element['#date_repeat_widget'] = module_exists('date_popup') ? 'date_popup' : 'date_select';
  48. }
  49. if (is_array($element['#default_value'])) {
  50. $element['#value'] = date_repeat_merge($element['#value'], $element);
  51. $rrule = date_api_ical_build_rrule($element['#value']);
  52. }
  53. else {
  54. $rrule = $element['#default_value'];
  55. }
  56. // Empty the original string value of the RRULE so we can create
  57. // an array of values for the form from the RRULE's contents.
  58. $element['#value'] = '';
  59. $parts = date_repeat_split_rrule($rrule);
  60. $rrule = $parts[0];
  61. $exceptions = $parts[1];
  62. $additions = $parts[2];
  63. $timezone = !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone();
  64. $merged_values = date_repeat_merge($rrule, $element);
  65. $until = '';
  66. if (!empty($merged_values['UNTIL']['datetime'])) {
  67. $until_date = new DateObject($merged_values['UNTIL']['datetime'], $merged_values['UNTIL']['tz']);
  68. date_timezone_set($until_date, timezone_open($timezone));
  69. $until = date_format($until_date, DATE_FORMAT_DATETIME);
  70. }
  71. $count = '';
  72. if (!empty($merged_values['COUNT'])) {
  73. $count = $merged_values['COUNT'];
  74. }
  75. $element['FREQ'] = array(
  76. '#type' => 'select',
  77. '#title' => t('Repeats', array(), array('context' => 'Date repeat')),
  78. '#default_value' => !empty($rrule['FREQ']) ? $rrule['FREQ'] : 'WEEKLY',
  79. '#options' => date_repeat_freq_options(),
  80. '#prefix' => '<div class="date-repeat-input">',
  81. '#suffix' => '</div>',
  82. );
  83. $element['daily'] = array(
  84. '#type' => 'container',
  85. '#tree' => TRUE,
  86. '#prefix' => '<div class="date-clear daily">',
  87. '#suffix' => '</div>',
  88. '#states' => array(
  89. 'visible' => array(
  90. ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'DAILY'),
  91. ),
  92. ),
  93. );
  94. $element['weekly'] = array(
  95. '#type' => 'container',
  96. '#tree' => TRUE,
  97. '#prefix' => '<div class="date-clear weekly">',
  98. '#suffix' => '</div>',
  99. '#states' => array(
  100. 'visible' => array(
  101. ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'WEEKLY'),
  102. ),
  103. ),
  104. );
  105. $element['monthly'] = array(
  106. '#type' => 'container',
  107. '#tree' => TRUE,
  108. '#prefix' => '<div class="date-clear monthly">',
  109. '#suffix' => '</div>',
  110. '#states' => array(
  111. 'visible' => array(
  112. ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'MONTHLY'),
  113. ),
  114. ),
  115. );
  116. $element['yearly'] = array(
  117. '#type' => 'container',
  118. '#tree' => TRUE,
  119. '#prefix' => '<div class="date-clear yearly">',
  120. '#suffix' => '</div>',
  121. '#states' => array(
  122. 'visible' => array(
  123. ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'YEARLY'),
  124. ),
  125. ),
  126. );
  127. list($prefix, $suffix) = explode('@interval', t('Every @interval days', array(), array('context' => 'Date repeat')));
  128. $daily_interval = array(
  129. '#type' => 'textfield',
  130. '#title' => t('Repeats', array(), array('context' => 'Date repeat')),
  131. '#title_display' => 'invisible',
  132. '#default_value' => (!empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1),
  133. '#element_validate' => array('element_validate_integer_positive'),
  134. '#attributes' => array('placeholder' => array('#')),
  135. '#size' => 3,
  136. '#maxlength' => 3,
  137. '#prefix' => '<div class="date-clear">',
  138. '#suffix' => t('days') . '</div>',
  139. '#field_prefix' => $prefix,
  140. '#field_suffix' => $suffix,
  141. );
  142. list($prefix, $suffix) = explode('@interval', t('Every @interval weeks', array(), array('context' => 'Date repeat')));
  143. $element['weekly']['INTERVAL'] = array(
  144. '#type' => 'textfield',
  145. '#title' => t('Repeats', array(), array('context' => 'Date repeat')),
  146. '#default_value' => (!empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1),
  147. '#element_validate' => array('element_validate_integer_positive'),
  148. '#attributes' => array('placeholder' => array('#')),
  149. '#size' => 3,
  150. '#maxlength' => 3,
  151. '#prefix' => '<div class="date-clear">',
  152. '#suffix' => '</div>',
  153. '#field_prefix' => $prefix,
  154. '#field_suffix' => $suffix,
  155. );
  156. list($prefix, $suffix) = explode('@interval', t('Every @interval months', array(), array('context' => 'Date repeat')));
  157. $element['monthly']['INTERVAL'] = array(
  158. '#access' => FALSE,
  159. '#type' => 'textfield',
  160. '#title' => t('Repeats', array(), array('context' => 'Date repeat')),
  161. '#default_value' => (!empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1),
  162. '#element_validate' => array('element_validate_integer_positive'),
  163. '#attributes' => array('placeholder' => array('#')),
  164. '#size' => 3,
  165. '#maxlength' => 3,
  166. '#prefix' => '<div class="date-clear">',
  167. '#suffix' => '</div>',
  168. '#field_prefix' => $prefix,
  169. '#field_suffix' => $suffix,
  170. );
  171. list($prefix, $suffix) = explode('@interval', t('Every @interval years', array(), array('context' => 'Date repeat')));
  172. $element['yearly']['INTERVAL'] = array(
  173. '#type' => 'textfield',
  174. '#title' => t('Repeats', array(), array('context' => 'Date repeat')),
  175. '#default_value' => (!empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1),
  176. '#element_validate' => array('element_validate_integer_positive'),
  177. '#attributes' => array('placeholder' => array('#')),
  178. '#size' => 3,
  179. '#maxlength' => 3,
  180. '#prefix' => '<div class="date-clear">',
  181. '#suffix' => '</div>',
  182. '#field_prefix' => $prefix,
  183. '#field_suffix' => $suffix,
  184. );
  185. $options = date_repeat_dow_day_options_abbr(TRUE);
  186. $options = date_repeat_dow_day_options_ordered($options);
  187. $element['weekly']['BYDAY'] = array(
  188. '#type' => 'checkboxes',
  189. '#title' => t('Repeat on', array(), array('context' => 'Date repeat')),
  190. '#default_value' => !empty($rrule['BYDAY']) && $rrule['FREQ'] === 'WEEKLY' ? $rrule['BYDAY'] : array(),
  191. '#options' => $options,
  192. '#attributes' => array('class' => array('container-inline byday')),
  193. '#multiple' => TRUE,
  194. '#prefix' => '<div class="date-clear">',
  195. '#suffix' => '</div>',
  196. );
  197. $daily_radios_default = 'INTERVAL';
  198. if (isset($rrule['FREQ']) && $rrule['FREQ'] === 'DAILY' && !empty($rrule['BYDAY'])) {
  199. switch (count($rrule['BYDAY'])) {
  200. case 2:
  201. $daily_radios_default = 'every_tu_th';
  202. break;
  203. case 3:
  204. $daily_radios_default = 'every_mo_we_fr';
  205. break;
  206. case 5:
  207. $daily_radios_default = 'every_weekday';
  208. break;
  209. }
  210. }
  211. $daily_every_weekday = array(
  212. '#type' => 'item',
  213. '#markup' => '<div>' . t('Every weekday', array(), array('context' => 'Date repeat')) . '</div>',
  214. );
  215. $daily_mo_we_fr = array(
  216. '#type' => 'item',
  217. '#markup' => '<div>' . t('Every Mon, Wed, Fri', array(), array('context' => 'Date repeat')) . '</div>',
  218. );
  219. $daily_tu_th = array(
  220. '#type' => 'item',
  221. '#markup' => '<div>' . t('Every Tue, Thu', array(), array('context' => 'Date repeat')) . '</div>',
  222. );
  223. $element['daily']['byday_radios'] = array(
  224. '#type' => 'date_repeat_form_element_radios',
  225. '#tree' => TRUE,
  226. '#title' => t('Repeats every', array(), array('context' => 'Date repeat')),
  227. '#prefix' => '<div class="date-clear">',
  228. '#suffix' => '</div>',
  229. '#states' => array(
  230. 'visible' => array(
  231. ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'DAILY'),
  232. ),
  233. ),
  234. '#default_value' => $daily_radios_default,
  235. '#options' => array(
  236. 'INTERVAL' => t('interval'),
  237. 'every_weekday' => t('every weekday'),
  238. 'every_mo_we_fr' => t('monday wednesday friday'),
  239. 'every_tu_th' => t('tuesday thursday'),
  240. ),
  241. 'INTERVAL_child' => $daily_interval,
  242. 'every_weekday_child' => $daily_every_weekday,
  243. 'mo_we_fr_child' => $daily_mo_we_fr,
  244. 'tu_th_child' => $daily_tu_th,
  245. '#div_classes' => array(
  246. 'container-inline interval',
  247. 'container-inline weekday',
  248. 'container-inline mo-we-fr',
  249. 'container-inline tu-th',
  250. ),
  251. );
  252. $monthly_day_month_default = 'BYMONTHDAY_BYMONTH';
  253. if (isset($rrule['FREQ']) && $rrule['FREQ'] === 'MONTHLY' && !empty($rrule['BYDAY'])) {
  254. $monthly_day_month_default = 'BYDAY_BYMONTH';
  255. }
  256. $monthly_on_day_bymonthday_of_bymonth = array(
  257. '#type' => 'container',
  258. '#tree' => TRUE,
  259. );
  260. list($bymonthday_title, $bymonthday_suffix) = explode('@bymonthday', t('On day @bymonthday of', array(), array('context' => 'Date repeat')));
  261. $monthly_on_day_bymonthday_of_bymonth['BYMONTHDAY'] = array(
  262. '#type' => 'select',
  263. '#title' => $bymonthday_title,
  264. '#default_value' => !empty($rrule['BYMONTHDAY']) && $rrule['FREQ'] === 'MONTHLY' ? $rrule['BYMONTHDAY'] : '',
  265. '#options' => drupal_map_assoc(range(1, 31)) + drupal_map_assoc(range(-1, -31)),
  266. '#multiple' => FALSE,
  267. '#prefix' => '<div class="date-clear bymonthday">',
  268. '#suffix' => '</div>',
  269. '#field_suffix' => $bymonthday_suffix,
  270. );
  271. $monthly_on_day_bymonthday_of_bymonth['BYMONTH'] = array(
  272. '#type' => 'checkboxes',
  273. '#title' => t('Bymonth', array(), array('context' => 'Date repeat')),
  274. '#title_display' => 'invisible',
  275. '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'MONTHLY' && $monthly_day_month_default === 'BYMONTHDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
  276. '#options' => date_month_names_abbr(TRUE),
  277. '#attributes' => array('class' => array('container-inline')),
  278. '#multiple' => TRUE,
  279. '#prefix' => '<div class="date-clear bymonth">',
  280. '#suffix' => '</div>',
  281. );
  282. $monthly_on_the_byday_of_bymonth = array(
  283. '#type' => 'container',
  284. '#tree' => TRUE,
  285. );
  286. $monthly_byday_count = '';
  287. $monthly_byday_day = '';
  288. if (isset($rrule['BYDAY']) && !empty($rrule['BYDAY']) && $rrule['FREQ'] === 'MONTHLY') {
  289. $monthly_byday_count = substr($rrule['BYDAY'][0], 0, -2);
  290. $monthly_byday_day = substr($rrule['BYDAY'][0], -2);;
  291. }
  292. list($byday_count_title, $byday_day_title) = explode('@byday', t('On the @byday of', array(), array('context' => 'Date repeat')));
  293. $monthly_on_the_byday_of_bymonth['BYDAY_COUNT'] = array(
  294. '#type' => 'select',
  295. '#title' => $byday_count_title,
  296. '#default_value' => !empty($monthly_byday_count) ? $monthly_byday_count : '',
  297. '#options' => date_order_translated(),
  298. '#multiple' => FALSE,
  299. '#prefix' => '<div class="date-repeat-input byday-count">',
  300. '#suffix' => '</div>',
  301. );
  302. $monthly_on_the_byday_of_bymonth['BYDAY_DAY'] = array(
  303. '#type' => 'select',
  304. '#title' => $byday_day_title,
  305. '#title_display' => 'after',
  306. '#default_value' => !empty($monthly_byday_day) ? $monthly_byday_day : '',
  307. '#options' => date_repeat_dow_day_options(TRUE),
  308. '#multiple' => FALSE,
  309. '#prefix' => '<div class="date-repeat-input byday-day">',
  310. '#suffix' => '</div>',
  311. );
  312. $monthly_on_the_byday_of_bymonth['BYMONTH'] = array(
  313. '#type' => 'checkboxes',
  314. '#title' => t('Bymonth', array(), array('context' => 'Date repeat')),
  315. '#title_display' => 'invisible',
  316. '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'MONTHLY' && $monthly_day_month_default === 'BYDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
  317. '#options' => date_month_names_abbr(TRUE),
  318. '#attributes' => array('class' => array('container-inline')),
  319. '#multiple' => TRUE,
  320. '#prefix' => '<div class="date-clear bymonth">',
  321. '#suffix' => '</div>',
  322. );
  323. $element['monthly']['day_month'] = array(
  324. '#type' => 'date_repeat_form_element_radios',
  325. '#tree' => TRUE,
  326. '#prefix' => '<div class="date-clear">',
  327. '#suffix' => '</div>',
  328. '#states' => array(
  329. 'visible' => array(
  330. ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'MONTHLY'),
  331. ),
  332. ),
  333. '#attributes' => array('class' => array('date-repeat-radios clearfix')),
  334. '#default_value' => $monthly_day_month_default,
  335. '#options' => array(
  336. 'BYMONTHDAY_BYMONTH' => t('On day ... of ...'),
  337. 'BYDAY_BYMONTH' => t('On the ... of ...'),
  338. ),
  339. 'BYMONTHDAY_BYMONTH_child' => $monthly_on_day_bymonthday_of_bymonth,
  340. 'BYDAY_BYMONTH_child' => $monthly_on_the_byday_of_bymonth,
  341. '#div_classes' => array(
  342. 'date-repeat-radios-item date-clear clearfix bymonthday-bymonth',
  343. 'date-repeat-radios-item date-clear clearfix byday-bymonth',
  344. ),
  345. );
  346. $yearly_day_month_default = 'BYMONTHDAY_BYMONTH';
  347. if (isset($rrule['FREQ']) && $rrule['FREQ'] === 'YEARLY' && !empty($rrule['BYDAY'])) {
  348. $yearly_day_month_default = 'BYDAY_BYMONTH';
  349. }
  350. $yearly_on_day_bymonthday_of_bymonth = array(
  351. '#type' => 'container',
  352. '#tree' => TRUE,
  353. );
  354. list($bymonthday_title, $bymonthday_suffix) = explode('@bymonthday', t('On day @bymonthday of', array(), array('context' => 'Date repeat')));
  355. $yearly_on_day_bymonthday_of_bymonth['BYMONTHDAY'] = array(
  356. '#type' => 'select',
  357. '#title' => $bymonthday_title,
  358. '#default_value' => !empty($rrule['BYMONTHDAY']) && $rrule['FREQ'] === 'YEARLY' ? $rrule['BYMONTHDAY'] : '',
  359. '#options' => drupal_map_assoc(range(1, 31)) + drupal_map_assoc(range(-1, -31)),
  360. '#multiple' => FALSE,
  361. '#prefix' => '<div class="date-clear bymonthday">',
  362. '#suffix' => '</div>',
  363. '#field_suffix' => $bymonthday_suffix,
  364. );
  365. $yearly_on_day_bymonthday_of_bymonth['BYMONTH'] = array(
  366. '#type' => 'checkboxes',
  367. '#title' => t('Bymonth', array(), array('context' => 'Date repeat')),
  368. '#title_display' => 'invisible',
  369. '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'YEARLY' && $yearly_day_month_default === 'BYMONTHDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
  370. '#options' => date_month_names_abbr(TRUE),
  371. '#attributes' => array('class' => array('container-inline')),
  372. '#multiple' => TRUE,
  373. '#prefix' => '<div class="date-clear bymonth">',
  374. '#suffix' => '</div>',
  375. );
  376. $yearly_on_the_byday_of_bymonth = array(
  377. '#type' => 'container',
  378. '#tree' => TRUE,
  379. );
  380. $yearly_byday_count = '';
  381. $yearly_byday_day = '';
  382. if (isset($rrule['BYDAY']) && !empty($rrule['BYDAY']) && $rrule['FREQ'] === 'YEARLY') {
  383. $yearly_byday_count = substr($rrule['BYDAY'][0], 0, -2);
  384. $yearly_byday_day = substr($rrule['BYDAY'][0], -2);;
  385. }
  386. list($byday_count_title, $byday_day_title) = explode('@byday', t('On the @byday of', array(), array('context' => 'Date repeat')));
  387. $yearly_on_the_byday_of_bymonth['BYDAY_COUNT'] = array(
  388. '#type' => 'select',
  389. '#title' => $byday_count_title,
  390. '#default_value' => !empty($yearly_byday_count) ? $yearly_byday_count : '',
  391. '#options' => date_order_translated(),
  392. '#multiple' => FALSE,
  393. '#prefix' => '<div class="date-repeat-input byday-count">',
  394. '#suffix' => '</div>',
  395. );
  396. $yearly_on_the_byday_of_bymonth['BYDAY_DAY'] = array(
  397. '#type' => 'select',
  398. '#title' => $byday_day_title,
  399. '#title_display' => 'after',
  400. '#default_value' => !empty($yearly_byday_day) ? $yearly_byday_day : '',
  401. '#options' => date_repeat_dow_day_options(TRUE),
  402. '#multiple' => FALSE,
  403. '#prefix' => '<div class="date-repeat-input byday-day">',
  404. '#suffix' => '</div>',
  405. );
  406. $yearly_on_the_byday_of_bymonth['BYMONTH'] = array(
  407. '#type' => 'checkboxes',
  408. '#title' => t('Bymonth', array(), array('context' => 'Date repeat')),
  409. '#title_display' => 'invisible',
  410. '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'YEARLY' && $yearly_day_month_default === 'BYDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
  411. '#options' => date_month_names_abbr(TRUE),
  412. '#attributes' => array('class' => array('container-inline')),
  413. '#multiple' => TRUE,
  414. '#prefix' => '<div class="date-clear bymonth">',
  415. '#suffix' => '</div>',
  416. );
  417. $element['yearly']['day_month'] = array(
  418. '#type' => 'date_repeat_form_element_radios',
  419. '#tree' => TRUE,
  420. '#prefix' => '<div class="date-clear">',
  421. '#suffix' => '</div>',
  422. '#states' => array(
  423. 'visible' => array(
  424. ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'YEARLY'),
  425. ),
  426. ),
  427. '#attributes' => array('class' => array('date-repeat-radios clearfix')),
  428. '#default_value' => $yearly_day_month_default,
  429. '#options' => array(
  430. 'BYMONTHDAY_BYMONTH' => t('On day ... of ...'),
  431. 'BYDAY_BYMONTH' => t('On the ... of ...'),
  432. ),
  433. 'BYMONTHDAY_BYMONTH_child' => $yearly_on_day_bymonthday_of_bymonth,
  434. 'BYDAY_BYMONTH_child' => $yearly_on_the_byday_of_bymonth,
  435. '#div_classes' => array(
  436. 'date-repeat-radios-item date-clear clearfix bymonthday-bymonth',
  437. 'date-repeat-radios-item date-clear clearfix byday-bymonth',
  438. ),
  439. );
  440. list($prefix, $suffix) = explode('@count', t('After @count occurrences', array(), array('context' => 'Date repeat')));
  441. $count_form_element = array(
  442. '#type' => 'textfield',
  443. '#title' => t('Count', array(), array('context' => 'Date repeat')),
  444. '#default_value' => $count,
  445. '#element_validate' => array('element_validate_integer_positive'),
  446. '#attributes' => array('placeholder' => array('#')),
  447. '#prefix' => $prefix,
  448. '#suffix' => $suffix,
  449. '#size' => 10,
  450. '#maxlength' => 10,
  451. );
  452. $until_form_element = array(
  453. '#type' => 'container',
  454. '#tree' => TRUE,
  455. '#prefix' => '<div class="date-prefix-inline">' . t('On', array(), array('context' => 'Date repeat')) . '</div>',
  456. 'datetime' => array(
  457. '#type' => $element['#date_repeat_widget'],
  458. '#title' => t('Until', array(), array('context' => 'Date repeat')),
  459. '#title_display' => 'invisible',
  460. '#default_value' => $until,
  461. '#date_format' => !empty($element['#date_format']) ?
  462. date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
  463. '#date_timezone' => $timezone,
  464. '#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
  465. '#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
  466. '#date_label_position' => !empty($element['#date_label_position']) ?
  467. $element['#date_label_position'] : 'within',
  468. '#date_flexible' => 0,
  469. ),
  470. 'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
  471. 'all_day' => array('#type' => 'hidden', '#value' => 1),
  472. 'granularity' => array(
  473. '#type' => 'hidden',
  474. '#value' => serialize(array('year', 'month', 'day')),
  475. ),
  476. );
  477. $range_of_repeat_default = 'COUNT';
  478. if (!empty($until)) {
  479. $range_of_repeat_default = 'UNTIL';
  480. }
  481. $element['range_of_repeat'] = array(
  482. '#type' => 'date_repeat_form_element_radios',
  483. '#tree' => TRUE,
  484. '#title' => t('Stop repeating', array(), array('context' => 'Date repeat')),
  485. '#title_display' => 'before',
  486. '#prefix' => '<div class="date-clear range-of-repeat">',
  487. '#suffix' => '</div>',
  488. '#states' => array(
  489. 'invisible' => array(
  490. ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'NONE'),
  491. ),
  492. ),
  493. '#default_value' => $range_of_repeat_default,
  494. '#options' => array(
  495. 'COUNT' => t('Count'),
  496. 'UNTIL' => t('Until'),
  497. ),
  498. 'count_child' => $count_form_element,
  499. 'until_child' => $until_form_element,
  500. '#div_classes' => array(
  501. 'container-inline count',
  502. "until widget-{$element['#date_repeat_widget']} label-{$element['#date_label_position']}",
  503. ),
  504. );
  505. $parents = $element['#array_parents'];
  506. $instance = implode('-', $parents);
  507. // Make sure this will work right either in the normal
  508. // form or in an ajax callback from the 'Add more' button.
  509. if (empty($form_state['num_exceptions'][$instance])) {
  510. $form_state['num_exceptions'][$instance] = count($exceptions);
  511. }
  512. if ($form_state['num_exceptions'][$instance] == 0) {
  513. $collapsed = TRUE;
  514. }
  515. else {
  516. $collapsed = FALSE;
  517. }
  518. $element['show_exceptions'] = array(
  519. '#type' => 'checkbox',
  520. '#title' => t('Exclude dates', array(), array('context' => 'Date repeat')),
  521. '#states' => array(
  522. 'invisible' => array(
  523. ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'NONE'),
  524. ),
  525. ),
  526. '#default_value' => empty($form_state['num_exceptions'][$instance]) ? 0 : 1,
  527. );
  528. $element['exceptions'] = array(
  529. '#type' => 'container',
  530. '#prefix' => '<div id="date-repeat-exceptions-' . $instance . '" class="date-repeat">',
  531. '#suffix' => '</div>',
  532. '#states' => array(
  533. 'visible' => array(
  534. ":input[name=\"{$element['#name']}[show_exceptions]\"]" => array('checked' => TRUE),
  535. ),
  536. ),
  537. );
  538. for ($i = 0; $i < max($form_state['num_exceptions'][$instance], 1); $i++) {
  539. $except = '';
  540. if (!empty($exceptions[$i]['datetime'])) {
  541. $ex_date = new DateObject($exceptions[$i]['datetime'], $exceptions[$i]['tz']);
  542. date_timezone_set($ex_date, timezone_open($timezone));
  543. $except = date_format($ex_date, DATE_FORMAT_DATETIME);
  544. }
  545. $date_format = 'Y-m-d';
  546. if (!empty($element['#date_format'])) {
  547. $grans = array('year', 'month', 'day');
  548. $date_format = date_limit_format($element['#date_format'], $grans);
  549. }
  550. $element['exceptions']['EXDATE'][$i] = array(
  551. '#tree' => TRUE,
  552. 'datetime' => array(
  553. '#name' => 'exceptions|' . $instance,
  554. '#type' => $element['#date_repeat_widget'],
  555. '#default_value' => $except,
  556. '#date_timezone' => !empty($element['#date_timezone']) ?
  557. $element['#date_timezone'] : date_default_timezone(),
  558. '#date_format' => $date_format,
  559. '#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
  560. '#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
  561. '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
  562. '#date_flexible' => 0,
  563. ),
  564. 'tz' => array(
  565. '#type' => 'hidden',
  566. '#value' => $element['#date_timezone'],
  567. ),
  568. 'all_day' => array(
  569. '#type' => 'hidden',
  570. '#value' => 1,
  571. ),
  572. 'granularity' => array(
  573. '#type' => 'hidden',
  574. '#value' => serialize(array('year', 'month', 'day')),
  575. ),
  576. );
  577. }
  578. // Collect additions in the same way as exceptions - implements RDATE.
  579. if (empty($form_state['num_additions'][$instance])) {
  580. $form_state['num_additions'][$instance] = count($additions);
  581. }
  582. if ($form_state['num_additions'][$instance] == 0) {
  583. $collapsed = TRUE;
  584. }
  585. else {
  586. $collapsed = FALSE;
  587. }
  588. $element['show_additions'] = array(
  589. '#type' => 'checkbox',
  590. '#title' => t('Include dates', array(), array('context' => 'Date repeat')),
  591. '#states' => array(
  592. 'invisible' => array(
  593. ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'NONE'),
  594. ),
  595. ),
  596. '#default_value' => empty($form_state['num_additions'][$instance]) ? 0 : 1,
  597. );
  598. $element['additions'] = array(
  599. '#type' => 'container',
  600. '#prefix' => '<div id="date-repeat-additions-' . $instance . '" class="date-repeat">',
  601. '#suffix' => '</div>',
  602. '#states' => array(
  603. 'visible' => array(
  604. ":input[name=\"{$element['#name']}[show_additions]\"]" => array('checked' => TRUE),
  605. ),
  606. ),
  607. );
  608. for ($i = 0; $i < max($form_state['num_additions'][$instance], 1); $i++) {
  609. $r_date = '';
  610. if (!empty($additions[$i]['datetime'])) {
  611. $rdate = new DateObject($additions[$i]['datetime'], $additions[$i]['tz']);
  612. date_timezone_set($rdate, timezone_open($timezone));
  613. $r_date = date_format($rdate, DATE_FORMAT_DATETIME);
  614. }
  615. $date_format = 'Y-m-d';
  616. if (!empty($element['#date_format'])) {
  617. $grans = array('year', 'month', 'day');
  618. $date_format = date_limit_format($element['#date_format'], $grans);
  619. }
  620. $element['additions']['RDATE'][$i] = array(
  621. '#tree' => TRUE,
  622. 'datetime' => array(
  623. '#type' => $element['#date_repeat_widget'],
  624. '#name' => 'additions|' . $instance,
  625. '#default_value' => $r_date,
  626. '#date_timezone' => !empty($element['#date_timezone']) ?
  627. $element['#date_timezone'] : date_default_timezone(),
  628. '#date_format' => $date_format,
  629. '#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
  630. '#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
  631. '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
  632. '#date_flexible' => 0,
  633. ),
  634. 'tz' => array(
  635. '#type' => 'hidden',
  636. '#value' => $element['#date_timezone'],
  637. ),
  638. 'all_day' => array(
  639. '#type' => 'hidden',
  640. '#value' => 1,
  641. ),
  642. 'granularity' => array(
  643. '#type' => 'hidden',
  644. '#value' => serialize(array('year', 'month', 'day')),
  645. ),
  646. );
  647. }
  648. $element['exceptions']['exceptions_add'] = array(
  649. '#type' => 'submit',
  650. '#name' => 'exceptions_add|' . $instance,
  651. '#value' => t('Add exception'),
  652. '#submit' => array('date_repeat_add_exception'),
  653. '#limit_validation_errors' => array(),
  654. '#ajax' => array(
  655. 'callback' => 'date_repeat_add_exception_callback',
  656. 'wrapper' => 'date-repeat-exceptions-' . $instance,
  657. ),
  658. );
  659. $element['additions']['additions_add'] = array(
  660. '#type' => 'submit',
  661. '#name' => 'additions_add|' . $instance,
  662. '#value' => t('Add addition'),
  663. '#submit' => array('date_repeat_add_addition'),
  664. '#limit_validation_errors' => array(),
  665. '#ajax' => array(
  666. 'callback' => 'date_repeat_add_addition_callback',
  667. 'wrapper' => 'date-repeat-additions-' . $instance,
  668. ),
  669. );
  670. $element['#date_repeat_collapsed'] = !empty($rrule['INTERVAL']) || !empty($rrule['FREQ']) ? 0 : (!empty($element['#date_repeat_collapsed']) ? $element['#date_repeat_collapsed'] : 0);
  671. return $element;
  672. }
  673. /**
  674. * Add callback to date repeat.
  675. */
  676. function date_repeat_add_exception_callback($form, &$form_state) {
  677. $parents = $form_state['triggering_element']['#array_parents'];
  678. $button_key = array_pop($parents);
  679. $element = drupal_array_get_nested_value($form, $parents);
  680. return $element;
  681. }
  682. /**
  683. * Add addition callback to date repeat.
  684. */
  685. function date_repeat_add_addition_callback($form, &$form_state) {
  686. $parents = $form_state['triggering_element']['#array_parents'];
  687. $button_key = array_pop($parents);
  688. $element = drupal_array_get_nested_value($form, $parents);
  689. return $element;
  690. }
  691. /**
  692. * Add exception to date repeat.
  693. */
  694. function date_repeat_add_exception($form, &$form_state) {
  695. $parents = $form_state['triggering_element']['#array_parents'];
  696. $instance = implode('-', array_slice($parents, 0, count($parents) - 2));
  697. $form_state['num_exceptions'][$instance]++;
  698. $form_state['rebuild'] = TRUE;
  699. }
  700. /**
  701. * Add addition to date repeat.
  702. */
  703. function date_repeat_add_addition($form, &$form_state) {
  704. $parents = $form_state['triggering_element']['#array_parents'];
  705. $instance = implode('-', array_slice($parents, 0, count($parents) - 2));
  706. $form_state['num_additions'][$instance]++;
  707. $form_state['rebuild'] = TRUE;
  708. }
  709. /**
  710. * Regroup values back into a consistant array, no matter what state it is in.
  711. */
  712. function date_repeat_merge($form_values, $element) {
  713. if (empty($form_values) || !is_array($form_values)) {
  714. return $form_values;
  715. }
  716. if (array_key_exists('exceptions', $form_values) || array_key_exists('additions', $form_values)) {
  717. if (!array_key_exists('exceptions', $form_values)) {
  718. $form_values['exceptions'] = array();
  719. }
  720. if (!array_key_exists('additions', $form_values)) {
  721. $form_values['additions'] = array();
  722. }
  723. $form_values = array_merge($form_values, (array) $form_values['exceptions'], (array) $form_values['additions']);
  724. unset($form_values['exceptions']);
  725. unset($form_values['additions']);
  726. }
  727. if (array_key_exists('FREQ', $form_values)) {
  728. switch ($form_values['FREQ']) {
  729. case 'DAILY':
  730. if (array_key_exists('daily', $form_values)) {
  731. switch ($form_values['daily']['byday_radios']) {
  732. case 'INTERVAL':
  733. $form_values['INTERVAL'] = $form_values['daily']['INTERVAL_child'];
  734. break;
  735. case 'every_weekday':
  736. $form_values['BYDAY'] = array('MO', 'TU', 'WE', 'TH', 'FR');
  737. break;
  738. case 'every_mo_we_fr':
  739. $form_values['BYDAY'] = array('MO', 'WE', 'FR');
  740. break;
  741. case 'every_tu_th':
  742. $form_values['BYDAY'] = array('TU', 'TH');
  743. break;
  744. }
  745. }
  746. break;
  747. case 'WEEKLY':
  748. if (array_key_exists('weekly', $form_values)) {
  749. $form_values = array_merge($form_values, (array) $form_values['weekly']);
  750. if (array_key_exists('BYDAY', $form_values)) {
  751. $form_values['BYDAY'] = date_repeat_transform_checkbox_values_to_select_values($form_values['BYDAY']);
  752. }
  753. }
  754. break;
  755. case 'MONTHLY':
  756. if (array_key_exists('monthly', $form_values)) {
  757. switch ($form_values['monthly']['day_month']) {
  758. case 'BYMONTHDAY_BYMONTH':
  759. $form_values['monthly'] = array_merge($form_values['monthly'], (array) $form_values['monthly']['BYMONTHDAY_BYMONTH_child']);
  760. break;
  761. case 'BYDAY_BYMONTH':
  762. $form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY'] = $form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY_COUNT'] . $form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY_DAY'];
  763. $form_values['monthly'] = array_merge($form_values['monthly'], (array) $form_values['monthly']['BYDAY_BYMONTH_child']);
  764. break;
  765. }
  766. unset($form_values['monthly']['BYDAY_BYMONTH_child']);
  767. unset($form_values['monthly']['BYMONTHDAY_BYMONTH_child']);
  768. $form_values = array_merge($form_values, (array) $form_values['monthly']);
  769. if (array_key_exists('BYMONTH', $form_values)) {
  770. $form_values['BYMONTH'] = date_repeat_transform_checkbox_values_to_select_values($form_values['BYMONTH']);
  771. }
  772. if (array_key_exists('BYMONTHDAY', $form_values) && !is_array($form_values['BYMONTHDAY'])) {
  773. $form_values['BYMONTHDAY'] = (array) $form_values['BYMONTHDAY'];
  774. }
  775. if (array_key_exists('BYDAY', $form_values) && !is_array($form_values['BYDAY'])) {
  776. $form_values['BYDAY'] = (array) $form_values['BYDAY'];
  777. }
  778. }
  779. break;
  780. case 'YEARLY':
  781. if (array_key_exists('yearly', $form_values)) {
  782. switch ($form_values['yearly']['day_month']) {
  783. case 'BYMONTHDAY_BYMONTH':
  784. $form_values['yearly'] = array_merge($form_values['yearly'], (array) $form_values['yearly']['BYMONTHDAY_BYMONTH_child']);
  785. break;
  786. case 'BYDAY_BYMONTH':
  787. $form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY'] = $form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY_COUNT'] . $form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY_DAY'];
  788. $form_values['yearly'] = array_merge($form_values['yearly'], (array) $form_values['yearly']['BYDAY_BYMONTH_child']);
  789. break;
  790. }
  791. unset($form_values['yearly']['BYDAY_BYMONTH_child']);
  792. unset($form_values['yearly']['BYMONTHDAY_BYMONTH_child']);
  793. $form_values = array_merge($form_values, (array) $form_values['yearly']);
  794. if (array_key_exists('BYMONTH', $form_values)) {
  795. $form_values['BYMONTH'] = date_repeat_transform_checkbox_values_to_select_values($form_values['BYMONTH']);
  796. }
  797. if (array_key_exists('BYMONTHDAY', $form_values) && !is_array($form_values['BYMONTHDAY'])) {
  798. $form_values['BYMONTHDAY'] = (array) $form_values['BYMONTHDAY'];
  799. }
  800. if (array_key_exists('BYDAY', $form_values) && !is_array($form_values['BYDAY'])) {
  801. $form_values['BYDAY'] = (array) $form_values['BYDAY'];
  802. }
  803. }
  804. break;
  805. default:
  806. break;
  807. }
  808. }
  809. unset($form_values['daily']);
  810. unset($form_values['weekly']);
  811. unset($form_values['monthly']);
  812. unset($form_values['yearly']);
  813. if (array_key_exists('range_of_repeat', $form_values)) {
  814. switch ($form_values['range_of_repeat']) {
  815. case 'COUNT':
  816. $form_values['COUNT'] = $form_values['count_child'];
  817. break;
  818. case 'UNTIL':
  819. $form_values['UNTIL'] = $form_values['until_child'];
  820. break;
  821. }
  822. }
  823. unset($form_values['count_child']);
  824. unset($form_values['until_child']);
  825. if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) {
  826. unset($form_values['BYDAY']['']);
  827. }
  828. if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH'])) {
  829. unset($form_values['BYMONTH']['']);
  830. }
  831. if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY'])) {
  832. unset($form_values['BYMONTHDAY']['']);
  833. }
  834. if (array_key_exists('UNTIL', $form_values) && is_array($form_values['UNTIL']['datetime'])) {
  835. $function = $element['#date_repeat_widget'] . '_input_date';
  836. $until_element = $element;
  837. $until_element['#date_format'] = !empty($element['#date_format']) ?
  838. date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
  839. $date = $function($until_element, $form_values['UNTIL']['datetime']);
  840. $form_values['UNTIL']['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
  841. }
  842. if (array_key_exists('show_exceptions', $form_values) && $form_values['show_exceptions'] === 0) {
  843. unset($form_values['EXDATE']);
  844. }
  845. if (array_key_exists('EXDATE', $form_values) && is_array($form_values['EXDATE'])) {
  846. $function = $element['#date_repeat_widget'] . '_input_date';
  847. $exdate_element = $element;
  848. $date_format = 'Y-m-d';
  849. if (!empty($element['#date_format'])) {
  850. $grans = array('year', 'month', 'day');
  851. $date_format = date_limit_format($element['#date_format'], $grans);
  852. }
  853. foreach ($form_values['EXDATE'] as $delta => $value) {
  854. if (is_array($value['datetime'])) {
  855. $exdate_element['#date_format'] = $date_format;
  856. $date = $function($exdate_element, $form_values['EXDATE'][$delta]['datetime']);
  857. $form_values['EXDATE'][$delta]['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
  858. }
  859. }
  860. }
  861. if (array_key_exists('show_additions', $form_values) && $form_values['show_additions'] === 0) {
  862. unset($form_values['RDATE']);
  863. }
  864. if (array_key_exists('RDATE', $form_values) && is_array($form_values['RDATE'])) {
  865. $function = $element['#date_repeat_widget'] . '_input_date';
  866. $rdate_element = $element;
  867. $date_format = 'Y-m-d';
  868. if (!empty($element['#date_format'])) {
  869. $grans = array('year', 'month', 'day');
  870. $date_format = date_limit_format($element['#date_format'], $grans);
  871. }
  872. foreach ($form_values['RDATE'] as $delta => $value) {
  873. if (is_array($value['datetime'])) {
  874. $rdate_element['#date_format'] = $date_format;
  875. $date = $function($rdate_element, $form_values['RDATE'][$delta]['datetime']);
  876. $form_values['RDATE'][$delta]['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
  877. }
  878. }
  879. }
  880. return $form_values;
  881. }
  882. /**
  883. * Build a RRULE out of the form values.
  884. */
  885. function date_repeat_rrule_validate($element, &$form_state) {
  886. if (date_hidden_element($element)) {
  887. return;
  888. }
  889. $parents = $element['#parents'];
  890. array_pop($parents);
  891. $field_values = drupal_array_get_nested_value($form_state['values'], $parents);
  892. if ($field_values['show_repeat_settings'] === 0 || $field_values['rrule']['FREQ'] === 'NONE') {
  893. form_set_value($element, NULL, $form_state);
  894. return;
  895. }
  896. // Clean the buttons off of the form. Needed to avoid errors when
  897. // the date is used on a user object, which then passes the form
  898. // through form_state_values_clean().
  899. foreach ($form_state['buttons'] as $delta => $item) {
  900. if (!empty($item['#ajax']['callback']) && in_array($item['#ajax']['callback'], array('date_repeat_add_exception_callback', 'date_repeat_add_addition_callback'))) {
  901. unset($form_state['buttons'][$delta]);
  902. }
  903. }
  904. module_load_include('inc', 'date_api', 'date_api_ical');
  905. $item = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
  906. $item = date_repeat_merge($item, $element);
  907. $rrule = date_api_ical_build_rrule($item);
  908. form_set_value($element, $rrule, $form_state);
  909. }
  910. /**
  911. * Theme the exception list as a table so the buttons line up.
  912. */
  913. function theme_date_repeat_current_exceptions($vars) {
  914. $rows = $vars['rows'];
  915. $rows_info = array();
  916. foreach ($rows as $key => $value) {
  917. if (substr($key, 0, 1) != '#') {
  918. $rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
  919. }
  920. }
  921. return theme('table', array(
  922. 'header' => array(t('Delete'), t('Current exceptions')),
  923. 'rows' => $rows_info)
  924. );
  925. }
  926. /**
  927. * Theme the exception list as a table so the buttons line up.
  928. */
  929. function theme_date_repeat_current_additions($rows = array()) {
  930. $rows_info = array();
  931. foreach ($rows as $key => $value) {
  932. if (substr($key, 0, 1) != '#') {
  933. $rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
  934. }
  935. }
  936. return theme('table', array(
  937. 'header' => array(t('Delete'), t('Current additions')),
  938. 'rows' => $rows_info)
  939. );
  940. }
  941. /**
  942. * Wrapper fieldset for repeat rule.
  943. */
  944. function theme_date_repeat_rrule($vars) {
  945. $element = $vars['element'];
  946. $id = drupal_html_id('repeat-settings-fieldset');
  947. $parents = $element['#parents'];
  948. $selector = $parents[0];
  949. for ($i = 1; $i < count($parents) - 1; $i++) {
  950. $selector .= '[' . $parents[$i] . ']';
  951. }
  952. $selector .= '[show_repeat_settings]';
  953. $fieldset = array(
  954. '#type' => 'item',
  955. '#title' => t('Repeat settings'),
  956. '#title_display' => 'invisible',
  957. '#markup' => $element['#children'],
  958. '#states' => array(
  959. 'invisible' => array(
  960. ":input[name=\"{$selector}\"]" => array('checked' => FALSE),
  961. ),
  962. ),
  963. '#id' => $id,
  964. );
  965. return drupal_render($fieldset);
  966. }
  967. /**
  968. * Filter non zero values.
  969. */
  970. function date_repeat_filter_non_zero_value($value) {
  971. return $value !== 0;
  972. }
  973. /**
  974. * Helper function for transforming the return value of checkbox(es) element.
  975. *
  976. * Can be used for transforming the returned value of checkbox(es) element
  977. * to the format of returned value of multiple select element.
  978. */
  979. function date_repeat_transform_checkbox_values_to_select_values($values) {
  980. return array_filter($values, 'date_repeat_filter_non_zero_value');
  981. }