Improved read-only tasks/events web view

Monotone-Parent: af17dd6e983493b4bd201d8d0a23bdac014fa84c
Monotone-Revision: 08f744da20c99e50446879fca5f5ee8194b2217b

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2009-07-29T18:46:44
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Francis Lachapelle 2009-07-29 18:46:44 +00:00
parent d7a9423108
commit 1cc51af9ef
11 changed files with 266 additions and 175 deletions

View File

@ -1,3 +1,26 @@
2009-07-29 Francis Lachapelle <flachapelle@inverse.ca>
* UI/Scheduler/UIxTaskEditor.m ([UIxTaskEditor
-taskStartDateTimeText]): new method to return a localized
description of the start date and time.
([UIxTasEditor -taskDueDateTimeText]): idem for the due date and
time.
([UIxTaskEditor -statusDateText]): idem for the status (task
completed) date.
* UI/Scheduler/UIxComponentEditor.m ([UIxComponentEditor -reply]):
the participation status of the calendar's owner is now returned
instead of the participation status of the active user.
([UIxComponentEditor -getDateFor:]): deleted, no longer needed.
* UI/Scheduler/UIxAppointmentEditor.m ([UIxAppointmentEditor
-aptStartDateText]): new method to return a localized description
of the start date.
([UIxAppointmentEditor -aptStartDateTimeText]): idem for the start
date and time.
([UIxAppointmentEditor -aptEndDateTimeText]): idem for the end
date and time.
2009-07-29 Cyril Robert <crobert@inverse.ca>
* SoObjects/Contacts/SOGoContactGCSFolder.m: Added c_o as a search field.

View File

@ -1,6 +1,6 @@
/* UIxAppointmentEditor.h - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
* Copyright (C) 2007-2009 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
@ -31,11 +31,12 @@
@interface UIxAppointmentEditor : UIxComponent
{
iCalEvent *event;
SOGoAppointmentFolder *componentCalendar;
BOOL isAllDay, isTransparent;
NSCalendarDate *aptStartDate;
NSCalendarDate *aptEndDate;
NSString *item;
SOGoAppointmentFolder *componentCalendar;
SOGoDateFormatter *dateFormatter;
}
/* template values */
@ -55,6 +56,10 @@
- (void) setAptEndDate: (NSCalendarDate *) newAptEndDate;
- (NSCalendarDate *) aptEndDate;
- (NSString *) aptStartDateText;
- (NSString *) aptStartDateTimeText;
- (NSString *) aptEndDateTimeText;
@end
#endif /* UIXAPPOINTMENTEDITOR_H */

View File

@ -1,6 +1,6 @@
/* UIxAppointmentEditor.m - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
* Copyright (C) 2007-2009 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
@ -59,6 +59,8 @@
- (id) init
{
SOGoUser *user;
if ((self = [super init]))
{
aptStartDate = nil;
@ -68,6 +70,9 @@
isAllDay = NO;
isTransparent = NO;
componentCalendar = nil;
user = [[self context] activeUser];
ASSIGN (dateFormatter, [user dateFormatterInContext: context]);
}
return self;
@ -79,6 +84,7 @@
[[event parent] release];
[aptStartDate release];
[aptEndDate release];
[dateFormatter release];
[componentCalendar release];
[super dealloc];
}
@ -167,6 +173,22 @@
ASSIGN (componentCalendar, _componentCalendar);
}
/* read-only event */
- (NSString *) aptStartDateText
{
return [dateFormatter formattedDate: aptStartDate];
}
- (NSString *) aptStartDateTimeText
{
return [dateFormatter formattedDateAndTime: aptStartDate];
}
- (NSString *) aptEndDateTimeText
{
return [dateFormatter formattedDateAndTime: aptEndDate];
}
/* actions */
- (NSCalendarDate *) newStartDate
{
@ -207,11 +229,14 @@
{
NSCalendarDate *startDate, *endDate;
NSString *duration;
NSTimeZone *timeZone;
unsigned int minutes;
SOGoObject <SOGoComponentOccurence> *co;
[self event];
co = [self clientObject];
timeZone = [[context activeUser] timeZone];
if ([co isNew]
&& [co isKindOfClass: [SOGoCalendarComponent class]])
{
@ -228,7 +253,6 @@
else
{
NSCalendarDate *firstDate;
NSTimeZone *timeZone;
iCalEvent *master;
signed int daylightOffset;
@ -241,7 +265,6 @@
// saving time with respect to the first occurrence of the recurrent event.
master = (iCalEvent*)[[event parent] firstChildWithTag: @"vevent"];
firstDate = [master startDate];
timeZone = [[context activeUser] timeZone];
if ([timeZone isDaylightSavingTimeForDate: startDate] != [timeZone isDaylightSavingTimeForDate: firstDate])
{
@ -259,7 +282,10 @@
isTransparent = ![event isOpaque];
}
[startDate setTimeZone: timeZone];
ASSIGN (aptStartDate, startDate);
[endDate setTimeZone: timeZone];
ASSIGN (aptEndDate, endDate);
return self;
@ -392,7 +418,6 @@
NSDictionary *data;
NSCalendarDate *firstDate, *eventDate;
NSTimeZone *timeZone;
SOGoDateFormatter *dateFormatter;
SOGoUser *user;
SOGoCalendarComponent *co;
iCalEvent *master;
@ -404,7 +429,6 @@
result = [self responseWithStatus: 200];
user = [context activeUser];
timeZone = [user timeZone];
dateFormatter = [user dateFormatterInContext: context];
eventDate = [event startDate];
[eventDate setTimeZone: timeZone];
co = [self clientObject];

View File

@ -978,8 +978,14 @@ iRANGE(2);
- (NSNumber *) reply
{
iCalPersonPartStat participationStatus;
LDAPUserManager *um;
NSString *owner, *ownerEmail;
participationStatus = [[component findParticipant: [context activeUser]] participationStatus];
um = [LDAPUserManager sharedUserManager];
owner = [componentCalendar ownerInContext: context];
ownerEmail = [um getEmailForUID: owner];
// We assume the owner is part of the participants
participationStatus = [[component findParticipantWithEmail: (id)ownerEmail] participationStatus];
return [NSNumber numberWithInt: participationStatus];
}
@ -2050,49 +2056,4 @@ RANGE(2);
return [self getEventRWType] == 1;
}
- (NSCalendarDate *) getDateFor: (NSString *) when
{
NSCalendarDate *startDate, *endDate, *firstDate, *rc;
NSTimeZone *timeZone;
iCalEvent *master;
signed int daylightOffset;
startDate = [component startDate];
daylightOffset = 0;
if ([component isKindOfClass: [SOGoAppointmentOccurence class]])
{
master = (iCalEvent*)[[component parent] firstChildWithTag: @"vevent"];
firstDate = [master startDate];
timeZone = [[context activeUser] timeZone];
if ([timeZone isDaylightSavingTimeForDate: startDate] != [timeZone isDaylightSavingTimeForDate: firstDate])
{
daylightOffset = (signed int)[timeZone secondsFromGMTForDate: firstDate]
- (signed int)[timeZone secondsFromGMTForDate: startDate];
startDate = [startDate dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:daylightOffset];
}
}
[startDate setTimeZone: [[context activeUser] timeZone]];
endDate = [[component endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:daylightOffset];
[endDate setTimeZone: [[context activeUser] timeZone]];
if ([when isEqualToString: @"start"])
rc = startDate;
else
rc = endDate;
return rc;
}
- (NSString *) startDateString
{
return [[self getDateFor: @"start"] description];
}
- (NSString *) endDateString
{
return [[self getDateFor: @"end"] description];
}
@end

View File

@ -1,6 +1,6 @@
/* UIxTaskEditor.h - this file is part of SOGo
*
* Copyright (C) 2007 Inverse inc.
* Copyright (C) 2007-2009 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
@ -39,6 +39,7 @@
BOOL hasStartDate;
BOOL hasDueDate;
NSString *item;
SOGoDateFormatter *dateFormatter;
}
/* template values */
@ -52,6 +53,10 @@
- (void) setTaskDueDate: (NSCalendarDate *) _date;
- (NSCalendarDate *) taskDueDate;
- (NSString *) taskStartDateTimeText;
- (NSString *) taskDueDateTimeText;
- (NSString *) statusDateText;
@end
#endif /* UIXAPPOINTMENTEDITOR_H */

View File

@ -50,6 +50,8 @@
- (id) init
{
SOGoUser *user;
if ((self = [super init]))
{
taskStartDate = nil;
@ -61,6 +63,9 @@
statusPercent = nil;
item = nil;
todo = nil;
user = [[self context] activeUser];
ASSIGN (dateFormatter, [user dateFormatterInContext: context]);
}
return self;
@ -73,6 +78,7 @@
[statusDate release];
[status release];
[statusPercent release];
[dateFormatter release];
[[todo parent] release];
[super dealloc];
}
@ -165,6 +171,12 @@
- (NSString *) itemStatusText
{
if (!item)
{
item = status;
if (!item)
item = @"NOT-SPECIFIED";
}
return [self labelForKey: [NSString stringWithFormat: @"status_%@", item]];
}
@ -219,6 +231,23 @@
return statusPercent;
}
/* viewing read-only tasks */
- (NSString *) taskStartDateTimeText
{
return [dateFormatter formattedDateAndTime: taskStartDate];
}
- (NSString *) taskDueDateTimeText
{
return [dateFormatter formattedDateAndTime: taskDueDate];
}
- (NSString *) statusDateText
{
return [dateFormatter formattedDate: statusDate];
}
/* actions */
- (NSCalendarDate *) newStartDate
{
@ -259,20 +288,27 @@
{
NSCalendarDate *startDate, *dueDate;
NSString *duration;
NSTimeZone *timeZone;
unsigned int minutes;
[self todo];
if (todo)
{
timeZone = [[context activeUser] timeZone];
startDate = [todo startDate];
dueDate = [todo due];
hasStartDate = (startDate != nil);
hasDueDate = (dueDate != nil);
ASSIGN (status, [todo status]);
if ([status isEqualToString: @"COMPLETED"])
ASSIGN (statusDate, [todo completed]);
{
ASSIGN (statusDate, [todo completed]);
[statusDate setTimeZone: timeZone];
}
else
ASSIGN (statusDate, [self newStartDate]);
{
ASSIGN (statusDate, [self newStartDate]);
}
ASSIGN (statusPercent, [todo percentComplete]);
}
else
@ -292,7 +328,10 @@
ASSIGN (statusPercent, @"");
}
[startDate setTimeZone: timeZone];
ASSIGN (taskStartDate, startDate);
[dueDate setTimeZone: timeZone];
ASSIGN (taskDueDate, dueDate);
/* here comes the code for initializing repeat, reminder and isAllDay... */
@ -389,7 +428,6 @@
NSDictionary *data;
NSCalendarDate *startDate, *dueDate;
NSTimeZone *timeZone;
SOGoDateFormatter *dateFormatter;
SOGoUser *user;
BOOL resetAlarm;
@ -398,7 +436,6 @@
result = [self responseWithStatus: 200];
user = [context activeUser];
timeZone = [user timeZone];
dateFormatter = [user dateFormatterInContext: context];
startDate = [todo startDate];
[startDate setTimeZone: timeZone];
dueDate = [todo due];

View File

@ -9,9 +9,11 @@
xmlns:label="OGo:label"
className="UIxComponentEditor"
componentCalendar="componentCalendar"
eventIsReadOnly="eventIsReadOnly"
var:component="event"
var:saveURL="saveURL">
<var:if condition="eventIsReadOnly" const:negate="YES">
<div class="menu" id="attendeesMenu">
<ul>
<li><var:string label:value="Invite Attendees"/>...</li>
@ -21,7 +23,6 @@
<li class="separator"><!-- separator --></li>
</ul>
</div>
<label><span class="content">
<span id="allDay"><input id="isAllDay" name="isAllDay" class="checkBox"
type="checkbox" var:selection="isAllDay"
@ -48,4 +49,25 @@
var:checked="isTransparent"
/> <var:string label:value="Show Time as Free"
/></span></span></label>
</var:if>
<var:if condition="eventIsReadOnly">
<var:if condition="isAllDay">
<label><var:string label:value="Start:" />
<span class="content"><var:string var:value="aptStartDateText"/> (<var:string label:value="All day Event"/>)</span>
</label>
</var:if>
<var:if condition="isAllDay" const:negate="YES">
<label><var:string label:value="Start:" />
<span class="content"><var:string var:value="aptStartDateTimeText" /></span>
</label>
<label><var:string label:value="End:" />
<span class="content"><var:string var:value="aptEndDateTimeText" /></span>
</label>
</var:if>
<var:if condition="isTransparent">
<label><span class="content">
<span id="isTransparent"><var:string label:value="Show Time as Free"
/></span></span></label>
</var:if>
</var:if>
</var:component>

View File

@ -42,7 +42,7 @@
var:value="location"
/></span></label>
<span class="checkBoxList"><var:string label:value="Category:" />
<span class="content"><var:popup name="category" list="categoryList" item="item"
<span class="content"><var:popup list="categoryList" item="item"
label:noSelectionString="category_none"
string="item" selection="category"
/> <var:string label:value="Calendar:" />
@ -194,12 +194,7 @@
<span class="content"><var:string var:value="priority"/></span>
</label>
</var:if>
<label><var:string label:value="Start:" />
<span class="content"><var:string var:value="startDateString" /></span>
</label>
<label><var:string label:value="End:" />
<span class="content"><var:string var:value="endDateString" /></span>
</label>
<var:component-content />
<var:if condition="hasRepeat">
<label><var:string label:value="Repeat:" />
<span class="content"><var:string var:value="repeatLabel" /></span>
@ -325,8 +320,8 @@
<div id="windowButtons">
<a id="cancelButton" href="#" class="button"
><var:string label:value="Cancel"/></a>
<a id="okButton" href="#" class="button"
><var:string label:value="OK"/></a>
<var:if condition="userIsAttendee"><a id="okButton" href="#" class="button"
><var:string label:value="OK"/></a></var:if>
</div>
</div>
</var:if>

View File

@ -9,9 +9,11 @@
xmlns:label="OGo:label"
className="UIxComponentEditor"
componentCalendar="componentCalendar"
eventIsReadOnly="eventIsReadOnly"
var:component="todo"
var:saveURL="saveURL">
<var:if condition="eventIsReadOnly" const:negate="YES">
<span class="checkBoxList"><var:string label:value="Start:" />
<span class="content"><input var:checked="hasStartDate"
id="startDateCB" type="checkbox" class="checkBox"
@ -53,4 +55,23 @@
var:disabled="statusPercentDisabled"
/><var:string label:value="% complete"
/></span></span>
</var:if>
<var:if condition="eventIsReadOnly">
<var:if condition="hasStartDate">
<label><var:string label:value="Start:" />
<span class="content"><var:string var:value="taskStartDateTimeText" /></span>
</label>
</var:if>
<var:if condition="hasDueDate">
<label><var:string label:value="Due Date:" />
<span class="content"><var:string var:value="taskDueDateTimeText" /></span>
</label>
</var:if>
<span class="checkBoxList"><var:string label:value="Status:" />
<span class="content"><var:string var:value="itemStatusText"
/><var:if condition="statusDateDisabled" const:negate="YES"> <var:string var:value="statusDateText"/></var:if
><var:if condition="statusPercentDisabled" const:negate="YES"> (<var:string var:value="statusPercent"/> <var:string label:value="% complete"/>)</var:if>
</span></span>
</var:if>
</var:component>

View File

@ -122,19 +122,19 @@ A#attendeesHref
text-decoration: underline; }
DIV#attendeesMenu *
{ padding-left: 20px; }
{ cursor: pointer;
padding-left: 20px;
background-repeat: no-repeat;
background-position: 5px center; }
DIV#attendeesMenu *:hover
{ text-decoration: underline; }
DIV#attendeesMenu .accepted
{ background-image: url("accepted.png");
background-repeat: no-repeat;
background-position: 5px center; }
{ background-image: url("accepted.png"); }
DIV#attendeesMenu .needs-action
{ background-image: url("needs-action.png");
background-repeat: no-repeat;
background-position: 5px center; }
{ background-image: url("needs-action.png"); }
DIV#attendeesMenu .declined
{ background-image: url("declined.png");
background-repeat: no-repeat;
background-position: 5px center; }
{ background-image: url("declined.png"); }

View File

@ -122,61 +122,59 @@ function initializePrivacyMenu() {
}
function onComponentEditorLoad(event) {
initializeDocumentHref();
initializePrivacyMenu();
var list = $("calendarList");
if (list) {
list.observe("change", onChangeCalendar, false);
list.fire("mousedown");
}
if ($("itemPrivacyList")) {
var menuItems = $("itemPrivacyList").childNodesWithTag("li");
for (var i = 0; i < menuItems.length; i++)
menuItems[i].observe("mousedown",
onMenuSetClassification.bindAsEventListener(menuItems[i]),
false);
}
var tmp = $("repeatHref");
if (tmp)
tmp.observe("click", onPopupRecurrenceWindow);
tmp = $("repeatList");
if (tmp)
tmp.observe("change", onPopupRecurrenceWindow);
tmp = $("reminderHref");
if (tmp)
tmp.observe("click", onPopupReminderWindow);
tmp = $("reminderList");
if (tmp)
tmp.observe("change", onPopupReminderWindow);
tmp = $("summary");
if (tmp)
tmp.observe("keyup", onSummaryChange);
Event.observe(window, "resize", onWindowResize);
onPopupRecurrenceWindow(null);
onPopupReminderWindow(null);
onSummaryChange (null);
var summary = $("summary");
if (summary) {
initializeDocumentHref();
initializePrivacyMenu();
var list = $("calendarList");
if (list) {
list.observe("change", onChangeCalendar, false);
list.fire("mousedown");
}
if ($("itemPrivacyList")) {
var menuItems = $("itemPrivacyList").childNodesWithTag("li");
for (var i = 0; i < menuItems.length; i++)
menuItems[i].observe("mousedown",
onMenuSetClassification.bindAsEventListener(menuItems[i]),
false);
}
var tmp = $("repeatHref");
if (tmp)
tmp.observe("click", onPopupRecurrenceWindow);
tmp = $("repeatList");
if (tmp)
tmp.observe("change", onPopupRecurrenceWindow);
tmp = $("reminderHref");
if (tmp)
tmp.observe("click", onPopupReminderWindow);
tmp = $("reminderList");
if (tmp)
tmp.observe("change", onPopupReminderWindow);
tmp = $("summary");
if (tmp)
tmp.observe("keyup", onSummaryChange);
Event.observe(window, "resize", onWindowResize);
onPopupRecurrenceWindow(null);
onPopupReminderWindow(null);
onSummaryChange (null);
var summary = $("summary");
if (summary) {
summary.focus();
summary.selectText(0, summary.value.length);
}
tmp = $("okButton");
if (tmp)
tmp.observe ("click", onOkButtonClick);
tmp = $("cancelButton");
if (tmp)
tmp.observe ("click", onCancelButtonClick);
if (tmp)
window.resizeTo(430,540)
summary.selectText(0, summary.value.length);
}
tmp = $("okButton");
if (tmp)
tmp.observe ("click", onOkButtonClick);
tmp = $("cancelButton");
if (tmp)
tmp.observe ("click", onCancelButtonClick);
if (tmp)
window.resizeTo(430,540);
}
function onSummaryChange (e) {
@ -185,60 +183,60 @@ function onSummaryChange (e) {
}
function onWindowResize(event) {
var document = $("documentLabel");
var comment = $("commentArea");
if (comment) {
var document = $("documentLabel");
var comment = $("commentArea");
if (comment) {
var area = comment.select("textarea").first();
var offset = 6;
var height;
var height;
height = window.height() - comment.cumulativeOffset().top - offset;
if (document.visible()) {
if ($("changeAttachButton"))
if ($("changeAttachButton"))
height -= $("changeAttachButton").getHeight();
else
height -= $("documentHref").getHeight();
}
else
height -= $("documentHref").getHeight();
}
if (area)
area.setStyle({ height: (height - offset*2) + "px" });
if (area)
area.setStyle({ height: (height - offset*2) + "px" });
comment.setStyle({ height: (height - offset) + "px" });
}
else {
$("eventView").style.height = window.height () + "px";
var height = window.height() - 120;
var tmp = $("generalDiv");
if (tmp)
height -= tmp.offsetHeight;
tmp = $("descriptionDiv");
if (tmp)
height -= tmp.offsetHeight;
$("attendeesDiv").style.height = height + "px";
$("attendeesMenu").style.height = (height - 20) + "px";
}
return true;
}
else {
$("eventView").style.height = window.height () + "px";
var height = window.height() - 120;
var tmp = $("generalDiv");
if (tmp)
height -= tmp.offsetHeight;
tmp = $("descriptionDiv");
if (tmp)
height -= tmp.offsetHeight;
$("attendeesDiv").style.height = height + "px";
$("attendeesMenu").style.height = (height - 20) + "px";
}
return true;
}
function onPopupRecurrenceWindow(event) {
if (event)
preventDefault(event);
var repeatHref = $("repeatHref");
var repeatList = $("repeatList");
if (repeatList && repeatList.value == 7) {
repeatHref.show();
if (event)
window.open(ApplicationBaseURL + "editRecurrence", null,
"width=500,height=400");
}
else if (repeatHref)
repeatHref.hide();
return false;
preventDefault(event);
var repeatHref = $("repeatHref");
var repeatList = $("repeatList");
if (repeatList && repeatList.value == 7) {
repeatHref.show();
if (event)
window.open(ApplicationBaseURL + "editRecurrence", null,
"width=500,height=400");
}
else if (repeatHref)
repeatHref.hide();
return false;
}
function onPopupReminderWindow(event) {