read terms-of-service from file
[brisk.git] / web / commons.js
index 454152a..a38a36c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  brisk - commons.js
  *
- *  Copyright (C) 2006-2008 Matteo Nastasi
+ *  Copyright (C) 2006-2012 Matteo Nastasi
  *                          mailto: nastasi@alternativeoutput.it 
  *                                  matteo.nastasi@milug.org
  *                          web: http://www.alternativeoutput.it
  * not, write to the Free Software Foundation, Inc, 59 Temple Place -
  * Suite 330, Boston, MA 02111-1307, USA.
  *
- * $Id$
- *
  */
 
 var PLAYERS_N = 3;
-var EXIT_BAN_TIME = 900;
+var EXIT_BAN_TIME = 3600;
 var cookiepath = "/brisk/";
 
+var mlang_commons = { 'imgload_a' : { 'it' : 'Immagini caricate ',
+                                      'en' : 'Loaded images ' },
+                      'imgload_b' : { 'it' : '%.', 
+                                      'en' : '%.' },
+                      'gamleav'   : { 'it' : 'Sei sicuro di volere lasciare questa mano?' ,
+                                      'en' : 'Are you sure to leave this game?' },
+                      'brileav'   : { 'it' : '    Vuoi veramente abbandonare la briscola ?\n(clicca annulla o cancel se vuoi ricaricare la briscola)',
+                                      'en' : '    Are you really sure to leave briscola ?\n(click cancel yo reload it)' },
+                      'brireco'   : { 'it' : 'Ripristino della briscola fallito, per non perdere la sessione ricaricare la pagina manualmente.',
+                                      'en' : 'Recovery of briscola failed, to keep the current session reload the page manually.' },
+                      'btn_sit'   : { 'it' : 'Mi siedo.',
+                                      'en' : 'Sit down.' },
+                      'btn_exit'  : { 'it' : 'Esco.',
+                                      'en' : 'Exit.' },
+                      'tit_list'  : { '0'  : { 'it' : '',
+                                               'en' : '' },
+                                      '1'  : { 'it' : '(solo aut.)',
+                                               'en' : '(only aut.)' },
+                                      '2'  : { 'it' : '(isolam.to)',
+                                               'en' : '(isolation)' } },
+                      'lic_refu'  : { 'it' : 'Rifiutando di sottoscrivere la nuova licenza d\' uso non ti sarà più possibile accedere col tuo utente registrato al sito, sei proprio sicuro di non voler accettare le nuove condizioni d\'uso ?',
+                                      'en' : 'EN Rifiutando di sottoscrivere la nuova licenza d\' uso non ti sarà più possibile accedere col tuo utente registrato al sito, sei proprio sicuro di non voler accettare le nuove condizioni d\'uso ?'
+                                    }
+                    };
+
 function $(id) { return document.getElementById(id); }
 
+function dec2hex(d, padding)
+{
+    var hex = Number(d).toString(16);
+    padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;
+
+    while (hex.length < padding) {
+        hex = "0" + hex;
+    }
+
+    return hex;
+}
+
 function getStyle(x,IEstyleProp, MozStyleProp) 
 {
     if (x.currentStyle) {
@@ -188,8 +223,8 @@ function reset_images()
 
 function update_images()
 {
-    //    if (g_imgct % 10 == 0) alert("g_imgct: "+g_imgct+" xx "+g_preload_img_arr[g_imgct]);
-    $("imgct").innerHTML = "Immagini caricate "+g_preload_imgsz_arr[g_imgct]+"%.";
+    // MLANG "Immagine caricate" + g_preload_imgsz_arr[g_imgct] + "%."
+    $("imgct").innerHTML = mlang_commons['imgload_a'][g_lang]+g_preload_imgsz_arr[g_imgct]+"%.";
     if (g_imgct+1 < g_preload_img_arr.length) {
         g_imgct++;
         setTimeout(preload_images, 100, g_preload_img_arr, g_imgct-1);
@@ -220,8 +255,10 @@ function safestatus(a)
 }
 
 function createXMLHttpRequest() {
-    try { return new ActiveXObject("Msxml2.XMLHTTP");    } catch(e) {}
-    try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) {}
+    if (typeof(ActiveXObject) != 'undefined') { // Konqueror complain as unknown object
+        try { return new ActiveXObject("Msxml2.XMLHTTP");    } catch(e) {}
+        try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) {}
+    }
     try { return new XMLHttpRequest();                   } catch(e) {}
     alert("XMLHttpRequest not supported");
     return null;
@@ -234,7 +271,13 @@ function send_mesg(mesg)
     
     // alert("xhr_wr: "+xhr_wr+"  is_conn: "+is_conn);
     xhr_wr.open('GET', 'index_wr.php?'+(is_conn ? 'sess='+sess+'&' : '')+'mesg='+mesg, (is_conn ? true : false));
+    xhr_wr.setRequestHeader("If-Modified-Since", new Date().toUTCString());
     xhr_wr.onreadystatechange = function() { return; };
+    if (typeof(g_debug) == 'number' && g_debug > 0
+        && typeof(console) == 'object' && typeof(console.log) == 'function') {
+            var ldate = new Date();
+            console.log(ldate.getTime()+':MESG:'+mesg);
+    }
     xhr_wr.send(null);
 
     if (!is_conn) {
@@ -244,14 +287,29 @@ function send_mesg(mesg)
     }
 }
 
+/*
+  sync request to server
+  server_request([arg0=arg1[, arg2=arg3[, ...]]])
+  if var name == '__POST__' than all other vars will be managed as POST content
+                                 and the call will be a POST
+ */
 function server_request()
 {
     var xhr_wr = createXMLHttpRequest();
-    var i, collect = "";
+    var i, collect = "", post_collect = null, is_post = false;
 
     if (arguments.length > 0) {
         for (i = 0 ; i < arguments.length ; i+= 2) {
-            collect += (i == 0 ? "" : "&") + arguments[i] + "=" + encodeURIComponent(arguments[i+1]);
+            if (arguments[i] == "__POST__") {
+                is_post = true;
+                post_collect = "";
+                i -= 1;
+                continue;
+            }
+            if (is_post)
+                post_collect += (post_collect == "" ? "" : "&") + arguments[i] + "=" + encodeURIComponent(arguments[i+1]);
+            else
+                collect += (i == 0 ? "" : "&") + arguments[i] + "=" + encodeURIComponent(arguments[i+1]);
         }
     }
     // alert("Args: "+arguments.length);
@@ -260,9 +318,15 @@ function server_request()
     
     // console.log("server_request:preresp: "+xhr_wr.responseText);
 
-    xhr_wr.open('GET', 'index_wr.php?'+(is_conn ? 'sess='+sess+'&' : '')+collect, false);
+    if (is_post) {
+        xhr_wr.open('POST', 'index_wr.php?'+(is_conn ? 'sess='+sess+'&' : '')+collect, false);
+        xhr_wr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
+    }
+    else {
+        xhr_wr.open('GET', 'index_wr.php?'+(is_conn ? 'sess='+sess+'&' : '')+collect, false);
+    }
     xhr_wr.onreadystatechange = function() { return; };
-    xhr_wr.send(null);
+    xhr_wr.send(post_collect);
     
     if (xhr_wr.responseText != null) {
         // console.log("server_request:resp: "+xhr_wr.responseText);
@@ -305,6 +369,11 @@ function act_chatt(value)
 }
 
 /* Stat: ROOM */
+function act_ping()
+{
+    send_mesg("ping");
+}
+
 function act_sitdown(table)
 {
     send_mesg("sitdown|"+table);
@@ -315,7 +384,10 @@ function act_wakeup()
     send_mesg("wakeup");
 }
 
-
+function act_splash()
+{
+    send_mesg("splash");
+}
 
 function act_help()
 {
@@ -343,6 +415,11 @@ function act_about()
     send_mesg("about");
 }
 
+function act_placing()
+{
+    send_mesg("placing");
+}
+
 function act_roadmap()
 {
     send_mesg("roadmap");
@@ -361,8 +438,8 @@ function act_lascio()
 function safelascio()
 {
     var res;
-
-    res = window.confirm("Sei sicuro di volere lasciare questa mano?");
+    // MLANG "Sei sicuro di volere lasciare questa mano?"
+    res = window.confirm(mlang_commons['gamleav'][g_lang]);
     if (res)
        act_lascio();
 }
@@ -392,13 +469,45 @@ function postact_logout()
 {
     // alert("postact_logout");
     try { 
-       xhr_rd.abort();
+       hstm.abort();
     } catch (e) {}
 
     // eraseCookie("sess");
     document.location.assign("index.php");
 }
 
+/*
+  type - 'hard' or 'soft'
+  code - if soft: accept (0), refuse (1), after (2)
+         if hard: accept (0), refuse (1)
+ */
+function act_licencemgr(type, code, lice_curr, lice_vers)
+{
+    if (type != "soft" && type != "hard") {
+        return false;
+    }
+    switch (code) {
+    case 0:
+    case 1:
+        send_mesg("licencemgr|"+type+"|"+code+"|"+lice_curr+"|"+lice_vers);
+        break;
+    case 2:
+        break;
+    default:
+        break;
+    }
+    return true;
+}
+
+function lice_confirm(val)
+{
+    if (val == 1) {
+        return (window.confirm(mlang_commons['lic_refu'][g_lang]));
+    }
+
+    return true;
+}
+
 /*
   function slowimg(img,x1,y1,deltat,free,action,srcend)
   img    - image to move
@@ -533,8 +642,169 @@ slowimg.prototype = {
     }
 }
 
+function div_show(div)
+{
+    div.style.top = parseInt((document.body.clientHeight - parseInt(getStyle(div,"height", "height"))) / 2) + document.body.scrollTop;
+    div.style.visibility = "visible";
+}
 
-function notify(st, text, tout, butt, w, h)
+/*
+  st
+  text
+  tout: if < 0 => infinite
+  butt: [ strings ]
+  w:
+  h:
+  is_opa:
+  block_time:
+  */
+
+function notify_document(st, text, tout, butt, confirm_func, w, h, is_opa, block_time)
+{
+    var i, clo, clodiv_ctx, clodiv_wai, box;
+
+    this.st = st;
+
+    this.ancestor = document.body;
+    this.confirm_func = confirm_func;
+
+    this.st.st_loc_new++;
+
+    clodiv_ctx = document.createElement("div");
+    clodiv_ctx.className = "notify_clo";
+
+    for (i = 0 ; i < butt.length ; i++) {
+        this.input_add(butt[i], i, this.hide, clodiv_ctx);
+    }
+
+    if (block_time > 0) {
+        clodiv_wai = document.createElement("div");
+        clodiv_wai.className = "notify_clo";
+
+        this.input_add("leggere, prego.", 0, null, clodiv_wai);
+        this.clodiv = clodiv_wai;
+        this.clodiv_pkg = clodiv_ctx;
+        clodiv_ctx.style.display = 'none';
+    }
+    else {
+        this.clodiv = clodiv_ctx;
+    }
+
+    cont = document.createElement("div");
+
+    cont.style.borderBottomStyle = "solid";
+    cont.style.borderBottomWidth = "1px";
+    cont.style.borderBottomColor = "gray";
+    cont.style.height = (h - 30)+"px";
+    cont.style.overflow = "auto";
+    cont.style.fontFamily = "monospace";
+    cont.innerHTML = text;
+
+    box =  document.createElement("div");
+    if (is_opa)
+        box.className = "notify_opaque";
+    else
+        box.className = "notify";
+
+    box.style.zIndex = 200;
+    box.style.width  = w+"px";
+    box.style.marginLeft  = -parseInt(w/2)+"px";
+    box.style.height = h+"px";
+    box.style.top = parseInt((document.body.clientHeight - h) / 2) + document.body.scrollTop;
+    box.appendChild(cont);
+    box.appendChild(this.clodiv);
+    box.style.visibility = "visible";
+
+    this.notitag = box;
+
+    this.ancestor.appendChild(box);
+
+    if (tout > 0) {
+        this.toutid = setTimeout(function(obj){ obj.unblock(); }, tout, this);
+    }
+
+    if (block_time != 0) {
+        this.tblkid = setTimeout(function(obj){ obj.notitag.removeChild(obj.clodiv); obj.clodiv = obj.clodiv_pkg; obj.clodiv.style.display = '';  obj.notitag.appendChild(obj.clodiv); }, block_time, this);
+    }
+}
+
+notify_document.prototype = {
+    ancestor: null,
+    st: null,
+    notitag: null,
+    toutid: null,
+    clo: null,
+
+    clodiv: null,
+    clodiv_pkg: null,
+
+    butt: null,
+    tblkid: null,
+
+    confirm_func: null,
+
+    ret: -1,
+
+    /*
+      s:          button string
+      idx:        button index
+      onclick_cb: name of the onclick callback (with signature f(idx) ) or null
+      anc:        parent dom object
+
+      return new button dom object
+      */
+    input_add: function(s, idx, onclick_cb, anc)
+    {
+        var clo;
+
+        clo = document.createElement("input");
+        clo.type    = "submit";
+        clo.className = "button";
+        clo.style.bottom = "4px";
+        clo.style.margin = "2px";
+        clo.obj     = this;
+        clo.obj_idx = idx;
+        clo.value   = s;
+        if (onclick_cb)
+            clo.onclick = function () { onclick_cb.call(this.obj, this.obj_idx); };
+
+        formsub_hilite(clo);
+        anc.appendChild(clo);
+
+        return (clo);
+    },
+
+    ret_get: function()
+    {
+        // alert("quiz: "+this.rett);
+        return this.ret;
+    },
+
+    unblock: function()
+    {
+       if (this.st.st_loc < this.st.st_loc_new) {
+           this.st.st_loc++;
+       }
+    },
+
+    hide: function(val)
+    {
+        if (this.confirm_func != null) {
+            if (this.confirm_func(val) == false) {
+                return false;
+            }
+        }
+        this.ret = val;
+       clearTimeout(this.toutid);
+       this.ancestor.removeChild(this.notitag);
+       this.unblock();
+    }
+}
+
+
+
+
+function notify_ex(st, text, tout, butt, w, h, is_opa, block_time)
 {
     var clo, box;
     var t = this;
@@ -549,12 +819,21 @@ function notify(st, text, tout, butt, w, h)
     clo.type = "submit";
     clo.className = "button";
     clo.style.bottom = "4px";
-    clo.value = butt;
     clo.obj = this;
-    clo.onclick = this.input_hide;
-    
+    if (block_time > 0) {
+        clo.value = "leggere, prego.";
+        this.butt = butt;
+    }
+    else {
+        clo.value = butt;
+        clo.onclick = function () { this.obj.hide() };
+    }
+
     clodiv = document.createElement("div");
     clodiv.className = "notify_clo";
+    this.clo = clo;
+    this.clodiv = clodiv;
+
     clodiv.appendChild(clo);
 
     cont = document.createElement("div");
@@ -567,7 +846,11 @@ function notify(st, text, tout, butt, w, h)
     cont.innerHTML = text;
 
     box =  document.createElement("div");
-    box.className = "notify";
+    if (is_opa)
+        box.className = "notify_opaque";
+    else
+        box.className = "notify";
+
     box.style.zIndex = 200;
     box.style.width  = w+"px";
     box.style.marginLeft  = -parseInt(w/2)+"px";
@@ -583,17 +866,27 @@ function notify(st, text, tout, butt, w, h)
     
     this.toutid = setTimeout(function(obj){ obj.unblock(); }, tout, this);
 
-    formsub_hilite(clo);
-    clo.focus();
+    if (block_time != 0) {
+        this.tblkid = setTimeout(function(obj){ obj.clo.value = obj.butt; obj.clo.onclick = function () { this.obj.hide() }; formsub_hilite(obj.clo); obj.clo.focus(); }, block_time, this);
+    }
+    else {
+        formsub_hilite(clo);
+        clo.focus();
+    }
 
 }
 
-notify.prototype = {
+
+notify_ex.prototype = {
     ancestor: null,
     st: null,
     notitag: null,
     toutid: null,
-    
+    clo: null,
+    clodiv: null, 
+    butt: null,
+    tblkid: null,
+
     unblock: function()
     {
        if (this.st.st_loc < this.st.st_loc_new) {
@@ -606,21 +899,26 @@ notify.prototype = {
        clearTimeout(this.toutid);
        this.ancestor.removeChild(this.notitag);
        this.unblock();
-    },
-
-    input_hide: function()
-    {
-       clearTimeout(this.obj.toutid);
-       this.obj.ancestor.removeChild(this.obj.notitag);
-       this.obj.unblock();
     }
 }
+
+
+notify.prototype = notify_ex.prototype;                // Define sub-class
+notify.prototype.constructor = notify;
+notify.baseConstructor = notify_ex;
+notify.superClass = notify_ex.prototype;
+
+function notify(st, text, tout, butt, w, h)
+{
+    notify_ex.call(this, st, text, tout, butt, w, h, false, 0);
+}
        
 
 function $(id) { 
     return document.getElementById(id); 
 }
 
+
 function globst() {
     this.st = -1;
     this.st_loc = -1;
@@ -628,7 +926,29 @@ function globst() {
     this.comms  = new Array;
 }
 
+globst.prototype = {
+    st: -1,
+    st_loc: -1,
+    st_loc_new: -1,
+    comms: null,
+    sleep_hdl: null,
 
+    sleep: function(delay) {
+        st.st_loc_new++;
+
+        if (!this.the_end) {
+            this.sleep_hdl = setTimeout(function(obj){ if (obj.st_loc_new > obj.st_loc) { obj.st_loc++; obj.sleep_hdl = null; }},
+                                       delay, this);
+        }
+    },
+
+    abort: function() {
+        if (this.sleep_hdl != null) {
+            clearTimeout(this.sleep_hdl);
+            this.sleep_hdl = null;
+        }
+    }
+}
 
 function remark_step()
 {
@@ -693,6 +1013,30 @@ var chatt_lines_n = 0;
 
 var CHATT_MAXLINES = 40;
 
+function user_decorator(user)
+{
+    var name;
+    var flags = user[0];
+    if ((flags & 0x03) != 0)
+        name = "<span class='au" + (flags & 0x03) + "'>"+user[1]+"</span>";
+    else
+        name = user[1];
+
+    return (name);
+}
+
+function user_dec_and_state(el)
+{
+    var content = "";
+    var val_el;
+
+    content = user_decorator(el);
+    content += state_add(el[0],(typeof(el[2]) != 'undefined' ? el[2] : null));
+    
+    return (content);
+}
+
+
 /* PRO CHATT */
 function chatt_sub(dt,data,str)
 {
@@ -700,39 +1044,34 @@ function chatt_sub(dt,data,str)
     var name;
     var flags;
     var isauth;
-
-    flags = data[0];
-    if (flags & 0x02)
-        name = "<i>"+data[1]+"</i>";
-    else
-        name = data[1];
-    // alert ($("txt").scrollTop + parseInt(getStyle($("txt"),"height", "height")) -  $("txt").scrollHeight);
-
-  if ($("txt").scrollTop + parseInt(getStyle($("txt"),"height", "height")) -  $("txt").scrollHeight >= 0)
-      must_scroll = true;
-
-  // alert("ARRIVA NAME: "+ name + "  STR:"+str);
-  if (chatt_lines_n == CHATT_MAXLINES) {
-    $("txt").innerHTML = "";
-    for (i = 0 ; i < (CHATT_MAXLINES - 1) ; i++) {
-      chatt_lines[i] = chatt_lines[i+1];
-      $("txt").innerHTML += chatt_lines[i];
+    var bolder = [ (data[0] | 1), data[1] ];
+    name = user_decorator(bolder);
+
+    if ($("txt").scrollTop + parseInt(getStyle($("txt"),"height", "height")) -  $("txt").scrollHeight >= 0)
+        must_scroll = true;
+
+    // alert("ARRIVA NAME: "+ name + "  STR:"+str);
+    if (chatt_lines_n == CHATT_MAXLINES) {
+        $("txt").innerHTML = "";
+        for (i = 0 ; i < (CHATT_MAXLINES - 1) ; i++) {
+            chatt_lines[i] = chatt_lines[i+1];
+            $("txt").innerHTML += chatt_lines[i];
+        }
+        chatt_lines[i] = dt+name+": "+str+ "<br>";
+        $("txt").innerHTML += chatt_lines[i];
     }
-    chatt_lines[i] = dt+"<b>"+name+"</b> "+str+ "<br>";
-    $("txt").innerHTML += chatt_lines[i];
-  }
-  else {
-    chatt_lines[chatt_lines_n] = dt+"<b>"+name+"</b> "+str+ "<br>";
-    $("txt").innerHTML += chatt_lines[chatt_lines_n];
-    chatt_lines_n++;
-  }
-  // $("txt").innerHTML;
-
+    else {
+        chatt_lines[chatt_lines_n] = dt+name+": "+str+ "<br>";
+        $("txt").innerHTML += chatt_lines[chatt_lines_n];
+        chatt_lines_n++;
+    }
+    // $("txt").innerHTML;
 
-  if (must_scroll) {
-      $("txt").scrollTop = 10000000;
-  }
-  // alert("scTOP "+$("txt").scrollTop+"  scHEIGHT: "+$("txt").scrollHeight+" HEIGHT: "+getStyle($("txt"),"height", "height") );
+    
+    if (must_scroll) {
+        $("txt").scrollTop = 10000000;
+    }
+    // alert("scTOP "+$("txt").scrollTop+"  scHEIGHT: "+$("txt").scrollHeight+" HEIGHT: "+getStyle($("txt"),"height", "height") );
 }
 
 /*
@@ -763,52 +1102,20 @@ function eraseCookie(name) {
        createCookie(name,"",-1);
 }
 
-var onunload_times = 0;
-
-
 function onbeforeunload_cb () {
     return("");
 }
 
-function onunload_cb_old () {
-    var u = 0;
-    
-    //    if (nonunload == true)
-    //     return true;
-    
-    if (onunload_times == 0) {
-       var res = window.confirm("    Vuoi veramente abbandonare la briscola ?\n(clicca annulla o cancel se vuoi ricaricare la briscola)");
-       if (res == true) {
-           the_end = true; 
-           act_shutdown();
-           // while (1) 
-           //  u++;
-       }
-       else {
-           try {
-               document.location.href = self.location; //  = self.location;
-                // alert ("passiamo di qui"+self.location);
-                return (false);
-           } catch (e) {
-               alert("Ripristino della briscola fallito, per non perdere la sessione ricaricare la pagina manualmente.");
-           }
-       }
-       onunload_times++;
-    }
-    
-    return(false);
-}
-
 function onunload_cb () {
     
-    the_end = true; 
+    if (typeof(hstm) != "undefined")
+        hstm.the_end = true; 
 
     act_shutdown();
     
     return(false);
 }
 
-
 function room_checkspace(emme,tables,inpe)
 {
     nome = "<b>";
@@ -822,7 +1129,8 @@ function room_checkspace(emme,tables,inpe)
 
     for (i = 0 ; i < tables ; i++) {
        $("table"+i).innerHTML = alta;
-       $("table_act"+i).innerHTML = "<input type=\"button\" class=\"button\" name=\"xhenter"+i+"\"  value=\"Mi siedo.\" onclick=\"act_sitdown(1);\">";
+        // MLANG Mi siedo.
+       $("table_act"+i).innerHTML = "<input type=\"button\" class=\"button\" name=\"xhenter"+i+"\"  value=\""+mlang_commons['btn_sit'][g_lang]+"\" onclick=\"act_sitdown(1);\">";
        }
 
     stand = "<table class=\"table_standup\"><tbody><tr>";
@@ -836,7 +1144,8 @@ function room_checkspace(emme,tables,inpe)
     $("standup").innerHTML = stand;
 
     // VERIFY: what is this button ?
-    $("esco").innerHTML = "<input class=\"button\" name=\"logout\" type=\"button\" value=\"Esco.\" onclick=\"act_logout();\" type=\"button\">";
+    // MLANG Esco.
+    $("esco").innerHTML = "<input class=\"button\" name=\"logout\" type=\"button\" value=\""+mlang_commons['btn_exit'][g_lang]+"\" onclick=\"act_logout();\" type=\"button\">";
 }
 
 function  unescapeHTML(cont) {
@@ -940,7 +1249,7 @@ function sidebanner2_cb()
 function langtolng(lang)
 {
     if (lang == "en")
-        return ("_en");
+        return ("-en");
     else
         return ("");
 }
@@ -959,3 +1268,124 @@ function formsub_hilite(obj)
     addEvent(obj, "blur",  function () { this.className = 'input_sub'; });
 }
 
+// return the value of the radio button that is checked
+// return an empty string if none are checked, or
+// there are no radio buttons
+function get_checked_value(radioObj) {
+       if(!radioObj)
+               return "";
+       var radioLength = radioObj.length;
+       if(radioLength == undefined)
+               if(radioObj.checked)
+                       return radioObj.value;
+               else
+                       return "";
+       for(var i = 0; i < radioLength; i++) {
+               if(radioObj[i].checked) {
+                       return radioObj[i].value;
+               }
+       }
+       return "";
+}
+
+// set the radio button with the given value as being checked
+// do nothing if there are no radio buttons
+// if the given value does not exist, all the radio buttons
+// are reset to unchecked
+function set_checked_value(radioObj, newValue) {
+       if(!radioObj)
+               return;
+       var radioLength = radioObj.length;
+       if(radioLength == undefined) {
+               radioObj.checked = (radioObj.value == newValue.toString());
+               return;
+       }
+       for(var i = 0; i < radioLength; i++) {
+               radioObj[i].checked = false;
+               if(radioObj[i].value == newValue.toString()) {
+                       radioObj[i].checked = true;
+               }
+       }
+}
+
+function url_append_arg(url, name, value)
+{
+    var pos, sep, pref, rest;
+
+    if ((pos = url.indexOf('?'+name+'=')) == -1) {
+        pos = url.indexOf('&'+name+'=');
+    }
+    if (pos == -1) {
+        if ((pos = url.indexOf('?')) != -1)
+            sep = '&';
+        else
+            sep = '?';
+
+        return (url+sep+name+"="+encodeURIComponent(value));
+    }
+    else {
+        pref = url.substring(0, pos+1);
+        rest = url.substring(pos+1);
+        // alert("rest: "+rest+"  pos: "+pos);
+        if ((pos = rest.indexOf('&')) != -1) {
+            rest = rest.substring(pos);
+        }
+        else {
+            rest = "";
+        }
+        return (pref+name+"="+encodeURIComponent(value)+rest);
+    }
+}
+
+function url_append_args(url)
+{
+    var i, ret;
+
+    ret = url;
+    for (i = 1 ; i < arguments.length-1 ; i+= 2) {
+        ret = url_append_arg(ret, arguments[i], arguments[i+1]);
+    }
+
+    return (ret);
+}
+
+function url_complete(parent, url)
+{
+    var p, p2, rest;
+    var host = "", path = "";
+
+    // host extraction
+    p = parent.indexOf("://");
+    if (p > -1) {
+        rest = parent.substring(p+3);
+        p2 = rest.indexOf("/");
+        if (p2 > -1) {
+            host = parent.substring(0, p+3+p2);
+            rest = parent.substring(p+3+p2);
+        }
+        else {
+            host = rest;
+            rest = "";
+        }
+    }
+    else {
+        rest = parent;
+    }
+
+    // path extraction
+    p = rest.lastIndexOf("/");
+    if (p > -1) {
+        path = rest.substring(0, p+1);
+    }
+
+    // alert("host: ["+host+"]  path: ["+path+"]");
+    if (url.substring(0,6) == 'http:/' || url.substring(0,7) == 'https:/' || url.substring(0,4) == 'ws:/') {
+        return (url);
+    }
+    else if (url.substring(0,1) == '/') {
+        return (host+url);
+    }
+    else {
+        return (host+path+url);
+    }
+}