1/*var tablecalc_table; 2var tablecalc_crow; 3var tablecalc_ccol; 4var tablecalc_labels; 5var tablecalc_defer;*/ 6 7function tablecalcXY(st) { 8 var r=st.match(/r\d+/); 9 y=r[0].substr(1)*1; 10 var c=st.match(/c\d+/); 11 x=c[0].substr(1)*1; 12 return new Array(x,y); 13} 14function tablecalcVal(x,y,table,tostring) { 15 if (typeof tostring == 'undefined') { 16 tostring=0; 17 } 18 var v='notset'; 19 if ((x>=0) && (y>=0)) { 20 if (typeof table.rows != 'undefined') { 21 if (typeof table.rows[y] != 'undefined') { 22 if (typeof table.rows[y].cells[x] != 'undefined') { 23 var mr=stripHTML(table.rows[y].cells[x].innerHTML); 24 mr=mr.trim(); 25 m=parseFloat(mr); 26 if (!isNaN(m)) { 27 v=m; 28 } else { 29 if (!tostring) { 30 v="notnum"; 31 } else { 32 v=String(mr); 33 } 34 } 35 } 36 } 37 } 38 } 39 return v; 40} 41 42 43function tablecalcToArray(a) { 44 if (!Array.isArray(a)) { 45 return [a]; 46 } else { 47 return a; 48 } 49} 50 51function tablecalcToNumArray(a) { 52 if (!Array.isArray(a)) { 53 a=[a]; 54 } 55 var b=[]; 56 for (var i=0;i<a.length;i++) { 57 if (!isNaN(a[i]*1)) { 58 b.push(a[i]); 59 } 60 } 61 return b; 62} 63 64function correctFloat(a) { 65 var x=10000000000000; 66 return Math.round(a*x)/x; 67} 68 69function sum(a) { 70 a=tablecalcToNumArray(a); 71 var s=0; 72 for (var i=0;i<a.length;i++) { 73 tablecalc_log(a[i]*1); 74 s+=a[i]*1; 75 s=correctFloat(s); 76 } 77 return s; 78} 79 80function average(a) { 81 a=tablecalcToNumArray(a); 82 return correctFloat(sum(a)/a.length); 83} 84 85function min(a) { 86 a=tablecalcToNumArray(a); 87 var s=1*a[0]; 88 for (var i=1;i<a.length;i++) { 89 if (1*a[i]<s) { 90 s=1*a[i]; 91 } 92 } 93 return s; 94} 95 96 97function max(a) { 98 a=tablecalcToNumArray(a); 99 var s=1*a[0]; 100 for (var i=1;i<a.length;i++) { 101 if (1*a[i]>s) { 102 s=1*a[i]; 103 } 104 } 105 return s; 106} 107 108function label(st) { 109 if (typeof tablecalc_labels[st] == 'undefined') { 110 tablecalc_labels[st]=tablecalc_table; 111 } 112 return ""; 113} 114 115function col() { 116 return tablecalc_ccol; 117} 118 119function row() { 120 return tablecalc_crow; 121} 122 123function rows(label) { 124 if (typeof label == 'undefined') { 125 var tbl=tablecalc_table; 126 } else { 127 var tbl=tablecalc_labels[label]; 128 } 129 if (!tbl) { 130 return 0; 131 } else { 132 return tbl.rows.length; 133 } 134} 135 136function cols(label) { 137 if (typeof label == 'undefined') { 138 var tbl=tablecalc_table; 139 } else { 140 var tbl=tablecalc_labels[label]; 141 } 142 if (!tbl) { 143 return 0; 144 } else { 145 let cols=0; 146 for (const row of tbl.rows) { 147 cols = Math.max(cols,row.cells.length); 148 } 149 return cols; 150 } 151} 152 153function cell(x,y) { 154 var tmp=tablecalcVal(x,y,tablecalc_table, 1); 155 if ( tmp=='notset' ) { 156 return ''; 157 } else { 158 return tmp; 159 } 160} 161 162function range(x1,y1,x2,y2) { 163 var members=new Array(); 164 for (var x=x1;x<=x2;x++) { 165 for (var y=y1;y<=y2;y++) { 166 var tmp=cell(x,y); 167 if (tmp!='') { 168 members[members.length]=tmp; 169 } 170 } 171 } 172 var result=""; 173 if (members.length>0) { 174 result="new Array("; 175 for (var k=0;k<members.length;k++) { 176 if (k) { 177 result+=','; 178 } 179 result+="'"+members[k]+"'"; 180 } 181 result+=")" 182 } else if (!tablecalc_checkfinal()) { 183 throw "norange"; 184 } 185 return eval(result); 186} 187 188function count(a) { 189 a=tablecalcToArray(a); 190 return a.length; 191} 192 193function calc() { 194 return nop(); 195} 196 197function round(num,digits) { 198 var d=1; 199 for (var i=0;i<digits;i++) { 200 d*=10; 201 } 202 var n=Math.round(num*d)/d; 203 return n.toFixed(digits); 204} 205 206 207function nop() { 208 return ""; 209} 210 211function check(condition,whenTrue,whenFalse) { 212 if (typeof condition == 'undefined') { 213 condition=0; 214 } 215 if (typeof whenTrue == 'undefined') { 216 whenTrue=""; 217 } 218 if (typeof whenFalse == 'undefined') { 219 whenFalse=""; 220 } 221 if (condition) { 222 return whenTrue; 223 } else { 224 return whenFalse; 225 } 226} 227 228function countif(range,check,operation) { 229 a=tablecalcToArray(range); 230 var cnt=0; 231 for (var i=0;i<a.length;i++) { 232 cnt+=compare(a[i],check,operation); 233 } 234 return cnt; 235} 236 237function criterionMatch(value, criterion) { 238 if (typeof value === 'undefined') { 239 return false; 240 } 241 242 if (typeof criterion === 'string') { 243 if (criterion.startsWith('>=')) { 244 return parseFloat(value) >= parseFloat(criterion.substring(2)); 245 } else if (criterion.startsWith('<=')) { 246 return parseFloat(value) <= parseFloat(criterion.substring(2)); 247 } else if (criterion.startsWith('>')) { 248 return parseFloat(value) > parseFloat(criterion.substring(1)); 249 } else if (criterion.startsWith('<')) { 250 return parseFloat(value) < parseFloat(criterion.substring(1)); 251 } else if (criterion.startsWith('=')) { 252 return parseFloat(value) == parseFloat(criterion.substring(1)); 253 } else if (criterion.includes('*') || criterion.includes('?')) { 254 // Mitigate ReDoS: collapse multiple wildcards 255 let safeCriterion = criterion.replace(/\*+/g, '*'); 256 257 // Build regex from wildcard string 258 let regexStr = "^"; 259 for (let i = 0; i < safeCriterion.length; i++) { 260 let char = safeCriterion[i]; 261 if (char === '~') { 262 // Next char is literal 263 i++; 264 if (i < safeCriterion.length) { 265 // escape for regex 266 regexStr += safeCriterion[i].replace(/([.*+?^${}()|\[\]\/\\])/g, "\\$1"); 267 } 268 } else if (char === '*') { 269 regexStr += ".*"; 270 } else if (char === '?') { 271 regexStr += "."; 272 } else { 273 // escape for regex 274 regexStr += char.replace(/([.*+?^${}()|\[\]\/\\])/g, "\\$1"); 275 } 276 } 277 regexStr += "$"; 278 279 try { 280 let regex = new RegExp(regexStr); 281 return regex.test(String(value)); 282 } catch (e) { 283 // Invalid regex, treat as no match 284 return false; 285 } 286 } 287 } 288 return String(value) == String(criterion); 289} 290 291function sumif(range, criterion, sum_range) { 292 range = tablecalcToArray(range); 293 if (typeof sum_range === 'undefined') { 294 sum_range = range; 295 } else { 296 sum_range = tablecalcToArray(sum_range); 297 } 298 299 var s = 0; 300 for (var i = 0; i < range.length; i++) { 301 if (criterionMatch(range[i], criterion)) { 302 var val = parseFloat(sum_range[i]); 303 if (!isNaN(val)) { 304 s += val; 305 s = correctFloat(s); 306 } 307 } 308 } 309 return s; 310} 311 312 313function compare(a,b,operation) { 314 if (typeof operation == 'undefined') { 315 operation='='; 316 } 317 if (typeof a == 'undefined') { 318 a=0; 319 } 320 if (typeof b == 'undefined') { 321 b=0; 322 } 323 switch (operation) { 324 case ">": 325 if (a>b) {return 1;} else {return 0;} 326 break; 327 case "<": 328 if (a<b) {return 1;} else {return 0;} 329 break; 330 case ">=": 331 if (a>=b) {return 1;} else {return 0;} 332 break; 333 case "<=": 334 if (a<=b) {return 1;} else {return 0;} 335 break; 336 case "<>": 337 case "!=": 338 if (a!=b) {return 1;} else {return 0;} 339 break; 340 case "=": 341 default: 342 if (a==b) {return 1;} else {return 0;} 343 } 344 return 0; 345} 346 347function tablecalc_log(st) { 348 if (!tablecalc_debug) {return;} 349 if (tablecalc_debug==1) { 350 alert(st); 351 } else { 352 console.log(st); 353 } 354} 355 356function tablecalc_checkfinal() { 357 if (typeof tablecalc_isfinal === "undefined") { 358 return 0; 359 } else { 360 return tablecalc_isfinal; 361 } 362} 363 364function tablecalc(divID, formula, final) { 365 366 if (isNaN(final)) {final=0;} 367 368 if (typeof tablecalc_debug === "undefined") { 369 window.tablecalc_debug=0; 370 } 371 if (typeof tablecalc_labels === "undefined") { 372 window.tablecalc_labels=[]; 373 } 374 if (typeof tablecalc_defer === "undefined") { 375 window.tablecalc_defer=[]; 376 } 377 if (typeof tablecalc_crow === "undefined") { 378 window.tablecalc_crow=null; 379 } 380 if (typeof tablecalc_ccol === "undefined") { 381 window.tablecalc_ccol=null; 382 } 383 if (typeof tablecalc_table === "undefined") { 384 window.tablecalc_table=null; 385 } 386 if (typeof tablecalc_isfinal === "undefined") { 387 window.tablecalc_isfinal=final; 388 } 389 if (typeof tablecalc_setfinal === "undefined") { 390 window.tablecalc_setfinal=1; 391 setTimeout(tablecalc_final,100); 392 } 393 394 var oFormula=formula; 395 396 tablecalc_log("Entering: "+divID+"=>"+formula+"; is final: "+final); 397 var div = document.getElementById(divID); 398 //getting parent TD 399 var table=0; 400 var cCol=0; 401 var cRow=0; 402 var cRows=0; 403 var cCols=0; 404 var pNode=findParentNodeByName(div,"TD"); 405 if (!pNode) { 406 pNode=findParentNodeByName(div,"TH"); 407 } 408 if (pNode) { 409 cCol = pNode.cellIndex; 410 pNode=findParentNodeByName(pNode,"TR"); 411 if (pNode) { 412 cRow = pNode.rowIndex; 413 table=findParentNodeByName(pNode,"TABLE"); 414 } 415 } 416 tablecalc_crow=cRow; 417 tablecalc_ccol=cCol; 418 tablecalc_table=table; 419 420 var matchA=formula.match(/([a-z0-9_]+\.)?(r|c)\d+(r|c)\d+(\:(r|c)\d+(r|c)\d+)?(\,([a-z0-9]+\.)?(r|c)\d+(r|c)\d+(\:(r|c)\d+(r|c)\d+)?){0,99}/g); 421 if (matchA != null) { 422 for (var i = 0; i<matchA.length; i++) { 423 var members=new Array(); 424 425 var matchL=matchA[i].split(','); 426 for (var j=0;j<matchL.length;j++) { 427 var tmp_table=table; 428 var matchB=matchL[j].split('.',2); 429 if (matchB.length<2) { 430 matchB[1]=matchB[0]; 431 } else { 432 if (typeof tablecalc_labels[matchB[0]] != 'undefined') { 433 tmp_table=tablecalc_labels[matchB[0]]; 434 } else { 435 if (final) { 436 tmp_table="notable"; 437 } else { 438 tablecalcAddDefer(divID,oFormula); 439 //tablecalcProcessDefer(); 440 return false; 441 } 442 } 443 } 444 if (tmp_table!="notable") { 445 var matchC=matchB[1].split(':',2); 446 if (matchC.length<2) { 447 matchC[1]=matchC[0]; 448 } 449 from=tablecalcXY(matchC[0]); 450 to=tablecalcXY(matchC[1]); 451 if (from[0]>to[0]) { 452 var tmp=to[0]; 453 to[0]=from[0]; 454 from[0]=tmp; 455 } 456 if (from[1]>to[1]) { 457 var tmp=to[1]; 458 to[1]=from[1]; 459 from[1]=tmp; 460 } 461 for (var fx=from[0];fx<=to[0];fx++) { 462 for (var fy=from[1];fy<=to[1];fy++) { 463 if ((fx==cCol) && (fy==cRow) && (tmp_table==table)) {continue;} 464 var tmp=tablecalcVal(fx,fy,tmp_table); 465 tablecalc_log("member["+fx+","+fy+"]="+tmp); 466 if ( (tmp == 'notnum') || (tmp == 'notset') ) { 467 tablecalcAddDefer(divID,oFormula); 468 if (!final) { 469 //tablecalcProcessDefer(); 470 return false; 471 } else { 472 members[members.length]=tablecalcVal(fx,fy,tmp_table,1); 473 } 474 } else {/*if (tmp!='notset') {*/ 475 members[members.length]=tmp; 476 } 477 } 478 } 479 } else { 480 tablecalc_log("table not found by label: "+matchB[0]); 481 } 482 } 483 var result=""; 484 if (members.length>0) { 485 if (members.length==1) { 486 var tmp=parseFloat(members[0]); 487 if (isNaN(tmp)) { 488 result="'"+members[0]+"'"; 489 } else { 490 result=members[0]*1; 491 } 492 } else { 493 result="new Array("; 494 for (var k=0;k<members.length;k++) { 495 if (k) { 496 result+=','; 497 } 498 result+="'"+members[k]+"'"; 499 } 500 result+=")" 501 } 502 } 503 formula=formula.replace(matchA[i],result); 504 } 505 } 506 507 formula=formula.replace(/;/g,","); 508 tablecalc_log("Evaluating: "+formula); 509 var rc; 510 try { 511 eval('calcresult = '+formula); 512 //if (!isNaN(calcresult)) { 513 tablecalc_log("Got result: "+calcresult+" ("+(typeof calcresult)+")"); 514 if ((typeof calcresult === "number") && (isNaN(calcresult))) { 515 tablecalcAddDefer(divID,oFormula); 516 rc=false; 517 } else { 518 div.innerHTML=calcresult; 519 rc=true; 520 } 521 } catch (e) { 522 rc=false; 523 tablecalc_log("Exception: "+e); 524 tablecalcAddDefer(divID,oFormula); 525 } 526 if (!final) { 527 tablecalcProcessDefer(); 528 } 529 return rc; 530} 531 532function tablecalcAddDefer(divID,formula) { 533 if (typeof tablecalc_defer[divID] == 'undefined') { 534 tablecalc_defer[divID]=formula; 535 tablecalc_log("Added defer: "+divID+"=>"+tablecalc_defer[divID]); 536 } 537} 538 539function tablecalcProcessDefer() { 540 var exit; 541 var steps=0; 542 do { 543 steps++; 544 exit=1; 545 for (var divID in tablecalc_defer) { 546 if (tablecalc_defer[divID].length) { 547 tablecalc_log("calling defer: "+divID+"=>"+tablecalc_defer[divID]); 548 var tmp=tablecalc_defer[divID]; 549 tablecalc_defer[divID]=""; 550 if (!tablecalc(divID,tmp,0)) { 551 tablecalc_defer[divID]=tmp; 552 } else { 553 exit=0; 554 } 555 } 556 } 557 } while ( (!exit) && (steps<99) ); 558 if (steps>=99) { 559 tablecalc_log("max steps reached!"); 560 } 561} 562 563function tablecalc_final() { 564 tablecalc_log("entering final"); 565 tablecalc_isfinal=1; 566 tablecalcProcessDefer(); 567 for (var divID in tablecalc_defer) { 568 if (tablecalc_defer[divID].length) { 569 tablecalc_log("calling final defer: "+divID+"=>"+tablecalc_defer[divID]); 570 if (tablecalc(divID,tablecalc_defer[divID],1,99)) { 571 tablecalc_defer[divID]=""; 572 } 573 } 574 } 575} 576 577function findParentNodeByName(pNode, tag) { 578 tag = tag.toUpperCase(); 579 580 while (pNode && pNode.nodeName !== tag) { 581 pNode = pNode.parentNode; 582 } 583 584 return (pNode && pNode.nodeName === tag) ? pNode : null; 585} 586 587 588function stripHTML(oldString) { 589 return oldString.replace(/<[^>]*>/g, ""); 590} 591