Skip to content
Permalink
Browse files

MDL-27242 Conditional availability dates should support time as well …

…as day

Change also adds minor feature to date-time selector so you can specify the time it uses as default when the value is 0 (disabled).

Credit: This feature was developed collaboratively by Charles Fulton, Neill Magill, and me.
  • Loading branch information...
sammarshallou committed Oct 11, 2011
1 parent 6731a04 commit 6282381d05a62b032c20d25b7b29d8ead41cfbbd
Showing with 117 additions and 48 deletions.
  1. +0 −12 course/modedit.php
  2. +17 −4 course/moodleform_mod.php
  3. +1 −0 lang/en/condition.php
  4. +74 −29 lib/conditionlib.php
  5. +18 −0 lib/db/upgrade.php
  6. +6 −2 lib/form/datetimeselector.php
  7. +1 −1 version.php
@@ -302,12 +302,6 @@
if (!empty($CFG->enableavailability)) {
$cm->availablefrom = $fromform->availablefrom;
$cm->availableuntil = $fromform->availableuntil;
// The form time is midnight, but because we want it to be
// inclusive, set it to 23:59:59 on that day.
if ($cm->availableuntil) {
$cm->availableuntil = strtotime('23:59:59',
$cm->availableuntil);
}
$cm->showavailability = $fromform->showavailability;
condition_info::update_cm_from_form($cm,$fromform,true);
}
@@ -393,12 +387,6 @@
if(!empty($CFG->enableavailability)) {
$newcm->availablefrom = $fromform->availablefrom;
$newcm->availableuntil = $fromform->availableuntil;
// The form time is midnight, but because we want it to be
// inclusive, set it to 23:59:59 on that day.
if ($newcm->availableuntil) {
$newcm->availableuntil = strtotime('23:59:59',
$newcm->availableuntil);
}
$newcm->showavailability = $fromform->showavailability;
}
if (isset($fromform->showdescription)) {
@@ -308,7 +308,7 @@ function validation($data, $files) {
// Conditions: Don't let them set dates which make no sense
if (array_key_exists('availablefrom', $data) &&
$data['availablefrom'] && $data['availableuntil'] &&
$data['availablefrom'] > $data['availableuntil']) {
$data['availablefrom'] >= $data['availableuntil']) {
$errors['availablefrom'] = get_string('badavailabledates', 'condition');
}
@@ -429,10 +429,23 @@ function standard_coursemodule_elements(){
if (!empty($CFG->enableavailability)) {
// Conditional availability
$mform->addElement('header', 'availabilityconditionsheader', get_string('availabilityconditions', 'condition'));
$mform->addElement('date_selector', 'availablefrom', get_string('availablefrom', 'condition'), array('optional'=>true));
// Available from/to defaults to midnight because then the display
// will be nicer where it tells users when they can access it (it
// shows only the date and not time).
$date = usergetdate(time());
$midnight = make_timestamp($date['year'], $date['mon'], $date['mday']);
// From/until controls
$mform->addElement('header', 'availabilityconditionsheader',
get_string('availabilityconditions', 'condition'));
$mform->addElement('date_time_selector', 'availablefrom',
get_string('availablefrom', 'condition'),
array('optional' => true, 'defaulttime' => $midnight));
$mform->addHelpButton('availablefrom', 'availablefrom', 'condition');
$mform->addElement('date_selector', 'availableuntil', get_string('availableuntil', 'condition'), array('optional'=>true));
$mform->addElement('date_time_selector', 'availableuntil',
get_string('availableuntil', 'condition'),
array('optional' => true, 'defaulttime' => $midnight));
// Conditions based on grades
$gradeoptions = array();
@@ -57,6 +57,7 @@
$string['requires_date'] = 'Available from {$a}.';
$string['requires_date_before'] = 'Available until {$a}.';
$string['requires_date_both'] = 'Available from {$a->from} to {$a->until}.';
$string['requires_date_both_single_day'] = 'Available on {$a}.';
$string['requires_grade_any'] = 'Not available until you have a grade in <strong>{$a}</strong>.';
$string['requires_grade_max'] = 'Not available unless you get an appropriate score in <strong>{$a}</strong>.';
$string['requires_grade_min'] = 'Not available until you achieve a required score in <strong>{$a}</strong>.';
@@ -331,24 +331,83 @@ public function get_full_information($modinfo=null) {
}
}
// Dates
// The date logic is complicated. The intention of this logic is:
// 1) display date without time where possible (whenever the date is
// midnight)
// 2) when the 'until' date is e.g. 00:00 on the 14th, we display it as
// 'until the 13th' (experience at the OU showed that students are
// likely to interpret 'until <date>' as 'until the end of <date>').
// 3) This behaviour becomes confusing for 'same-day' dates where there
// are some exceptions.
// Users in different time zones will typically not get the 'abbreviated'
// behaviour but it should work OK for them aside from that.
// The following cases are possible:
// a) From 13:05 on 14 Oct until 12:10 on 17 Oct (exact, exact)
// b) From 14 Oct until 12:11 on 17 Oct (midnight, exact)
// c) From 13:05 on 14 Oct until 17 Oct (exact, midnight 18 Oct)
// d) From 14 Oct until 17 Oct (midnight 14 Oct, midnight 18 Oct)
// e) On 14 Oct (midnight 14 Oct, midnight 15 Oct)
// f) From 13:05 on 14 Oct until 0:00 on 15 Oct (exact, midnight, same day)
// g) From 0:00 on 14 Oct until 12:05 on 14 Oct (midnight, exact, same day)
// h) From 13:05 on 14 Oct (exact)
// i) From 14 Oct (midnight)
// j) Until 13:05 on 14 Oct (exact)
// k) Until 14 Oct (midnight 15 Oct)
// Check if start and end dates are 'midnights', if so we show in short form
$shortfrom = self::is_midnight($this->cm->availablefrom);
$shortuntil = self::is_midnight($this->cm->availableuntil);
// For some checks and for display, we need the previous day for the 'until'
// value, if we are going to display it in short form
if ($this->cm->availableuntil) {
$daybeforeuntil = strtotime("-1 day", usergetmidnight($this->cm->availableuntil));
}
// Special case for if one but not both are exact and they are within a day
if ($this->cm->availablefrom && $this->cm->availableuntil &&
$shortfrom != $shortuntil && $daybeforeuntil < $this->cm->availablefrom) {
// Don't use abbreviated version (see examples f, g above)
$shortfrom = false;
$shortuntil = false;
}
// When showing short end date, the display time is the 'day before' one
$displayuntil = $shortuntil ? $daybeforeuntil : $this->cm->availableuntil;
if ($this->cm->availablefrom && $this->cm->availableuntil) {
$information .= get_string('requires_date_both', 'condition',
(object)array(
'from' => self::show_time($this->cm->availablefrom, false),
'until' => self::show_time($this->cm->availableuntil, true)));
if ($shortfrom && $shortuntil && $daybeforeuntil == $this->cm->availablefrom) {
$information .= get_string('requires_date_both_single_day', 'condition',
self::show_time($this->cm->availablefrom, true));
} else {
$information .= get_string('requires_date_both', 'condition', (object)array(
'from' => self::show_time($this->cm->availablefrom, $shortfrom),
'until' => self::show_time($displayuntil, $shortuntil)));
}
} else if ($this->cm->availablefrom) {
$information .= get_string('requires_date', 'condition',
self::show_time($this->cm->availablefrom, false));
self::show_time($this->cm->availablefrom, $shortfrom));
} else if ($this->cm->availableuntil) {
$information .= get_string('requires_date_before', 'condition',
self::show_time($this->cm->availableuntil, true));
self::show_time($displayuntil, $shortuntil));
}
$information = trim($information);
return $information;
}
/**
* Checks whether a given time refers exactly to midnight (in current user
* timezone).
* @param int $time Time
* @return bool True if time refers to midnight, false if it's some other
* time or if it is set to zero
*/
private static function is_midnight($time) {
return $time && usergetmidnight($time) == $time;
}
/**
* Determines whether this particular course-module is currently available
* according to these criteria.
@@ -467,7 +526,8 @@ public function is_available(&$information, $grabthelot=false, $userid=0, $modin
$available = false;
$information .= get_string('requires_date', 'condition',
self::show_time($this->cm->availablefrom, false));
self::show_time($this->cm->availablefrom,
self::is_midnight($this->cm->availablefrom)));
}
}
@@ -491,30 +551,15 @@ public function is_available(&$information, $grabthelot=false, $userid=0, $modin
}
/**
* Shows a time either as a date (if it falls exactly on the day) or
* a full date and time, according to user's timezone.
*
* Shows a time either as a date or a full date and time, according to
* user's timezone.
* @param int $time Time
* @param bool $until True if this date should be treated as the second of
* an inclusive pair - if so the time will be shown unless date is 23:59:59.
* Without this the date shows for 0:00:00.
* @param bool $dateonly If true, uses date only
* @return string Date
*/
private function show_time($time, $until) {
// Break down the time into fields
$userdate = usergetdate($time);
// Handle the 'inclusive' second date
if($until) {
$dateonly = $userdate['hours']==23 && $userdate['minutes']==59 &&
$userdate['seconds']==59;
} else {
$dateonly = $userdate['hours']==0 && $userdate['minutes']==0 &&
$userdate['seconds']==0;
}
return userdate($time, get_string(
$dateonly ? 'strftimedate' : 'strftimedatetime', 'langconfig'));
private function show_time($time, $dateonly) {
return userdate($time,
get_string($dateonly ? 'strftimedate' : 'strftimedatetime', 'langconfig'));
}
/**
@@ -6792,6 +6792,24 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2011100700.02);
}
if ($oldversion < 2011101200.01) {
// The conditional availability date system used to rely on dates being
// set to 23:59:59 for the end date, but now that exact times are
// supported, it uses midnight on the following day.
// The query is restricted on 'time mod 10 = 9' in order that
// it is safe to run this upgrade twice if something goes wrong.
$DB->execute('UPDATE {course_modules} SET availableuntil = availableuntil + 1 ' .
'WHERE availableuntil > 0 AND ' . $DB->sql_modulo('availableuntil', 10) . ' = 9');
// Because availableuntil is stored in modinfo, we need to clear modinfo
// for all courses.
rebuild_course_cache(0, true);
// Main savepoint reached
upgrade_main_savepoint(true, 2011101200.01);
}
return true;
}
@@ -40,12 +40,13 @@ class MoodleQuickForm_date_time_selector extends MoodleQuickForm_group{
*
* startyear => integer start of range of years that can be selected
* stopyear => integer last year that can be selected
* defaulttime => default time value if the field is currently not set
* timezone => float/string timezone
* applydst => apply users daylight savings adjustment?
* step => step to increment minutes by
* optional => if true, show a checkbox beside the date to turn it on (or off)
*/
var $_options = array('startyear' => 1970, 'stopyear' => 2020,
var $_options = array('startyear' => 1970, 'stopyear' => 2020, 'defaulttime' => 0,
'timezone' => 99, 'applydst' => true, 'step' => 5, 'optional' => false);
/**
@@ -159,7 +160,10 @@ function onQuickFormEvent($event, $arg, &$caller)
}
$requestvalue=$value;
if ($value == 0) {
$value = time();
$value = $this->_options['defaulttime'];
if (!$value) {
$value = time();
}
}
if (!is_array($value)) {
$currentdate = usergetdate($value);
@@ -31,7 +31,7 @@
$version = 2011101200.00; // YYYYMMDD = weekly release date of this DEV branch
$version = 2011101200.01; // YYYYMMDD = weekly release date of this DEV branch
// RR = release increments - 00 in DEV branches
// .XX = incremental changes

0 comments on commit 6282381

Please sign in to comment.
You can’t perform that action at this time.