See ChangeLog.

Monotone-Parent: d11c3e99fe05eb716e0732c7b5c44019dcd75934
Monotone-Revision: 0a8cad3c6a768c445cd15f040d34f93bba3eb6ea

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2011-06-13T20:28:10
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Francis Lachapelle 2011-06-13 20:28:10 +00:00
parent 80b7efed49
commit 2015c05a3c
15 changed files with 497 additions and 298 deletions

View File

@ -1,3 +1,20 @@
2011-06-13 Francis Lachapelle <flachapelle@inverse.ca>
* UI/WebServerResources/SOGoTimePicker.js: new interface to add a
time picker widget to an input field.
* UI/Scheduler/UIxTimeDateControl.m: replaced hours and minutes
popup menu by one input field.
* UI/WebServerResources/UIxAppointmentEditor.js: idem.
* UI/WebServerResources/UIxTaskEditor.js: idem.
* UI/Scheduler/UIxAppointmentEditor.m (-newStartDate): round
minutes to the nearest 15-minute.
* UI/Scheduler/UIxTaskEditor.m (-newStartDate): idem.
2011-06-08 Francis Lachapelle <flachapelle@inverse.ca>
* UI/WebServerResources/MailerUI.js (initMailer): added the Thread

View File

@ -210,7 +210,7 @@
NSCalendarDate *newStartDate, *now;
NSTimeZone *timeZone;
SOGoUserDefaults *ud;
int hour;
int hour, minute;
unsigned int uStart, uEnd;
newStartDate = [self selectedDate];
@ -226,12 +226,15 @@
{
uEnd = [ud dayEndHour];
hour = [now hourOfDay];
minute = [now minuteOfHour];
if (minute % 15)
minute += 15 - (minute % 15);
if (hour < uStart)
newStartDate = [now hour: uStart minute: 0];
else if (hour > uEnd)
newStartDate = [[now tomorrow] hour: uStart minute: 0];
else
newStartDate = now;
newStartDate = [now hour: [now hourOfDay] minute: minute];
}
else
newStartDate = [newStartDate hour: uStart minute: 0];

View File

@ -280,6 +280,7 @@ static NSArray *tasksFields = nil;
...
*/
//NSLog(@"***[UIxCalListingActions _fixDates:] %@", [theRecord objectForKey: @"c_title"]);
if (dayBasedView || [[theRecord objectForKey: @"c_isallday"] boolValue])
{
for (count = 0; count < 2; count++)
@ -288,6 +289,7 @@ static NSArray *tasksFields = nil;
aDate = [theRecord objectForKey: aDateField];
daylightOffset = (int) ([userTimeZone secondsFromGMTForDate: aDate]
- [userTimeZone secondsFromGMTForDate: startDate]);
//NSLog(@"***[UIxCalListingActions _fixDates:] %@ = %@ (%i)", aDateField, aDate, daylightOffset);
if (daylightOffset)
{
aDate = [aDate dateByAddingYears: 0 months: 0 days: 0 hours: 0
@ -413,6 +415,7 @@ static NSArray *tasksFields = nil;
date = [NSCalendarDate dateWithTimeIntervalSince1970: seconds];
// Adjust for daylight saving time? (wrt to startDate)
//NSLog(@"***[UIxCalListingActions _formattedDateForSeconds] user timezone is %@", userTimeZone);
[date setTimeZone: userTimeZone];
if (forAllDay)
formattedDate = [dateFormatter formattedDate: date];
@ -975,6 +978,11 @@ _computeBlocksPosition (NSArray *blocks)
for (count = 0; count < max; count++)
{
event = [events objectAtIndex: count];
// NSLog(@"***[UIxCalListingActions eventsBlocksAction] %i = %@ : %@ / %@ / %@", count,
// [event objectAtIndex: eventTitleIndex],
// [event objectAtIndex: eventStartDateIndex],
// [event objectAtIndex: eventEndDateIndex],
// [event objectAtIndex: eventRecurrenceIdIndex]);
eventNbr = [NSNumber numberWithUnsignedInt: count];
isAllDay = [[event objectAtIndex: eventIsAllDayIndex] boolValue];
if (dayBasedView && isAllDay)

View File

@ -257,7 +257,7 @@
NSCalendarDate *newStartDate, *now;
NSTimeZone *timeZone;
SOGoUserDefaults *ud;
int hour;
int hour, minute;
unsigned int uStart, uEnd;
newStartDate = [self selectedDate];
@ -273,12 +273,15 @@
{
uEnd = [ud dayEndHour];
hour = [now hourOfDay];
minute = [now minuteOfHour];
if (minute % 15)
minute += 15 - (minute % 15);
if (hour < uStart)
newStartDate = [now hour: uStart minute: 0];
else if (hour > uEnd)
newStartDate = [[now tomorrow] hour: uStart minute: 0];
else
newStartDate = now;
newStartDate = [now hour: [now hourOfDay] minute: minute];
}
else
newStartDate = [newStartDate hour: uStart minute: 0];
@ -302,8 +305,14 @@
{
startDate = [todo startDate];
dueDate = [todo due];
hasStartDate = (startDate != nil);
hasDueDate = (dueDate != nil);
if (startDate)
hasStartDate = YES;
else
startDate = [self newStartDate];
if (dueDate)
hasDueDate = YES;
else
dueDate = [self newStartDate];
ASSIGN (status, [todo status]);
if ([status isEqualToString: @"COMPLETED"])
{

View File

@ -33,36 +33,23 @@
NSString *controlID;
NSString *label;
NSCalendarDate *date;
id hour;
id minute;
id second;
NSString *time;
id day;
id month;
id year;
BOOL displayTimeControl;
unsigned int startHour;
unsigned int endHour;
NSNumber *currentHour;
NSNumber *currentMinute;
BOOL isDisabled;
}
- (void) setDayStartHour: (unsigned int) hour;
- (void) setDayEndHour: (unsigned int) hour;
- (void)setControlID:(NSString *)_controlID;
- (NSString *)controlID;
- (void)setLabel:(NSString *)_label;
- (NSString *)label;
- (void)setDate:(NSCalendarDate *)_date;
- (NSCalendarDate *)date;
- (void)setTime:(NSString *)_time;
- (NSString *)time;
- (void)setHour:(id)_hour;
- (id)hour;
- (void)setMinute:(id)_minute;
- (id)minute;
- (void)setSecond:(id)_second;
- (id)second;
- (void)setDay:(id)_day;
- (id)day;
- (void)setMonth:(id)_month;

View File

@ -45,9 +45,7 @@
[controlID release];
[label release];
[date release];
[hour release];
[minute release];
[second release];
[time release];
[day release];
[month release];
[year release];
@ -56,23 +54,28 @@
/* accessors */
- (void)setControlID:(NSString *)_controlID {
- (void)setControlID:(NSString *)_controlID
{
ASSIGNCOPY(controlID, _controlID);
}
- (NSString *)controlID {
- (NSString *)controlID
{
return controlID;
}
- (void)setLabel:(NSString *)_label {
- (void)setLabel:(NSString *)_label
{
ASSIGNCOPY(label, _label);
}
- (NSString *)label {
- (NSString *)label
{
return label;
}
- (void) setDate: (NSCalendarDate *) _date
{
SOGoUserDefaults *ud;
int minuteValue;
if (!_date)
_date = [NSCalendarDate date];
@ -81,148 +84,63 @@
[_date setTimeZone: [ud timeZone]];
[self _setDate: _date];
[self setTime: [_date descriptionWithCalendarFormat: @"%H:%M"]];
minuteValue = [_date minuteOfHour];
if (minuteValue % 15)
minuteValue += 15 - (minuteValue % 15);
[self setHour: [NSNumber numberWithInt: [_date hourOfDay]]];
[self setMinute: [NSNumber numberWithInt: minuteValue]];
[self setYear: [NSNumber numberWithInt: [_date yearOfCommonEra]]];
[self setMonth: [NSNumber numberWithInt: [_date monthOfYear]]];
[self setDay: [NSNumber numberWithInt: [_date dayOfMonth]]];
}
- (void)_setDate:(NSCalendarDate *)_date {
- (void)_setDate:(NSCalendarDate *)_date
{
ASSIGN(date, _date);
}
- (NSCalendarDate *)date {
- (NSCalendarDate *)date
{
return date;
}
- (void)setHour:(id)_hour {
ASSIGN(hour, _hour);
- (void) setTime: (NSString *)_time
{
ASSIGN(time, _time);
}
- (id)hour {
return hour;
}
- (void)setMinute:(id)_minute {
ASSIGN(minute, _minute);
}
- (id)minute {
return minute;
}
- (void)setSecond:(id)_second {
ASSIGN(second, _second);
}
- (id)second {
return second;
- (NSString *) time
{
return time;
}
- (void)setDay:(id)_day {
- (void)setDay:(id)_day
{
ASSIGN(day, _day);
}
- (id)day {
- (id)day
{
return day;
}
- (void)setMonth:(id)_month {
- (void)setMonth:(id)_month
{
ASSIGN(month, _month);
}
- (id)month {
- (id)month
{
return month;
}
- (void)setYear:(id)_year {
- (void)setYear:(id)_year
{
ASSIGN(year, _year);
}
- (id)year {
- (id)year
{
return year;
}
- (void) setDayStartHour: (unsigned int) aStartHour
{
startHour = aStartHour;
}
- (void) setDayEndHour: (unsigned int) anEndHour
{
endHour = anEndHour;
}
- (void) setHourOption: (NSNumber *) option
{
currentHour = option;
}
- (BOOL) isCurrentHour
{
return [currentHour isEqual: hour];
}
- (BOOL) isCurrentMinute
{
return [currentMinute isEqual: minute];
}
- (int) hourValue
{
return [currentHour intValue];
}
- (NSString *) hourLabel
{
return [NSString stringWithFormat: @"%.2d", [currentHour intValue]];
}
- (NSArray *) selectableHours
{
NSMutableArray *hours;
unsigned int h;
hours = [NSMutableArray array];
for (h = startHour; h < (endHour + 1); h++)
[hours addObject: [NSNumber numberWithInt: h]];
return hours;
}
- (NSString *) hourSelectId
{
return [[self controlID] stringByAppendingString:@"_time_hour"];
}
- (void) setMinuteOption: (NSNumber *) option
{
currentMinute = option;
}
- (int) minuteValue
{
return [currentMinute intValue];
}
- (NSString *) minuteLabel
{
return [NSString stringWithFormat: @"%.2d", [currentMinute intValue]];
}
- (NSArray *) selectableMinutes
{
NSMutableArray *minutes;
unsigned int m;
minutes = [NSMutableArray array];
for (m = 0; m < 60; m += 15)
[minutes addObject: [NSNumber numberWithInt: m]];
return minutes;
}
- (NSString *) minuteSelectId
{
return [[self controlID] stringByAppendingString:@"_time_minute"];
}
- (NSString *) timeID
{
return [[self controlID] stringByAppendingString:@"_time"];
@ -249,8 +167,9 @@
inContext: (WOContext *) _ctx
{
NSCalendarDate *d;
unsigned _year, _month, _day, _hour, _minute, _second;
unsigned _year, _month, _day, _hour, _minute;//, _second;
SOGoUserDefaults *ud;
NSArray *_time;
/* call super, so that the form values are applied on the popups */
[super takeValuesFromRequest:_rq inContext:_ctx];
@ -258,18 +177,18 @@
_year = [[self year] intValue];
if (_year > 0)
{
[self setHour: [_rq formValueForKey: [self hourSelectId]]];
[self setMinute: [_rq formValueForKey: [self minuteSelectId]]];
[self setTime: [_rq formValueForKey: [self timeID]]];
_month = [[self month] intValue];
_day = [[self day] intValue];
_hour = [[self hour] intValue];
_minute = [[self minute] intValue];
_second = [[self second] intValue];
_time = [[self time] componentsSeparatedByString: @":"];
_hour = [[_time objectAtIndex: 0] intValue];
_minute = [[_time objectAtIndex: 1] intValue];
// _second = [[self second] intValue];
ud = [[context activeUser] userDefaults];
d = [NSCalendarDate dateWithYear: _year month: _month day: _day
hour: _hour minute: _minute second: _second
hour: _hour minute: _minute second: 0
timeZone: [ud timeZone]];
[self _setDate: d];
}

View File

@ -12,7 +12,7 @@
title="name"
var:toolbar="toolbar"
const:cssFiles="UIxComponentEditor.css"
const:jsFiles="skycalendar.js,UIxComponentEditor.js,SOGoAutoCompletion.js">
const:jsFiles="skycalendar.js,UIxComponentEditor.js,SOGoAutoCompletion.js,SOGoTimePicker.js">
<script type="text/javascript">
var activeCalendar = '<var:string value="componentCalendar.nameInContainer"/>';

View File

@ -16,58 +16,13 @@
var:disabled="disabled"
/>
<var:if condition="displayTimeControl">
<var:if condition="disabled">
<select var:shadow-value="hour"
var:id="hourSelectId" var:name="hourSelectId" const:disabled="disabled">
<var:foreach list="selectableHours" item="hourOption"
><var:if condition="isCurrentHour"
><option var:value="hourValue" selected="selected"
><var:string value="hourLabel"
/></option></var:if
><var:if condition="isCurrentHour" const:negate="YES"
><option var:value="hourValue"><var:string value="hourLabel"
/></option></var:if>
</var:foreach
></select>
<select var:shadow-value="minute"
var:id="minuteSelectId" var:name="minuteSelectId" const:disabled="disabled">
<var:foreach list="selectableMinutes" item="minuteOption"
><var:if condition="isCurrentMinute"
><option var:value="minuteValue" selected="selected"
><var:string value="minuteLabel"
/></option></var:if
><var:if condition="isCurrentMinute" const:negate="YES"
><option var:value="minuteValue"
><var:string value="minuteLabel"
/></option></var:if>
</var:foreach
></select>
</var:if
><var:if condition="disabled" const:negate="YES">
<select var:shadow-value="hour" var:id="hourSelectId" var:name="hourSelectId">
<var:foreach list="selectableHours" item="hourOption"
><var:if condition="isCurrentHour"
><option var:value="hourValue" selected="selected"
><var:string value="hourLabel"
/></option></var:if
><var:if condition="isCurrentHour" const:negate="YES"
><option var:value="hourValue"><var:string value="hourLabel"
/></option></var:if>
</var:foreach
></select>
<select var:shadow-value="minute" var:id="minuteSelectId" var:name="minuteSelectId">
<var:foreach list="selectableMinutes" item="minuteOption"
><var:if condition="isCurrentMinute"
><option var:value="minuteValue" selected="selected"
><var:string value="minuteLabel"
/></option></var:if
><var:if condition="isCurrentMinute" const:negate="YES"
><option var:value="minuteValue"
><var:string value="minuteLabel"
/></option></var:if>
</var:foreach
></select>
</var:if>
<input type="text"
var:disabled="disabled"
class="textField"
var:id="timeID"
var:name="timeID"
var:shadow-value="time"
var:value="time"
size="5"/>
</var:if>
</span>

View File

@ -178,11 +178,11 @@ Date.prototype.getHourString = function() {
};
Date.prototype.getDisplayHoursString = function() {
var hoursString = "" + this.getUTCHours();
var hoursString = "" + this.getHours();
if (hoursString.length == 1)
hoursString = '0' + hoursString;
var minutesString = "" + this.getUTCMinutes();
var minutesString = "" + this.getMinutes();
if (minutesString.length == 1)
minutesString = '0' + minutesString;

View File

@ -0,0 +1,220 @@
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* Time picker widget interface to be added to an INPUT (this!)
*
* Available events:
* time:change -- fired once the value of the input has changed
*
*/
var SOGoTimePickerInterface = {
div: null,
extendedButton: null,
minutes: '00',
hours: '00',
extended: false,
mouseInside: false,
disposeHandler: null,
bind: function () {
// Build widget
this.div = new Element("div", {'class': 'SOGoTimePickerMenu'});
this.div.hide();
document.body.appendChild(this.div);
var inner = new Element("div");
this.div.appendChild(inner);
var hours = new Element("div", {'class': 'hours'});
inner.appendChild(hours);
for (var i = 0; i < 24; i++) {
var v = (i < 10)? '0' + i : i;
var content = new Element("div", {'class': 'SOGoTimePickerHour_'+v}).update(v);
content.on("click", this.onHourClick.bindAsEventListener(this));
var span = new Element("span", {'class': 'cell'});
span.appendChild(content);
hours.appendChild(span);
if (i == 11) {
hours = new Element("div", {'class': 'hours'});
inner.appendChild(hours);
}
}
var minutes = new Element("div", {'class': 'minutes min5'});
inner.appendChild(minutes);
for (var i = 0; i < 60; i += 5) {
var v = (i < 10)? '0' + i : i;
var content = new Element("div", {'class': 'SOGoTimePickerMinute_'+v}).update(":"+v);
content.on("click", this.onMinuteClick.bindAsEventListener(this));
var span = new Element("span", {'class': 'cell'});
span.appendChild(content);
minutes.appendChild(span);
if (i == 25) {
minutes = new Element("div", {'class': 'minutes min5'});
inner.appendChild(minutes);
}
}
var minutes = new Element("div", {'class': 'minutes min1'});
minutes.hide();
inner.appendChild(minutes);
for (var i = 0; i < 60;) {
var v = (i < 10)? '0' + i : i;
var content = new Element("div", {'class': 'SOGoTimePickerMinute_'+v}).update(":"+v);
content.on("click", this.onMinuteClick.bindAsEventListener(this));
var span = new Element("span", {'class': 'cell'});
span.appendChild(content);
minutes.appendChild(span);
i++;
if (i % 5 == 0) {
minutes = new Element("div", {'class': 'minutes min1'});
minutes.hide();
inner.appendChild(minutes);
}
}
var a = new Element("a", {'class': 'button'});
a.on("click", this.toggleExtendedView.bindAsEventListener(this));
this.extendedButton = new Element("span").update('&gt;&gt;');
a.appendChild(this.extendedButton);
inner.appendChild(a);
inner.appendChild(new Element("hr"));
// Compute position
var inputPosition = this.cumulativeOffset();
var inputDimensions = this.getDimensions();
var divWidth = this.div.getWidth();
var windowWidth = window.width();
var left = inputPosition[0];
var arrow = -1000 + inputDimensions['width'] - 10;
if (left + divWidth > windowWidth) {
left = windowWidth - divWidth - 2;
arrow += (inputPosition[0] - left);
}
//var top = inputPosition[1] + parseInt(inputDimensions['height']/2);
var top = inputPosition[1] + 12;
this.div.setStyle({ top: top+"px",
left: left+"px",
backgroundPosition: arrow+'px top'});
// Register observers
this.on("click", this.toggleVisibility.bindAsEventListener(this));
this.on("change", this.onChange.bindAsEventListener(this));
this.on("keydown", this.onKeydown.bindAsEventListener(this));
this.div.on("mouseenter", this.onEnter.bindAsEventListener(this));
this.div.on("mouseleave", this.onLeave.bindAsEventListener(this));
this.disposeHandler = $(document.body).on("click", this.onDispose.bindAsEventListener(this));
this.disposeHandler.stop();
// Apply current input value if defined
this.onChange();
},
onHourClick: function (event) {
this.div.down('.SOGoTimePickerHour_' + this.hours).removeClassName("selected");
this.hours = Event.findElement(event).className.substring(19);
this.div.down('.SOGoTimePickerHour_' + this.hours).addClassName("selected");
this._updateValue();
},
onMinuteClick: function (event) {
this.div.select('.SOGoTimePickerMinute_' + this.minutes).each(function(e) { e.removeClassName("selected") });
this.minutes = Event.findElement(event).className.substring(21);
this.div.select('.SOGoTimePickerMinute_' + this.minutes).each(function(e) { e.addClassName("selected") });
this._updateValue();
this.div.hide();
},
toggleExtendedView: function (event) {
this.extended = !this.extended;
if (this.extended) {
this.extendedButton.update('&lt;&lt;');
this.div.select("DIV.min5").invoke('hide');
this.div.select("DIV.min1").invoke('show');
}
else {
this.extendedButton.update('&gt;&gt;');
this.div.select("DIV.min1").invoke('hide');
this.div.select("DIV.min5").invoke('show');
}
},
toggleVisibility: function (event) {
if (this.div.visible())
this.div.hide();
else {
$$('DIV.SOGoTimePickerMenu').invoke('hide');
this.div.show();
this.disposeHandler.start();
}
Event.stop(event);
},
onChange: function (event) {
this.div.down('.SOGoTimePickerHour_' + this.hours).removeClassName("selected");
this.div.select('.SOGoTimePickerMinute_' + this.minutes).each(function(e) { e.removeClassName("selected") });
var matches = this.value.match(/([0-9]+):([0-9]+)/);
if (matches) {
this.hours = matches[1];
this.minutes = matches[2];
if (parseInt(this.hours) > 23) this.hours = 23;
if (parseInt(this.minutes) > 59) this.minutes = 59;
if (this.minutes % 5 == 0) {
if (this.extended)
this.toggleExtendedView();
}
else if (!this.extended)
this.toggleExtendedView();
if (this.hours.length < 2) this.hours = '0' + this.hours;
if (this.minutes.length < 2) this.minutes = '0' + this.minutes;
this.div.down('.SOGoTimePickerHour_' + this.hours).addClassName("selected");
this.div.select('.SOGoTimePickerMinute_' + this.minutes).each(function(e) { e.addClassName("selected") });
}
this._updateValue();
},
onKeydown: function (event) {
this.div.hide();
this.disposeHandler.stop();
if (event.metaKey == 1 || event.ctrlKey == 1 ||
event.keyCode == Event.KEY_TAB)
return true;
if (event.keyCode > 57 && event.keyCode != 186 ||
event.keyCode == 186 && this.value.indexOf(":") >= 0 ||
event.keyCode != Event.KEY_BACKSPACE && this.value.length > 4) {
Event.stop(event);
}
},
onEnter: function (event) {
this.mouseInside = true;
this.disposeHandler.stop();
},
onLeave: function (event) {
this.mouseInside = false;
this.disposeHandler.start();
},
onDispose: function (event) {
if (!this.mouseInside) {
this.div.hide();
this.disposeHandler.stop();
Event.stop(event);
}
},
_updateValue: function () {
var value = this.hours + ':' + this.minutes;
if (value != this.value) {
this.value = value;
this.fire("time:change");
}
}
};

View File

@ -77,23 +77,38 @@ function validateAptEditor() {
}
else if (tmpdate == null /* means: same date */) {
// TODO: check time
var start, end;
var startHour, startMinute, endHour, endMinute;
var matches;
start = parseInt(document.forms[0]['startTime_time_hour'].value);
end = parseInt(document.forms[0]['endTime_time_hour'].value);
matches = document.forms[0]['startTime_time'].value.match(/([0-9]+):([0-9]+)/);
if (matches) {
startHour = parseInt(matches[1]);
startMinute = parseInt(matches[2]);
matches = document.forms[0]['endTime_time'].value.match(/([0-9]+):([0-9]+)/);
if (matches) {
endHour = parseInt(matches[1]);
endMinute = parseInt(matches[2]);
if (start > end) {
alert(labels.validate_endbeforestart);
return false;
}
else if (start == end) {
start = parseInt(document.forms[0]['startTime_time_minute'].value);
end = parseInt(document.forms[0]['endTime_time_minute'].value);
if (start > end) {
alert(labels.validate_endbeforestart);
if (startHour > endHour) {
alert(labels.validate_endbeforestart);
return false;
}
else if (startHour == endHour) {
if (startMinute > endMinute) {
alert(labels.validate_endbeforestart);
return false;
}
}
}
else {
alert(labels.validate_invalid_enddate);
return false;
}
}
else {
alert(labels.validate_invalid_startdate);
return false;
}
}
AIM.submit($(document.editform), {'onComplete' : onEventPostComplete});
@ -212,18 +227,18 @@ function endDayAsShortString() {
function _getDate(which) {
var date = window.timeWidgets[which]['date'].inputAsDate();
date.setHours( window.timeWidgets[which]['hour'].value );
date.setMinutes( window.timeWidgets[which]['minute'].value );
var time = window.timeWidgets[which]['time'].value.split(":");
date.setHours(time[0]);
date.setMinutes(time[1]);
return date;
}
function _getShadowDate(which) {
var date = window.timeWidgets[which]['date'].getAttribute("shadow-value").asDate();
var intValue = parseInt(window.timeWidgets[which]['hour'].getAttribute("shadow-value"));
date.setHours(intValue);
intValue = parseInt(window.timeWidgets[which]['minute'].getAttribute("shadow-value"));
date.setMinutes(intValue);
var time = window.timeWidgets[which]['time'].getAttribute("shadow-value").split(":");
date.setHours(time[0]);
date.setMinutes(time[1]);
return date;
}
@ -246,11 +261,7 @@ function getShadowEndDate() {
function _setDate(which, newDate) {
window.timeWidgets[which]['date'].setInputAsDate(newDate);
window.timeWidgets[which]['hour'].value = newDate.getHours();
var minutes = newDate.getMinutes();
if (minutes % 15)
minutes += (15 - minutes % 15);
window.timeWidgets[which]['minute'].value = minutes;
window.timeWidgets[which]['time'].value = newDate.getDisplayHoursString();
}
function setStartDate(newStartDate) {
@ -273,11 +284,9 @@ function onAdjustTime(event) {
window.setEndDate(newEndDate);
window.timeWidgets['end']['date'].updateShadowValue();
window.timeWidgets['end']['hour'].updateShadowValue();
window.timeWidgets['end']['minute'].updateShadowValue();
window.timeWidgets['end']['time'].updateShadowValue();
window.timeWidgets['start']['date'].updateShadowValue();
window.timeWidgets['start']['hour'].updateShadowValue();
window.timeWidgets['start']['minute'].updateShadowValue();
window.timeWidgets['start']['time'].updateShadowValue();
}
else {
// End date was changed
@ -288,17 +297,15 @@ function onAdjustTime(event) {
window.setEndDate(oldEndDate);
window.timeWidgets['end']['date'].updateShadowValue();
window.timeWidgets['end']['hour'].updateShadowValue();
window.timeWidgets['end']['minute'].updateShadowValue();
window.timeWidgets['end']['time'].updateShadowValue();
window.timeWidgets['end']['time'].onChange(); // method from SOGoTimePicker
}
}
}
function onAllDayChanged(event) {
for (var type in window.timeWidgets) {
window.timeWidgets[type]['hour'].disabled = this.checked;
window.timeWidgets[type]['minute'].disabled = this.checked;
}
for (var type in window.timeWidgets)
window.timeWidgets[type]['time'].disabled = this.checked;
}
function initTimeWidgets(widgets) {
@ -306,14 +313,14 @@ function initTimeWidgets(widgets) {
if (widgets['start']['date']) {
widgets['start']['date'].observe("change", this.onAdjustTime, false);
widgets['start']['hour'].observe("change", this.onAdjustTime, false);
widgets['start']['minute'].observe("change", this.onAdjustTime, false);
widgets['start']['time'].observe("time:change", this.onAdjustTime, false);
widgets['start']['time'].addInterface(SOGoTimePickerInterface);
}
if (widgets['end']['date']) {
widgets['end']['date'].observe("change", this.onAdjustTime, false);
widgets['end']['hour'].observe("change", this.onAdjustTime, false);
widgets['end']['minute'].observe("change", this.onAdjustTime, false);
widgets['end']['time'].observe("time:change", this.onAdjustTime, false);
widgets['end']['time'].addInterface(SOGoTimePickerInterface);
}
var allDayLabel = $("allDay");
@ -321,10 +328,8 @@ function initTimeWidgets(widgets) {
var input = $(allDayLabel).childNodesWithTag("input")[0];
input.observe("change", onAllDayChanged.bindAsEventListener(input));
if (input.checked) {
for (var type in widgets) {
widgets[type]['hour'].disabled = true;
widgets[type]['minute'].disabled = true;
}
for (var type in widgets)
widgets[type]['time'].disabled = true;
}
}
}
@ -375,15 +380,15 @@ function refreshAttendees(newAttendees) {
if (attendees.keys().length > 0) {
// Update attendees link and show label
var names = new Array();
var names = new Array();
attendees.values().each(function(attendee) {
attendee = $H(attendee);
var name = attendee.get('name') || attendee.get('email');
if (!attendee.get('delegated-to'))
var delegatedTo = attendee.get('delegated-to');
if (!delegatedTo)
names.push(name);
if (attendeesMenu) {
var delegatedTo = attendee.get('delegated-to');
if (!attendee.get('delegated-from') || delegatedTo) {
var node = createElement("li");
attendeesMenu.appendChild(node);
@ -475,11 +480,9 @@ function onAppointmentEditorLoad() {
assignCalendar('endTime_date');
var widgets = {'start': {'date': $("startTime_date"),
'hour': $("startTime_time_hour"),
'minute': $("startTime_time_minute")},
'time': $("startTime_time")},
'end': {'date': $("endTime_date"),
'hour': $("endTime_time_hour"),
'minute': $("endTime_time_minute")}};
'time': $("endTime_time")}};
initTimeWidgets(widgets);
}

View File

@ -14,8 +14,9 @@ A#changeAttachButton
right: 0;
display: inline; }
SPAN.datePicker INPUT.textField
{ width: 7em; }
SPAN.datePicker INPUT.textField,
SPAN.timeDateControl INPUT.textField
{ width: 7em; }
SPAN.timeDateControl A.button
{ border: 0; }
@ -131,3 +132,69 @@ SPAN.timeDateControl INPUT,
SPAN.timeDateControl SELECT,
SPAN.timeDateControl SPAN
{ vertical-align: top; }
/* SOGoTimePicker */
.SOGoTimePickerMenu
{ position: absolute;
z-index: 1000;
background-image: url("dialog-top.png");
background-repeat: no-repeat;
color: #000;
font-family: sans-serif;
font-size: 11px;
text-align: center; }
.SOGoTimePickerMenu > DIV
{ background-color: #fff;
border: 1px solid #444;
border-top: 0px;
margin-top: 19px;
padding: 5px; }
.SOGoTimePickerMenu SPAN DIV
{ padding: 2px; }
.SOGoTimePickerMenu DIV.hours SPAN
{ float: left;
width: 25px; }
.SOGoTimePickerMenu DIV.hours SPAN DIV
{ background-color: #ddd;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc; }
.SOGoTimePickerMenu DIV.min5 SPAN
{ float: left;
width: 50px; }
.SOGoTimePickerMenu DIV.min1 SPAN
{ float: left;
width: 60px; }
.SOGoTimePickerMenu DIV.minutes SPAN DIV
{ border-right: 1px solid #fff;
border-bottom: 1px solid #fff; }
.SOGoTimePickerMenu DIV.hours SPAN DIV:hover,
.SOGoTimePickerMenu DIV.minutes SPAN DIV:hover
{ background-color: #eee;
border-right: 1px solid #eee;
border-bottom: 1px solid #eee;
color: #333;
cursor: pointer; }
.SOGoTimePickerMenu DIV.hours SPAN DIV.selected,
.SOGoTimePickerMenu DIV.minutes SPAN DIV.selected
{ background-color: #9ABCD8;
border-right: 1px solid #9ABCD8;
border-bottom: 1px solid #9ABCD8;
color: #fff; }
.SOGoTimePickerMenu HR
{ clear: both;
height: 0px;
margin: 0px;
padding: 0px;
color: #fff;
border: 0px; }

View File

@ -4,16 +4,13 @@ var contactSelectorAction = 'calendars-contacts';
function uixEarlierDate(date1, date2) {
// can this be done in a sane way?
// cuicui = 'year';
if (date1 && date2) {
if (date1.getYear() < date2.getYear()) return date1;
if (date1.getYear() > date2.getYear()) return date2;
// same year
// cuicui += '/month';
if (date1.getMonth() < date2.getMonth()) return date1;
if (date1.getMonth() > date2.getMonth()) return date2;
// // same month
// cuicui += '/date';
// same month
if (date1.getDate() < date2.getDate()) return date1;
if (date1.getDate() > date2.getDate()) return date2;
}
@ -65,23 +62,39 @@ function validateTaskEditor() {
}
else if (tmpdate == null /* means: same date */) {
// TODO: check time
var start, end;
start = parseInt(document.forms[0]['startTime_time_hour'].value);
end = parseInt(document.forms[0]['dueTime_time_hour'].value);
if (start > end) {
alert(labels.validate_endbeforestart);
return false;
}
else if (start == end) {
start = parseInt(document.forms[0]['startTime_time_minute'].value);
end = parseInt(document.forms[0]['dueTime_time_minute'].value);
if (start > end) {
alert(labels.validate_endbeforestart);
return false;
var startHour, startMinute, endHour, endMinute;
var matches;
matches = document.forms[0]['startTime_time'].value.match(/([0-9]+):([0-9]+)/);
if (matches) {
startHour = parseInt(matches[1]);
startMinute = parseInt(matches[2]);
matches = document.forms[0]['dueTime_time'].value.match(/([0-9]+):([0-9]+)/);
if (matches) {
endHour = parseInt(matches[1]);
endMinute = parseInt(matches[2]);
if (startHour > endHour) {
alert(labels.validate_endbeforestart);
return false;
}
else if (startHour == endHour) {
if (startMinute > endMinute) {
alert(labels.validate_endbeforestart);
return false;
}
}
}
else {
alert(labels.validate_invalid_enddate);
return false;
}
}
else {
alert(labels.validate_invalid_startdate);
return false;
}
}
}
}
@ -187,19 +200,18 @@ function dueDayAsShortString() {
this._getDate = function(which) {
var date = window.timeWidgets[which]['date'].inputAsDate();
date.setHours( window.timeWidgets[which]['hour'].value );
date.setMinutes( window.timeWidgets[which]['minute'].value );
var time = window.timeWidgets[which]['time'].value.split(":");
date.setHours(time[0]);
date.setMinutes(time[1]);
return date;
};
this._getShadowDate = function(which) {
var date = window.timeWidgets[which]['date'].getAttribute("shadow-value").asDate();
var intValue = parseInt(window.timeWidgets[which]['hour'].getAttribute("shadow-value"));
date.setHours(intValue);
intValue = parseInt(window.timeWidgets[which]['minute'].getAttribute("shadow-value"));
date.setMinutes(intValue);
// window.alert("shadow: " + date);
var time = window.timeWidgets[which]['time'].getAttribute("shadow-value").split(":");
date.setHours(time[0]);
date.setMinutes(time[1]);
return date;
};
@ -222,11 +234,7 @@ this.getShadowDueDate = function() {
this._setDate = function(which, newDate) {
window.timeWidgets[which]['date'].setInputAsDate(newDate);
window.timeWidgets[which]['hour'].value = newDate.getHours();
var minutes = newDate.getMinutes();
if (minutes % 15)
minutes += (15 - minutes % 15);
window.timeWidgets[which]['minute'].value = minutes;
window.timeWidgets[which]['time'].value = newDate.getDisplayHoursString();
};
this.setStartDate = function(newStartDate) {
@ -250,16 +258,16 @@ this.onAdjustDueTime = function(event) {
window.setDueDate(newDueDate);
}
window.timeWidgets['start']['date'].updateShadowValue();
window.timeWidgets['start']['hour'].updateShadowValue();
window.timeWidgets['start']['minute'].updateShadowValue();
window.timeWidgets['start']['time'].updateShadowValue();
};
this.initTimeWidgets = function (widgets) {
this.timeWidgets = widgets;
widgets['start']['date'].observe("change", this.onAdjustDueTime, false);
widgets['start']['hour'].observe("change", this.onAdjustDueTime, false);
widgets['start']['minute'].observe("change", this.onAdjustDueTime, false);
widgets['start']['time'].observe("time:change", this.onAdjustDueTime, false);
widgets['start']['time'].addInterface(SOGoTimePickerInterface);
widgets['due']['time'].addInterface(SOGoTimePickerInterface);
};
function onStatusListChange(event) {
@ -308,11 +316,9 @@ function onTaskEditorLoad() {
if (readOnly == false) {
var widgets = {'start': {'date': $("startTime_date"),
'hour': $("startTime_time_hour"),
'minute': $("startTime_time_minute")},
'time': $("startTime_time")},
'due': {'date': $("dueTime_date"),
'hour': $("dueTime_time_hour"),
'minute': $("dueTime_time_minute")}};
'time': $("dueTime_time")}};
initTimeWidgets(widgets);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

View File

@ -206,4 +206,9 @@ DIV#filtersListWrapper
{ overflow-x: hidden; }
TABLE#filtersList
{ width: auto; }
{ width: auto; }
/* UIxComponentEditor */
.SOGoTimePickerMenu > DIV
{ width: 310px; }