diff genajax.js @ 1069:5f92fa5e683a

Refactor how the "AJAX" stuff works.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 24 Jan 2017 17:25:48 +0200
parents ajax.js@82ecea33c477
children 7da8bde9b7be
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/genajax.js	Tue Jan 24 17:25:48 2017 +0200
@@ -0,0 +1,385 @@
+//
+// FAPWeb - Simple Web-based Demoparty Management System
+// Common JavaScript / AJAX code
+// (C) Copyright 2012-2015 Tecnic Software productions (TNSP)
+//
+var jsMessageBoxCBCancel = null, jsMessageBoxCBData = null, jsMessageBoxCBOK = null;
+var jsUploadCBS = [];
+
+
+function jsHandleMessageBoxKeys(ev)
+{
+  ev = ev || window.event;
+  var key = ev.keyCode ? ev.keyCode : ev.which;
+  if (key == 27)
+  {
+    jsCloseMessageBox(jsMessageBoxCBCancel, jsMessageBoxCBData);
+    return false;
+  }
+  else
+    return true;
+}
+
+
+function jsSetMessageBoxCBs(cb_ok, cb_cancel, cb_data)
+{
+  jsMessageBoxCBOK = cb_ok;
+  jsMessageBoxCBCancel = cb_cancel;
+  jsMessageBoxCBData = cb_data;
+}
+
+
+function jsCloseMessageBox(callback, cb_data)
+{
+  var nitem = document.getElementById("messageBox");
+  if (nitem)
+  {
+    document.onkeydown = null;
+    jsSetMessageBoxCBs(null, null, null);
+
+    if (nitem.style.display != "none")
+    {
+      nitem.style.display = "none";
+
+      if (callback && typeof(callback) === "function")
+        callback(cb_data);
+    }
+  }
+}
+
+
+function jsMessageBox(msg)
+{
+  var nitem = document.getElementById("messageBox");
+  if (nitem)
+  {
+    nitem.innerHTML = "<div class='messageBoxInner'>"+ msg +
+      "<div class='messageBoxControls'>"+
+      "<input id='msgBoxConfirmClose' type='button' value=' OK '>"+
+      "</div></div>";
+
+    document.onkeydown = jsHandleMessageBoxKeys;
+    jsSetMessageBoxCBs(null, null, null);
+
+    var elem = document.getElementById("msgBoxConfirmClose");
+    elem.onclick = function () { jsCloseMessageBox(0, 0); }
+
+    nitem.style.display = "block";
+  }
+}
+
+
+function jsErrorMessageBox(msg)
+{
+  jsMessageBox("<h1>Error!</h1><div>"+msg+"</div>");
+}
+
+
+function jsTitleMessageBox(title, msg)
+{
+  jsMessageBox("<h1>"+title+"</h1><div>"+msg+"</div>");
+}
+
+
+function jsConfirmBox(msg, cb_ok, cb_cancel, cb_data)
+{
+  var nitem = document.getElementById("messageBox");
+  if (nitem)
+  {
+    nitem.innerHTML = "<div class='messageBoxInner'><h1>Confirmation</h1><p>"+ msg +"</p>"+
+      "<div class='messageBoxControls'>"+
+      "<input id='msgBoxConfirmCancel' type='button' value=' Cancel '>"+
+      "<input id='msgBoxConfirmOK' type='button' value=' OK '>"+
+      "</div></div>";
+
+    document.onkeydown = jsHandleMessageBoxKeys;
+    jsSetMessageBoxCBs(cb_ok, cb_cancel, cb_data);
+
+    var elem = document.getElementById("msgBoxConfirmCancel");
+    elem.onclick = function () { jsCloseMessageBox(cb_cancel, cb_data); }
+
+    elem = document.getElementById("msgBoxConfirmOK");
+    elem.onclick = function () { jsCloseMessageBox(cb_ok, cb_data); }
+    
+    nitem.style.display = "block";
+  }
+}
+
+
+function jsStatusMsg(msg)
+{
+  var nitem = document.getElementById("nstatus");
+  if (nitem) nstatus.innerHTML = msg;
+}
+
+
+function strtrim(str)
+{
+  if (!str || str == null)
+    return "";
+  return str.replace(/^\s+|\s+$/g,'')
+}
+
+
+function strencode(str)
+{
+  return encodeURIComponent(str);
+}
+
+
+function jsCreateXMLRequest()
+{
+  var req;
+  if (window.XMLHttpRequest)
+  {
+    // Modern browsers
+    req = new XMLHttpRequest();
+  }
+  else
+  {
+    // Old IE versions
+    req = new ActiveXObject("Microsoft.XMLHTTP");
+  }
+  return req;
+}
+
+
+//
+// Function for creating AJAX POST request arguments list based
+// on fields and giving them specified types. Also basic check
+// for validity can be performed (e.g. field empty or not)
+//
+var lastPostArgs = Object();
+function jsMakePostArgs(fields, fprefix, fsuffix, nofail)
+{
+  var res = [];
+  lastPostArgs = Object();
+
+  for (var id in fields)
+  {
+    var elname = fprefix + id + fsuffix;
+    switch (fields[id])
+    {
+      case 4:
+        elname += "Sel";
+        break;
+    }
+
+    var elem = document.getElementById(elname);
+    if (!elem && !nofail)
+    {
+      jsErrorMessageBox("No such DOM element '"+ elname +"'.");
+      return "";
+    }
+
+    if (elem)
+    {
+      switch (fields[id])
+      {
+        case 1:
+          var vstr = strtrim(elem.value);
+          res.push(id+"="+strencode(vstr));
+          lastPostArgs[id] = vstr;
+          break;
+
+        case 2:
+          var vint = parseInt(strtrim(elem.value));
+          res.push(id+"="+vint);
+          lastPostArgs[id] = vint;
+          break;
+
+        case 3:
+          res.push(id+"="+(elem.checked ? "1" : "0"));
+          lastPostArgs[id] = elem.checked;
+          break;
+
+        case 4:
+          var vval = (elem.selectedIndex != -1) ? elem.options[elem.selectedIndex].value : -1;
+          res.push(id+"="+vval);
+          lastPostArgs[id] = vval;
+          break;
+
+        default:
+          jsErrorMessageBox("Unsupported field type in "+ elname);
+          return "";
+      }
+    }
+  }
+  return res.join("&");
+}
+
+
+function jsGetValue(elname, eltype)
+{
+  var elem = document.getElementById(elname);
+  if (!elem)
+  {
+    jsErrorMessageBox("No such DOM element '"+ elname +"'.");
+    return "";
+  }
+
+  switch (eltype)
+  {
+    case 1:
+      var vstr = strtrim(elem.value);
+      return strencode(vstr);
+
+    case 2:
+      var vint = parseInt(strtrim(elem.value));
+      return vint;
+
+    case 3:
+      return elem.checked ? "1" : "0";
+
+    case 4:
+      if (elem.selectedIndex != -1)
+        return elem.options[elem.selectedIndex].value;
+      else
+        return null;
+
+    default:
+      jsErrorMessageBox("Unsupported field type in "+ elname);
+      return "";
+  }
+}
+
+
+function jsShowPreviewImage(file)
+{
+  var nitem = document.getElementById("messageBox");
+  if (nitem)
+  {
+    nitem.innerHTML = "<div class='imageBoxInner'>"+
+      "<img src='"+file+"' alt='"+file+"' />"+
+      "</div>";
+
+    var elem = document.getElementById("messageBox");
+    elem.onclick = function () { jsCloseMessageBox(0, 0); }
+
+    nitem.style.display = "block";
+
+    return false;
+  }
+
+  return true;
+}
+
+
+function jsFormatSize(bytes)
+{
+  var suffixes = ["Bytes", "KiB", "MiB"];
+  var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
+  return (bytes / Math.pow(1024, i)).toFixed(1) +' '+ suffixes[i];
+}
+
+
+function jsStartFileUpload(formID, formTarget, fileSelID, fileMaxSize, fileCallback)
+{
+  var formFile = document.getElementById(fileSelID).files[0];
+  if (!formFile || typeof(formFile) !== "object")
+  {
+    jsErrorMessageBox("No file selected to be uploaded.");
+    return;
+  }
+
+  if (formFile.size > fileMaxSize)
+  {
+    jsErrorMessageBox("File size exceeds "+ jsFormatSize(fileMaxSize) +".");
+    return;
+  }
+
+  var filename = formFile.name;
+  var formElem = document.getElementById(formID);
+  if (!formElem)
+  {
+    jsErrorMessageBox("File upload form '"+ formID +"' element not found!");
+    return;
+  }
+
+  var formData = new FormData(formElem);
+  var req = jsCreateXMLRequest();
+  req.upload.addEventListener("progress", function(e)
+  {
+    if (e.lengthComputable)
+    {
+      var complete = Math.round(e.loaded * 100 / e.total);
+      if (complete < 100)
+        jsStatusMsg("Uploaded ["+filename+"] "+ complete.toString() +'%, '+ jsFormatSize(e.loaded));
+      else
+        jsStatusMsg("Upload ["+filename+"] finished ...");
+    }
+  }, false);
+  req.addEventListener("error", function(e)
+  {
+    jsErrorMessageBox("Error occured while uploading "+filename);
+  }, false);
+  req.addEventListener("abort", function(e)
+  {
+    jsStatusMsg("Upload of '"+filename+"' aborted.");
+  }, false);
+
+  req.onreadystatechange = function()
+  {
+    if (req.readyState == 4)
+    {
+      switch (req.status)
+      {
+        case 902:
+          jsStatusMsg(req.statusText);
+          jsMessageBox(req.responseText);
+          break;
+
+        case 903:
+          {
+            var nitem = document.getElementById("messageBox");
+            if (nitem)
+            {
+              nitem.innerHTML = "<div class='messageBoxInner'>"+ req.responseText +
+                "<div class='messageBoxControls'>"+
+                "</div></div>";
+              nitem.style.display = "block";
+            }
+          }
+          break;
+        
+        case 200:
+          if (fileCallback)
+          {
+            var tid = setTimeout(function(qtid)
+            {
+              jsRemoveUploadCB(qtid);
+              setTimeout(fileCallback, 10);
+              //jsTitleMessageBox("File upload", req.responseText);
+            }, 10, qtid);
+            jsUploadCBS.push(tid);
+          }
+          break;
+        
+        default:
+          jsStatusMsg("["+req.status+" - "+req.statusText+"] "+ req.responseText);
+          break;
+      }
+    }
+  }
+
+  req.open("POST", formTarget);
+  req.send(formData);
+}
+
+
+function jsCancelUploadCBS()
+{
+  if (jsUploadCBS.length > 0)
+  {
+    for (var tid in jsUploadCBS)
+      clearTimeout(tid);
+  }
+}
+
+
+function jsRemoveUploadCB(tid)
+{
+  var index = jsUploadCBS.indexOf(tid);
+  if (index >= 0)
+    jsUploadCBS.splice(index, 1);
+}