From b991ded8162f7f94c3ca7c275883fe29431735e5 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 8 Sep 2011 00:42:13 -0700 Subject: [PATCH] Re-do the logic for the event micro-app's dropdowns (way trickier than it seems at first blush). --- plugins/Event/event.js | 169 +++++++++++++++++++++++--------- plugins/Event/eventform.php | 24 ++--- plugins/Event/eventtimelist.php | 43 ++++---- plugins/Event/newevent.php | 5 +- 4 files changed, 157 insertions(+), 84 deletions(-) diff --git a/plugins/Event/event.js b/plugins/Event/event.js index 8ed25a899b..696176edbd 100644 --- a/plugins/Event/event.js +++ b/plugins/Event/event.js @@ -1,73 +1,144 @@ $(document).ready(function() { - var today = new Date(); + // get current time from server + var today = new Date($('now').val()); $("#event-startdate").datepicker({ - // Don't let the user set a crazy start date + // Don't let the user set a start date < before today minDate: today, - onClose: function(dateText, picker) { - // Don't let the user set a crazy end date - var newStartDate = new Date(dateText); - var endDate = new Date($("#event-startdate").val()); - if (endDate < newStartDate) { - $("#event-enddate").val(dateText); - } - if (dateText !== null) { - $("#event-enddate").datepicker('option', 'minDate', new Date(dateText)); - } - }, - onSelect: function() { - var startd = $("#event-startdate").val(); - var endd = $("#event-enddate").val(); - var sdate = new Date(startd); - var edate = new Date(endd); - if (sdate !== edate) { - updateTimes(); - } - } + onClose: onStartDateSelected }); $("#event-enddate").datepicker({ minDate: today, - onSelect: function() { - var startd = $("#event-startdate").val(); - var endd = $("#event-enddate").val(); - var sdate = new Date(startd); - var edate = new Date(endd); - if (sdate !== edate) { - updateTimes(); + onClose: onEndDateSelected + }); + + $("#event-starttime").change(function(e) { + var tz = $("#tz").val(); + + var startDate = $("#event-startdate").val(); + var startTime = $("#event-starttime option:selected").val().replace(/(pm|am)/, ' $1'); + var startStr = startDate + ' ' + startTime + ' ' + tz; + + var endDate = $("#event-enddate").val(); + var endTime = $("#event-endtime option:selected").val(); + var endStr = endDate + ' ' + endTime.replace(/(pm|am)/, ' $1') + ' ' + tz; + + // just need to compare hours + var start = new Date(startStr); + var end = new Date(endStr); + + updateTimes(startStr, (startDate === endDate), function (data) { + var times = []; + $.each(data, function(key, val) { + times.push(''); + }); + $("#event-endtime").html(times.join('')); + + if (start > end) { + $("#event-endtime").val(startTime).attr("selected", "selected"); + } else { + $("#event-endtime").val(endTime).attr("selected", "selected"); + } + }); + + }); + + $("#event-endtime").change(function(e) { + var HOUR = 60 * 60 * 1000; + var tz = $("#tz").val(); + var startDate = $("#event-startdate").val(); + var endDate = $("#event-enddate").val(); + var starttime = $("#event-starttime option:selected").val(); + var endtime = $("#event-endtime option:selected").val(); + var endtimeText = $("#event-endtime option:selected").text(); + + // If the end time is in the next day then update the start date + if (startDate === endDate) { + var startstr = startDate + ' ' + starttime.replace(/(pm|am)/, ' $1') + ' ' + tz; + var start = new Date(startstr); + var matches = endtimeText.match(/\(.*\)/); + var hours; + if (matches) { + hours = matches[0].substr(1).split(' ')[0]; // get x from (x hours) + if (hours) { + if (hours == 30) { + hours = .5; // special case: x == 30 from (30 mins) + } + var end = new Date(start.getTime() + (hours * HOUR)); + if (end.getDate() > start.getDate()) { + $("#event-enddate").datepicker('setDate', end); + var endstr = endDate + ' 12:00 am ' + tz; + updateTimes(endstr, false, function(data) { + var times = []; + $.each(data, function(key, val) { + times.push(''); + }); + $("#event-endtime").html(times.join('')); + + if (start > end) { + $("#event-endtime").val(starttime).attr("selected", "selected"); + } else { + $("#event-endtime").val(endtime).attr("selected", "selected"); + } + }); + } + } } } }); - function updateTimes() { - var startd = $("#event-startdate").val(); - var endd = $("#event-enddate").val(); + function onStartDateSelected(dateText, inst) { + var tz = $("#tz").val(); + var startTime = $("#event-starttime option:selected").val(); + var startDateTime = new Date(dateText + ' ' + startTime.replace(/(pm|am)/, ' $1') + ' ' + tz); + + // When we update the start date and time, we need to update the end date and time + // to make sure they are equal or in the future + $("#event-enddate").datepicker('option', 'minDate', startDateTime); + + recalculateTimes(); + } + + function onEndDateSelected(dateText, inst) { + recalculateTimes(); + } + + function recalculateTimes(showDuration) { + var tz = $("#tz").val(); - var startt = $("#event-starttime option:selected").val(); - var endt = $("#event-endtime option:selected").val(); + var startDate = $("#event-startdate").val(); + var startTime = $("#event-starttime option:selected").val(); + var startStr = startDate + ' ' + startTime.replace(/(pm|am)/, ' $1') + ' ' + tz; + var startDateTime = new Date(startStr); - var sdate = new Date(startd + " " + startt); - var edate = new Date(endd + " " + endt); - var duration = (startd === endd); + var endDate = $("#event-enddate").val(); + var endTime = $("#event-endtime option:selected").val(); + var endDateTime = new Date(endDate + ' ' + endTime.replace(/(pm|am)/, ' $1') + ' ' + tz); + var showDuration = true; + + if (endDateTime.getDate() !== startDateTime.getDate()) { + starStr = endDate + ' 12:00 am ' + tz; + showDuration = false; + } - $.getJSON($('#timelist_action_url').val(), - { start: startt, ajax: true, duration: duration }, - function(data) { - var times = []; - $.each(data, function(key, val) { + updateTimes(startStr, showDuration, function(data) { + var times = []; + $.each(data, function(key, val) { times.push(''); }); - $("#event-endtime").html(times.join('')); - if (startt < endt) { - $("#event-endtime").val(endt).attr("selected", "selected"); + if (startDateTime > endDateTime) { + $("#event-endtime").val(startTime).attr("selected", "selected"); + } else { + $("#event-endtime").val(endTime).attr("selected", "selected"); } - }) + }); } - $("#event-starttime").change(function(e) { - updateTimes(); - }); + function updateTimes(start, duration, onSuccess) { + $.getJSON($('#timelist_action_url').val(), {start: start, ajax: true, duration: duration}, onSuccess); + } }); diff --git a/plugins/Event/eventform.php b/plugins/Event/eventform.php index c09a7ab171..ab50e6d47e 100644 --- a/plugins/Event/eventform.php +++ b/plugins/Event/eventform.php @@ -123,7 +123,12 @@ class EventForm extends Form $this->li(); - $times = EventTimeList::getTimes(); + $times = EventTimeList::getTimes($today->format('m/d/Y 12:00') . ' am ' . $today->format('T')); + + common_debug(var_export($times, true)); + + $start = EventTimeList::nearestHalfHour('@' . $today->getTimestamp()); + $start->setTimezone(new DateTimeZone(common_timezone())); $this->out->dropdown( 'event-starttime', @@ -131,11 +136,15 @@ class EventForm extends Form _m('LABEL','Start time'), $times, // TRANS: Field title on event form. %s is the abbreviated timezone - sprintf(_m("Time the event starts (%s)."), $today->format("T")), + sprintf(_m("Time the event starts (%s)."), $today->format('T')), false, - null + $start->format('g:ia') ); + // Need to keep JavaScript TZ in sync with PHP TZ + $this->out->hidden('tz', $today->format('T')); + $this->out->hidden('now', $today->format('F d, Y H:i:s T')); + $this->unli(); $this->li(); @@ -150,18 +159,11 @@ class EventForm extends Form $this->li(); - // XXX: Initial end time should be at least 30 mins out? We could do - // every 15 minute instead -z - $keys = array_keys($times); - $endStr = date('m/d/y', strtotime('now')) . " {$keys[0]}"; - $end = new DateTime($endStr); - $end->modify('+30'); - $this->out->dropdown( 'event-endtime', // TRANS: Field label on event form. _m('LABEL','End time'), - EventTimeList::getTimes($end->format('c'), true), + EventTimeList::getTimes('@' . $start->getTimestamp(), true), // TRANS: Field title on event form. _m('Time the event ends.'), false, diff --git a/plugins/Event/eventtimelist.php b/plugins/Event/eventtimelist.php index 9238f294d0..2436a4fc6e 100644 --- a/plugins/Event/eventtimelist.php +++ b/plugins/Event/eventtimelist.php @@ -39,10 +39,10 @@ class EventTimeList { */ public static function nearestHalfHour($time) { - $start = strtotime($time); + $startd = new DateTime($time); - $minutes = date('i', $start); - $hour = date('H', $start); + $minutes = $startd->format('i'); + $hour = $startd->format('H'); if ($minutes >= 30) { $minutes = '00'; @@ -51,39 +51,34 @@ class EventTimeList { $minutes = '30'; } - $newTimeStr = date('m/d/y', $start) . " {$hour}:{$minutes}:00"; - return new DateTime($newTimeStr); + $startd->setTime($hour, $minutes, 0); + + return $startd; } /** * Output a list of times in half-hour intervals * - * @param string $start Time to start with (date/time string) + * @param string $start Time to start with (date string, usually a ts) * @param boolean $duration Whether to include the duration of the event * (from the start) - * @return array $times (UTC time string => localized time string) + * @return array $times (localized 24 hour time string => fancy time string) */ public static function getTimes($start = 'now', $duration = false) { - $newTime = self::nearestHalfHour($start); + $newTime = new DateTime($start); + $times = array(); + $len = 0; $newTime->setTimezone(new DateTimeZone(common_timezone())); - $times = array(); - $len = 0; - for ($i = 0; $i < 48; $i++) { - // make sure we store the time as UTC - $newTime->setTimezone(new DateTimeZone('UTC')); - $utcTime = $newTime->format('H:i:s'); + for ($i = 0; $i < 47; $i++) { - // localize time for user - $newTime->setTimezone(new DateTimeZone(common_timezone())); - $localTime = $newTime->format('g:ia'); + $localTime = $newTime->format("g:ia"); // pretty up the end-time option list a bit if ($duration) { - $len += 30; - $hours = $len / 60; + $hours = $len / 60; switch ($hours) { case 0: // TRANS: 0 minutes abbreviated. Used in a list. @@ -98,14 +93,18 @@ class EventTimeList { $total = ' ' . _m('(1 hour)'); break; default: - // TRANS: Number of hours (%d). Used in a list. - $total = ' ' . sprintf(_m('(%d hour)','(%d hours)',$hours), $hours); + // TRANS: Number of hours (%.1f and %d). Used in a list. + $format = is_float($hours) + ? _m('(%.1f hours)') + : _m('(%d hours)'); + $total = ' ' . sprintf($format, $hours); break; } $localTime .= $total; + $len += 30; } - $times[$utcTime] = $localTime; + $times[$newTime->format('g:ia')] = $localTime; $newTime->modify('+30min'); // 30 min intervals } diff --git a/plugins/Event/newevent.php b/plugins/Event/newevent.php index 1bfcddba34..14e3168d42 100644 --- a/plugins/Event/newevent.php +++ b/plugins/Event/newevent.php @@ -101,6 +101,7 @@ class NeweventAction extends Action $this->location = $this->trimmed('location'); $this->url = $this->trimmed('url'); $this->description = $this->trimmed('description'); + $tz = $this->trimmed('tz'); $startDate = $this->trimmed('startdate'); @@ -128,11 +129,11 @@ class NeweventAction extends Action $endTime = '00:00'; } - $start = $startDate . ' ' . $startTime; + $start = $startDate . ' ' . $startTime . ' ' . $tz; common_debug("Event start: '$start'"); - $end = $endDate . ' ' . $endTime; + $end = $endDate . ' ' . $endTime . ' ' . $tz; common_debug("Event start: '$end'"); -- 2.39.2