//
-// $Id: wclib.js,v 625.2 2005/09/18 04:04:32 ajc Exp $
+// $Id$
//
// JavaScript function library for WebCit.
//
var ns6=document.getElementById&&!document.all;
-//
-// This code handles the popups for instant messages.
-//
+function CtdlRandomString() {
+ return((Math.random()+'').substr(3));
+}
-function hide_page_popup() {
- if (browserType == "gecko" )
- document.poppedLayer = eval('document.getElementById(\'page_popup\')');
- else if (browserType == "ie")
- document.poppedLayer = eval('document.all[\'page_popup\']');
- else
- document.poppedLayer = eval('document.layers[\'`page_popup\']');
- document.poppedLayer.style.visibility = "hidden";
+// We love string tokenizers.
+function extract_token(source_string, token_num, delimiter) {
+ var i = 0;
+ var extracted_string = source_string;
+
+ if (token_num > 0) {
+ for (i=0; i<token_num; ++i) {
+ var j = extracted_string.indexOf(delimiter);
+ if (j >= 0) {
+ extracted_string = extracted_string.substr(j+1);
+ }
+ }
+ }
+
+ j = extracted_string.indexOf(delimiter);
+ if (j >= 0) {
+ extracted_string = extracted_string.substr(0, j);
+ }
+
+ return extracted_string;
}
+
+
+// This code handles the popups for important-messages.
function hide_imsg_popup() {
if (browserType == "gecko" )
document.poppedLayer = eval('document.getElementById(\'important_message\')');
document.poppedLayer.style.visibility = "hidden";
}
+
// This function activates the ajax-powered recipient autocompleters on the message entry screen.
function activate_entmsg_autocompleters() {
new Ajax.Autocompleter('cc_id', 'cc_name_choices', 'cc_autocomplete', {} );
function switch_to_room_list() {
$('iconbar').innerHTML = $('iconbar').innerHTML.substr(0, $('iconbar').innerHTML.indexOf('switch'));
+ CtdlLoadScreen('iconbar');
new Ajax.Updater('iconbar', 'iconbar_ajax_rooms', { method: 'get' } );
}
function switch_to_menu_buttons() {
which_div_expanded = null;
num_drop_targets = 0;
+ CtdlLoadScreen('iconbar');
new Ajax.Updater('iconbar', 'iconbar_ajax_menu', { method: 'get' } );
}
//
var CtdlNumMsgsSelected = 0;
var CtdlMsgsSelected = new Array();
+var CtdlLastMsgnumSelected = 0;
// This gets called when you single click on a message in the mailbox view.
// We know that the element id of the table row will be the letter 'm' plus the message number.
// Clear the preview pane until we load the new message
$('preview_pane').innerHTML = '';
- // De-select any messages that were already selected, *unless* the Ctrl key
- // is being pressed, in which case the user wants multi select.
- if (!evt.ctrlKey) {
+ // De-select any messages that were already selected, *unless* the Ctrl or
+ // Shift key is being pressed, in which case the user wants multi select
+ // or group select.
+ if ( (!evt.ctrlKey) && (!evt.shiftKey) ) {
if (CtdlNumMsgsSelected > 0) {
for (i=0; i<CtdlNumMsgsSelected; ++i) {
$('m'+CtdlMsgsSelected[i]).style.backgroundColor = '#fff';
for (i=0; i<CtdlNumMsgsSelected; ++i) {
if (CtdlMsgsSelected[i] == msgnum) {
already_selected = 1;
+ already_selected_pos = i;
}
}
}
// Now select (or de-select) the message
if ( (evt.ctrlKey) && (already_selected == 1) ) {
+
+ // Deselect: first un-highlight it...
$('m'+msgnum).style.backgroundColor = '#fff';
$('m'+msgnum).style.color = '#000';
+
+ // Then remove it from the selected messages list.
+ for (i=already_selected_pos; i<(CtdlNumMsgsSelected-1); ++i) {
+ CtdlMsgsSelected[i] = CtdlMsgsSelected[i+1];
+ }
+ CtdlNumMsgsSelected = CtdlNumMsgsSelected - 1;
+
}
+
+ else if (evt.shiftKey) {
+
+ // Group select: first clear everything out...
+ if (CtdlNumMsgsSelected > 0) {
+ for (i=0; i<CtdlNumMsgsSelected; ++i) {
+ $('m'+CtdlMsgsSelected[i]).style.backgroundColor = '#fff';
+ $('m'+CtdlMsgsSelected[i]).style.color = '#000';
+ }
+ }
+ CtdlNumMsgsSelected = 0;
+
+ // Then highlight and select the group.
+ // Traverse the table looking for a row whose ID contains the desired msgnum
+
+ var in_the_group = 0;
+ var is_edge = 0;
+ var table = $('summary_headers');
+ if (table) {
+ for (var r = 0; r < table.rows.length; r++) {
+ var thename = table.rows[r].id;
+ if ( (thename.substr(1) == msgnum) || (thename.substr(1) == CtdlLastMsgnumSelected) ) {
+ in_the_group = 1 - in_the_group;
+ is_edge = 1;
+ }
+ else {
+ is_edge = 0;
+ }
+ if ( (in_the_group == 1) || (is_edge == 1) ) {
+ // Highlight it...
+ table.rows[r].style.backgroundColor='#69aaff';
+ table.rows[r].style.color='#fff';
+
+ // And add it to the selected messages list.
+ CtdlNumMsgsSelected = CtdlNumMsgsSelected + 1;
+ CtdlMsgsSelected[CtdlNumMsgsSelected-1] = thename.substr(1);
+ }
+ }
+ }
+ }
+
else {
+ // Select: first highlight it...
$('m'+msgnum).style.backgroundColor='#69aaff';
$('m'+msgnum).style.color='#fff';
+
+ // Then add it to the selected messages list.
CtdlNumMsgsSelected = CtdlNumMsgsSelected + 1;
CtdlMsgsSelected[CtdlNumMsgsSelected-1] = msgnum;
- }
-
- // Update the preview pane
- new Ajax.Updater('preview_pane', 'msg/'+msgnum, { method: 'get' } );
- // Mark the message as read
- new Ajax.Request(
- 'ajax_servcmd', {
- method: 'post',
- parameters: 'g_cmd=SEEN '+msgnum+'|1',
- onComplete: CtdlRemoveTheUnseenBold(msgnum)
- }
- );
+ // Gradient
+ CtdlLoadScreen('preview_pane');
+ // Update the preview pane
+ new Ajax.Updater('preview_pane', 'msg/'+msgnum, { method: 'get' } );
+
+ // Mark the message as read
+ new Ajax.Request(
+ 'ajax_servcmd', {
+ method: 'post',
+ parameters: 'g_cmd=SEEN '+msgnum+'|1',
+ onComplete: CtdlRemoveTheUnseenBold(msgnum)
+ }
+ );
+ }
+
+ // Save the selected position in case the user does a group select next time.
+ CtdlLastMsgnumSelected = msgnum;
return false; // try to defeat the default click behavior
}
}
// A message has been deleted, so yank it from the list.
-// (IE barfs on m9999.innerHTML='' so we use a script.aculo.us effect instead.)
function CtdlClearDeletedMsg(msgnum) {
- new Effect.Squish('m'+msgnum);
-}
+ // Traverse the table looking for a row whose ID contains the desired msgnum
+ var table = $('summary_headers');
+ if (table) {
+ for (var r = 0; r < table.rows.length; r++) {
+ var thename = table.rows[r].id;
+ if (thename.substr(1) == msgnum) {
+ try {
+ table.deleteRow(r);
+ }
+ catch(e) {
+ alert('error: browser failed to clear row ' + r);
+ }
+ }
+ }
+ }
+ else { // if we can't delete it,
+ new Effect.Squish('m'+msgnum); // just hide it.
+ }
+
+
+}
+
// These functions called when the user down-clicks on the message list resizer bar
var saved_x = 0;
+
+
+// These functions handle moving sticky notes around the screen by dragging them
+
+var uid_of_note_being_dragged = 0;
+var saved_cursor_style = 'default';
+var note_was_dragged = 0;
+
+function NotesDragMouseUp(evt) {
+ document.onmouseup = null;
+ document.onmousemove = null;
+ if (document.layers) {
+ document.releaseEvents(Event.MOUSEUP | Event.MOUSEMOVE);
+ }
+
+ d = $('note-' + uid_of_note_being_dragged);
+ d.style.cursor = saved_cursor_style;
+
+ // If any motion actually occurred, submit an ajax http call to record it to the server
+ if (note_was_dragged > 0) {
+ p = 'note_uid=' + uid_of_note_being_dragged
+ + '&left=' + d.style.left
+ + '&top=' + d.style.top
+ + '&r=' + CtdlRandomString();
+ new Ajax.Request(
+ 'ajax_update_note',
+ {
+ method: 'post',
+ parameters: p
+ }
+ );
+ }
+
+ uid_of_note_being_dragged = '';
+ return true;
+}
+
+function NotesDragMouseMove(evt) {
+ x = (ns6 ? evt.clientX : event.clientX);
+ x_increment = x - saved_x;
+ y = (ns6 ? evt.clientY : event.clientY);
+ y_increment = y - saved_y;
+
+ // Move the div
+ d = $('note-' + uid_of_note_being_dragged);
+
+ divTop = parseInt(d.style.top);
+ divLeft = parseInt(d.style.left);
+
+ d.style.top = (divTop + y_increment) + 'px';
+ d.style.left = (divLeft + x_increment) + 'px';
+
+ saved_x = x;
+ saved_y = y;
+ note_was_dragged = 1;
+ return true;
+}
+
+
+function NotesDragMouseDown(evt, uid) {
+ saved_x = (ns6 ? evt.clientX : event.clientX);
+ saved_y = (ns6 ? evt.clientY : event.clientY);
+ document.onmouseup = NotesDragMouseUp;
+ document.onmousemove = NotesDragMouseMove;
+ if (document.layers) {
+ document.captureEvents(Event.MOUSEUP | Event.MOUSEMOVE);
+ }
+ uid_of_note_being_dragged = uid;
+ d = $('note-' + uid_of_note_being_dragged);
+ saved_cursor_style = d.style.cursor;
+ d.style.cursor = 'move';
+ return false; // disable the default action
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
// These functions handle drag and drop message moving
var mm_div = null;
}
+
+// This function handles the creation of new notes in the "Notes" view.
+//
+function add_new_note() {
+
+ new_eid = CtdlRandomString();
+
+ $('new_notes_here').innerHTML = $('new_notes_here').innerHTML
+ + '<IMG ALIGN=MIDDLE src=\"static/storenotes_48x.gif\" id=\"' + new_eid + '\" alt=\"Note\" class=\"notes\">'
+ + '<script type=\"text/javascript\">new Draggable (\"%s\", {revert:true})</script>'
+ + '<span id=\"note' + new_eid + '\">' + Date() + '</span><br />'
+ ;
+
+ new Ajax.InPlaceEditor('note' + new_eid,
+ 'updatenote?eid=' + new_eid , {rows:5,cols:72});
+}
+
+function CtdlShowRaw(msgnum) {
+var customnav = document.createElement("span");
+var mode_citadel = document.createElement("a");
+mode_citadel.appendChild(document.createTextNode("Citadel Source"));
+var mode_rfc822 = document.createElement("a");
+mode_rfc822.appendChild(document.createTextNode(" RFC822 Source"));
+mode_citadel.setAttribute("href","#");
+mode_rfc822.setAttribute("href","#");
+mode_rfc822.setAttribute("onclick","rawSwitch822('" + msgnum + "');");
+mode_citadel.setAttribute("onclick","rawSwitchCitadel('" + msgnum + "');");
+customnav.appendChild(mode_citadel);
+customnav.appendChild(mode_rfc822);
+customnav.setAttribute("class","floatcustomnav");
+floatwindow("headerscreen","pre",customnav);
+rawSwitch822(msgnum);
+}
+
+function rawSwitch822(msgnum) {
+CtdlLoadScreen("headerscreen");
+new Ajax.Updater("headerscreen",
+'ajax_servcmd_esc',
+ { method: 'post',parameters: 'g_cmd=MSG2 ' +msgnum } );
+
+}
+
+function rawSwitchCitadel(msgnum) {
+CtdlLoadScreen("headerscreen");
+new Ajax.Updater("headerscreen",
+'ajax_servcmd_esc',
+ { method: 'post',parameters: 'g_cmd=MSG0 ' +msgnum } );
+
+}
+
+function floatwindow(newdivid,contentelementtype,customnav) {
+var windiv = document.createElement("div");
+windiv.setAttribute("class","floatwindow");
+var winid = newdivid+"_window";
+windiv.setAttribute("id",winid);
+var nav = document.createElement("div");
+if (customnav != null) {
+nav.appendChild(customnav);
+}
+var minimizeA = document.createElement("a");
+var minimizeButton = document.createTextNode("Close");
+minimizeA.appendChild(minimizeButton);
+minimizeA.setAttribute("onclick","killFloatWindow(this);");
+minimizeA.setAttribute("href","#");
+nav.appendChild(minimizeA);
+nav.setAttribute("class","floatnav");
+windiv.appendChild(nav);
+var contentarea = document.createElement("pre");
+contentarea.setAttribute("class","floatcontent");
+contentarea.setAttribute("id",newdivid);
+windiv.appendChild(contentarea);
+document.body.appendChild(windiv);
+}
+function killFloatWindow(caller) {
+var span = caller.parentNode;
+var fwindow = span.parentNode;
+fwindow.parentNode.removeChild(fwindow);
+}
+// Place a gradient loadscreen on an element, e.g to use before Ajax.updater
+function CtdlLoadScreen(elementid) {
+var elem = document.getElementById(elementid);
+elem.innerHTML = "<div align=center><br><table border=0 cellpadding=10 bgcolor=\"#ffffff\"><tr><td><img src=\"static/throbber.gif\" /><font color=\"#AAAAAA\"> Loading....</font></td></tr></table><br /></div>";
+}
+
+
+// Show info for a user, basically replaces showuser()
+// matt@comalies is to blame for this poorly coded masterpiece.
+function CtdlShowUserInfoPopup(Element) {
+ try {
+ // hopefully no one needs to use the class attribute... could be better done
+ // with xmlns though..
+ var user = Element.getAttribute("class");
+ var updname = "biospace_"+user;
+ if (document.getElementById(updname) == null) {
+ // insert a space for the bio
+ var pNode = Element.parentNode;
+ var newdiv = document.createElement("div");
+ newdiv.id = updname;
+ newdiv.innerHTML = "Getting user info....";
+ pNode.appendChild(newdiv);
+ CtdlLoadScreen(updname);
+ new Ajax.Updater(updname, 'showuser_ajax?who='+user, { method: 'get' } );
+ }
+ }
+ catch(err) {
+ return true;
+ }
+ return false;
+}
+
+
+
+// Pop open the address book (target_input is the INPUT field to populate)
+
+function PopOpenAddressBook(target_input) {
+ $('address_book_popup').style.display = 'block';
+ p = 'target_input=' + target_input + '&r=' + CtdlRandomString();
+ new Ajax.Updater(
+ 'address_book_popup_middle_div',
+ 'display_address_book_middle_div',
+ {
+ method: 'get',
+ parameters: p,
+ evalScripts: true
+ }
+ );
+}
+
+function PopulateAddressBookInnerDiv(which_addr_book, target_input) {
+ $('address_book_inner_div').innerHTML = "<div align=center><br><table border=0 cellpadding=10 bgcolor=\"#ffffff\"><tr><td><img src=\"static/throbber.gif\" /><font color=\"#AAAAAA\"> Loading....</font></td></tr></table><br /></div>";
+ p = 'which_addr_book=' + which_addr_book
+ + '&target_input=' + target_input
+ + '&r=' + CtdlRandomString();
+ new Ajax.Updater(
+ 'address_book_inner_div',
+ 'display_address_book_inner_div',
+ {
+ method: 'get',
+ parameters: p
+ }
+ );
+}
+
+// What happens when a contact is selected from the address book popup
+// (populate the specified target)
+
+function AddContactsToTarget(target, whichaddr) {
+ while (whichaddr.selectedIndex != -1) {
+ if (target.value.length > 0) {
+ target.value = target.value + ', ';
+ }
+ target.value = target.value + whichaddr.value;
+ whichaddr.options[whichaddr.selectedIndex].selected = false;
+ }
+}
+
+// Respond to a meeting invitation
+function RespondToInvitation(question_divname, title_divname, msgnum, cal_partnum, sc) {
+ p = 'msgnum=' + msgnum + '&cal_partnum=' + cal_partnum + '&sc=' + sc ;
+ new Ajax.Updater(title_divname, 'respond_to_request', { method: 'post', parameters: p } );
+ Effect.Fade(question_divname, { duration: 0.5 });
+}
+
+// Handle a received RSVP
+function HandleRSVP(question_divname, title_divname, msgnum, cal_partnum, sc) {
+ p = 'msgnum=' + msgnum + '&cal_partnum=' + cal_partnum + '&sc=' + sc ;
+ new Ajax.Updater(title_divname, 'handle_rsvp', { method: 'post', parameters: p } );
+ Effect.Fade(question_divname, { duration: 0.5 });
+}
+