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