See ChangeLog

Monotone-Parent: 6909119bf676c36ec9130366c9880eea70ad1841
Monotone-Revision: 91077f9a3b3dec2d983310daef5d9923ce41255f

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2010-07-08T04:13:56
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Francis Lachapelle 2010-07-08 04:13:56 +00:00
parent 9c79bd5473
commit a8a0084614
9 changed files with 158 additions and 44 deletions

View File

@ -1,3 +1,14 @@
2010-07-09 Francis Lachapelle <flachapelle@inverse.ca>
* UI/WebServerResources/UIxAttendeesEditor.js (onContactKeydown):
reset left scroll uppon autocompletion (fix for IE).
(onAttendeeResultClick): idem.
(prepareAttendees): add the organizer at the top of the attendees list.
* UI/Scheduler/UIxComponentEditor.m (-jsonOrganizer): new method
that returns a JSON representation of a dictionary describing the
organizer of the event.
2010-07-07 Francis Lachapelle <flachapelle@inverse.ca>
* UI/WebServerResources/HTMLInputElement.js: renamed valueAsDate

View File

@ -25,6 +25,8 @@
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <Common/UIxPageFrame.h>
#import "UIxAttendeesEditor.h"

View File

@ -1,6 +1,6 @@
/* UIxComponentEditor.m - this file is part of SOGo
*
* Copyright (C) 2006-2009 Inverse inc.
* Copyright (C) 2006-2010 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
@ -812,6 +812,65 @@ iRANGE(2);
return [jsonAttendees jsonRepresentation];
}
- (NSString *) jsonOrganizer
{
NSMutableDictionary *jsonOrganizer;
NSDictionary *ownerIdentity;
NSString *uid, *name, *email, *partstat, *role;
SOGoUserManager *um;
SOGoCalendarComponent *co;
SOGoUser *ownerUser;
jsonOrganizer = [NSMutableDictionary dictionary];
email = [organizer rfc822Email];
role = nil;
partstat = nil;
if ([email length])
{
um = [SOGoUserManager sharedUserManager];
name = [organizer cn];
uid = [um getUIDForEmail: email];
partstat = [[organizer partStat] lowercaseString];
role = [[organizer role] lowercaseString];
}
else
{
// No organizer defined in vEvent
co = [self clientObject];
uid = [[co container] ownerInContext: context];
ownerUser = [SOGoUser userWithLogin: uid roles: nil];
ownerIdentity = [ownerUser defaultIdentity];
name = [ownerIdentity objectForKey: @"fullName"];
email = [ownerIdentity objectForKey: @"email"];
}
if (uid != nil)
[jsonOrganizer setObject: uid
forKey: @"uid"];
[jsonOrganizer setObject: name
forKey: @"name"];
[jsonOrganizer setObject: email
forKey: @"email"];
if (partstat == nil || ![partstat length])
partstat = @"accepted";
[jsonOrganizer setObject: partstat
forKey: @"partstat"];
if (role == nil || ![role length])
role = @"chair";
[jsonOrganizer setObject: role
forKey: @"role"];
return [jsonOrganizer jsonRepresentation];
}
- (void) setLocation: (NSString *) _value
{
ASSIGN (location, _value);

View File

@ -12,7 +12,7 @@
const:popup="YES"
const:jsFiles="skycalendar.js">
<div class="popupMenu" id="attendeesMenu">
<ul></ul>
<ul><!-- space --></ul>
</div>
<script type="text/javascript">
var dayStartHour = <var:string value="dayStartHour"/>;
@ -21,20 +21,22 @@
<div id="attendeesView">
<form const:href=""
><div id="freeBusyViewButtons">
<var:string label:value="Suggest time slot:"/>
<span id="freeBusyViewOptions">
<var:string label:value="Suggest time slot:"/>
<span id="freeBusyTimeRange">
<var:string label:value="Between"/>
<select const:id="timeSlotStartLimitHour"><!--space --></select>
<select const:id="timeSlotStartLimitMinute"><!--space --></select>
<var:string label:value="and"/>
<select const:id="timeSlotEndLimitHour"><!--space --></select>
<select const:id="timeSlotEndLimitMinute"><!--space --></select>
</span>
<span id="freeBusyTimeRange">
<var:string label:value="Between"/>
<select const:id="timeSlotStartLimitHour"><!-- space --></select>
<select const:id="timeSlotStartLimitMinute"><!-- space --></select>
<var:string label:value="and"/>
<select const:id="timeSlotEndLimitHour"><!-- space --></select>
<select const:id="timeSlotEndLimitMinute"><!-- space --></select>
</span>
<label><input type="checkbox" const:id="workDaysOnly" const:checked="YES"
/><var:string label:value="Work days only"/></label>
</span>
<label><input type="checkbox" const:id="workDaysOnly"
const:checked="YES"
/><var:string label:value="Work days only"/></label>
<a id="nextSlot" href="#" class="button"
><span><var:string label:value="Next slot" /></span></a>
<a id="previousSlot" href="#" class="button"
@ -77,8 +79,8 @@
<td class="freeBusyData">
<div><table id="freeBusyData" cellspacing="0" cellpadding="0">
<tbody>
<tr class="futureData"></tr>
<tr class="dataModel"></tr>
<tr class="futureData"><!-- space --></tr>
<tr class="dataModel"><!-- space --></tr>
</tbody>
</table></div>
</td>

View File

@ -21,6 +21,7 @@
const:negate="YES">false</var:if>;
var attendees = <var:string value="jsonAttendees" const:escapeHTML="NO"/>;
var ownerLogin = '<var:string value="ownerLogin"/>';
var organizer = <var:string value="jsonOrganizer" const:escapeHTML="NO"/>;
</script>
<var:if condition="eventIsReadOnly" const:negate="YES">

View File

@ -164,7 +164,7 @@ function addContact(tag, fullContactName, contactId, contactName, contactEmail)
function saveEvent(sender) {
if (validateAptEditor()) {
document.forms['editform'].attendees.value = $(attendees).toJSON();
document.forms['editform'].attendees.value = Object.toJSON($(attendees));
document.forms['editform'].submit();
}
@ -324,7 +324,7 @@ function refreshAttendees(newAttendees) {
if (!attendeesHref)
return refreshAttendeesRO();
if (attendeesMenu)
attendeesMenu = $("attendeesMenu").down("ul");
@ -337,12 +337,12 @@ function refreshAttendees(newAttendees) {
if (menuItems && attendeesMenu)
for (var i = 0; i < menuItems.length; i++)
attendeesMenu.removeChild(menuItems[i]);
if (newAttendees) {
if (newAttendees)
// Update global variable
attendees = $H(newAttendees.evalJSON());
}
if (attendees.keys().length > 0) {
if (attendees.keys().length > 0) {
// Update attendees link and show label
var names = new Array();
attendees.values().each(function(attendee) {

View File

@ -243,13 +243,15 @@ TABLE#freeBusyData TD.noFreeBusy
{ margin: 0px;
text-align: left; }
SPAN#freeBusyViewOptions
{ float: left; }
#freeBusyViewButtons SELECT
{ width: 50px; }
SPAN.hidden
{ display: none; }
#freeBusyViewButtons > DIV.buttons
{ margin: 0px;
margin-top: 4px; }
DIV#freeBusyReplicas
{ position: absolute;
top: 2px;

View File

@ -106,8 +106,10 @@ function onContactKeydown(event) {
this.focussed = true;
return;
}
if (event.keyCode == 9 || event.keyCode == 13) { // Tab
if (event.keyCode == Event.KEY_TAB || event.keyCode == Event.KEY_RETURN) {
preventDefault(event);
this.scrollLeft = 0;
$(this).up('DIV').scrollLeft = 0;
if (this.confirmedValue)
this.value = this.confirmedValue;
this.hasfreebusy = false;
@ -128,7 +130,7 @@ function onContactKeydown(event) {
}
}
else if (event.keyCode == 0
|| event.keyCode == 8 // Backspace
|| event.keyCode == Event.KEY_BACKSPACE
|| event.keyCode == 32 // Space
|| event.keyCode > 47) {
this.modified = true;
@ -349,6 +351,8 @@ function onAttendeeResultClick(event) {
input.confirmedValue = input.value = this.address;
initializeAttendeeRole(input);
checkAttendee(input);
this.scrollLeft = 0;
$(this).up('DIV').scrollLeft = 0;
this.parentNode.input = null;
}
@ -440,7 +444,7 @@ function rotateAttendeeStatus(row) {
idx++;
}
row.setAttribute(attributeName, values[idx]);
if (Prototype.Browser.IE) {
if (!Prototype.Browser.Gecko) {
/* This hack enables a refresh of the row element right after the
click. Otherwise, this occurs only when leaving the element with
them mouse cursor. */
@ -1289,7 +1293,7 @@ function onEditorOkClick(event) {
var inputs = $("freeBusy").getElementsByTagName("input");
for (var i = 0; i < inputs.length - 1; i++) {
var input = inputs[i];
if (input.uid) {
if (!input.disabled && input.uid) {
uids.push(input.uid);
}
}
@ -1321,6 +1325,8 @@ function _confirmEditorOkClick() {
var newAttendees = new Hash();
var inputs = $("freeBusy").getElementsByTagName("input");
for (var i = 0; i < inputs.length - 1; i++) {
if (inputs[i].disabled)
continue;
var row = $(inputs[i]).up("tr");
var name = extractEmailName(inputs[i].value);
var email = extractEmailAddress(inputs[i].value);
@ -1348,7 +1354,7 @@ function _confirmEditorOkClick() {
attendee["role"] = role;
newAttendees.set(email, attendee);
}
window.opener.refreshAttendees(newAttendees.toJSON());
window.opener.refreshAttendees(Object.toJSON(newAttendees));
updateParentDateFields("startTime", "startTime");
updateParentDateFields("endTime", "endTime");
@ -1481,16 +1487,48 @@ function prepareTableRows() {
function prepareAttendees() {
var tableAttendees = $("freeBusyAttendees");
var tableData = $("freeBusyData");
var organizer = window.opener.organizer;
var attendees = window.opener.attendees;
var attendeesKeys = (attendees ? attendees.keys() : null);
if (attendeesKeys && attendeesKeys.length > 0) {
var tbodyAttendees = tableAttendees.tBodies[0];
var modelAttendee = tbodyAttendees.rows[tbodyAttendees.rows.length - 1];
var newAttendeeRow = tbodyAttendees.rows[tbodyAttendees.rows.length - 2];
var tbodyData = tableData.tBodies[0];
var modelData = tbodyData.rows[tbodyData.rows.length - 1];
var newDataRow = tbodyData.rows[tbodyData.rows.length - 2];
var tbodyAttendees = tableAttendees.tBodies[0];
var modelAttendee = tbodyAttendees.rows[tbodyAttendees.rows.length - 1];
var newAttendeeRow = tbodyAttendees.rows[tbodyAttendees.rows.length - 2];
var tbodyData = tableData.tBodies[0];
var modelData = tbodyData.rows[tbodyData.rows.length - 1];
var newDataRow = tbodyData.rows[tbodyData.rows.length - 2];
// Unconditionaly add the organizer
var row = $(modelAttendee.cloneNode(true));
tbodyAttendees.insertBefore(row, newAttendeeRow);
row.removeClassName("attendeeModel");
row.setAttribute("partstat", organizer["partstat"]);
row.setAttribute("role", organizer["role"]);
var uid = organizer["uid"];
row.addClassName("organizer-row");
row.removeClassName("attendee-row");
row.isOrganizer = true;
var input = row.down("input");
var value = organizer["name"];
if (value)
value += " ";
else
value = "";
value += "<" + organizer["email"] + ">";
input.value = value;
input.uid = uid;
//input.cname = organizer["cname"];
input.setAttribute("name", "");
input.modified = false;
input.disable();
row = $(modelData.cloneNode(true));
tbodyData.insertBefore(row, newDataRow);
row.removeClassName("dataModel");
displayFreeBusyForNode(input);
if (attendeesKeys && attendeesKeys.length > 0) {
attendeesKeys.each(function(atKey) {
var attendee = attendees.get(atKey);
@ -1524,7 +1562,7 @@ function prepareAttendees() {
value = "";
value += "<" + attendee["email"] + ">";
input.value = value;
input.uid = attendee["uid"];
input.uid = uid;
input.cname = attendee["cname"];
input.setAttribute("name", "");
input.modified = false;
@ -1535,7 +1573,7 @@ function prepareAttendees() {
row = $(modelData.cloneNode(true));
tbodyData.insertBefore(row, newDataRow);
row.removeClassName("dataModel");
displayFreeBusyForNode(input);
displayFreeBusyForNode(input);
});
}
else {

View File

@ -352,7 +352,6 @@ function initMailEditor() {
var subjectField = $$("div#subjectRow input").first();
initTabIndex($("addressList"), subjectField, textarea);
//onWindowResize.defer();
var focusField = (mailIsReply ? textarea : $("addr_0"));
focusField.focus();
@ -517,18 +516,18 @@ function onWindowResize(event) {
var attachmentsarea = $("attachmentsArea");
var attachmentswidth = 0;
var subjectfield = headerarea.down("div#subjectRow span.headerField");
var subjectinput = headerarea.down("div#subjectRow input.textField");
if (attachmentsarea.style.display) {
// Resize attachments list
attachmentswidth = attachmentsarea.getWidth();
fromfield = $(document).getElementsByClassName('headerField', headerarea)[0];
var height = headerarea.getHeight() - fromfield.getHeight() - 10;
var height = headerarea.getHeight() - fromfield.getHeight() - subjectfield.getHeight() - 10;
if (Prototype.Browser.IE)
$("attachments").setStyle({ height: (height - 13) + 'px' });
else
$("attachments").setStyle({ height: height + 'px' });
}
var subjectfield = headerarea.down("div#subjectRow span.headerField");
var subjectinput = headerarea.down("div#subjectRow input.textField");
// Resize subject field
subjectinput.setStyle({ width: (window.width()