Commit 5eba1030 authored by Evan Prodromou's avatar Evan Prodromou

Merge remote-tracking branch 'origin/1.0.x' into 1.0.x

parents b7a5041e 449451b8
......@@ -161,7 +161,9 @@ abstract class Managed_DataObject extends Memcached_DataObject
foreach ($table['foreign keys'] as $keyname => $keydef) {
if (count($keydef) == 2 && is_string($keydef[0]) && is_array($keydef[1]) && count($keydef[1]) == 1) {
$links[$keydef[1][0]] = $keydef[0].':'.$keydef[1][1];
if (isset($keydef[1][0])) {
$links[$keydef[1][0]] = $keydef[0].':'.$keydef[1][1];
}
}
}
return $links;
......
$(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('<option value="' + key + '">' + val + '</option>');
});
$("#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('<option value="' + key + '">' + val + '</option>');
});
$("#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('<option value="' + key + '">' + val + '</option>');
});
$("#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);
}
});
......@@ -123,7 +123,9 @@ class EventForm extends Form
$this->li();
$times = EventTimeList::getTimes();
$times = EventTimeList::getTimes($today->format('m/d/Y 12:00') . ' am ' . $today->format('T'));
$start = EventTimeList::nearestHalfHour('@' . $today->getTimestamp());
$start->setTimezone(new DateTimeZone(common_timezone()));
$this->out->dropdown(
'event-starttime',
......@@ -131,11 +133,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 +156,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,
......
......@@ -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
}
......
......@@ -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,13 +129,8 @@ class NeweventAction extends Action
$endTime = '00:00';
}
$start = $startDate . ' ' . $startTime;
common_debug("Event start: '$start'");
$end = $endDate . ' ' . $endTime;
common_debug("Event start: '$end'");
$start = $startDate . ' ' . $startTime . ' ' . $tz;
$end = $endDate . ' ' . $endTime . ' ' . $tz;
$this->startTime = strtotime($start);
$this->endTime = strtotime($end);
......@@ -194,6 +190,7 @@ class NeweventAction extends Action
function newEvent()
{
try {
if (empty($this->title)) {
// TRANS: Client exception thrown when trying to post an event without providing a title.
throw new ClientException(_m('Event must have a title.'));
......@@ -209,6 +206,11 @@ class NeweventAction extends Action
throw new ClientException(_m('Event must have an end time.'));
}
if (isset($this->url) && Validate::uri($this->url) === false) {
// TRANS: Client exception thrown when trying to post an event with an invalid URL.
throw new ClientException(_m('URL must be valid.'));
}
$options = array();
// Does the heavy-lifting for getting "To:" information
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment