2009-09-01 16:12:53 +02:00
|
|
|
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
|
2009-10-28 18:48:22 +01:00
|
|
|
// NOTE: The popup menu with id "contactsMenu" must exist before
|
|
|
|
// using this interface.
|
|
|
|
//
|
|
|
|
// This interface fires two events:
|
|
|
|
// - autocompletion:changed : fired when a new contact is selected
|
|
|
|
// - autocompletion:changedlist : fired when a new list is selected
|
|
|
|
//
|
2009-09-01 16:12:53 +02:00
|
|
|
var SOGoAutoCompletionInterface = {
|
2009-10-28 18:48:22 +01:00
|
|
|
|
|
|
|
// Attributes that could be changed from the object
|
|
|
|
// inheriting the inteface
|
2009-09-01 16:12:53 +02:00
|
|
|
uidField: "c_name",
|
2009-10-28 18:48:22 +01:00
|
|
|
addressBook: null,
|
2009-09-10 20:31:20 +02:00
|
|
|
excludeGroups: false,
|
2009-10-28 18:48:22 +01:00
|
|
|
excludeLists: false,
|
|
|
|
|
|
|
|
// Internal attributes
|
2009-09-01 16:12:53 +02:00
|
|
|
animationParent: null,
|
|
|
|
selectedIndex: -1,
|
|
|
|
delay: 0.750,
|
|
|
|
delayedSearch: false,
|
|
|
|
menu: null,
|
2009-09-11 15:32:22 +02:00
|
|
|
|
2009-09-01 16:12:53 +02:00
|
|
|
bind: function () {
|
2009-10-02 15:41:49 +02:00
|
|
|
this.menu = $('contactsMenu');
|
|
|
|
this.writeAttribute("autocomplete", "off");
|
|
|
|
this.observe("keydown", this.onKeydown.bindAsEventListener(this));
|
|
|
|
this.observe("blur", this.onBlur.bindAsEventListener(this));
|
2009-09-01 16:12:53 +02:00
|
|
|
},
|
2009-09-11 15:32:22 +02:00
|
|
|
|
2009-09-01 16:12:53 +02:00
|
|
|
onKeydown: function (event) {
|
2009-10-02 15:41:49 +02:00
|
|
|
if (event.ctrlKey || event.metaKey) {
|
|
|
|
this.focussed = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (event.keyCode == Event.KEY_TAB) {
|
|
|
|
if (this.confirmedValue)
|
|
|
|
this.value = this.confirmedValue;
|
|
|
|
else
|
2009-10-28 18:48:22 +01:00
|
|
|
this.writeAttribute("uid", null);
|
|
|
|
if (document.currentPopupMenu)
|
2009-10-02 15:41:49 +02:00
|
|
|
hideMenu(document.currentPopupMenu);
|
2009-10-28 18:48:22 +01:00
|
|
|
if (this.readAttribute("container")) {
|
|
|
|
this.confirmedValue = null;
|
|
|
|
this.fire("autocompletion:changedlist", this.readAttribute("container"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
this.fire("autocompletion:changed");
|
2009-10-02 15:41:49 +02:00
|
|
|
}
|
|
|
|
else if (event.keyCode == 0
|
|
|
|
|| event.keyCode == Event.KEY_BACKSPACE
|
|
|
|
|| event.keyCode == 32 // Space
|
|
|
|
|| event.keyCode > 47) {
|
|
|
|
this.confirmedValue = null;
|
|
|
|
this.selectedIndex = -1;
|
|
|
|
if (this.delayedSearch)
|
|
|
|
window.clearTimeout(this.delayedSearch);
|
|
|
|
this.delayedSearch = this.performSearch.delay(this.delay, this);
|
|
|
|
}
|
|
|
|
else if (event.keyCode == Event.KEY_RETURN) {
|
|
|
|
preventDefault(event);
|
|
|
|
if (this.confirmedValue)
|
|
|
|
this.value = this.confirmedValue;
|
2009-10-28 18:48:22 +01:00
|
|
|
else
|
|
|
|
this.writeAttribute("uid", null);
|
2009-10-02 15:41:49 +02:00
|
|
|
$(this).select();
|
|
|
|
if (document.currentPopupMenu)
|
|
|
|
hideMenu(document.currentPopupMenu);
|
|
|
|
this.selectedIndex = -1;
|
2009-10-28 18:48:22 +01:00
|
|
|
if (this.readAttribute("container")) {
|
|
|
|
this.confirmedValue = null;
|
|
|
|
this.fire("autocompletion:changedlist", this.readAttribute("container"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
this.fire("autocompletion:changed");
|
2009-10-02 15:41:49 +02:00
|
|
|
}
|
|
|
|
else if (this.menu.getStyle('visibility') == 'visible') {
|
|
|
|
if (event.keyCode == Event.KEY_UP) { // Up arrow
|
|
|
|
if (this.selectedIndex > 0) {
|
|
|
|
var contacts = this.menu.select("li");
|
|
|
|
contacts[this.selectedIndex--].removeClassName("selected");
|
|
|
|
this.value = contacts[this.selectedIndex].readAttribute("address");
|
2009-10-28 18:48:22 +01:00
|
|
|
this.confirmedValue = this.value;
|
|
|
|
this.writeAttribute("uid", contacts[this.selectedIndex].readAttribute("uid"));
|
2009-10-02 15:41:49 +02:00
|
|
|
contacts[this.selectedIndex].addClassName("selected");
|
2009-10-28 18:48:22 +01:00
|
|
|
var container = contacts[this.selectedIndex].readAttribute("container");
|
|
|
|
if (container)
|
|
|
|
this.writeAttribute("container", container);
|
2009-10-02 15:41:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event.keyCode == Event.KEY_DOWN) { // Down arrow
|
|
|
|
var contacts = this.menu.select("li");
|
|
|
|
if (contacts.size() - 1 > this.selectedIndex) {
|
|
|
|
if (this.selectedIndex >= 0)
|
|
|
|
contacts[this.selectedIndex].removeClassName("selected");
|
|
|
|
this.selectedIndex++;
|
|
|
|
this.value = contacts[this.selectedIndex].readAttribute("address");
|
2009-10-28 18:48:22 +01:00
|
|
|
this.confirmedValue = this.value;
|
|
|
|
this.writeAttribute("uid", contacts[this.selectedIndex].readAttribute("uid"));
|
2009-10-02 15:41:49 +02:00
|
|
|
contacts[this.selectedIndex].addClassName("selected");
|
2009-10-28 18:48:22 +01:00
|
|
|
var container = contacts[this.selectedIndex].readAttribute("container");
|
|
|
|
if (container)
|
|
|
|
this.writeAttribute("container", container);
|
2009-10-02 15:41:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-09-11 21:30:22 +02:00
|
|
|
},
|
2009-09-11 15:32:22 +02:00
|
|
|
|
|
|
|
onBlur: function (event) {
|
|
|
|
if (this.delayedSearch)
|
2009-10-02 15:41:49 +02:00
|
|
|
window.clearTimeout(this.delayedSearch);
|
2009-10-28 18:48:22 +01:00
|
|
|
if (this.confirmedValue) {
|
2009-10-02 15:41:49 +02:00
|
|
|
this.value = this.confirmedValue;
|
2009-10-28 18:48:22 +01:00
|
|
|
if (this.readAttribute("container"))
|
|
|
|
this.fire("autocompletion:changedlist", this.readAttribute("container"));
|
|
|
|
}
|
2009-09-11 15:32:22 +02:00
|
|
|
else
|
2009-10-28 18:48:22 +01:00
|
|
|
this.writeAttribute("uid", null);
|
2009-09-01 16:12:53 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
performSearch: function (input) {
|
2009-09-11 15:32:22 +02:00
|
|
|
// Perform address completion
|
2009-09-01 16:12:53 +02:00
|
|
|
if (document.contactLookupAjaxRequest) {
|
2009-09-11 15:32:22 +02:00
|
|
|
// Abort any pending request
|
|
|
|
document.contactLookupAjaxRequest.aborted = true;
|
|
|
|
document.contactLookupAjaxRequest.abort();
|
2009-09-01 16:12:53 +02:00
|
|
|
}
|
|
|
|
if (input.value.trim().length > 2) {
|
2009-10-28 18:48:22 +01:00
|
|
|
var urlstr = UserFolderURL + "Contacts/";
|
|
|
|
if (input.addressBook)
|
|
|
|
urlstr += input.addressBook + "/contact";
|
|
|
|
else
|
|
|
|
urlstr += "allContact";
|
|
|
|
urlstr += "Search?search=" + encodeURIComponent(input.value);
|
2009-09-11 15:32:22 +02:00
|
|
|
if (input.excludeGroups)
|
2009-10-02 15:41:49 +02:00
|
|
|
urlstr += "&excludeGroups=1";
|
2009-09-11 21:30:22 +02:00
|
|
|
if (input.excludeLists)
|
2009-10-02 15:41:49 +02:00
|
|
|
urlstr += "&excludeLists=1";
|
2009-09-11 15:32:22 +02:00
|
|
|
if (input.animationParent)
|
2009-10-02 15:41:49 +02:00
|
|
|
startAnimation(input.animationParent);
|
2009-09-01 16:12:53 +02:00
|
|
|
document.contactLookupAjaxRequest =
|
2009-10-02 15:41:49 +02:00
|
|
|
triggerAjaxRequest(urlstr, input.performSearchCallback.bind(input), input);
|
2009-09-01 16:12:53 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (document.currentPopupMenu)
|
2009-10-02 15:41:49 +02:00
|
|
|
hideMenu(document.currentPopupMenu);
|
2009-09-01 16:12:53 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
performSearchCallback: function (http) {
|
2009-09-11 15:32:22 +02:00
|
|
|
if (http.readyState == 4) {
|
|
|
|
var list = this.menu.down("ul");
|
|
|
|
|
2009-09-01 16:12:53 +02:00
|
|
|
var input = http.callbackData;
|
|
|
|
|
|
|
|
if (http.status == 200) {
|
2009-09-11 15:32:22 +02:00
|
|
|
var start = input.value.length;
|
|
|
|
var data = http.responseText.evalJSON(true);
|
2009-09-01 16:12:53 +02:00
|
|
|
|
2009-09-11 15:32:22 +02:00
|
|
|
if (data.contacts.length > 1) {
|
2009-09-01 16:12:53 +02:00
|
|
|
list.select("li").each(function(item) {
|
2009-10-02 15:41:49 +02:00
|
|
|
item.stopObserving("mousedown");
|
|
|
|
item.remove();
|
|
|
|
});
|
2009-09-11 15:32:22 +02:00
|
|
|
|
2009-09-01 16:12:53 +02:00
|
|
|
// Populate popup menu
|
|
|
|
for (var i = 0; i < data.contacts.length; i++) {
|
2009-09-11 15:32:22 +02:00
|
|
|
var contact = data.contacts[i];
|
2009-09-11 21:30:22 +02:00
|
|
|
var completeEmail = contact["c_cn"];
|
|
|
|
if (contact["c_mail"])
|
2009-10-02 15:41:49 +02:00
|
|
|
completeEmail += " <" + contact["c_mail"] + ">";
|
2009-10-28 18:48:22 +01:00
|
|
|
var node = new Element('li', { 'address': completeEmail,
|
|
|
|
'uid': contact[this.uidField] });
|
2009-09-11 15:32:22 +02:00
|
|
|
var matchPosition = completeEmail.toLowerCase().indexOf(data.searchText.toLowerCase());
|
|
|
|
var matchBefore = completeEmail.substring(0, matchPosition);
|
|
|
|
var matchText = completeEmail.substring(matchPosition, matchPosition + data.searchText.length);
|
|
|
|
var matchAfter = completeEmail.substring(matchPosition + data.searchText.length);
|
|
|
|
list.appendChild(node);
|
2009-09-11 21:30:22 +02:00
|
|
|
if (contact['c_name'].endsWith (".vlf")) {
|
2009-10-28 18:48:22 +01:00
|
|
|
// Keep track of list containers
|
2009-09-14 22:43:50 +02:00
|
|
|
node.writeAttribute("container", contact['container']);
|
2009-09-11 21:30:22 +02:00
|
|
|
}
|
2009-09-11 15:32:22 +02:00
|
|
|
node.appendChild(document.createTextNode(matchBefore));
|
|
|
|
node.appendChild(new Element('strong').update(matchText));
|
|
|
|
node.appendChild(document.createTextNode(matchAfter));
|
|
|
|
if (contact["contactInfo"])
|
2009-10-02 15:41:49 +02:00
|
|
|
node.appendChild(document.createTextNode(" (" + contact["contactInfo"] + ")"));
|
2009-09-11 15:32:22 +02:00
|
|
|
$(node).observe("mousedown", this.onAddressResultClick.bindAsEventListener(this));
|
2009-09-01 16:12:53 +02:00
|
|
|
}
|
2009-09-11 15:32:22 +02:00
|
|
|
|
2009-09-01 16:12:53 +02:00
|
|
|
// Show popup menu
|
|
|
|
var offsetScroll = Element.cumulativeScrollOffset(input);
|
2009-10-28 18:48:22 +01:00
|
|
|
var offset = Element.positionedOffset(input);
|
2010-04-01 22:24:29 +02:00
|
|
|
if (offset.top < 50)
|
|
|
|
// Hack for some situations where the offset must be computed differently
|
2009-10-28 18:48:22 +01:00
|
|
|
offset = Element.cumulativeOffset(input);
|
2009-11-04 23:13:20 +01:00
|
|
|
var top = offset.top - offsetScroll.top + node.offsetHeight + 3;
|
2009-09-01 16:12:53 +02:00
|
|
|
var height = 'auto';
|
|
|
|
var heightDiff = window.height() - offset[1];
|
|
|
|
var nodeHeight = node.getHeight();
|
2009-09-11 15:32:22 +02:00
|
|
|
|
2009-09-01 16:12:53 +02:00
|
|
|
if ((data.contacts.length * nodeHeight) > heightDiff)
|
2009-10-02 15:41:49 +02:00
|
|
|
// Limit the size of the popup to the window height, minus 12 pixels
|
|
|
|
height = parseInt(heightDiff/nodeHeight) * nodeHeight - 12 + 'px';
|
2009-09-11 15:32:22 +02:00
|
|
|
|
2009-09-01 16:12:53 +02:00
|
|
|
this.menu.setStyle({ top: top + "px",
|
2009-10-02 15:41:49 +02:00
|
|
|
left: offset[0] + "px",
|
|
|
|
height: height,
|
|
|
|
visibility: "visible" });
|
2009-09-01 16:12:53 +02:00
|
|
|
this.menu.scrollTop = 0;
|
2009-09-11 15:32:22 +02:00
|
|
|
|
2009-09-01 16:12:53 +02:00
|
|
|
document.currentPopupMenu = this.menu;
|
2009-09-11 15:32:22 +02:00
|
|
|
$(document.body).stopObserving("click");
|
2009-09-01 16:12:53 +02:00
|
|
|
$(document.body).observe("click", onBodyClickMenuHandler);
|
2009-09-11 15:32:22 +02:00
|
|
|
}
|
2009-10-28 18:48:22 +01:00
|
|
|
else {
|
2009-09-01 16:12:53 +02:00
|
|
|
if (document.currentPopupMenu)
|
2009-10-02 15:41:49 +02:00
|
|
|
hideMenu(document.currentPopupMenu);
|
2009-09-11 15:32:22 +02:00
|
|
|
|
2009-09-01 16:12:53 +02:00
|
|
|
if (data.contacts.length == 1) {
|
2009-09-11 15:32:22 +02:00
|
|
|
// Single result
|
|
|
|
var contact = data.contacts[0];
|
2009-10-28 18:48:22 +01:00
|
|
|
input.writeAttribute("uid", contact[this.uidField]);
|
|
|
|
if (contact['c_name'].endsWith(".vlf")) {
|
2009-09-14 22:43:50 +02:00
|
|
|
this.writeAttribute("container", contact['container']);
|
2009-09-11 21:30:22 +02:00
|
|
|
}
|
2009-10-28 18:48:22 +01:00
|
|
|
var completeEmail = contact["c_cn"];
|
|
|
|
if (contact["c_mail"])
|
|
|
|
completeEmail += " <" + contact["c_mail"] + ">";
|
|
|
|
if (contact["c_cn"].substring(0, input.value.length).toUpperCase()
|
|
|
|
== input.value.toUpperCase())
|
|
|
|
input.value = completeEmail;
|
|
|
|
else
|
|
|
|
// The result matches email address, not user name
|
|
|
|
input.value += ' >> ' + completeEmail;
|
|
|
|
input.confirmedValue = completeEmail;
|
|
|
|
|
|
|
|
var end = input.value.length;
|
|
|
|
$(input).selectText(start, end);
|
|
|
|
|
|
|
|
this.selectedIndex = -1;
|
2009-09-01 16:12:53 +02:00
|
|
|
}
|
2009-09-11 15:32:22 +02:00
|
|
|
}
|
2009-09-01 16:12:53 +02:00
|
|
|
}
|
|
|
|
else
|
2009-10-02 15:41:49 +02:00
|
|
|
if (document.currentPopupMenu)
|
|
|
|
hideMenu(document.currentPopupMenu);
|
2009-09-01 16:12:53 +02:00
|
|
|
document.contactLookupAjaxRequest = null;
|
2009-09-11 15:32:22 +02:00
|
|
|
}
|
2009-09-01 16:12:53 +02:00
|
|
|
},
|
2009-09-11 15:32:22 +02:00
|
|
|
|
2009-09-01 16:12:53 +02:00
|
|
|
onAddressResultClick: function(event) {
|
2009-09-11 15:32:22 +02:00
|
|
|
var e = Event.element(event);
|
|
|
|
if (e.tagName != 'LI')
|
2009-10-02 15:41:49 +02:00
|
|
|
e = e.up('LI');
|
2009-09-11 15:32:22 +02:00
|
|
|
if (e) {
|
2009-10-28 18:48:22 +01:00
|
|
|
this.value = e.readAttribute("address");
|
|
|
|
this.writeAttribute("uid", e.readAttribute("uid"));
|
|
|
|
if (e.readAttribute("container"))
|
|
|
|
this.fire("autocompletion:changedlist", e.readAttribute("container"));
|
2009-09-11 21:30:22 +02:00
|
|
|
else {
|
2009-10-28 18:48:22 +01:00
|
|
|
this.confirmedValue = this.value;
|
|
|
|
this.fire("autocompletion:changed");
|
2009-09-11 21:30:22 +02:00
|
|
|
}
|
2009-09-11 15:32:22 +02:00
|
|
|
}
|
2009-09-01 16:12:53 +02:00
|
|
|
}
|
|
|
|
};
|