1// JavaScript Document 2 3//TRIM POLYFILL FOR OLDER BROWSERS// 4// ...eyes on you, IE... // 5if( ! "trim" in String.prototype ) 6 String.prototype.trim = function() { this.replace(/^\s*/, '').replace(/\s*$/, ''); }; 7 8String.prototype.ersPaddingLeft = function(paddingValue) 9{ 10 return String(paddingValue + this).slice(-paddingValue.length); 11} 12 13loader_script_arr = new Array(); 14function add_loader_script(str) 15{ 16 loader_script_arr[loader_script_arr.length] = str; 17} 18 19function run_loader_scripts() 20{ 21 for(n=0; n<loader_script_arr.length; n++) 22 { 23 var script_str = loader_script_arr[n]; 24 eval(script_str); 25 } 26} 27 28window.onload = run_loader_scripts; 29 30function sort_js_array_by_key(jsarr,jskey) { 31 // note that keys must be unique and must exist in all rows for this function to work properly 32 var klist = new Array(); 33 var arr_by_keys = new Array(); 34 for(var k in jsarr) { 35 var keyval = jsarr[k][jskey]; 36 arr_by_keys['K' + keyval] = jsarr[k]; 37 klist.push(keyval); 38 } 39 klist.sort(); 40 var newarr = new Array(); 41 for(var k=0; k<klist.length; k++) { 42 var keyval = klist[k]; 43 newarr.push(arr_by_keys['K' + keyval]); 44 } 45 return newarr; 46} 47 48function is_dev_site() 49{ 50 var wnlc = "" + window.location + ""; 51 if(wnlc.indexOf('_dev') > 1 || wnlc.indexOf('-dev') > 1) 52 { 53 return true; 54 } 55 else return false; 56} 57 58function append_html_to_id(areaid, newhtml, element_container) 59{ 60 if(!element_container) 61 element_container = 'div'; 62 newhtml = decode_escaped_string(newhtml); 63 var t = document.createElement(element_container); 64 t.innerHTML = newhtml; 65 document.getElementById(areaid).appendChild(t); 66 //document.getElementById(areaid).innerHTML += newhtml; 67 return t; 68} 69 70function decode_escaped_string(str) 71{ 72 str = str.replace(/\[_quot_\]/ig,"\""); 73 str = str.replace(/\[_squot_\]/ig,"'"); 74 str = str.replace(/\[_lt_\]/ig,"<"); 75 str = str.replace(/\[_gt_\]/ig,">"); 76 str = str.replace(/\[_ls_\]/ig,"\\"); 77 str = str.replace(/\[_fs_\]/ig,"/"); 78 str = str.replace(/\[_nl_\]/ig,"\n"); 79 str = str.replace(/\[_qu_\]/ig,"?"); 80 return str; 81} 82 83function getObjPosition(obj,type,check_scroll) 84{ 85 if (!obj) 86 { 87 return []; 88 } 89 90 if(!check_scroll) check_scroll = false; 91 if(!type) type = "all"; 92 var curwidth = obj.offsetWidth; 93 var curheight = obj.offsetHeight; 94 var curleft = obj.offsetLeft; 95 var curtop = obj.offsetTop; 96 var offleft = 0; 97 var offtop = 0; 98 if(check_scroll) { 99 if(obj.offsetParent != obj.parentNode) { 100 offleft -= obj.parentNode.scrollLeft; 101 offtop -= obj.parentNode.scrollTop; 102 //console.log(obj.parentNode.className + ":" + obj.parentNode.scrollTop); 103 } 104 } 105 106 107 while(obj.offsetParent) 108 { 109 obj = obj.offsetParent; 110 curleft += obj.offsetLeft; 111 curtop += obj.offsetTop; 112 offleft += obj.offsetLeft; 113 offtop += obj.offsetTop; 114 if(check_scroll) { 115 offleft -= obj.scrollLeft; 116 offtop -= obj.scrollTop; 117 } 118 } 119 var retval = new Array(); 120 retval[0] = curleft; 121 retval[1] = curtop; 122 retval[2] = curwidth; 123 retval[3] = curheight; 124 retval['left'] = curleft; 125 retval['top'] = curtop; 126 retval['width'] = curwidth; 127 retval['height'] = curheight; 128 retval['offleft'] = offleft; 129 retval['offtop'] = offtop; 130 if(type=="left" || type=="top" || type=="width" || type=="height") return retval[type]; 131 return retval; 132} 133 134function getElementByIdOrNode(node) { 135 if( node instanceof HTMLElement ) return node; 136 if( typeof node === "string" ) return document.getElementById(node); 137 return null; 138} 139 140/*** 141 * elementDescendedFrom(element_id: string|Node, descendent_id: string|Node) -> success: bool 142 * @returns success: bool 143 * 144 * Returns whether or not element_id is an ancestor of descendent_id in the 145 * DOM tree. 146 * */ 147function elementDescendedFrom(element_id,descendent_id) 148{ 149 //JL: 2017.07.30 150 //Added if statement to allow DOM nodes as parameters. 151 //The old functionality is within the first `if`: 152 if( typeof element_id === "string" ) { 153 154 //begin old function// 155 var str = "searching for: " + descendent_id; 156 var obj = document.getElementById(element_id); 157 str += "\n" + obj.id; 158 if(obj.id==descendent_id) return true; 159 while(obj.offsetParent) 160 { 161 obj = obj.offsetParent; 162 str += "\n" + obj.id; 163 if(obj.id==descendent_id) return true; 164 } 165 return false;
166 //end old function// 167 } 168 169 if( element_id instanceof HTMLElement ) { 170 171 var descendent = getElementByIdOrNode(descendent_id); 172 if( obj === descendent ) return true; 173 while( obj.parentNode && obj.parentNode.tagName !== "BODY" ) { 174 obj = obj.parentNode; 175 if( obj === descendent ) return true; 176 } 177 } 178 return false; 179} 180 181function getElementPosition(element_id) 182{ 183 var obj = document.getElementById(element_id); 184 return getObjPosition(obj); 185} 186 187function getViewPortSize() 188{ 189 var viewportwidth; 190 var viewportheight; 191 // the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight 192 if (typeof window.innerWidth != 'undefined') 193 { 194 viewportwidth = window.innerWidth, 195 viewportheight = window.innerHeight 196 } 197 // IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document) 198 else if (typeof document.documentElement != 'undefined' && typeof document.documentElement.clientWidth != 'undefined' && document.documentElement.clientWidth != 0) 199 { 200 viewportwidth = document.documentElement.clientWidth, 201 viewportheight = document.documentElement.clientHeight 202 } 203 // older versions of IE 204 else 205 { 206 viewportwidth = document.getElementsByTagName('body')[0].clientWidth, 207 viewportheight = document.getElementsByTagName('body')[0].clientHeight 208 } 209 return new Array(viewportwidth, viewportheight); 210} 211 212function get_parent_element(parent_id) 213{ 214 obj = document.getElementById("floating_window").parentNode; 215 while(obj.id.substring(0,14)=="container_area") 216 obj = obj.parentNode; 217 return obj; 218} 219 220function add_value_to_select(selectbox,setval_id,setval_name) // add value to select box but don't select it 221{ 222 for ( var i = 0; i < selectbox.options.length; i++ ) 223 { 224 if ( selectbox.options[i].value == setval_id ) 225 { 226 //selectbox.options[i].selected = true; 227 return; 228 } 229 } 230 selectbox.options[selectbox.options.length] = new Option(setval_name, setval_id, false, false); // last arg is selected (t/f) 231} 232 233function set_select_value(selectbox,setval_id,setval_name) // add value to select box if doesn't exist and select it 234{ 235 for ( var i = 0; i < selectbox.options.length; i++ ) 236 { 237 if ( selectbox.options[i].value == setval_id ) 238 { 239 selectbox.options[i].selected = true; 240 return; 241 } 242 } 243 selectbox.options[selectbox.options.length] = new Option(setval_name, setval_id, false, true); // last arg is selected (t/f) 244 //alert("value " + setval + " is not in the dropdown list yet"); 245} 246 247function open_help_video(containerid,videoid) 248{ 249 var setstr = ""; 250 if(videoid.indexOf(',') > 0) 251 { 252 setstr += "<table cellspacing=8 cellpadding=2>"; 253 videoid_list = videoid.split(','); 254 for(var vh=0; vh<videoid_list.length; vh++) 255 { 256 var videoid_parts = videoid_list[vh].split(':'); 257 var current_videoid = videoid_parts[0]; 258 var video_title = "Video #" + (vh + 1); 259 if(videoid_parts.length > 1) 260 { 261 video_title = videoid_parts[1]; 262 } 263 setstr += "<tr>"; 264 setstr += "<td style='border:solid 1px #777777; width:240px; cursor:pointer; font-size:14px; color:#004400' align='left' bgcolor='#ccccdd' onmouseover='this.bgColor = \"#eeeef8\"' onmouseout='this.bgColor = \"#ccccdd\"' onclick='open_help_video(\"" + containerid + "\",\"" + current_videoid + "\")'>"; 265 //setstr += (vh + 1) + ")"; 266 setstr += "<table><tr><td valign='middle'><img src='/cp/images/video_camera.png' border='0' /></td>"; 267 setstr += "<td valign='middle' style='font-size:14px; color:#004400'>"; 268 setstr += " Watch \"" + video_title + "\""; 269 setstr += "</td></tr></table>"; 270 271 setstr += "</td>"; 272 setstr += "</tr>"; 273 } 274 setstr += "</table>"; 275 } 276 else 277 { 278 setstr += "<table width='100%'><tr><td width='100%' align='center'><iframe allowfullscreen=\"\" frameborder=\"0\" height=\"315\" src=\"//www.youtube.com/embed/" + videoid + "\" width=\"560\"></iframe></td></tr></table>"; 279 } 280 auto_reset_content_when_closed = true; 281 open_floating_window(" ",setstr,"main_area"); 282 //document.getElementById(containerid).innerHTML = setstr; 283} 284 285 286/******* Help Stuff */ 287 288function cp_page_help_edit(action) 289{ 290 // Action can be: 291 // enable - The edit button has been clicked, so display the edit controls and set up variables 292 // save - submit the new cp-page-help string to the server for save 293 // cancel - cancel 294 295 if (action=='init') 296 { 297 window.cp_page_help_edit_mode = false;
298 } else 299 if (action=='enable') 300 { 301 window.cp_page_help_edit_mode = true; 302 window.cp_page_help_edit_data = undefined; 303 } else 304 if (action=='save' && typeof window.page_area !== 'undefined') 305 { 306 new_data = cp_page_help_array_to_str(window.cp_page_help_edit_data); 307 308 var ajax_data = { 309 cmd: "cp_page_help_update", 310 data: new_data, 311 area: window.page_area 312 }; 313 314 $.ajax({ 315 type: 'POST', 316 async: false, 317 url: '/ajax_query/', 318 data: ajax_data 319 }) 320 .done(function(response) 321 { 322 // console.log("done"); 323 }) 324 .fail(function(error) 325 { 326 console.log('Failed: ' + error); 327 }) 328 .always(function(message) 329 { 330 }); 331 332 } else 333 if (action=='cancel') 334 { 335 window.cp_page_help_edit_mode = false; 336 window.cp_page_help_edit_data = []; 337 } 338} 339 340function cp_page_help_str_to_array(data) 341{ 342 if (data == "") 343 return []; 344 345 var array_data = []; 346 var item_count = 0; 347 var split_items = []; 348 349 if (data.indexOf(',') === -1) 350 split_items[0] = data; 351 else 352 split_items = data.split(','); 353 354 355 split_items.forEach(function(item){ 356 item_parts = []; 357 358 if (item.indexOf(":") === -1) 359 item_parts[0] = item; 360 else 361 item_parts = item.split(':'); 362 363 item_data = item_parts[0]; 364 item_data_raw = item_data; 365 if (item_parts.length > 1) 366 item_title = item_parts[1]; 367 else 368 item_title = 'Item ' + ((item_count*1)+1); 369 370 if (item_data.match(/(kb_search_)/)) 371 { 372 item_type = 'kb_search'; 373 item_data = item_data.replace(/kb_search_/,""); 374 } else 375 if (item_data.match(/(kb_id_)/)) 376 { 377 item_type = 'kb_id'; 378 item_data = item_data.replace(/kb_id_/,""); 379 } else 380 if (item_data.match(/zendesk/)) 381 { 382 item_type = "zendesk"; 383 item_data = "https://dumpsterrentalsystems.zendesk.com/hc/en-us/"; 384 } else 385 { 386 item_type = 'youtube'; 387 } 388 389 array_data[item_count] = {title: item_title, data: item_data, data_raw: item_data_raw, type:item_type}; 390 item_count++; 391 }); 392 393 return array_data; 394} 395 396function cp_page_help_array_to_str(data) 397{ 398 var str_data = ""; 399 var total_count = data.length; 400 var count = 0; 401 402 data.forEach(function(data_item){ 403 if (!data_item['data_raw'].match(/zendesk/)) 404 { 405 str_data += `${data_item['data_raw']}:${data_item['title']}`; 406 if (count < (total_count-1)) 407 str_data += ","; 408 } 409 count++; 410 }); 411 412 return str_data; 413} 414 415function cp_page_help_row_action(action, id, args) 416{ 417 // console.log(id+": "+action); 418 419 if (action=="up" && id > 0) 420 { 421 temp = window.cp_page_help_edit_data[id-1]; 422 window.cp_page_help_edit_data[id-1] = window.cp_page_help_edit_data[id]; 423 window.cp_page_help_edit_data[id] = temp; 424 } else 425 if (action=="down" && id < (window.cp_page_help_edit_data.length-1)) 426 { 427 temp = window.cp_page_help_edit_data[id+1]; 428 window.cp_page_help_edit_data[id+1] = window.cp_page_help_edit_data[id]; 429 window.cp_page_help_edit_data[id] = temp; 430 } else 431 if (action=="trash") 432 { 433 if(confirm(`Are you sure you want to delete this item?\n"${window.cp_page_help_edit_data[id]['title']}?"\n(This won't be final until you click save)`)) 434 window.cp_page_help_edit_data.splice(id,1); 435 } else 436 if (action=="add") 437 { 438 row_type = $(`#new_row_type`).val(); 439 row_title = $(`#new_row_title`).val(); 440 row_data = $(`#new_row_data`).val(); 441 row_industries = $(`#new_row_industries`).val(); 442 443 if (row_industries != '') 444 { 445 row_industries = row_industries.toLowerCase(); 446 row_title += " (product " + row_industries.replace(',',' ') + ")"; 447 console.log('present'); 448 } else 449 { 450 console.log('empty'); 451 } 452 453 if (row_type == 'kb_search') 454 raw_pre = "kb_search_"; 455 else if (row_type == 'kb_id') 456 raw_pre = "kb_id_"; 457 else 458 raw_pre = ''; 459 460 row_data_raw = raw_pre+row_data; 461 462 window.cp_page_help_edit_data[(window.cp_page_help_edit_data.length)] = { 463 type: row_type, 464 title: row_title, 465 data: row_data, 466 data_raw: row_data_raw 467 }; 468 } else 469 { 470 // console.log ('limit'); 471 return; 472 } 473 // console.log("args:"); 474 // console.log(args); 475 open_cp_page_help_content(args['containerid'],args['content_data'],args['header'],args['back'],args['show_edit']); 476} 477 478function open_cp_page_help_content(containerid,content_data,header,back="", show_edit="") 479{ 480 header_display = header; 481 482 // console.log(content_data); 483 484 if (typeof window.cp_page_help_edit_mode === 'undefined') 485 { 486 cp_page_help_edit('init'); 487 var cp_help_data = cp_page_help_str_to_array(content_data); 488 } else 489 if (window.cp_page_help_edit_mode === true) 490 { 491 if (typeof window.cp_page_help_edit_data === 'undefined' || window.cp_page_help_edit_data.length === '
491init') 492 window.cp_page_help_edit_data = cp_page_help_str_to_array(content_data); 493 494 var cp_help_data = window.cp_page_help_edit_data; 495 } else 496 { 497 var cp_help_data = cp_page_help_str_to_array(content_data); 498 } 499 500 // console.log('cp_help_data:', cp_help_data); 501 502 var output = ""; 503 504 if (cp_help_data.length > 1 || cp_help_data.length == 0 || window.cp_page_help_edit_mode === true || content_data.match(/zendesk/)) 505 { 506 // Multiple Items Listing 507 if (window.cp_page_help_edit_mode === true) 508 { 509 var cp_page_help_row_template = `<tr><td>ICON TITLE</td><td class='text-right'>UP DOWN TRASH</td></tr>`; 510 var cp_page_help_row_template_zendesk = cp_page_help_row_template; 511 } else 512 { 513 var cp_page_help_row_template_zendesk = `<tr><td class='zendesk_link'>ICON <a href='LINK' target='_blank'>TITLE</a></td><td> </td></tr>`; 514 var cp_page_help_row_template = `<tr><td LINK>ICON TITLE</td><td class='text-right'>UP DOWN TRASH</td></tr>`; 515 // var cp_page_help_row_template = `<tr><td LINK>ICON TITLE</td></tr>`; 516 } 517 output += `<table class='table table-striped table-hover cp_page_help_table'>`; 518 519 cp_help_data.forEach(function(data_item, key){ 520 521 if (!window.lv) 522 display_title = data_item['title'].replace(/\(products?\s*?([^\)]*)\)/,""); 523 else 524 display_title = data_item['title']; 525 526 // Don't display row if it's not the right industry (unless it's a level 12) 527 if (data_item['title'].match(/\(product/) && !window.lv) 528 { 529 row_industries = data_item['title'].match(/\(products?\s*?([^\)]*)\)/); 530 if (!row_industries[1].match(window.my_industry)) 531 return; 532 } 533 534 if (data_item['type'].match(/kb/)) 535 data_icon = `<i class='fal fa-fw fa-file-alt' style='font-size: 20px;'></i>`; 536 else 537 if (data_item['type'].match(/zendesk/)) 538 data_icon = `<i class="fas fa-fw fa-globe-americas" style='font-size: 20px;'></i>`; 539 else 540 data_icon = `<i class='fal fa-fw fa-video' style='font-size: 20px;'></i>`; 541 542 if (window.cp_page_help_edit_mode === true && !data_item['type'].match(/zendesk/)) 543 { 544 args = `{containerid: "${containerid}", content_data: "${content_data}", header: "${header}", back: "${back}", show_edit: "${show_edit}"}`; 545 data_link = ""; 546 button_up = `<button class='btn btn-xs btn-default cp_page_help_row_button' type='button' onclick='cp_page_help_row_action("up",${key}, ${args});'><i class="far fa-arrow-alt-up fa-fw"></i></button>`; 547 button_down = `<button class='btn btn-xs btn-default cp_page_help_row_button' type='button' onclick='cp_page_help_row_action("down",${key}, ${args});'><i class="far fa-arrow-alt-down fa-fw"></i></button>`; 548 button_trash = `<button class='btn btn-xs btn-default cp_page_help_row_button' type='button' onclick='cp_page_help_row_action("trash",${key}, ${args});'><i class="fal fa-trash-alt fa-fw"></i></button>`; 549 row_template = cp_page_help_row_template; 550 } else 551 if (data_item['type'].match(/zendesk/)) 552 { 553 data_link = data_item['data']; 554 button_up = ""; 555 button_down = ""; 556 button_trash = ""; 557 row_template = cp_page_help_row_template_zendesk; 558 } else 559 { 560 data_link = `onclick='open_cp_page_help_content("${containerid}", "${data_item['data_raw']}:${display_title}", "${header}", "${content_data}", "${show_edit}")'`; 561 button_up = ""; 562 button_down = ""; 563 button_trash = ""; 564 row_template = cp_page_help_row_template; 565 } 566 567 if (window.cp_page_help_edit_mode === false || (window.cp_page_help_edit_mode === true && !data_item['type'].match(/zendesk/))) 568 output += row_template.replace(/LINK/g,data_link).replace(/ICON/g,data_icon).replace(/TITLE/g,display_title).replace(/UP/g,button_up).replace(/DOWN/g,button_down).replace(/TRASH/g,button_trash); 569 570 }); 571 572 if (window.cp_page_help_edit_mode === true) 573 { 574 args = `{containerid: "${containerid}", content_data: "${content_data}", header: "${header}", back: "${back}", show_edit: "${show_edit}"}`; 575 output += `<tr><td class='bg-info'> 576 <div class='form-group col-xs-12 col-md-3'> 577 <label for='type'>Content Type</label> 578 <select class='form-control' id="new_row_type" name="type"> 579 <option value="video" selected>Youtube Video</option> 580 <option value="kb_search">Knowledge Base Search</option> 581 <option value="kb_id">Knowledge Base ID</option> 582 </select> 583 </div> 584 <div class='form-group col-xs-12 col-md-3'> 585 <label for='title'>Title</label> 586 <input class='form-control' type='text' id='new_row_title' name='title'> 587 </div> 588 <div class='form-group col-xs-12 col-md-3'> 589 <label for='data'>Data</label> 590 <input class='form-control' type='text' id='new_row_data' name='data'> 591 </div> 592 <div class='form-group col-xs-12 col-md-3'> 593 <label for='data'>Industries <button tabindex="-1" type="button" class="btn btn-default btn-xs" data-toggle="tooltip" data-placement="top" title="List one or more industries separated with spaces, or leave blank to be visible for all industries.">?</button></label> 594 <input class='form-control' type='text' id='new_row_industries' name='industries' placeholder='eg: "bounce dumpster fec"'> 595 </div> 596 </td><td class='text-right bg-info' style='vertical-align: middle;'><button style='margin-right: 5px;' class='btn btn-success' type='button' onclick='cp_page_help_row_action("add",0, ${args});'>Add</button></td>`; 597 window.setTimeout(function () {$('[data-toggle="tooltip"]').tooltip();}); 598 } 599 output += `</table>`; 600 } else 601 { 602 // Single Content Item 603 if (back.indexOf(',') > 0) 604 back_button = `<h4><a href='#' onclick='open_cp_page_help_content("${containerid}","${back}","${header}","","${show_edit}");'><i class="far fa-backward"></i> Back</a></h4>`; 605 else 606 back_button = ''; 607 608 if (cp_help_data[0]['type'].match(/(kb_(search|id))/)) 609 { 610 var ajax_data = { 611 cmd: "ers_help", 612 mode: "search", 613 search: cp_help_data[0]['data_raw'].replace(/kb_search_/,"").replace(/^kb_id_/,"id:") 614 }; 615 616 $.ajax({ 617 type: 'POST', 618 async: false, 619 url: '/ajax_query/', 620 data: ajax_data 621 }) 622 .done(function(response) 623 { 624 adj_response = decodeQueryString(response);
625 output += back_button + "<div class='eh_sections_container'>" + adj_response['content'] + "</div>"; 626 }) 627 .fail(function(error) 628 { 629 console.log('Failed: ' + error); 630 }) 631 .always(function(message) 632 { 633 }); 634 } else 635 { 636 if (cp_help_data[0]['data'].match(/\?/)) 637 d = "&"; 638 else 639 d = "?"; 640 641 data_link = "//www.youtube.com/embed/" + cp_help_data[0]['data'] + d + 'autoplay=1'; 642 // data_link = "http://youtu.be/" + cp_help_data[0]['data']; 643 644 output += back_button + `<div class='cp_page_help_video_wrapper'><iframe allowfullscreen="" allow='autoplay' frameborder="0" class="cp_page_help_video_iframe" src="${data_link}"></iframe></div>`; 645 } 646 647 if (!window.lv) 648 display_title = cp_help_data[0]['title'].replace(/\(products?\s*?([^\)]*)\)/,""); 649 else 650 display_title = cp_help_data[0]['title']; 651 652 header_display = header + " - " + display_title; 653 } 654 655 edit_button = ""; 656 if (show_edit == "yes" && back=="") 657 { 658 if (window.cp_page_help_edit_mode === true) 659 { 660 edit_button += `<button id='button_cp_help_Save' class='btn btn-sm btn-success' style='margin-left: 15px;' type='button' onclick='cp_page_help_edit("save"); location.reload();'>Save</button> `; 661 edit_button += `<button id='button_cp_help_Cancel' class='btn btn-sm btn-danger' style='margin-left: 15px;' type='button' onclick='cp_page_help_edit("cancel"); open_cp_page_help_content("${containerid}","${content_data}","${header}","","yes");'>Cancel</button>`; 662 edit_button += `<a target='_blank' class='btn btn-sm btn-default' style='margin-left:15px; type='button' href='${window.appConfig.filesURL}/cp/upload/default_dev/HelpHelp.mp4'>Help Help</a>`; 663 } else 664 { 665 edit_button = `<button id='button_cp_help_Edit' class='btn btn-sm btn-warning' style='margin-left: 15px;' type='button' onclick='cp_page_help_edit("enable"); open_cp_page_help_content("${containerid}","${content_data}","${header}","","yes");'>Edit</button>`; 666 } 667 } 668 669 auto_reset_content_when_closed = true; 670 open_floating_window("<h3>Control Panel Help: " + header_display + edit_button + "</h3>",output,"main_area",'90vw'); 671} 672 673/******* End Help Stuff */ 674 675function advance_time(t,add) 676{ 677 var t_mins = t % 100; 678 var t_hours = t - t_mins; 679 var add_mins = add % 100; 680 var add_hours = add - add_mins; 681 682 var set_hours = t_hours + add_hours; 683 var set_mins = t_mins + add_mins; 684 if(set_mins >= 60) 685 { 686 set_hours += 100; 687 set_mins -= 60; 688 } 689 690 return (set_hours * 1 + set_mins * 1); 691} 692function display_time(t) 693{ 694 if(typeof(t)=="String" && t.indexOf(':') > 0) { 695 t = t.replace(/\:/ig,''); 696 } 697 698 var t_mins = t % 100; 699 var t_hours = (t - t_mins) / 100; 700 701 if(t_mins < 10) t_mins = "0" + (t_mins * 1); 702 if(t_hours==0) { t_hours = 12; t_ampm = "am"; } 703 else if(t_hours==24) { t_hours = 12; t_ampm = "am"; } 704 else if(t_hours > 24) { t_hours -= 24; t_ampm = "am"; } 705 else if(t_hours==12) { t_ampm = "pm"; } 706 else if(t_hours > 12) { t_hours -= 12; t_ampm = "pm"; } 707 else { t_ampm = "am"; } 708 709 return t_hours + ":" + t_mins + t_ampm; 710} 711function unescape_decode(dstr) 712{ 713 return unescape(dstr.replace(/\+/ig,' ')); 714} 715function ersCurrentUnixTimestamp() 716{ 717 return Math.floor(Date.now() / 1000); 718} 719function ersCurrentDateTime(joined) 720{ 721 var d = new Date(); 722 723 var year = d.getFullYear(); 724 var month = (d.getMonth() + 1); 725 var day = d.getDate(); 726 var hour = d.getHours(); 727 var minute = d.getMinutes(); 728 var second = d.getSeconds(); 729 730 month = month.toString().ersPaddingLeft("00"); 731 day = day.toString().ersPaddingLeft("00"); 732 hour = hour.toString().ersPaddingLeft("00"); 733 minute = minute.toString().ersPaddingLeft("00"); 734 second = second.toString().ersPaddingLeft("00"); 735 736 if (joined) 737 { 738 return year + "" + month + "" + day + "" + hour + "" + minute + "" + second; 739 } 740 else 741 { 742 return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second; 743 } 744} 745function ersDateStringFromDate(d) 746{ 747 var year = d.getFullYear(); 748 var month = (d.getMonth() + 1); 749 var day = d.getDate(); 750 751 month = month.toString().ersPaddingLeft("00"); 752 day = day.toString().ersPaddingLeft("00"); 753 754 return year + "-" + month + "-" + day; 755} 756function ersIsValidDate(date_str, boolean) 757{ 758 var dashed = ersVS(date_str).split("-"); 759 var slashed = ersVS(date_str).split("/"); 760 var dparts = []; 761 var sep = ""; 762 763 if (dashed.length >= 3) 764 { 765 sep = "-"; 766 dparts = dashed; 767 } 768 else if (slashed.length >= 3) 769 { 770 sep = "/"; 771 dparts = slashed; 772 } 773 774 if (dparts.length < 3) 775 { 776 return false;
777 } 778 779 var d0 = dparts[0]; 780 var d1 = dparts[1]; 781 var d2 = dparts[2]; 782 783 if (isNaN(d0) || d0*1<1 || isNaN(d1) || d1*1<1 || isNaN(d2) || d2*1<1) 784 { 785 return false; 786 } 787 788 var l0 = d0.length; 789 var l1 = d1.length; 790 var l2 = d2.length; 791 792 var is_valid = false; 793 794 switch (sep) 795 { 796 case "-": 797 798 is_valid = (l0!=4 || l1!=2 || l1!=2)?false:true; 799 break; 800 801 case "/": 802 803 is_valid = (l0<1 || l0>2 || l1<1 || l1>2 || l2!=4)?false:true; 804 break; 805 806 default: 807 break; 808 } 809 810 if (boolean) 811 { 812 return is_valid; 813 } 814 815 return { 816 'parts': dparts, 817 'seperator': sep, 818 'valid': is_valid 819 } 820} 821function ersTSFromDate(date_str) 822{ 823 var is_valid = ersIsValidDate(date_str); 824 825 if (!is_valid || !is_valid.valid) 826 { 827 return 0; 828 } 829 830 var dparts = is_valid.parts; 831 832 var d = new Date(); 833 d.setHours(0); 834 d.setMinutes(0); 835 d.setSeconds(0); 836 d.setMilliseconds(0); 837 838 switch (is_valid.seperator) 839 { 840 case "-": 841 842 d.setYear(dparts[0] * 1); 843 d.setMonth((dparts[1] * 1) - 1); 844 d.setDate(dparts[2] * 1); 845 break; 846 847 case "/": 848 849 d.setYear(dparts[2] * 1); 850 d.setMonth((dparts[0] * 1) - 1); 851 d.setDate((dparts[1] * 1)); 852 break; 853 854 default: 855 856 return 0; 857 } 858 859 return d.valueOf(); 860} 861 862function ersDurationFromSeconds(seconds, simplified) 863{ 864 var sec = ersVI(seconds); 865 var seconds_ts = (sec % 60); 866 var total_mins_ts = ((sec - seconds_ts) / 60); 867 var mins_ts = (total_mins_ts % 60); 868 var hours_ts = ((total_mins_ts - mins_ts) / 60); 869 870 var time_str = ""; 871 if (hours_ts >= 1) 872 { 873 if (simplified) 874 { 875 if ((mins_ts >= 20) && (mins_ts <= 40)) 876 { 877 hours_ts += 0.5; 878 } 879 else if (mins_ts > 40) 880 { 881 hours_ts += 1; 882 } 883 } 884 885 if (hours_ts > 1) 886 { 887 time_str += hours_ts + " hrs "; 888 } 889 else if (hours_ts == 1) 890 { 891 time_str += hours_ts + " hr "; 892 } 893 894 if (simplified) 895 { 896 return time_str.trim(); 897 } 898 } 899 900 if (mins_ts >= 1) 901 { 902 if (simplified) 903 { 904 if ((seconds_ts >= 20) && (seconds_ts <= 40)) 905 { 906 mins_ts += 0.5; 907 } 908 else if (seconds_ts > 40) 909 { 910 mins_ts += 1; 911 } 912 } 913 914 if (mins_ts > 1) 915 { 916 time_str += mins_ts + " mins "; 917 } 918 else if (mins_ts == 1) 919 { 920 time_str += mins_ts + " min "; 921 } 922 923 if (simplified) 924 { 925 return time_str.trim(); 926 } 927 } 928 929 if (seconds_ts > 1) 930 { 931 time_str += seconds_ts + " secs"; 932 } 933 else if (seconds_ts == 1) 934 { 935 time_str += seconds_ts + " sec"; 936 } 937 938 return time_str; 939} 940 941function display_date(d) 942{ 943 var d_parts = d.split("-"); 944 if(d_parts.length > 2) 945 { 946 return d_parts[1] + "/" + d_parts[2] + "/" + d_parts[0]; 947 } 948 else return d; 949} 950 951function change_date_by_days(dt,mod) 952{ 953 var dt_parts = dt.split("-"); 954 var actualDate = new Date(dt_parts[1] + "/" + dt_parts[2] + "/" + dt_parts[0]); // convert to actual date 955 var newDate = new Date(actualDate.getFullYear(), actualDate.getMonth(), actualDate.getDate()+mod); // create new increased date 956 var newYear = newDate.getFullYear(); 957 var newMonth = (newDate.getMonth() + 1); 958 var newDate = newDate.getDate(); 959 var datestr = newYear + "-"; 960 if(newMonth < 10) datestr += "0" + newMonth; else datestr += newMonth; 961 datestr += "-"; 962 if(newDate < 10) datestr += "0" + newDate; else datestr += newDate; 963 964 return datestr; 965} 966 967function advance_date_by_day(dt) 968{ 969 return change_date_by_days(dt,1); 970} 971 972function reverse_date_by_day(dt) 973{ 974 return change_date_by_days(dt,-1); 975} 976 977function enableSelection(element) 978{ 979 element.onselectstart=null; 980 element.onmousedown=null; 981} 982 983function disableSelection(element) 984{ 985 element.onselectstart=function(){return false}; 986 element.onmousedown=function(){return false}; 987} 988 989function element_exists(elementid) 990{ 991 var element = document.getElementById(elementid); 992 return typeof element !== "undefined" && element !== null; 993} 994 995function noenter(e) 996{ 997 var key; 998 if(window.event) 999 key = window.event.keyCode; //IE 1000 else 1001 key = e.which; //firefox 1002 if(key == 13) 1003 return false; 1004 else 1005 return true; 1006} 1007 1008function trim_string(str) 1009{ 1010 if( String.prototype.trim ) return str.trim(); 1011 return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); 1012} 1013 1014//****** blurOnEnter ***************************************** 1015// This function blurs a field on hitting enter. 1016// 1017// element -- is the element that needs to be blurred 1018// e -- is the event (sometimes e = element). 1019// 1020// Added by AMC October 7, 2014 1021//************************************************************ 1022function blurOnEnter(element, e) 1023{ 1024 var key; 1025 if(window.event) 1026 key = window.event.keyCode; //IE 1027 else 1028 key = e.which; //firefox 1029 if(key == 13) 1030 { 1031 element.blur(); 1032 } 1033} 1034 1035//****** updateNumber **************************************** 1036// This function is used with a dropdown box that displays 1037// a list of numbers for item quantity selection. 1038// if "other" is chosen, it will convert the dropdown box to 1039// a basic text input box. 1040// 1041// element -- typically "this" 1042// length -- how long the dropdown can be (e.g. 100) 1043// avail -- the maximum number of items available 1044// (could be greater or less than length). 1045// selection -- sets the pre-selected value 1046// can_overbook -- a boolean, whether or not they have permission to overbook. 1047// 1048// Added by AMC October 2, 2014 1049//************************************************************ 1050function updateNumber(element, length, avail, selection, can_overbook, update_onchange, qty_onchange) 1051{ 1052 if (element.value=='other') 1053 { 1054 var newElement = document.createElement('input'); 1055 newElement.name = element.name;
1056 newElement.id = element.id; 1057 newElement.type='number'; 1058 newElement.value=''; 1059 newElement.size='8'; 1060 newElement.style.width='60px'; 1061 newElement.min='0'; 1062 newElement.style.display='block'; 1063 newElement.placeholder= avail + ' avail'; //This will only work in HTML 5 1064 newElement.onblur = function(event){ updateSelect(this, length, avail, selection, can_overbook, update_onchange, qty_onchange); }; 1065 newElement.onkeyup = function(event) { blurOnEnter(newElement, event); }; 1066 newElement.onkeypress = function(event){ return noenter(event); }; 1067 1068 //alert(element.parentNode.name); 1069 element.parentNode.replaceChild(newElement, element); 1070 1071 //Handle iOS differently. 1072 var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent); 1073 if (deviceIsIOS && targetElement.setSelectionRange) //Turns out there is an error (or feature) in how mobile safari 1074 { // handles on focus events, and basically they can't be triggered 1075 length = newElement.value.length; // programattically. So this kind of gets around that. 1076 newElement.setSelectionRange(length, length); // It won't "lose" focus and revert to a list, but it doesn't get focus 1077 } 1078 else 1079 { 1080 newElement.parentNode.focus(); //This is only needed for firefox, which is dopey. AMC December 2, 2014. 1081 newElement.focus(); 1082 } 1083 1084 //Create an "update" link (this a dummy, to encourage them to click). 1085 if (update_onchange) 1086 { 1087 var b = document.createElement('button'); 1088 var t = document.createTextNode('update qty'); 1089 b.appendChild(t); 1090 newElement.parentNode.appendChild(b); 1091 } 1092 } 1093 else 1094 { 1095 if (update_onchange) 1096 qty_onchange(element); 1097 } 1098} 1099 1100//****** updateSelect **************************************** 1101// This function is a complement to updateNumber. It will 1102// revert an input text box back to a dropdown selection, 1103// if the text box is empty and the focus shifts. 1104// 1105// element -- typically "this" 1106// length -- how long the dropdown can be (e.g. 100) 1107// avail -- the maximum number of items available 1108// (could be greater or less than length). 1109// selection -- sets the pre-selected value 1110// can_overbook -- a boolean, whether or not they have permission to overbook. 1111// 1112// Added by AMC October 2, 2014 1113//************************************************************ 1114function updateSelect(element, length, avail, selection, can_overbook, update_onchange, qty_onchange) 1115{ 1116 //Here we do some validation: 1117 if (element.value != '') 1118 { 1119 v = element.value; 1120 if (v > avail) 1121 { 1122 if (can_overbook) 1123 { 1124 if(!confirm("This will cause an overbooking (max avail: "+avail+")\n Are you sure you wish to overbook?")) 1125 element.value = ""; 1126 } 1127 else 1128 { 1129 alert ("Maximum quantity available is " + avail); 1130 element.value = ""; 1131 } 1132 } 1133 if (update_onchange) 1134 qty_onchange(element); 1135 } 1136 1137 1138 if (element.value=='' && element.type=='number') 1139 { 1140 if (update_onchange) 1141 qty_onchange(element); 1142 var newElement = document.createElement('select'); 1143 newElement.name = element.name; 1144 newElement.id = element.id; 1145 //newElement.type='select'; 1146 newElement.onchange = function(event){ updateNumber(this, length, avail, selection, can_overbook, update_onchange, qty_onchange); }; 1147 1148 for (var i=0; i<=length; i++) 1149 { 1150 var opt = document.createElement('option'); 1151 opt.value = i; 1152 opt.text = i; 1153 if (i == selection) 1154 opt.selected = true; 1155 newElement.options.add(opt); 1156 } 1157 1158 var opt = document.createElement('option'); 1159 opt.value = 'other'; 1160 opt.text = '>'+length; 1161 newElement.options.add(opt); 1162 1163 1164 element.parentNode.replaceChild(newElement, element); 1165 } 1166} 1167 1168function decround(val, p) 1169{ 1170 if(typeof p === 'undefined' || +p === 0) return Math.round(val); 1171 val = +val; 1172 p = +p; 1173 if (isNaN(val) || !(typeof p === 'number' && p % 1 === 0)) return NaN; 1174 val = val.toString().split('e'); 1175 val = Math.round(+(val[0] + 'e' + (val[1] ? (+val[1] + p) : p))); 1176 val = val.toString().split('e'); 1177 return +(val[0] + 'e' + (val[1] ? (+val[1] - p) : -p)); 1178} 1179 1180function formatDollar(num) { 1181 var p = parseFloat(num).toFixed(2).split("."); 1182 return "$" + p[0].split("").reverse().reduce(function(acc, num, i, orig) { 1183 return num + (i && !(i % 3) ? "," : "") + acc; 1184 }, "") + "." + p[1]; 1185} 1186 1187blue_editor_button_arr = new Array(); 1188 1189(function() { 1190 "use strict"; 1191 1192 //UTILITIES// 1193 1194 window._UTIL = {}; 1195 1196 function base64_encode_safe(input) { 1197 /* Encodes input as base64 string in a URL-safe manner, e.g. void of "/", "+", and "=". */ 1198 /* Decode with base64_decode_safe($str). */ 1199 /* NOTE: since '=' padding is removed, it is not safe to append 1200 * multiple encoded strings generated by this method (you won't be able 1201 * to decode them). */
1202 return btoa(input) 1203 .replace(/=/g, '') 1204 .replace(/\+/g, '-') 1205 .replace(/\//g, '_'); 1206 } 1207 _UTIL.base64_encode_safe = base64_encode_safe; 1208 1209 function base64_decode_safe(input) { 1210 /* Decodes input generated by "base64_encode_safe()". */ 1211 return atob(input 1212 .replace(/=/g, '') 1213 .replace(/-/g, '+') 1214 .replace(/_/g, '/')); 1215 } 1216 _UTIL.base64_decode_safe = base64_decode_safe; 1217 1218 function object_to_query(object) { 1219 return "?"+Object.keys(object).map(function(key) { 1220 var safeKey = encodeURIComponent(key); 1221 var safeVal = encodeURIComponent(object[key]); 1222 return safeKey+"="+safeVal; 1223 }).join("&"); 1224 } 1225 _UTIL.object_to_query = object_to_query; 1226 1227 function query_to_object(query) { 1228 if( query.startsWith("?") ) 1229 query = query.slice(1); 1230 return query.split("&") 1231 .map(function(keyVal) { 1232 return keyVal.split("="); }) 1233 .reduce(function(acc, element, index) { 1234 var key = decodeURIComponent(element.shift()); 1235 var val = decodeURIComponent(element.shift()); 1236 acc[key] = val; 1237 return acc; }, {}); 1238 } 1239 _UTIL.query_to_object = query_to_object; 1240 1241 window.ERSPromise = (function() { 1242 //do done, fail, always 1243 function P() { 1244 this.doDone = function(){}; 1245 this.doFail = function(){}; 1246 this.doAlways = function(){}; 1247 }; 1248 P.prototype = { 1249 done : function(callback) { 1250 if( typeof callback !== "function" ) 1251 throw new TypeError("ERSPromise.prototype.done expects function as 1st parameter, found \""+typeof callback+"\""); 1252 this.doDone = callback; 1253 this.runIfDone(); 1254 return this; 1255 }, 1256 fail : function(callback) { 1257 if( typeof callback !== "function" ) 1258 throw new TypeError("ERSPromise.prototype.fail expects function as 1st parameter, found \""+typeof callback+"\""); 1259 this.doFail = callback; 1260 this.runIfDone(); 1261 return this; 1262 }, 1263 always : function(callback) { 1264 if( typeof callback !== "function" ) 1265 throw new TypeError("ERSPromise.prototype.always expects function as 1st parameter, found \""+typeof callback+"\""); 1266 this.doAlways = callback; 1267 this.runIfDone(); 1268 return this; 1269 }, 1270 setResponse: function(data, success) { 1271 this.response = data; 1272 this.isDone = true; 1273 this.error = !success; 1274 this.runIfDone(); 1275 }, 1276 runIfDone: function() { 1277 if( this.isDone ) { 1278 this.doAlways(this.response); 1279 if( this.error ) { 1280 this.doFail(this.response); 1281 } else { 1282 this.doDone(this.response); 1283 } 1284 } 1285 } 1286 1287 }; 1288 return P; 1289 })(); 1290 1291 function safe_decode(input) { 1292 if( input ) 1293 return JSON.parse(_UTIL.base64_decode_safe(input)); 1294 return ""; 1295 } 1296 _UTIL.safe_decode = safe_decode; 1297 1298 function safe_encode(input) { 1299 if( input ) 1300 return _UTIL.base64_encode_safe(JSON.stringify(input)); 1301 return ""; 1302 } 1303 _UTIL.safe_encode = safe_encode; 1304 1305})(); 1306 1307function decodeQueryString(str) { 1308 str = str.trim(); 1309 return str.split("&").map(function(keyvalString) { 1310 if( keyvalString.trim() ) 1311 return keyvalString.split("="); 1312 return false; 1313 }).filter(function(keyvalArray) { 1314 return keyvalArray !== false; 1315 }).reduce(function(acc,keyvalArray) { 1316 acc[unescape(keyvalArray[0])] = unescape(keyvalArray[1]); 1317 return acc; 1318 }, {}); 1319} 1320 1321window.E = (function() { 1322 1323 "use strict"; 1324 1325 function appendChildren(element, children) { 1326 (children||[]).forEach(function(child) { 1327 if( child ) element.appendChild(child); 1328 }); 1329 return element; 1330 } 1331 1332 function setAttributes(element, obj) { 1333 for( var key in obj ) 1334 if( typeof key === "string" && key !== "children" ) 1335 element[key] = obj[key]; 1336 return element; 1337 } 1338 1339 function newElement(tagname, attributes) { 1340 var elem = document.createElement(tagname); 1341 if( elem ) { 1342 setAttributes(elem, attributes); 1343 appendChildren(elem, attributes.children); 1344 return elem; 1345 } 1346 return null; 1347 }; 1348 1349 return function validator(tagname, attributes) { 1350 if( typeof tagname !== "string" ) 1351 throw new TypeError("newElement: 1st arg \"tagname\" should be \"string\", found \""+typeof tagname+"\"."); 1352 if( ! attributes instanceof Object ) 1353 throw new TypeError("newElement: 1st arg \"tagname\" should be instance of \"array\", found \""+typeof tagname+"\"."); 1354 return newElement(tagname, attributes); 1355 } 1356 1357})(); 1358 1359window.in_appcp = function(callback) 1360{ 1361 var result = location.pathname.startsWith("/cp"); 1362 if( callback instanceof Function ) callback( result ); 1363 return result; 1364}; 1365 1366function err(msg) { throw msg; } 1367 1368window.do_ajax_query = (function() 1369{ 1370 function paramsToString(params) 1371 { 1372 return Object.keys(params).map(function(key) { 1373 return encodeURIComponent(key) + "=" + encodeURIComponent(params[key]); 1374 }).join("&"); 1375 } 1376 1377 return function(params, callback, end_point) 1378 { 1379 if (!end_point) end_point = "/ajax_query/"; 1380 1381 var requestStr = paramsToString(params); 1382 var xhr = new XMLHttpRequest(); 1383 xhr.open("POST", end_point, true); 1384 xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 1385 xhr.onload = function() { 1386 var response = decodeQueryString(xhr.responseText); 1387 callback(response); 1388 }; 1389 xhr.send(requestStr); 1390 }; 1391 1392}()); 1393 1394(function() { 1395 var modal_container = null; 1396 1397 function closeModal() 1398 { 1399 if( modal_container && modal_container.parentNode ) 1400 modal_container.parentNode.removeChild(modal_container); 1401 } 1402 window.closeModal = closeModal; 1403 1404 function createModal(contents, styles, can_clickout) { 1405 closeModal(); 1406 can_clickout = can_clickout !== false; 1407 styles = styles || {}; 1408 1409 var modal_content = document.createElement("span"); 1410 modal_content.style.borderRadius = "5px"; 1411 modal_content.style.backgroundColor = "#ddd"; 1412 modal_content.style.verticalAlign = "middle"; 1413 modal_content.style.display = "inline-block"; 1414 modal_content.style.padding = "1em"; 1415 modal_content.style.overflowX = "hidden"; 1416 modal_content.style.overflowY = "hidden"; 1417 modal_content.onclick = function(event) { 1418 event.stopPropagation(); 1419 }; 1420 1421 if( contents instanceof HTMLElement ) 1422 modal_content.appendChild(contents); 1423 if( typeof contents === "string" ) 1424 modal_content.appendChild(document.createTextNode(contents)); 1425 1426 var modal_centerizer = document.createElement("span"); 1427 modal_centerizer.style.verticalAlign = "middle"; 1428 modal_centerizer.style.display = "inline-block"; 1429 modal_centerizer.style.height = "100%"; 1430 modal_centerizer.style.width = 0; 1431 1432 modal_container = document.createElement("div"); 1433 modal_container.appendChild(modal_centerizer); 1434 modal_container.appendChild(modal_content); 1435 modal_container.style.backgroundColor = "rgba(0,0,0,0.9)"; 1436 modal_container.style.textAlign = "center"; 1437 modal_container.style.position = "fixed"; 1438 modal_container.style.height = "100%"; 1439 modal_container.style.zIndex = 12000; 1440 modal_container.style.width = "100%"; 1441 modal_container.style.left = 0; 1442 modal_container.style.top = 0; 1443 modal_container.style.overflow = "scroll"; 1444 modal_container.addEventListener("click", function(event) { 1445 event.stopPropagation(); 1446 if( can_clickout ) { 1447 modal_container.parentNode.removeChild(modal_container); 1448 } 1449 });
1450 Object.keys(styles).forEach(function(style) { 1451 modal_content.style[style] = styles[style]; 1452 }); 1453 document.body.appendChild(modal_container); 1454 return modal_container; 1455 } 1456 window.createModal = createModal; 1457 1458 function modalPrompt(question, callback) { 1459 callback = callback instanceof Function ? callback : function(){}; 1460 1461 var container_node = document.createElement("div"); 1462 1463 var question_node = document.createElement("h4"); 1464 question_node.innerHTML = question; 1465 container_node.appendChild(question_node); 1466 1467 var input_node = document.createElement("input"); 1468 input_node.style.borderRadius = "5px"; 1469 input_node.style.textIndent = "2em"; 1470 input_node.style.border = "#ccc solid 1px"; 1471 input_node.style.height = "3em"; 1472 input_node.style.width = "90%"; 1473 input_node.type = "text"; 1474 1475 container_node.appendChild(document.createElement("br")); 1476 container_node.appendChild(input_node); 1477 container_node.appendChild(document.createElement("br")); 1478 container_node.appendChild(document.createElement("br")); 1479 1480 var button_no = document.createElement("button"); 1481 button_no.className = "btn btn-info"; 1482 button_no.innerHTML = "cancel"; 1483 container_node.appendChild(button_no); 1484 button_no.onclick = function() { 1485 closeModal(); 1486 callback(false); 1487 }; 1488 1489 var button_ok = document.createElement("button"); 1490 button_ok.className = "btn btn-success"; 1491 button_ok.innerHTML = "OK"; 1492 container_node.appendChild(button_ok); 1493 button_ok.onclick = function() { 1494 closeModal(); 1495 callback(input_node.value); 1496 }; 1497 1498 var modal_container = createModal(container_node, {'minWidth':'60%'}, true); 1499 modal_container.addEventListener('click', function(event) { 1500 event.stopPropagation(); 1501 closeModal(); 1502 callback(false); 1503 }); 1504 } 1505 window.modalPrompt = modalPrompt; 1506 1507 function modalAlert(msg, callback) { 1508 callback = callback instanceof Function ? callback : function(){}; 1509 1510 var container_node = document.createElement("div"); 1511 1512 var msg_node = document.createElement("div"); 1513 msg_node.innerHTML = msg; 1514 container_node.appendChild(msg_node); 1515 1516 var button_ok = document.createElement("button"); 1517 button_ok.className = "btn btn-md"; 1518 button_ok.innerHTML = "done"; 1519 container_node.appendChild(button_ok); 1520 button_ok.onclick = function() { 1521 closeModal(); 1522 callback(); 1523 }; 1524 1525 createModal(container_node, {'minWidth':'60%'}, true); 1526 } 1527 window.modalAlert = modalAlert; 1528 1529})(); 1530 1531/** 1532 * For accordian icon toggling 1533 */ 1534function toggleChevron(e) 1535{ 1536 $(e.target) 1537 .prev('.panel-heading') 1538 .find("i.indicator") 1539 .toggleClass('glyphicon-chevron-down glyphicon-chevron-up'); 1540} 1541 1542(function() 1543{ 1544 var get_cache = null; 1545 var cookie_cache = null; 1546 1547 if ( ! ( "_GET" in window ) ) 1548 { 1549 Object.defineProperties( window, { 1550 "_GET": { 1551 get : function() { 1552 if (get_cache === null) { 1553 1554 return ( get_cache = location.search 1555 .slice(1) 1556 .split("&") 1557 .map(function(e) { 1558 return e.split("="); 1559 }) 1560 .reduce(function(acc,el) { 1561 acc[el[0]] = typeof el[1] !== "undefined" ? el[1] : null; 1562 return acc; 1563 }, {})); 1564 1565 } 1566 return get_cache; 1567 1568 } 1569 }, 1570 "_COOKIE": { 1571 1572 get : function() { 1573 if (cookie_cache === null) { 1574 1575 return ( cookie_cache = document.cookie 1576 .slice(1) 1577 .split("; ") 1578 .map(function(e) { 1579 return e.split("="); 1580 }) 1581 .reduce(function(acc,el) { 1582 acc[el[0]] = typeof el[1] !== "undefined" ? el[1] : null; 1583 return acc; 1584 }, {})); 1585 } 1586 return cookie_cache; 1587 } 1588 } 1589 }); 1590 } 1591})(); 1592 1593 1594function getvar( key, def ) 1595{ 1596 var val = _GET[key]; 1597 if (typeof val === "undefined" || val === null) 1598 { 1599 return def; 1600 } 1601 return val; 1602} 1603 1604 1605function cookievar( key, def ) 1606{ 1607 var val = _COOKIE[key]; 1608 if (typeof val === "undefined" || val === null) 1609 { 1610 return def; 1611 } 1612 return val; 1613} 1614 1615function ersCBC(eid) // checkbox checked 1616{ 1617 var el = ersDE(eid); 1618 if (el && "checked" in el) 1619 { 1620 return el.checked; 1621 } 1622 1623 return false; 1624} 1625 1626function ersDE(eid) // document element 1627{ 1628 return document.getElementById(eid); 1629} 1630 1631function ersEP(eid) // element parent 1632{ 1633 var el = ersDE(eid); 1634 if (el) 1635 { 1636 return el.parentElement; 1637 } 1638 1639 return null; 1640} 1641
1642function ersDEBN(name, full_list) // document element(s) by name 1643{ 1644 var els = document.getElementsByName(name); 1645 1646 if (NodeList.prototype.isPrototypeOf(els) && (els.length > 0)) 1647 { 1648 if (full_list) 1649 { 1650 return els; 1651 } 1652 1653 return els[0]; 1654 } 1655 1656 return null; 1657} 1658 1659function ersDEBC(cls) // document elements by class name 1660{ 1661 return document.getElementsByClassName(cls); 1662} 1663 1664function ersElDisplay(el, display) 1665{ 1666 if (el) 1667 { 1668 el.style.display = display; 1669 } 1670} 1671 1672function ersElHTML(el, html) 1673{ 1674 if (el) 1675 { 1676 el.innerHTML = ersVS(html); 1677 } 1678} 1679function ersElOHTML(el, html) 1680{ 1681 if (el) 1682 { 1683 el.outerHTML = ersVS(html); 1684 } 1685} 1686 1687function ersElOpac(el, opacity) 1688{ 1689 if (el) 1690 { 1691 el.style.opacity = opacity; 1692 } 1693} 1694 1695function ersElPointerEvents(el, po) 1696{ 1697 if (el) 1698 { 1699 el.style.pointerEvents = po; 1700 } 1701} 1702 1703function ersElValue(el, value) 1704{ 1705 if (el) 1706 { 1707 el.value = value; 1708 } 1709} 1710 1711function ersElVisibility(el, vis) 1712{ 1713 if (el) 1714 { 1715 el.style.visibility = vis; 1716 } 1717} 1718 1719function ersElsByClass(cl) 1720{ 1721 return document.getElementsByClassName(cl); 1722} 1723 1724function ersEV(eid) // element value 1725{ 1726 var el = ersDE(eid); 1727 if (el) 1728 { 1729 if ("value" in el) 1730 { 1731 return ersVS(el.value); 1732 } 1733 1734 if (el.dataset && el.dataset.value) 1735 { 1736 return ersVS(el.dataset.value); 1737 } 1738 } 1739 1740 return ""; 1741} 1742 1743function ersFDE(iframe, eid) // iframe document element 1744{ 1745 if (iframe && "contentWindow" in iframe) 1746 { 1747 return iframe.contentWindow.document.getElementById(eid); 1748 } 1749 1750 return null; 1751} 1752 1753function ersJSON(str) 1754{ 1755 try 1756 { 1757 var o = JSON.parse(str); 1758 if (o && typeof o === "object" && o !== null) 1759 { 1760 return o; 1761 } 1762 } 1763 catch (e) 1764 { 1765 //console.log(e); 1766 } 1767 1768 return false; 1769} 1770 1771function ersObjectKeys(obj) 1772{ 1773 var keys = []; 1774 if ((obj !== null) && (obj instanceof Object)) 1775 { 1776 for (var k in obj) 1777 { 1778 keys.push(k); 1779 } 1780 } 1781 1782 return keys; 1783} 1784 1785function ersQSFO(obj) // query string from object 1786{ 1787 var string = ""; 1788 1789 if (obj instanceof Object) 1790 { 1791 arr = []; 1792 for (var k in obj) 1793 { 1794 arr.push( encodeURIComponent(k) + "=" + encodeURIComponent(obj[k]) ); 1795 } 1796 1797 string = arr.join("&"); 1798 } 1799 1800 return string; 1801} 1802 1803function ersSetSessvar(key, value) 1804{ 1805 if (ersVS(key).length == 0) 1806 { 1807 return; 1808 } 1809 1810 var params = { 1811 cmd: "set_sessvar", 1812 key: key, 1813 value: value 1814 }; 1815 1816 do_ajax_query(params, function(response){}); 1817} 1818 1819function ersVA(arr) // valid array 1820{ 1821 if (arr === null) return []; 1822 if (typeof arr === "undefined") return []; 1823 if (arr.constructor !== Array) return []; 1824 return arr; 1825} 1826 1827function ersVAFA(arr, index) // valid array from array 1828{ 1829 var array = ersVA(arr); 1830 if ((arr.length - 1) < ersVI(index)) return []; 1831 return ersVA(arr[index]); 1832} 1833 1834function ersVAFO(obj, key) // valid array from object 1835{ 1836 if (typeof key !== "string") return []; 1837 var object = ersVO(obj); 1838 return ersVA(object[key]); 1839} 1840 1841function ersVI(integer, def) // valid integer 1842{ 1843 if (!def) 1844 { 1845 def = 0; 1846 } 1847 1848 return parseInt(integer) || def; 1849} 1850 1851function ersVIFA(arr, index, def) // valid integer from array 1852{ 1853 if (!def) def = 0; 1854 var array = ersVA(arr); 1855 if ((arr.length - 1) < ersVI(index)) return def; 1856 return ersVI(arr[index], def); 1857} 1858 1859function ersVIFO(obj, key, def) // valid integer from object 1860{ 1861 if (!def) def = 0; 1862 if (typeof key !== "string") return def; 1863 var object = ersVO(obj); 1864 return ersVI(object[key], def); 1865} 1866 1867function ersVO(obj) // valid object 1868{ 1869 if (obj === null) return {}; 1870 if (typeof obj === "undefined") return {}; 1871 if (obj.constructor !== Object) return {}; 1872 return obj; 1873} 1874 1875function ersVOFA(arr, index) // valid object from array 1876{ 1877 var array = ersVA(arr); 1878 if ((arr.length - 1) < ersVI(index)) return {}; 1879 return ersVO(arr[index]); 1880} 1881 1882function ersVOFO(obj, key) // valid object from object 1883{ 1884 if (typeof key !== "string") return {}; 1885 var object = ersVO(obj); 1886 return ersVO(object[key]); 1887} 1888 1889function ersVS(str, def, convert) // valid string 1890{ 1891 if (!def) def = ""; 1892 if (str === null) return def; 1893 if (typeof str === "undefined") return def; 1894 if (convert) return str.toString(); 1895 if (typeof str !== "string") return def; 1896 return str; 1897} 1898 1899function ersVSFA(arr, index, def) // valid string from array 1900{ 1901 if (!def) def = ""; 1902 var array = ersVA(arr); 1903 if ((arr.length - 1) < ersVI(index)) return def; 1904 return ersVS(arr[index]); 1905} 1906 1907function ersVSFO(obj, key, def) // valid string from object 1908{ 1909 if (!def) def = ""; 1910 if (typeof key !== "string") return def; 1911 var object = ersVO(obj); 1912 return ersVS(object[key], def, true); 1913} 1914 1915function fake_sleep(ms) 1916{ 1917 var date = new Date(); 1918 var curDate = null; 1919 do { curDate = new Date(); } 1920 while(curDate-date < ms); 1921} 1922 1923function ers_real_sleep(ms) 1924{ 1925 return new Promise(resolve => setTimeout(resolve, ms)); 1926} 1927 1928function ersAddClass(el, class_name, if_has_class) // if_has_class is optional 1929{ 1930 if (!el) 1931 { 1932 return; 1933 } 1934 1935 var cl_na = ersVS(class_name); 1936 if (cl_na.length == 0) 1937 { 1938 return; 1939 } 1940 1941 var ihc = ersVS(if_has_class); 1942 if (ihc.length > 0) 1943 { 1944 if (!el.classList.contains(ihc)) 1945 { 1946 return; 1947 } 1948 } 1949 1950 if (!el.classList.contains(cl_na)) 1951 { 1952 el.classList.add(cl_na); 1953 } 1954} 1955 1956function ersRemoveClass(el, class_name) 1957{ 1958 if (!el) 1959 { 1960 return; 1961 } 1962 1963 var cl_na = ersVS(class_name); 1964 if (cl_na.length == 0) 1965 { 1966 return; 1967 } 1968 1969 el.classList.remove(cl_na); 1970} 1971 1972function ersRemoveElement(el) 1973{ 1974 if (!el) 1975 { 1976 return; 1977 } 1978 1979 var pn = el.parentNode; 1980 if (pn) 1981 { 1982 pn.removeChild(el); 1983 } 1984} 1985 1986function ersHasClass(el, cls) 1987{ 1988 if (!el) 1989 { 1990 return false;
1991 } 1992 1993 return (" " + el.className + " ").indexOf(" " + cls + " ") > -1; 1994} 1995 1996function ersIsElement(obj) 1997{ 1998 try 1999 { 2000 return obj instanceof HTMLElement; 2001 } 2002 catch(e) 2003 { 2004 return (typeof obj==="object") 2005 && (obj.nodeType===1) 2006 && (typeof obj.style === "object") 2007 && (typeof obj.ownerDocument === "object"); 2008 } 2009} 2010 2011function ersIsFunction(f) 2012{ 2013 return (f && {}.toString.call(f) === "[object Function]"); 2014} 2015 2016function ersRandom() 2017{ 2018 return Math.floor((Math.random() * 1000000) + 1); 2019} 2020 2021var ersScheduledActions = []; 2022var ersScheduledActionTimer = null; 2023var ersRunningScheduledAction = false; 2024 2025function ersScheduleAction(action, delay) 2026{ 2027 if (!delay) 2028 { 2029 delay = 0; 2030 } 2031 2032 if (delay == 0) 2033 { 2034 ersScheduledActions.push(action); 2035 } 2036 else 2037 { 2038 window.setTimeout(function(){ ersScheduledActions.push(action) }, delay); 2039 } 2040 2041 if (ersScheduledActionTimer == null) 2042 { 2043 ersScheduledActionTimer = setInterval(function() { ersRunNextScheduledAction() }, 99); 2044 } 2045} 2046 2047function ersRunNextScheduledAction() 2048{ 2049 if (ersScheduledActions.length == 0) 2050 { 2051 return; 2052 } 2053 2054 if (ersRunningScheduledAction) 2055 { 2056 return; 2057 } 2058 2059 ersRunningScheduledAction = true; 2060 2061 var this_action = ersScheduledActions[0]; 2062 2063 ersScheduledActions.splice(0, 1); 2064 2065 this_action(); 2066 2067 ersRunningScheduledAction = false; 2068 2069 if (ersScheduledActions.length == 0) 2070 { 2071 clearInterval(ersScheduledActionTimer); 2072 ersScheduledActionTimer = null; 2073 } 2074} 2075 2076var ERSPreloadedImages = {}; 2077 2078function ersPreloadImages(preload_list) 2079{ 2080 if (preload_list == null) 2081 { 2082 return; 2083 } 2084 2085 if (preload_list instanceof Array) 2086 { 2087 for (p = 0; p < preload_list.length; p++) 2088 { 2089 ersPreloadImage(preload_list[p]); 2090 } 2091 } 2092} 2093 2094function ersPreloadImage(image_path) 2095{ 2096 var check_path = ersVS(image_path); 2097 if (check_path.length == 0) 2098 { 2099 return; 2100 } 2101 2102 if (ERSPreloadedImages.hasOwnProperty(check_path)) 2103 { 2104 return; 2105 } 2106 2107 var image = new Image(); 2108 image.onload = function(){ ERSPreloadedImages[check_path] = this; }; 2109 image.src = check_path; 2110} 2111 2112function ERSClickOrTouch() 2113{ 2114 return CM_use_touch?"ontouchstart":"onclick"; 2115} 2116 2117function html_to_dom(str) { 2118 const whole_doc = "<html><head></head><body>" + str + "</body></html>"; 2119 parser = new DOMParser(); 2120 doc = parser.parseFromString(whole_doc, "text/html"); 2121 return doc.body.children[0]; 2122} 2123 2124/* 2125function add_class(node, className) { 2126 const new_cnames = className.split(" ").filter(c=>c.trim()).filter(Boolean); 2127 const old_cnames = node.className.split(" ").filter(c=>c.trim()).filter(Boolean); 2128 for (const cname of new_cnames) { 2129 if (old_cnames.includes(cname)) { 2130 continue; 2131 } 2132 old_cnames.push(cname); 2133 } 2134 node.className = old_cnames.join(" "); 2135} 2136 2137function rm_class(node, className) { 2138 const new_cnames = className.split(" ").filter(c=>c.trim()).filter(Boolean); 2139 const old_cnames = node.className.split(" ").filter(c=>c.trim()).filter(Boolean); 2140 node.className = old_cnames.filter(cname => new_cnames.includes(cname) === false).join(" "); 2141} 2142 2143(function() { 2144 2145 function diff_dom(root, newstr) {
2146 const frag = html_to_dom(newstr); 2147 diff(root, frag); 2148 } 2149 2150 function diff(rootDOM, newDOM) { 2151 if (newDOM instanceof HTMLElement && rootDOM instanceof HTMLElement || 2152 newDOM instanceof Text && rootDOM instanceof Text) { 2153 2154 // if same types, we can diff 2155 if (newDOM instanceof HTMLElement) { 2156 if (newDOM.tagName === rootDOM.tagName) { 2157 diff_html_node(rootDOM, newDOM); 2158 } else { 2159 rootDOM.parentNode.replaceChild(newDOM, rootDOM); 2160 } 2161 } else if (newDOM instanceof Text) { 2162 diff_text(rootDOM, newDOM); 2163 } else { 2164 throw new TypeError("No way to diff element: ", newDOM); 2165 } 2166 } else { 2167 // if they're different types, just replace whole branch 2168 rootDOM.parentNode.replaceChild(newDOM, rootDOM); 2169 } 2170 } 2171 2172 function diff_text(rootDOM, newDOM) { 2173 rootDOM.textContent = newDOM.textContent; 2174 } 2175 2176 function diff_html_node(rootDOM, newDOM) { 2177 diff_attributes(rootDOM, newDOM); 2178 diff_children(rootDOM, newDOM); 2179 } 2180 2181 function diff_attributes(rootDOM, newDOM) { 2182 // delete old attrs // 2183 for (const attr_name of rootDOM.getAttributeNames()) { 2184 if (!newDOM.hasAttribute(attr_name)) { 2185 rootDOM.removeAttribute(attr_name); 2186 } 2187 } 2188 2189 // add/set other attrs // 2190 for (const attr_name of newDOM.getAttributeNames()) { 2191 if (rootDOM[attr_name] !== newDOM[attr_name]) { 2192 if (attr_name.slice(0, 2) === "on") { 2193 rootDOM[attr_name] = new Function(newDOM.getAttribute(attr_name)); 2194 } else { 2195 rootDOM[attr_name] = newDOM.getAttribute(attr_name); 2196 } 2197 } 2198 } 2199 } 2200 2201 function diff_children(rootDOM, newDOM) { 2202 const old_length = rootDOM.childNodes.length; 2203 const new_length = newDOM.childNodes.length; 2204 const least_length = Math.min(old_length, new_length); 2205 const greatest_length = Math.max(old_length, new_length); 2206 const deletables = []; 2207 const appendables = []; 2208 2209 for (let i = greatest_length-1; i >= 0; i--) { 2210 if (i < least_length) { 2211 // diff existing child 2212 const curr_child = rootDOM.childNodes[i]; 2213 const next_child = newDOM.childNodes[i]; 2214 diff(curr_child, next_child); 2215 //diff(rootDOM.childNodes[i], newDOM.childNodes[i]); 2216 } else { 2217 // remove / add excess child 2218 if (old_length > new_length) { 2219 deletables.push(rootDOM.childNodes[i]); 2220 } else { 2221 appendables.push(newDOM.childNodes[i]); 2222 } 2223 } 2224 } 2225 2226 // delete 2227 for (const node of deletables) { 2228 node.parentNode.removeChild(node); 2229 } 2230 // add 2231 for (const node of appendables) { 2232 rootDOM.appendChild(node); 2233 } 2234 } 2235 2236 window.diff_dom = diff_dom; 2237})();*/ 2238 2239function strip_html_from(text) 2240{ 2241 return text.replace(/(<([^>]+)>)/gi, ""); 2242} 2243 2244function ampersand_decode(text) 2245{ 2246 var ta = document.createElement("textarea"); 2247 ta.innerHTML = text; 2248 return ta.value; 2249} 2250 2251function encode_notes_text(text) 2252{ 2253 return strip_html_from(text); 2254} 2255 2256function decoded_notes_text(el) 2257{ 2258 var html = ampersand_decode(el.innerHTML).replace("<br>", ""); 2259 2260 if (strip_html_from(html).trim() == "") 2261 { 2262 return ""; 2263 } 2264 2265 var regexp1 = new RegExp("</div><div>", "ig"); 2266 var regexp2 = new RegExp("<div>", "ig"); 2267 2268 html = html.replace(regexp1, "\r\n"); 2269 if (html.substring(0, 5) == "<div>") 2270 { 2271 html = html.substring(5); 2272 } 2273 html = html.replace(regexp2, "\r\n"); 2274 2275 return strip_html_from(html).trim(); 2276} 2277 2278function ersDisplayMoreBelow(el) 2279{ 2280 window.setTimeout(function() 2281 { 2282 ersElDisplay(el, "none");
2283 ersElDisplay(el.nextElementSibling, "block"); 2284 }, 100); 2285} 2286 2287function ersDisplayLessBelow(el) 2288{ 2289 window.setTimeout(function() 2290 { 2291 var hide_div = el.parentElement; 2292 if (hide_div) 2293 { 2294 ersElDisplay(hide_div, "none"); 2295 ersElDisplay(hide_div.previousElementSibling, "inline-block"); 2296 } 2297 }, 100); 2298} 2299 2300function ersValueTrue(val) 2301{ 2302 var str = ((ersVS(val, "", true).toLowerCase()).trim()).substr(0, 1); 2303 2304 return (val===true || str=="y" || str=="t" || str=="1"); 2305} 2306 2307function ersInlinePropStop() 2308{ 2309 var event = arguments[0] || window.event; 2310 if (event) 2311 { 2312 if (event.stopPropagation) 2313 { 2314 event.stopPropagation(); 2315 } 2316 else 2317 { 2318 event.cancelBubble = true; 2319 } 2320 } 2321} 2322 2323function ersTSVDownload(filename, tsv_text) 2324{ 2325 var edll = ersDE("ERSExportDownloadLink"); 2326 if (!edll) 2327 { 2328 // create on the fly? 2329 } 2330 if (edll) 2331 { 2332 edll.href = "data:text/tab-separated-values;charset=utf-8," + encodeURIComponent(tsv_text); 2333 // 2023-02-06 JML - changed encodeURI to encodeURIComponent to fix partial tsv export problem. 2334 edll.download = filename + ".tsv"; 2335 edll.click(); 2336 } 2337} 2338 2339function wm_title_to_id(tit) 2340{ 2341 var replaces = { ' ': "_", '/': "-", ':': "_", "'": "", ',': "" }; 2342 2343 return tit.replace(/ |\/|:|'|,/gi, function(matched) { return replaces[matched]; }).toLowerCase(); 2344} 2345 2346function ersPostRequestToScript(req_obj, script, new_window) 2347{ 2348 var form = document.createElement("form"); 2349 form.setAttribute("method", "post"); 2350 form.setAttribute("action", script); 2351 if (new_window) 2352 { 2353 form.setAttribute("target", "_blank"); 2354 } 2355 2356 for (var key in req_obj) 2357 { 2358 if (req_obj.hasOwnProperty(key)) 2359 { 2360 var value = req_obj[key]; 2361 var value_string = ""; 2362 2363 if ((value.constructor === Array) || (value.constructor === Object)) 2364 { 2365 value_string = JSON.stringify(value); 2366 } 2367 else 2368 { 2369 value_string = value.toString(); 2370 } 2371 2372 var hiddenField = document.createElement("input"); 2373 hiddenField.setAttribute("type", "hidden"); 2374 hiddenField.setAttribute("name", key); 2375 hiddenField.setAttribute("value", value_string); 2376 2377 form.appendChild(hiddenField); 2378 } 2379 } 2380 2381 document.body.appendChild(form); 2382 form.submit(); 2383 2384 return form; 2385} 2386 2387function capitalizeWords(str) { 2388 return str 2389 .split(" ") 2390 .map(word => word.charAt(0).toUpperCase() + word.slice(1)) 2391 .join(" "); 2392} 2393 2394function documentReady(callback) { 2395 if (document.readyState !== "loading") { 2396 callback(); 2397 } else { 2398 document.addEventListener("DOMContentLoaded", callback); 2399 } 2400}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.