var pModel = {}; var ModelNozzleSelected = {}; let SearchBox; let $content; function InitGlobalVariables() { SearchBox = document.querySelector('.searchTerm'); $content = $('#Content'); } function RequestProfile() { var tSend={}; tSend['sequence_id']=Math.round(new Date() / 1000); tSend['command']="request_userguide_profile"; SendWXMessage( JSON.stringify(tSend) ); } function HandleStudio( pVal ) { // alert(strInput); // alert(JSON.stringify(strInput)); // // let pVal=IsJson(strInput); // if(pVal==null) // { // alert("Msg Format Error is not Json"); // return; // } let strCmd=pVal['command']; //alert(strCmd); if(strCmd=='response_userguide_profile') { HandleModelList(pVal['response']); } } function HandleModelList( pVal ) { if( !pVal.hasOwnProperty("model") ) return; pModel=pVal['model']; // ORCA ensure list correctly ordered pModel = pModel.sort((a, b)=>(a["vendor"].localeCompare(b["vendor"]))) pModel = [ // move custom printers to top ...pModel.filter(i=>i.vendor === "Custom"), ...pModel.filter(i=>i.vendor !== "Custom") ]; let nTotal=pModel.length; let ModelHtml={}; for(let n=0;n 0) { if( $(ChooseItem).hasClass('ModelCheckBoxSelected') ) $(ChooseItem).removeClass('ModelCheckBoxSelected'); else $(ChooseItem).addClass('ModelCheckBoxSelected'); SetModelSelect(vendor, ModelName, $(ChooseItem).hasClass('ModelCheckBoxSelected')); } } function FilterModelList(keyword) { //Save checkbox state let ModelSelect = $('.ModelCheckBox'); for (let n = 0; n < ModelSelect.length; n++) { let OneItem = ModelSelect[n]; let strModel = OneItem.getAttribute("model"); let strVendor = OneItem.getAttribute("vendor"); SetModelSelect(strVendor, strModel, $(OneItem).hasClass('ModelCheckBoxSelected')); } $('.search')[0].setAttribute("hasvalue", keyword ? "1" : "0") let nTotal = pModel.length; let ModelHtml = {}; let kwSplit = keyword.toLowerCase().match(/\S+/g) || []; $('#Content').empty(); for (let n = 0; n < nTotal; n++) { let OneModel = pModel[n]; let strVendor = OneModel['vendor']; let search = (OneModel['name'] + '\0' + strVendor).toLowerCase(); if (!kwSplit.every(s => search.includes(s))) continue; //Add Vendor Html Node if ($(".OneVendorBlock[vendor='" + strVendor + "']").length == 0) { let HtmlNewVendor = CreateVendorBlock(strVendor); $('#Content').append(HtmlNewVendor); } //Collect Html Node Nozzel Html if (!ModelHtml.hasOwnProperty(strVendor)) ModelHtml[strVendor] = ''; ModelHtml[strVendor] += CreatePrinterBlock(OneModel); // ORCA } //Update Nozzel Html Append for (let key in ModelHtml) { let obj = $(".OneVendorBlock[vendor='" + key + "'] .PrinterArea"); obj.empty(); obj.append(ModelHtml[key]); } //Update Checkbox ModelSelect = $('.ModelCheckBox'); for (let n = 0; n < ModelSelect.length; n++) { let OneItem = ModelSelect[n]; let strModel = OneItem.getAttribute("model"); let strVendor = OneItem.getAttribute("vendor"); let checked = GetModelSelect(strVendor, strModel); if (checked) $(OneItem).addClass('ModelCheckBoxSelected'); else $(OneItem).removeClass('ModelCheckBoxSelected'); } UpdateSidebarVendors(); $content.css("padding-right", $content[0].scrollHeight > $content[0].clientHeight ? "10px" : "20px"); // let AlreadySelect=$(".ModelCheckBoxSelected"); // let nSelect=AlreadySelect.length; // if(nSelect==0) // { // $("div.OneVendorBlock[vendor='"+BBL+"'] .ModelCheckBox").addClass('ModelCheckBoxSelected'); // } TranslatePage(); } function textInput(obj) { FilterModelList(obj.value); } function CreateVendorBlock(vendorName) { let alt = vendorName; if( alt == "BBL" ) alt = "Bambu Lab"; if( alt == "Custom") alt = "Custom Printer"; if( alt == "Other") alt = "Orca colosseum"; return '
' + '
' + ' ' + alt + '' + '
'+ '
' + ' '+ '
'+ '
' + '
' + '
' + '
'; } function CreatePrinterBlock(OneModel) { let vendor = OneModel['vendor'] let vendorName = vendor=="BBL" ? "Bambu Lab" : vendor=="Custom" ? "Generic Printer" : vendor; let modelName = OneModel['name']; // Most of it unneeded. this can be applied in profiles if( vendor=="Custom") modelName = modelName.split(" ")[1]; // these uses different case in name; seckit, ratrig, blocks else if (modelName.toLowerCase().startsWith(vendorName.toLowerCase())) modelName = modelName.slice(vendorName.length); // these not matches. have to fix in profiles to reduce conditions in here; else if (vendor == "MagicMaker" && modelName.startsWith("MM")) modelName = modelName.slice(("MM").length); else if (vendor == "OrcaArena") modelName = modelName.slice(("Orca Arena").length); else if (vendor == "RolohaunDesign" && modelName.startsWith("Rolohaun")) modelName = modelName.slice(("Rolohaun").length); return '
'+ '
'+ ' '+ '
'+ '
?
'+ '
'+ '
Nozzle
'+ '
' + OneModel['nozzle_diameter'].replaceAll(";", " ยท ") + '
'+ '
'+ '
'+ '
'+ '
'+ modelName +'
'+ // >

'+ vendorName +'

'
'+ '
'; } function scrollToVendor(vendor) { const el = $(".OneVendorBlock[vendor='"+vendor+"']")[0]; if (el){ document.getElementById('SidebarContainer').setAttribute('open', '0'); document.getElementById('Content').scrollTo({top: el.offsetTop, behavior: "smooth"}); } } function UpdateSidebarVendors() { let SidebarHTML = ""; $(`.OneVendorBlock`).each((i, el)=>{ UpdateVendorCheckbox(el.getAttribute("vendor")); SidebarHTML +=`
${el.getAttribute('vendor')}
`; }); $('#SidebarVendors').html(SidebarHTML) } function ChooseVendor(sVendor) { // automatically selects / unselects all const $cbs = $(`.OneVendorBlock[vendor='${sVendor}'] .ModelCheckBox`); const sel = $cbs.length && $cbs.not('.ModelCheckBoxSelected').length; sel ? $cbs.addClass('ModelCheckBoxSelected') : $cbs.removeClass('ModelCheckBoxSelected'); $cbs.each((i, el)=>{SetModelSelect(sVendor, el.getAttribute('model'), sel)}); } function UpdateVendorCheckbox(sVendor) { const $vb = $(`.OneVendorBlock[vendor='${sVendor}']`); const $cbs = $vb.find(`.ModelCheckBox`); const $vcb = $vb.find(`.VendorCheckbox`); const selCount = $cbs.filter('.ModelCheckBoxSelected').length; const allSel = selCount === $cbs.length && selCount > 0; const nonSel = selCount === 0; $vcb.prop({checked: allSel , indeterminate: !allSel && !nonSel}); $vb.find(".modelCount").text(selCount + " / " + $cbs.length); } function OnExit() { let ModelAll={}; let ModelSelect=$(".ModelCheckBoxSelected"); let nTotal=ModelSelect.length; if( nTotal==0 ) { ShowNotice(1); return 0; } for(let n=0;n(el.getBoundingClientRect().top); const contentTop = bcTop($content[0]); const bannerH = ($content.find('.BlockBanner')[0] || {}).offsetHeight || 0; const firstCard = $content.find('.PrinterBlock')[0]; const firstArea = $content.find('.PrinterArea')[0]; const cardGap = (firstCard && firstArea) ? (bcTop(firstCard) - bcTop(firstArea)) : 0; const candidates = $content.find('.BlockBanner, .PrinterBlock').get(); if (dir === 'up') candidates.reverse(); let result = lastSeen = null; for (const el of candidates) { const snapTo = Math.round( el.classList.contains('BlockBanner') ? (bcTop(el.closest('.OneVendorBlock')) - contentTop) : Math.max(0, bcTop(el) - contentTop - bannerH - cardGap) ); if (snapTo != lastSeen){ lastSeen = snapTo; if (dir === 'down' && snapTo > cur + SNAP_CORR) { result = snapTo; break; } if (dir === 'up' && snapTo < cur - SNAP_CORR) { result = snapTo; break; } } } $content[0].scrollTop = savedScroll; // Restore scroll position return result; } function smoothScrollTo(target) { if (snapRafId) { cancelAnimationFrame(snapRafId); snapRafId = null; } const el = $content[0]; const from = el.scrollTop; const dist = target - from; const t0 = performance.now(); const ease = t => t < 0.5 ? 2*t*t : -1 + (4 - 2*t)*t; function onDone() { el.scrollTop = target; lastScrollTop = lastSnapTarget = target; waitingForUserScroll = true; clearTimeout(scrollTimer); scrollTimer = null; snapRafId = null; isSnapping = false; } if (Math.abs(dist) < 2) return onDone(); snapRafId = requestAnimationFrame(function step(now) { const p = Math.min((now - t0) / SNAP_DURATION, 1); el.scrollTop = from + dist * ease(p); if (p < 1) snapRafId = requestAnimationFrame(step); else onDone(); }); } function armSnap() { waitingForUserScroll = false; lastSnapTarget = null; } function initScrollEvents() { $content.on('scroll', function() { if (isSnapping) return; if (this.scrollTop > lastScrollTop + 1) scrollDir = 'down'; else if (this.scrollTop < lastScrollTop - 1) scrollDir = 'up'; lastScrollTop = this.scrollTop; if (waitingForUserScroll) return; clearTimeout(scrollTimer); scrollTimer = setTimeout(()=>{ if (isSnapping) return; const target = findSnap($content[0].scrollTop, scrollDir); if (target){ isSnapping = true; smoothScrollTo(target); } }, SNAP_DELAY); }); let touchY = 0; $content[0].addEventListener('touchstart', e => { touchY = e.touches[0].clientY; armSnap(); }, { passive: true }); $content[0].addEventListener('touchmove', e => { const dy = touchY - e.touches[0].clientY; if (Math.abs(dy) > 3) scrollDir = dy > 0 ? 'down' : 'up'; }, { passive: true }); // Re-arm snap system on user scroll $content[0].addEventListener('wheel', armSnap, { passive: true }); // Re-arm on after scrollbar usage $content[0].addEventListener('pointerdown', e => { if (e.target === $content[0]) armSnap(); }); // Re-arm on keyboard scroll or focus changes document.addEventListener('keydown', e => { if (document.activeElement != SearchBox){ let scrollKeys = ['ArrowUp','ArrowDown','PageUp','PageDown',' ']; let hasFocus = $content[0].contains(document.activeElement); if(scrollKeys.includes(e.key) || (hasFocus && e.which == 9)) armSnap(); } }); // ORCA unfocus search bar while scrolling and its content empty $content[0].addEventListener("scroll", () => { if (document.activeElement === SearchBox && SearchBox.value == "") SearchBox.blur(); }); } document.addEventListener('DOMContentLoaded', initScrollEvents); // LAYOUT SELECTOR function LayoutMode(value) { let LayoutSelector = document.querySelector('.LayoutSelector > .TabGroup'); let LayoutBtns = Array.from(LayoutSelector.children); let LayoutTypes = ["compact-list","compact-cover","large-cover"]; if($content[0].getAttribute("layout") === value) return; // find current visible vendor and scroll to it after layout change let target = null; for (const el of $content.find('.OneVendorBlock')) { if (el.getBoundingClientRect().bottom - $content[0].getBoundingClientRect().top >= -1) { target = el.getAttribute("vendor"); break; } } LayoutBtns.forEach(el => el.classList.remove('selected')); LayoutBtns[LayoutTypes.indexOf(value)].classList.add('selected'); $content[0].setAttribute("layout", value); if (target) scrollToVendor(target); } document.addEventListener('DOMContentLoaded', () => LayoutMode("large-cover")); // KEY EVENTS function initKeyEvents(closeOnESC) { document.onkeydown = function (event) { var e = event || window.event || arguments.callee.caller.arguments[0]; let sidebar = document.getElementById('SidebarContainer'); if (e.keyCode == 27){ if(sidebar.getAttribute('open') == "1") { // prefer to close sidebar first if its open sidebar.setAttribute('open', '0'); } else if (closeOnESC){ ClosePage(); } } // ORCA focus search bar on key input // SearchBox not in focus && writable character && non modifier if (document.activeElement != SearchBox && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) { SearchBox.focus(); } // Close sidebar on any key input sidebar.setAttribute('open', '0'); //if (window.event) { // try { e.keyCode = 0; } catch (e) { } // e.returnValue = true; //} }; }