File: 0.00.0a/js/freedesk.js (View as HTML)

  1: /* -------------------------------------------------------------
  2: This file is part of FreeDESK
  3: 
  4: FreeDESK is (C) Copyright 2012 David Cutting
  5: 
  6: FreeDESK is free software: you can redistribute it and/or modify
  7: it under the terms of the GNU General Public License as published by
  8: the Free Software Foundation, either version 3 of the License, or
  9: (at your option) any later version.
 10: 
 11: FreeDESK is distributed in the hope that it will be useful,
 12: but WITHOUT ANY WARRANTY; without even the implied warranty of
 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14: GNU General Public License for more details.
 15: 
 16: You should have received a copy of the GNU General Public License
 17: along with FreeDESK.  If not, see www.gnu.org/licenses
 18: 
 19: For more information see www.purplepixie.org/freedesk/
 20: -------------------------------------------------------------- */
 21: 
 22: /**
 23:  * The main FreeDESK JavaScript client-side code
 24: **/
 25: 
 26: function FreeDESK()
 27: {
 28: 	this.sid = ""; // Session ID
 29: 	
 30: 	// Statuses of requests (text)
 31: 	this.requestStatus = new Array();
 32: 	// List of display fields for request list
 33: 	this.fieldList = new Array();
 34: 
 35: 	// XML of last request list fetched (for redisplay)
 36: 	this.lastListXML = null;
 37: 	
 38: 	// Last Request Details
 39: 	this.lastTeam = 0;
 40: 	this.lastUser = "";
 41: 	
 42: 	// Last subpage
 43: 	this.lastSubpage = "";
 44: 	this.lastSubpageOpts = "";
 45: 	
 46: 	// Sort Criteria
 47: 	this.sortField = "requestid";
 48: 	this.sortOrder = "D";
 49: 	
 50: 	// Refresh Event
 51: 	this.refreshEvent = null;
 52: 
 53: 	// Login Support
 54: 	this.login_action = function(responseXML)
 55: 	{
 56: 		//alert(responseXML);
 57: 		//var txt = document.createTextNode(responseXML);
 58: 		//document.getElementById("login_content").appendChild(txt);
 59: 		if (DESK.isError(responseXML))
 60: 		{
 61: 			DESK.show_login(DESK.getError(responseXML));
 62: 		}
 63: 		else
 64: 		{
 65: 			var newsid = responseXML.getElementsByTagName("sid")[0].childNodes[0].nodeValue;
 66: 			if (DESK.sid == "") // no current session so reload to index
 67: 			{
 68: 				//var loc = "./?sid="+newsid;
 69: 				//window.location.href = loc;
 70: 				document.forms['login_sid_form'].elements['sid'].value = newsid;
 71: 				document.forms['login_sid_form'].submit();
 72: 			}
 73: 			else
 74: 			{
 75: 				DESK.sid = newsid;
 76: 				DESK.hide_login();
 77: 				// Any other actions?
 78: 			}
 79: 		}
 80: 	}
 81: 
 82: 	this.login_click=function()
 83: 	{
 84: 		var req = new ServerRequest();
 85: 		req.url = "api.php?mode=login&type=user&username="
 86: 			+document.getElementById("login_username").value
 87: 			+"&password="
 88: 			+document.getElementById("login_password").value;
 89: 		req.callback = DESK.login_action;
 90: 		req.Get();
 91: 	}
 92: 	
 93: 	this.show_login=function(errormsg)
 94: 	{
 95: 		this.backdrop(true);
 96: 		var txt = "";
 97: 		if (errormsg !== undefined)
 98: 			txt=errormsg;
 99: 		document.getElementById("login_message").innerHTML = txt;
100: 		document.getElementById("login_form").style.display = "block";
101: 	}
102: 	
103: 	this.hide_login=function()
104: 	{
105: 		document.getElementById("login_form").style.display = "none";
106: 		document.getElementById("login_message").style.display = "none";
107: 		this.backdrop(false);
108: 	}
109: 
110: 	// Logout
111: 	this.logout_click=function()
112: 	{
113: 		var req = new ServerRequest();
114: 		req.url="api.php?mode=logout&sid="+this.sid;
115: 		req.callback = DESK.logout_action;
116: 		req.Get();
117: 	}
118: 	
119: 	this.logout_action=function()
120: 	{
121: 		window.location.href="./";
122: 	}
123: 
124: 	// Show/Hide Backdrop
125: 	this.backdrop = function(set)
126: 	{
127: 		var bd = document.getElementById("screen_backdrop");
128: 		if (set === undefined) // toggle
129: 		{
130: 			if (bd.style.display == "block")
131: 				set = false;
132: 			else
133: 				set = true;
134: 		}
135: 		
136: 		if (set)
137: 			bd.style.display = "block";
138: 		else
139: 			bd.style.display = "none";
140: 	}
141: 	
142: 	// Check for errors
143: 	this.isError = function(xml)
144: 	{
145: 		//alert(xml);
146: 		//alert(xml.documentElement);
147: 		//alert(xml.documentElement.tagName);
148: 		//alert(xml.getElementsByTagName("error")[0].childNodes[0].nodeValue);
149: 		if (xml.documentElement.tagName == "error")
150: 		//if (xml.getElementsByTagName("error").length > 0)
151: 			return true;
152: 		return false;
153: 	}
154: 	
155: 	this.getError = function(xml)
156: 	{
157: 		var out = xml.getElementsByTagName("code")[0].childNodes[0].nodeValue;
158: 		out += ": ";
159: 		out += xml.getElementsByTagName("text")[0].childNodes[0].nodeValue;
160: 		return out;
161: 	}
162: 	
163: 	this.getErrorCode = function(xml)
164: 	{
165: 		return xml.getElementsByTagName("code")[0].childNodes[0].nodeValue;
166: 	}
167: 	
168: 	// Display main or sub page (true for main, false for sub)
169: 	this.displayMain = function(disp)
170: 	{
171: 		if (disp)
172: 		{
173: 			document.getElementById("subpage").style.display="none";
174: 			document.getElementById("mainpage").style.display="block";
175: 		}
176: 		else
177: 		{
178: 			document.getElementById("mainpage").style.display="none";
179: 			document.getElementById("subpage").style.display="block";
180: 		}
181: 	}
182: 	
183: 	// Load sub-pages
184: 	this.displaySubpage = function(text)
185: 	{
186: 		document.getElementById("subpage").innerHTML = text;
187: 		DESK.displayMain(false);
188: 	}
189: 	
190: 	this.loadSubpage = function(page, opts)
191: 	{
192: 		if (opts == undefined)
193: 			var opts = "";
194: 		this.lastSubpage = page;
195: 		this.lastSubpageOpts = opts;
196: 		var sr = new ServerRequest();
197: 		sr.xmlrequest=false;
198: 		sr.url = "page.php?page="+page;
199: 		if (opts != "")
200: 			sr.url += "&"+opts;
201: 		sr.url += "&sid="+this.sid;
202: 		sr.callback = DESK.displaySubpage;
203: 		sr.Get();
204: 	}
205: 	
206: 	// Refresh the subpage
207: 	this.refreshSubpage = function()
208: 	{
209: 		DESK.loadSubpage(DESK.lastSubpage, DESK.lastSubpageOpts);
210: 	}
211: 	
212: 	// Load a Request List to the Main Pane
213: 	this.mainPane = function(teamid, username)
214: 	{
215: 		if (teamid == undefined)
216: 			var teamid = 0;
217: 		if (username == undefined)
218: 			var username="";
219: 		//alert(teamid+" "+username);
220: 		var sr = new ServerRequest();
221: 		this.lastTeam = teamid;
222: 		this.lastUser = username;
223: 		
224: 		sr.url = "api.php?mode=requests_assigned&teamid="+teamid+"&username="+username;
225: 		if (this.sortField != "")
226: 		{
227: 			sr.url += "&sort="+this.sortField;
228: 			sr.url += "&order="+this.sortOrder;
229: 		}
230: 		sr.url += "&sid="+this.sid;
231: 		sr.callback = DESK.mainPaneDisplay;
232: 		sr.Get();
233: 	}
234: 	
235: 	// Refresh the Main Pane
236: 	this.mainPaneRefresh = function()
237: 	{
238: 		DESK.mainPane(DESK.lastTeam, DESK.lastUser);
239: 	}
240: 	
241: 	// Display a request list in the main pane
242: 	this.mainPaneDisplay = function(xml)
243: 	{
244: 		DESK.lastListXML = xml;
245: 		var table = document.createElement("table"); // table for results
246: 		table.border=0;
247: 		table.width="100%";
248: 		table.className="requestList";
249: 		
250: 		var container = document.getElementById('mainright');
251: 		
252: 		if (container.hasChildNodes())
253: 		{
254: 			while(container.childNodes.length >= 1)
255: 				container.removeChild(container.firstChild);
256: 		}
257: 		
258: 		var requests = xml.getElementsByTagName("request");
259: 		
260: 		if (requests.length <= 0)
261: 		{
262: 			container.innerHTML = "<h3>No Requests Found</h3>";
263: 			return;
264: 		}
265: 		
266: 		container.appendChild(table);
267: 		
268: 		var title = table.insertRow(0);
269: 		title.className = "requestListTitle";
270: 		for (var i=0; i<DESK.fieldList.length; ++i)
271: 		{
272: 			if (DESK.fieldList[i][1] == 1) // displayed field
273: 			{
274: 				var cell = title.insertCell(-1);
275: 				
276: 				var fieldTitle = DESK.fieldList[i][0];
277: 				
278: 				var link = "<a href=\"#\" onclick=\"DESK.mainPaneSort('"+DESK.fieldList[i][2]+"');\">";
279: 				link += fieldTitle;
280: 				
281: 				if (DESK.sortField == DESK.fieldList[i][2])
282: 					if (DESK.sortOrder == "D")
283: 						link+=" &gt;";
284: 					else
285: 						link+=" &lt;";
286: 						
287: 				link+"</a>";
288: 				
289: 				cell.innerHTML = link;
290: 			}
291: 		}
292: 		
293: 		for (var req=0; req<requests.length; ++req)
294: 		{
295: 			var request = requests[req];
296: 			var row = table.insertRow(table.getElementsByTagName("tr").length);
297: 			row.className="requestList";
298: 			
299: 			for (var fc=0; fc<DESK.fieldList.length; ++fc)
300: 			{
301: 				var field = DESK.fieldList[fc];
302: 				if (field[1] == 1) // display this field
303: 				{
304: 					var contents = "";
305: 					var data = request.getElementsByTagName(field[2])[0];
306: 					if (!data) // no field data of this form returned
307: 					{
308: 						contents="&nbsp;-";
309: 					}
310: 					else
311: 					{
312: 						contents = (data.textContent == undefined) ? data.firstChild.nodeValue : data.textContent;
313: 						if (field[2]=="status")
314: 							contents = DESK.requestStatus[contents];
315: 						else if (field[2]=="requestid")
316: 						{
317: 							var id = contents;
318: 							contents = "<a href=\"#\" onclick=\"DESK.displayRequest("+contents+");\">"+contents+"</a>";
319: 							// row.onclick = function(){ return DESK.displayRequest(id); }; // Always uses last - TODO fix it
320: 						}
321: 					}
322: 					
323: 					var cell = row.insertCell(-1);
324: 					cell.innerHTML = contents;
325: 				}
326: 			}
327: 		}
328: 	}
329: 	
330: 	// Set main pane sort
331: 	this.mainPaneSort = function(field)
332: 	{
333: 		if (DESK.sortField == field)
334: 		{
335: 			if (DESK.sortOrder == "D")
336: 				DESK.sortOrder = "A";
337: 			else
338: 				DESK.sortOrder = "D";
339: 		}
340: 		else
341: 		{
342: 			DESK.sortField = field;
343: 			DESK.sortOrder = "D";
344: 		}
345: 		DESK.mainPane(DESK.lastTeam, DESK.lastUser);
346: 	}
347: 	
348: 	// Option Displays for Main Page
349: 	this.optionDisplay = function(opt)
350: 	{
351: 		if (opt == 1)
352: 		{
353: 			document.getElementById('option_select').style.display = "none";
354: 			
355: 			var container = document.getElementById('option_dialog');
356: 			
357: 			if (container.hasChildNodes())
358: 			{
359: 				while(container.childNodes.length >= 1)
360: 					container.removeChild(container.firstChild);
361: 			}
362: 			
363: 			for (var i=0; i<this.fieldList.length; ++i)
364: 			{
365: 				var displayed = false;
366: 				if (this.fieldList[i][1]==1)
367: 					displayed=true;
368: 				var a = "";
369: 				if (displayed)
370: 					a += "<b>";
371: 				a += "<a href=\"#\" onclick=\"DESK.setFieldDisplay("+i+",";
372: 				if (displayed)
373: 					a+="0";
374: 				else
375: 					a+="1";
376: 				a+="); DESK.optionDisplay(1);\">";
377: 				//container.innerHTML += a;
378: 				a += this.fieldList[i][0];
379: 				a += "</a>";
380: 				if (displayed)
381: 					a += "</b>";
382: 				container.innerHTML += a;
383: 				container.innerHTML += "<br />";
384: 			}
385: 				
386: 				
387: 			container.innerHTML += "<br /><a href=\"#\" onclick=\"DESK.optionDisplay(0); DESK.mainPaneDisplay(DESK.lastListXML);\">Close and Apply</a>";
388: 			
389: 			container.style.display = "block";
390: 		}
391: 		else
392: 		{
393: 			document.getElementById('option_dialog').style.display = "none";
394: 			document.getElementById('option_select').style.display = "block";
395: 		}
396: 	}
397: 		
398: 	// Set a fieldDisplay property
399: 	this.setFieldDisplay = function(index, setting)
400: 	{
401: 		this.fieldList[index][1]=setting;
402: 	}
403: 	
404: 	// Display a Request
405: 	this.displayRequest = function(id)
406: 	{
407: 		var url = "request.php?id="+id+"&sid="+DESK.sid;
408: 		DESK.openWindow("FreeDESK Request", url);
409: 	}
410: 	
411: 	// Open a Window
412: 	this.openWindow = function(windowname, url, xsize, ysize, resizeable)
413: 	{
414: 		if (xsize == undefined)
415: 			var xsize = 700;
416: 		if (ysize == undefined)
417: 			var ysize = 500;
418: 			
419: 		if (resizeable == undefined)
420: 			var resizeable = 1;
421: 		else if(resizeable)
422: 			resizeable=1;
423: 		else if(!resizeable)
424: 			resizable=0;
425: 		
426: 		var windowopts = "location=0,status=0,scrollbars=1,toolbar=0,width="+xsize+",height="+ysize+",resizeable="+resizeable;
427: 		
428: 		window.open(url, windowname, windowopts);
429: 	}
430: 	
431: 	// Perform an entity search
432: 	this.entitySearch = function(entity, callback, fields)
433: 	{
434: 		var url = "entity.php?mode=search&entity="+entity;
435: 		
436: 		if (callback != undefined)
437: 			url += "&callback="+callback;
438: 		if (fields != undefined)
439: 		{
440: 			for (var i=0; i<fields.length; ++i)
441: 			{
442: 				url += "&" + fields[i][0] + "=" + fields[i][1]; // escape?
443: 			}
444: 		}
445: 		url += "&sid=" + this.sid;
446: 		
447: 		this.openWindow("Search "+entity, url);
448: 	}
449: 	
450: 	// Open Edit Entity
451: 	this.editEntity = function(entity, keyfield, keyfieldValue)
452: 	{
453: 		var url = "entity.php?mode=edit&entity="+entity+"&keyfield="+keyfield+"&value="+keyfieldValue;
454: 		url += "&sid=" + this.sid;
455: 	
456: 		this.openWindow("Edit "+entity, url);
457: 	}
458: 	
459: 	// Perform an entity creation
460: 	this.entityCreate = function(entity, callback)
461: 	{
462: 		var url = "entity.php?mode=create&entity="+entity;
463: 		
464: 		if (callback != undefined)
465: 			url += "&callback="+callback;
466: 			
467: 		url += "&sid=" + this.sid;
468: 		
469: 		this.openWindow("Create "+entity, url);
470: 	}
471: 	
472: 	// Convert form to query string
473: 	this.formToQuery = function(formid)
474: 	{
475: 		var data = "";
476: 		
477: 		function add(name, value)
478: 		{
479: 			if (value == undefined)
480: 				var value = "";
481: 			
482: 			data += (data.length > 0 ? "&" : ""); // add & if required
483: 		
484: 			data += escape(name).replace(/\+/g, "%2B") + "=";
485: 		
486: 			data += escape(value).replace(/\+/g, "%2B");
487: 		}
488: 		
489: 		var form = document.forms[formid];
490: 		if (!form)
491: 			return "";
492: 		var elements = form.elements;
493: 		
494: 		for (var i=0; i<elements.length; ++i)
495: 		{
496: 			var element = elements[i];
497: 			var type = element.type.toLowerCase();
498: 			var name = element.name;
499: 			
500: 			if (name)
501: 			{
502: 				if (	type == "text" || type == "password" ||
503: 						type == "button" || type == "reset" ||
504: 						type == "file" || type == "submit" ||
505: 						type == "image" || type == "hidden"	|| 
506: 						type == "textarea" )
507: 					add(name, element.value);
508: 					
509: 				else if ( type == "checkbox" && element.checked )
510: 					add(name, element.value ? element.value : "On");
511: 				
512: 				else if ( type == "radio" && element.checked)
513: 					add(name, element.value);
514: 				
515: 				else if ( type.indexOf("select") != -1 )
516: 				{
517: 					for (var x=0; x<element.options.length; ++x)
518: 					{
519: 						var opt = element.options[x];
520: 						if (opt.selected)
521: 							add(name, opt.value ? opt.value : opt.text);
522: 					}
523: 				}
524: 			}
525: 		}
526: 		
527: 		return data;
528: 	}
529: 	
530: 	// API Form Action e.g. save entity
531: 	this.formAPI = function(formid, closeOnComplete, reloadOnComplete, callbackOnComplete)
532: 	{
533: 		if (closeOnComplete == undefined)
534: 			var closeOnComplete = false;
535: 		if (reloadOnComplete == undefined)
536: 			var reloadOnComplete = false;
537: 		if (callbackOnComplete == undefined)
538: 			var callbackOnComplete = false;
539: 		
540: 		
541: 		var q = DESK.formToQuery(formid);
542: 		
543: 		q += "&sid=" + DESK.sid;
544: 		
545: 		var sr = new ServerRequest();
546: 		sr.url = "api.php";
547: 		sr.callback = DESK.formAPIcallback;
548: 		sr.additional = new Array();
549: 		sr.additional[0] = closeOnComplete;
550: 		sr.additional[1] = reloadOnComplete;
551: 		sr.additional[2] = callbackOnComplete;
552: 		sr.Post(q);
553: 	}
554: 	
555: 	this.formAPIcallback = function(xml, additional)
556: 	{
557: 		if (DESK.isError(xml))
558: 		{
559: 			Alerts.add(DESK.getError(xml), 2, 10);
560: 		}
561: 		else
562: 		{
563: 			// We got this far - no DESK error or XML error so we can say success!
564: 			Alerts.add("Operation Successful", 0);
565: 			
566: 			if (additional[0])
567: 				window.close();
568: 			else if (additional[1])
569: 				window.location.reload();
570: 			else if (additional[2])
571: 			{	
572: 				additional[2](xml);
573: 			}
574: 		}
575: 	}
576: 	
577: 	// Switch a pane
578: 	this.paneSwitch = function(pid, oid)
579: 	{
580: 		var pane = document.getElementById("pane_"+pid);
581: 		var header = document.getElementById("pane_"+pid+"_header");
582: 		
583: 		var child = header.firstChild;
584: 		
585: 		var spans = header.getElementsByTagName("SPAN");
586: 		
587: 		for (var i=0; i<spans.length; ++i)
588: 		{
589: 			var arr = spans[i].id.split("_");
590: 			var opt = arr[arr.length-1];
591: 			
592: 			var contentid = "pane_"+pid+"_"+opt+"_content";
593: 			
594: 			if (oid == opt)
595: 				spans[i].className = "pane_option_selected";
596: 			else
597: 				spans[i].className = "pane_option";
598: 			// Always hide the divs to avoid duplicate display
599: 			document.getElementById(contentid).className = "pane_content_hidden";
600: 		}
601: 		
602: 		var contentid = "pane_"+pid+"_"+oid+"_content";
603: 		document.getElementById(contentid).className = "pane_content";
604: 		
605: 	}
606: 	
607: 	// Open new create request window
608: 	this.createRequest = function(reqclass)
609: 	{
610: 		if (reqclass == undefined)
611: 			var reqclass = "";
612: 		
613: 		var url = "request.php?";
614: 		if (reqclass != "")
615: 			url += "class="+reqclass+"&";
616: 		url += "sid="+DESK.sid;
617: 		
618: 		DESK.openWindow("FreeDESK Request", url);
619: 	}
620: 	
621: 	// Debug data output
622: 	this.debugData = function(container, session)
623: 	{
624: 		var out = "<b>Client-Side JavaScript Debug</b><br /><br />";
625: 		if (session == DESK.sid)
626: 			out += "Session IDs match server and client side<br /><br />";
627: 		else
628: 			out += "Session ID mis-match between client and server<br /><br />";
629: 			
630: 		document.getElementById(container).innerHTML = out;
631: 	}
632: 	
633: 	// Relogin (use current SID and re-post login form)
634: 	this.relogin = function()
635: 	{
636: 		document.forms['login_sid_form'].elements['sid'].value = DESK.sid;
637: 		document.forms['login_sid_form'].submit();
638: 	}
639: 	
640: 	// Start Auto-refreshing
641: 	this.startRefresh = function(interval)
642: 	{
643: 		if (interval == undefined)
644: 			var interval = 30;
645: 		interval = interval * 1000;
646: 		
647: 		DESK.refreshEvent = setInterval(
648: 			function(){ DESK.mainPaneRefresh(); },
649: 			interval );
650: 	}
651: 	
652: 	// Stop Auto-refreshing
653: 	this.stopRefresh = function()
654: 	{
655: 		clearInterval(DESK.refreshEvent);
656: 	}
657: 		
658: }
659: 
660: var DESK = new FreeDESK();
661: 
662: