date_repeat_form.inc 38 KB

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