form.js (16143B)
1 /* 26jun13abu 2 * (c) Software Lab. Alexander Burger 3 */ 4 5 var FormReq = new XMLHttpRequest(); 6 FormReq.upload.addEventListener("progress", dropProgress, false); 7 FormReq.upload.addEventListener("load", dropLoad, false); 8 9 var Btn = []; 10 var Queue = []; 11 var SesId, Key, InBtn, Auto, Chg, Drop, Hint, Hints, Item, Beg, End; 12 13 function inBtn(flg) {InBtn = flg;} 14 15 function formKey(event) { 16 Key = event.keyCode; 17 if (Hint && Hint.style.visibility == "visible") { 18 if ((Item >= 0 && Key == 13) || Key == 38 || Key == 40) 19 return false; 20 if (event.keyCode == 27) { 21 Hint.style.visibility = "hidden"; 22 return false; 23 } 24 } 25 if (event.charCode || event.keyCode == 8) 26 Chg = true; 27 return true; 28 } 29 30 function fldChg(field) { 31 Chg = true; 32 if (!InBtn && Key != 13) 33 post(field.form, false, null, null); 34 return true; 35 } 36 37 function doBtn(btn) { 38 Btn.push(btn); 39 return true; 40 } 41 42 function doDrag(event) { 43 event.stopPropagation(); 44 event.preventDefault(); 45 } 46 47 function doDrop(btn, event) { 48 doDrag(event); 49 if (event.dataTransfer.files.length != 0) { 50 Btn.push(Drop = btn); 51 btn.value = "0 %"; 52 post(btn.form, false, null, event.dataTransfer.files[0]); 53 } 54 } 55 56 function dropProgress(event) { 57 if (Drop) 58 Drop.value = event.lengthComputable? 59 Math.round((event.loaded * 100) / event.total) + " %" : "(?) %"; 60 } 61 62 function dropLoad(event) { 63 Drop = null; 64 } 65 66 function hasElement(form, name) { 67 for (var i = 0; i < form.elements.length; ++i) 68 if (form.elements[i].name == name) 69 return true; 70 return false; 71 } 72 73 function setHref(fld, url) { 74 var i = url.indexOf("~"); 75 76 if (url.charAt(i = i>=0? i+1 : 0) == "+") { 77 url = url.substr(0,i) + url.substr(i+1); 78 fld.target = "_blank"; 79 } 80 fld.href = decodeURIComponent(url); 81 } 82 83 /*** Form submit ***/ 84 function doPost(form) { 85 for (var i = 0; ; ++i) { 86 if (i == Btn.length) 87 return true; 88 if (Btn[i].form == form) 89 return post(form, false, null, null); 90 } 91 } 92 93 function post(form, auto, exe, file) { 94 var i, data; 95 96 if (!FormReq || !hasElement(form,"*Get") || (i = form.action.indexOf("~")) <= 0) 97 return true; 98 if (FormReq.readyState > 0 && FormReq.readyState < 4) { 99 Queue.push([form, auto, exe, file]); 100 return false; 101 } 102 form.style.cursor = "wait"; 103 try {FormReq.open("POST", SesId + "!jsForm?" + form.action.substr(i+1));} 104 catch (e) {return true;} 105 FormReq.onload = function() { 106 var i, j; 107 108 if (FormReq.responseText == "T") { 109 Queue.length = 0; 110 form.submit(); 111 } 112 else { 113 var txt = FormReq.responseText.split("&"); 114 115 if (txt[0]) { 116 var r = txt[0].split(":"); 117 118 if (Auto) 119 clearTimeout(Auto); 120 if (!r[1]) 121 Auto = null; 122 else { 123 Auto = setTimeout(function() { 124 if (Chg) 125 Auto = setTimeout(arguments.callee, r[1]); 126 else { 127 Btn.push(document.getElementById(r[0])); 128 post(form, true, null, null); 129 } 130 }, r[1] ); 131 } 132 } 133 if (!auto || !Chg) { 134 for (i = 1; i < txt.length;) { 135 var fld = txt[i++]; 136 var val = decodeURIComponent(txt[i++]); 137 138 if (!fld) { 139 window[txt[i++]](val); 140 continue; 141 } 142 if (!(fld = document.getElementById(fld))) 143 continue; 144 if (fld.tagName == "SPAN") { 145 if (i != txt.length && txt[i].charAt(0) == "=") 146 ++i; 147 if (i == txt.length || txt[i].charAt(0) != "+") { 148 if (fld.firstChild.tagName != "A") 149 fld.firstChild.data = val? val : "\u00A0"; 150 else 151 fld.replaceChild(document.createTextNode(val? val : "\u00A0"), fld.firstChild); 152 } 153 else { 154 var a = document.createElement("A"); 155 156 setHref(a, txt[i++].substr(1)); 157 a.appendChild(document.createTextNode(val)); 158 fld.replaceChild(a, fld.firstChild); 159 } 160 } 161 else if (fld.tagName == "A") { 162 if (i != txt.length && txt[i].charAt(0) == "=") 163 ++i; 164 if (i == txt.length || txt[i].charAt(0) != "+") { 165 fld.replaceChild(document.createTextNode(val? val : "\u00A0"), fld.firstChild); 166 fld.removeAttribute("href"); 167 } 168 else { 169 fld.firstChild.data = val; 170 setHref(fld, txt[i++].substr(1)); 171 } 172 } 173 else if (fld.tagName == "IMG") { 174 var parent = fld.parentNode; 175 176 fld.src = val; 177 fld.alt = txt[i++]; 178 if (parent.tagName == "A") { 179 if (txt[i]) 180 setHref(parent, txt[i]); 181 else { 182 var grand = parent.parentNode; 183 184 grand.removeChild(parent); 185 grand.appendChild(fld); 186 } 187 } 188 else if (txt[i]) { 189 var a = document.createElement("A"); 190 191 parent.removeChild(fld); 192 parent.appendChild(a); 193 a.appendChild(fld); 194 setHref(a, txt[i]); 195 } 196 ++i; 197 } 198 else { 199 if (fld.type == "checkbox") { 200 fld.checked = val != ""; 201 document.getElementsByName(fld.name)[0].value = ""; 202 } 203 else if (fld.type == "select-one") { 204 for (j = 0; j < fld.options.length; ++j) { 205 if (fld.options[j].text == val) 206 fld.selectedIndex = j; 207 fld.options[j].disabled = false; 208 } 209 } 210 else if (fld.type == "radio") { 211 fld.value = val; 212 fld.checked = txt[i++].charAt(0) != ""; 213 } 214 else if (fld.type == "image") 215 fld.src = val; 216 else if (fld.value != val) { 217 fld.value = val; 218 fld.scrollTop = fld.scrollHeight; 219 } 220 fld.disabled = false; 221 if (i < txt.length && txt[i].charAt(0) == "=") { 222 if (fld.type == "select-one") { 223 for (j = 0; j < fld.options.length; ++j) 224 if (fld.options[j].text != val) 225 fld.options[j].disabled = true; 226 } 227 fld.disabled = true; 228 InBtn = 0; // 'onblur' on won't come when disabled 229 if (fld.type == "checkbox" && fld.checked) 230 document.getElementsByName(fld.name)[0].value = "T"; 231 ++i; 232 } 233 } 234 while (i < txt.length && (j = "#*?".indexOf(txt[i].charAt(0))) >= 0) { 235 switch (j) { 236 237 case 0: // '#' 238 var cls; 239 240 val = txt[i++].substr(1); 241 if ((cls = fld.getAttribute("class")) != null && (j = cls.indexOf(" ")) >= 0) 242 val += cls.substr(j); 243 fld.setAttribute("class", val); 244 break; 245 246 case 1: // '*' 247 var node = fld.parentNode.parentNode.lastChild; 248 var img = document.createElement("IMG"); 249 250 if (!node.firstChild) 251 node = fld.parentNode.parentNode.parentNode.lastChild; 252 node.removeChild(node.firstChild); 253 img.src = txt[i++].substr(1); 254 if (!txt[i]) 255 node.appendChild(img); 256 else { 257 var a = document.createElement("A"); 258 259 setHref(a, txt[i]); 260 a.appendChild(img); 261 node.appendChild(a); 262 } 263 ++i; 264 break; 265 266 case 2: // '?' 267 fld.title = decodeURIComponent(txt[i++].substr(1)); 268 break; 269 } 270 } 271 } 272 Chg = false; 273 } 274 } 275 form.style.cursor = ""; 276 if (Queue.length > 0) { 277 var a = Queue.shift(); 278 post(a[0], a[1], a[2], a[3]); 279 } 280 } 281 if (!exe) 282 data = ""; 283 else { 284 data = "*Gui:0:=" + exe[0]; 285 for (var i = 1; i < exe.length; ++i) 286 data += "&*JsArgs:" + i + ":=" + exe[i]; 287 } 288 for (i = 0; i < Btn.length;) 289 if (Btn[i].form != form) 290 ++i; 291 else { 292 data += "&" + Btn[i].name + "=" + encodeURIComponent(Btn[i].type == "submit"? Btn[i].value : Btn[i].src); 293 Btn.splice(i,1); 294 } 295 for (i = 0; i < form.elements.length; ++i) { 296 var fld = form.elements[i]; 297 298 if (fld.name && fld.type != "submit") { // "image" won't come :-( 299 var val; 300 301 if (fld.type == "checkbox") 302 val = fld.checked? "T" : ""; 303 else if (fld.type == "select-one") 304 val = fld.options[fld.selectedIndex].text; 305 else if (fld.type == "radio" && !fld.checked) 306 continue; 307 else 308 val = fld.value; 309 data += "&" + fld.name + "=" + encodeURIComponent(val.replace(/ +$/,"")); 310 } 311 } 312 try { 313 if (!file) 314 FormReq.send(data); 315 else { 316 var rd = new FileReader(); 317 rd.readAsBinaryString(file); 318 rd.onload = function() { 319 FormReq.setRequestHeader("X-Pil", "*ContLen="); 320 FormReq.sendAsBinary(data + "&*Drop=" + 321 encodeURIComponent(file.name) + "=" + 322 file.size + "\n" + rd.result ); 323 } 324 } 325 } 326 catch (e) { 327 FormReq.abort(); 328 return true; 329 } 330 return false; 331 } 332 333 /*** Hints ***/ 334 function doHint(field) { 335 if (!Hint) { 336 Hint = document.createElement("div"); 337 Hint.setAttribute("class", "hint"); 338 Hint.style.visibility = "hidden"; 339 Hint.style.position = "absolute"; 340 Hint.style.zIndex = 9999; 341 Hint.style.textAlign = "left"; 342 Hints = document.createElement("div"); 343 Hints.setAttribute("class", "hints"); 344 Hints.style.position = "relative"; 345 Hints.style.top = "-2px"; 346 Hints.style.left = "-3px"; 347 Hint.appendChild(Hints); 348 } 349 field.parentNode.appendChild(Hint); 350 field.onblur = function() { 351 Hint.style.visibility = "hidden"; 352 } 353 var top = field.offsetHeight + 2; 354 var left = 3; 355 for (var obj = field; obj.id != "main" && obj.id != "menu"; obj = obj.offsetParent) { 356 top += obj.offsetTop; 357 left += obj.offsetLeft; 358 } 359 Hint.style.top = top + "px"; 360 Hint.style.left = left + "px"; 361 } 362 363 function hintKey(field, event, tok, coy) { 364 var i, data; 365 366 if (event.keyCode == 9 || event.keyCode == 27) 367 return false; 368 if (Hint.style.visibility == "visible") { 369 if (Item >= 0 && event.keyCode == 13) { 370 setHint(field, Hints.childNodes[Item]); 371 return false; 372 } 373 if (event.keyCode == 38) { // Up 374 if (Item > 0) { 375 hintOff(Item); 376 hintOn(--Item); 377 } 378 return false; 379 } 380 if (event.keyCode == 40) { // Down 381 if (Item < (lst = Hints.childNodes).length-1) { 382 if (Item >= 0) 383 hintOff(Item); 384 hintOn(++Item); 385 } 386 return false; 387 } 388 } 389 if (event.keyCode == 13) 390 return true; 391 var req = new XMLHttpRequest(); 392 if (tok) { 393 for (Beg = field.selectionStart; Beg > 0 && !field.value.charAt(Beg-1).match(/\s/); --Beg); 394 End = field.selectionEnd; 395 } 396 else { 397 Beg = 0; 398 End = field.value.length; 399 } 400 if (event.keyCode != 45) { // INS 401 if (Beg == End) { 402 Hint.style.visibility = "hidden"; 403 return false; 404 } 405 if (coy && Hint.style.visibility == "hidden") 406 return false; 407 } 408 try { 409 req.open("POST", (SesId? SesId : "") + 410 ((i = field.id.lastIndexOf("-")) < 0? 411 "!jsHint?$" + field.id : "!jsHint?+" + field.id.substr(i+1) ) ); 412 } 413 catch (e) {return true;} 414 req.onload = function() { 415 var i, n, lst, str; 416 417 if ((str = req.responseText).length == 0) 418 Hint.style.visibility = "hidden"; 419 else { 420 lst = str.split("&"); 421 while (Hints.hasChildNodes()) 422 Hints.removeChild(Hints.firstChild); 423 for (i = 0, n = 7; i < lst.length; ++i) { 424 addHint(i, field, str = decodeURIComponent(lst[i])); 425 if (str.length > n) 426 n = str.length; 427 } 428 Hints.style.width = n + 3 + "ex"; 429 Hint.style.width = n + 4 + "ex"; 430 Hint.style.visibility = "visible"; 431 Item = -1; 432 } 433 } 434 var data = "*JsHint=" + encodeURIComponent(field.value.substring(Beg,End)); 435 for (i = 0; i < field.form.elements.length; ++i) { 436 var fld = field.form.elements[i]; 437 438 if (fld.name == "*Get") 439 data += "&*Get=" + fld.value; 440 else if (fld.name == "*Form") 441 data += "&*Form=" + fld.value; 442 } 443 try {req.send(data);} 444 catch (e) { 445 req.abort(); 446 return true; 447 } 448 return (event.keyCode != 45); // INS 449 } 450 451 function addHint(i, field, str) { 452 var item = document.createElement("div"); 453 item.appendChild(document.createTextNode(str)); 454 item.onmouseover = function() { 455 if (Item >= 0) 456 hintOff(Item); 457 hintOn(i); 458 field.onblur = false; 459 field.onchange = false; 460 Item = i; 461 } 462 item.onmouseout = function() { 463 hintOff(Item); 464 field.onblur = function() { 465 Hint.style.visibility = "hidden"; 466 } 467 field.onchange = function() { 468 return fldChg(field, item); 469 }; 470 Item = -1; 471 } 472 item.onclick = function() { 473 setHint(field, item); 474 } 475 Hints.appendChild(item); 476 } 477 478 function setHint(field, item) { 479 Hint.style.visibility = "hidden"; 480 field.value = field.value.substr(0,Beg) + item.firstChild.nodeValue + field.value.substr(End); 481 Chg = true; 482 post(field.form, false, null, null); 483 field.setSelectionRange(Beg + item.firstChild.nodeValue.length, field.value.length); 484 field.focus(); 485 field.onchange = function() { 486 return fldChg(field) 487 }; 488 } 489 490 function hintOn(i) { 491 var s = Hints.childNodes[i].style; 492 s.background = "black"; 493 s.color= "white"; 494 } 495 496 function hintOff(i) { 497 var s = Hints.childNodes[i].style; 498 s.background = "white"; 499 s.color= "black"; 500 } 501 502 /*** Lisp calls ***/ 503 function lisp(form, fun) { 504 if (form) { 505 var exe = [fun]; 506 507 for (var i = 2; i < arguments.length; ++i) 508 if (typeof arguments[i] === "number") 509 exe[i-1] = "+" + arguments[i]; 510 else 511 exe[i-1] = "." + encodeURIComponent(arguments[i]); 512 return post(form, false, exe, null); 513 } 514 if (arguments.length > 2) { 515 fun += "?" + lispVal(arguments[2]); 516 for (var i = 3; i < arguments.length; ++i) 517 fun += "&" + lispVal(arguments[i]); 518 } 519 var req = new XMLHttpRequest(); 520 try {req.open("GET", SesId + "!" + fun);} 521 catch (e) {return true;} 522 try {req.send(null);} 523 catch (e) { 524 req.abort(); 525 return true; 526 } 527 setTimeout(function(){req.abort();}, 40); // No response expected 528 return false; 529 } 530 531 function lispVal(x) { 532 if (typeof x === "number") 533 return "+" + x; 534 if (x.charAt(0) == "-") 535 return "%2D" + encodeURIComponent(x.substr(1)); 536 return encodeURIComponent(x); 537 }