diff --git a/ChangeLog b/ChangeLog index 701fede3a..0c07a32ae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2011-04-21 Francis Lachapelle + + * UI/WebServerResources/SchedulerUI.js (deleteEvent): we now show + in the confirmation dialog box which events will be deleted. + + * UI/WebServerResources/generic.js (createDialog): the legend + argument can now be a string or an element. + (isWebKit): was isSafari; now consider all WebKit-based browsers together. + + * UI/WebServerResources/UIxMailToSelection.js: various + improvements to behave like in Thunderbird. + + * UI/WebServerResources/SOGoAutoCompletion.js: idem. + + * UI/WebServerResources/UIxMailEditor.js (initAddresses): was + initTabIndex. We were not handling the tab indexes properly which + was causing incorrect behavior in IE. + 2011-04-19 Wolfgang Sourdeau * OpenChange/MAPIStoreMailAttachment.m (-): binary properties are diff --git a/UI/Templates/MailerUI/UIxMailToSelection.wox b/UI/Templates/MailerUI/UIxMailToSelection.wox index 6a51f9293..c3b3b3b4d 100644 --- a/UI/Templates/MailerUI/UIxMailToSelection.wox +++ b/UI/Templates/MailerUI/UIxMailToSelection.wox @@ -13,8 +13,7 @@ + > diff --git a/UI/WebServerResources/SOGoAutoCompletion.js b/UI/WebServerResources/SOGoAutoCompletion.js index 97abf70ea..b7c137e05 100644 --- a/UI/WebServerResources/SOGoAutoCompletion.js +++ b/UI/WebServerResources/SOGoAutoCompletion.js @@ -44,12 +44,6 @@ var SOGoAutoCompletionInterface = { this.writeAttribute("uid", null); if (document.currentPopupMenu) hideMenu(document.currentPopupMenu); - if (this.readAttribute("container")) { - this.confirmedValue = null; - this.fire("autocompletion:changedlist", this.readAttribute("container")); - } - else - this.fire("autocompletion:changed"); } else if (event.keyCode == 0 || event.keyCode == Event.KEY_BACKSPACE @@ -68,7 +62,6 @@ var SOGoAutoCompletionInterface = { this.value = this.confirmedValue; else this.writeAttribute("uid", null); - $(this).select(); if (document.currentPopupMenu) hideMenu(document.currentPopupMenu); this.selectedIndex = -1; @@ -77,7 +70,7 @@ var SOGoAutoCompletionInterface = { this.fire("autocompletion:changedlist", this.readAttribute("container")); } else - this.fire("autocompletion:changed"); + this.fire("autocompletion:changed", event.keyCode); } else if (this.menu.getStyle('visibility') == 'visible') { if (event.keyCode == Event.KEY_UP) { // Up arrow @@ -118,6 +111,8 @@ var SOGoAutoCompletionInterface = { this.value = this.confirmedValue; if (this.readAttribute("container")) this.fire("autocompletion:changedlist", this.readAttribute("container")); + else + this.fire("autocompletion:changed", event.keyCode); } else this.writeAttribute("uid", null); @@ -264,13 +259,14 @@ var SOGoAutoCompletionInterface = { if (e.tagName != 'LI') e = e.up('LI'); if (e) { + preventDefault(event); this.value = e.readAttribute("address"); this.writeAttribute("uid", e.readAttribute("uid")); if (e.readAttribute("container")) this.fire("autocompletion:changedlist", e.readAttribute("container")); else { this.confirmedValue = this.value; - this.fire("autocompletion:changed"); + this.fire("autocompletion:changed", Event.KEY_RETURN); } } } diff --git a/UI/WebServerResources/SchedulerUI.js b/UI/WebServerResources/SchedulerUI.js index 7572e7873..881d1dc27 100644 --- a/UI/WebServerResources/SchedulerUI.js +++ b/UI/WebServerResources/SchedulerUI.js @@ -215,6 +215,7 @@ function deleteEvent() { var canDelete; var sortedNodes = []; var calendars = []; + var events = []; for (var i = 0; i < nodes.length; i++) { canDelete = nodes[i].erasable; if (canDelete) { @@ -223,15 +224,26 @@ function deleteEvent() { sortedNodes[calendar] = []; calendars.push(calendar); } - sortedNodes[calendar].push(nodes[i].cname); + if (sortedNodes[calendar].indexOf(nodes[i].cname) < 0) { + sortedNodes[calendar].push(nodes[i].cname); + events.push(nodes[i].down('td').allTextContent()); + } } } for (i = 0; i < calendars.length; i++) { calendarsOfEventsToDelete.push(calendars[i]); eventsToDelete.push(sortedNodes[calendars[i]]); } - if (i > 0) - showConfirmDialog(_("Warning"), label, deleteEventFromListConfirm); + if (i > 0) { + var p = createElement("p"); + var str = ""; + if (Prototype.Browser.IE) + str = label.formatted('

- ' + events.join('
- ') + '

'); + else + str = label.formatted(''); + p.innerHTML = str; + showConfirmDialog(_("Warning"), p, deleteEventFromListConfirm, deleteEventCancel); + } else showAlertDialog(_("You don't have the required privileges to perform the operation.")); } @@ -251,6 +263,7 @@ function deleteEvent() { var canDelete; var sortedNodes = []; var calendars = []; + var events = []; for (var i = 0; i < selectedCalendarCell.length; i++) { canDelete = selectedCalendarCell[i].erasable; if (canDelete) { @@ -259,7 +272,19 @@ function deleteEvent() { sortedNodes[calendar] = []; calendars.push(calendar); } - sortedNodes[calendar].push(selectedCalendarCell[i].cname); + if (sortedNodes[calendar].indexOf(selectedCalendarCell[i].cname) < 0) { + // Extract event name for confirmation dialog + var content = ""; + var event = $(selectedCalendarCell[i]).down("DIV.text"); + for (var j = 0; j < event.childNodes.length; j++) { + var node = event.childNodes[j]; + if (node.nodeType == Node.TEXT_NODE) { + content += node.nodeValue; + } + } + events.push(content); + sortedNodes[calendar].push(selectedCalendarCell[i].cname); + } } } @@ -267,9 +292,20 @@ function deleteEvent() { calendarsOfEventsToDelete.push(calendars[i]); eventsToDelete.push(sortedNodes[calendars[i]]); } - if (i > 0) - showConfirmDialog(_("Warning"), _("eventDeleteConfirmation"), - deleteEventFromViewConfirm, deleteEventFromViewCancel); + if (i > 0) { + var p = createElement("p"); + var str = ""; + if (Prototype.Browser.IE) + str = label.formatted('

- ' + events.join('
- ') + '

'); + else + str = label.formatted(''); + p.innerHTML = str; + showConfirmDialog(_("Warning"), p, deleteEventFromListConfirm); + + var p = new Element("p").update(_("eventDeleteConfirmation").formatted('')); + showConfirmDialog(_("Warning"), p, + deleteEventFromViewConfirm, deleteEventCancel); + } else showAlertDialog(_("You don't have the required privileges to perform the operation.")); } @@ -301,7 +337,7 @@ function deleteEventFromViewConfirm() { disposeDialog(); } -function deleteEventFromViewCancel(event) { +function deleteEventCancel(event) { calendarsOfEventsToDelete = []; eventsToDelete = []; disposeDialog(); @@ -1181,23 +1217,25 @@ function scrollDayView(scrollEvent) { if (scrollEvent) { var contentView; var eventRow = $(scrollEvent); - var eventBlocks = selectCalendarEvent(eventRow.calendar, eventRow.cname, eventRow.recurrenceTime); - if (eventBlocks) { - var firstEvent = eventBlocks.first(); - - if (currentView == "monthview") - contentView = firstEvent.up("DIV.day"); - else - contentView = $("daysView"); - - // Don't scroll to an all-day event - if (typeof eventRow.hour != "undefined") { - var top = firstEvent.cumulativeOffset()[1] - contentView.scrollTop; - // Don't scroll if the event is visible to the user - if (top < contentView.cumulativeOffset()[1]) - contentView.scrollTop = firstEvent.cumulativeOffset()[1] - contentView.cumulativeOffset()[1]; - else if (top > contentView.cumulativeOffset()[1] + contentView.getHeight() - firstEvent.getHeight()) - contentView.scrollTop = firstEvent.cumulativeOffset()[1] - contentView.cumulativeOffset()[1]; + if (eventRow) { + var eventBlocks = selectCalendarEvent(eventRow.calendar, eventRow.cname, eventRow.recurrenceTime); + if (eventBlocks) { + var firstEvent = eventBlocks.first(); + + if (currentView == "monthview") + contentView = firstEvent.up("DIV.day"); + else + contentView = $("daysView"); + + // Don't scroll to an all-day event + if (typeof eventRow.hour != "undefined") { + var top = firstEvent.cumulativeOffset()[1] - contentView.scrollTop; + // Don't scroll if the event is visible to the user + if (top < contentView.cumulativeOffset()[1]) + contentView.scrollTop = firstEvent.cumulativeOffset()[1] - contentView.cumulativeOffset()[1]; + else if (top > contentView.cumulativeOffset()[1] + contentView.getHeight() - firstEvent.getHeight()) + contentView.scrollTop = firstEvent.cumulativeOffset()[1] - contentView.cumulativeOffset()[1]; + } } } } @@ -2163,7 +2201,7 @@ function onShowCompletedTasks(event) { function updateTaskStatus(event) { var newStatus = (this.checked ? 1 : 0); - if (isSafari() && !isSafari3()) { + if (isWebKit() && !isSafari3()) { newStatus = (newStatus ? 0 : 1); } _updateTaskCompletion (this.parentNode, newStatus); @@ -2174,7 +2212,7 @@ function updateCalendarStatus(event) { var list = []; var newStatus = (this.checked ? 1 : 0); - if (isSafari() && !isSafari3()) { + if (isWebKit() && !isSafari3()) { newStatus = (newStatus ? 0 : 1); this.checked = newStatus; } diff --git a/UI/WebServerResources/UIxMailEditor.js b/UI/WebServerResources/UIxMailEditor.js index 8f95b50bf..a479fe482 100644 --- a/UI/WebServerResources/UIxMailEditor.js +++ b/UI/WebServerResources/UIxMailEditor.js @@ -339,21 +339,20 @@ function onTextMouseDown(event) { } } -function initTabIndex(addressList, subjectField, msgArea) { +function initAddresses() { + var addressList = $("addressList"); var i = 1; addressList.select("input.textField").each(function (input) { if (!input.readAttribute("readonly")) { - input.writeAttribute("tabindex", i++); input.addInterface(SOGoAutoCompletionInterface); input.uidField = "c_name"; - input.observe("focus", addressFieldGotFocus.bind(input)); - input.observe("blur", addressFieldLostFocus.bind(input)); - input.observe("autocompletion:changedlist", expandContactList); + input.on("focus", addressFieldGotFocus.bind(input)); + input.on("blur", addressFieldLostFocus.bind(input)); + input.on("autocompletion:changedlist", expandContactList); + input.on("autocompletion:changed", addressFieldChanged.bind(input)); //input.onListAdded = expandContactList; } }); - subjectField.writeAttribute("tabindex", i++); - msgArea.writeAttribute("tabindex", i); } function initMailEditor() { @@ -391,8 +390,7 @@ function initMailEditor() { textarea.observe(ieEvents[i], onTextIEUpdateCursorPos, false); } - var subjectField = $$("div#subjectRow input").first(); - initTabIndex($("addressList"), subjectField, textarea); + initAddresses(); var focusField = (mailIsReply ? textarea : $("addr_0")); focusField.focus(); @@ -559,7 +557,7 @@ function onSelectAllAttachments() { } function onSelectOptions(event) { - if (event.button == 0 || (isSafari() && event.button == 1)) { + if (event.button == 0 || (isWebKit() && event.button == 1)) { var node = getTarget(event); if (node.tagName != 'A') node = $(node).up("A"); diff --git a/UI/WebServerResources/UIxMailToSelection.js b/UI/WebServerResources/UIxMailToSelection.js index f9f55c6dd..2383e54f9 100644 --- a/UI/WebServerResources/UIxMailToSelection.js +++ b/UI/WebServerResources/UIxMailToSelection.js @@ -83,15 +83,15 @@ function fancyAddRow(text, type) { input.id = 'addr_' + currentIndex; input.value = text; input.stopObserving(); - input.addInterface(SOGoAutoCompletionInterface); - input.focus(); - input.select(); + addressList.insertBefore(row, lastChild); input.observe("focus", addressFieldGotFocus.bind(input)); input.observe("blur", addressFieldLostFocus.bind(input)); input.observe("autocompletion:changedlist", expandContactList); + input.on("autocompletion:changed", addressFieldChanged.bind(input)); + input.focus(); - addressList.insertBefore(row, lastChild); + return input; } function expandContactList (e) { @@ -132,6 +132,8 @@ function addressFieldGotFocus(event) { idx = getIndexFromIdentifier(this.id); if (lastIndex == idx) return; removeLastEditedRowIfEmpty(); + if (Prototype.Browser.IE && this.value.length == 0) + $(this).setCaretTo(0); // IE hack onWindowResize(null); return false; @@ -139,7 +141,9 @@ function addressFieldGotFocus(event) { function addressFieldLostFocus(event) { lastIndex = getIndexFromIdentifier(this.id); - +} + +function addressFieldChanged(event) { var addresses = this.value.split(/[,;]/); if (addresses.length > 0) { var first = true; @@ -177,9 +181,18 @@ function addressFieldLostFocus(event) { } } } - onWindowResize(null); - return false; + // Verify if a new row should be created + var keyCode = event.memo; + if (keyCode == Event.KEY_RETURN) { + var input = fancyAddRow(""); + if (Prototype.Browser.IE) + $(input.id).focus(); + else + input.focus(); + } + + onWindowResize(null); } function removeLastEditedRowIfEmpty() { diff --git a/UI/WebServerResources/generic.js b/UI/WebServerResources/generic.js index b4dde435b..7b6b88a50 100644 --- a/UI/WebServerResources/generic.js +++ b/UI/WebServerResources/generic.js @@ -449,16 +449,17 @@ function isSafari3() { return (navigator.appVersion.indexOf("Version") > -1); } -function isSafari() { +function isWebKit() { //var agt = navigator.userAgent.toLowerCase(); //var is_safari = ((agt.indexOf('safari')!=-1)&&(agt.indexOf('mac')!=-1))?true:false; - - return (navigator.vendor == "Apple Computer, Inc.") || (navigator.userAgent.toLowerCase().indexOf('konqueror') != -1); + return (navigator.vendor == "Apple Computer, Inc.") || + (navigator.userAgent.toLowerCase().indexOf('konqueror') != -1) || + (navigator.userAgent.indexOf('AppleWebKit') != -1); } function isHttpStatus204(status) { return (status == 204 || // Firefox - (isSafari() && typeof(status) == 'undefined') || // Safari + (isWebKit() && typeof(status) == 'undefined') || // Safari status == 1223); // IE } @@ -498,7 +499,7 @@ function refreshOpener() { function eventIsLeftClick(event) { var isLeftClick = true; - if (isMac() && isSafari()) { + if (isMac() && isWebKit()) { if (event.ctrlKey == 1) { // Control-click is equivalent to right-click under Mac OS X isLeftClick = false; @@ -1778,9 +1779,13 @@ function createDialog(id, title, legend, content, positionClass) { var titleh3 = createElement("h3", null, null, null, null, subdiv); titleh3.appendChild(document.createTextNode(title)); } - if (legend && legend.length > 0) { - var legendP = createElement("p", null, null, null, null, subdiv); - legendP.appendChild(document.createTextNode(legend)); + if (legend) { + if (Object.isElement(legend)) + subdiv.appendChild(legend); + else if (legend.length > 0) { + var legendP = createElement("p", null, null, null, null, subdiv); + legendP.appendChild(document.createTextNode(legend)); + } } if (content) subdiv.appendChild(content); @@ -1833,7 +1838,10 @@ function _showAlertDialog(label) { } function showConfirmDialog(title, label, callbackYes, callbackNo) { - var dialog = dialogs[title+label]; + var key = title; + if (Object.isElement(label)) key += label.allTextContent(); + else key += label; + var dialog = dialogs[key]; if (dialog) { $("bgDialogDiv").show(); @@ -1854,7 +1862,7 @@ function showConfirmDialog(title, label, callbackYes, callbackNo) { fields, "none"); document.body.appendChild(dialog); - dialogs[title+label] = dialog; + dialogs[key] = dialog; } dialog.show(); }