Monotone-Parent: 3239b46c1626108a2b1a3d6cab30ae4c9bd6a731

Monotone-Revision: a3ce416b24dfccdfe9594ae00a7b6d94421077a9

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2007-11-13T22:51:32
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Francis Lachapelle 2007-11-13 22:51:32 +00:00
parent d5d78c5f79
commit 4235abc956
8 changed files with 166 additions and 102 deletions

2
NEWS
View File

@ -17,6 +17,8 @@
- support for resizable columns in tables; - support for resizable columns in tables;
- improved support for multiple selection in tables and lists; - improved support for multiple selection in tables and lists;
- improved IE7 and Safari support: attendees selector, email file attachments; - improved IE7 and Safari support: attendees selector, email file attachments;
- updated PrototypeJS to version 1.6.0;
- improved address completion in attendees selector;
- changed look of message composition window to Thunderbird 2.0; - changed look of message composition window to Thunderbird 2.0;
- countless bugfixes; - countless bugfixes;

View File

@ -35,6 +35,7 @@
#import <SoObjects/SOGo/LDAPUserManager.h> #import <SoObjects/SOGo/LDAPUserManager.h>
#import <SoObjects/SOGo/SOGoPermissions.h> #import <SoObjects/SOGo/SOGoPermissions.h>
#import <SoObjects/SOGo/SOGoUser.h> #import <SoObjects/SOGo/SOGoUser.h>
#import <SoObjects/SOGo/NSArray+Utilities.h>
#import <SoObjects/SOGo/NSString+Utilities.h> #import <SoObjects/SOGo/NSString+Utilities.h>
#import <SoObjects/Contacts/SOGoContactFolders.h> #import <SoObjects/Contacts/SOGoContactFolders.h>
#import <SoObjects/Contacts/SOGoContactFolder.h> #import <SoObjects/Contacts/SOGoContactFolder.h>
@ -121,8 +122,10 @@
{ {
WOResponse *response; WOResponse *response;
NSEnumerator *contacts; NSEnumerator *contacts;
NSString *responseString, *email; NSString *email;
NSDictionary *contact; NSDictionary *contact;
NSMutableArray *formattedContacts;
NSMutableDictionary *formattedContact;
response = [context response]; response = [context response];
@ -131,21 +134,25 @@
[response setStatus: 200]; [response setStatus: 200];
contacts = [results objectEnumerator]; contacts = [results objectEnumerator];
contact = [contacts nextObject]; contact = [contacts nextObject];
if (contact) formattedContacts = [[NSMutableArray alloc] initWithCapacity: [results count]];
while (contact)
{ {
email = [contact objectForKey: @"c_email"]; email = [contact objectForKey: @"c_email"];
if ([email length]) if ([email length])
{ {
responseString = [NSString stringWithFormat: @"%@:%@:%@", formattedContact = [NSMutableDictionary dictionary];
[contact objectForKey: @"c_uid"], [formattedContact setObject: [contact objectForKey: @"c_uid"]
[contact objectForKey: @"cn"], forKey: @"uid"];
email]; [formattedContact setObject: [contact objectForKey: @"cn"]
// [response setHeader: @"text/plain; charset=iso-8859-1" forKey: @"name"];
// forKey: @"Content-Type"]; [formattedContact setObject: email
[response appendContentString: responseString]; forKey: @"email"];
[formattedContacts addObject: formattedContact];
} }
// contact = [contacts nextObject]; contact = [contacts nextObject];
} }
[response appendContentString: [formattedContacts jsonRepresentation]];
[formattedContacts release];
} }
else else
[response setStatus: 404]; [response setStatus: 404];

View File

@ -11,6 +11,9 @@
const:toolbar="none" const:toolbar="none"
const:popup="YES" const:popup="YES"
const:jsFiles="skycalendar.js"> const:jsFiles="skycalendar.js">
<div class="menu" id="attendeesMenu">
<ul></ul>
</div>
<div id="attendeesView"> <div id="attendeesView">
<div id="freeBusyViewButtons"> <div id="freeBusyViewButtons">
<var:string label:value="Suggest time slot:"/> <var:string label:value="Suggest time slot:"/>

View File

@ -32,10 +32,13 @@ function newEvent(sender, type) {
if (!hour) if (!hour)
hour = sender.getAttribute("hour"); hour = sender.getAttribute("hour");
var folder = getSelectedFolder(); var folder = getSelectedFolder();
var roles = folder.getAttribute("roles").split(",");
var folderID = folder.getAttribute("id"); var folderID = folder.getAttribute("id");
if ($(roles).indexOf("PublicModifier") < 0) var roles = folder.getAttribute("roles");
folderID = "/personal"; if (roles) {
roles = roles.split(",")
if ($(roles).indexOf("PublicModifier") < 0)
folderID = "/personal";
}
var urlstr = ApplicationBaseURL + folderID + "/new" + type; var urlstr = ApplicationBaseURL + folderID + "/new" + type;
var params = new Array(); var params = new Array();
if (day) if (day)

View File

@ -1,3 +1,7 @@
DIV#attendeesMenu
{ overflow: auto;
overflow-x: hidden; }
DIV#attendeesView DIV#attendeesView
{ position: absolute; { position: absolute;
left: 1em; left: 1em;

View File

@ -42,6 +42,10 @@ function onContactKeydown(event) {
running = true; running = true;
requestField = this; requestField = this;
requestField.setAttribute("modified", "1"); requestField.setAttribute("modified", "1");
if (searchField) {
searchField.confirmedValue = null;
searchField.uid = null;
}
setTimeout("triggerRequest()", delay); setTimeout("triggerRequest()", delay);
} }
else if (this.confirmedValue) { else if (this.confirmedValue) {
@ -67,35 +71,95 @@ function triggerRequest() {
function updateResults(http) { function updateResults(http) {
if (http.readyState == 4) { if (http.readyState == 4) {
var menu = $('attendeesMenu');
var list = menu.down("ul");
searchField = http.callbackData;
searchField.hasfreebusy = false;
if (http.status == 200) { if (http.status == 200) {
var searchField = http.callbackData;
var start = searchField.value.length; var start = searchField.value.length;
var text = http.responseText.split(":"); var data = http.responseText.evalJSON(true);
if (text[0].length > 0) if (data.length > 1) {
searchField.uid = text[0]; $(list.childNodesWithTag("li")).each(function(item) {
else item.remove();
searchField.uid = null; });
searchField.hasfreebusy = false;
var completeEmail = text[1] + " <" + text[2] + ">"; // Populate popup menu
if (text[1].substring(0, searchField.value.length).toUpperCase() for (var i = 0; i < data.length; i++) {
== searchField.value.toUpperCase()) var contact = data[i];
searchField.value = completeEmail; var completeEmail = contact["name"] + " <" + contact["email"] + ">";
var node = document.createElement("li");
list.appendChild(node);
node.uid = contact["uid"];
node.appendChild(document.createTextNode(completeEmail));
$(node).observe("mousedown", onAttendeeResultClick);
}
// Show popup menu
var offset;
if (isSafari())
offset = Position.positionedOffset(searchField);
else
offset = Position.cumulativeOffset(searchField);
var top = offset[1] + node.offsetHeight + 3;
var height = 'auto';
if (data.length > 5) {
height = 5 * node.getHeight() + 'px';
}
menu.setStyle({ top: top + "px",
left: offset[0] + "px",
height: height,
visibility: "visible" });
menu.scrollTop = 0;
document.currentPopupMenu = menu;
$(document.body).observe("click", onBodyClickMenuHandler);
}
else { else {
searchField.value += ' >> ' + completeEmail; if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
if (data.length == 1) {
var contact = data[0];
if (contact["uid"].length > 0)
searchField.uid = contact["uid"];
else
searchField.uid = null;
var completeEmail = contact["name"] + " <" + contact["email"] + ">";
if (contact["name"].substring(0, searchField.value.length).toUpperCase()
== searchField.value.toUpperCase())
searchField.value = completeEmail;
else {
searchField.value += ' >> ' + completeEmail;
}
searchField.confirmedValue = completeEmail;
if (searchField.focussed) {
var end = searchField.value.length;
$(searchField).selectText(start, end);
}
else
searchField.value = contact["name"];
}
} }
searchField.confirmedValue = completeEmail;
if (searchField.focussed) {
var end = searchField.value.length;
$(searchField).selectText(start, end);
}
else
searchField.value = text[1];
} }
else
if (document.currentPopupMenu)
hideMenu(document.currentPopupMenu);
running = false; running = false;
document.contactLookupAjaxRequest = null; document.contactLookupAjaxRequest = null;
} }
} }
function onAttendeeResultClick(event) {
if (searchField) {
searchField.uid = this.uid;
searchField.value = this.firstChild.nodeValue.trim();
searchField.confirmedValue = searchField.value;
searchField.blur(); // triggers checkAttendee function call
}
}
function UIDLookupCallback(http) { function UIDLookupCallback(http) {
if (http.readyState == 4) { if (http.readyState == 4) {
if (http.status == 200) { if (http.status == 200) {
@ -198,14 +262,21 @@ function newAttendee(event) {
var input = $(newRow.cells[0]).childNodesWithTag("input")[0]; var input = $(newRow.cells[0]).childNodesWithTag("input")[0];
input.setAttribute("autocomplete", "off"); input.setAttribute("autocomplete", "off");
Event.observe(input, "blur", checkAttendee.bindAsEventListener(input));
Event.observe(input, "keydown", onContactKeydown.bindAsEventListener(input)); Event.observe(input, "keydown", onContactKeydown.bindAsEventListener(input));
Event.observe(input, "blur", checkAttendee.bindAsEventListener(input));
input.focussed = true; input.focussed = true;
input.activate(); input.activate();
} }
function checkAttendee() { function checkAttendee() {
if (document.currentPopupMenu && !this.confirmedValue) {
// Hack for IE7; blur event is triggered on input field when
// selecting a menu item
var visible = $(document.currentPopupMenu).getStyle('visibility') != 'hidden';
if (visible)
return;
}
this.focussed = false; this.focussed = false;
var th = this.parentNode.parentNode; var th = this.parentNode.parentNode;
var tbody = th.parentNode; var tbody = th.parentNode;
@ -541,4 +612,4 @@ function onFreeBusyLoadHandler() {
initializeFreebusys(); initializeFreebusys();
} }
addEvent(window, 'load', onFreeBusyLoadHandler); document.observe("dom:loaded", onFreeBusyLoadHandler);

View File

@ -576,7 +576,7 @@ function popupMenu(event, menuId, target) {
document.currentPopupMenu = popup; document.currentPopupMenu = popup;
Event.observe(document.body, "click", onBodyClickMenuHandler); $(document.body).observe("click", onBodyClickMenuHandler);
preventDefault(event); preventDefault(event);
} }
@ -600,7 +600,7 @@ function getParentMenu(node) {
function onBodyClickMenuHandler(event) { function onBodyClickMenuHandler(event) {
hideMenu(document.currentPopupMenu); hideMenu(document.currentPopupMenu);
Event.stopObserving(document.body, "click", onBodyClickMenuHandler); document.body.stopObserving("click", onBodyClickMenuHandler);
if (event) if (event)
preventDefault(event); preventDefault(event);
@ -615,15 +615,12 @@ function hideMenu(menuNode) {
} }
menuNode.setStyle({ visibility: "hidden" }); menuNode.setStyle({ visibility: "hidden" });
// menuNode.hide();
if (menuNode.parentMenuItem) { if (menuNode.parentMenuItem) {
Event.stopObserving(menuNode.parentMenuItem, "mouseover", menuNode.parentMenuItem.stopObserving("mouseover",onMouseEnteredSubmenu);
onMouseEnteredSubmenu); menuNode.stopObserving("mouseover", onMouseEnteredSubmenu);
Event.stopObserving(menuNode, "mouseover", onMouseEnteredSubmenu); menuNode.parentMenuItem.stopObserving("mouseout", onMouseLeftSubmenu);
Event.stopObserving(menuNode.parentMenuItem, "mouseout", onMouseLeftSubmenu); menuNode.stopObserving("mouseout", onMouseLeftSubmenu);
Event.stopObserving(menuNode, "mouseout", onMouseLeftSubmenu); menuNode.parentMenu.stopObserving("mouseover", onMouseEnteredParentMenu);
Event.stopObserving(menuNode.parentMenu, "mouseover",
onMouseEnteredParentMenu);
$(menuNode.parentMenuItem).removeClassName("submenu-selected"); $(menuNode.parentMenuItem).removeClassName("submenu-selected");
menuNode.parentMenuItem.mouseInside = false; menuNode.parentMenuItem.mouseInside = false;
menuNode.parentMenuItem = null; menuNode.parentMenuItem = null;
@ -632,18 +629,7 @@ function hideMenu(menuNode) {
menuNode.parentMenu = null; menuNode.parentMenu = null;
} }
if (document.createEvent) { // Safari & Mozilla $(menuNode).fire("mousedown");
var onhideEvent;
if (isSafari())
onhideEvent = document.createEvent("UIEvents");
else
onhideEvent = document.createEvent("Events");
onhideEvent.initEvent("mousedown", false, true);
menuNode.dispatchEvent(onhideEvent);
}
else if (document.createEventObject) { // IE
menuNode.fireEvent("onmousedown");
}
} }
function onMenuEntryClick(event) { function onMenuEntryClick(event) {
@ -673,8 +659,8 @@ function initLogConsole() {
var logConsole = $("logConsole"); var logConsole = $("logConsole");
if (logConsole) { if (logConsole) {
logConsole.highlighted = false; logConsole.highlighted = false;
Event.observe(logConsole, "dblclick", onLogDblClick, false); logConsole.observe("dblclick", onLogDblClick, false);
logConsole.innerHTML = ""; logConsole.update();
Event.observe(window, "keydown", onBodyKeyDown); Event.observe(window, "keydown", onBodyKeyDown);
} }
} }
@ -776,15 +762,11 @@ function popupSubmenu(event) {
menuLeft = parentNode.offsetLeft - submenuNode.offsetWidth + 3; menuLeft = parentNode.offsetLeft - submenuNode.offsetWidth + 3;
this.mouseInside = true; this.mouseInside = true;
Event.observe(this, "mouseover", this.observe("mouseover", onMouseEnteredSubmenu);
onMouseEnteredSubmenu.bindAsEventListener(this)); submenuNode.observe("mouseover", onMouseEnteredSubmenu);
Event.observe(submenuNode, "mouseover", this.observe("mouseout", onMouseLeftSubmenu);
onMouseEnteredSubmenu.bindAsEventListener(submenuNode)); submenuNode.observe("mouseout", onMouseLeftSubmenu);
Event.observe(this, "mouseout", onMouseLeftSubmenu.bindAsEventListener(this)); parentNode.observe("mouseover", onMouseEnteredParentMenu);
Event.observe(submenuNode, "mouseout",
onMouseLeftSubmenu.bindAsEventListener(submenuNode));
Event.observe(parentNode, "mouseover",
onMouseEnteredParentMenu.bindAsEventListener(parentNode));
$(this).addClassName("submenu-selected"); $(this).addClassName("submenu-selected");
submenuNode.setStyle({ top: menuTop + "px", submenuNode.setStyle({ top: menuTop + "px",
left: menuLeft + "px", left: menuLeft + "px",
@ -829,7 +811,7 @@ function popupSearchMenu(event) {
visibility: "visible" }); visibility: "visible" });
document.currentPopupMenu = popup; document.currentPopupMenu = popup;
Event.observe(document.body, "click", onBodyClickMenuHandler); $(document.body).observe("click", onBodyClickMenuHandler);
} }
} }
@ -865,17 +847,12 @@ function configureSearchField() {
if (!searchValue) return; if (!searchValue) return;
Event.observe(searchValue, "mousedown", searchValue.observe("click", popupSearchMenu);
onSearchMouseDown.bindAsEventListener(searchValue)); searchValue.observe("blur", onSearchBlur);
Event.observe(searchValue, "click", searchValue.observe("focus", onSearchFocus);
popupSearchMenu.bindAsEventListener(searchValue)); searchValue.observe("keydown", onSearchKeyDown);
Event.observe(searchValue, "blur", searchValue.observe("mousedown", onSearchMouseDown);
onSearchBlur.bindAsEventListener(searchValue));
Event.observe(searchValue, "focus",
onSearchFocus.bindAsEventListener(searchValue));
Event.observe(searchValue, "keydown",
onSearchKeyDown.bindAsEventListener(searchValue));
if (!searchOptions) return; if (!searchOptions) return;
// Set the checkmark to the first option // Set the checkmark to the first option
@ -975,7 +952,7 @@ function popupToolbarMenu(node, menuId) {
visibility: "visible" }); visibility: "visible" });
document.currentPopupMenu = popup; document.currentPopupMenu = popup;
Event.observe(document.body, "click", onBodyClickMenuHandler); $(document.body).observe("click", onBodyClickMenuHandler);
} }
/* contact selector */ /* contact selector */
@ -1099,10 +1076,8 @@ function initTabs() {
if (currentNode.tagName == 'LI') { if (currentNode.tagName == 'LI') {
if (!firstTab) if (!firstTab)
firstTab = i; firstTab = i;
Event.observe(currentNode, "mousedown", $(currentNode).observe("mousedown", onTabMouseDown);
onTabMouseDown.bindAsEventListener(currentNode)); $(currentNode).observe("click", onTabClick);
Event.observe(currentNode, "click",
onTabClick.bindAsEventListener(currentNode));
//$(currentNode.getAttribute("target")).hide(); //$(currentNode.getAttribute("target")).hide();
} }
} }
@ -1132,9 +1107,7 @@ function initMenu(menuDIV, callbacks) {
var lis = $(menuDIV.childNodesWithTag("ul")[0]).childNodesWithTag("li"); var lis = $(menuDIV.childNodesWithTag("ul")[0]).childNodesWithTag("li");
for (var j = 0; j < lis.length; j++) { for (var j = 0; j < lis.length; j++) {
var node = $(lis[j]); var node = $(lis[j]);
Event.observe(node, "mousedown", node.observe("mousedown", listRowMouseDownHandler, false);
listRowMouseDownHandler.bindAsEventListener(node),
false);
var callback = callbacks[j]; var callback = callbacks[j];
if (callback) { if (callback) {
if (typeof(callback) == "string") { if (typeof(callback) == "string") {
@ -1143,15 +1116,12 @@ function initMenu(menuDIV, callbacks) {
else { else {
node.submenu = callback; node.submenu = callback;
node.addClassName("submenu"); node.addClassName("submenu");
Event.observe(node, "mouseover", node.observe("mouseover", popupSubmenu);
popupSubmenu.bindAsEventListener(node));
} }
} }
else { else {
Event.observe(node, "mouseup", node.observe("mouseup", onBodyClickMenuHandler);
onBodyClickMenuHandler); node.observe("click", callback);
Event.observe(node, "click",
$(callback).bindAsEventListener(node));
} }
} }
else else
@ -1349,7 +1319,7 @@ function onLoadHandler(event) {
var progressImage = $("progressIndicator"); var progressImage = $("progressIndicator");
if (progressImage) if (progressImage)
progressImage.parentNode.removeChild(progressImage); progressImage.parentNode.removeChild(progressImage);
Event.observe(document.body, "contextmenu", onBodyClickContextMenu); $(document.body).observe("contextmenu", onBodyClickContextMenu);
} }
function onBodyClickContextMenu(event) { function onBodyClickContextMenu(event) {
@ -1360,8 +1330,8 @@ function configureSortableTableHeaders(table) {
var headers = $(table).getElementsByClassName("sortableTableHeader"); var headers = $(table).getElementsByClassName("sortableTableHeader");
for (var i = 0; i < headers.length; i++) { for (var i = 0; i < headers.length; i++) {
var header = headers[i]; var header = headers[i];
Event.observe(header, "click", onHeaderClick.bindAsEventListener(header)) $(header).observe("click", onHeaderClick);
} }
} }
function onLinkBannerClick() { function onLinkBannerClick() {
@ -1384,13 +1354,13 @@ function configureLinkBanner() {
if (linkBanner) { if (linkBanner) {
var anchors = linkBanner.childNodesWithTag("a"); var anchors = linkBanner.childNodesWithTag("a");
for (var i = 1; i < 3; i++) { for (var i = 1; i < 3; i++) {
Event.observe(anchors[i], "mousedown", listRowMouseDownHandler); $(anchors[i]).observe("mousedown", listRowMouseDownHandler);
Event.observe(anchors[i], "click", onLinkBannerClick); $(anchors[i]).observe("click", onLinkBannerClick);
} }
Event.observe(anchors[4], "mousedown", listRowMouseDownHandler); $(anchors[4]).observe("mousedown", listRowMouseDownHandler);
Event.observe(anchors[4], "click", onPreferencesClick); $(anchors[4]).observe("click", onPreferencesClick);
if (anchors.length > 5) if (anchors.length > 5)
Event.observe(anchors[5], "click", toggleLogConsole); $(anchors[5]).observe("click", toggleLogConsole);
} }
} }
@ -1432,7 +1402,7 @@ function onFinalLoadHandler(event) {
safetyNet.parentNode.removeChild(safetyNet); safetyNet.parentNode.removeChild(safetyNet);
} }
addEvent(window, 'load', onLoadHandler); document.observe("dom:loaded", onLoadHandler);
function parent$(element) { function parent$(element) {
return this.opener.document.getElementById(element); return this.opener.document.getElementById(element);

View File

@ -50,6 +50,10 @@ SPAN.content > INPUT.textField
/* UIxAttendeesEditor */ /* UIxAttendeesEditor */
DIV#attendeesMenu
{ overflow: scroll;
overflow-x: hidden; }
DIV#freeBusyView DIV#freeBusyView
{ border-bottom: 1px solid #fff; { border-bottom: 1px solid #fff;
border-right: 1px solid #fff; border-right: 1px solid #fff;