1 /** Webcit Summary View v2
2 All comments, flowers and death threats to Mathew McBride
3 <matt@mcbridematt.dhs.org> / <matt@comalies>
5 document.observe("dom:loaded", createMessageView);
7 var message_view = null;
10 var currentSortMode = null;
14 var mlh_subject = null;
16 var currentSorterToggle = null;
18 var currentlyMarkedRows = new Object();
20 var mouseDownEvent = null;
21 var exitedMouseDown = false;
24 "rdate" : sortRowsByDateDescending,
25 "date" : sortRowsByDateAscending,
26 // "reverse" : sortRowsByDateDescending,
27 "subj" : sortRowsBySubjectAscending,
28 "rsubj" : sortRowsBySubjectDescending,
29 "sender": sortRowsByFromAscending,
30 "rsender" : sortRowsByFromDescending
33 window.console = window.console || {};
34 var opera = opera || null;
35 if (opera && opera.postError) {
36 console.log = opera.postError;
40 function createMessageView() {
41 message_view = document.getElementById("message_list_body");
42 loadingMsg = document.getElementById("loading");
44 mlh_date = $("mlh_date");
45 mlh_subject = $('mlh_subject');
46 mlh_from = $('mlh_from');
47 toggles["rdate"] = mlh_date;
48 toggles["date"] = mlh_date;
49 // toggles["reverse"] = mlh_date;
50 toggles["subj"] = mlh_subject;
51 toggles["rsubj"] = mlh_subject;
52 toggles["sender"] = mlh_from;
53 toggles["rsender"] = mlh_from;
54 mlh_date.observe('click',ApplySort);
55 mlh_subject.observe('click',ApplySort);
56 mlh_from.observe('click',ApplySort);
57 $(document).observe('keyup',CtdlMessageListKeyUp,false);
58 window.oncontextmenu = function() { return false; };
59 $('resize_msglist').observe('mousedown', CtdlResizeMouseDown);
60 $('m_refresh').observe('click', getMessages);
61 document.getElementById('m_refresh').setAttribute("href","#");
62 Event.observe(document.onresize ? document : window, "resize", normalizeHeaderTable);
64 Event.observe(document.onresize ? document : window, "resize", sizePreviewPane);
65 $('summpage').observe('change', getPage);
66 takeOverSearchOMatic();
67 setupDragDrop(); // here for now
69 function getMessages() {
70 if (loadingMsg.parentNode == null) {
71 message_view.innerHTML = "";
72 message_view.appendChild(loadingMsg);
74 roomName = getTextContent(document.getElementById("rmname"));
75 var parameters = {'room':roomName, 'startmsg': startmsg};
77 parameters['maxmsgs'] = 500;
78 if (currentSortMode != null) {
79 var SortBy = currentSortMode[0];
80 if (SortBy.charAt(0) == 'r') {
81 SortBy = SortBy.substr(1);
82 parameters["SortOrder"] = "2";
84 parameters["SortBy"] = SortBy;
87 if (query.length > 0) {
88 parameters["query"] = query;
90 new Ajax.Request("roommsgs", {
92 onSuccess: loadMessages,
93 parameters: parameters,
96 onFailure: function(e) { alert("Failure: " + e);}
99 function loadMessages(transport) {
101 var data = eval('('+transport.responseText+')');
102 if (!!data && transport.responseText.length < 2) {
103 alert("Message loading failed");
105 nummsgs = data['nummsgs'];
106 var msgs = data['msgs'];
107 var length = msgs.length;
108 rowArray = new Array(); // store so they can be sorted
109 var start = new Date();
110 for(var i=0; i<length;i++) {
111 var trElement = document.createElement("tr");
114 var rowId = "msg_" + msgId;
115 trElement.setAttribute("id",rowId);
116 //$(trElement).observe('click', CtdlMessageListClick);
117 trElement.ctdlMsgId = msgId;
118 for(var j=1; j<5;j++) { // 1=msgId (hidden), 4 date timestamp (hidden) 6 = isNew etc.
119 var content = data[j];
120 if(content.length < 1) {
124 trElement.ctdlDate = content;
127 var tdElement = document.createElement("td");
128 trElement.appendChild(tdElement);
129 var txtContent = document.createTextNode(content);
130 tdElement.appendChild(txtContent);
133 var classStmt = "col"+x;
134 tdElement.setAttribute("class", classStmt);
136 if (!!window.console && !!console.log) {
137 console.log("Error on #"+msgId +" col"+j+":"+e);
143 trElement.setAttribute("class", "new_message");
145 trElement.dropEnabled = true;
146 trElement.ctdlRowId = i;
147 trElement.ctdlMarked = false;
148 rowArray[i] = trElement;
150 var end = new Date();
151 if (!!window.console && !!console.log) {
152 var delta = end.getTime() - start.getTime();
153 console.log("loadMessages construct: " + delta);
158 if (currentSortMode == null) {
159 if (sortmode.length < 1) {
162 currentSortMode = [sortmode, sortModes[sortmode]];
163 currentSorterToggle = toggles[sortmode];
166 resortAndDisplay(sortRowsByDateDescending);
168 resortAndDisplay(null);
170 loadingMsg.parentNode.removeChild(loadingMsg);
174 function resortAndDisplay(sortMode) {
175 var start = new Date();
176 emptyElement(message_view);
177 var fragment = document.createDocumentFragment();
178 if (sortMode != null) {
179 rowArray.sort(sortMode);
181 var length = rowArray.length;
182 for(var x=0; x<length; ++x) {
184 var currentRow = rowArray[x];
185 var className = currentRow.className;
186 className = className.replace("table-alt-row","");
187 className = className.replace("table-row","");
188 if (((x-1) % 2) == 0) {
189 className += " table-alt-row";
191 className += " table-row";
193 currentRow.className = className;
194 /* Using element.onclick is evil, but until IE
195 supports addEventListener, it is much faster
196 than prototype observe */
197 currentRow.onclick = CtdlMessageListClick;
198 currentRow.ctdlDnDElement = summaryViewDragAndDropHandler;
199 fragment.appendChild(currentRow);
201 alert("Exception" + e);
204 message_view.appendChild(fragment);
205 var end = new Date();
206 if (!!window.console && !!console.log) {
207 var delta = end.getTime() - start.getTime();
208 console.log("resortAndDisplay sort and append: " + delta);
211 normalizeHeaderTable();
213 function sortRowsByDateAscending(a, b) {
214 var dateOne = a.ctdlDate;
215 var dateTwo = b.ctdlDate;
216 return (dateOne - dateTwo);
218 function sortRowsByDateDescending(a, b) {
219 var dateOne = a.ctdlDate;
220 var dateTwo = b.ctdlDate;
221 return (dateTwo - dateOne);
224 function sortRowsBySubjectAscending(a, b) {
225 var subjectOne = getTextContent(a.getElementsByTagName("td")[0]).toLowerCase();
226 var subjectTwo = getTextContent(b.getElementsByTagName("td")[0]).toLowerCase();
227 return (subjectOne.charCodeAt(0) - subjectTwo.charCodeAt(0));
230 function sortRowsBySubjectDescending(a, b) {
231 var subjectOne = getTextContent(a.getElementsByTagName("td")[0]).toLowerCase();
232 var subjectTwo = getTextContent(b.getElementsByTagName("td")[0]).toLowerCase();
233 return (subjectTwo.charCodeAt(0) - subjectOne.charCodeAt(0));
236 function sortRowsByFromAscending(a, b) {
237 var fromOne = getTextContent(a.getElementsByTagName("td")[1]).toLowerCase();
238 var fromTwo = getTextContent(b.getElementsByTagName("td")[1]).toLowerCase();
239 return (fromOne.charCodeAt(0) - fromTwo.charCodeAt(0));
242 function sortRowsByFromDescending(a, b) {
243 var fromOne = getTextContent(a.getElementsByTagName("td")[1]).toLowerCase();
244 var fromTwo = getTextContent(b.getElementsByTagName("td")[1]).toLowerCase();
245 return (fromTwo.charCodeAt(0) - fromOne.charCodeAt(0));
248 function CtdlMessageListClick(evt) {
249 /* Since element.onload is used here, test to see if evt is defined */
250 var event = evt ? evt : window.event;
251 var target = event.target ? event.target: event.srcElement; // and again..
252 var parent = target.parentNode;
253 var msgId = parent.ctdlMsgId;
254 // If the ctrl key modifier wasn't used, unmark all rows and load the message
255 if (!event.shiftKey && !event.ctrlKey) {
257 new Ajax.Updater('preview_pane', 'msg/'+msgId, {method: 'get'});
259 new Ajax.Request('ajax_servcmd', {
261 parameters: 'g_cmd=SEEN ' + msgId + '|1',
262 onComplete: CtdlMarkRowAsRead(parent)});
263 } else if (event.button != 2) {
265 // TODO: introduce code to mark rows inbetween
268 function CtdlMarkRowAsRead(rowElement) {
269 var classes = rowElement.className;
270 classes = classes.replace("new_message","");
271 rowElement.className = classes;
273 function ApplySort(event) {
274 var target = event.target;
275 var sortId = target.id;
276 removeOldSortClass();
277 currentSorterToggle = target;
278 var sortModes = getSortMode(target); // returns [[key, func],[key,func]]
279 var sortModeToUse = null;
280 if (currentSortMode[0] == sortModes[0][0]) {
281 sortModeToUse = sortModes[1];
283 sortModeToUse = sortModes[0];
285 currentSortMode = sortModeToUse;
287 getMessages(); // in safe mode, we load from server already sorted
289 resortAndDisplay(sortModeToUse[1]);
292 function getSortMode(toggleElem) {
295 for(var key in toggles) {
296 var kr = (key.charAt(0) == 'r');
297 if (toggles[key] == toggleElem && !kr) {
298 forward = [key, sortModes[key]];
299 } else if (toggles[key] == toggleElem && kr) {
300 reverse = [key, sortModes[key]];
303 return [forward, reverse];
305 function removeOldSortClass() {
306 if (currentSorterToggle) {
307 var classes = currentSorterToggle.className;
308 classes = classes.replace("current_sort_mode","");
309 classes = classes.replace("sort_ascending","");
310 classes = classes.replace("sort_descending","");
311 currentSorterToggle.className = classes;
314 function markRow( row) {
315 var msgId = row.ctdlMsgId;
316 row.className = row.className += " marked_row";
317 row.ctdlMarked = true;
318 currentlyMarkedRows[msgId] = row;
320 function unmarkRow(row) {
321 var msgId = row.ctdlMsgId;
322 row.className = row.className.replace("marked_row","");
323 row.ctdlMarked = false;
324 delete currentlyMarkedRows[msgId];
326 function unmarkAllRows() {
327 for(msgId in currentlyMarkedRows) {
328 unmarkRow(currentlyMarkedRows[msgId]);
331 function deleteAllMarkedRows() {
332 for(msgId in currentlyMarkedRows) {
333 var row = currentlyMarkedRows[msgId];
334 var rowArrayId = row.ctdlRowId;
335 row.parentNode.removeChild(row);
336 delete currentlyMarkedRows[msgId];
337 delete rowArray[rowArrayId];
340 function CtdlMessageListKeyUp(event) {
341 var key = event.which;
342 if (key == 46) { // DELETE
343 for(msgId in currentlyMarkedRows) {
344 new Ajax.Request('ajax_servcmd',
346 parameters: 'g_cmd=MOVE ' + msgId + '|_TRASH_|0',
349 deleteAllMarkedRows();
353 function clearMessage(msgId) {
354 var row = document.getElementById('msg_'+msgId);
355 row.parentNode.removeChild(row);
356 delete currentlyMarkedRows[msgId];
359 function summaryViewContextMenu() {
360 if (!exitedMouseDown) {
361 var contextSource = document.getElementById("listViewContextMenu");
362 CtdlSpawnContextMenu(mouseDownEvent, contextSource);
366 function summaryViewDragAndDropHandler() {
367 var element = document.createElement("div");
368 var msgList = document.createElement("ul");
369 element.appendChild(msgList);
370 for(msgId in currentlyMarkedRows) {
371 msgRow = currentlyMarkedRows[msgId];
372 var subject = getTextContent(msgRow.getElementsByTagName("td")[0]);
373 var li = document.createElement("li");
374 msgList.appendChild(li);
375 setTextContent(li, subject);
376 li.ctdlMsgId = msgId;
382 function CtdlResizeMouseDown(event) {
383 $(document).observe('mousemove', CtdlResizeMouseMove);
384 $(document).observe('mouseup', CtdlResizeMouseUp);
385 saved_y = event.clientY;
388 function sizePreviewPane() {
389 var preview_pane = document.getElementById("preview_pane");
390 var content = $('content'); // we'd like to use prototype methods here
391 var childElements = content.childElements();
392 var sizeOfElementsAbove = 0;
393 var heightOfContent = content.offsetHeight;
394 for(var i=0; i<childElements.length; i++) {
395 var element = childElements[i];
396 if (element.id != 'preview_pane') {
397 var height = element.offsetHeight;
398 sizeOfElementsAbove += height;
401 preview_pane.style.height = (heightOfContent-sizeOfElementsAbove)+"px";
403 function CtdlResizeMouseMove(event) {
404 var clientX = event.clientX;
405 var clientY = event.clientY;
406 var summary_view = document.getElementById("summary_view");
407 var summaryViewHeight = summary_view.offsetHeight;
408 var increment = clientY-saved_y;
409 summary_view.style.height = (increment+summaryViewHeight)+"px";
410 var msglist = document.getElementById("preview_pane");
411 var msgListHeight = msglist.offsetHeight;
412 msglist.style.height = (msgListHeight-increment)+"px";
414 /* For some reason the grippy doesn't work without position: absolute
415 so we need to set its top pos manually all the time */
416 var resize = document.getElementById("resize_msglist");
417 var resizePos = resize.offsetTop;
418 resize.style.top = (resizePos+increment)+"px";
420 function CtdlResizeMouseUp(event) {
421 $(document).stopObserving('mousemove', CtdlResizeMouseMove);
422 $(document).stopObserving('mouseup', CtdlResizeMouseUp);
424 function ApplySorterToggle() {
425 var className = currentSorterToggle.className;
426 className += " current_sort_mode";
427 if (currentSortMode[1] == sortRowsByDateDescending ||
428 currentSortMode[1] == sortRowsBySubjectDescending ||
429 currentSortMode[1] == sortRowsByFromDescending) {
430 className += " sort_descending";
432 className += " sort_ascending";
434 currentSorterToggle.className = className;
436 /** Hack to make the header table line up with the data */
437 function normalizeHeaderTable() {
438 var message_list_hdr = document.getElementById("message_list_hdr");
439 var summary_view = document.getElementById("summary_view");
440 var headerTable = message_list_hdr.getElementsByTagName("table")[0];
441 var dataTable = summary_view.getElementsByTagName("table")[0];
442 var dataTableWidth = dataTable.offsetWidth;
443 headerTable.style.width = dataTableWidth+"px";
446 function setupPageSelector() {
447 var summpage = document.getElementById("summpage");
448 summpage.innerHTML = "";
450 summpage.parentNode.style.display="inline !important"; //override webcit.css
454 var pages = nummsgs / 500;
455 for(var i=0; i<pages; i++) {
456 var opt = document.createElement("option");
457 var startmsg = i * 500;
458 opt.setAttribute("value",startmsg);
459 opt.appendChild(document.createTextNode((i+1)));
460 summpage.appendChild(opt);
463 function getPage(event) {
464 var target = event.target;
465 startmsg = target.options.item(target.selectedIndex).value;
468 function takeOverSearchOMatic() {
469 var searchForm = document.getElementById("searchomatic").getElementsByTagName("form")[0];
470 // First disable the form post
471 searchForm.setAttribute("action","javascript:void();");
472 searchForm.removeAttribute("method");
473 $(searchForm).observe('submit', doSearch);
475 function doSearch() {
476 query = document.getElementById("srchquery").value;