diff --git a/NEWS b/NEWS
index 04f109bf9..a92a5b705 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,7 @@
- added checkmarks in live search options popup menus;
- added browser detection with recommanded alternatives;
- support for resizable columns in tables;
+- improved support for multiple selection in tables and lists;
- improved IE7 and Safari support: attendees selector, email file attachments;
- countless bugfixes;
diff --git a/UI/Common/UIxPageFrame.m b/UI/Common/UIxPageFrame.m
index 193781ed9..a5e6989a8 100644
--- a/UI/Common/UIxPageFrame.m
+++ b/UI/Common/UIxPageFrame.m
@@ -274,6 +274,7 @@
([[cc userAgentType] isEqualToString: @"IE"] && [cc majorVersion] >= 7) ||
([[cc userAgentType] isEqualToString: @"Mozilla"] && [cc majorVersion] >= 5) ||
([[cc userAgentType] isEqualToString: @"Safari"] && [cc majorVersion] >= 4)
+ // ([[cc userAgentType] isEqualToString: @"Konqueror"])
);
}
diff --git a/UI/Templates/SchedulerUI/UIxCalMainView.wox b/UI/Templates/SchedulerUI/UIxCalMainView.wox
index 85fe44937..19ac4c815 100644
--- a/UI/Templates/SchedulerUI/UIxCalMainView.wox
+++ b/UI/Templates/SchedulerUI/UIxCalMainView.wox
@@ -94,12 +94,15 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/UI/Templates/SchedulerUI/UIxCalendarSelector.wox b/UI/Templates/SchedulerUI/UIxCalendarSelector.wox
index ae36b74f9..6340a7257 100644
--- a/UI/Templates/SchedulerUI/UIxCalendarSelector.wox
+++ b/UI/Templates/SchedulerUI/UIxCalendarSelector.wox
@@ -27,7 +27,7 @@
label:title="Remove the selected Calendar"
/>
-
+
-
diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js
index 2bd42c5aa..49be9404d 100644
--- a/UI/WebServerResources/MailerUI.js
+++ b/UI/WebServerResources/MailerUI.js
@@ -381,7 +381,8 @@ function openMailbox(mailbox, reload, idx) {
var url = ApplicationBaseURL + mailbox + "/view?noframe=1";
var messageContent = $("messageContent");
messageContent.update();
-
+ lastClickedRow = null; // from generic.js
+
var currentMessage;
if (!idx) {
currentMessage = currentMessages[mailbox];
@@ -637,7 +638,7 @@ function storeCachedMessage(cachedMessage) {
cachedMessages[oldest] = cachedMessage;
}
-function onMessageSelectionChange() { log("onMessageSelectionChange");
+function onMessageSelectionChange() {
var rows = this.getSelectedRowsId();
if (rows.length == 1) {
@@ -987,6 +988,7 @@ function configureMessageListBodyEvents(table) {
rows = table.tBodies[0].rows;
for (var i = 0; i < rows.length; i++) {
Event.observe(rows[i], "mousedown", onRowClick);
+ Event.observe(rows[i], "selectstart", listRowMouseDownHandler);
Event.observe(rows[i], "contextmenu", onMessageContextMenu.bindAsEventListener(rows[i]));
rows[i].dndTypes = function() { return new Array("mailRow"); };
diff --git a/UI/WebServerResources/SchedulerUI.css b/UI/WebServerResources/SchedulerUI.css
index 9c93e21ce..970062ce0 100644
--- a/UI/WebServerResources/SchedulerUI.css
+++ b/UI/WebServerResources/SchedulerUI.css
@@ -61,6 +61,7 @@ UL#tasksList, UL#calendarList
border-top: 2px solid #222;
border-left: 2px solid #222;
background-color: #fff;
+ -khtml-user-select: none;
-moz-border-top-colors: #9c9a94 #000 transparent;
-moz-border-left-colors: #9c9a94 #000 transparent;
list-style-type: none;
diff --git a/UI/WebServerResources/SchedulerUI.js b/UI/WebServerResources/SchedulerUI.js
index 043d4ddcd..e8baa1f43 100644
--- a/UI/WebServerResources/SchedulerUI.js
+++ b/UI/WebServerResources/SchedulerUI.js
@@ -311,6 +311,7 @@ function eventsListCallback(http) {
var params = parseQueryParameters(http.callbackData);
sortKey = params["sort"];
sortOrder = params["desc"];
+ lastClickedRow = null; // from generic.js
var data = http.responseText.evalJSON(true);
for (var i = 0; i < data.length; i++) {
@@ -370,7 +371,7 @@ function tasksListCallback(http) {
//log(i + " = " + data[i][3]);
var listItem = document.createElement("li");
list.appendChild(listItem);
- Event.observe(listItem, "mousedown", listRowMouseDownHandler); // causes problem with Safari
+ Event.observe(listItem, "mousedown", listRowMouseDownHandler);
Event.observe(listItem, "click", onRowClick);
Event.observe(listItem, "dblclick", editDoubleClickedEvent.bindAsEventListener(listItem));
listItem.setAttribute("id", data[i][0]);
@@ -896,8 +897,8 @@ function _loadEventHref(href) {
= triggerAjaxRequest(url, eventsListCallback, href);
var table = $("eventsList").tBodies[0];
- while (table.rows.length > 1)
- table.removeChild(table.rows[1]);
+ while (table.rows.length > 0)
+ table.removeChild(table.rows[0]);
return false;
}
@@ -1131,17 +1132,15 @@ function updateTaskStatus(event) {
var taskId = this.parentNode.getAttribute("id");
var newStatus = (this.checked ? 1 : 0);
var http = createHTTPClient();
-
- if (isSafari())
+
+ if (isSafari() && !isSafari3()) {
newStatus = (newStatus ? 0 : 1);
- //log("update task status: " + taskId + " to " + this.checked);
- event.cancelBubble = true;
+ }
url = (ApplicationBaseURL + "/" + this.parentNode.calendar
+ "/" + taskId + "/changeStatus?status=" + newStatus);
if (http) {
-// log ("url: " + url);
// TODO: add parameter to signal that we are only interested in OK
http.open("POST", url, false /* not async */);
http.url = url;
@@ -1156,6 +1155,12 @@ function updateTaskStatus(event) {
function updateCalendarStatus(event) {
var list = new Array();
+ var newStatus = (this.checked ? 1 : 0);
+
+ if (isSafari() && !isSafari3()) {
+ newStatus = (newStatus ? 0 : 1);
+ this.checked = newStatus;
+ }
var nodes = $("calendarList").childNodesWithTag("li");
for (var i = 0; i < nodes.length; i++) {
@@ -1181,7 +1186,7 @@ function updateCalendarStatus(event) {
if (event) {
var folderID = this.parentNode.getAttribute("id");
var urlstr = URLForFolderID(folderID);
- if (this.checked)
+ if (newStatus)
urlstr += "/activateFolder";
else
urlstr += "/deactivateFolder";
@@ -1201,18 +1206,18 @@ function updateCalendarStatus(event) {
function calendarStatusCallback(http) {
if (http.readyState == 4) {
if (isHttpStatus204(http.status)) {
- refreshEvents();
- refreshTasks();
- changeCalendarDisplay();
- }
- else {
- var folder = $(http.callbackData);
- var input = folder.childNodesWithTag("input")[0];
- input.checked = (!input.checked);
- }
- }
- else
- log("calendarStatusCallback Ajax error");
+ refreshEvents();
+ refreshTasks();
+ changeCalendarDisplay();
+ }
+ else {
+ var folder = $(http.callbackData);
+ var input = folder.childNodesWithTag("input")[0];
+ input.checked = (!input.checked);
+ }
+ }
+ else
+ log("calendarStatusCallback Ajax error");
}
function calendarEntryCallback(http) {
@@ -1342,12 +1347,15 @@ function initCalendarSelector() {
updateCalendarStatus();
selector.changeNotification = updateCalendarsList;
- var list = $("calendarList").childNodesWithTag("li");
- for (var i = 0; i < list.length; i++) {
- var input = list[i].childNodesWithTag("input")[0];
- Event.observe(input, "click", updateCalendarStatus.bindAsEventListener(input)); // not registered in IE?
- //Event.observe(list[i], "mousedown", listRowMouseDownHandler, true); // problem with Safari
- Event.observe(list[i], "click", onRowClick);
+ var list = $("calendarList");
+ list.multiselect = true;
+ var items = list.childNodesWithTag("li");
+ for (var i = 0; i < items.length; i++) {
+ var input = items[i].childNodesWithTag("input")[0];
+ Event.observe(input, "click", updateCalendarStatus.bindAsEventListener(input));
+ Event.observe(items[i], "mousedown", listRowMouseDownHandler);
+ Event.observe(items[i], "selectstart", listRowMouseDownHandler);
+ Event.observe(items[i], "click", onRowClick);
}
var links = $("calendarSelectorButtons").childNodesWithTag("a");
@@ -1414,30 +1422,31 @@ function appendCalendar(folderName, folder) {
var li = document.createElement("li");
calendarList.appendChild(li);
+ li.setAttribute("id", folder);
var checkBox = document.createElement("input");
checkBox.setAttribute("type", "checkbox");
li.appendChild(checkBox);
li.appendChild(document.createTextNode(" "));
+ $(checkBox).addClassName("checkBox");
var colorBox = document.createElement("div");
li.appendChild(colorBox);
- li.appendChild(document.createTextNode(" " + folderName));
+ li.appendChild(document.createTextNode(" " + folderName)); log (folderName);
colorBox.appendChild(document.createTextNode("OO"));
- li.setAttribute("id", folder);
- Event.observe(li, "mousedown", listRowMouseDownHandler);
- Event.observe(li, "click", onRowClick);
- $(checkBox).addClassName("checkBox");
-
- Event.observe(checkBox, "click",
- updateCalendarStatus.bindAsEventListener(checkBox));
-
$(colorBox).addClassName("colorBox");
if (color)
$(colorBox).setStyle({color: color,
backgroundColor: color});
+ // Register events (doesn't work with Safari)
+ Event.observe(li, "mousedown", listRowMouseDownHandler);
+ Event.observe(li, "selectstart", listRowMouseDownHandler);
+ Event.observe(li, "click", onRowClick);
+ Event.observe(checkBox, "click",
+ updateCalendarStatus.bindAsEventListener(checkBox));
+
var url = URLForFolderID(folder) + "/canAccessContent";
triggerAjaxRequest(url, calendarEntryCallback, folder);
@@ -1460,7 +1469,7 @@ function appendCalendar(folderName, folder) {
}
function onFolderSubscribeCB(folderData) {
- var folder = $(folderData["folder"]);
+ var folder = $(folderData["folder"]);
if (!folder)
appendCalendar(folderData["folderName"], folderData["folder"]);
}
diff --git a/UI/WebServerResources/UIxContactsUserFolders.js b/UI/WebServerResources/UIxContactsUserFolders.js
index bfcbd245c..1734da55a 100644
--- a/UI/WebServerResources/UIxContactsUserFolders.js
+++ b/UI/WebServerResources/UIxContactsUserFolders.js
@@ -22,7 +22,7 @@ function addLineToTree(tree, parent, line) {
|| nodes.length > 1) {
var parentNode = nodes[0];
var userInfos = parentNode.split(":");
- var email = userInfos[1] + " <" + userInfos[2] + ">";
+ var email = userInfos[1] + " <" + userInfos[2] + ">";
tree.add(parent, 0, email, 0, '#', userInfos[0], 'person',
'', '',
ResourcesURL + '/abcard.gif',
@@ -35,7 +35,11 @@ function addLineToTree(tree, parent, line) {
else
icon += 'calendar-folder-16x16.png';
var folderId = userInfos[0] + ":" + folderInfos[1];
- tree.add(parent + i, parent, folderInfos[0], 0, '#', folderId,
+ var name = folderInfos[0]; // name has the format "Folername (Firstname Lastname )"
+ var pos = name.indexOf(' (')
+ if (pos !== -1)
+ name = name.substring(0, pos); // strip the part with fullname and email
+ tree.add(parent + i, parent, name, 0, '#', folderId,
folderInfos[2] + '-folder', '', '', icon, icon);
}
offset = nodes.length - 1;
diff --git a/UI/WebServerResources/generic.js b/UI/WebServerResources/generic.js
index a535ed085..9fa35dedb 100644
--- a/UI/WebServerResources/generic.js
+++ b/UI/WebServerResources/generic.js
@@ -32,6 +32,8 @@ var menus = new Array();
var search = {};
var sorting = {};
+var lastClickedRow = null;
+
var weekStartIsMonday = true;
// logArea = null;
@@ -343,6 +345,10 @@ function checkAjaxRequestsState() {
}
}
+function isSafari3() {
+ return (navigator.appVersion.indexOf("Version") > -1);
+}
+
function isSafari() {
//var agt = navigator.userAgent.toLowerCase();
//var is_safari = ((agt.indexOf('safari')!=-1)&&(agt.indexOf('mac')!=-1))?true:false;
@@ -483,7 +489,7 @@ function isNodeSelected(node) {
function acceptMultiSelect(node) {
var response = false;
var attribute = node.getAttribute('multiselect');
- if (attribute) {
+ if (attribute && attribute.length > 0) {
log("node '" + node.getAttribute("id")
+ "' is still using old-stylemultiselect!");
response = (attribute.toLowerCase() == 'yes');
@@ -496,42 +502,63 @@ function acceptMultiSelect(node) {
function onRowClick(event) {
var node = getTarget(event);
+ var rowIndex = null;
- if (node.tagName == 'TD')
- node = node.parentNode;
- var startSelection = $(node.parentNode).getSelectedNodes();
- if (event.shiftKey == 1
+ if (node.tagName == 'TD') {
+ node = node.parentNode; // select TR
+ rowIndex = node.rowIndex - $(node).up('table').down('thead').getElementsByTagName('tr').length;
+ }
+ else if (node.tagName == 'LI') {
+ // Find index of clicked row
+ var list = node.parentNode;
+ var items = list.childNodesWithTag("li");
+ for (var i = 0; i < items.length; i++) {
+ if (items[i] == node) {
+ rowIndex = i;
+ break;
+ }
+ }
+ }
+
+ var initialSelection = $(node.parentNode).getSelectedNodes();
+ if ((event.shiftKey == 1 || event.ctrlKey == 1)
+ && lastClickedRow
&& (acceptMultiSelect(node.parentNode)
|| acceptMultiSelect(node.parentNode.parentNode))) {
- if (isNodeSelected(node) == true) {
+ if (event.shiftKey)
+ $(node.parentNode).selectRange(lastClickedRow, rowIndex);
+ else if (isNodeSelected(node) == true) {
$(node).deselect();
} else {
$(node).select();
}
+ // At this point, should empty content of 3-pane view
} else {
+ // Single line selection
$(node.parentNode).deselectAll();
$(node).select();
- }
-
- if (startSelection != $(node.parentNode).getSelectedNodes()) {
- // Selection has changed; fire mousedown event
- var parentNode = node.parentNode;
- if (parentNode.tagName == 'TBODY')
- parentNode = parentNode.parentNode;
- if (document.createEvent) {
- var onSelectionChangeEvent;
- if (isSafari())
- onSelectionChangeEvent = document.createEvent("UIEvents");
- else
- onSelectionChangeEvent = document.createEvent("Events");
- onSelectionChangeEvent.initEvent("mousedown", true, true);
- parentNode.dispatchEvent(onSelectionChangeEvent);
- }
- else if (document.createEventObject) {
- parentNode.fireEvent("onmousedown");
+
+ if (initialSelection != $(node.parentNode).getSelectedNodes()) {
+ // Selection has changed; fire mousedown event
+ var parentNode = node.parentNode;
+ if (parentNode.tagName == 'TBODY')
+ parentNode = parentNode.parentNode;
+ if (document.createEvent) {
+ var onSelectionChangeEvent;
+ if (isSafari())
+ onSelectionChangeEvent = document.createEvent("UIEvents");
+ else
+ onSelectionChangeEvent = document.createEvent("Events");
+ onSelectionChangeEvent.initEvent("mousedown", true, true);
+ parentNode.dispatchEvent(onSelectionChangeEvent);
+ }
+ else if (document.createEventObject) {
+ parentNode.fireEvent("onmousedown");
+ }
}
}
-
+ lastClickedRow = rowIndex;
+
return true;
}