moved qdb here because matt is lazy
[public/www-new.git] / pub / qdb / res / themes / default / js / administration.js
1 /*\r
2 ###############################################################################\r
3 # Chirpy! 0.3, a quote management system                                      #\r
4 # Copyright (C) 2005-2007 Tim De Pauw <ceetee@users.sourceforge.net>          #\r
5 ###############################################################################\r
6 # This program is free software; you can redistribute it and/or modify it     #\r
7 # under the terms of the GNU General Public License as published by the Free  #\r
8 # Software Foundation; either version 2 of the License, or (at your option)   #\r
9 # any later version.                                                          #\r
10 #                                                                             #\r
11 # This program is distributed in the hope that it will be useful, but WITHOUT #\r
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #\r
13 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   #\r
14 # more details.                                                               #\r
15 #                                                                             #\r
16 # You should have received a copy of the GNU General Public License along     #\r
17 # with this program; if not, write to the Free Software Foundation, Inc., 51  #\r
18 # Franklin St, Fifth Floor, Boston, MA  02110-1301  USA                       #\r
19 ###############################################################################\r
20 \r
21 ###############################################################################\r
22 # administration.js                                                           #\r
23 # Functions specific to the administration interface                          #\r
24 ###############################################################################\r
25 # $Id:: administration.js 291 2007-02-05 21:24:46Z ceetee                   $ #\r
26 ###############################################################################\r
27 */\r
28 \r
29 var eventLogTable;\r
30 var eventLogTableBody;\r
31 var eventLogHeaders;\r
32 var eventLogRequest;\r
33 var eventLogPreviousLinks = new Array();\r
34 var eventLogNextLinks = new Array();\r
35 var eventLogCurrentLinks = new Array();\r
36 var eventLogURLParam = new Array();\r
37 eventLogURLParam["start"] = 0;\r
38 eventLogURLParam["count"] = 10;\r
39 eventLogURLParam["asc"] = 0;\r
40 \r
41 function editQuote (id) {\r
42         var editLink = document.getElementById("quote-edit-" + id);\r
43         editLink.parentNode.removeChild(editLink);\r
44         var body = getNodeText("quote-body-" + id);\r
45         var notes = getNodeText("quote-notes-" + id);\r
46         var tags = getNodeText("quote-tags-" + id);\r
47         var dataNode = document.getElementById("quote-data-" + id);\r
48         while (dataNode.firstChild) dataNode.removeChild(dataNode.firstChild);\r
49         var bodyArea = document.createElement("textarea");\r
50         bodyArea.name = "body_" + id;\r
51         bodyArea.appendChild(document.createTextNode(body));\r
52         bodyArea.className = "body-field";\r
53         var notesArea = document.createElement("textarea");\r
54         notesArea.name = "notes_" + id;\r
55         notesArea.appendChild(document.createTextNode(notes));\r
56         notesArea.className = "notes-field";\r
57         var tagsInput = document.createElement("input");\r
58         tagsInput.name = "tags_" + id;\r
59         tagsInput.value = tags;\r
60         tagsInput.className = "tags-field";\r
61         dataNode.appendChild(stickInDiv(bodyArea));\r
62         dataNode.appendChild(stickInDiv(notesArea));\r
63         dataNode.appendChild(stickInDiv(tagsInput));\r
64         document.getElementById("a" + id + "-1").checked = true;\r
65 }\r
66 \r
67 function stickInDiv (node) {\r
68         var div = document.createElement("div");\r
69         div.className = "field-container";\r
70         div.appendChild(node);\r
71         return div;\r
72 }\r
73 \r
74 function getNodeText (id) {\r
75         var node = document.getElementById(id);\r
76         if (!node) return "";\r
77         var text = "";\r
78         for (var i = 0; i < node.childNodes.length; i++) {\r
79                 var child = node.childNodes[i];\r
80                 if (child.nodeType == 3) {\r
81                         text += child.nodeValue.replace(/ *[\r\n]/g, "");\r
82                 }\r
83                 else if (child.nodeName && child.nodeName.toLowerCase() == "br") {\r
84                         // \n breaks in IE\r
85                         text += "\r";\r
86                 }\r
87         }\r
88         return text;\r
89 }\r
90 \r
91 function insertEventLog () {\r
92         var node = document.getElementById("event-log-placeholder");\r
93         if (!node || !ajaxSupported()) return;\r
94         var div = document.createElement("div");\r
95         var navTop = createEventLogNavigation();\r
96         navTop.id = "event-log-navigation-top";\r
97         var navBottom = createEventLogNavigation();\r
98         navBottom.id = "event-log-navigation-bottom";\r
99         div.appendChild(navTop);\r
100         var table = document.createElement("table");\r
101         eventLogTable = table;\r
102         eventLogHeaders = new Array();\r
103         table.id = "event-log-table";\r
104         var thead = document.createElement("thead");\r
105         var thr = document.createElement("tr");\r
106         var cols = [ "id", "date", "username", "event" ];\r
107         for (var i = 0; i < cols.length; i++) {\r
108                 var col = cols[i];\r
109                 var th = document.createElement("th");\r
110                 th.className = col;\r
111                 var text = eventLogLocale[col];\r
112                 var cont;\r
113                 if (col == "id") {\r
114                         cont = document.createElement("a");\r
115                         var href = document.createAttribute("href");\r
116                         var asc = (eventLogURLParam["asc"] > 0);\r
117                         href.value = getEventLogURL(true, "asc", asc ? 0 : 1);\r
118                         cont.setAttributeNode(href);\r
119                         var up = String.fromCharCode(0x25B2);\r
120                         var down = String.fromCharCode(0x25BC);\r
121                         var tn = document.createTextNode(asc ? up : down);\r
122                         cont.appendChild(tn);\r
123                         cont.onclick = function () {\r
124                                 var asc = !(eventLogURLParam["asc"] > 0);\r
125                                 tn.nodeValue = (asc ? up : down);\r
126                                 href.value = getEventLogURL(true, "asc", asc ? 1 : 0);\r
127                                 eventLogURLParam["asc"] = (asc ? 1 : 0);\r
128                                 updateEventLog(true);\r
129                                 return false;\r
130                         };\r
131                 }\r
132                 else\r
133                         cont = document.createTextNode(text);\r
134                 th.appendChild(cont);\r
135                 thr.appendChild(th);\r
136                 eventLogHeaders[col] = th;\r
137         }\r
138         thead.appendChild(thr);\r
139         table.appendChild(thead);\r
140         eventLogTableBody = document.createElement("tbody");\r
141         table.appendChild(eventLogTableBody);\r
142         div.appendChild(table);\r
143         div.appendChild(navBottom);\r
144         node.parentNode.replaceChild(div, node);\r
145         updateEventLog();\r
146 }\r
147 \r
148 function createEventLogNavigation () {\r
149         var div = document.createElement("div");\r
150         div.className = "event-log-navigation";\r
151         var prev = document.createElement("a");\r
152         var pHref = document.createAttribute("href");\r
153         prev.setAttributeNode(pHref);\r
154         prev.appendChild(document.createTextNode(\r
155                 String.fromCharCode(0x2190) + " " + eventLogLocale["previous"]));\r
156         prev.className = "back";\r
157         var next = document.createElement("a");\r
158         var nHref = document.createAttribute("href");\r
159         next.setAttributeNode(nHref);\r
160         next.appendChild(document.createTextNode(\r
161                 eventLogLocale["next"] + " " + String.fromCharCode(0x2192)));\r
162         next.className = "forward";\r
163         var current = document.createElement("a");\r
164         var cHref = document.createAttribute("href");\r
165         current.setAttributeNode(cHref);\r
166         current.appendChild(document.createTextNode(\r
167                 eventLogLocale["current"]));\r
168         current.className = "current";\r
169         div.appendChild(prev);\r
170         div.appendChild(next);\r
171         div.appendChild(current);\r
172         eventLogPreviousLinks.push(prev);\r
173         eventLogNextLinks.push(next);\r
174         eventLogCurrentLinks.push(current);\r
175         return div;\r
176 }\r
177 \r
178 function updateEventLog (reset) {\r
179         clearEventLog();\r
180         var tr = document.createElement("tr");\r
181         var td = document.createElement("td");\r
182         td.colSpan = 4;\r
183         td.className = "loading";\r
184         td.appendChild(document.createTextNode(eventLogLocale["loading"]));\r
185         tr.appendChild(td);\r
186         eventLogTableBody.appendChild(tr);\r
187         eventLogHeaders["event"].className = "event" + (eventLogURLParam["code"] != null ? " filtered" : "");\r
188         eventLogHeaders["username"].className = "username" + (eventLogURLParam["user"] != null ? " filtered" : "");\r
189         if (eventLogRequest) eventLogRequest.abort();\r
190         eventLogRequest = getAjaxObject();\r
191         eventLogRequest.onreadystatechange = checkEventLogRequest;\r
192         var url = getEventLogURL(reset);\r
193         for (var i = 0; i < eventLogCurrentLinks.length; i++) {\r
194                 var link = eventLogCurrentLinks[i];\r
195                 link.getAttributeNode("href").value = url;\r
196         }\r
197         url += "&output=xml";\r
198         eventLogRequest.open("GET", url, true);\r
199         eventLogRequest.send("");\r
200 }\r
201 \r
202 function checkEventLogRequest () {\r
203         if (eventLogRequest.readyState != 4 || eventLogRequest.status != 200) return;\r
204         var xml = eventLogRequest.responseXML;\r
205         eventLogRequest = null;\r
206         var data = parseEventLogXML(xml);\r
207         if (data == null) {\r
208                 return;\r
209         }\r
210         fillEventLog(data);\r
211 }\r
212 \r
213 function clearEventLog () {\r
214         setEventLogNavigationEnabled(false, false);\r
215         setEventLogNavigationEnabled(true, false);\r
216         while (eventLogTableBody.firstChild)\r
217                 eventLogTableBody.removeChild(eventLogTableBody.firstChild);\r
218 }\r
219 \r
220 function fillEventLog (tableData) {\r
221         clearEventLog();\r
222         setEventLogNavigationEnabled(false, tableData["leading"]);\r
223         setEventLogNavigationEnabled(true, tableData["trailing"]);\r
224         var events = tableData["events"];\r
225         var dataFilter;\r
226         if (eventLogURLParam["data"])\r
227                 dataFilter = eventLogURLParam["data"].replace(/=.*/, "");\r
228         for (var i = 0; i < events.length; i++) {\r
229                 var evt = events[i];\r
230                 var data = evt["data"];\r
231                 var evenOdd = (i % 2 == 0 ? "even" : "odd");\r
232                 var firstRow = document.createElement("tr");\r
233                 firstRow.className = evenOdd;\r
234                 var idCell = document.createElement("td");\r
235                 idCell.className = "id";\r
236                 var rowSpan = 1;\r
237                 for (name in data) rowSpan++;\r
238                 idCell.rowSpan = rowSpan;\r
239                 idCell.appendChild(document.createTextNode(evt["id"]));\r
240                 firstRow.appendChild(idCell);\r
241                 var dateCell = document.createElement("td");\r
242                 dateCell.className = "date";\r
243                 dateCell.appendChild(document.createTextNode(evt["date"]));\r
244                 firstRow.appendChild(dateCell);\r
245                 var userCell = document.createElement("td");\r
246                 userCell.className = "username";\r
247                 var userID = evt["userid"];\r
248                 var username;\r
249                 if (userID == 0) {\r
250                         userCell.className += " guest";\r
251                         username = eventLogLocale["guest"];\r
252                 }\r
253                 else if ("username" in evt) {\r
254                         username = evt["username"];\r
255                 }\r
256                 else {\r
257                         userCell.className += " removed-account";\r
258                         username = "#" + userID;\r
259                 }\r
260                 var userLink = createEventLogLink("user", userID);\r
261                 userLink.appendChild(document.createTextNode(username));\r
262                 userCell.appendChild(userLink);\r
263                 firstRow.appendChild(userCell);\r
264                 var descCell = document.createElement("td");\r
265                 descCell.className = "event";\r
266                 var descLink = document.createElement("a");\r
267                 var descHref = document.createAttribute("href");\r
268                 var descLink = createEventLogLink("code", evt["code"]);\r
269                 descLink.appendChild(document.createTextNode(evt["description"]));\r
270                 descCell.appendChild(descLink);\r
271                 firstRow.appendChild(descCell);\r
272                 eventLogTableBody.appendChild(firstRow);\r
273                 for (name in data) {\r
274                         var value = data[name];\r
275                         var row = document.createElement("tr");\r
276                         row.className = evenOdd;\r
277                         var nameCell = document.createElement("td");\r
278                         nameCell.className = "property-name";\r
279                         if (dataFilter && name == dataFilter)\r
280                                 nameCell.className += " filtered";\r
281                         nameCell.appendChild(document.createTextNode(name));\r
282                         var valueCell = document.createElement("td");\r
283                         valueCell.className = "property-value";\r
284                         valueCell.colSpan = 2;\r
285                         if (value.length > 1) {\r
286                                 valueCell.appendChild(document.createTextNode(fixWhiteSpace(value[0])));\r
287                                 for (var j = 1; j < value.length; j++) {\r
288                                         valueCell.appendChild(document.createElement("br"));\r
289                                         valueCell.appendChild(document.createTextNode(fixWhiteSpace(value[j])));\r
290                                 }\r
291                         }\r
292                         else {\r
293                                 var empty = (value.length == 0);\r
294                                 var val = (!empty ? value[0].replace(/'/g, '\\\'') : "");\r
295                                 var link = createEventLogLink("data", name + "=" + val);\r
296                                 var text;\r
297                                 if (empty) {\r
298                                         link.className = "empty";\r
299                                         text = eventLogLocale["empty"];\r
300                                 }\r
301                                 else\r
302                                         text = fixWhiteSpace(value[0]);\r
303                                 link.appendChild(document.createTextNode(text));\r
304                                 valueCell.appendChild(link);\r
305                         }\r
306                         row.appendChild(nameCell);\r
307                         row.appendChild(valueCell);\r
308                         eventLogTableBody.appendChild(row);\r
309                 }\r
310         }\r
311 }\r
312 \r
313 function setEventLogNavigationEnabled (next, enabled) {\r
314         var links, className;\r
315         if (next) {\r
316                 links = eventLogNextLinks;\r
317                 className = "forward";\r
318         }\r
319         else {\r
320                 links = eventLogPreviousLinks;\r
321                 className = "back";\r
322         }\r
323         for (var i = 0; i < links.length; i++) {\r
324                 var link = links[i];\r
325                 var href = link.getAttributeNode("href");\r
326                 if (enabled) {\r
327                         link.className = className;\r
328                         var start = eventLogURLParam["start"];\r
329                         var count = eventLogURLParam["count"];\r
330                         if (!next)\r
331                                 start = (start >= count ? start - count : 0);\r
332                         else\r
333                                 start += count;\r
334                         link.onclick = function () {\r
335                                 eventLogURLParam["start"] = start;\r
336                                 updateEventLog();\r
337                                 return false;\r
338                         };\r
339                         href.value = getEventLogURL(false, "start", start);\r
340                 }\r
341                 else {\r
342                         link.className = className + " inactive";\r
343                         link.onclick = function () {\r
344                                 return false;\r
345                         };\r
346                         href.value = "#";\r
347                 }\r
348         }\r
349 }\r
350 \r
351 function parseEventLogXML (xml) {\r
352         if (!xml || !xml.childNodes) return null;\r
353         var leading = false;\r
354         var trailing = false;\r
355         var events = new Array();\r
356         for (var i = 0; i < xml.childNodes.length; i++) {\r
357                 var root = xml.childNodes[i];\r
358                 if (root.nodeType != 1) continue;\r
359                 for (var j = 0; j < root.childNodes.length; j++) {\r
360                         var child = root.childNodes[j];\r
361                         if (child.nodeType == 1) {\r
362                                 switch (child.nodeName) {\r
363                                         case "event":\r
364                                                 events.push(parseLogEventNode(child));\r
365                                                 break;\r
366                                         case "leading":\r
367                                                 leading = true;\r
368                                                 break;\r
369                                         case "trailing":\r
370                                                 trailing = true;\r
371                                                 break;\r
372                                 }\r
373                         }\r
374                 }\r
375         }\r
376         var data = new Array();\r
377         data["leading"] = leading;\r
378         data["trailing"] = trailing;\r
379         data["events"] = events;\r
380         return data;\r
381 }\r
382 \r
383 function parseLogEventNode (node) {\r
384         var event = new Array();\r
385         event["data"] = new Array();\r
386         for (var i = 0; i < node.childNodes.length; i++) {\r
387                 var child = node.childNodes[i];\r
388                 if (child.nodeType != 1) continue;\r
389                 if (child.nodeName == "data") {\r
390                         var name, value;\r
391                         for (var j = 0; j < child.childNodes.length; j++) {\r
392                                 var n = child.childNodes[j];\r
393                                 if (n.nodeType != 1) continue;\r
394                                 switch (n.nodeName) {\r
395                                         case "name":\r
396                                                 name = n.firstChild.nodeValue;\r
397                                                 break;\r
398                                         case "value":\r
399                                                 value = extractLogEventDataValue(n);\r
400                                                 break;\r
401                                 }\r
402                         }\r
403                         event["data"][name] = value;\r
404                 }\r
405                 else {\r
406                         event[child.nodeName] = child.firstChild.nodeValue;\r
407                 }\r
408         }\r
409         return event;\r
410 }\r
411 \r
412 function extractLogEventDataValue (node) {\r
413         var value = new Array();\r
414         for (var i = 0; i < node.childNodes.length; i++) {\r
415                 var child = node.childNodes[i];\r
416                 if (child.nodeType != 3) continue;\r
417                 value.push(child.nodeValue);\r
418         }\r
419         return value;\r
420 }\r
421 \r
422 function createEventLogLink (name, value) {\r
423         var anchor = document.createElement("a");\r
424         var href = document.createAttribute("href");\r
425         href.value = getEventLogURL(true, name, value);\r
426         anchor.setAttributeNode(href);\r
427         anchor.onclick = function () {\r
428                 eventLogURLParam[name]\r
429                         = (eventLogURLParam[name] == value ? null : value);\r
430                 updateEventLog(true);\r
431                 return false;\r
432         };\r
433         return anchor;\r
434 }\r
435 \r
436 function getEventLogURL (reset, name, value) {\r
437         var pairs = new Array();\r
438         var found = false;\r
439         for (key in eventLogURLParam) {\r
440                 var val;\r
441                 switch (key) {\r
442                         case name:\r
443                                 val = (eventLogURLParam[key] == value ? null : value);\r
444                                 found = true;\r
445                                 break;\r
446                         case "start":\r
447                                 val = (reset ? 0 : eventLogURLParam[key]);\r
448                                 break;\r
449                         default:\r
450                                 val = eventLogURLParam[key];\r
451                 }\r
452                 if (val != null)\r
453                         pairs.push(escape(key) + "=" + escape(val));\r
454         }\r
455         if (name && !found) {\r
456                 pairs.push(escape(name) + "=" + escape(value));\r
457         }\r
458         return eventLogURL + pairs.join("&");\r
459 }\r
460 \r
461 function fixWhiteSpace (text) {\r
462         var nbsp = String.fromCharCode(160);\r
463         return text\r
464                 .replace(/[\r\n]+/g, "")\r
465                 .replace(/^\s/, nbsp)\r
466                 .replace(/\s$/, nbsp)\r
467                 .replace(/\s{2}/g, nbsp + nbsp);\r
468 }\r
469 \r
470 function addOnloadFunction (f) {\r
471         if (window.onload != null) {\r
472                 var old = window.onload;\r
473                 window.onload = function (e) {\r
474                         old(e);\r
475                         f();\r
476                 };\r
477         }\r
478         else {\r
479                 window.onload = f;\r
480         }\r
481 }\r
482 \r
483 addOnloadFunction(insertEventLog);