From da3041379a60483da243a29b343562806c50e184 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Mon, 16 Sep 2013 17:30:59 +0800 Subject: [PATCH] MDL-41792 core_calendar: refactored the calendar to allow the use of multiple calendar types --- .../calendar_month/block_calendar_month.php | 14 +- calendar/classes/type_base.php | 86 ++- calendar/classes/type_factory.php | 3 +- calendar/delete.php | 3 +- calendar/event.php | 49 +- calendar/export.php | 57 +- calendar/export_execute.php | 54 +- calendar/lib.php | 522 +++++++++--------- calendar/preferences.php | 2 +- calendar/renderer.php | 200 +++---- calendar/type/gregorian/classes/structure.php | 172 +++++- calendar/type/gregorian/version.php | 4 +- calendar/view.php | 43 +- lib/moodlelib.php | 25 +- 14 files changed, 759 insertions(+), 475 deletions(-) diff --git a/blocks/calendar_month/block_calendar_month.php b/blocks/calendar_month/block_calendar_month.php index 01adcaf9864..41cd98e56b5 100644 --- a/blocks/calendar_month/block_calendar_month.php +++ b/blocks/calendar_month/block_calendar_month.php @@ -49,6 +49,7 @@ class block_calendar_month extends block_base { $calm = optional_param('cal_m', 0, PARAM_INT); $caly = optional_param('cal_y', 0, PARAM_INT); + $time = optional_param('time', 0, PARAM_INT); require_once($CFG->dirroot.'/calendar/lib.php'); @@ -56,6 +57,15 @@ class block_calendar_month extends block_base { return $this->content; } + // If a day, month and year were passed then convert it to a timestamp. If these were passed then we can assume + // the day, month and year are passed as Gregorian, as no where in core should we be passing these values rather + // than the time. This is done for BC. + if (!empty($calm) && (!empty($caly))) { + $time = make_timestamp($caly, $calm, 1); + } else if (empty($time)) { + $time = time(); + } + $this->content = new stdClass; $this->content->text = ''; $this->content->footer = ''; @@ -78,11 +88,11 @@ class block_calendar_month extends block_base { list($courses, $group, $user) = calendar_set_filters($filtercourse); if ($issite) { // For the front page. - $this->content->text .= calendar_get_mini($courses, $group, $user, $calm, $caly, 'frontpage', $courseid); + $this->content->text .= calendar_get_mini($courses, $group, $user, false, false, 'frontpage', $courseid, $time); // No filters for now. } else { // For any other course. - $this->content->text .= calendar_get_mini($courses, $group, $user, $calm, $caly, 'course', $courseid); + $this->content->text .= calendar_get_mini($courses, $group, $user, false, false, 'course', $courseid, $time); $this->content->text .= '

'.get_string('eventskey', 'calendar').'

'; $this->content->text .= '
'.calendar_filter_controls($this->page->url).'
'; } diff --git a/calendar/classes/type_base.php b/calendar/classes/type_base.php index 6458220d80f..b470ffcc4ab 100644 --- a/calendar/classes/type_base.php +++ b/calendar/classes/type_base.php @@ -27,6 +27,16 @@ namespace core_calendar; */ abstract class type_base { + /** + * Returns the name of the calendar. + * + * This is the non-translated name, usually just + * the name of the calendar folder. + * + * @return string the calendar name + */ + public abstract function get_name(); + /** * Returns a list of all the possible days for all months. * @@ -62,10 +72,76 @@ abstract class type_base { */ public abstract function get_max_year(); + /** + * Returns the number of days in a week. + * + * @return int the number of days + */ + public abstract function get_num_weekdays(); + + /** + * Returns an indexed list of all the names of the weekdays. + * + * The list starts with the index 0. Each index, representing a + * day, must be an array that contains the indexes 'shortname' + * and 'fullname'. + * + * @return array array of days + */ + public abstract function get_weekdays(); + + /** + * Returns the index of the starting week day. + * + * This may vary, for example in the Gregorian calendar, some may consider Monday + * as the start of the week, where as others may consider Sunday the start. + * + * @return int + */ + public abstract function get_starting_weekday(); + + /** + * Returns the index of the weekday for a specific calendar date. + * + * @param int $year + * @param int $month + * @param int $day + * @return int + */ + public abstract function get_weekday($year, $month, $day); + + /** + * Returns the number of days in a given month. + * + * + * @param int $year + * @param int $month + * @return int the number of days + */ + public abstract function get_num_days_in_month($year, $month); + + /** + * Get the previous month. + * + * @param int $year + * @param int $month + * @return array previous month and year + */ + public abstract function get_prev_month($year, $month); + + /** + * Get the next month. + * + * @param int $year + * @param int $month + * @return array the following month and year + */ + public abstract function get_next_month($year, $month); + /** * Returns a formatted string that represents a date in user time. * - * @param int $date the timestamp in UTC, as obtained from the database + * @param int $time the timestamp in UTC, as obtained from the database * @param string $format strftime format * @param int|float|string $timezone the timezone to use * {@link http://docs.moodle.org/dev/Time_API#Timezone} @@ -75,7 +151,7 @@ abstract class type_base { * if false then the leading zero is maintained * @return string the formatted date/time */ - public abstract function timestamp_to_date_string($date, $format, $timezone, $fixday, $fixhour); + public abstract function timestamp_to_date_string($time, $format, $timezone, $fixday, $fixhour); /** * Given a $time timestamp in GMT (seconds since epoch), returns an array that represents @@ -86,7 +162,7 @@ abstract class type_base { * {@link http://docs.moodle.org/dev/Time_API#Timezone} * @return array an array that represents the date in user time */ - public abstract function timestamp_to_date_array($time, $timezone); + public abstract function timestamp_to_date_array($time, $timezone = 99); /** * Provided with a day, month, year, hour and minute in the specific @@ -97,7 +173,7 @@ abstract class type_base { * @param int $day * @param int $hour * @param int $minute - * @return array the converted day, month and year. + * @return array the converted date */ public abstract function convert_to_gregorian($year, $month, $day, $hour = 0, $minute = 0); @@ -110,7 +186,7 @@ abstract class type_base { * @param int $day * @param int $hour * @param int $minute - * @return array the converted day, month and year. + * @return array the converted date */ public abstract function convert_from_gregorian($year, $month, $day, $hour = 0, $minute = 0); } diff --git a/calendar/classes/type_factory.php b/calendar/classes/type_factory.php index 535dd2bbb02..8a47a84433a 100644 --- a/calendar/classes/type_factory.php +++ b/calendar/classes/type_factory.php @@ -74,7 +74,8 @@ class type_factory { public static function get_calendar_type() { global $CFG, $USER, $SESSION, $COURSE; - if (!empty($COURSE->id) and $COURSE->id != SITEID and !empty($COURSE->calendartype)) { // Course calendartype can override all other settings for this page. + // Course calendartype can override all other settings for this page. + if (!empty($COURSE->id) and $COURSE->id != SITEID and !empty($COURSE->calendartype)) { $return = $COURSE->calendartype; } else if (!empty($SESSION->calendartype)) { // Session calendartype can override other settings. $return = $SESSION->calendartype; diff --git a/calendar/delete.php b/calendar/delete.php index 4f72df71f05..4074b1e6beb 100644 --- a/calendar/delete.php +++ b/calendar/delete.php @@ -69,8 +69,7 @@ $event->count_repeats(); // Is used several times, and sometimes with modification if required $viewcalendarurl = new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming')); -$viewcalendarurl->param('cal_y', userdate($event->timestart, '%Y')); -$viewcalendarurl->param('cal_m', userdate($event->timestart, '%m')); +$viewcalendarurl->param('time', $event->timestart, '%Y'); // If confirm is set (PARAM_BOOL) then we have confirmation of initention to delete if ($confirm) { diff --git a/calendar/event.php b/calendar/event.php index 027527bf9dc..bf1c6c249b3 100644 --- a/calendar/event.php +++ b/calendar/event.php @@ -57,26 +57,34 @@ $action = optional_param('action', 'new', PARAM_ALPHA); $eventid = optional_param('id', 0, PARAM_INT); $courseid = optional_param('courseid', SITEID, PARAM_INT); $courseid = optional_param('course', $courseid, PARAM_INT); -$cal_y = optional_param('cal_y', 0, PARAM_INT); -$cal_m = optional_param('cal_m', 0, PARAM_INT); -$cal_d = optional_param('cal_d', 0, PARAM_INT); +$day = optional_param('cal_d', 0, PARAM_INT); +$month = optional_param('cal_m', 0, PARAM_INT); +$year = optional_param('cal_y', 0, PARAM_INT); +$time = optional_param('time', 0, PARAM_INT); + +// If a day, month and year were passed then convert it to a timestamp. If these were passed +// then we can assume the day, month and year are passed as Gregorian, as no where in core +// should we be passing these values rather than the time. This is done for BC. +if (!empty($day) && !empty($month) && !empty($year)) { + if (checkdate($month, $day, $year)) { + $time = make_timestamp($year, $month, $day); + } else { + $time = time(); + } +} else if (empty($time)) { + $time = time(); +} $url = new moodle_url('/calendar/event.php', array('action' => $action)); + if ($eventid != 0) { $url->param('id', $eventid); } + if ($courseid != SITEID) { $url->param('course', $courseid); } -if ($cal_y !== 0) { - $url->param('cal_y', $cal_y); -} -if ($cal_m !== 0) { - $url->param('cal_m', $cal_m); -} -if ($cal_d !== 0) { - $url->param('cal_d', $cal_d); -} + $PAGE->set_url($url); $PAGE->set_pagelayout('standard'); @@ -99,7 +107,7 @@ if ($action === 'delete' && $eventid > 0) { redirect($deleteurl); } -$calendar = new calendar_information($cal_d, $cal_m, $cal_y); +$calendar = new calendar_information(0, 0, 0, $time); $calendar->prepare_for_view($course, $courses); $formoptions = new stdClass; @@ -133,16 +141,7 @@ if ($eventid !== 0) { unset($formoptions->eventtypes->groups); } } - if($cal_y && $cal_m && $cal_d && checkdate($cal_m, $cal_d, $cal_y)) { - $event->timestart = make_timestamp($cal_y, $cal_m, $cal_d, 0, 0, 0); - } else if($cal_y && $cal_m && checkdate($cal_m, 1, $cal_y)) { - $now = usergetdate(time()); - if($cal_y == $now['year'] && $cal_m == $now['mon']) { - $event->timestart = make_timestamp($cal_y, $cal_m, $now['mday'], 0, 0, 0); - } else { - $event->timestart = make_timestamp($cal_y, $cal_m, 1, 0, 0, 0); - } - } + $event->timestart = $time; $event = new calendar_event($event); if (!calendar_add_event_allowed($event)) { print_error('nopermissions'); @@ -168,9 +167,7 @@ if ($data) { $params = array( 'view' => 'day', - 'cal_d' => userdate($event->timestart, '%d'), - 'cal_m' => userdate($event->timestart, '%m'), - 'cal_y' => userdate($event->timestart, '%Y'), + 'time' => $event->timestart, ); $eventurl = new moodle_url('/calendar/view.php', $params); if (!empty($event->courseid) && $event->courseid != SITEID) { diff --git a/calendar/export.php b/calendar/export.php index d6a7981fb07..92c2db337f2 100644 --- a/calendar/export.php +++ b/calendar/export.php @@ -56,11 +56,28 @@ if (empty($CFG->enablecalendarexport)) { $courseid = optional_param('course', SITEID, PARAM_INT); $action = optional_param('action', '', PARAM_ALPHA); -$day = optional_param('cal_d', 0, PARAM_INT); -$mon = optional_param('cal_m', 0, PARAM_INT); -$yr = optional_param('cal_y', 0, PARAM_INT); +$day = optional_param('cal_d', 0, PARAM_INT); +$mon = optional_param('cal_m', 0, PARAM_INT); +$year = optional_param('cal_y', 0, PARAM_INT); +$time = optional_param('time', 0, PARAM_INT); $generateurl = optional_param('generateurl', 0, PARAM_BOOL); +// Get the calendar type we are using. +$calendartype = \core_calendar\type_factory::get_calendar_instance(); + +// If a day, month and year were passed then convert it to a timestamp. If these were passed +// then we can assume the day, month and year are passed as Gregorian, as no where in core +// should we be passing these values rather than the time. This is done for BC. +if (!empty($day) && !empty($mon) && !empty($year)) { + if (checkdate($mon, $day, $year)) { + $time = make_timestamp($year, $mon, $day); + } else { + $time = time(); + } +} else if (empty($time)) { + $time = time(); +} + if ($courseid != SITEID && !empty($courseid)) { $course = $DB->get_record('course', array('id' => $courseid)); $courses = array($course->id => $course); @@ -72,36 +89,29 @@ if ($courseid != SITEID && !empty($courseid)) { } require_course_login($course); -$url = new moodle_url('/calendar/export.php'); +$url = new moodle_url('/calendar/export.php', array('time' => $time)); + if ($action !== '') { $url->param('action', $action); } -if ($day !== 0) { - $url->param('cal_d', $day); -} -if ($mon !== 0) { - $url->param('cal_m', $mon); -} -if ($yr !== 0) { - $url->param('cal_y', $yr); -} + if ($course !== NULL) { $url->param('course', $course->id); } $PAGE->set_url($url); -$calendar = new calendar_information($day, $mon, $yr); +$calendar = new calendar_information(0, 0, 0, $time); $calendar->prepare_for_view($course, $courses); $pagetitle = get_string('export', 'calendar'); -$now = usergetdate(time()); +$now = $calendartype->timestamp_to_date_array($time); // Print title and header if ($issite) { $PAGE->navbar->add($course->shortname, new moodle_url('/course/view.php', array('id'=>$course->id))); } $link = new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming', 'course'=>$calendar->courseid)); -$PAGE->navbar->add(get_string('calendar', 'calendar'), calendar_get_link_href($link, $now['mday'], $now['mon'], $now['year'])); +$PAGE->navbar->add(get_string('calendar', 'calendar'), calendar_get_link_href($link, 0, 0, 0, $time)); $PAGE->navbar->add($pagetitle); $PAGE->set_title($course->shortname.': '.get_string('calendar', 'calendar').': '.$pagetitle); @@ -125,14 +135,17 @@ switch($action) { $weekend = intval($CFG->calendar_weekend); } + // Get the number of days. + $numberofdaysinweek = $calendartype->get_num_weekdays(); + $authtoken = sha1($USER->id . $DB->get_field('user', 'password', array('id'=>$USER->id)). $CFG->calendar_exportsalt); // Let's populate some vars to let "common tasks" be somewhat smart... - // If today it's weekend, give the "next week" option - $allownextweek = $weekend & (1 << $now['wday']); - // If it's the last week of the month, give the "next month" option - $allownextmonth = calendar_days_in_month($now['mon'], $now['year']) - $now['mday'] < 7; - // If today it's weekend but tomorrow it isn't, do NOT give the "this week" option - $allowthisweek = !(($weekend & (1 << $now['wday'])) && !($weekend & (1 << (($now['wday'] + 1) % 7)))); + // If today it's weekend, give the "next week" option. + $allownextweek = $weekend & (1 << $now['wday']); + // If it's the last week of the month, give the "next month" option. + $allownextmonth = calendar_days_in_month($now['mon'], $now['year']) - $now['mday'] < $numberofdaysinweek; + // If today it's weekend but tomorrow it isn't, do NOT give the "this week" option. + $allowthisweek = !(($weekend & (1 << $now['wday'])) && !($weekend & (1 << (($now['wday'] + 1) % $numberofdaysinweek)))); echo $renderer->basic_export_form($allowthisweek, $allownextweek, $allownextmonth, $USER->id, $authtoken); break; } diff --git a/calendar/export_execute.php b/calendar/export_execute.php index 7cd585bdcf0..6e76e331867 100644 --- a/calendar/export_execute.php +++ b/calendar/export_execute.php @@ -31,10 +31,14 @@ if (!$authuserid && !$authusername) { die('Invalid authentication'); } +// Get the calendar type we are using. +$calendartype = \core_calendar\type_factory::get_calendar_instance(); + $what = optional_param('preset_what', 'all', PARAM_ALPHA); $time = optional_param('preset_time', 'weeknow', PARAM_ALPHA); -$now = usergetdate(time()); +$now = $calendartype->timestamp_to_date_array(time()); + // Let's see if we have sufficient and correct data $allowed_what = array('all', 'courses'); $allowed_time = array('weeknow', 'weeknext', 'monthnow', 'monthnext', 'recentupcoming', 'custom'); @@ -74,20 +78,23 @@ if(!empty($what) && !empty($time)) { $groups = false; } + // Store the number of days in the week. + $numberofdaysinweek = $calendartype->get_num_weekdays(); + switch($time) { case 'weeknow': - $startweekday = get_user_preferences('calendar_startwday', calendar_get_starting_weekday()); - $startmonthday = find_day_in_month($now['mday'] - 6, $startweekday, $now['mon'], $now['year']); - $startmonth = $now['mon']; - $startyear = $now['year']; + $startweekday = calendar_get_starting_weekday(); + $startmonthday = find_day_in_month($now['mday'] - ($numberofdaysinweek - 1), $startweekday, $now['mon'], $now['year']); + $startmonth = $now['mon']; + $startyear = $now['year']; if($startmonthday > calendar_days_in_month($startmonth, $startyear)) { list($startmonth, $startyear) = calendar_add_month($startmonth, $startyear); $startmonthday = find_day_in_month(1, $startweekday, $startmonth, $startyear); } $timestart = make_timestamp($startyear, $startmonth, $startmonthday); - $endmonthday = $startmonthday + 7; - $endmonth = $startmonth; - $endyear = $startyear; + $endmonthday = $startmonthday + $numberofdaysinweek; + $endmonth = $startmonth; + $endyear = $startyear; if($endmonthday > calendar_days_in_month($endmonth, $endyear)) { list($endmonth, $endyear) = calendar_add_month($endmonth, $endyear); $endmonthday = find_day_in_month(1, $startweekday, $endmonth, $endyear); @@ -95,18 +102,18 @@ if(!empty($what) && !empty($time)) { $timeend = make_timestamp($endyear, $endmonth, $endmonthday) - 1; break; case 'weeknext': - $startweekday = get_user_preferences('calendar_startwday', calendar_get_starting_weekday()); + $startweekday = calendar_get_starting_weekday(); $startmonthday = find_day_in_month($now['mday'] + 1, $startweekday, $now['mon'], $now['year']); - $startmonth = $now['mon']; - $startyear = $now['year']; + $startmonth = $now['mon']; + $startyear = $now['year']; if($startmonthday > calendar_days_in_month($startmonth, $startyear)) { list($startmonth, $startyear) = calendar_add_month($startmonth, $startyear); $startmonthday = find_day_in_month(1, $startweekday, $startmonth, $startyear); } $timestart = make_timestamp($startyear, $startmonth, $startmonthday); - $endmonthday = $startmonthday + 7; - $endmonth = $startmonth; - $endyear = $startyear; + $endmonthday = $startmonthday + $numberofdaysinweek; + $endmonth = $startmonth; + $endyear = $startyear; if($endmonthday > calendar_days_in_month($endmonth, $endyear)) { list($endmonth, $endyear) = calendar_add_month($endmonth, $endyear); $endmonthday = find_day_in_month(1, $startweekday, $endmonth, $endyear); @@ -114,13 +121,24 @@ if(!empty($what) && !empty($time)) { $timeend = make_timestamp($endyear, $endmonth, $endmonthday) - 1; break; case 'monthnow': - $timestart = make_timestamp($now['year'], $now['mon'], 1); - $timeend = make_timestamp($now['year'], $now['mon'], calendar_days_in_month($now['mon'], $now['year']), 23, 59, 59); + // Convert to gregorian. + $gregoriandate = $calendartype->convert_to_gregorian($now['year'], $now['mon'], 1); + + $timestart = make_timestamp($gregoriandate['year'], $gregoriandate['month'], $gregoriandate['day']); + $timeend = make_timestamp($gregoriandate['year'], $gregoriandate['month'], + calendar_days_in_month($now['mon'], $now['year']), 23, 59, 59); break; case 'monthnext': + // Get the next month for this calendar. list($nextmonth, $nextyear) = calendar_add_month($now['mon'], $now['year']); - $timestart = make_timestamp($nextyear, $nextmonth, 1); - $timeend = make_timestamp($nextyear, $nextmonth, calendar_days_in_month($nextmonth, $nextyear), 23, 59, 59); + + // Convert to gregorian. + $gregoriandate = $calendartype->convert_to_gregorian($nextyear, $nextmonth, 1); + + // Create the timestamps. + $timestart = make_timestamp($gregoriandate['year'], $gregoriandate['month'], $gregoriandate['day']); + $timeend = make_timestamp($gregoriandate['year'], $gregoriandate['month'], + calendar_days_in_month($nextmonth, $nextyear), 23, 59, 59); break; case 'recentupcoming': //Events in the last 5 or next 60 days diff --git a/calendar/lib.php b/calendar/lib.php index ede82803316..a805f33b279 100644 --- a/calendar/lib.php +++ b/calendar/lib.php @@ -126,7 +126,8 @@ define('CALENDAR_SUBSCRIPTION_REMOVE', 2); * @return array array of days */ function calendar_get_days() { - return array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_weekdays(); } /** @@ -158,19 +159,8 @@ function calendar_get_subscription($id) { * @return int */ function calendar_get_starting_weekday() { - global $CFG; - - if (isset($CFG->calendar_startwday)) { - $firstday = $CFG->calendar_startwday; - } else { - $firstday = get_string('firstdayofweek', 'langconfig'); - } - - if(!is_numeric($firstday)) { - return CALENDAR_DEFAULT_STARTING_WEEKDAY; - } else { - return intval($firstday) % 7; - } + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_starting_weekday(); } /** @@ -179,83 +169,96 @@ function calendar_get_starting_weekday() { * @param array $courses list of course to list events from * @param array $groups list of group * @param array $users user's info - * @param int $cal_month calendar month in numeric, default is set to false - * @param int $cal_year calendar month in numeric, default is set to false - * @param string $placement the place/page the calendar is set to appear - passed on the the controls function - * @param int $courseid id of the course the calendar is displayed on - passed on the the controls function + * @param int|bool $calmonth calendar month in numeric, default is set to false + * @param int|bool $calyear calendar month in numeric, default is set to false + * @param string|bool $placement the place/page the calendar is set to appear - passed on the the controls function + * @param int|bool $courseid id of the course the calendar is displayed on - passed on the the controls function + * @param int $time the unixtimestamp representing the date we want to view, this is used instead of $calmonth + * and $calyear to support multiple calendars * @return string $content return html table for mini calendar */ -function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_year = false, $placement = false, $courseid = false ) { - global $CFG, $USER, $OUTPUT; +function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyear = false, $placement = false, + $courseid = false, $time = 0) { + global $CFG, $OUTPUT; + + // Get the calendar type we are using. + $calendartype = \core_calendar\type_factory::get_calendar_instance(); $display = new stdClass; - $display->minwday = get_user_preferences('calendar_startwday', calendar_get_starting_weekday()); - $display->maxwday = $display->minwday + 6; + + // Assume we are not displaying this month for now. + $display->thismonth = false; $content = ''; - if(!empty($cal_month) && !empty($cal_year)) { - $thisdate = usergetdate(time()); // Date and time the user sees at his location - if($cal_month == $thisdate['mon'] && $cal_year == $thisdate['year']) { - // Navigated to this month - $date = $thisdate; - $display->thismonth = true; + // Do this check for backwards compatibility. The core should be passing a timestamp rather than month and year. + // If a month and year are passed they will be in Gregorian. + if (!empty($calmonth) && !empty($calyear)) { + // Ensure it is a valid date, else we will just set it to the current timestamp. + if (checkdate($calmonth, 1, $calyear)) { + $time = make_timestamp($calyear, $calmonth, 1); } else { - // Navigated to other month, let's do a nice trick and save us a lot of work... - if(!checkdate($cal_month, 1, $cal_year)) { - $date = array('mday' => 1, 'mon' => $thisdate['mon'], 'year' => $thisdate['year']); - $display->thismonth = true; - } else { - $date = array('mday' => 1, 'mon' => $cal_month, 'year' => $cal_year); - $display->thismonth = false; - } + $time = time(); + } + $date = usergetdate($time); + if ($calmonth == $date['mon'] && $calyear == $date['year']) { + $display->thismonth = true; + } + // We can overwrite date now with the date used by the calendar type, if it is not Gregorian, otherwise + // there is no need as it is already in Gregorian. + if ($calendartype->get_name() != 'gregorian') { + $date = $calendartype->timestamp_to_date_array($time); + } + } else if (!empty($time)) { + // Get the specified date in the calendar type being used. + $date = $calendartype->timestamp_to_date_array($time); + $thisdate = $calendartype->timestamp_to_date_array(time()); + if ($date['month'] == $thisdate['month'] && $date['year'] == $thisdate['year']) { + $display->thismonth = true; + // If we are the current month we want to set the date to the current date, not the start of the month. + $date = $thisdate; } } else { - $date = usergetdate(time()); // Date and time the user sees at his location + // Get the current date in the calendar type being used. + $time = time(); + $date = $calendartype->timestamp_to_date_array($time); $display->thismonth = true; } - // Fill in the variables we 're going to use, nice and tidy - list($d, $m, $y) = array($date['mday'], $date['mon'], $date['year']); // This is what we want to display + list($d, $m, $y) = array($date['mday'], $date['mon'], $date['year']); // This is what we want to display. + + // Get Gregorian date. + $gregoriandate = $calendartype->convert_to_gregorian($date['year'], $date['mon'], 1); + + // Store the gregorian year and month to be used later. + list($gy, $gm, $gd, $gh, $gmin) = array($gregoriandate['year'], $gregoriandate['month'], $gregoriandate['day'], + $gregoriandate['hour'], $gregoriandate['minute']); + + // Get the max number of days in this month for this calendar type. $display->maxdays = calendar_days_in_month($m, $y); - - if (get_user_timezone_offset() < 99) { - // We 'll keep these values as GMT here, and offset them when the time comes to query the db - $display->tstart = gmmktime(0, 0, 0, $m, 1, $y); // This is GMT - $display->tend = gmmktime(23, 59, 59, $m, $display->maxdays, $y); // GMT - } else { - // no timezone info specified - $display->tstart = mktime(0, 0, 0, $m, 1, $y); - $display->tend = mktime(23, 59, 59, $m, $display->maxdays, $y); - } - + // Get the starting week day for this month. $startwday = dayofweek(1, $m, $y); + // Get the days in a week. + $daynames = calendar_get_days(); + // Store the number of days in a week. + $numberofdaysinweek = $calendartype->get_num_weekdays(); + + // Set the min and max weekday. + $display->minwday = calendar_get_starting_weekday(); + $display->maxwday = $display->minwday + ($numberofdaysinweek - 1); + + // These are used for DB queries, so we want unixtime, so we need to use Gregorian dates. + $display->tstart = make_timestamp($gy, $gm, $gd, $gh, $gmin, 0); + $display->tend = make_timestamp($gy, $gm, $display->maxdays, 23, 59, 59); // Align the starting weekday to fall in our display range // This is simple, not foolproof. - if($startwday < $display->minwday) { - $startwday += 7; + if ($startwday < $display->minwday) { + $startwday += $numberofdaysinweek; } - // TODO: THIS IS TEMPORARY CODE! - // [pj] I was just reading through this and realized that I when writing this code I was probably - // asking for trouble, as all these time manipulations seem to be unnecessary and a simple - // make_timestamp would accomplish the same thing. So here goes a test: - //$test_start = make_timestamp($y, $m, 1); - //$test_end = make_timestamp($y, $m, $display->maxdays, 23, 59, 59); - //if($test_start != usertime($display->tstart) - dst_offset_on($display->tstart)) { - //notify('Failed assertion in calendar/lib.php line 126; display->tstart = '.$display->tstart.', dst_offset = '.dst_offset_on($display->tstart).', usertime = '.usertime($display->tstart).', make_t = '.$test_start); - //} - //if($test_end != usertime($display->tend) - dst_offset_on($display->tend)) { - //notify('Failed assertion in calendar/lib.php line 130; display->tend = '.$display->tend.', dst_offset = '.dst_offset_on($display->tend).', usertime = '.usertime($display->tend).', make_t = '.$test_end); - //} - - // Get the events matching our criteria. Don't forget to offset the timestamps for the user's TZ! - $events = calendar_get_events( - usertime($display->tstart) - dst_offset_on($display->tstart), - usertime($display->tend) - dst_offset_on($display->tend), - $users, $groups, $courses); + $events = calendar_get_events($display->tstart, $display->tend, $users, $groups, $courses); // Set event course class for course events if (!empty($events)) { @@ -273,7 +276,6 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y // possibly removing SITEID from $courses, there is only one course left, then clicking on a day in the month // will also set the $SESSION->cal_courses_shown variable to that one course. Otherwise, we 'd need to add extra // arguments to this function. - $hrefparams = array(); if(!empty($courses)) { $courses = array_diff($courses, array(SITEID)); @@ -283,27 +285,21 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y } // We want to have easy access by day, since the display is on a per-day basis. - // Arguments passed by reference. - //calendar_events_by_day($events, $display->tstart, $eventsbyday, $durationbyday, $typesbyday); calendar_events_by_day($events, $m, $y, $eventsbyday, $durationbyday, $typesbyday, $courses); - //Accessibility: added summary and elements. - $days_title = calendar_get_days(); - - $summary = get_string('calendarheading', 'calendar', userdate(make_timestamp($y, $m), get_string('strftimemonthyear'))); - $content .= ''; // Begin table - if (($placement !== false) && ($courseid !== false)) { - $content .= ''; + // Accessibility: added summary and elements. + $summary = get_string('calendarheading', 'calendar', userdate($display->tstart, get_string('strftimemonthyear'))); + $content .= '
'. calendar_top_controls($placement, array('id' => $courseid, 'm' => $m, 'y' => $y)) .'
'; // Begin table. + if (($placement !== false) && ($courseid !== false)) { + $content .= ''; } $content .= ''; // Header row: day names - // Print out the names of the weekdays - $days = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'); - for($i = $display->minwday; $i <= $display->maxwday; ++$i) { - // This uses the % operator to get the correct weekday no matter what shift we have - // applied to the $display->minwday : $display->maxwday range from the default 0 : 6 - $content .= '\n"; + // Print out the names of the weekdays. + for ($i = $display->minwday; $i <= $display->maxwday; ++$i) { + $pos = $i % $numberofdaysinweek; + $content .= '\n"; } $content .= ''; // End of day names; prepare for day numbers @@ -322,16 +318,17 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y } // Now display all the calendar + $daytime = $display->tstart - DAYSECS; for($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) { + $daytime += DAYSECS; if($dayweek > $display->maxwday) { // We need to change week (table row) $content .= ''; $dayweek = $display->minwday; } - // Reset vars - $cell = ''; - if ($weekend & (1 << ($dayweek % 7))) { + // Reset vars. + if ($weekend & (1 << ($dayweek % $numberofdaysinweek))) { // Weekend. This is true no matter what the exact range is. $class = 'weekend day'; } else { @@ -341,9 +338,10 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y // Special visual fx if an event is defined if(isset($eventsbyday[$day])) { + $class .= ' hasevent'; $hrefparams['view'] = 'day'; - $dayhref = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', $hrefparams), $day, $m, $y); + $dayhref = calendar_get_link_href(new moodle_url(CALENDAR_URL . 'view.php', $hrefparams), 0, 0, 0, $daytime); $popupcontent = ''; foreach($eventsbyday[$day] as $eventid) { @@ -353,17 +351,17 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y $event = new calendar_event($events[$eventid]); $popupalt = ''; $component = 'moodle'; - if(!empty($event->modulename)) { + if (!empty($event->modulename)) { $popupicon = 'icon'; $popupalt = $event->modulename; $component = $event->modulename; - } else if ($event->courseid == SITEID) { // Site event + } else if ($event->courseid == SITEID) { // Site event. $popupicon = 'i/siteevent'; - } else if ($event->courseid != 0 && $event->courseid != SITEID && $event->groupid == 0) { // Course event + } else if ($event->courseid != 0 && $event->courseid != SITEID && $event->groupid == 0) { // Course event. $popupicon = 'i/courseevent'; - } else if ($event->groupid) { // Group event + } else if ($event->groupid) { // Group event. $popupicon = 'i/groupevent'; - } else if ($event->userid) { // User event + } else { // Must be a user event. $popupicon = 'i/userevent'; } @@ -823,43 +821,59 @@ function calendar_get_events_by_id($eventids) { * @return string $content return available control for the calender in html */ function calendar_top_controls($type, $data) { - global $CFG, $PAGE; - $content = ''; - if(!isset($data['d'])) { - $data['d'] = 1; - } + global $PAGE; - // Ensure course id passed if relevant - // Required due to changes in view/lib.php mainly (calendar_session_vars()) + // Get the calendar type we are using. + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + + $content = ''; + + // Ensure course id passed if relevant. $courseid = ''; if (!empty($data['id'])) { $courseid = '&course='.$data['id']; } - if(!checkdate($data['m'], $data['d'], $data['y'])) { + // If we are passing a month and year then we need to convert this to a timestamp to + // support multiple calendars. No where in core should these be passed, this logic + // here is for third party plugins that may use this function. + if (!empty($data['m']) && !empty($date['y'])) { + if (!isset($data['d'])) { + $data['d'] = 1; + } + if (!checkdate($data['m'], $data['d'], $data['y'])) { + $time = time(); + } else { + $time = make_timestamp($data['y'], $data['m'], $data['d']); + } + } else if (!empty($data['time'])) { + $time = $data['time']; + } else { $time = time(); } - else { - $time = make_timestamp($data['y'], $data['m'], $data['d']); - } - $date = usergetdate($time); - $data['m'] = $date['mon']; - $data['y'] = $date['year']; + // Get the date for the calendar type. + $date = $calendartype->timestamp_to_date_array($time); + $urlbase = $PAGE->url; - //Accessibility: calendar block controls, replaced
'. calendar_top_controls($placement, array('id' => $courseid, 'time' => $time)) .'
'. - get_string($days[$i % 7], 'calendar') ."'. + $daynames[$pos]['shortname'] ."
with
. - //$nexttext = link_arrow_right(get_string('monthnext', 'access'), $url='', $accesshide=true); - //$prevtext = link_arrow_left(get_string('monthprev', 'access'), $url='', $accesshide=true); + // We need to get the previous and next months in certain cases. + if ($type == 'frontpage' || $type == 'course' || $type == 'month') { + $prevmonth = calendar_sub_month($date['mon'], $date['year']); + $prevmonthtime = $calendartype->convert_to_gregorian($prevmonth[1], $prevmonth[0], $date['mday']); + $prevmonthtime = make_timestamp($prevmonthtime['year'], $prevmonthtime['month'], $prevmonthtime['day']); - switch($type) { + $nextmonth = calendar_add_month($date['mon'], $date['year']); + $nextmonthtime = $calendartype->convert_to_gregorian($nextmonth[1], $nextmonth[0], $date['mday']); + $nextmonthtime = make_timestamp($nextmonthtime['year'], $nextmonthtime['month'], $nextmonthtime['day']); + } + + switch ($type) { case 'frontpage': - list($prevmonth, $prevyear) = calendar_sub_month($data['m'], $data['y']); - list($nextmonth, $nextyear) = calendar_add_month($data['m'], $data['y']); - $nextlink = calendar_get_link_next(get_string('monthnext', 'access'), $urlbase, 0, $nextmonth, $nextyear, true); - $prevlink = calendar_get_link_previous(get_string('monthprev', 'access'), $urlbase, 0, $prevmonth, $prevyear, true); + $prevlink = calendar_get_link_previous(get_string('monthprev', 'access'), $urlbase, false, false, false, true, $prevmonthtime); + $nextlink = calendar_get_link_next(get_string('monthnext', 'access'), $urlbase, false, false, false, true, $nextmonthtime); + $calendarlink = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view' => 'month')), false, false, false, $time); - $calendarlink = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'month')), 1, $data['m'], $data['y']); if (!empty($data['id'])) { $calendarlink->param('course', $data['id']); } @@ -881,12 +895,10 @@ function calendar_top_controls($type, $data) { break; case 'course': - list($prevmonth, $prevyear) = calendar_sub_month($data['m'], $data['y']); - list($nextmonth, $nextyear) = calendar_add_month($data['m'], $data['y']); - $nextlink = calendar_get_link_next(get_string('monthnext', 'access'), $urlbase, 0, $nextmonth, $nextyear, true); - $prevlink = calendar_get_link_previous(get_string('monthprev', 'access'), $urlbase, 0, $prevmonth, $prevyear, true); + $prevlink = calendar_get_link_previous(get_string('monthprev', 'access'), $urlbase, false, false, false, true, $prevmonthtime); + $nextlink = calendar_get_link_next(get_string('monthnext', 'access'), $urlbase, false, false, false, true, $nextmonthtime); + $calendarlink = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view' => 'month')), false, false, false, $time); - $calendarlink = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'month')), 1, $data['m'], $data['y']); if (!empty($data['id'])) { $calendarlink->param('course', $data['id']); } @@ -907,7 +919,7 @@ function calendar_top_controls($type, $data) { $content .= html_writer::end_tag('div'); break; case 'upcoming': - $calendarlink = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming')), 1, $data['m'], $data['y']); + $calendarlink = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view' => 'upcoming')), false, false, false, $time); if (!empty($data['id'])) { $calendarlink->param('course', $data['id']); } @@ -915,7 +927,7 @@ function calendar_top_controls($type, $data) { $content .= html_writer::tag('div', $calendarlink, array('class'=>'centered')); break; case 'display': - $calendarlink = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'month')), 1, $data['m'], $data['y']); + $calendarlink = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view' => 'month')), false, false, false, $time); if (!empty($data['id'])) { $calendarlink->param('course', $data['id']); } @@ -923,12 +935,8 @@ function calendar_top_controls($type, $data) { $content .= html_writer::tag('h3', $calendarlink); break; case 'month': - list($prevmonth, $prevyear) = calendar_sub_month($data['m'], $data['y']); - list($nextmonth, $nextyear) = calendar_add_month($data['m'], $data['y']); - $prevdate = make_timestamp($prevyear, $prevmonth, 1); - $nextdate = make_timestamp($nextyear, $nextmonth, 1); - $prevlink = calendar_get_link_previous(userdate($prevdate, get_string('strftimemonthyear')), 'view.php?view=month'.$courseid.'&', 1, $prevmonth, $prevyear); - $nextlink = calendar_get_link_next(userdate($nextdate, get_string('strftimemonthyear')), 'view.php?view=month'.$courseid.'&', 1, $nextmonth, $nextyear); + $prevlink = calendar_get_link_previous(userdate($prevmonthtime, get_string('strftimemonthyear')), 'view.php?view=month'.$courseid.'&', false, false, false, false, $prevmonthtime); + $nextlink = calendar_get_link_next(userdate($nextmonthtime, get_string('strftimemonthyear')), 'view.php?view=month'.$courseid.'&', false, false, false, false, $nextmonthtime); if (right_to_left()) { $left = $nextlink; @@ -946,13 +954,17 @@ function calendar_top_controls($type, $data) { break; case 'day': $days = calendar_get_days(); - $data['d'] = $date['mday']; // Just for convenience - $prevdate = usergetdate(make_timestamp($data['y'], $data['m'], $data['d'] - 1)); - $nextdate = usergetdate(make_timestamp($data['y'], $data['m'], $data['d'] + 1)); - $prevname = calendar_wday_name($days[$prevdate['wday']]); - $nextname = calendar_wday_name($days[$nextdate['wday']]); - $prevlink = calendar_get_link_previous($prevname, 'view.php?view=day'.$courseid.'&', $prevdate['mday'], $prevdate['mon'], $prevdate['year']); - $nextlink = calendar_get_link_next($nextname, 'view.php?view=day'.$courseid.'&', $nextdate['mday'], $nextdate['mon'], $nextdate['year']); + + $prevtimestamp = $time - DAYSECS; + $nexttimestamp = $time + DAYSECS; + + $prevdate = $calendartype->timestamp_to_date_array($prevtimestamp); + $nextdate = $calendartype->timestamp_to_date_array($nexttimestamp); + + $prevname = $days[$prevdate['wday']]['fullname']; + $nextname = $days[$nextdate['wday']]['fullname']; + $prevlink = calendar_get_link_previous($prevname, 'view.php?view=day'.$courseid.'&', false, false, false, false, $prevtimestamp); + $nextlink = calendar_get_link_next($nextname, 'view.php?view=day'.$courseid.'&', false, false, false, false, $nexttimestamp); if (right_to_left()) { $left = $nextlink; @@ -1133,24 +1145,33 @@ function calendar_time_representation($time) { * @param int $d The number of the day. * @param int $m The number of the month. * @param int $y The number of the year. + * @param int $time the unixtime, used for multiple calendar support. The values $d, + * $m and $y are kept for backwards compatibility. * @return moodle_url|null $linkbase */ -function calendar_get_link_href($linkbase, $d, $m, $y) { +function calendar_get_link_href($linkbase, $d, $m, $y, $time = 0) { if (empty($linkbase)) { return ''; } if (!($linkbase instanceof moodle_url)) { $linkbase = new moodle_url($linkbase); } - if (!empty($d)) { - $linkbase->param('cal_d', $d); - } - if (!empty($m)) { - $linkbase->param('cal_m', $m); - } - if (!empty($y)) { - $linkbase->param('cal_y', $y); + + // If a day, month and year were passed then convert it to a timestamp. If these were passed + // then we can assume the day, month and year are passed as Gregorian, as no where in core + // should we be passing these values rather than the time. + if (!empty($d) && !empty($m) && !empty($y)) { + if (checkdate($m, $d, $y)) { + $time = make_timestamp($y, $m, $d); + } else { + $time = time(); + } + } else if (empty($time)) { + $time = time(); } + + $linkbase->param('time', $time); + return $linkbase; } @@ -1163,10 +1184,12 @@ function calendar_get_link_href($linkbase, $d, $m, $y) { * @param int $m The number of the month. * @param int $y year The number of the year. * @param bool $accesshide Default visible, or hide from all except screenreaders. + * @param int $time the unixtime, used for multiple calendar support. The values $d, + * $m and $y are kept for backwards compatibility. * @return string HTML string. */ -function calendar_get_link_previous($text, $linkbase, $d, $m, $y, $accesshide=false) { - $href = calendar_get_link_href(new moodle_url($linkbase), $d, $m, $y); +function calendar_get_link_previous($text, $linkbase, $d, $m, $y, $accesshide = false, $time = 0) { + $href = calendar_get_link_href(new moodle_url($linkbase), $d, $m, $y, $time); if (empty($href)) { return $text; } @@ -1182,10 +1205,12 @@ function calendar_get_link_previous($text, $linkbase, $d, $m, $y, $accesshide=fa * @param int $m The number of the month. * @param int $y The number of the year. * @param bool $accesshide Default visible, or hide from all except screenreaders. + * @param int $time the unixtime, used for multiple calendar support. The values $d, + * $m and $y are kept for backwards compatibility. * @return string HTML string. */ -function calendar_get_link_next($text, $linkbase, $d, $m, $y, $accesshide=false) { - $href = calendar_get_link_href(new moodle_url($linkbase), $d, $m, $y); +function calendar_get_link_next($text, $linkbase, $d, $m, $y, $accesshide = false, $time = 0) { + $href = calendar_get_link_href(new moodle_url($linkbase), $d, $m, $y, $time); if (empty($href)) { return $text; } @@ -1210,7 +1235,8 @@ function calendar_wday_name($englishname) { * @return int */ function calendar_days_in_month($month, $year) { - return intval(date('t', mktime(0, 0, 0, $month, 1, $year))); + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_num_days_in_month($year, $month); } /** @@ -1239,8 +1265,7 @@ function calendar_get_block_upcoming($events, $linkhref = NULL, $showcourselink $content .= $events[$i]->referer; } else { if(!empty($linkhref)) { - $ed = usergetdate($events[$i]->timestart); - $href = calendar_get_link_href(new moodle_url(CALENDAR_URL.$linkhref), $ed['mday'], $ed['mon'], $ed['year']); + $href = calendar_get_link_href(new moodle_url(CALENDAR_URL . $linkhref), 0, 0, 0, $events[$i]->timestart); $href->set_anchor('event_'.$events[$i]->id); $content .= html_writer::link($href, $events[$i]->name); } @@ -1262,38 +1287,27 @@ function calendar_get_block_upcoming($events, $linkhref = NULL, $showcourselink /** * Get the next following month * - * If the current month is December, it will get the first month of the following year. - * - * * @param int $month the number of the month. * @param int $year the number of the year. * @return array the following month */ function calendar_add_month($month, $year) { - if($month == 12) { - return array(1, $year + 1); - } - else { - return array($month + 1, $year); - } + // Get the calendar type we are using. + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_next_month($year, $month); } /** - * Get the previous month - * - * If the current month is January, it will get the last month of the previous year. + * Get the previous month. * * @param int $month the number of the month. * @param int $year the number of the year. * @return array previous month */ function calendar_sub_month($month, $year) { - if($month == 1) { - return array(12, $year - 1); - } - else { - return array($month - 1, $year); - } + // Get the calendar type we are using. + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_prev_month($year, $month); } /** @@ -1309,6 +1323,9 @@ function calendar_sub_month($month, $year) { * @return void */ function calendar_events_by_day($events, $month, $year, &$eventsbyday, &$durationbyday, &$typesbyday, &$courses) { + // Get the calendar type we are using. + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + $eventsbyday = array(); $typesbyday = array(); $durationbyday = array(); @@ -1317,12 +1334,11 @@ function calendar_events_by_day($events, $month, $year, &$eventsbyday, &$duratio return; } - foreach($events as $event) { - - $startdate = usergetdate($event->timestart); + foreach ($events as $event) { + $startdate = $calendartype->timestamp_to_date_array($event->timestart); // Set end date = start date if no duration if ($event->timeduration) { - $enddate = usergetdate($event->timestart + $event->timeduration - 1); + $enddate = $calendartype->timestamp_to_date_array($event->timestart + $event->timeduration - 1); } else { $enddate = $startdate; } @@ -1637,90 +1653,81 @@ function calendar_preferences_button(stdClass $course) { * @param int $showtime determine the show time GMT timestamp * @return string $eventtime link/string for event time */ -function calendar_format_event_time($event, $now, $linkparams = null, $usecommonwords = true, $showtime=0) { - $startdate = usergetdate($event->timestart); - $enddate = usergetdate($event->timestart + $event->timeduration); - $usermidnightstart = usergetmidnight($event->timestart); - - if($event->timeduration) { - // To avoid doing the math if one IF is enough :) - $usermidnightend = usergetmidnight($event->timestart + $event->timeduration); - } - else { - $usermidnightend = $usermidnightstart; - } +function calendar_format_event_time($event, $now, $linkparams = null, $usecommonwords = true, $showtime = 0) { + $starttime = $event->timestart; + $endtime = $event->timestart + $event->timeduration; if (empty($linkparams) || !is_array($linkparams)) { $linkparams = array(); } + $linkparams['view'] = 'day'; // OK, now to get a meaningful display... - // First of all we have to construct a human-readable date/time representation - - if($event->timeduration) { - // It has a duration - if($usermidnightstart == $usermidnightend || - ($event->timestart == $usermidnightstart) && ($event->timeduration == 86400 || $event->timeduration == 86399) || - ($event->timestart + $event->timeduration <= $usermidnightstart + 86400)) { - // But it's all on the same day - $timestart = calendar_time_representation($event->timestart); - $timeend = calendar_time_representation($event->timestart + $event->timeduration); - $time = $timestart.' » '.$timeend; - - if ($event->timestart == $usermidnightstart && ($event->timeduration == 86400 || $event->timeduration == 86399)) { + // Check if there is a duration for this event. + if ($event->timeduration) { + // Get the midnight of the day the event will start. + $usermidnightstart = usergetmidnight($starttime); + // Get the midnight of the day the event will end. + $usermidnightend = usergetmidnight($endtime); + // Check if we will still be on the same day. + if ($usermidnightstart == $usermidnightend) { + // Check if we are running all day. + if ($event->timeduration == DAYSECS) { $time = get_string('allday', 'calendar'); + } else { // Specify the time we will be running this from. + $datestart = calendar_time_representation($starttime); + $dateend = calendar_time_representation($endtime); + $time = $datestart . ' » ' . $dateend; } - // Set printable representation + // Set printable representation. if (!$showtime) { $day = calendar_day_representation($event->timestart, $now, $usecommonwords); - $url = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', $linkparams), $enddate['mday'], $enddate['mon'], $enddate['year']); - $eventtime = html_writer::link($url, $day).', '.$time; + $url = calendar_get_link_href(new moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $endtime); + $eventtime = html_writer::link($url, $day) . ', ' . $time; } else { $eventtime = $time; } - } else { - // It spans two or more days - $daystart = calendar_day_representation($event->timestart, $now, $usecommonwords).', '; + } else { // It must spans two or more days. + $daystart = calendar_day_representation($event->timestart, $now, $usecommonwords) . ', '; if ($showtime == $usermidnightstart) { $daystart = ''; } $timestart = calendar_time_representation($event->timestart); - $dayend = calendar_day_representation($event->timestart + $event->timeduration, $now, $usecommonwords).', '; + $dayend = calendar_day_representation($event->timestart + $event->timeduration, $now, $usecommonwords) . ', '; if ($showtime == $usermidnightend) { $dayend = ''; } $timeend = calendar_time_representation($event->timestart + $event->timeduration); - // Set printable representation - if ($now >= $usermidnightstart && $now < ($usermidnightstart + 86400)) { - $url = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', $linkparams), $enddate['mday'], $enddate['mon'], $enddate['year']); - $eventtime = $timestart.' » '.html_writer::link($url, $dayend).$timeend; + // Set printable representation. + if ($now >= $usermidnightstart && $now < ($usermidnightstart + DAYSECS)) { + $url = calendar_get_link_href(new moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $endtime); + $eventtime = $timestart . ' » ' . html_writer::link($url, $dayend) . $timeend; } else { - $url = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', $linkparams), $enddate['mday'], $enddate['mon'], $enddate['year']); - $eventtime = html_writer::link($url, $daystart).$timestart.' » '; + $url = calendar_get_link_href(new moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $endtime); + $eventtime = html_writer::link($url, $daystart) . $timestart . ' » '; - $url = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', $linkparams), $startdate['mday'], $startdate['mon'], $startdate['year']); - $eventtime .= html_writer::link($url, $dayend).$timeend; + $url = calendar_get_link_href(new moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $starttime); + $eventtime .= html_writer::link($url, $dayend) . $timeend; } } - } else { + } else { // There is no time duration. $time = calendar_time_representation($event->timestart); - - // Set printable representation + // Set printable representation. if (!$showtime) { $day = calendar_day_representation($event->timestart, $now, $usecommonwords); - $url = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', $linkparams), $startdate['mday'], $startdate['mon'], $startdate['year']); - $eventtime = html_writer::link($url, $day).', '.trim($time); + $url = calendar_get_link_href(new moodle_url(CALENDAR_URL . 'view.php', $linkparams), 0, 0, 0, $starttime); + $eventtime = html_writer::link($url, $day) . ', ' . trim($time); } else { $eventtime = $time; } } - if($event->timestart + $event->timeduration < $now) { - // It has expired - $eventtime = ''.str_replace(' href=', ' class="dimmed" href=', $eventtime).''; + // Check if It has expired. + if ($event->timestart + $event->timeduration < $now) { + $eventtime = '' . str_replace(' href=', ' class="dimmed" href=', $eventtime) . ''; } return $eventtime; @@ -2632,14 +2639,14 @@ class calendar_event { * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class calendar_information { - /** @var int The day */ - public $day; - /** @var int The month */ - public $month; - - /** @var int The year */ - public $year; + /** + * @var int The timestamp + * + * Rather than setting the day, month and year we will set a timestamp which will be able + * to be used by multiple calendars. + */ + public $time; /** @var int A course id */ public $courseid = null; @@ -2659,26 +2666,34 @@ class calendar_information { * @param int $day the number of the day * @param int $month the number of the month * @param int $year the number of the year + * @param int $time the unixtimestamp representing the date we want to view, this is used instead of $calmonth + * and $calyear to support multiple calendars */ - public function __construct($day=0, $month=0, $year=0) { - - $date = usergetdate(time()); - - if (empty($day)) { - $day = $date['mday']; + public function __construct($day = 0, $month = 0, $year = 0, $time = 0) { + // If a day, month and year were passed then convert it to a timestamp. If these were passed + // then we can assume the day, month and year are passed as Gregorian, as no where in core + // should we be passing these values rather than the time. This is done for BC. + if (!empty($day) || !empty($month) || !empty($year)) { + $date = usergetdate(time()); + if (empty($day)) { + $day = $date['mday']; + } + if (empty($month)) { + $month = $date['mon']; + } + if (empty($year)) { + $year = $date['year']; + } + if (checkdate($month, $day, $year)) { + $this->time = make_timestamp($year, $month, $day); + } else { + $this->time = time(); + } + } else if (!empty($time)) { + $this->time = $time; + } else { + $this->time = time(); } - - if (empty($month)) { - $month = $date['mon']; - } - - if (empty($year)) { - $year = $date['year']; - } - - $this->day = $day; - $this->month = $month; - $this->year = $year; } /** @@ -2719,13 +2734,14 @@ class calendar_information { } return true; } + /** * Gets todays timestamp for the calendar * * @return int today timestamp */ public function timestamp_today() { - return make_timestamp($this->year, $this->month, $this->day); + return $this->time; } /** * Gets tomorrows timestamp for the calendar @@ -2733,7 +2749,7 @@ class calendar_information { * @return int tomorrow timestamp */ public function timestamp_tomorrow() { - return make_timestamp($this->year, $this->month, $this->day+1); + return $this->time + DAYSECS; } /** * Adds the pretend blocks for the calendar @@ -2745,7 +2761,7 @@ class calendar_information { public function add_sidecalendar_blocks(core_calendar_renderer $renderer, $showfilters=false, $view=null) { if ($showfilters) { $filters = new block_contents(); - $filters->content = $renderer->fake_block_filters($this->courseid, $this->day, $this->month, $this->year, $view, $this->courses); + $filters->content = $renderer->fake_block_filters($this->courseid, 0, 0, 0, $view, $this->courses); $filters->footer = ''; $filters->title = get_string('eventskey', 'calendar'); $renderer->add_pretend_calendar_block($filters, BLOCK_POS_RIGHT); diff --git a/calendar/preferences.php b/calendar/preferences.php index 165466d6479..aeb502dadd9 100644 --- a/calendar/preferences.php +++ b/calendar/preferences.php @@ -32,7 +32,7 @@ if (isset($CFG->calendar_maxevents)) { $prefs = new stdClass; $prefs->timeformat = get_user_preferences('calendar_timeformat', ''); -$prefs->startwday = get_user_preferences('calendar_startwday', calendar_get_starting_weekday()); +$prefs->startwday = calendar_get_starting_weekday(); $prefs->maxevents = get_user_preferences('calendar_maxevents', $defaultmaxevents); $prefs->lookahead = get_user_preferences('calendar_lookahead', $defaultlookahead); $prefs->persistflt = get_user_preferences('calendar_persistflt', 0); diff --git a/calendar/renderer.php b/calendar/renderer.php index 4fc9a05d76c..efb4725baf9 100644 --- a/calendar/renderer.php +++ b/calendar/renderer.php @@ -166,18 +166,27 @@ class core_calendar_renderer extends plugin_renderer_base { * @return string */ public function fake_block_threemonths(calendar_information $calendar) { + // Get the calendar type we are using. + $calendartype = \core_calendar\type_factory::get_calendar_instance(); - list($prevmon, $prevyr) = calendar_sub_month($calendar->month, $calendar->year); - list($nextmon, $nextyr) = calendar_add_month($calendar->month, $calendar->year); + $date = $calendartype->timestamp_to_date_array($calendar->time); - $content = html_writer::start_tag('div', array('class'=>'minicalendarblock')); - $content .= calendar_get_mini( $calendar->courses, $calendar->groups, $calendar->users, $prevmon, $prevyr, 'display', $calendar->courseid); + $prevmonth = calendar_sub_month($date['mon'], $date['year']); + $prevmonthtime = $calendartype->convert_to_gregorian($prevmonth[1], $prevmonth[0], $date['mday']); + $prevmonthtime = make_timestamp($prevmonthtime['year'], $prevmonthtime['month'], $prevmonthtime['day']); + + $nextmonth = calendar_add_month($date['mon'], $date['year']); + $nextmonthtime = $calendartype->convert_to_gregorian($nextmonth[1], $nextmonth[0], $date['mday']); + $nextmonthtime = make_timestamp($nextmonthtime['year'], $nextmonthtime['month'], $nextmonthtime['day']); + + $content = html_writer::start_tag('div', array('class' => 'minicalendarblock')); + $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users, false, false, 'display', $calendar->courseid, $prevmonthtime); $content .= html_writer::end_tag('div'); - $content .= html_writer::start_tag('div', array('class'=>'minicalendarblock')); - $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users, $calendar->month, $calendar->year, 'display', $calendar->courseid); + $content .= html_writer::start_tag('div', array('class' => 'minicalendarblock')); + $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users, false, false, 'display', $calendar->courseid, $calendar->time); $content .= html_writer::end_tag('div'); - $content .= html_writer::start_tag('div', array('class'=>'minicalendarblock')); - $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users, $nextmon, $nextyr, 'display', $calendar->courseid); + $content .= html_writer::start_tag('div', array('class' => 'minicalendarblock')); + $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users, false, false, 'display', $calendar->courseid, $nextmonthtime); $content .= html_writer::end_tag('div'); return $content; } @@ -199,24 +208,31 @@ class core_calendar_renderer extends plugin_renderer_base { * @param int $day * @param int $month * @param int $year + * @param int $time the unixtime, used for multiple calendar support. The values $day, + * $month and $year are kept for backwards compatibility. * @return string */ - protected function add_event_button($courseid, $day=null, $month=null, $year=null) { + protected function add_event_button($courseid, $day = null, $month = null, $year = null, $time = null) { + // If a day, month and year were passed then convert it to a timestamp. If these were passed + // then we can assume the day, month and year are passed as Gregorian, as no where in core + // should we be passing these values rather than the time. This is done for BC. + if (!empty($day) && !empty($month) && !empty($year)) { + if (checkdate($month, $day, $year)) { + $time = make_timestamp($year, $month, $day); + } else { + $time = time(); + } + } else if (empty($time)) { + $time = time(); + } + $output = html_writer::start_tag('div', array('class'=>'buttons')); - $output .= html_writer::start_tag('form', array('action'=>CALENDAR_URL.'event.php', 'method'=>'get')); + $output .= html_writer::start_tag('form', array('action' => CALENDAR_URL . 'event.php', 'method' => 'get')); $output .= html_writer::start_tag('div'); - $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'action', 'value'=>'new')); - $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'course', 'value'=>$courseid)); - if ($day !== null) { - $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'cal_d', 'value'=>$day)); - } - if ($month !== null) { - $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'cal_m', 'value'=>$month)); - } - if ($year !== null) { - $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'cal_y', 'value'=>$year)); - } - $output .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('newevent', 'calendar'))); + $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name' => 'action', 'value' => 'new')); + $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name' => 'course', 'value' => $courseid)); + $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name' => 'time', 'value' => $time)); + $output .= html_writer::empty_tag('input', array('type'=>'submit', 'value' => get_string('newevent', 'calendar'))); $output .= html_writer::end_tag('div'); $output .= html_writer::end_tag('form'); $output .= html_writer::end_tag('div'); @@ -235,18 +251,17 @@ class core_calendar_renderer extends plugin_renderer_base { $returnurl = $this->page->url; } - $calendar->checkdate(); $events = calendar_get_upcoming($calendar->courses, $calendar->groups, $calendar->users, 1, 100, $calendar->timestamp_today()); $output = html_writer::start_tag('div', array('class'=>'header')); if (calendar_user_can_add_event($calendar->course)) { - $output .= $this->add_event_button($calendar->course->id, $calendar->day, $calendar->month, $calendar->year); + $output .= $this->add_event_button($calendar->course->id, 0, 0, 0, $calendar->time); } //$output .= html_writer::tag('label', get_string('dayview', 'calendar'), array('for'=>'cal_course_flt_jump')); $output .= $this->course_filter_selector($returnurl, get_string('dayview', 'calendar')); $output .= html_writer::end_tag('div'); // Controls - $output .= html_writer::tag('div', calendar_top_controls('day', array('id' => $calendar->courseid, 'd' => $calendar->day, 'm' => $calendar->month, 'y' => $calendar->year)), array('class'=>'controls')); + $output .= html_writer::tag('div', calendar_top_controls('day', array('id' => $calendar->courseid, 'time' => $calendar->time)), array('class'=>'controls')); if (empty($events)) { // There is nothing to display today. @@ -376,6 +391,7 @@ class core_calendar_renderer extends plugin_renderer_base { * Displays a month in detail * * @param calendar_information $calendar + * @param moodle_url $returnurl the url to return to * @return string */ public function show_month_detailed(calendar_information $calendar, moodle_url $returnurl = null) { @@ -385,34 +401,52 @@ class core_calendar_renderer extends plugin_renderer_base { $returnurl = $this->page->url; } - $date = usergetdate(time()); + // Get the calendar type we are using. + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + // Store the display settings. $display = new stdClass; - $display->minwday = get_user_preferences('calendar_startwday', calendar_get_starting_weekday()); - $display->maxwday = $display->minwday + 6; - $display->thismonth = ($date['mon'] == $calendar->month); - $display->maxdays = calendar_days_in_month($calendar->month, $calendar->year); + $display->thismonth = false; - $startwday = 0; - if (get_user_timezone_offset() < 99) { - // We 'll keep these values as GMT here, and offset them when the time comes to query the db - $display->tstart = gmmktime(0, 0, 0, $calendar->month, 1, $calendar->year); // This is GMT - $display->tend = gmmktime(23, 59, 59, $calendar->month, $display->maxdays, $calendar->year); // GMT - $startwday = gmdate('w', $display->tstart); // $display->tstart is already GMT, so don't use date(): messes with server's TZ - } else { - // no timezone info specified - $display->tstart = mktime(0, 0, 0, $calendar->month, 1, $calendar->year); - $display->tend = mktime(23, 59, 59, $calendar->month, $display->maxdays, $calendar->year); - $startwday = date('w', $display->tstart); // $display->tstart not necessarily GMT, so use date() + // Get the specified date in the calendar type being used. + $date = $calendartype->timestamp_to_date_array($calendar->time); + $thisdate = $calendartype->timestamp_to_date_array(time()); + if ($date['mon'] == $thisdate['mon'] && $date['year'] == $thisdate['year']) { + $display->thismonth = true; + $date = $thisdate; + $calendar->time = time(); } + // Get Gregorian date. + $gregoriandate = $calendartype->convert_to_gregorian($date['year'], $date['mon'], 1); + + // Store the gregorian year and month to be used later. + list($gy, $gm, $gd, $gh, $gmin) = array($gregoriandate['year'], $gregoriandate['month'], $gregoriandate['day'], + $gregoriandate['hour'], $gregoriandate['minute']); + + // Get the starting week day for this month. + $startwday = dayofweek(1, $date['mon'], $date['year']); + // Get the days in a week. + $daynames = calendar_get_days(); + // Store the number of days in a week. + $numberofdaysinweek = $calendartype->get_num_weekdays(); + + $display->minwday = calendar_get_starting_weekday(); + $display->maxwday = $display->minwday + ($numberofdaysinweek - 1); + $display->maxdays = calendar_days_in_month($date['mon'], $date['year']); + + // These are used for DB queries, so we want unixtime, so we need to use Gregorian dates. + $display->tstart = make_timestamp($gy, $gm, $gd, $gh, $gmin, 0); + $display->tend = make_timestamp($gy, $gm, $display->maxdays, 23, 59, 59); + // Align the starting weekday to fall in our display range + // This is simple, not foolproof. if ($startwday < $display->minwday) { - $startwday += 7; + $startwday += $numberofdaysinweek; } // Get events from database - $events = calendar_get_events(usertime($display->tstart), usertime($display->tend), $calendar->users, $calendar->groups, $calendar->courses); + $events = calendar_get_events($display->tstart, $display->tend, $calendar->users, $calendar->groups, $calendar->courses); if (!empty($events)) { foreach($events as $eventid => $event) { $event = new calendar_event($event); @@ -426,61 +460,33 @@ class core_calendar_renderer extends plugin_renderer_base { } // Extract information: events vs. time - calendar_events_by_day($events, $calendar->month, $calendar->year, $eventsbyday, $durationbyday, $typesbyday, $calendar->courses); + calendar_events_by_day($events, $date['mon'], $date['year'], $eventsbyday, $durationbyday, $typesbyday, $calendar->courses); $output = html_writer::start_tag('div', array('class'=>'header')); if (calendar_user_can_add_event($calendar->course)) { - $output .= $this->add_event_button($calendar->course->id, null, $calendar->month, $calendar->year); + $output .= $this->add_event_button($calendar->course->id, 0, 0, 0, $calendar->time); } $output .= get_string('detailedmonthview', 'calendar').': '.$this->course_filter_selector($returnurl); $output .= html_writer::end_tag('div', array('class'=>'header')); // Controls - $output .= html_writer::tag('div', calendar_top_controls('month', array('id' => $calendar->courseid, 'm' => $calendar->month, 'y' => $calendar->year)), array('class'=>'controls')); - - $days = calendar_get_days(); + $output .= html_writer::tag('div', calendar_top_controls('month', array('id' => $calendar->courseid, 'time' => $calendar->time)), array('class' => 'controls')); $table = new html_table(); $table->attributes = array('class'=>'calendarmonth calendartable'); - $time = make_timestamp($calendar->year, $calendar->month); - $table->summary = get_string('calendarheading', 'calendar', userdate($time, get_string('strftimemonthyear'))); + $table->summary = get_string('calendarheading', 'calendar', userdate($calendar->time, get_string('strftimemonthyear'))); $table->data = array(); - $header = new html_table_row(); - $header->attributes = array('class'=>'weekdays'); - $header->cells = array(); + // Get the day names as the header. + $header = array(); for($i = $display->minwday; $i <= $display->maxwday; ++$i) { - // This uses the % operator to get the correct weekday no matter what shift we have - // applied to the $display->minwday : $display->maxwday range from the default 0 : 6 - $cell = new html_table_cell(get_string($days[$i % 7], 'calendar')); - $cell->header = true; - $header->cells[] = $cell; + $header[] = $daynames[$i % $numberofdaysinweek]['shortname']; } + $table->head = $header; // For the table display. $week is the row; $dayweek is the column. $week = 1; $dayweek = $startwday; - // Create an array of all the week days. - $wdays = array(0 => ''. get_string('sun', 'calendar'). '', - 1 => ''. get_string('mon', 'calendar'). '', - 2 => ''. get_string('tue', 'calendar'). '', - 3 => ''. get_string('wed', 'calendar'). '', - 4 => ''. get_string('thu', 'calendar'). '', - 5 => ''. get_string('fri', 'calendar'). '', - 6 => ''. get_string('sat', 'calendar'). ''); - - // Loop only if the day offset is greater than 0. - // This loop involves shifting the days around until the desired start day - // is at the start of the array. - $daycount = 0; - while ($display->minwday > $daycount++) { - $wdays_end = array_shift($wdays); - array_push($wdays, $wdays_end); - } - - // Now we set the (modified) array to the table header to be displayed. - $table->head = $wdays; - $row = new html_table_row(array()); // Paddding (the first week may have blank days in the beginning) @@ -496,7 +502,9 @@ class core_calendar_renderer extends plugin_renderer_base { $weekend = intval($CFG->calendar_weekend); } - for ($calendar->day = 1; $calendar->day <= $display->maxdays; ++$calendar->day, ++$dayweek) { + $daytime = $display->tstart - DAYSECS; + for ($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) { + $daytime = $daytime + DAYSECS; if($dayweek > $display->maxwday) { // We need to change week (table row) $table->data[] = $row; @@ -507,36 +515,36 @@ class core_calendar_renderer extends plugin_renderer_base { // Reset vars $cell = new html_table_cell(); - $dayhref = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'day', 'course'=>$calendar->courseid)), $calendar->day, $calendar->month, $calendar->year); + $dayhref = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view' => 'day', 'course' => $calendar->courseid)), 0, 0, 0, $daytime); $cellclasses = array(); - if ($weekend & (1 << ($dayweek % 7))) { + if ($weekend & (1 << ($dayweek % $numberofdaysinweek))) { // Weekend. This is true no matter what the exact range is. $cellclasses[] = 'weekend'; } // Special visual fx if an event is defined - if (isset($eventsbyday[$calendar->day])) { - if(count($eventsbyday[$calendar->day]) == 1) { + if (isset($eventsbyday[$day])) { + if(count($eventsbyday[$day]) == 1) { $title = get_string('oneevent', 'calendar'); } else { - $title = get_string('manyevents', 'calendar', count($eventsbyday[$calendar->day])); + $title = get_string('manyevents', 'calendar', count($eventsbyday[$day])); } - $cell->text = html_writer::tag('div', html_writer::link($dayhref, $calendar->day, array('title'=>$title)), array('class'=>'day')); + $cell->text = html_writer::tag('div', html_writer::link($dayhref, $day, array('title'=>$title)), array('class'=>'day')); } else { - $cell->text = html_writer::tag('div', $calendar->day, array('class'=>'day')); + $cell->text = html_writer::tag('div', $day, array('class'=>'day')); } // Special visual fx if an event spans many days $durationclass = false; - if (isset($typesbyday[$calendar->day]['durationglobal'])) { + if (isset($typesbyday[$day]['durationglobal'])) { $durationclass = 'duration_global'; - } else if (isset($typesbyday[$calendar->day]['durationcourse'])) { + } else if (isset($typesbyday[$day]['durationcourse'])) { $durationclass = 'duration_course'; - } else if (isset($typesbyday[$calendar->day]['durationgroup'])) { + } else if (isset($typesbyday[$day]['durationgroup'])) { $durationclass = 'duration_group'; - } else if (isset($typesbyday[$calendar->day]['durationuser'])) { + } else if (isset($typesbyday[$day]['durationuser'])) { $durationclass = 'duration_user'; } if ($durationclass) { @@ -545,16 +553,16 @@ class core_calendar_renderer extends plugin_renderer_base { } // Special visual fx for today - if ($display->thismonth && $calendar->day == $date['mday']) { + if ($display->thismonth && $day == $date['mday']) { $cellclasses[] = 'day today'; } else { $cellclasses[] = 'day nottoday'; } $cell->attributes = array('class'=>join(' ',$cellclasses)); - if (isset($eventsbyday[$calendar->day])) { + if (isset($eventsbyday[$day])) { $cell->text .= html_writer::start_tag('ul', array('class'=>'events-new')); - foreach($eventsbyday[$calendar->day] as $eventindex) { + foreach($eventsbyday[$day] as $eventindex) { // If event has a class set then add it to the event
  • tag $attributes = array(); if (!empty($events[$eventindex]->class)) { @@ -566,9 +574,9 @@ class core_calendar_renderer extends plugin_renderer_base { } $cell->text .= html_writer::end_tag('ul'); } - if (isset($durationbyday[$calendar->day])) { + if (isset($durationbyday[$day])) { $cell->text .= html_writer::start_tag('ul', array('class'=>'events-underway')); - foreach($durationbyday[$calendar->day] as $eventindex) { + foreach($durationbyday[$day] as $eventindex) { $cell->text .= html_writer::tag('li', '['.format_string($events[$eventindex]->name,true).']', array('class'=>'events-underway')); } $cell->text .= html_writer::end_tag('ul'); diff --git a/calendar/type/gregorian/classes/structure.php b/calendar/type/gregorian/classes/structure.php index d209864d299..cf50cfca7c7 100644 --- a/calendar/type/gregorian/classes/structure.php +++ b/calendar/type/gregorian/classes/structure.php @@ -26,6 +26,18 @@ use core_calendar\type_base; */ class structure extends type_base { + /** + * Returns the name of the calendar. + * + * This is the non-translated name, usually just + * the name of the folder. + * + * @return string the calendar name + */ + public function get_name() { + return 'gregorian'; + } + /** * Returns a list of all the possible days for all months. * @@ -81,6 +93,140 @@ class structure extends type_base { return 2050; } + /** + * Returns the number of days in a week. + * + * @return int the number of days + */ + public function get_num_weekdays() { + return 7; + } + + /** + * Returns an indexed list of all the names of the weekdays. + * + * The list starts with the index 0. Each index, representing a + * day, must be an array that contains the indexes 'shortname' + * and 'fullname'. + * + * @return array array of days + */ + public function get_weekdays() { + return array( + 0 => array( + 'shortname' => get_string('sun', 'calendar'), + 'fullname' => get_string('sunday', 'calendar') + ), + 1 => array( + 'shortname' => get_string('mon', 'calendar'), + 'fullname' => get_string('monday', 'calendar') + ), + 2 => array( + 'shortname' => get_string('tue', 'calendar'), + 'fullname' => get_string('tuesday', 'calendar') + ), + 3 => array( + 'shortname' => get_string('wed', 'calendar'), + 'fullname' => get_string('wednesday', 'calendar') + ), + 4 => array( + 'shortname' => get_string('thu', 'calendar'), + 'fullname' => get_string('thursday', 'calendar') + ), + 5 => array( + 'shortname' => get_string('fri', 'calendar'), + 'fullname' => get_string('friday', 'calendar') + ), + 6 => array( + 'shortname' => get_string('sat', 'calendar'), + 'fullname' => get_string('saturday', 'calendar') + ), + ); + } + + /** + * Returns the index of the starting week day. + * + * This may vary, for example some may consider Monday as the start of the week, + * where as others may consider Sunday the start. + * + * @return int + */ + public function get_starting_weekday() { + global $CFG; + + if (isset($CFG->calendar_startwday)) { + $firstday = $CFG->calendar_startwday; + } else { + $firstday = get_string('firstdayofweek', 'langconfig'); + } + + if (!is_numeric($firstday)) { + $startingweekday = CALENDAR_DEFAULT_STARTING_WEEKDAY; + } else { + $startingweekday = intval($firstday) % 7; + } + + return get_user_preferences('calendar_startwday', $startingweekday); + } + + /** + * Returns the index of the weekday for a specific calendar date. + * + * @param int $year + * @param int $month + * @param int $day + * @return int + */ + public function get_weekday($year, $month, $day) { + return intval(date('w', mktime(12, 0, 0, $month, $day, $year))); + } + + /** + * Returns the number of days in a given month. + * + * @param int $year + * @param int $month + * @return int the number of days + */ + public function get_num_days_in_month($year, $month) { + return intval(date('t', mktime(0, 0, 0, $month, 1, $year))); + } + + /** + * Get the previous month. + * + * If the current month is January, it will get the last month of the previous year. + * + * @param int $year + * @param int $month + * @return array previous month and year + */ + public function get_prev_month($year, $month) { + if ($month == 1) { + return array(12, $year - 1); + } else { + return array($month - 1, $year); + } + } + + /** + * Get the next month. + * + * If the current month is December, it will get the first month of the following year. + * + * @param int $year + * @param int $month + * @return array the following month and year + */ + public function get_next_month($year, $month) { + if ($month == 12) { + return array(1, $year + 1); + } else { + return array($month + 1, $year); + } + } + /** * Returns a formatted string that represents a date in user time. * @@ -94,7 +240,7 @@ class structure extends type_base { * If parameter fixday = true (default), then take off leading * zero from %d, else maintain it. * - * @param int $date the timestamp in UTC, as obtained from the database + * @param int $time the timestamp in UTC, as obtained from the database * @param string $format strftime format * @param int|float|string $timezone the timezone to use * {@link http://docs.moodle.org/dev/Time_API#Timezone} @@ -104,7 +250,7 @@ class structure extends type_base { * if false then the leading zero is maintained * @return string the formatted date/time */ - public function timestamp_to_date_string($date, $format, $timezone, $fixday, $fixhour) { + public function timestamp_to_date_string($time, $format, $timezone, $fixday, $fixhour) { global $CFG; if (empty($format)) { @@ -134,7 +280,7 @@ class structure extends type_base { // Add daylight saving offset for string timezones only, as we can't get dst for // float values. if timezone is 99 (user default timezone), then try update dst. if ((99 == $timezone) || !is_numeric($timezone)) { - $date += dst_offset_on($date, $timezone); + $time += dst_offset_on($time, $timezone); } $timezone = get_user_timezone_offset($timezone); @@ -142,24 +288,24 @@ class structure extends type_base { // If we are running under Windows convert to windows encoding and then back to UTF-8 // (because it's impossible to specify UTF-8 to fetch locale info in Win32). if (abs($timezone) > 13) { // Server time. - $datestring = date_format_string($date, $format, $timezone); + $datestring = date_format_string($time, $format, $timezone); if ($fixday) { - $daystring = ltrim(str_replace(array(' 0', ' '), '', strftime(' %d', $date))); + $daystring = ltrim(str_replace(array(' 0', ' '), '', strftime(' %d', $time))); $datestring = str_replace('DD', $daystring, $datestring); } if ($fixhour) { - $hourstring = ltrim(str_replace(array(' 0', ' '), '', strftime(' %I', $date))); + $hourstring = ltrim(str_replace(array(' 0', ' '), '', strftime(' %I', $time))); $datestring = str_replace('HH', $hourstring, $datestring); } } else { - $date += (int)($timezone * 3600); - $datestring = date_format_string($date, $format, $timezone); + $time += (int)($timezone * 3600); + $datestring = date_format_string($time, $format, $timezone); if ($fixday) { - $daystring = ltrim(str_replace(array(' 0', ' '), '', gmstrftime(' %d', $date))); + $daystring = ltrim(str_replace(array(' 0', ' '), '', gmstrftime(' %d', $time))); $datestring = str_replace('DD', $daystring, $datestring); } if ($fixhour) { - $hourstring = ltrim(str_replace(array(' 0', ' '), '', gmstrftime(' %I', $date))); + $hourstring = ltrim(str_replace(array(' 0', ' '), '', gmstrftime(' %I', $time))); $datestring = str_replace('HH', $hourstring, $datestring); } } @@ -176,7 +322,7 @@ class structure extends type_base { * dst offset is applied {@link http://docs.moodle.org/dev/Time_API#Timezone} * @return array an array that represents the date in user time */ - public function timestamp_to_date_array($time, $timezone) { + public function timestamp_to_date_array($time, $timezone = 99) { return usergetdate($time, $timezone); } @@ -192,7 +338,7 @@ class structure extends type_base { * @param int $day * @param int $hour * @param int $minute - * @return array the converted day, month, year, hour and minute. + * @return array the converted date */ public function convert_from_gregorian($year, $month, $day, $hour = 0, $minute = 0) { $date = array(); @@ -217,7 +363,7 @@ class structure extends type_base { * @param int $day * @param int $hour * @param int $minute - * @return array the converted day, month, year, hour and minute. + * @return array the converted date */ public function convert_to_gregorian($year, $month, $day, $hour = 0, $minute = 0) { $date = array(); diff --git a/calendar/type/gregorian/version.php b/calendar/type/gregorian/version.php index deeac17ed5e..cec41a3e402 100644 --- a/calendar/type/gregorian/version.php +++ b/calendar/type/gregorian/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2013082300; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2012120300; // Requires this Moodle version. +$plugin->version = 2013100200; // The current plugin version (Date: YYYYMMDDXX). +$plugin->requires = 2013082300; // Requires this Moodle version. $plugin->component = 'calendartype_gregorian'; // Full name of the plugin (used for diagnostics). diff --git a/calendar/view.php b/calendar/view.php index 73e5924e89d..8e6f7d4de39 100644 --- a/calendar/view.php +++ b/calendar/view.php @@ -46,26 +46,36 @@ require_once($CFG->dirroot.'/calendar/lib.php'); $courseid = optional_param('course', SITEID, PARAM_INT); $view = optional_param('view', 'upcoming', PARAM_ALPHA); -$day = optional_param('cal_d', 0, PARAM_INT); -$mon = optional_param('cal_m', 0, PARAM_INT); -$yr = optional_param('cal_y', 0, PARAM_INT); +$day = optional_param('cal_d', 0, PARAM_INT); +$mon = optional_param('cal_m', 0, PARAM_INT); +$year = optional_param('cal_y', 0, PARAM_INT); +$time = optional_param('time', 0, PARAM_INT); $url = new moodle_url('/calendar/view.php'); + if ($courseid != SITEID) { $url->param('course', $courseid); } + if ($view !== 'upcoming') { $url->param('view', $view); } -if ($day !== 0) { - $url->param('cal_d', $day); -} -if ($mon !== 0) { - $url->param('cal_m', $mon); -} -if ($yr !== 0) { - $url->param('cal_y', $yr); + +// If a day, month and year were passed then convert it to a timestamp. If these were passed +// then we can assume the day, month and year are passed as Gregorian, as no where in core +// should we be passing these values rather than the time. This is done for BC. +if (!empty($day) && !empty($mon) && !empty($year)) { + if (checkdate($mon, $day, $year)) { + $time = make_timestamp($year, $mon, $day); + } else { + $time = time(); + } +} else if (empty($time)) { + $time = time(); } + +$url->param('time', $time); + $PAGE->set_url($url); if ($courseid != SITEID && !empty($courseid)) { @@ -78,23 +88,16 @@ if ($courseid != SITEID && !empty($courseid)) { $courses = calendar_get_default_courses(); $issite = true; } + require_course_login($course); -$calendar = new calendar_information($day, $mon, $yr); +$calendar = new calendar_information(0, 0, 0, $time); $calendar->prepare_for_view($course, $courses); -$now = usergetdate(time()); $pagetitle = ''; $strcalendar = get_string('calendar', 'calendar'); -if (!checkdate($mon, $day, $yr)) { - $day = intval($now['mday']); - $mon = intval($now['mon']); - $yr = intval($now['year']); -} -$time = make_timestamp($yr, $mon, $day); - switch($view) { case 'day': $PAGE->navbar->add(userdate($time, get_string('strftimedate'))); diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 5e714a42f67..8253c389505 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -2685,8 +2685,10 @@ function dst_offset_on($time, $strtimezone = null) { * @return int */ function find_day_in_month($startday, $weekday, $month, $year) { + $calendartype = \core_calendar\type_factory::get_calendar_instance(); $daysinmonth = days_in_month($month, $year); + $daysinweek = count($calendartype->get_weekdays()); if ($weekday == -1) { // Don't care about weekday, so return: @@ -2696,46 +2698,40 @@ function find_day_in_month($startday, $weekday, $month, $year) { } // From now on we 're looking for a specific weekday. - // Give "end of month" its actual value, since we know it. if ($startday == -1) { $startday = -1 * $daysinmonth; } // Starting from day $startday, the sign is the direction. - if ($startday < 1) { - $startday = abs($startday); - $lastmonthweekday = strftime('%w', mktime(12, 0, 0, $month, $daysinmonth, $year)); + $lastmonthweekday = dayofweek($daysinmonth, $month, $year); // This is the last such weekday of the month. $lastinmonth = $daysinmonth + $weekday - $lastmonthweekday; if ($lastinmonth > $daysinmonth) { - $lastinmonth -= 7; + $lastinmonth -= $daysinweek; } // Find the first such weekday <= $startday. while ($lastinmonth > $startday) { - $lastinmonth -= 7; + $lastinmonth -= $daysinweek; } return $lastinmonth; - } else { - - $indexweekday = strftime('%w', mktime(12, 0, 0, $month, $startday, $year)); + $indexweekday = dayofweek($startday, $month, $year); $diff = $weekday - $indexweekday; if ($diff < 0) { - $diff += 7; + $diff += $daysinweek; } // This is the first such weekday of the month equal to or after $startday. $firstfromindex = $startday + $diff; return $firstfromindex; - } } @@ -2749,7 +2745,8 @@ function find_day_in_month($startday, $weekday, $month, $year) { * @return int */ function days_in_month($month, $year) { - return intval(date('t', mktime(12, 0, 0, $month, 1, $year))); + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_num_days_in_month($year, $month); } /** @@ -2763,8 +2760,8 @@ function days_in_month($month, $year) { * @return int */ function dayofweek($day, $month, $year) { - // I wonder if this is any different from strftime('%w', mktime(12, 0, 0, $month, $daysinmonth, $year, 0));. - return intval(date('w', mktime(12, 0, 0, $month, $day, $year))); + $calendartype = \core_calendar\type_factory::get_calendar_instance(); + return $calendartype->get_weekday($year, $month, $day); } // USER AUTHENTICATION AND LOGIN.