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();
19 var markedRowId = null;
21 var mouseDownEvent = null;
22 var exitedMouseDown = false;
25 "rdate" : sortRowsByDateDescending,
26 "date" : sortRowsByDateAscending,
27 // "reverse" : sortRowsByDateDescending,
28 "subj" : sortRowsBySubjectAscending,
29 "rsubj" : sortRowsBySubjectDescending,
30 "sender": sortRowsByFromAscending,
31 "rsender" : sortRowsByFromDescending
37 function createMessageView() {
38 message_view = document.getElementById("message_list_body");
39 loadingMsg = document.getElementById("loading");
41 mlh_date = $("mlh_date");
42 mlh_subject = $('mlh_subject');
43 mlh_from = $('mlh_from');
44 toggles["rdate"] = mlh_date;
45 toggles["date"] = mlh_date;
46 // toggles["reverse"] = mlh_date;
47 toggles["subj"] = mlh_subject;
48 toggles["rsubj"] = mlh_subject;
49 toggles["sender"] = mlh_from;
50 toggles["rsender"] = mlh_from;
51 mlh_date.observe('click',ApplySort);
52 mlh_subject.observe('click',ApplySort);
53 mlh_from.observe('click',ApplySort);
54 $(document).observe('keyup',CtdlMessageListKeyUp,false);
55 window.oncontextmenu = function() { return false; };
56 $('resize_msglist').observe('mousedown', CtdlResizeMouseDown);
57 $('m_refresh').observe('click', getMessages);
58 document.getElementById('m_refresh').setAttribute("href","#");
59 Event.observe(document.onresize ? document : window, "resize", normalizeHeaderTable);
61 Event.observe(document.onresize ? document : window, "resize", sizePreviewPane);
62 $('summpage').observe('change', getPage);
63 takeOverSearchOMatic();
64 setupDragDrop(); // here for now
66 function getMessages() {
67 if (loadingMsg.parentNode == null) {
68 message_view.innerHTML = "";
69 message_view.appendChild(loadingMsg);
71 roomName = getTextContent(document.getElementById("rmname"));
72 var parameters = {'room':roomName, 'startmsg': startmsg};
74 parameters['maxmsgs'] = 500;
75 if (currentSortMode != null) {
76 var SortBy = currentSortMode[0];
77 if (SortBy.charAt(0) == 'r') {
78 SortBy = SortBy.substr(1);
79 parameters["SortOrder"] = "2";
81 parameters["SortBy"] = SortBy;
84 if (query.length > 0) {
85 parameters["query"] = query;
87 new Ajax.Request("roommsgs", {
89 onSuccess: loadMessages,
90 parameters: parameters,
93 onFailure: function(e) { alert("Failure: " + e);}
96 function loadMessages(transport) {
98 var data = eval('('+transport.responseText+')');
99 if (!!data && transport.responseText.length < 2) {
100 alert("Message loading failed");
102 nummsgs = data['nummsgs'];
103 var msgs = data['msgs'];
104 var length = msgs.length;
105 rowArray = new Array(); // store so they can be sorted
106 var start = new Date();
107 for(var i=0; i<length;i++) {
108 var trElement = document.createElement("tr");
111 var rowId = "msg_" + msgId;
112 trElement.setAttribute("id",rowId);
113 //$(trElement).observe('click', CtdlMessageListClick);
114 trElement.ctdlMsgId = msgId;
115 for(var j=1; j<5;j++) { // 1=msgId (hidden), 4 date timestamp (hidden) 6 = isNew etc.
116 var content = data[j];
117 if(content.length < 1) {
121 trElement.ctdlDate = content;
124 var tdElement = document.createElement("td");
125 trElement.appendChild(tdElement);
126 var txtContent = document.createTextNode(content);
127 tdElement.appendChild(txtContent);
130 var classStmt = "col"+x;
131 tdElement.setAttribute("class", classStmt);
133 WCLog("Error on #"+msgId +" col"+j+":"+e);
138 trElement.setAttribute("class", "new_message");
140 trElement.dropEnabled = true;
141 trElement.ctdlMarked = false;
142 rowArray[i] = trElement;
144 var end = new Date();
145 var delta = end.getTime() - start.getTime();
146 WCLog("loadMessages construct: " + delta);
150 if (currentSortMode == null) {
151 if (sortmode.length < 1) {
154 currentSortMode = [sortmode, sortModes[sortmode]];
155 currentSorterToggle = toggles[sortmode];
158 resortAndDisplay(sortRowsByDateDescending);
160 resortAndDisplay(null);
162 loadingMsg.parentNode.removeChild(loadingMsg);
166 function resortAndDisplay(sortMode) {
167 var start = new Date();
168 emptyElement(message_view);
169 var fragment = document.createDocumentFragment();
170 if (sortMode != null) {
171 rowArray.sort(sortMode);
173 var length = rowArray.length;
174 for(var x=0; x<length; ++x) {
176 var currentRow = rowArray[x];
177 var className = currentRow.className;
178 className = className.replace("table-alt-row","");
179 className = className.replace("table-row","");
180 if (((x-1) % 2) == 0) {
181 className += " table-alt-row";
183 className += " table-row";
185 currentRow.className = className;
186 /* Using element.onclick is evil, but until IE
187 supports addEventListener, it is much faster
188 than prototype observe */
189 currentRow.onclick = CtdlMessageListClick;
190 currentRow.ctdlDnDElement = summaryViewDragAndDropHandler;
191 currentRow.ctdlRowId = x;
192 fragment.appendChild(currentRow);
194 alert("Exception" + e);
197 message_view.appendChild(fragment);
198 var end = new Date();
199 var delta = end.getTime() - start.getTime();
200 WCLog("resortAndDisplay sort and append: " + delta);
202 normalizeHeaderTable();
204 function sortRowsByDateAscending(a, b) {
205 var dateOne = a.ctdlDate;
206 var dateTwo = b.ctdlDate;
207 return (dateOne - dateTwo);
209 function sortRowsByDateDescending(a, b) {
210 var dateOne = a.ctdlDate;
211 var dateTwo = b.ctdlDate;
212 return (dateTwo - dateOne);
215 function sortRowsBySubjectAscending(a, b) {
216 var subjectOne = getTextContent(a.getElementsByTagName("td")[0]).toLowerCase();
217 var subjectTwo = getTextContent(b.getElementsByTagName("td")[0]).toLowerCase();
218 return (subjectOne.charCodeAt(0) - subjectTwo.charCodeAt(0));
221 function sortRowsBySubjectDescending(a, b) {
222 var subjectOne = getTextContent(a.getElementsByTagName("td")[0]).toLowerCase();
223 var subjectTwo = getTextContent(b.getElementsByTagName("td")[0]).toLowerCase();
224 return (subjectTwo.charCodeAt(0) - subjectOne.charCodeAt(0));
227 function sortRowsByFromAscending(a, b) {
228 var fromOne = getTextContent(a.getElementsByTagName("td")[1]).toLowerCase();
229 var fromTwo = getTextContent(b.getElementsByTagName("td")[1]).toLowerCase();
230 return (fromOne.charCodeAt(0) - fromTwo.charCodeAt(0));
233 function sortRowsByFromDescending(a, b) {
234 var fromOne = getTextContent(a.getElementsByTagName("td")[1]).toLowerCase();
235 var fromTwo = getTextContent(b.getElementsByTagName("td")[1]).toLowerCase();
236 return (fromTwo.charCodeAt(0) - fromOne.charCodeAt(0));
239 function CtdlMessageListClick(evt) {
240 /* Since element.onload is used here, test to see if evt is defined */
241 var event = evt ? evt : window.event;
242 var target = event.target ? event.target: event.srcElement; // and again..
243 var parent = target.parentNode;
244 var msgId = parent.ctdlMsgId;
245 // If the ctrl key modifier wasn't used, unmark all rows and load the message
246 if (!event.shiftKey && !event.ctrlKey && !event.altKey) {
248 markedRowId = parent.ctdlRowId;
249 new Ajax.Updater('preview_pane', 'msg/'+msgId, {method: 'get'});
251 new Ajax.Request('ajax_servcmd', {
253 parameters: 'g_cmd=SEEN ' + msgId + '|1',
254 onComplete: CtdlMarkRowAsRead(parent)});
255 } else if (event.button != 2 && event.shiftKey) {
257 var rowId = parent.ctdlRowId;
258 var startMarkingFrom = 0;
260 if (rowId > markedRowId) {
261 startMarkingFrom = markedRowId+1;
263 } else if (rowId < markedRowId) {
264 startMarkingFrom = rowId+1;
265 finish = markedRowId;
267 for(var x = startMarkingFrom; x<finish; x++) {
268 WCLog("Marking row "+x);
269 markRow(rowArray[x]);
271 } else if (event.button != 2 && (event.ctrlKey || event.altKey)) {
275 function CtdlMarkRowAsRead(rowElement) {
276 var classes = rowElement.className;
277 classes = classes.replace("new_message","");
278 rowElement.className = classes;
280 function ApplySort(event) {
281 var target = event.target;
282 var sortId = target.id;
283 removeOldSortClass();
284 currentSorterToggle = target;
285 var sortModes = getSortMode(target); // returns [[key, func],[key,func]]
286 var sortModeToUse = null;
287 if (currentSortMode[0] == sortModes[0][0]) {
288 sortModeToUse = sortModes[1];
290 sortModeToUse = sortModes[0];
292 currentSortMode = sortModeToUse;
294 getMessages(); // in safe mode, we load from server already sorted
296 resortAndDisplay(sortModeToUse[1]);
299 function getSortMode(toggleElem) {
302 for(var key in toggles) {
303 var kr = (key.charAt(0) == 'r');
304 if (toggles[key] == toggleElem && !kr) {
305 forward = [key, sortModes[key]];
306 } else if (toggles[key] == toggleElem && kr) {
307 reverse = [key, sortModes[key]];
310 return [forward, reverse];
312 function removeOldSortClass() {
313 if (currentSorterToggle) {
314 var classes = currentSorterToggle.className;
315 classes = classes.replace("current_sort_mode","");
316 classes = classes.replace("sort_ascending","");
317 classes = classes.replace("sort_descending","");
318 currentSorterToggle.className = classes;
321 function markRow( row) {
322 var msgId = row.ctdlMsgId;
323 row.className = row.className += " marked_row";
324 row.ctdlMarked = true;
325 currentlyMarkedRows[msgId] = row;
327 function unmarkRow(row) {
328 var msgId = row.ctdlMsgId;
329 row.className = row.className.replace("marked_row","");
330 row.ctdlMarked = false;
331 delete currentlyMarkedRows[msgId];
333 function unmarkAllRows() {
334 for(msgId in currentlyMarkedRows) {
335 unmarkRow(currentlyMarkedRows[msgId]);
338 function deleteAllMarkedRows() {
339 for(msgId in currentlyMarkedRows) {
340 var row = currentlyMarkedRows[msgId];
341 var rowArrayId = row.ctdlRowId;
342 row.parentNode.removeChild(row);
343 delete currentlyMarkedRows[msgId];
344 delete rowArray[rowArrayId];
346 // Now we have to reconstruct rowarray as the array length has changed */
347 var newRowArray = new Array();
349 for(var i=0; i<rowArray.length; i++) {
350 var currentRow = rowArray[i];
351 if (currentRow != null) {
352 newRowArray[x] = currentRow;
356 rowArray = newRowArray;
357 resortAndDisplay(null);
359 function CtdlMessageListKeyUp(event) {
360 var key = event.which;
361 if (key == 46) { // DELETE
362 for(msgId in currentlyMarkedRows) {
363 new Ajax.Request('ajax_servcmd',
365 parameters: 'g_cmd=MOVE ' + msgId + '|_TRASH_|0'
368 deleteAllMarkedRows();
372 function clearMessage(msgId) {
373 var row = document.getElementById('msg_'+msgId);
374 row.parentNode.removeChild(row);
375 delete currentlyMarkedRows[msgId];
378 function summaryViewContextMenu() {
379 if (!exitedMouseDown) {
380 var contextSource = document.getElementById("listViewContextMenu");
381 CtdlSpawnContextMenu(mouseDownEvent, contextSource);
385 function summaryViewDragAndDropHandler() {
386 var element = document.createElement("div");
387 var msgList = document.createElement("ul");
388 element.appendChild(msgList);
389 for(msgId in currentlyMarkedRows) {
390 msgRow = currentlyMarkedRows[msgId];
391 var subject = getTextContent(msgRow.getElementsByTagName("td")[0]);
392 var li = document.createElement("li");
393 msgList.appendChild(li);
394 setTextContent(li, subject);
395 li.ctdlMsgId = msgId;
401 function CtdlResizeMouseDown(event) {
402 $(document).observe('mousemove', CtdlResizeMouseMove);
403 $(document).observe('mouseup', CtdlResizeMouseUp);
404 saved_y = event.clientY;
407 function sizePreviewPane() {
408 var preview_pane = document.getElementById("preview_pane");
409 var content = $('content'); // we'd like to use prototype methods here
410 var childElements = content.childElements();
411 var sizeOfElementsAbove = 0;
412 var heightOfContent = content.offsetHeight;
413 for(var i=0; i<childElements.length; i++) {
414 var element = childElements[i];
415 if (element.id != 'preview_pane') {
416 var height = element.offsetHeight;
417 sizeOfElementsAbove += height;
420 preview_pane.style.height = (heightOfContent-sizeOfElementsAbove)+"px";
422 function CtdlResizeMouseMove(event) {
423 var clientX = event.clientX;
424 var clientY = event.clientY;
425 var summary_view = document.getElementById("summary_view");
426 var summaryViewHeight = summary_view.offsetHeight;
427 var increment = clientY-saved_y;
428 summary_view.style.height = (increment+summaryViewHeight)+"px";
429 var msglist = document.getElementById("preview_pane");
430 var msgListHeight = msglist.offsetHeight;
431 msglist.style.height = (msgListHeight-increment)+"px";
433 /* For some reason the grippy doesn't work without position: absolute
434 so we need to set its top pos manually all the time */
435 var resize = document.getElementById("resize_msglist");
436 var resizePos = resize.offsetTop;
437 resize.style.top = (resizePos+increment)+"px";
439 function CtdlResizeMouseUp(event) {
440 $(document).stopObserving('mousemove', CtdlResizeMouseMove);
441 $(document).stopObserving('mouseup', CtdlResizeMouseUp);
443 function ApplySorterToggle() {
444 var className = currentSorterToggle.className;
445 className += " current_sort_mode";
446 if (currentSortMode[1] == sortRowsByDateDescending ||
447 currentSortMode[1] == sortRowsBySubjectDescending ||
448 currentSortMode[1] == sortRowsByFromDescending) {
449 className += " sort_descending";
451 className += " sort_ascending";
453 currentSorterToggle.className = className;
455 /** Hack to make the header table line up with the data */
456 function normalizeHeaderTable() {
457 var message_list_hdr = document.getElementById("message_list_hdr");
458 var summary_view = document.getElementById("summary_view");
459 var headerTable = message_list_hdr.getElementsByTagName("table")[0];
460 var dataTable = summary_view.getElementsByTagName("table")[0];
461 var dataTableWidth = dataTable.offsetWidth;
462 headerTable.style.width = dataTableWidth+"px";
465 function setupPageSelector() {
466 var summpage = document.getElementById("summpage");
467 summpage.innerHTML = "";
469 summpage.parentNode.style.display="inline !important"; //override webcit.css
473 var pages = nummsgs / 500;
474 for(var i=0; i<pages; i++) {
475 var opt = document.createElement("option");
476 var startmsg = i * 500;
477 opt.setAttribute("value",startmsg);
478 opt.appendChild(document.createTextNode((i+1)));
479 summpage.appendChild(opt);
482 function getPage(event) {
483 var target = event.target;
484 startmsg = target.options.item(target.selectedIndex).value;
487 function takeOverSearchOMatic() {
488 var searchForm = document.getElementById("searchomatic").getElementsByTagName("form")[0];
489 // First disable the form post
490 searchForm.setAttribute("action","javascript:void();");
491 searchForm.removeAttribute("method");
492 $(searchForm).observe('submit', doSearch);
494 function doSearch() {
495 query = document.getElementById("srchquery").value;