Now all modules are in core modules folder

This commit is contained in:
Manuel Cillero 2017-08-08 12:14:45 +02:00
parent 5ba1cdfa0b
commit 05b6a91b0c
1907 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,11 @@
name = Date Repeat API
description = A Date Repeat API to calculate repeating dates and times from iCal rules.
dependencies[] = date_api
package = Date/Time
core = 6.x
; Information added by Drupal.org packaging script on 2014-03-31
version = "6.x-2.10"
core = "6.x"
project = "date"
datestamp = "1396284252"

View file

@ -0,0 +1,62 @@
<?php
/**
* @file
* Install file for Date Repeat.
*/
/**
* Implementation of hook_install().
*/
function date_repeat_install() {
// Make sure this module loads after date_api.
db_query("UPDATE {system} SET weight = 1 WHERE name = 'date_repeat'");
if (module_exists('content')) {
drupal_load('module', 'content');
if (!db_table_exists(content_instance_tablename())) {
return;
}
db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=1 WHERE widget_type='%s' OR widget_type='%s' OR widget_type='%s'", 'date_select_repeat', 'date_text_repeat', 'date_popup_repeat');
content_clear_type_cache(TRUE);
}
}
/**
* Implementation of hook_uninstall().
*/
function date_repeat_uninstall() {
if (module_exists('content')) {
drupal_load('module', 'content');
if (!db_table_exists(content_instance_tablename())) {
return;
}
db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=0 WHERE widget_type='%s' OR widget_type='%s' OR widget_type='%s'", 'date_select_repeat', 'date_text_repeat', 'date_popup_repeat');
content_clear_type_cache(TRUE);
}
}
/**
* Implementation of hook_enable().
*/
function date_repeat_enable() {
if (module_exists('content')) {
drupal_load('module', 'content');
if (!db_table_exists(content_instance_tablename())) {
return;
}
db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=1 WHERE widget_type='%s' OR widget_type='%s' OR widget_type='%s'", 'date_select_repeat', 'date_text_repeat', 'date_popup_repeat');
content_clear_type_cache(TRUE);
}
}
/**
* Implementation of hook_disable().
*/
function date_repeat_disable() {
if (module_exists('content')) {
drupal_load('module', 'content');
if (!db_table_exists(content_instance_tablename())) {
return;
}
db_query("UPDATE {". content_instance_tablename() ."} SET widget_active=0 WHERE widget_type='%s' OR widget_type='%s' OR widget_type='%s'", 'date_select_repeat', 'date_text_repeat', 'date_popup_repeat');
content_clear_type_cache(TRUE);
}
}

View file

@ -0,0 +1,306 @@
<?php
/**
* @file
*
* 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.
*
*/
/**
* Implementation of hook_elements().
*/
function date_repeat_elements() {
$type['date_repeat_rrule'] = array(
'#input' => TRUE,
'#process' => array('date_repeat_rrule_process'),
'#element_validate' => array('date_repeat_rrule_validate'),
);
return $type;
}
/**
* Implementation of hook_menu.
*/
function date_repeat_menu() {
$items = array();
$items['date_repeat_get_exception_form_ajax'] = array(
'page callback' => 'date_repeat_get_exception_form_ajax',
'page arguments' => array(1, 2),
'file' => 'date_repeat_form.inc',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK
);
return $items;
}
function date_repeat_theme() {
return array(
'date_repeat' => array('arguments' => array('element' => NULL)),
'date_repeat_current_exceptions' => array('arguments' => array('element' => NULL)),
'date_repeat_current_additions' => array('arguments' => array('element' => NULL)),
);
}
/**
* Helper function for FREQ options.
*/
function FREQ_options() {
return array(
'NONE' => t('-- Period'),
'DAILY' => date_t('Days', 'datetime_plural'),
'WEEKLY' => date_t('Weeks', 'datetime_plural'),
'MONTHLY' => date_t('Months', 'datetime_plural'),
'YEARLY' => date_t('Years', 'datetime_plural'),
);
}
function INTERVAL_options() {
$options = array(
0 => t('-- Frequency'),
1 => date_t('Every', 'date_order'),
);
for ($i = 2; $i < 367; $i++) {
$options[$i] = t('Every @number', array('@number' => $i));
}
return $options;
}
/**
* Helper function for FREQ options.
*
* Translated and untranslated arrays of the iCal day of week names.
* We need the untranslated values for date_modify(), translated
* values when displayed to user.
*/
function date_repeat_dow_day_options($translated = TRUE) {
return array(
'SU' => $translated ? date_t('Sunday', 'day_name') : 'Sunday',
'MO' => $translated ? date_t('Monday', 'day_name') : 'Monday',
'TU' => $translated ? date_t('Tuesday', 'day_name') : 'Tuesday',
'WE' => $translated ? date_t('Wednesday', 'day_name') : 'Wednesday',
'TH' => $translated ? date_t('Thursday', 'day_name') : 'Thursday',
'FR' => $translated ? date_t('Friday', 'day_name') : 'Friday',
'SA' => $translated ? date_t('Saturday', 'day_name') : 'Saturday',
);
}
function date_repeat_dow_day_options_ordered($week_start) {
$unordered = date_repeat_dow_day_options(FALSE);
if (variable_get('date_first_day', 1) > 0) {
for ($i = 1; $i <= variable_get('date_first_day', 1); $i++) {
$last = array_shift($weekdays);
array_push($weekdays, $last);
}
}
return $weekdays;
}
/**
* Helper function for BYDAY options.
*/
function date_repeat_dow_count_options() {
return array('' => date_t('Every', 'date_order')) + date_order_translated();
}
/**
* Helper function for BYDAY options.
*
* Creates options like -1SU and 2TU
*/
function date_repeat_dow_options() {
$options = array();
foreach (date_repeat_dow_count_options() as $count_key => $count_value) {
foreach (date_repeat_dow_day_options() as $dow_key => $dow_value) {
$options[$count_key . $dow_key] = $count_value .' '. $dow_value;
}
}
return $options;
}
/**
* Translate a day of week position to the iCal day name.
*
* Used with date_format($date, 'w') or get_variable('date_first_day'),
* which return 0 for Sunday, 1 for Monday, etc.
*
* dow 2 becomes 'TU', dow 3 becomes 'WE', and so on.
*/
function date_repeat_dow2day($dow) {
$days_of_week = array_keys(date_repeat_dow_day_options(FALSE));
return $days_of_week[$dow];
}
/**
* Shift the array of iCal day names into the right order
* for a specific week start day.
*/
function date_repeat_days_ordered($week_start_day) {
$days = array_flip(array_keys(date_repeat_dow_day_options(FALSE)));
$start_position = $days[$week_start_day];
$keys = array_flip($days);
if ($start_position > 0) {
for ($i = 1; $i <= $start_position; $i++) {
$last = array_shift($keys);
array_push($keys, $last);
}
}
return $keys;
}
/**
* Build a description of an iCal rule.
*
* Constructs a human-readable description of the rule.
*/
function date_repeat_rrule_description($rrule, $format = 'D M d Y') {
// Empty or invalid value.
if (empty($rrule) || !strstr($rrule, 'RRULE')) {
return;
}
require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
require_once('./'. drupal_get_path('module', 'date_repeat') .'/date_repeat_calc.inc');
// Make sure there will be an empty description for any unused parts.
$description = array(
'!interval' => '',
'!byday' => '',
'!bymonth' => '',
'!count' => '',
'!until' => '',
'!except' => '',
'!additional' => '',
'!week_starts_on' => '',
);
$parts = date_repeat_split_rrule($rrule);
$additions = $parts[2];
$exceptions = $parts[1];
$rrule = $parts[0];
$interval = INTERVAL_options();
switch ($rrule['FREQ']) {
case 'WEEKLY':
$description['!interval'] = format_plural($rrule['INTERVAL'], 'every week', 'every @count weeks') .' ';
break;
case 'MONTHLY':
$description['!interval'] = format_plural($rrule['INTERVAL'], 'every month', 'every @count months') .' ';
break;
case 'YEARLY':
$description['!interval'] = format_plural($rrule['INTERVAL'], 'every year', 'every @count years') .' ';
break;
default:
$description['!interval'] = format_plural($rrule['INTERVAL'], 'every day', 'every @count days') .' ';
break;
}
if (!empty($rrule['BYDAY'])) {
$days = date_repeat_dow_day_options();
$counts = date_repeat_dow_count_options();
$results = array();
foreach ($rrule['BYDAY'] as $byday) {
$day = drupal_substr($byday, -2);
$count = intval(str_replace(' '. $day, '', $byday));
if ($count = intval(str_replace(' ' . $day, '', $byday))) {
$results[] = trim(t('!repeats_every_interval on the !date_order !day_of_week', array('!repeats_every_interval ' => '', '!date_order' => strtolower($counts[drupal_substr($byday, 0, 2)]), '!day_of_week' => $days[$day])));
}
else {
$results[] = trim(t('!repeats_every_interval every !day_of_week', array('!repeats_every_interval ' => '', '!day_of_week' => $days[$day])));
}
}
$description['!byday'] = implode(' '. t('and') .' ', $results);
}
if (!empty($rrule['BYMONTH'])) {
if (sizeof($rrule['BYMONTH']) < 12) {
$results = array();
$months = date_month_names();
foreach ($rrule['BYMONTH'] as $month) {
$results[] = $months[$month];
}
if (!empty($rrule['BYMONTHDAY'])) {
$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))));
}
else {
$description['!bymonth'] = trim(t('!repeats_every_interval on !month_names', array('!repeats_every_interval ' => '', '!month_names' => implode(', ', $results))));
}
}
}
if ($rrule['INTERVAL'] < 1) {
$rrule['INTERVAL'] = 1;
}
if (!empty($rrule['COUNT'])) {
$description['!count'] = trim(t('!repeats_every_interval !count times', array('!repeats_every_interval ' => '', '!count' => $rrule['COUNT'])));
}
if (!empty($rrule['UNTIL'])) {
$until = date_ical_date($rrule['UNTIL'], 'UTC');
date_timezone_set($until, date_default_timezone());
$description['!until'] = trim(t('!repeats_every_interval until !until_date', array('!repeats_every_interval ' => '', '!until_date' => date_format_date($until, 'custom', $format))));
}
if ($exceptions) {
$values = array();
foreach ($exceptions as $exception) {
$values[] = date_format_date(date_ical_date($exception), 'custom', $format);
}
$description['!except'] = trim(t('!repeats_every_interval except !except_dates', array('!repeats_every_interval ' => '', '!except_dates' => implode(', ', $values))));
}
if ($additions) {
$values = array();
foreach ($additions as $addition) {
$values[] = date_format_date(date_ical_date($addition), 'custom', $format);
}
$description['!additional'] = trim(t('Also includes !additional_dates.', array('!additional_dates' => implode(', ', $values))));
}
if (!empty($rrule['WKST'])) {
$day_names = date_repeat_dow_day_options();
$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'])])));
}
return t('Repeats !interval !bymonth !byday !count !until !except. !additional', $description);
}
/**
* Parse an iCal rule into a parsed RRULE array and an EXDATE array.
*/
function date_repeat_split_rrule($rrule) {
$parts = explode("\n", str_replace("\r\n", "\n", $rrule));
$rrule = array();
$exceptions = array();
$additions = array();
foreach ($parts as $part) {
if (strstr($part, 'RRULE')) {
$RRULE = str_replace('RRULE:', '', $part);
$rrule = (array) date_ical_parse_rrule('RRULE:', $RRULE);
}
elseif (strstr($part, 'EXDATE')) {
$EXDATE = str_replace('EXDATE:', '', $part);
$exceptions = (array) date_ical_parse_exceptions('EXDATE:', $EXDATE);
unset($exceptions['DATA']);
}
elseif (strstr($part, 'RDATE')) {
$RDATE = str_replace('RDATE:', '', $part);
$additions = (array) date_ical_parse_exceptions('RDATE:', $RDATE);
unset($additions['DATA']);
}
}
return array($rrule, $exceptions, $additions);
}
/**
* Analyze a RRULE and return dates that match it.
*/
function date_repeat_calc($rrule, $start, $end, $exceptions = array(), $timezone = NULL, $additions = array()) {
require_once('./'. drupal_get_path('module', 'date_repeat') .'/date_repeat_calc.inc');
return _date_repeat_calc($rrule, $start, $end, $exceptions, $timezone, $additions);
}
/**
* Generate the repeat rule setting form.
*/
function date_repeat_rrule_process($element, $edit, $form_state, $form) {
require_once('./'. drupal_get_path('module', 'date_repeat') .'/date_repeat_form.inc');
return _date_repeat_rrule_process($element, $edit, $form_state, $form);
}

View file

@ -0,0 +1,581 @@
<?php
/**
* @file
* Code to compute the dates that match an iCal RRULE.
*
* Moved to a separate file since it is not used on most pages
* so the code is not parsed unless needed.
*
* Extensive simpletests have been created to test the RRULE calculation
* results against official examples from RFC 2445.
*
* These calculations are expensive and results should be stored or cached
* so the calculation code is not called more often than necessary.
*
* Currently implemented:
* INTERVAL, UNTIL, COUNT, EXDATE, RDATE, BYDAY, BYMONTHDAY, BYMONTH,
* YEARLY, MONTHLY, WEEKLY, DAILY
*
* Currently not implemented:
*
* BYYEARDAY, MINUTELY, HOURLY, SECONDLY, BYMINUTE, BYHOUR, BYSECOND
* These could be implemented in the future.
*
* BYSETPOS
* Seldom used anywhere, so no reason to complicated the code.
*/
/**
* Private implementation of date_repeat_calc().
*
* Compute dates that match the requested rule, within a specified date range.
*/
function _date_repeat_calc($rrule, $start, $end, $exceptions, $timezone, $additions) {
module_load_include('inc', 'date_api', 'date_api_ical');
if (empty($timezone)) {
$timezone = date_default_timezone_name();
}
// Make sure the 'EXCEPTIONS' string isn't appended to the rule.
$parts = explode("\n", $rrule);
if (count($parts)) {
$rrule = $parts[0];
}
// Get the parsed array of rule values.
$rrule = date_ical_parse_rrule('RRULE:', $rrule);
// These default values indicate there is no RRULE here.
if ($rrule['FREQ'] == 'NONE' || (isset($rrule['INTERVAL']) && $rrule['INTERVAL'] == 0)) {
return array();
}
// Create a date object for the start and end dates.
$start_date = date_make_date($start, $timezone);
// Versions of PHP greater than PHP 5.3.5 require that we set an explicit time when
// using date_modify() or the time may not match the original value. Adding this
// modifier gives us the same results in both older and newer versions of PHP.
$modify_time = ' ' . $start_date->format('g:ia');
// If the rule has an UNTIL, see if that is earlier than the end date.
if (!empty($rrule['UNTIL'])) {
$end_date = date_make_date($end, $timezone);
$until_date = date_ical_date($rrule['UNTIL'], $timezone);
if (date_format($until_date, 'U') < date_format($end_date, 'U')) {
$end_date = $until_date;
}
}
// The only valid option for an empty end date is when we have a count.
elseif (empty($end)) {
if (!empty($rrule['COUNT'])) {
$end_date = NULL;
}
else {
return array();
}
}
else {
$end_date = date_make_date($end, $timezone);
}
// Get an integer value for the interval, if none given, '1' is implied.
if (empty($rrule['INTERVAL'])) {
$rrule['INTERVAL'] = 1;
}
$interval = max(1, $rrule['INTERVAL']);
$count = isset($rrule['COUNT']) ? $rrule['COUNT'] : NULL;
if (empty($rrule['FREQ'])) {
$rrule['FREQ'] = 'DAILY';
}
// Make sure DAILY frequency isn't used in places it won't work;
if (!empty($rrule['BYMONTHDAY']) && !in_array($rrule['FREQ'], array('MONTHLY', 'YEARLY'))) {
$rrule['FREQ'] = 'MONTHLY';
}
elseif (!empty($rrule['BYDAY']) && !in_array($rrule['FREQ'], array('MONTHLY', 'WEEKLY', 'YEARLY'))) {
$rrule['FREQ'] = 'WEEKLY';
}
// Find the time period to jump forward between dates.
switch ($rrule['FREQ']) {
case 'DAILY':
$jump = $interval . ' days';
break;
case 'WEEKLY':
$jump = $interval . ' weeks';
break;
case 'MONTHLY':
$jump = $interval . ' months';
break;
case 'YEARLY':
$jump = $interval . ' years';
break;
}
$rrule = date_repeat_adjust_rrule($rrule, $start_date);
// The start date always goes into the results, whether or not it meets
// the rules. RFC 2445 includes examples where the start date DOES NOT
// meet the rules, but the expected results always include the start date.
$days = array(date_format($start_date, DATE_FORMAT_DATETIME));
// BYMONTHDAY will look for specific days of the month in one or more months.
// This process is only valid when frequency is monthly or yearly.
if (!empty($rrule['BYMONTHDAY'])) {
$finished = FALSE;
$current_day = drupal_clone($start_date);
$direction_days = array();
// Deconstruct the day in case it has a negative modifier.
foreach ($rrule['BYMONTHDAY'] as $day) {
preg_match("@(-)?([0-9]{1,2})@", $day, $regs);
if (!empty($regs[2])) {
// Convert parameters into full day name, count, and direction.
$direction_days[$day] = array(
'direction' => !empty($regs[1]) ? $regs[1] : '+',
'direction_count' => $regs[2],
);
}
}
while (!$finished) {
$period_finished = FALSE;
while (!$period_finished) {
foreach ($rrule['BYMONTHDAY'] as $monthday) {
$day = $direction_days[$monthday];
$current_day = date_repeat_set_month_day($current_day, NULL, $day['direction_count'], $day['direction'], $timezone, $modify_time);
date_repeat_add_dates($days, $current_day, $start_date, $end_date, $exceptions, $rrule);
if ($finished = date_repeat_is_finished($current_day, $days, $count, $end_date)) {
$period_finished = TRUE;
}
}
// If it's monthly, keep looping through months, one INTERVAL at a time.
if ($rrule['FREQ'] == 'MONTHLY') {
if ($finished = date_repeat_is_finished($current_day, $days, $count, $end_date)) {
$period_finished = TRUE;
}
// Back up to first of month and jump.
$current_day = date_repeat_set_month_day($current_day, NULL, 1, '+', $timezone, $modify_time);
date_modify($current_day, '+' . $jump . $modify_time);
}
// If it's yearly, break out of the loop at the
// end of every year, and jump one INTERVAL in years.
else {
if (date_format($current_day, 'n') == 12) {
$period_finished = TRUE;
}
else {
// Back up to first of month and jump.
$current_day = date_repeat_set_month_day($current_day, NULL, 1, '+', $timezone, $modify_time);
date_modify($current_day, '+1 month' . $modify_time);
}
}
}
if ($rrule['FREQ'] == 'YEARLY') {
// Back up to first of year and jump.
$current_day = date_repeat_set_year_day($current_day, NULL, 1, '+', $timezone, $modify_time);
date_modify($current_day, '+' . $jump . $modify_time);
}
$finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
}
}
// This is the simple fallback case, not looking for any BYDAY,
// just repeating the start date. Because of imputed BYDAY above, this
// will only test TRUE for a DAILY or less frequency (like HOURLY).
elseif (empty($rrule['BYDAY'])) {
// $current_day will keep track of where we are in the calculation.
$current_day = drupal_clone($start_date);
$finished = FALSE;
$months = !empty($rrule['BYMONTH']) ? $rrule['BYMONTH'] : array();
while (!$finished) {
date_repeat_add_dates($days, $current_day, $start_date, $end_date, $exceptions, $rrule);
$finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
date_modify($current_day, '+' . $jump . $modify_time);
}
}
else {
// More complex searches for day names and criteria like '-1SU' or '2TU,2TH',
// require that we interate through the whole time period checking each BYDAY.
// Create helper array to pull day names out of iCal day strings.
$day_names = date_repeat_dow_day_options(FALSE);
$days_of_week = array_keys($day_names);
// Parse out information about the BYDAYs and separate them
// depending on whether they have directional parameters like -1SU or 2TH.
$month_days = array();
$week_days = array();
// Find the right first day of the week to use, iCal rules say Monday
// should be used if none is specified.
$week_start_rule = !empty($rrule['WKST']) ? trim($rrule['WKST']) : 'MO';
$week_start_day = $day_names[$week_start_rule];
// Make sure the week days array is sorted into week order,
// we use the $ordered_keys to get the right values into the key
// and force the array to that order. Needed later when we
// iterate through each week looking for days so we don't
// jump to the next week when we hit a day out of order.
$ordered = date_repeat_days_ordered($week_start_rule);
$ordered_keys = array_flip($ordered);
foreach ($rrule['BYDAY'] as $day) {
preg_match("@(-)?([0-9]+)?([SU|MO|TU|WE|TH|FR|SA]{2})@", trim($day), $regs);
if (!empty($regs[2])) {
// Convert parameters into full day name, count, and direction.
$direction_days[] = array(
'day' => $day_names[$regs[3]],
'direction' => !empty($regs[1]) ? $regs[1] : '+',
'direction_count' => $regs[2],
);
}
else {
$week_days[$ordered_keys[$regs[3]]] = $day_names[$regs[3]];
}
}
ksort($week_days);
// BYDAYs with parameters like -1SU (last Sun) or 2TH (second Thur)
// need to be processed one month or year at a time.
if (!empty($direction_days) && in_array($rrule['FREQ'], array('MONTHLY', 'YEARLY'))) {
$finished = FALSE;
$current_day = drupal_clone($start_date);
while (!$finished) {
foreach ($direction_days as $day) {
// Find the BYDAY date in the current month.
if ($rrule['FREQ'] == 'MONTHLY') {
$current_day = date_repeat_set_month_day($current_day, $day['day'], $day['direction_count'], $day['direction'], $timezone, $modify_time);
}
else {
$current_day = date_repeat_set_year_day($current_day, $day['day'], $day['direction_count'], $day['direction'], $timezone, $modify_time);
}
date_repeat_add_dates($days, $current_day, $start_date, $end_date, $exceptions, $rrule);
}
$finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
// Reset to beginning of period before jumping to next period.
// Needed especially when working with values like 'last Saturday'
// to be sure we don't skip months like February.
$year = date_format($current_day, 'Y');
$month = date_format($current_day, 'n');
if ($rrule['FREQ'] == 'MONTHLY') {
date_date_set($current_day, $year, $month, 1);
}
else {
date_date_set($current_day, $year, 1, 1);
}
// Jump to the next period.
date_modify($current_day, '+' . $jump . $modify_time);
}
}
// For BYDAYs without parameters,like TU,TH (every Tues and Thur),
// we look for every one of those days during the frequency period.
// Iterate through periods of a WEEK, MONTH, or YEAR, checking for
// the days of the week that match our criteria for each week in the
// period, then jumping ahead to the next week, month, or year,
// an INTERVAL at a time.
if (!empty($week_days) && in_array($rrule['FREQ'], array('MONTHLY', 'WEEKLY', 'YEARLY'))) {
$finished = FALSE;
$current_day = drupal_clone($start_date);
$format = $rrule['FREQ'] == 'YEARLY' ? 'Y' : 'n';
$current_period = date_format($current_day, $format);
// Back up to the beginning of the week in case we are somewhere in the
// middle of the possible week days, needed so we don't prematurely
// jump to the next week. The date_repeat_add_dates() function will
// keep dates outside the range from getting added.
if (date_format($current_day, 'l') != $day_names[$day]) {
date_modify($current_day, '-1 ' . $week_start_day . $modify_time);
}
while (!$finished) {
$period_finished = FALSE;
while (!$period_finished) {
$moved = FALSE;
foreach ($week_days as $delta => $day) {
// Find the next occurence of each day in this week, only add it
// if we are still in the current month or year. The date_repeat_add_dates
// function is insufficient to test whether to include this date
// if we are using a rule like 'every other month', so we must
// explicitly test it here.
// If we're already on the right day, don't jump or we
// will prematurely move into the next week.
if (date_format($current_day, 'l') != $day) {
date_modify($current_day, '+1 ' . $day . $modify_time);
$moved = TRUE;
}
if ($rrule['FREQ'] == 'WEEKLY' || date_format($current_day, $format) == $current_period) {
date_repeat_add_dates($days, $current_day, $start_date, $end_date, $exceptions, $rrule);
}
}
$finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
// Make sure we don't get stuck in endless loop if the current
// day never got changed above.
if (!$moved) {
date_modify($current_day, '+1 day' . $modify_time);
}
// If this is a WEEKLY frequency, stop after each week,
// otherwise, stop when we've moved outside the current period.
// Jump to the end of the week, then test the period.
if ($finished || $rrule['FREQ'] == 'WEEKLY') {
$period_finished = TRUE;
}
elseif ($rrule['FREQ'] != 'WEEKLY' && date_format($current_day, $format) != $current_period) {
$period_finished = TRUE;
}
}
if ($finished) {
continue;
}
// We'll be at the end of a week, month, or year when
// we get to this point in the code.
// Go back to the beginning of this period before we jump, to
// ensure we jump to the first day of the next period.
switch ($rrule['FREQ']) {
case 'WEEKLY':
date_modify($current_day, '+1 ' . $week_start_day . $modify_time);
date_modify($current_day, '-1 week' . $modify_time);
break;
case 'MONTHLY':
date_modify($current_day, '-' . (date_format($current_day, 'j') - 1) . ' days' . $modify_time);
date_modify($current_day, '-1 month' . $modify_time);
break;
case 'YEARLY':
date_modify($current_day, '-' . date_format($current_day, 'z') . ' days' . $modify_time);
date_modify($current_day, '-1 year' . $modify_time);
break;
}
// Jump ahead to the next period to be evaluated.
date_modify($current_day, '+' . $jump . $modify_time);
$current_period = date_format($current_day, $format);
$finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
}
}
}
// add additional dates
foreach ($additions as $addition) {
$date = date_make_date($addition . ' ' . date_format($start_date, 'H:i:s'), $timezone);
$days[] = date_format($date, DATE_FORMAT_DATETIME);
}
sort($days);
return $days;
}
/**
* See if the RRULE needs some imputed values added to it.
*/
function date_repeat_adjust_rrule($rrule, $start_date) {
// If this is not a valid value, do nothing;
if (empty($rrule) || empty($rrule['FREQ'])) {
return array();
}
// RFC 2445 says if no day or monthday is specified when creating repeats for
// weeks, months, or years, impute the value from the start date.
if (empty($rrule['BYDAY']) && $rrule['FREQ'] == 'WEEKLY') {
$rrule['BYDAY'] = array(date_repeat_dow2day(date_format($start_date, 'w')));
}
elseif (empty($rrule['BYDAY']) && empty($rrule['BYMONTHDAY']) && $rrule['FREQ'] == 'MONTHLY') {
$rrule['BYMONTHDAY'] = array(date_format($start_date, 'j'));
}
elseif (empty($rrule['BYDAY']) && empty($rrule['BYMONTHDAY']) && empty($rrule['BYYEARDAY']) && $rrule['FREQ'] == 'YEARLY') {
$rrule['BYMONTHDAY'] = array(date_format($start_date, 'j'));
if (empty($rrule['BYMONTH'])) {
$rrule['BYMONTH'] = array(date_format($start_date, 'n'));
}
}
// If we are processing rules for period other than YEARLY or MONTHLY
// and have BYDAYS like 2SU or -1SA, simplify them to SU or SA since the
// position rules make no sense in other periods and just add complexity.
elseif (!empty($rrule['BYDAY']) && !in_array($rrule['FREQ'], array('MONTHLY', 'YEARLY'))) {
foreach ($rrule['BYDAY'] as $delta => $BYDAY) {
$rrule['BYDAY'][$delta] = drupal_substr($BYDAY, -2);
}
}
return $rrule;
}
/**
* Helper function to add found date to the $dates array.
*
* Check that the date to be added is between the start and end date
* and that it is not in the $exceptions, nor already in the $days array,
* and that it meets other criteria in the RRULE.
*/
function date_repeat_add_dates(&$days, $current_day, $start_date, $end_date, $exceptions, $rrule) {
if (isset($rrule['COUNT']) && sizeof($days) >= $rrule['COUNT']) {
return FALSE;
}
$formatted = date_format($current_day, DATE_FORMAT_DATETIME);
if (!empty($end_date) && $formatted > date_format($end_date, DATE_FORMAT_DATETIME)) {
return FALSE;
}
if ($formatted < date_format($start_date, DATE_FORMAT_DATETIME)) {
return FALSE;
}
if (in_array(date_format($current_day, 'Y-m-d'), $exceptions)) {
return FALSE;
}
if (!empty($rrule['BYDAY'])) {
$BYDAYS = $rrule['BYDAY'];
foreach ($BYDAYS as $delta => $BYDAY) {
$BYDAYS[$delta] = drupal_substr($BYDAY, -2);
}
if (!in_array(date_repeat_dow2day(date_format($current_day, 'w')), $BYDAYS)) {
return FALSE;
}}
if (!empty($rrule['BYYEAR']) && !in_array(date_format($current_day, 'Y'), $rrule['BYYEAR'])) {
return FALSE;
}
if (!empty($rrule['BYMONTH']) && !in_array(date_format($current_day, 'n'), $rrule['BYMONTH'])) {
return FALSE;
}
if (!empty($rrule['BYMONTHDAY'])) {
// Test month days, but only if there are no negative numbers.
$test = TRUE;
$BYMONTHDAYS = array();
foreach ($rrule['BYMONTHDAY'] as $day) {
if ($day > 0) {
$BYMONTHDAYS[] = $day;
}
else {
$test = FALSE;
break;
}
}
if ($test && !empty($BYMONTHDAYS) && !in_array(date_format($current_day, 'j'), $BYMONTHDAYS)) {
return FALSE;
}
}
// Don't add a day if it is already saved so we don't throw the count off.
if (in_array($formatted, $days)) {
return TRUE;
}
else {
$days[] = $formatted;
}
}
/**
* Stop when $current_day is greater than $end_date or $count is reached.
*/
function date_repeat_is_finished($current_day, $days, $count, $end_date) {
if (($count && sizeof($days) >= $count)
|| (!empty($end_date) && date_format($current_day, 'U') > date_format($end_date, 'U'))) {
return TRUE;
}
else {
return FALSE;
}
}
/**
* Set a date object to a specific day of the month.
*
* Example,
* date_set_month_day($date, 'Sunday', 2, '-')
* will reset $date to the second to last Sunday in the month.
* If $day is empty, will set to the number of days from the
* beginning or end of the month.
*/
function date_repeat_set_month_day($date_in, $day, $count = 1, $direction = '+', $timezone = 'UTC', $modify_time) {
if (is_object($date_in)) {
$current_month = date_format($date_in, 'n');
// Reset to the start of the month.
// We should be able to do this with date_date_set(), but
// for some reason the date occasionally gets confused if run
// through this function multiple times. It seems to work
// reliably if we create a new object each time.
$datetime = date_format($date_in, DATE_FORMAT_DATETIME);
$datetime = substr_replace($datetime, '01', 8, 2);
$date = date_make_date($datetime, $timezone);
if ($direction == '-') {
// For negative search, start from the end of the month.
date_modify($date, '+1 month' . $modify_time);
}
else {
// For positive search, back up one day to get outside the
// current month, so we can catch the first of the month.
date_modify($date, '-1 day' . $modify_time);
}
if (empty($day)) {
date_modify($date, $direction . $count . ' days' . $modify_time);
}
else {
// Use the English text for order, like First Sunday
// instead of +1 Sunday to overcome PHP5 bug, (see #369020).
$order = date_order();
$step = $count <= 5 ? $order[$direction . $count] : $count;
date_modify($date, $step . ' ' . $day . $modify_time);
}
// If that takes us outside the current month, don't go there.
if (date_format($date, 'n') == $current_month) {
return $date;
}
}
return $date_in;
}
/**
* Set a date object to a specific day of the year.
*
* Example,
* date_set_year_day($date, 'Sunday', 2, '-')
* will reset $date to the second to last Sunday in the year.
* If $day is empty, will set to the number of days from the
* beginning or end of the year.
*/
function date_repeat_set_year_day($date_in, $day, $count = 1, $direction = '+', $timezone = 'UTC', $modify_time) {
if (is_object($date_in)) {
$current_year = date_format($date_in, 'Y');
// Reset to the start of the month.
// See note above.
$datetime = date_format($date_in, DATE_FORMAT_DATETIME);
$datetime = substr_replace($datetime, '01-01', 5, 5);
$date = date_make_date($datetime, $timezone);
if ($direction == '-') {
// For negative search, start from the end of the year.
date_modify($date, '+1 year' . $modify_time);
}
else {
// For positive search, back up one day to get outside the
// current year, so we can catch the first of the year.
date_modify($date, '-1 day' . $modify_time);
}
if (empty($day)) {
date_modify($date, $direction . $count . ' days' . $modify_time);
}
else {
// Use the English text for order, like First Sunday
// instead of +1 Sunday to overcome PHP5 bug, (see #369020).
$order = date_order();
$step = $count <= 5 ? $order[$direction . $count] : $count;
date_modify($date, $step . ' ' . $day . $modify_time);
}
// If that takes us outside the current year, don't go there.
if (date_format($date, 'Y') == $current_year) {
return $date;
}
}
return $date_in;
}

View file

@ -0,0 +1,407 @@
<?php
/**
* @file
* Code to add a date repeat selection form to a date field and create
* an iCal RRULE from the chosen selections.
*
* Moved to a separate file since it is not used on most pages
* so the code is not parsed unless needed.
*
* Currently implemented:
* INTERVAL, UNTIL, EXDATE, RDATE, BYDAY, BYMONTHDAY, BYMONTH,
* YEARLY, MONTHLY, WEEKLY, DAILY
*
* Currently not implemented:
*
* BYYEARDAY, MINUTELY, HOURLY, SECONDLY, BYMINUTE, BYHOUR, BYSECOND
* These could be implemented in the future.
*
* COUNT
* The goal of this module is to create a way we can parse an iCal
* RRULE and pull out just dates for a specified date range, for
* instance with a date that repeats daily for several years, we might
* want to only be able to pull out the dates for the current year.
*
* Adding COUNT to the rules we create makes it impossible to do that
* without parsing and computing the whole range of dates that the rule
* will create. COUNT is left off of the user form completely for this
* reason.
*
* BYSETPOS
* Seldom used anywhere, so no reason to complicated the code.
*/
/**
* Generate the repeat setting form.
*/
function _date_repeat_rrule_process($element, $edit, $form_state, $form) {
require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
if (empty($element['#date_repeat_widget'])) {
$element['#date_repeat_widget'] = module_exists('date_popup') ? 'date_popup' : 'date_select';
}
if (is_array($element['#value'])) {
$element['#value'] = date_repeat_merge($element['#value'], $element);
$rrule = date_api_ical_build_rrule($element['#value']);
}
else {
$rrule = $element['#value'];
}
// Empty the original string value of the RRULE so we can create
// an array of values for the form from the RRULE's contents.
$element['#value'] = '';
$parts = date_repeat_split_rrule($rrule);
$rrule = $parts[0];
$exceptions = $parts[1];
$additions = $parts[2];
$timezone = !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone_name();
$merged_values = date_repeat_merge($rrule, $element);
$UNTIL = '';
if (!empty($merged_values['UNTIL']['datetime'])) {
$until_date = date_make_date($merged_values['UNTIL']['datetime'], $merged_values['UNTIL']['tz']);
date_timezone_set($until_date, timezone_open($timezone));
$UNTIL = date_format($until_date, DATE_FORMAT_DATETIME);
}
$parent_collapsed = !empty($rrule['INTERVAL']) || !empty($rrule['FREQ']) ? 0 : (!empty($element['#date_repeat_collapsed']) ? $element['#date_repeat_collapsed'] : 0);
$element['#type'] = 'fieldset';
$element['#title'] = t('Repeat');
$element['#description'] = theme('advanced_help_topic', 'date_api', 'date-repeat-form') . t('Choose a frequency and period to repeat this date. If nothing is selected, the date will not repeat.');
$element['#collapsible'] = TRUE;
$element['#collapsed'] = $parent_collapsed;
// Make sure we don't get floating parts where we don't want them.
$element['#prefix'] = '<div class="date-clear">';
$element['#suffix'] = '</div>';
$element['INTERVAL'] = array(
'#type' => 'select',
//'#title' => t('Interval'),
'#default_value' => (!empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 0),
'#options' => INTERVAL_options(),
'#prefix' => '<div class="date-repeat-input">',
'#suffix' => '</div>',
);
$element['FREQ'] = array(
'#type' => 'select',
//'#title' => t('Frequency'),
'#default_value' => !empty($rrule['FREQ']) ? $rrule['FREQ'] : 'NONE',
'#options' => FREQ_options(),
'#prefix' => '<div class="date-repeat-input">',
'#suffix' => '</div>',
);
$element['UNTIL'] = array(
'#tree' => TRUE,
'#prefix' => '<div class="date-clear">',
'#suffix' => '</div>',
'datetime' => array(
'#type' => $element['#date_repeat_widget'],
'#title' => t('Until'),
'#description' => t('Date to stop repeating this item.'),
'#default_value' => $UNTIL,
'#date_timezone' => $timezone,
'#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
'#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
'#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
'#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
),
'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
'all_day' => array('#type' => 'hidden', '#value' => isset($merged_values['UNTIL']['all_day']) ? $merged_values['UNTIL']['all_day'] : 1),
'granularity' => array('#type' => 'hidden', '#value' => isset($merged_values['UNTIL']['granularity']) ? $merged_values['UNTIL']['granularity'] : serialize(array('year', 'month', 'day'))),
);
$collapsed = TRUE;
if (!empty($merged_values['BYDAY']) || !empty($merged_values['BYMONTH'])) {
$collapsed = FALSE;
}
// start the advanced fieldset
$element['advanced'] = array(
'#type' => 'fieldset',
'#title' => t('Advanced'),
'#collapsible' => TRUE,
'#collapsed' => $collapsed,
'#description' => t("If no advanced options are selected, the date will repeat on the day of week of the start date for weekly repeats, otherwise on the month and day of the start date. Use the options below to override that behavior to select specific months and days to repeat on. Use the 'Except' box to input dates that should be omitted from the results.") .' ',
'#prefix' => '<div class="date-clear">',
'#suffix' => '</div>',
);
$element['advanced']['BYMONTH'] = array(
'#type' => 'select',
'#title' => date_t('Month', 'datetime'),
'#default_value' => !empty($rrule['BYMONTH']) ? $rrule['BYMONTH'] : '',
'#options' => array('' => t('-- Any')) + date_month_names(TRUE),
'#multiple' => TRUE,
'#size' => 10,
'#prefix' => '<div class="date-repeat-input">',
'#suffix' => '</div>',
);
$element['advanced']['BYMONTHDAY'] = array(
'#type' => 'select',
'#title' => t('Day of Month'),
'#default_value' => !empty($rrule['BYMONTHDAY']) ? $rrule['BYMONTHDAY'] : '',
'#options' => array('' => t('-- Any')) + drupal_map_assoc(range(1, 31)) + drupal_map_assoc(range(-1, -31)),
'#multiple' => TRUE,
'#size' => 10,
'#prefix' => '<div class="date-repeat-input">',
'#suffix' => '</div>',
);
$element['advanced']['BYDAY'] = array(
'#type' => 'select',
'#title' => t('Day of Week'),
'#default_value' => !empty($rrule['BYDAY']) ? $rrule['BYDAY'] : '',
'#options' => array('' => t('-- Any')) + date_repeat_dow_options(),
//'#attributes' => array('size' => '5'),
'#multiple' => TRUE,
'#size' => 10,
'#prefix' => '<div class="date-repeat-input">',
'#suffix' => '</div>',
);
$element['exceptions'] = array(
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#collapsed' => empty($exceptions) ? TRUE : FALSE,
'#title' => t('Except'),
'#description' => t('Dates to omit from the list of repeating dates.'),
'#prefix' => '<div id="date-repeat-exceptions" class="date-repeat">',
'#suffix' => '</div>',
);
$max = !empty($exceptions) ? sizeof($exceptions) : 0;
for ($i = 0; $i <= $max; $i++) {
$EXCEPT = '';
if (!empty($exceptions[$i]['datetime'])) {
$EXCEPT = $exceptions[$i]['datetime'];
}
$element['exceptions']['EXDATE'][$i] = array(
'#tree' => TRUE,
'datetime' => array(
'#type' => $element['#date_repeat_widget'],
'#default_value' => $EXCEPT,
'#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone_name(),
'#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
'#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
'#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
'#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
),
'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
'all_day' => array('#type' => 'hidden', '#value' => 1),
'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
);
}
// collect additions in the same way as exceptions - implements RDATE.
$element['additions'] = array(
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#collapsed' => empty($additions) ? TRUE : FALSE,
'#title' => t('Additional'),
'#description' => t('Dates to add to the list of repeating dates.'),
'#prefix' => '<div id="date-repeat-additions" class="date-repeat">',
'#suffix' => '</div>',
);
$max = !empty($additions) ? sizeof($additions) : 0;
for ($i = 0; $i <= $max; $i++) {
$RDATE = '';
if (!empty($additions[$i]['datetime'])) {
$RDATE = $additions[$i]['datetime'];
}
$element['additions']['RDATE'][$i] = array(
'#tree' => TRUE,
'datetime' => array(
'#type' => $element['#date_repeat_widget'],
'#default_value' => $RDATE,
'#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone_name(),
'#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
'#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
'#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
'#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
),
'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
'all_day' => array('#type' => 'hidden', '#value' => 1),
'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
);
}
// Create an "Add another" button for the exceptions.
$field_name = $element['#parents'][0];
$element['exceptions']['exceptions_addmore'] = array(
'#type' => 'button',
'#value' => t('Add more exceptions'),
'#ahah' => array(
'event' => 'click',
'path' => 'date_repeat_get_exception_form_ajax/exceptions/' . $field_name,
'wrapper' => 'date-repeat-exceptions',
'method' => 'replace',
'effect' => 'fade'
)
);
// Create an "Add another" button for the additions.
$field_name = $element['#parents'][0];
$element['additions']['additions_addmore'] = array(
'#type' => 'button',
'#value' => t('Add more additions'),
'#ahah' => array(
'event' => 'click',
'path' => 'date_repeat_get_exception_form_ajax/additions/' . $field_name,
'wrapper' => 'date-repeat-additions',
'method' => 'replace',
'effect' => 'fade'
)
);
return $element;
}
/**
* Ajax callback to get the exceptions form. This is needed to
* implement the "Add another" button for the date repeat exceptions.
*
* @param $type - 'exceptions' or 'additions'.
* @param $field_name - The name of the date field.
*/
function date_repeat_get_exception_form_ajax($type, $field_name) {
// Get the cached form.
$form_state = array('storage' => NULL, 'submitted' => FALSE);
if (!($form = form_get_cache($_POST['form_build_id'], $form_state))) {
drupal_json(array('status' => FALSE, 'data' => ''));
exit();
}
// Set the form state values.
$form_state = array_merge($form_state, array('values' => $_POST));
// Set the new form rrule value.
$form[$field_name]['rrule']['#value'] = $form_state['values'][$field_name]['rrule'];
// Cache the new form state.
form_set_cache($_POST['form_build_id'], $form, $form_state);
// Rebuild the form.
$form_state = array();
$form['#post'] = array();
$form = form_builder($form['form_id']['#value'] , $form, $form_state);
// Force a rebuild of the Drupal.settings javascript object.
// - Borrowed from content.node_form.inc, content_add_more_js function
$javascript = drupal_add_js(NULL, NULL);
$output_js = isset($javascript['setting']) ? '<script type="text/javascript">jQuery.extend(Drupal.settings, '. drupal_to_js(call_user_func_array('array_merge_recursive', $javascript['setting'])) .');</script>' : '';
// Create our output.
$output = drupal_render($form[$field_name]['rrule'][$type]) . $output_js;
// Set the new exceptions form.
drupal_json(array('status' => TRUE, 'data' => $output));
exit();
}
/**
* Regroup values back into a consistant array, no matter what state it is in.
*/
function date_repeat_merge($form_values, $element) {
if (empty($form_values) || !is_array($form_values)) {
return $form_values;
}
if (array_key_exists('advanced', $form_values) || array_key_exists('exceptions', $form_values) || array_key_exists('additions', $form_values)) {
if (!array_key_exists('advanced', $form_values)) $form_values['advanced'] = array();
if (!array_key_exists('exceptions', $form_values)) $form_values['exceptions'] = array();
if (!array_key_exists('additions', $form_values)) $form_values['additions'] = array();
$form_values = array_merge($form_values, (array) $form_values['advanced'], (array) $form_values['exceptions'], (array) $form_values['additions']);
unset($form_values['advanced']);
unset($form_values['exceptions']);
unset($form_values['additions']);
}
if (array_key_exists('BYDAY', $form_values)) unset($form_values['BYDAY']['']);
if (array_key_exists('BYMONTH', $form_values)) unset($form_values['BYMONTH']['']);
if (array_key_exists('BYMONTHDAY', $form_values)) unset($form_values['BYMONTHDAY']['']);
if (array_key_exists('UNTIL', $form_values) && is_array($form_values['UNTIL']['datetime'])) {
$function = $element['#date_repeat_widget'] .'_input_value';
$until_element = $element;
$until_element['#value'] = $form_values['UNTIL']['datetime'];
$until_element['#date_format'] = date_limit_format($element['#date_format'], array('year', 'month', 'day'));
$form_values['UNTIL']['datetime'] = $function($until_element, 0, 10);
$form_values['UNTIL']['datetime'] = substr($form_values['UNTIL']['datetime'], 0, 10);
$form_values['UNTIL']['granularity'] = serialize(drupal_map_assoc(array('year', 'month', 'day', 'hour')));
$form_values['UNTIL']['all_day'] = TRUE;
}
if (array_key_exists('EXDATE', $form_values) && is_array($form_values['EXDATE'])) {
$function = $element['#date_repeat_widget'] .'_input_value';
$exdate_element = $element;
foreach ($form_values['EXDATE'] as $delta => $value) {
if (is_array($value['datetime'])) {
$exdate_element['#value'] = $form_values['EXDATE'][$delta]['datetime'];
$exdate_element['#date_format'] = date_limit_format($element['#date_format'], array('year', 'month', 'day'));
$form_values['EXDATE'][$delta]['datetime'] = $function($exdate_element);
}
}
}
if (array_key_exists('RDATE', $form_values) && is_array($form_values['RDATE'])) {
$function = $element['#date_repeat_widget'] .'_input_value';
$rdate_element = $element;
foreach ($form_values['RDATE'] as $delta => $value) {
if (is_array($value['datetime'])) {
$rdate_element['#value'] = $form_values['RDATE'][$delta]['datetime'];
$rdate_element['#date_format'] = date_limit_format($element['#date_format'], array('year', 'month', 'day'));
$form_values['RDATE'][$delta]['datetime'] = $function($rdate_element);
}
}
}
return $form_values;
}
/**
* Build a RRULE out of the form values.
*/
function date_repeat_rrule_validate($element, &$form_state) {
require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
$form_values = $form_state['values'];
$field_name = $element['#parents'][0];
$item = $form_values[$field_name]['rrule'];
$item = date_repeat_merge($item, $element);
if (!empty($item['UNTIL']['datetime'])) {
$date = date_make_date($item['UNTIL']['datetime'], $item['UNTIL']['tz']);
date_time_set($date, 23, 59, 59);
date_timezone_set($date, timezone_open('UTC'));
$item['UNTIL']['datetime'] = date_format($date, DATE_FORMAT_DATETIME);
$item['UNTIL']['tz'] = 'UTC';
}
$rrule = date_api_ical_build_rrule($item);
form_set_value($element, $rrule, $form_state);
}
/**
* Theme the exception list as a table so the buttons line up
*/
function theme_date_repeat_current_exceptions($rows = array()) {
$rows_info = array();
foreach ($rows as $key => $value) {
if (drupal_substr($key, 0, 1) != '#') {
$rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
}
}
return theme('table', array(t('Delete'), t('Current exceptions')), $rows_info);
}
/**
* Theme the exception list as a table so the buttons line up
*/
function theme_date_repeat_current_additions($rows = array()) {
$rows_info = array();
foreach ($rows as $key => $value) {
if (drupal_substr($key, 0, 1) != '#') {
$rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
}
}
return theme('table', array(t('Delete'), t('Current additions')), $rows_info);
}
/**
* Themes the date repeat element.
*/
function theme_date_repeat($element) {
return theme('form_element', $element, '<div class="container-inline">'. drupal_render($element) . '</div>');
}