From 1cc51af9efc202a2295ec7eb6b9c0ab005c7fd6b Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Wed, 29 Jul 2009 18:46:44 +0000 Subject: [PATCH] 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 --- ChangeLog | 23 +++ UI/Scheduler/UIxAppointmentEditor.h | 9 +- UI/Scheduler/UIxAppointmentEditor.m | 34 +++- UI/Scheduler/UIxComponentEditor.m | 53 +---- UI/Scheduler/UIxTaskEditor.h | 7 +- UI/Scheduler/UIxTaskEditor.m | 45 +++- .../SchedulerUI/UIxAppointmentEditor.wox | 24 ++- .../SchedulerUI/UIxComponentEditor.wox | 13 +- UI/Templates/SchedulerUI/UIxTaskEditor.wox | 21 ++ .../UIxAppointmentEditor.css | 20 +- UI/WebServerResources/UIxComponentEditor.js | 192 +++++++++--------- 11 files changed, 266 insertions(+), 175 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6adb055c2..96d4ecfee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2009-07-29 Francis Lachapelle + + * 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 * SoObjects/Contacts/SOGoContactGCSFolder.m: Added c_o as a search field. diff --git a/UI/Scheduler/UIxAppointmentEditor.h b/UI/Scheduler/UIxAppointmentEditor.h index 2052885b3..0dfd226ce 100644 --- a/UI/Scheduler/UIxAppointmentEditor.h +++ b/UI/Scheduler/UIxAppointmentEditor.h @@ -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 * @@ -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 */ diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index fb4dbfab5..f807c3ce9 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -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 * @@ -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 *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]; diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index aa063c4f4..7985adf25 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -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 diff --git a/UI/Scheduler/UIxTaskEditor.h b/UI/Scheduler/UIxTaskEditor.h index 68537a7fb..2deeaaf78 100644 --- a/UI/Scheduler/UIxTaskEditor.h +++ b/UI/Scheduler/UIxTaskEditor.h @@ -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 * @@ -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 */ diff --git a/UI/Scheduler/UIxTaskEditor.m b/UI/Scheduler/UIxTaskEditor.m index 73e002f26..ce442a1b3 100644 --- a/UI/Scheduler/UIxTaskEditor.m +++ b/UI/Scheduler/UIxTaskEditor.m @@ -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]; diff --git a/UI/Templates/SchedulerUI/UIxAppointmentEditor.wox b/UI/Templates/SchedulerUI/UIxAppointmentEditor.wox index 5c3bd4f64..73cf2eafb 100644 --- a/UI/Templates/SchedulerUI/UIxAppointmentEditor.wox +++ b/UI/Templates/SchedulerUI/UIxAppointmentEditor.wox @@ -9,9 +9,11 @@ xmlns:label="OGo:label" className="UIxComponentEditor" componentCalendar="componentCalendar" + eventIsReadOnly="eventIsReadOnly" var:component="event" var:saveURL="saveURL"> + - + + + + + + + + + + + + + diff --git a/UI/Templates/SchedulerUI/UIxComponentEditor.wox b/UI/Templates/SchedulerUI/UIxComponentEditor.wox index fb97c9a1d..22c7fabe4 100644 --- a/UI/Templates/SchedulerUI/UIxComponentEditor.wox +++ b/UI/Templates/SchedulerUI/UIxComponentEditor.wox @@ -42,7 +42,7 @@ var:value="location" /> - @@ -194,12 +194,7 @@ - - + diff --git a/UI/Templates/SchedulerUI/UIxTaskEditor.wox b/UI/Templates/SchedulerUI/UIxTaskEditor.wox index 4fe1d9d7a..5f4a305de 100644 --- a/UI/Templates/SchedulerUI/UIxTaskEditor.wox +++ b/UI/Templates/SchedulerUI/UIxTaskEditor.wox @@ -9,9 +9,11 @@ xmlns:label="OGo:label" className="UIxComponentEditor" componentCalendar="componentCalendar" + eventIsReadOnly="eventIsReadOnly" var:component="todo" var:saveURL="saveURL"> + + + + + + + + + + + ( ) + + + diff --git a/UI/WebServerResources/UIxAppointmentEditor.css b/UI/WebServerResources/UIxAppointmentEditor.css index 92796734e..9fa7e42c3 100644 --- a/UI/WebServerResources/UIxAppointmentEditor.css +++ b/UI/WebServerResources/UIxAppointmentEditor.css @@ -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"); } diff --git a/UI/WebServerResources/UIxComponentEditor.js b/UI/WebServerResources/UIxComponentEditor.js index b8fed7a94..4ee9ee6b9 100644 --- a/UI/WebServerResources/UIxComponentEditor.js +++ b/UI/WebServerResources/UIxComponentEditor.js @@ -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) {