diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dda0d18..ec0b6b4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -174,3 +174,45 @@ jobs: git merge --squash origin/auto git commit -m "v${{ needs.build.outputs.CURRENT_VERSION }}; ${{ needs.build.outputs.TITLE }}" -m "${{ needs.build.outputs.BODY }}" || echo "No changes to commit" git push origin main + + update-wiki: + + permissions: + contents: write + + runs-on: ubuntu-latest + + needs: [update-auto, build, update-requirements] # Needs the update-auto, build, and update-requirements jobs to finish first + + steps: + - name: Checkout main branch + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Force update wiki branch + run: | + git fetch origin + git branch -f wiki origin/main + git push origin wiki --force + + - name: Checkout wiki branch + run: git checkout wiki + + - name: Install dependencies + run: | + npm ci + npm install minami --no-save + + - name: Generate JSDoc from jsdoc.json + run: | + npx jsdoc -c jsdoc.json + + - name: Commit and push to wiki branch + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }} + git add docs + git commit -m "Update wiki via JSDoc" || echo "No changes to commit" + git push origin wiki diff --git a/dist/BlueMarble.user.js b/dist/BlueMarble.user.js index d94878a..44ccce1 100644 --- a/dist/BlueMarble.user.js +++ b/dist/BlueMarble.user.js @@ -22,4 +22,4 @@ // Wplace --> https://wplace.live // License --> https://www.mozilla.org/en-US/MPL/2.0/ -(()=>{var t,e,n=t=>{throw TypeError(t)},i=(t,e,i)=>e.has(t)?n("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,i),s=(t,e,i)=>(((t,e)=>{e.has(t)||n("Cannot access private method")})(t,e),i),o=class{constructor(e,n){i(this,t),this.name=e,this.version=n,this.t=null,this.i="bm-b",this.o=null,this.l=null,this.h=[]}u(t){this.t=t}m(){return this.h.length>0&&(this.l=this.h.pop()),this}p(t){t?.appendChild(this.o),this.o=null,this.l=null,this.h=[]}v(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"div",{},n)),this}M(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"p",{},n)),this}$(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"small",{},n)),this}C(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"img",{},n)),this}D(n,i={},o=()=>{}){return o(this,s(this,t,e).call(this,"h"+n,{},i)),this}T(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"hr",{},n)),this}I(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"br",{},n)),this}k(n={},i=()=>{}){const o=s(this,t,e).call(this,"label",{textContent:n.textContent??""});delete n.textContent;const a=s(this,t,e).call(this,"input",{type:"checkbox"},n);return o.insertBefore(a,o.firstChild),this.m(),i(this,o,a),this}N(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"button",{},n)),this}S(n={},i=()=>{}){const o=n.title??n.textContent??"Help: No info";delete n.textContent,n.title=`Help: ${o}`;const a={textContent:"?",className:"bm-q",onclick:()=>{this.B(this.i,o)}};return i(this,s(this,t,e).call(this,"button",a,n)),this}O(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"input",{},n)),this}L(n={},i=()=>{}){const o=n.textContent??"";delete n.textContent;const a=s(this,t,e).call(this,"div"),r=s(this,t,e).call(this,"input",{type:"file",style:"display: none !important; visibility: hidden !important; position: absolute !important; left: -9999px !important; width: 0 !important; height: 0 !important; opacity: 0 !important;"},n);this.m();const c=s(this,t,e).call(this,"button",{textContent:o});return this.m(),this.m(),r.setAttribute("tabindex","-1"),r.setAttribute("aria-hidden","true"),c.addEventListener("click",()=>{r.click()}),r.addEventListener("change",()=>{c.style.maxWidth=`${c.offsetWidth}px`,r.files.length>0?c.textContent=r.files[0].name:c.textContent=o}),i(this,a,r,c),this}H(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"textarea",{},n)),this}B(t,e,n=!1){const i=document.getElementById(t.replace(/^#/,""));i&&(i instanceof HTMLInputElement?i.value=e:n?i.textContent=e:i.innerHTML=e)}j(t,e){let n,i=!1,s=0,o=null,a=0,r=0,c=0,l=0;if(t=document.querySelector("#"==t?.[0]?t:"#"+t),e=document.querySelector("#"==e?.[0]?e:"#"+e),!t||!e)return void this.q(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`);const h=()=>{if(i){const e=Math.abs(a-c),n=Math.abs(r-l);(e>.5||n>.5)&&(a=c,r=l,t.style.transform=`translate(${a}px, ${r}px)`,t.style.left="0px",t.style.top="0px",t.style.right=""),o=requestAnimationFrame(h)}};let u=null;const m=(m,d)=>{i=!0,u=t.getBoundingClientRect(),n=m-u.left,s=d-u.top;const p=window.getComputedStyle(t).transform;if(p&&"none"!==p){const t=new DOMMatrix(p);a=t.m41,r=t.m42}else a=u.left,r=u.top;c=a,l=r,document.body.style.userSelect="none",e.classList.add("dragging"),o&&cancelAnimationFrame(o),h()},d=()=>{i=!1,o&&(cancelAnimationFrame(o),o=null),document.body.style.userSelect="",e.classList.remove("dragging")};e.addEventListener("mousedown",function(t){t.preventDefault(),m(t.clientX,t.clientY)}),e.addEventListener("touchstart",function(t){const e=t?.touches?.[0];e&&(m(e.clientX,e.clientY),t.preventDefault())},{passive:!1}),document.addEventListener("mousemove",function(t){i&&u&&(c=t.clientX-n,l=t.clientY-s)},{passive:!0}),document.addEventListener("touchmove",function(t){if(i&&u){const e=t?.touches?.[0];if(!e)return;c=e.clientX-n,l=e.clientY-s,t.preventDefault()}},{passive:!1}),document.addEventListener("mouseup",d),document.addEventListener("touchend",d),document.addEventListener("touchcancel",d)}A(t){(0,console.info)(`${this.name}: ${t}`),this.B(this.i,"Status: "+t,!0)}q(t){(0,console.error)(`${this.name}: ${t}`),this.B(this.i,"Error: "+t,!0)}};function a(t,e){if(0===t)return e[0];let n="";const i=e.length;for(;t>0;)n=e[t%i]+n,t=Math.floor(t/i);return n}function r(t){let e="";for(let n=0;n0)for(const t in e){const n=t,i=e[t];if(e.hasOwnProperty(t)){const t=n.split(" "),e=Number(t?.[0]),s=t?.[1]||"0",o=i.name||`Template ${e||""}`,a=i.tiles,r={};for(const t in a)if(a.hasOwnProperty(t)){const e=c(a[t]),n=new Blob([e],{type:"image/png"}),i=await createImageBitmap(n);r[t]=i}const l=new m({displayName:o,_:e||this.X?.length||0,F:s||""});l.P=r,this.X.push(l)}}};var d=GM_info.script.name.toString(),p=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-r",d),e.setAttribute("bm-o","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement?.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-r")||"Blue Marble",n=t?.getAttribute("bm-o")||"",i=new Map;window.addEventListener("message",t=>{const{source:s,endpoint:o,blobID:a,blobData:r,blink:c}=t.data;if(Date.now(),"blue-marble"==s&&a&&r&&!o){const t=i.get(a);"function"==typeof t?t(r):function(...t){(0,console.warn)(...t)}(`%c${e}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,n,"",a),i.delete(a)}});const s=window.fetch;window.fetch=async function(...t){const e=await s.apply(this,t),n=e.clone(),o=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore",a=n.headers.get("content-type")||"";if(a.includes("application/json"))n.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:o,jsonData:t},"*")}).catch(t=>{});else if(a.includes("image/")&&!o.includes("openfreemap")&&!o.includes("maps")){const t=Date.now(),e=await n.blob();return new Promise(s=>{const a=crypto.randomUUID();i.set(a,t=>{s(new Response(t,{headers:n.headers,status:n.status,statusText:n.statusText}))}),window.postMessage({source:"blue-marble",endpoint:o,blobID:a,blobData:e,blink:t})}).catch(t=>{Date.now()})}return e}});var b=GM_getResourceText("CSS-BM-File");GM_addStyle(b);var f=document.createElement("link");f.href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",f.rel="preload",f.as="style",f.onload=function(){this.onload=null,this.rel="stylesheet"},document.head?.appendChild(f),new class{constructor(){this.Z=null,this.K=null,this.tt="#bm-5"}et(t){return this.K=t,this.Z=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.tt)}),this}nt(){return this.Z}observe(t,e=!1,n=!1){t.observe(this.K,{childList:e,subtree:n})}};var w=new o(d,p),v=(new o(d,p),new class{constructor(t,e,n){i(this,l),this.name=t,this.version=e,this.o=n,this.it="1.0.0",this.st=null,this.ot="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.R=1e3,this.rt=3,this.ct=null,this.lt=null,this.ht="bm-p",this.ut="div#map canvas.maplibregl-canvas",this.dt=null,this.bt="",this.X=[],this.W=null,this.ft=!0}wt(){if(document.body.contains(this.ct))return this.ct;document.getElementById(this.ht)?.remove();const t=document.querySelector(this.ut),e=document.createElement("canvas");return e.id=this.ht,e.className="maplibregl-canvas",e.style.position="absolute",e.style.top="0",e.style.left="0",e.style.height=t?.clientHeight*(window.devicePixelRatio||1)+"px",e.style.width=t?.clientWidth*(window.devicePixelRatio||1)+"px",e.height=t?.clientHeight*(window.devicePixelRatio||1),e.width=t?.clientWidth*(window.devicePixelRatio||1),e.style.zIndex="8999",e.style.pointerEvents="none",t?.parentElement?.appendChild(e),this.ct=e,window.addEventListener("move",this.vt),window.addEventListener("zoom",this.yt),window.addEventListener("resize",this.xt),this.ct}async gt(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.it,templates:{}}}async Mt(t,e,n){this.W||(this.W=await this.gt()),this.o.A(`Creating template at ${n.join(", ")}...`);const i=new m({displayName:e,_:0,F:a(this.st||0,this.ot),file:t,coords:n}),{Y:o,J:r}=await i.U(this.R);i.P=o,this.W.templates[`${i._} ${i.F}`]={name:i.displayName,coords:n.join(", "),enabled:!0,tiles:r},this.X=[],this.X.push(i);const c=(new Intl.NumberFormat).format(i.G);this.o.A(`Template created at ${n.join(", ")}! Total pixels: ${c}`),await s(this,l,h).call(this)}$t(){}async Ct(){this.W||(this.W=await this.gt())}async Dt(t,e){if(!this.ft)return t;const n=this.R*this.rt;e=e[0].toString().padStart(4,"0")+","+e[1].toString().padStart(4,"0");const i=this.X;i.sort((t,e)=>t._-e._);const s=i.map(t=>{const n=Object.keys(t.P).filter(t=>t.startsWith(e));if(0===n.length)return null;const i=n.map(e=>{const n=e.split(",");return{Tt:t.P[e],It:[n[0],n[1]],kt:[n[2],n[3]]}});return i?.[0]}).filter(Boolean),o=s?.length||0;if(o>0){const t=i.filter(t=>Object.keys(t.P).filter(t=>t.startsWith(e)).length>0).reduce((t,e)=>t+(e.G||0),0),n=(new Intl.NumberFormat).format(t);this.o.A(`Displaying ${o} template${1==o?"":"s"}.\nTotal pixels: ${n}`)}else this.o.A(`Displaying ${o} templates.`);const a=await createImageBitmap(t),r=new OffscreenCanvas(n,n),c=r.getContext("2d");c.imageSmoothingEnabled=!1,c.beginPath(),c.rect(0,0,n,n),c.clip(),c.clearRect(0,0,n,n),c.drawImage(a,0,0,n,n);for(const t of s)c.drawImage(t.Tt,Number(t.kt[0])*this.rt,Number(t.kt[1])*this.rt);return await r.convertToBlob({type:"image/png"})}Nt(t){"BlueMarble"==t?.whoami&&s(this,l,u).call(this,t)}St(t){this.ft=t}}(d,p,w)),y=new class{constructor(t){this.Bt=t,this.Ot=!1,this.Lt=[],this.zt=[]}Ht(t){window.addEventListener("message",async e=>{const n=e.data,i=n.jsonData;if(!n||"blue-marble"!==n.source)return;if(!n.endpoint)return;const s=n.endpoint?.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).filter(t=>t&&!t.includes(".")).pop();switch(s){case"me":if(i.status&&"2"!=i.status?.toString()[0])return void t.q("You are not logged in!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(i.level)*Math.pow(30,.65),1/.65)-i.pixelsPainted);i.id||i.id,this.Bt.st=i.id,t.B("bm-h",`Username: ${function(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}(i.name)}`),t.B("bm-c",`Droplets: ${(new Intl.NumberFormat).format(i.droplets)}`),t.B("bm-6",`Next level in ${(new Intl.NumberFormat).format(e)} pixel${1==e?"":"s"}`);break;case"pixel":const s=n.endpoint.split("?")[0].split("/").filter(t=>t&&!isNaN(Number(t))),r=new URLSearchParams(n.endpoint.split("?")[1]),c=[r.get("x"),r.get("y")];if(this.Lt.length&&(!s.length||!c.length))return void t.q("Coordinates are malformed!\nDid you try clicking the canvas first?");this.Lt=[...s,...c];const l=(o=s,a=c,[parseInt(o[0])%4*1e3+parseInt(a[0]),parseInt(o[1])%4*1e3+parseInt(a[1])]),h=document.querySelectorAll("span");for(const t of h)if(t.textContent.trim().includes(`${l[0]}, ${l[1]}`)){let e=document.querySelector("#bm-5");const n=`(Tl X: ${s[0]}, Tl Y: ${s[1]}, Px X: ${c[0]}, Px Y: ${c[1]})`;e?e.textContent=n:(e=document.createElement("span"),e.id="bm-5",e.textContent=n,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"tiles":let u=n.endpoint.split("/");u=[parseInt(u[u.length-2]),parseInt(u[u.length-1].replace(".png",""))];const m=n.blobID,d=n.blobData,p=await this.Bt.Dt(d,u);window.postMessage({source:"blue-marble",blobID:m,blobData:p,blink:n.blink});break;case"robots":this.Ot="false"==i.userscript?.toString().toLowerCase()}var o,a})}}(v);w.u(y);var x=JSON.parse(GM_getValue("bmTemplates","{}"));v.Nt(x),function(){let t=!1;w.v({id:"bm-n",style:"top: 10px; right: 75px;"}).v({id:"bm-7"}).v({id:"bm-i"}).m().C({alt:"Blue Marble Icon - Click to minimize/maximize",src:"https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png",style:"cursor: pointer;"},(e,n)=>{n.addEventListener("click",()=>{t=!t;const i=document.querySelector("#bm-n"),s=document.querySelector("#bm-7"),o=document.querySelector("#bm-i"),a=document.querySelector("#bm-8"),r=document.querySelector("#bm-d"),c=document.querySelector("#bm-e"),l=document.querySelector("#bm-f"),h=document.querySelector("#bm-9"),u=document.querySelectorAll("#bm-8 input");t||(i.style.width="auto",i.style.maxWidth="300px",i.style.minWidth="200px",i.style.padding="10px"),["#bm-n h1","#bm-4","#bm-n hr","#bm-3 > *:not(#bm-8)","#bm-2","#bm-1",`#${e.i}`].forEach(e=>{document.querySelectorAll(e).forEach(e=>{e.style.display=t?"none":""})}),t?(a&&(a.style.display="none"),r&&(r.style.display="none"),c&&(c.style.display="none"),l&&(l.style.display="none"),h&&(h.style.display="none"),u.forEach(t=>{t.style.display="none"}),i.style.width="60px",i.style.height="76px",i.style.maxWidth="60px",i.style.minWidth="60px",i.style.padding="8px",n.style.marginLeft="3px",s.style.textAlign="center",s.style.margin="0",s.style.marginBottom="0",o&&(o.style.display="",o.style.marginBottom="0.25em")):(a&&(a.style.display="",a.style.flexDirection="",a.style.justifyContent="",a.style.alignItems="",a.style.gap="",a.style.textAlign="",a.style.margin=""),r&&(r.style.display=""),c&&(c.style.display="",c.style.marginTop=""),l&&(l.style.display="",l.style.marginTop=""),h&&(h.style.display="",h.style.marginTop=""),u.forEach(t=>{t.style.display=""}),n.style.marginLeft="",i.style.padding="10px",s.style.textAlign="",s.style.margin="",s.style.marginBottom="",o&&(o.style.marginBottom="0.5em"),i.style.width="",i.style.height=""),n.alt=t?"Blue Marble Icon - Minimized (Click to maximize)":"Blue Marble Icon - Maximized (Click to minimize)"})}).m().D(1,{textContent:d}).m().m().T().m().v({id:"bm-4"}).M({id:"bm-h",textContent:"Username:"}).m().M({id:"bm-c",textContent:"Droplets:"}).m().M({id:"bm-6",textContent:"Next level in..."}).m().m().T().m().v({id:"bm-3"}).v({id:"bm-8"}).N({id:"bm-d",className:"bm-q",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.t?.Lt;e?.[0]?(t.B("bm-j",e?.[0]||""),t.B("bm-k",e?.[1]||""),t.B("bm-l",e?.[2]||""),t.B("bm-m",e?.[3]||"")):t.q("Coordinates are malformed! Did you try clicking on the canvas first?")}}).m().O({type:"number",id:"bm-j",placeholder:"Tl X",min:0,max:2047,step:1,required:!0}).m().O({type:"number",id:"bm-k",placeholder:"Tl Y",min:0,max:2047,step:1,required:!0}).m().O({type:"number",id:"bm-l",placeholder:"Px X",min:0,max:2047,step:1,required:!0}).m().O({type:"number",id:"bm-m",placeholder:"Px Y",min:0,max:2047,step:1,required:!0}).m().m().L({id:"bm-2",textContent:"Upload Template",accept:"image/png, image/jpeg, image/webp, image/bmp, image/gif"}).m().v({id:"bm-0"}).N({id:"bm-f",textContent:"Enable"},(t,e)=>{e.onclick=()=>{t.t?.Bt?.St(!0),t.A("Enabled templates!")}}).m().N({id:"bm-e",textContent:"Create"},(t,e)=>{e.onclick=()=>{const e=document.querySelector("#bm-2"),n=document.querySelector("#bm-j");if(!n.checkValidity())return n.reportValidity(),void t.q("Coordinates are malformed! Did you try clicking on the canvas first?");const i=document.querySelector("#bm-k");if(!i.checkValidity())return i.reportValidity(),void t.q("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-l");if(!s.checkValidity())return s.reportValidity(),void t.q("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-m");if(!o.checkValidity())return o.reportValidity(),void t.q("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(v.Mt(e.files[0],e.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(n.value),Number(i.value),Number(s.value),Number(o.value)]),t.A("Drew to canvas!")):t.q("No file selected!")}}).m().N({id:"bm-9",textContent:"Disable"},(t,e)=>{e.onclick=()=>{t.t?.Bt?.St(!1),t.A("Disabled templates!")}}).m().m().H({id:w.i,placeholder:`Status: Sleeping...\nVersion: ${p}`,readOnly:!0}).m().v({id:"bm-1"}).v().N({id:"bm-a",className:"bm-q",innerHTML:"🎨",title:"Template Color Converter"},(t,e)=>{e.addEventListener("click",()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")})}).m().m().$({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).m().m().m().p(document.body)}(),w.j("#bm-n","#bm-i"),y.Ht(w),new MutationObserver((t,e)=>{const n=document.querySelector("#color-1");if(!n)return;let i=document.querySelector("#bm-g");if(!i){i=document.createElement("button"),i.id="bm-g",i.textContent="Move ↑",i.className="btn btn-soft",i.onclick=function(){const t=this.parentNode.parentNode.parentNode.parentNode,e="Move ↑"==this.textContent;t.parentNode.className=t.parentNode.className.replace(e?"bottom":"top",e?"top":"bottom"),t.style.borderTopLeftRadius=e?"0px":"var(--radius-box)",t.style.borderTopRightRadius=e?"0px":"var(--radius-box)",t.style.borderBottomLeftRadius=e?"var(--radius-box)":"0px",t.style.borderBottomRightRadius=e?"var(--radius-box)":"0px",this.textContent=e?"Move ↓":"Move ↑"};const t=n.parentNode.parentNode.parentNode.parentNode.querySelector("h2");t.parentNode?.appendChild(i)}}).observe(document.body,{childList:!0,subtree:!0}),function(...t){(0,console.log)(...t)}(`%c${d}%c (${p}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file +(()=>{var t,e,n=t=>{throw TypeError(t)},i=(t,e,i)=>e.has(t)?n("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,i),o=(t,e,i)=>(((t,e)=>{e.has(t)||n("Cannot access private method")})(t,e),i),s=class{constructor(e,n){i(this,t),this.name=e,this.version=n,this.t=null,this.i="bm-b",this.o=null,this.l=null,this.h=[]}m(t){this.t=t}u(){return this.h.length>0&&(this.l=this.h.pop()),this}p(t){t?.appendChild(this.o),this.o=null,this.l=null,this.h=[]}$(n={},i=()=>{}){return i(this,o(this,t,e).call(this,"div",{},n)),this}v(n={},i=()=>{}){return i(this,o(this,t,e).call(this,"p",{},n)),this}M(n={},i=()=>{}){return i(this,o(this,t,e).call(this,"small",{},n)),this}S(n={},i=()=>{}){return i(this,o(this,t,e).call(this,"img",{},n)),this}T(n,i={},s=()=>{}){return s(this,o(this,t,e).call(this,"h"+n,{},i)),this}D(n={},i=()=>{}){return i(this,o(this,t,e).call(this,"hr",{},n)),this}C(n={},i=()=>{}){return i(this,o(this,t,e).call(this,"br",{},n)),this}I(n={},i=()=>{}){const s=o(this,t,e).call(this,"label",{textContent:n.textContent??""});delete n.textContent;const a=o(this,t,e).call(this,"input",{type:"checkbox"},n);return s.insertBefore(a,s.firstChild),this.u(),i(this,s,a),this}k(n={},i=()=>{}){return i(this,o(this,t,e).call(this,"button",{},n)),this}N(n={},i=()=>{}){const s=n.title??n.textContent??"Help: No info";delete n.textContent,n.title=`Help: ${s}`;const a={textContent:"?",className:"bm-q",onclick:()=>{this.B(this.i,s)}};return i(this,o(this,t,e).call(this,"button",a,n)),this}O(n={},i=()=>{}){return i(this,o(this,t,e).call(this,"input",{},n)),this}P(n={},i=()=>{}){const s=n.textContent??"";delete n.textContent;const a=o(this,t,e).call(this,"div"),r=o(this,t,e).call(this,"input",{type:"file",style:"display: none !important; visibility: hidden !important; position: absolute !important; left: -9999px !important; width: 0 !important; height: 0 !important; opacity: 0 !important;"},n);this.u();const c=o(this,t,e).call(this,"button",{textContent:s});return this.u(),this.u(),r.setAttribute("tabindex","-1"),r.setAttribute("aria-hidden","true"),c.addEventListener("click",()=>{r.click()}),r.addEventListener("change",()=>{c.style.maxWidth=`${c.offsetWidth}px`,r.files.length>0?c.textContent=r.files[0].name:c.textContent=s}),i(this,a,r,c),this}H(n={},i=()=>{}){return i(this,o(this,t,e).call(this,"textarea",{},n)),this}B(t,e,n=!1){const i=document.getElementById(t.replace(/^#/,""));i&&(i instanceof HTMLInputElement?i.value=e:n?i.textContent=e:i.innerHTML=e)}L(t,e){let n,i=!1,o=0,s=null,a=0,r=0,c=0,l=0;if(t=document.querySelector("#"==t?.[0]?t:"#"+t),e=document.querySelector("#"==e?.[0]?e:"#"+e),!t||!e)return void this.j(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`);const h=()=>{if(i){const e=Math.abs(a-c),n=Math.abs(r-l);(e>.5||n>.5)&&(a=c,r=l,t.style.transform=`translate(${a}px, ${r}px)`,t.style.left="0px",t.style.top="0px",t.style.right=""),s=requestAnimationFrame(h)}};let m=null;const u=(u,d)=>{i=!0,m=t.getBoundingClientRect(),n=u-m.left,o=d-m.top;const p=window.getComputedStyle(t).transform;if(p&&"none"!==p){const t=new DOMMatrix(p);a=t.m41,r=t.m42}else a=m.left,r=m.top;c=a,l=r,document.body.style.userSelect="none",e.classList.add("dragging"),s&&cancelAnimationFrame(s),h()},d=()=>{i=!1,s&&(cancelAnimationFrame(s),s=null),document.body.style.userSelect="",e.classList.remove("dragging")};e.addEventListener("mousedown",function(t){t.preventDefault(),u(t.clientX,t.clientY)}),e.addEventListener("touchstart",function(t){const e=t?.touches?.[0];e&&(u(e.clientX,e.clientY),t.preventDefault())},{passive:!1}),document.addEventListener("mousemove",function(t){i&&m&&(c=t.clientX-n,l=t.clientY-o)},{passive:!0}),document.addEventListener("touchmove",function(t){if(i&&m){const e=t?.touches?.[0];if(!e)return;c=e.clientX-n,l=e.clientY-o,t.preventDefault()}},{passive:!1}),document.addEventListener("mouseup",d),document.addEventListener("touchend",d),document.addEventListener("touchcancel",d)}A(t){(0,console.info)(`${this.name}: ${t}`),this.B(this.i,"Status: "+t,!0)}j(t){(0,console.error)(`${this.name}: ${t}`),this.B(this.i,"Error: "+t,!0)}};function a(t,e){if(0===t)return e[0];let n="";const i=e.length;for(;t>0;)n=e[t%i]+n,t=Math.floor(t/i);return n}function r(t){let e="";for(let n=0;n0)for(const t in e){const n=t,i=e[t];if(console.log(n),e.hasOwnProperty(t)){const t=n.split(" "),e=Number(t?.[0]),o=t?.[1]||"0",s=i.name||`Template ${e||""}`,a=i.tiles,r={};for(const t in a)if(console.log(t),a.hasOwnProperty(t)){const e=c(a[t]),n=new Blob([e],{type:"image/png"}),i=await createImageBitmap(n);r[t]=i}const l=new u({displayName:s,G:e||this.W?.length||0,J:o||""});l.F=r,this.W.push(l),console.log(this.W),console.log("^^^ This ^^^")}}};var d=GM_info.script.name.toString(),p=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-r",d),e.setAttribute("bm-o","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement?.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-r")||"Blue Marble",n=t?.getAttribute("bm-o")||"",i=new Map;window.addEventListener("message",t=>{const{source:o,endpoint:s,blobID:a,blobData:r,blink:c}=t.data,l=Date.now()-c;if(console.groupCollapsed(`%c${e}%c: ${i.size} Recieved IMAGE message about blob "${a}"`,n,""),console.log(`Blob fetch took %c${String(Math.floor(l/6e4)).padStart(2,"0")}:${String(Math.floor(l/1e3)%60).padStart(2,"0")}.${String(l%1e3).padStart(3,"0")}%c MM:SS.mmm`,n,""),console.log(i),console.groupEnd(),"blue-marble"==o&&a&&r&&!s){const t=i.get(a);"function"==typeof t?t(r):function(...t){(0,console.warn)(...t)}(`%c${e}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,n,"",a),i.delete(a)}});const o=window.fetch;window.fetch=async function(...t){const s=await o.apply(this,t),a=s.clone(),r=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore",c=a.headers.get("content-type")||"";if(c.includes("application/json"))console.log(`%c${e}%c: Sending JSON message about endpoint "${r}"`,n,""),a.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:r,jsonData:t},"*")}).catch(t=>{console.error(`%c${e}%c: Failed to parse JSON: `,n,"",t)});else if(c.includes("image/")&&!r.includes("openfreemap")&&!r.includes("maps")){const t=Date.now(),o=await a.blob();return console.log(`%c${e}%c: ${i.size} Sending IMAGE message about endpoint "${r}"`,n,""),new Promise(s=>{const c=crypto.randomUUID();i.set(c,t=>{s(new Response(t,{headers:a.headers,status:a.status,statusText:a.statusText})),console.log(`%c${e}%c: ${i.size} Processed blob "${c}"`,n,"")}),window.postMessage({source:"blue-marble",endpoint:r,blobID:c,blobData:o,blink:t})}).catch(o=>{const s=Date.now();console.error(`%c${e}%c: Failed to Promise blob!`,n,""),console.groupCollapsed(`%c${e}%c: Details of failed blob Promise:`,n,""),console.log(`Endpoint: ${r}\nThere are ${i.size} blobs processing...\nBlink: ${t.toLocaleString()}\nTime Since Blink: ${String(Math.floor(s/6e4)).padStart(2,"0")}:${String(Math.floor(s/1e3)%60).padStart(2,"0")}.${String(s%1e3).padStart(3,"0")} MM:SS.mmm`),console.error("Exception stack:",o),console.groupEnd()})}return s}});var b=GM_getResourceText("CSS-BM-File");GM_addStyle(b);var f=document.createElement("link");f.href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",f.rel="preload",f.as="style",f.onload=function(){this.onload=null,this.rel="stylesheet"},document.head?.appendChild(f),new class{constructor(){this.Z=null,this.K=null,this.tt="#bm-5"}et(t){return this.K=t,this.Z=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.tt)}),this}nt(){return this.Z}observe(t,e=!1,n=!1){t.observe(this.K,{childList:e,subtree:n})}};var w=new s(d,p),g=(new s(d,p),new class{constructor(t,e,n){i(this,l),this.name=t,this.version=e,this.o=n,this.it="1.0.0",this.ot=null,this.st="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.R=1e3,this.rt=3,this.ct=null,this.lt=null,this.ht="bm-p",this.ut="div#map canvas.maplibregl-canvas",this.dt=null,this.bt="",this.W=[],this.V=null,this.ft=!0}wt(){if(document.body.contains(this.ct))return this.ct;document.getElementById(this.ht)?.remove();const t=document.querySelector(this.ut),e=document.createElement("canvas");return e.id=this.ht,e.className="maplibregl-canvas",e.style.position="absolute",e.style.top="0",e.style.left="0",e.style.height=t?.clientHeight*(window.devicePixelRatio||1)+"px",e.style.width=t?.clientWidth*(window.devicePixelRatio||1)+"px",e.height=t?.clientHeight*(window.devicePixelRatio||1),e.width=t?.clientWidth*(window.devicePixelRatio||1),e.style.zIndex="8999",e.style.pointerEvents="none",t?.parentElement?.appendChild(e),this.ct=e,window.addEventListener("move",this.gt),window.addEventListener("zoom",this.$t),window.addEventListener("resize",this.vt),this.ct}async xt(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.it,templates:{}}}async yt(t,e,n){this.V||(this.V=await this.xt(),console.log("Creating JSON...")),this.o.A(`Creating template at ${n.join(", ")}...`);const i=new u({displayName:e,G:0,J:a(this.ot||0,this.st),file:t,coords:n}),{_:s,U:r}=await i.q(this.R);i.F=s,this.V.templates[`${i.G} ${i.J}`]={name:i.displayName,coords:n.join(", "),enabled:!0,tiles:r},this.W=[],this.W.push(i);const c=(new Intl.NumberFormat).format(i.Y);this.o.A(`Template created at ${n.join(", ")}! Total pixels: ${c}`),console.log(Object.keys(this.V.templates).length),console.log(this.V),console.log(this.W),console.log(JSON.stringify(this.V)),await o(this,l,h).call(this)}Mt(){}async St(){this.V||(this.V=await this.xt(),console.log("Creating JSON..."))}async Tt(t,e){if(!this.ft)return t;const n=this.R*this.rt;e=e[0].toString().padStart(4,"0")+","+e[1].toString().padStart(4,"0"),console.log(`Searching for templates in tile: "${e}"`);const i=this.W;console.log(i),i.sort((t,e)=>t.G-e.G),console.log(i);const o=i.map(t=>{const n=Object.keys(t.F).filter(t=>t.startsWith(e));if(0===n.length)return null;const i=n.map(e=>{const n=e.split(",");return{Dt:t.F[e],Ct:[n[0],n[1]],It:[n[2],n[3]]}});return i?.[0]}).filter(Boolean);console.log(o);const s=o?.length||0;if(console.log(`templateCount = ${s}`),s>0){const t=i.filter(t=>Object.keys(t.F).filter(t=>t.startsWith(e)).length>0).reduce((t,e)=>t+(e.Y||0),0),n=(new Intl.NumberFormat).format(t);this.o.A(`Displaying ${s} template${1==s?"":"s"}.\nTotal pixels: ${n}`)}else this.o.A(`Displaying ${s} templates.`);const a=await createImageBitmap(t),r=new OffscreenCanvas(n,n),c=r.getContext("2d");c.imageSmoothingEnabled=!1,c.beginPath(),c.rect(0,0,n,n),c.clip(),c.clearRect(0,0,n,n),c.drawImage(a,0,0,n,n);for(const t of o)console.log("Template:"),console.log(t),c.drawImage(t.Dt,Number(t.It[0])*this.rt,Number(t.It[1])*this.rt);return await r.convertToBlob({type:"image/png"})}kt(t){console.log("Importing JSON..."),console.log(t),"BlueMarble"==t?.whoami&&o(this,l,m).call(this,t)}Nt(t){this.ft=t}}(d,p,w)),$=new class{constructor(t){this.Bt=t,this.Ot=!1,this.Pt=[],this.zt=[]}Et(t){window.addEventListener("message",async e=>{const n=e.data,i=n.jsonData;if(!n||"blue-marble"!==n.source)return;if(!n.endpoint)return;const o=n.endpoint?.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).filter(t=>t&&!t.includes(".")).pop();switch(console.log('%cBlue Marble%c: Recieved message about "%s"',"color: cornflowerblue;","",o),o){case"me":if(i.status&&"2"!=i.status?.toString()[0])return void t.j("You are not logged in!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(i.level)*Math.pow(30,.65),1/.65)-i.pixelsPainted);console.log(i.id),(i.id||0===i.id)&&console.log(a(i.id,"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")),this.Bt.ot=i.id,t.B("bm-h",`Username: ${function(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}(i.name)}`),t.B("bm-c",`Droplets: ${(new Intl.NumberFormat).format(i.droplets)}`),t.B("bm-6",`Next level in ${(new Intl.NumberFormat).format(e)} pixel${1==e?"":"s"}`);break;case"pixel":const o=n.endpoint.split("?")[0].split("/").filter(t=>t&&!isNaN(Number(t))),c=new URLSearchParams(n.endpoint.split("?")[1]),l=[c.get("x"),c.get("y")];if(this.Pt.length&&(!o.length||!l.length))return void t.j("Coordinates are malformed!\nDid you try clicking the canvas first?");this.Pt=[...o,...l];const h=(s=o,r=l,[parseInt(s[0])%4*1e3+parseInt(r[0]),parseInt(s[1])%4*1e3+parseInt(r[1])]),m=document.querySelectorAll("span");for(const t of m)if(t.textContent.trim().includes(`${h[0]}, ${h[1]}`)){let e=document.querySelector("#bm-5");const n=`(Tl X: ${o[0]}, Tl Y: ${o[1]}, Px X: ${l[0]}, Px Y: ${l[1]})`;e?e.textContent=n:(e=document.createElement("span"),e.id="bm-5",e.textContent=n,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"tiles":let u=n.endpoint.split("/");u=[parseInt(u[u.length-2]),parseInt(u[u.length-1].replace(".png",""))];const d=n.blobID,p=n.blobData,b=await this.Bt.Tt(p,u);window.postMessage({source:"blue-marble",blobID:d,blobData:b,blink:n.blink});break;case"robots":this.Ot="false"==i.userscript?.toString().toLowerCase();break}var s,r})}}(g);w.m($);var v=JSON.parse(GM_getValue("bmTemplates","{}"));console.log(v),g.kt(v),function(){let t=!1;w.$({id:"bm-n",style:"top: 10px; right: 75px;"}).$({id:"bm-7"}).$({id:"bm-i"}).u().S({alt:"Blue Marble Icon - Click to minimize/maximize",src:"https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png",style:"cursor: pointer;"},(e,n)=>{n.addEventListener("click",()=>{t=!t;const i=document.querySelector("#bm-n"),o=document.querySelector("#bm-7"),s=document.querySelector("#bm-i"),a=document.querySelector("#bm-8"),r=document.querySelector("#bm-d"),c=document.querySelector("#bm-e"),l=document.querySelector("#bm-f"),h=document.querySelector("#bm-9"),m=document.querySelectorAll("#bm-8 input");t||(i.style.width="auto",i.style.maxWidth="300px",i.style.minWidth="200px",i.style.padding="10px"),["#bm-n h1","#bm-4","#bm-n hr","#bm-3 > *:not(#bm-8)","#bm-2","#bm-1",`#${e.i}`].forEach(e=>{document.querySelectorAll(e).forEach(e=>{e.style.display=t?"none":""})}),t?(a&&(a.style.display="none"),r&&(r.style.display="none"),c&&(c.style.display="none"),l&&(l.style.display="none"),h&&(h.style.display="none"),m.forEach(t=>{t.style.display="none"}),i.style.width="60px",i.style.height="76px",i.style.maxWidth="60px",i.style.minWidth="60px",i.style.padding="8px",n.style.marginLeft="3px",o.style.textAlign="center",o.style.margin="0",o.style.marginBottom="0",s&&(s.style.display="",s.style.marginBottom="0.25em")):(a&&(a.style.display="",a.style.flexDirection="",a.style.justifyContent="",a.style.alignItems="",a.style.gap="",a.style.textAlign="",a.style.margin=""),r&&(r.style.display=""),c&&(c.style.display="",c.style.marginTop=""),l&&(l.style.display="",l.style.marginTop=""),h&&(h.style.display="",h.style.marginTop=""),m.forEach(t=>{t.style.display=""}),n.style.marginLeft="",i.style.padding="10px",o.style.textAlign="",o.style.margin="",o.style.marginBottom="",s&&(s.style.marginBottom="0.5em"),i.style.width="",i.style.height=""),n.alt=t?"Blue Marble Icon - Minimized (Click to maximize)":"Blue Marble Icon - Maximized (Click to minimize)"})}).u().T(1,{textContent:d}).u().u().D().u().$({id:"bm-4"}).v({id:"bm-h",textContent:"Username:"}).u().v({id:"bm-c",textContent:"Droplets:"}).u().v({id:"bm-6",textContent:"Next level in..."}).u().u().D().u().$({id:"bm-3"}).$({id:"bm-8"}).k({id:"bm-d",className:"bm-q",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.t?.Pt;e?.[0]?(t.B("bm-j",e?.[0]||""),t.B("bm-k",e?.[1]||""),t.B("bm-l",e?.[2]||""),t.B("bm-m",e?.[3]||"")):t.j("Coordinates are malformed! Did you try clicking on the canvas first?")}}).u().O({type:"number",id:"bm-j",placeholder:"Tl X",min:0,max:2047,step:1,required:!0}).u().O({type:"number",id:"bm-k",placeholder:"Tl Y",min:0,max:2047,step:1,required:!0}).u().O({type:"number",id:"bm-l",placeholder:"Px X",min:0,max:2047,step:1,required:!0}).u().O({type:"number",id:"bm-m",placeholder:"Px Y",min:0,max:2047,step:1,required:!0}).u().u().P({id:"bm-2",textContent:"Upload Template",accept:"image/png, image/jpeg, image/webp, image/bmp, image/gif"}).u().$({id:"bm-0"}).k({id:"bm-f",textContent:"Enable"},(t,e)=>{e.onclick=()=>{t.t?.Bt?.Nt(!0),t.A("Enabled templates!")}}).u().k({id:"bm-e",textContent:"Create"},(t,e)=>{e.onclick=()=>{const e=document.querySelector("#bm-2"),n=document.querySelector("#bm-j");if(!n.checkValidity())return n.reportValidity(),void t.j("Coordinates are malformed! Did you try clicking on the canvas first?");const i=document.querySelector("#bm-k");if(!i.checkValidity())return i.reportValidity(),void t.j("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-l");if(!o.checkValidity())return o.reportValidity(),void t.j("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-m");if(!s.checkValidity())return s.reportValidity(),void t.j("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(g.yt(e.files[0],e.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(n.value),Number(i.value),Number(o.value),Number(s.value)]),t.A("Drew to canvas!")):t.j("No file selected!")}}).u().k({id:"bm-9",textContent:"Disable"},(t,e)=>{e.onclick=()=>{t.t?.Bt?.Nt(!1),t.A("Disabled templates!")}}).u().u().H({id:w.i,placeholder:`Status: Sleeping...\nVersion: ${p}`,readOnly:!0}).u().$({id:"bm-1"}).$().k({id:"bm-a",className:"bm-q",innerHTML:"🎨",title:"Template Color Converter"},(t,e)=>{e.addEventListener("click",()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")})}).u().u().M({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).u().u().u().p(document.body)}(),w.L("#bm-n","#bm-i"),$.Et(w),new MutationObserver((t,e)=>{const n=document.querySelector("#color-1");if(!n)return;let i=document.querySelector("#bm-g");if(!i){i=document.createElement("button"),i.id="bm-g",i.textContent="Move ↑",i.className="btn btn-soft",i.onclick=function(){const t=this.parentNode.parentNode.parentNode.parentNode,e="Move ↑"==this.textContent;t.parentNode.className=t.parentNode.className.replace(e?"bottom":"top",e?"top":"bottom"),t.style.borderTopLeftRadius=e?"0px":"var(--radius-box)",t.style.borderTopRightRadius=e?"0px":"var(--radius-box)",t.style.borderBottomLeftRadius=e?"var(--radius-box)":"0px",t.style.borderBottomRightRadius=e?"var(--radius-box)":"0px",this.textContent=e?"Move ↓":"Move ↑"};const t=n.parentNode.parentNode.parentNode.parentNode.querySelector("h2");t.parentNode?.appendChild(i)}}).observe(document.body,{childList:!0,subtree:!0}),function(...t){(0,console.log)(...t)}(`%c${d}%c (${p}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file diff --git a/docs/Overlay.js.html b/docs/Overlay.js.html deleted file mode 100644 index 5f930dd..0000000 --- a/docs/Overlay.js.html +++ /dev/null @@ -1,748 +0,0 @@ - - - - - JSDoc: Source: Overlay.js - - - - - - - - - - -
- -

Source: Overlay.js

- - - - - - -
-
-
/** The overlay builder for the Blue Marble script.
- * @description This class handles the overlay UI for the Blue Marble script.
- * @since 0.0.2
- * @example
- * const overlay = new Overlay();
- * overlay.addDiv({ 'id': 'overlay' })
- *   .addDiv({ 'id': 'header' })
- *     .addHeader(1, {'textContent': 'Your Overlay'}).buildElement()
- *     .addP({'textContent': 'This is your overlay. It is versatile.'}).buildElement()
- *   .buildElement() // Marks the end of the header <div>
- *   .addHr().buildElement()
- * .buildOverlay(document.body);
- * // Output:
- * // (Assume <body> already exists in the webpage)
- * <body>
- *   <div id="overlay">
- *     <div id="header">
- *       <h1>Your Overlay</h1>
- *       <p>This is your overlay. It is versatile.</p>
- *     </div>
- *     <hr>
- *   </div>
- * </body>
-*/
-export default class Overlay {
-
-  /** Constructor for the Overlay class.
-   * @param {string} name - The name of the userscript
-   * @param {string} version - The version of the userscript
-   * @since 0.0.2
-   * @see {@link Overlay}
-   */
-  constructor(name, version) {
-    this.name = name; // Name of userscript
-    this.version = version; // Version of userscript
-
-    this.apiManager = null; // The API manager instance. Later populated when setApiManager is called
-    
-    this.outputStatusId = 'bm-output-status'; // ID for status element
-
-    this.overlay = null; // The overlay root DOM HTMLElement
-    this.currentParent = null; // The current parent HTMLElement in the overlay
-    this.parentStack = []; // Tracks the parent elements BEFORE the currentParent so we can nest elements
-  }
-
-  /** Populates the apiManager variable with the apiManager class.
-   * @param {apiManager} apiManager - The apiManager class instance
-   * @since 0.41.4
-   */
-  setApiManager(apiManager) {this.apiManager = apiManager;}
-
-  /** Creates an element.
-   * For **internal use** of the {@link Overlay} class.
-   * @param {string} tag - The tag name as a string.
-   * @param {Object.<string, any>} [properties={}] - The DOM properties of the element.
-   * @returns {HTMLElement} HTML Element
-   * @since 0.43.2
-   */
-  #createElement(tag, properties = {}, additionalProperties={}) {
-
-    const element = document.createElement(tag); // Creates the element
-
-    // If this is the first element made...
-    if (!this.overlay) {
-      this.overlay = element; // Declare it the highest overlay element
-      this.currentParent = element;
-    } else {
-      this.currentParent?.appendChild(element); // ...else delcare it the child of the last element
-      this.parentStack.push(this.currentParent);
-      this.currentParent = element;
-    }
-
-    // For every passed in property (shared by all like-elements), apply the it to the element
-    for (const [property, value] of Object.entries(properties)) {
-      element[property] = value;
-    }
-
-    // For every passed in additional property, apply the it to the element
-    for (const [property, value] of Object.entries(additionalProperties)) {
-      element[property] = value;
-    }
-    
-    return element;
-  }
-
-  /** Finishes building an element.
-   * Call this after you are finished adding children.
-   * If the element will have no children, call it anyways.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.2
-   * @example
-   * overlay
-   *   .addDiv()
-   *     .addHeader(1).buildElement() // Breaks out of the <h1>
-   *     .addP().buildElement() // Breaks out of the <p>
-   *   .buildElement() // Breaks out of the <div>
-   *   .addHr() // Since there are no more elements, calling buildElement() is optional
-   * .buildOverlay(document.body);
-   */
-  buildElement() {
-    if (this.parentStack.length > 0) {
-      this.currentParent = this.parentStack.pop();
-    }
-    return this;
-  }
-
-  /** Finishes building the overlay and displays it.
-   * Call this when you are done chaining methods.
-   * @param {HTMLElement} parent - The parent HTMLElement this overlay should be appended to as a child.
-   * @since 0.43.2
-   * @example
-   * overlay
-   *   .addDiv()
-   *     .addP().buildElement()
-   *   .buildElement()
-   * .buildOverlay(document.body); // Adds DOM structure to document body
-   * // <div><p></p></div>
-   */
-  buildOverlay(parent) {
-    parent?.appendChild(this.overlay);
-
-    // Resets the class-bound variables of this class instance back to default so overlay can be build again later
-    this.overlay = null;
-    this.currentParent = null;
-    this.parentStack = [];
-  }
-
-  /** Adds a `div` to the overlay.
-   * This `div` element will have properties shared between all `div` elements in the overlay.
-   * You can override the shared properties by using a callback.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the `div` that are NOT shared between all overlay `div` elements. These should be camelCase.
-   * @param {function(Overlay, HTMLDivElement):void} [callback=()=>{}] - Additional JS modification to the `div`.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.2
-   * @example
-   * // Assume all <div> elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addDiv({'id': 'foo'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <div id="foo" class="bar"></div>
-   * </body>
-   */
-  addDiv(additionalProperties = {}, callback = () => {}) {
-
-    const properties = {}; // Shared <div> DOM properties
-
-    const div = this.#createElement('div', properties, additionalProperties); // Creates the <div> element
-    callback(this, div); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Adds a `p` to the overlay.
-   * This `p` element will have properties shared between all `p` elements in the overlay.
-   * You can override the shared properties by using a callback.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the `p` that are NOT shared between all overlay `p` elements. These should be camelCase.
-   * @param {function(Overlay, HTMLParagraphElement):void} [callback=()=>{}] - Additional JS modification to the `p`.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.2
-   * @example
-   * // Assume all <p> elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addP({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <p id="foo" class="bar">Foobar.</p>
-   * </body>
-   */
-  addP(additionalProperties = {}, callback = () => {}) {
-
-    const properties = {}; // Shared <p> DOM properties
-
-    const p = this.#createElement('p', properties, additionalProperties); // Creates the <p> element
-    callback(this, p); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Adds a `small` to the overlay.
-   * This `small` element will have properties shared between all `small` elements in the overlay.
-   * You can override the shared properties by using a callback.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the `small` that are NOT shared between all overlay `small` elements. These should be camelCase.
-   * @param {function(Overlay, HTMLParagraphElement):void} [callback=()=>{}] - Additional JS modification to the `small`.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.55.8
-   * @example
-   * // Assume all <small> elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addSmall({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <small id="foo" class="bar">Foobar.</small>
-   * </body>
-   */
-  addSmall(additionalProperties = {}, callback = () => {}) {
-
-    const properties = {}; // Shared <small> DOM properties
-
-    const small = this.#createElement('small', properties, additionalProperties); // Creates the <small> element
-    callback(this, small); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Adds a `img` to the overlay.
-   * This `img` element will have properties shared between all `img` elements in the overlay.
-   * You can override the shared properties by using a callback.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the `img` that are NOT shared between all overlay `img` elements. These should be camelCase.
-   * @param {function(Overlay, HTMLImageElement):void} [callback=()=>{}] - Additional JS modification to the `img`.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.2
-   * @example
-   * // Assume all <img> elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addimg({'id': 'foo', 'src': './img.png'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <img id="foo" src="./img.png" class="bar">
-   * </body>
-   */
-  addImg(additionalProperties = {}, callback = () => {}) {
-
-    const properties = {}; // Shared <img> DOM properties
-
-    const img = this.#createElement('img', properties, additionalProperties); // Creates the <img> element
-    callback(this, img); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Adds a header to the overlay.
-   * This header element will have properties shared between all header elements in the overlay.
-   * You can override the shared properties by using a callback.
-   * @param {number} level - The header level. Must be between 1 and 6 (inclusive)
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the header that are NOT shared between all overlay header elements. These should be camelCase.
-   * @param {function(Overlay, HTMLHeadingElement):void} [callback=()=>{}] - Additional JS modification to the header.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.7
-   * @example
-   * // Assume all header elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addHeader(6, {'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <h6 id="foo" class="bar">Foobar.</h6>
-   * </body>
-   */
-  addHeader(level, additionalProperties = {}, callback = () => {}) {
-
-    const properties = {}; // Shared header DOM properties
-
-    const header = this.#createElement('h' + level, properties, additionalProperties); // Creates the header element
-    callback(this, header); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Adds a `hr` to the overlay.
-   * This `hr` element will have properties shared between all `hr` elements in the overlay.
-   * You can override the shared properties by using a callback.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the `hr` that are NOT shared between all overlay `hr` elements. These should be camelCase.
-   * @param {function(Overlay, HTMLHRElement):void} [callback=()=>{}] - Additional JS modification to the `hr`.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.7
-   * @example
-   * // Assume all <hr> elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addhr({'id': 'foo'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <hr id="foo" class="bar">
-   * </body>
-   */
-  addHr(additionalProperties = {}, callback = () => {}) {
-
-    const properties = {}; // Shared <hr> DOM properties
-
-    const hr = this.#createElement('hr', properties, additionalProperties); // Creates the <hr> element
-    callback(this, hr); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Adds a `br` to the overlay.
-   * This `br` element will have properties shared between all `br` elements in the overlay.
-   * You can override the shared properties by using a callback.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the `br` that are NOT shared between all overlay `br` elements. These should be camelCase.
-   * @param {function(Overlay, HTMLBRElement):void} [callback=()=>{}] - Additional JS modification to the `br`.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.11
-   * @example
-   * // Assume all <br> elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addbr({'id': 'foo'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <br id="foo" class="bar">
-   * </body>
-   */
-  addBr(additionalProperties = {}, callback = () => {}) {
-
-    const properties = {}; // Shared <br> DOM properties
-
-    const br = this.#createElement('br', properties, additionalProperties); // Creates the <br> element
-    callback(this, br); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Adds a checkbox to the overlay.
-   * This checkbox element will have properties shared between all checkbox elements in the overlay.
-   * You can override the shared properties by using a callback. Note: the checkbox element is inside a label element.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the checkbox that are NOT shared between all overlay checkbox elements. These should be camelCase.
-   * @param {function(Overlay, HTMLLabelElement, HTMLInputElement):void} [callback=()=>{}] - Additional JS modification to the checkbox.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.10
-   * @example
-   * // Assume all checkbox elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addCheckbox({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <label>
-   *     <input type="checkbox" id="foo" class="bar">
-   *     "Foobar."
-   *   </label>
-   * </body>
-   */
-  addCheckbox(additionalProperties = {}, callback = () => {}) {
-
-    const properties = {'type': 'checkbox'}; // Shared checkbox DOM properties
-
-    const label = this.#createElement('label', {'textContent': additionalProperties['textContent'] ?? ''}); // Creates the label element
-    delete additionalProperties['textContent']; // Deletes 'textContent' DOM property before adding the properties to the checkbox
-    const checkbox = this.#createElement('input', properties, additionalProperties); // Creates the checkbox element
-    label.insertBefore(checkbox, label.firstChild); // Makes the checkbox the first child of the label (before the text content)
-    this.buildElement(); // Signifies that we are done adding children to the checkbox
-    callback(this, label, checkbox); // Runs any script passed in through the callback
-    return this;
-  }
-  
-  /** Adds a `button` to the overlay.
-   * This `button` element will have properties shared between all `button` elements in the overlay.
-   * You can override the shared properties by using a callback.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the `button` that are NOT shared between all overlay `button` elements. These should be camelCase.
-   * @param {function(Overlay, HTMLButtonElement):void} [callback=()=>{}] - Additional JS modification to the `button`.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.12
-   * @example
-   * // Assume all <button> elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addButton({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <button id="foo" class="bar">Foobar.</button>
-   * </body>
-   */
-  addButton(additionalProperties = {}, callback = () => {}) {
-
-    const properties = {}; // Shared <button> DOM properties
-
-    const button = this.#createElement('button', properties, additionalProperties); // Creates the <button> element
-    callback(this, button); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Adds a help button to the overlay. It will have a "?" icon unless overridden in callback.
-   * On click, the button will attempt to output the title to the output element (ID defined in Overlay constructor).
-   * This `button` element will have properties shared between all `button` elements in the overlay.
-   * You can override the shared properties by using a callback.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the `button` that are NOT shared between all overlay `button` elements. These should be camelCase.
-   * @param {function(Overlay, HTMLButtonElement):void} [callback=()=>{}] - Additional JS modification to the `button`.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.12
-   * @example
-   * // Assume all help button elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addButtonHelp({'id': 'foo', 'title': 'Foobar.'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <button id="foo" class="bar" title="Help: Foobar.">?</button>
-   * </body>
-   * @example
-   * // Assume all help button elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addButtonHelp({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <button id="foo" class="bar" title="Help: Foobar.">?</button>
-   * </body>
-   */
-  addButtonHelp(additionalProperties = {}, callback = () => {}) {
-
-    const tooltip = additionalProperties['title'] ?? additionalProperties['textContent'] ?? 'Help: No info'; // Retrieves the tooltip
-
-    // Makes sure the tooltip is stored in the title property
-    delete additionalProperties['textContent'];
-    additionalProperties['title'] = `Help: ${tooltip}`;
-
-    // Shared help button DOM properties
-    const properties = {
-      'textContent': '?',
-      'className': 'bm-help',
-      'onclick': () => {
-        this.updateInnerHTML(this.outputStatusId, tooltip);
-      }
-    };
-
-    const help = this.#createElement('button', properties, additionalProperties); // Creates the <button> element
-    callback(this, help); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Adds a `input` to the overlay.
-   * This `input` element will have properties shared between all `input` elements in the overlay.
-   * You can override the shared properties by using a callback.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the `input` that are NOT shared between all overlay `input` elements. These should be camelCase.
-   * @param {function(Overlay, HTMLInputElement):void} [callback=()=>{}] - Additional JS modification to the `input`.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.13
-   * @example
-   * // Assume all <input> elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addInput({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <input id="foo" class="bar">Foobar.</input>
-   * </body>
-   */
-  addInput(additionalProperties = {}, callback = () => {}) {
-
-    const properties = {}; // Shared <input> DOM properties
-
-    const input = this.#createElement('input', properties, additionalProperties); // Creates the <input> element
-    callback(this, input); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Adds a file input to the overlay with enhanced visibility controls.
-   * This input element will have properties shared between all file input elements in the overlay.
-   * Uses multiple hiding methods to prevent browser native text from appearing during minimize/maximize.
-   * You can override the shared properties by using a callback.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the file input that are NOT shared between all overlay file input elements. These should be camelCase.
-   * @param {function(Overlay, HTMLDivElement, HTMLInputElement, HTMLButtonElement):void} [callback=()=>{}] - Additional JS modification to the file input.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.17
-   * @example
-   * // Assume all file input elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addInputFile({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <div>
-   *     <input type="file" id="foo" class="bar" style="display: none"></input>
-   *     <button>Foobar.</button>
-   *   </div>
-   * </body>
-   */
-  addInputFile(additionalProperties = {}, callback = () => {}) {
-    
-    const properties = {
-      'type': 'file', 
-      'style': 'display: none !important; visibility: hidden !important; position: absolute !important; left: -9999px !important; width: 0 !important; height: 0 !important; opacity: 0 !important;'
-    }; // Complete file input hiding to prevent native browser text interference
-    const text = additionalProperties['textContent'] ?? ''; // Retrieves the text content
-
-    delete additionalProperties['textContent']; // Deletes the text content before applying the additional properties to the file input
-
-    const container = this.#createElement('div'); // Container for file input
-    const input = this.#createElement('input', properties, additionalProperties); // Creates the file input
-    this.buildElement(); // Signifies that we are done adding children to the file input
-    const button = this.#createElement('button', {'textContent': text});
-    this.buildElement(); // Signifies that we are done adding children to the button
-    this.buildElement(); // Signifies that we are done adding children to the container
-
-    // Prevent file input from being accessible or visible by screen-readers and tabbing
-    input.setAttribute('tabindex', '-1');
-    input.setAttribute('aria-hidden', 'true');
-    
-    button.addEventListener('click', () => {
-      input.click(); // Clicks the file input
-    });
-
-    // Update button text when file is selected
-    input.addEventListener('change', () => {
-      button.style.maxWidth = `${button.offsetWidth}px`;
-      if (input.files.length > 0) {
-        button.textContent = input.files[0].name;
-      } else {
-        button.textContent = text;
-      }
-    });
-
-    callback(this, container, input, button); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Adds a `textarea` to the overlay.
-   * This `textarea` element will have properties shared between all `textarea` elements in the overlay.
-   * You can override the shared properties by using a callback.
-   * @param {Object.<string, any>} [additionalProperties={}] - The DOM properties of the `textarea` that are NOT shared between all overlay `textarea` elements. These should be camelCase.
-   * @param {function(Overlay, HTMLTextAreaElement):void} [callback=()=>{}] - Additional JS modification to the `textarea`.
-   * @returns {Overlay} Overlay class instance (this)
-   * @since 0.43.13
-   * @example
-   * // Assume all <textarea> elements have a shared class (e.g. {'className': 'bar'})
-   * overlay.addTextarea({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
-   * // Output:
-   * // (Assume <body> already exists in the webpage)
-   * <body>
-   *   <textarea id="foo" class="bar">Foobar.</textarea>
-   * </body>
-   */
-  addTextarea(additionalProperties = {}, callback = () => {}) {
-
-    const properties = {}; // Shared <textarea> DOM properties
-
-    const textarea = this.#createElement('textarea', properties, additionalProperties); // Creates the <textarea> element
-    callback(this, textarea); // Runs any script passed in through the callback
-    return this;
-  }
-
-  /** Updates the inner HTML of the element.
-   * The element is discovered by it's id.
-   * If the element is an `input`, it will modify the value attribute instead.
-   * @param {string} id - The ID of the element to change
-   * @param {string} html - The HTML/text to update with
-   * @param {boolean} [doSafe] - (Optional) Should `textContent` be used instead of `innerHTML` to avoid XSS? False by default
-   * @since 0.24.2
-   */
-  updateInnerHTML(id, html, doSafe=false) {
-
-    const element = document.getElementById(id.replace(/^#/, '')); // Retrieve the element from the 'id' (removed the '#')
-    
-    if (!element) {return;} // Kills itself if the element does not exist
-
-    // Input elements don't have innerHTML, so we modify the value attribute instead
-    if (element instanceof HTMLInputElement) {
-      element.value = html;
-      return;
-    } 
-
-    if (doSafe) {
-      element.textContent = html; // Populate element with plain-text HTML/text
-    } else {
-      element.innerHTML = html; // Populate element with HTML/text
-    }
-  }
-
-  /** Handles dragging of the overlay.
-   * Uses requestAnimationFrame for smooth animations and GPU-accelerated transforms.
-   * @param {string} moveMe - The ID of the element to be moved
-   * @param {string} iMoveThings - The ID of the drag handle element
-   * @since 0.8.2
-  */
-  handleDrag(moveMe, iMoveThings) {
-    let isDragging = false;
-    let offsetX, offsetY = 0;
-    let animationFrame = null;
-    let currentX = 0;
-    let currentY = 0;
-    let targetX = 0;
-    let targetY = 0;
-
-    // Retrieves the elements (allows either '#id' or 'id' to be passed in)
-    moveMe = document.querySelector(moveMe?.[0] == '#' ? moveMe : '#' + moveMe);
-    iMoveThings = document.querySelector(iMoveThings?.[0] == '#' ? iMoveThings : '#' + iMoveThings);
-
-    // What to do when one of the two elements are not found
-    if (!moveMe || !iMoveThings) {
-      this.handleDisplayError(`Can not drag! ${!moveMe ? 'moveMe' : ''} ${!moveMe && !iMoveThings ? 'and ' : ''}${!iMoveThings ? 'iMoveThings ' : ''}was not found!`);
-      return; // Kills itself
-    }
-
-    // Smooth animation loop using requestAnimationFrame for optimal performance
-    const updatePosition = () => {
-      if (isDragging) {
-        // Only update DOM if position changed significantly (reduce repaints)
-        const deltaX = Math.abs(currentX - targetX);
-        const deltaY = Math.abs(currentY - targetY);
-        
-        if (deltaX > 0.5 || deltaY > 0.5) {
-          currentX = targetX;
-          currentY = targetY;
-          
-          // Use CSS transform for GPU acceleration instead of left/top
-          moveMe.style.transform = `translate(${currentX}px, ${currentY}px)`;
-          moveMe.style.left = '0px';
-          moveMe.style.top = '0px';
-          moveMe.style.right = '';
-        }
-        
-        animationFrame = requestAnimationFrame(updatePosition);
-      }
-    };
-
-    // Cache initial position to avoid expensive getBoundingClientRect calls during drag
-    let initialRect = null;
-    
-    const startDrag = (clientX, clientY) => {
-      isDragging = true;
-      initialRect = moveMe.getBoundingClientRect();
-      offsetX = clientX - initialRect.left;
-      offsetY = clientY - initialRect.top;
-      
-      // Get current position from transform or use element position
-      const computedStyle = window.getComputedStyle(moveMe);
-      const transform = computedStyle.transform;
-      
-      if (transform && transform !== 'none') {
-        const matrix = new DOMMatrix(transform);
-        currentX = matrix.m41;
-        currentY = matrix.m42;
-      } else {
-        currentX = initialRect.left;
-        currentY = initialRect.top;
-      }
-      
-      targetX = currentX;
-      targetY = currentY;
-      
-      document.body.style.userSelect = 'none';
-      iMoveThings.classList.add('dragging');
-      
-      // Start animation loop
-      if (animationFrame) {
-        cancelAnimationFrame(animationFrame);
-      }
-      updatePosition();
-    };
-
-    const endDrag = () => {
-      isDragging = false;
-      if (animationFrame) {
-        cancelAnimationFrame(animationFrame);
-        animationFrame = null;
-      }
-      document.body.style.userSelect = '';
-      iMoveThings.classList.remove('dragging');
-    };
-
-    // Mouse down - start dragging
-    iMoveThings.addEventListener('mousedown', function(event) {
-      event.preventDefault();
-      startDrag(event.clientX, event.clientY);
-    });
-
-    // Touch start - start dragging
-    iMoveThings.addEventListener('touchstart', function(event) {
-      const touch = event?.touches?.[0];
-      if (!touch) {return;}
-      startDrag(touch.clientX, touch.clientY);
-      event.preventDefault();
-    }, { passive: false });
-
-    // Mouse move - update target position
-    document.addEventListener('mousemove', function(event) {
-      if (isDragging && initialRect) {
-        targetX = event.clientX - offsetX;
-        targetY = event.clientY - offsetY;
-      }
-    }, { passive: true });
-
-    // Touch move - update target position
-    document.addEventListener('touchmove', function(event) {
-      if (isDragging && initialRect) {
-        const touch = event?.touches?.[0];
-        if (!touch) {return;}
-        targetX = touch.clientX - offsetX;
-        targetY = touch.clientY - offsetY;
-        event.preventDefault();
-      }
-    }, { passive: false });
-
-    // End drag events
-    document.addEventListener('mouseup', endDrag);
-    document.addEventListener('touchend', endDrag);
-    document.addEventListener('touchcancel', endDrag);
-  }
-
-  /** Handles status display.
-   * This will output plain text into the output Status box.
-   * Additionally, this will output an info message to the console.
-   * @param {string} text - The status text to display.
-   * @since 0.58.4
-   */
-  handleDisplayStatus(text) {
-    const consoleInfo = console.info; // Creates a copy of the console.info function
-    consoleInfo(`${this.name}: ${text}`); // Outputs something like "ScriptName: text" as an info message to the console
-    this.updateInnerHTML(this.outputStatusId, 'Status: ' + text, true); // Update output Status box
-  }
-
-  /** Handles error display.
-   * This will output plain text into the output Status box.
-   * Additionally, this will output an error to the console.
-   * @param {string} text - The error text to display.
-   * @since 0.41.6
-   */
-  handleDisplayError(text) {
-    const consoleError = console.error; // Creates a copy of the console.error function
-    consoleError(`${this.name}: ${text}`); // Outputs something like "ScriptName: text" as an error message to the console
-    this.updateInnerHTML(this.outputStatusId, 'Error: ' + text, true); // Update output Status box
-  }
-}
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/Template.js.html b/docs/Template.js.html deleted file mode 100644 index 74ed730..0000000 --- a/docs/Template.js.html +++ /dev/null @@ -1,230 +0,0 @@ - - - - - JSDoc: Source: Template.js - - - - - - - - - - -
- -

Source: Template.js

- - - - - - -
-
-
import { uint8ToBase64 } from "./utils";
-
-/** An instance of a template.
- * Handles all mathematics, manipulation, and analysis regarding a single template.
- * @since 0.65.2
- */
-export default class Template {
-
-  /** The constructor for the {@link Template} class with enhanced pixel tracking.
-   * @param {Object} [params={}] - Object containing all optional parameters
-   * @param {string} [params.displayName='My template'] - The display name of the template
-   * @param {number} [params.sortID=0] - The sort number of the template for rendering priority
-   * @param {string} [params.authorID=''] - The user ID of the person who exported the template (prevents sort ID collisions)
-   * @param {string} [params.url=''] - The URL to the source image
-   * @param {File} [params.file=null] - The template file (pre-processed File or processed bitmap)
-   * @param {Array<number>} [params.coords=null] - The coordinates of the top left corner as (tileX, tileY, pixelX, pixelY)
-   * @param {Object} [params.chunked=null] - The affected chunks of the template, and their template for each chunk
-   * @param {number} [params.tileSize=1000] - The size of a tile in pixels (assumes square tiles)
-   * @param {number} [params.pixelCount=0] - Total number of pixels in the template (calculated automatically during processing)
-   * @since 0.65.2
-   */
-  constructor({
-    displayName = 'My template',
-    sortID = 0,
-    authorID = '',
-    url = '',
-    file = null,
-    coords = null,
-    chunked = null,
-    tileSize = 1000,
-  } = {}) {
-    this.displayName = displayName;
-    this.sortID = sortID;
-    this.authorID = authorID;
-    this.url = url;
-    this.file = file;
-    this.coords = coords;
-    this.chunked = chunked;
-    this.tileSize = tileSize;
-    this.pixelCount = 0; // Total pixel count in template
-  }
-
-  /** Creates chunks of the template for each tile.
-   * 
-   * @returns {Object} Collection of template bitmaps & buffers organized by tile coordinates
-   * @since 0.65.4
-   */
-  async createTemplateTiles() {
-    console.log('Template coordinates:', this.coords);
-
-    const shreadSize = 3; // Scale image factor for pixel art enhancement (must be odd)
-    const bitmap = await createImageBitmap(this.file); // Create efficient bitmap from uploaded file
-    const imageWidth = bitmap.width;
-    const imageHeight = bitmap.height;
-    
-    // Calculate total pixel count using standard width × height formula
-    // TODO: Use non-transparent pixels instead of basic width times height
-    const totalPixels = imageWidth * imageHeight;
-    console.log(`Template pixel analysis - Dimensions: ${imageWidth}×${imageHeight} = ${totalPixels.toLocaleString()} pixels`);
-    
-    // Store pixel count in instance property for access by template manager and UI components
-    this.pixelCount = totalPixels;
-
-    const templateTiles = {}; // Holds the template tiles
-    const templateTilesBuffers = {}; // Holds the buffers of the template tiles
-
-    const canvas = new OffscreenCanvas(this.tileSize, this.tileSize);
-    const context = canvas.getContext('2d', { willReadFrequently: true });
-
-    // For every tile...
-    for (let pixelY = this.coords[3]; pixelY < imageHeight + this.coords[3]; ) {
-
-      // Draws the partial tile first, if any
-      // This calculates the size based on which is smaller:
-      // A. The top left corner of the current tile to the bottom right corner of the current tile
-      // B. The top left corner of the current tile to the bottom right corner of the image
-      const drawSizeY = Math.min(this.tileSize - (pixelY % this.tileSize), imageHeight - (pixelY - this.coords[3]));
-
-      console.log(`Math.min(${this.tileSize} - (${pixelY} % ${this.tileSize}), ${imageHeight} - (${pixelY - this.coords[3]}))`);
-
-      for (let pixelX = this.coords[2]; pixelX < imageWidth + this.coords[2];) {
-
-        console.log(`Pixel X: ${pixelX}\nPixel Y: ${pixelY}`);
-
-        // Draws the partial tile first, if any
-        // This calculates the size based on which is smaller:
-        // A. The top left corner of the current tile to the bottom right corner of the current tile
-        // B. The top left corner of the current tile to the bottom right corner of the image
-        const drawSizeX = Math.min(this.tileSize - (pixelX % this.tileSize), imageWidth - (pixelX - this.coords[2]));
-
-        console.log(`Math.min(${this.tileSize} - (${pixelX} % ${this.tileSize}), ${imageWidth} - (${pixelX - this.coords[2]}))`);
-
-        console.log(`Draw Size X: ${drawSizeX}\nDraw Size Y: ${drawSizeY}`);
-
-        // Change the canvas size and wipe the canvas
-        const canvasWidth = drawSizeX * shreadSize;// + (pixelX % this.tileSize) * shreadSize;
-        const canvasHeight = drawSizeY * shreadSize;// + (pixelY % this.tileSize) * shreadSize;
-        canvas.width = canvasWidth;
-        canvas.height = canvasHeight;
-
-        console.log(`Draw X: ${drawSizeX}\nDraw Y: ${drawSizeY}\nCanvas Width: ${canvasWidth}\nCanvas Height: ${canvasHeight}`);
-
-        context.imageSmoothingEnabled = false; // Nearest neighbor
-
-        console.log(`Getting X ${pixelX}-${pixelX + drawSizeX}\nGetting Y ${pixelY}-${pixelY + drawSizeY}`);
-
-        // Draws the template segment on this tile segment
-        context.clearRect(0, 0, canvasWidth, canvasHeight); // Clear any previous drawing (only runs when canvas size does not change)
-        context.drawImage(
-          bitmap, // Bitmap image to draw
-          pixelX - this.coords[2], // Coordinate X to draw from
-          pixelY - this.coords[3], // Coordinate Y to draw from
-          drawSizeX, // X width to draw from
-          drawSizeY, // Y height to draw from
-          0, // Coordinate X to draw at
-          0, // Coordinate Y to draw at
-          drawSizeX * shreadSize, // X width to draw at
-          drawSizeY * shreadSize // Y height to draw at
-        ); // Coordinates and size of draw area of source image, then canvas
-
-        // const final = await canvas.convertToBlob({ type: 'image/png' });
-        // const url = URL.createObjectURL(final); // Creates a blob URL
-        // window.open(url, '_blank'); // Opens a new tab with blob
-        // setTimeout(() => URL.revokeObjectURL(url), 60000); // Destroys the blob 1 minute later
-
-        const imageData = context.getImageData(0, 0, canvasWidth, canvasHeight); // Data of the image on the canvas
-
-        for (let y = 0; y < canvasHeight; y++) {
-          for (let x = 0; x < canvasWidth; x++) {
-            // For every pixel...
-
-            // ... Make it transparent unless it is the "center"
-            if (x % shreadSize !== 1 || y % shreadSize !== 1) {
-              const pixelIndex = (y * canvasWidth + x) * 4; // Find the pixel index in an array where every 4 indexes are 1 pixel
-              imageData.data[pixelIndex + 3] = 0; // Make the pixel transparent on the alpha channel
-
-              // if (!!imageData.data[pixelIndex + 3]) {
-              //   imageData.data[pixelIndex + 3] = 50; // Alpha
-              //   imageData.data[pixelIndex] = 30; // Red
-              //   imageData.data[pixelIndex + 1] = 30; // Green
-              //   imageData.data[pixelIndex + 2] = 30; // Blue
-              // }
-            }
-          }
-        }
-
-        console.log(`Shreaded pixels for ${pixelX}, ${pixelY}`, imageData);
-
-        context.putImageData(imageData, 0, 0);
-
-        // Creates the "0000,0000,000,000" key name
-        const templateTileName = `${(this.coords[0] + Math.floor(pixelX / 1000))
-          .toString()
-          .padStart(4, '0')},${(this.coords[1] + Math.floor(pixelY / 1000))
-          .toString()
-          .padStart(4, '0')},${(pixelX % 1000)
-          .toString()
-          .padStart(3, '0')},${(pixelY % 1000).toString().padStart(3, '0')}`;
-
-        templateTiles[templateTileName] = await createImageBitmap(canvas); // Creates the bitmap
-        
-        const canvasBlob = await canvas.convertToBlob();
-        const canvasBuffer = await canvasBlob.arrayBuffer();
-        const canvasBufferBytes = Array.from(new Uint8Array(canvasBuffer));
-        templateTilesBuffers[templateTileName] = uint8ToBase64(canvasBufferBytes); // Stores the buffer
-
-        console.log(templateTiles);
-
-        pixelX += drawSizeX;
-      }
-
-      pixelY += drawSizeY;
-    }
-
-    console.log('Template Tiles: ', templateTiles);
-    console.log('Template Tiles Buffers: ', templateTilesBuffers);
-    return { templateTiles, templateTilesBuffers };
-  }
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/apiManager.js.html b/docs/apiManager.js.html deleted file mode 100644 index b709c82..0000000 --- a/docs/apiManager.js.html +++ /dev/null @@ -1,193 +0,0 @@ - - - - - JSDoc: Source: apiManager.js - - - - - - - - - - -
- -

Source: apiManager.js

- - - - - - -
-
-
/** ApiManager class for handling API requests, responses, and interactions.
- * Note: Fetch spying is done in main.js, not here.
- * @since 0.11.1
- */
-
-import TemplateManager from "./templateManager.js";
-import { escapeHTML, numberToEncoded, serverTPtoDisplayTP } from "./utils.js";
-
-export default class ApiManager {
-
-  /** Constructor for ApiManager class
-   * @param {TemplateManager} templateManager 
-   * @since 0.11.34
-   */
-  constructor(templateManager) {
-    this.templateManager = templateManager;
-    this.disableAll = false; // Should the entire userscript be disabled?
-    this.coordsTilePixel = []; // Contains the last detected tile/pixel coordinate pair requested
-    this.templateCoordsTilePixel = []; // Contains the last "enabled" template coords
-  }
-
-  /** Determines if the spontaneously recieved response is something we want.
-   * Otherwise, we can ignore it.
-   * Note: Due to aggressive compression, make your calls like `data['jsonData']['name']` instead of `data.jsonData.name`
-   * 
-   * @param {Overlay} overlay - The Overlay class instance
-   * @since 0.11.1
-  */
-  spontaneousResponseListener(overlay) {
-
-    // Triggers whenever a message is sent
-    window.addEventListener('message', async (event) => {
-
-      const data = event.data; // The data of the message
-      const dataJSON = data['jsonData']; // The JSON response, if any
-
-      // Kills itself if the message was not intended for Blue Marble
-      if (!(data && data['source'] === 'blue-marble')) {return;}
-
-      // Kills itself if the message has no endpoint (intended for Blue Marble, but not this function)
-      if (!data['endpoint']) {return;}
-
-      // Trims endpoint to the second to last non-number, non-null directoy.
-      // E.g. "wplace.live/api/pixel/0/0?payload" -> "pixel"
-      // E.g. "wplace.live/api/files/s0/tiles/0/0/0.png" -> "tiles"
-      const endpointText = data['endpoint']?.split('?')[0].split('/').filter(s => s && isNaN(Number(s))).filter(s => s && !s.includes('.')).pop();
-
-      console.log(`%cBlue Marble%c: Recieved message about "%s"`, 'color: cornflowerblue;', '', endpointText);
-
-      // Each case is something that Blue Marble can use from the fetch.
-      // For instance, if the fetch was for "me", we can update the overlay stats
-      switch (endpointText) {
-
-        case 'me': // Request to retrieve user data
-
-          // If the game can not retrieve the userdata...
-          if (dataJSON['status'] && dataJSON['status']?.toString()[0] != '2') {
-            // The server is probably down (NOT a 2xx status)
-            
-            overlay.handleDisplayError(`You are not logged in!\nCould not fetch userdata.`);
-            return; // Kills itself before attempting to display null userdata
-          }
-
-          const nextLevelPixels = Math.ceil(Math.pow(Math.floor(dataJSON['level']) * Math.pow(30, 0.65), (1/0.65)) - dataJSON['pixelsPainted']); // Calculates pixels to the next level
-
-          console.log(dataJSON['id']);
-          if (!!dataJSON['id'] || dataJSON['id'] === 0) {
-            console.log(numberToEncoded(
-              dataJSON['id'],
-              '!#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~'
-            ));
-          }
-          this.templateManager.userID = dataJSON['id'];
-          
-          overlay.updateInnerHTML('bm-user-name', `Username: <b>${escapeHTML(dataJSON['name'])}</b>`); // Updates the text content of the username field
-          overlay.updateInnerHTML('bm-user-droplets', `Droplets: <b>${new Intl.NumberFormat().format(dataJSON['droplets'])}</b>`); // Updates the text content of the droplets field
-          overlay.updateInnerHTML('bm-user-nextlevel', `Next level in <b>${new Intl.NumberFormat().format(nextLevelPixels)}</b> pixel${nextLevelPixels == 1 ? '' : 's'}`); // Updates the text content of the next level field
-          break;
-
-        case 'pixel': // Request to retrieve pixel data
-          const coordsTile = data['endpoint'].split('?')[0].split('/').filter(s => s && !isNaN(Number(s))); // Retrieves the tile coords as [x, y]
-          const payloadExtractor = new URLSearchParams(data['endpoint'].split('?')[1]); // Declares a new payload deconstructor and passes in the fetch request payload
-          const coordsPixel = [payloadExtractor.get('x'), payloadExtractor.get('y')]; // Retrieves the deconstructed pixel coords from the payload
-          
-          // Don't save the coords if there are previous coords that could be used
-          if (this.coordsTilePixel.length && (!coordsTile.length || !coordsPixel.length)) {
-            overlay.handleDisplayError(`Coordinates are malformed!\nDid you try clicking the canvas first?`);
-            return; // Kills itself
-          }
-          
-          this.coordsTilePixel = [...coordsTile, ...coordsPixel]; // Combines the two arrays such that [x, y, x, y]
-          const displayTP = serverTPtoDisplayTP(coordsTile, coordsPixel);
-          
-          const spanElements = document.querySelectorAll('span'); // Retrieves all span elements
-
-          // For every span element, find the one we want (pixel numbers when canvas clicked)
-          for (const element of spanElements) {
-            if (element.textContent.trim().includes(`${displayTP[0]}, ${displayTP[1]}`)) {
-
-              let displayCoords = document.querySelector('#bm-display-coords'); // Find the additional pixel coords span
-
-              const text = `(Tl X: ${coordsTile[0]}, Tl Y: ${coordsTile[1]}, Px X: ${coordsPixel[0]}, Px Y: ${coordsPixel[1]})`;
-              
-              // If we could not find the addition coord span, we make it then update the textContent with the new coords
-              if (!displayCoords) {
-                displayCoords = document.createElement('span');
-                displayCoords.id = 'bm-display-coords';
-                displayCoords.textContent = text;
-                displayCoords.style = 'margin-left: calc(var(--spacing)*3); font-size: small;';
-                element.parentNode.parentNode.parentNode.insertAdjacentElement('afterend', displayCoords);
-              } else {
-                displayCoords.textContent = text;
-              }
-            }
-          }
-          break;
-        
-        case 'tiles':
-
-          // Runs only if the tile has the template
-          let tileCoordsTile = data['endpoint'].split('/');
-          tileCoordsTile = [parseInt(tileCoordsTile[tileCoordsTile.length - 2]), parseInt(tileCoordsTile[tileCoordsTile.length - 1].replace('.png', ''))];
-          
-          const blobUUID = data['blobID'];
-          const blobData = data['blobData'];
-          
-          const templateBlob = await this.templateManager.drawTemplateOnTile(blobData, tileCoordsTile);
-
-          window.postMessage({
-            source: 'blue-marble',
-            blobID: blobUUID,
-            blobData: templateBlob,
-            blink: data['blink']
-          });
-          break;
-
-        case 'robots': // Request to retrieve what script types are allowed
-          this.disableAll = dataJSON['userscript']?.toString().toLowerCase() == 'false'; // Disables Blue Marble if site owner wants userscripts disabled
-          break;
-      }
-    });
-  }
-}
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/fonts/OpenSans-Bold-webfont.eot b/docs/fonts/OpenSans-Bold-webfont.eot deleted file mode 100644 index 5d20d91..0000000 Binary files a/docs/fonts/OpenSans-Bold-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Bold-webfont.svg b/docs/fonts/OpenSans-Bold-webfont.svg deleted file mode 100644 index 3ed7be4..0000000 --- a/docs/fonts/OpenSans-Bold-webfont.svg +++ /dev/null @@ -1,1830 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Bold-webfont.woff b/docs/fonts/OpenSans-Bold-webfont.woff deleted file mode 100644 index 1205787..0000000 Binary files a/docs/fonts/OpenSans-Bold-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.eot b/docs/fonts/OpenSans-BoldItalic-webfont.eot deleted file mode 100644 index 1f639a1..0000000 Binary files a/docs/fonts/OpenSans-BoldItalic-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.svg b/docs/fonts/OpenSans-BoldItalic-webfont.svg deleted file mode 100644 index 6a2607b..0000000 --- a/docs/fonts/OpenSans-BoldItalic-webfont.svg +++ /dev/null @@ -1,1830 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.woff b/docs/fonts/OpenSans-BoldItalic-webfont.woff deleted file mode 100644 index ed760c0..0000000 Binary files a/docs/fonts/OpenSans-BoldItalic-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-Italic-webfont.eot b/docs/fonts/OpenSans-Italic-webfont.eot deleted file mode 100644 index 0c8a0ae..0000000 Binary files a/docs/fonts/OpenSans-Italic-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Italic-webfont.svg b/docs/fonts/OpenSans-Italic-webfont.svg deleted file mode 100644 index e1075dc..0000000 --- a/docs/fonts/OpenSans-Italic-webfont.svg +++ /dev/null @@ -1,1830 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Italic-webfont.woff b/docs/fonts/OpenSans-Italic-webfont.woff deleted file mode 100644 index ff652e6..0000000 Binary files a/docs/fonts/OpenSans-Italic-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-Light-webfont.eot b/docs/fonts/OpenSans-Light-webfont.eot deleted file mode 100644 index 1486840..0000000 Binary files a/docs/fonts/OpenSans-Light-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Light-webfont.svg b/docs/fonts/OpenSans-Light-webfont.svg deleted file mode 100644 index 11a472c..0000000 --- a/docs/fonts/OpenSans-Light-webfont.svg +++ /dev/null @@ -1,1831 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Light-webfont.woff b/docs/fonts/OpenSans-Light-webfont.woff deleted file mode 100644 index e786074..0000000 Binary files a/docs/fonts/OpenSans-Light-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-LightItalic-webfont.eot b/docs/fonts/OpenSans-LightItalic-webfont.eot deleted file mode 100644 index 8f44592..0000000 Binary files a/docs/fonts/OpenSans-LightItalic-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-LightItalic-webfont.svg b/docs/fonts/OpenSans-LightItalic-webfont.svg deleted file mode 100644 index 431d7e3..0000000 --- a/docs/fonts/OpenSans-LightItalic-webfont.svg +++ /dev/null @@ -1,1835 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-LightItalic-webfont.woff b/docs/fonts/OpenSans-LightItalic-webfont.woff deleted file mode 100644 index 43e8b9e..0000000 Binary files a/docs/fonts/OpenSans-LightItalic-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-Regular-webfont.eot b/docs/fonts/OpenSans-Regular-webfont.eot deleted file mode 100644 index 6bbc3cf..0000000 Binary files a/docs/fonts/OpenSans-Regular-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Regular-webfont.svg b/docs/fonts/OpenSans-Regular-webfont.svg deleted file mode 100644 index 25a3952..0000000 --- a/docs/fonts/OpenSans-Regular-webfont.svg +++ /dev/null @@ -1,1831 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Regular-webfont.woff b/docs/fonts/OpenSans-Regular-webfont.woff deleted file mode 100644 index e231183..0000000 Binary files a/docs/fonts/OpenSans-Regular-webfont.woff and /dev/null differ diff --git a/docs/global.html b/docs/global.html deleted file mode 100644 index ca35bc1..0000000 --- a/docs/global.html +++ /dev/null @@ -1,7664 +0,0 @@ - - - - - JSDoc: Global - - - - - - - - - - -
- -

Global

- - - - - - -
- -
- -

- - -
- -
-
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

addBr(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a `br` to the overlay. This `br` element will have properties shared between all `br` elements in the overlay. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the `br` that are NOT shared between all overlay `br` elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the `br`.
- - - - - - -
- - - - -
Since:
-
  • 0.43.11
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all <br> elements have a shared class (e.g. {'className': 'bar'})
overlay.addbr({'id': 'foo'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <br id="foo" class="bar">
</body>
- - - - - - - - - -

addButton(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a `button` to the overlay. This `button` element will have properties shared between all `button` elements in the overlay. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the `button` that are NOT shared between all overlay `button` elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the `button`.
- - - - - - -
- - - - -
Since:
-
  • 0.43.12
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all <button> elements have a shared class (e.g. {'className': 'bar'})
overlay.addButton({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <button id="foo" class="bar">Foobar.</button>
</body>
- - - - - - - - - -

addButtonHelp(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a help button to the overlay. It will have a "?" icon unless overridden in callback. On click, the button will attempt to output the title to the output element (ID defined in Overlay constructor). This `button` element will have properties shared between all `button` elements in the overlay. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the `button` that are NOT shared between all overlay `button` elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the `button`.
- - - - - - -
- - - - -
Since:
-
  • 0.43.12
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Examples
- -
// Assume all help button elements have a shared class (e.g. {'className': 'bar'})
overlay.addButtonHelp({'id': 'foo', 'title': 'Foobar.'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <button id="foo" class="bar" title="Help: Foobar.">?</button>
</body>
- -
// Assume all help button elements have a shared class (e.g. {'className': 'bar'})
overlay.addButtonHelp({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <button id="foo" class="bar" title="Help: Foobar.">?</button>
</body>
- - - - - - - - - -

addCheckbox(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a checkbox to the overlay. This checkbox element will have properties shared between all checkbox elements in the overlay. You can override the shared properties by using a callback. Note: the checkbox element is inside a label element. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the checkbox that are NOT shared between all overlay checkbox elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the checkbox.
- - - - - - -
- - - - -
Since:
-
  • 0.43.10
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all checkbox elements have a shared class (e.g. {'className': 'bar'})
overlay.addCheckbox({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <label>
    <input type="checkbox" id="foo" class="bar">
    "Foobar."
  </label>
</body>
- - - - - - - - - -

addDiv(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a `div` to the overlay. This `div` element will have properties shared between all `div` elements in the overlay. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the `div` that are NOT shared between all overlay `div` elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the `div`.
- - - - - - -
- - - - -
Since:
-
  • 0.43.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all <div> elements have a shared class (e.g. {'className': 'bar'})
overlay.addDiv({'id': 'foo'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <div id="foo" class="bar"></div>
</body>
- - - - - - - - - -

addHeader(level, additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a header to the overlay. This header element will have properties shared between all header elements in the overlay. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
level - - -number - - - - - - - - - - - - The header level. Must be between 1 and 6 (inclusive)
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the header that are NOT shared between all overlay header elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the header.
- - - - - - -
- - - - -
Since:
-
  • 0.43.7
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all header elements have a shared class (e.g. {'className': 'bar'})
overlay.addHeader(6, {'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <h6 id="foo" class="bar">Foobar.</h6>
</body>
- - - - - - - - - -

addHr(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a `hr` to the overlay. This `hr` element will have properties shared between all `hr` elements in the overlay. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the `hr` that are NOT shared between all overlay `hr` elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the `hr`.
- - - - - - -
- - - - -
Since:
-
  • 0.43.7
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all <hr> elements have a shared class (e.g. {'className': 'bar'})
overlay.addhr({'id': 'foo'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <hr id="foo" class="bar">
</body>
- - - - - - - - - -

addImg(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a `img` to the overlay. This `img` element will have properties shared between all `img` elements in the overlay. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the `img` that are NOT shared between all overlay `img` elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the `img`.
- - - - - - -
- - - - -
Since:
-
  • 0.43.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all <img> elements have a shared class (e.g. {'className': 'bar'})
overlay.addimg({'id': 'foo', 'src': './img.png'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <img id="foo" src="./img.png" class="bar">
</body>
- - - - - - - - - -

addInput(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a `input` to the overlay. This `input` element will have properties shared between all `input` elements in the overlay. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the `input` that are NOT shared between all overlay `input` elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the `input`.
- - - - - - -
- - - - -
Since:
-
  • 0.43.13
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all <input> elements have a shared class (e.g. {'className': 'bar'})
overlay.addInput({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <input id="foo" class="bar">Foobar.</input>
</body>
- - - - - - - - - -

addInputFile(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a file input to the overlay with enhanced visibility controls. This input element will have properties shared between all file input elements in the overlay. Uses multiple hiding methods to prevent browser native text from appearing during minimize/maximize. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the file input that are NOT shared between all overlay file input elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the file input.
- - - - - - -
- - - - -
Since:
-
  • 0.43.17
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all file input elements have a shared class (e.g. {'className': 'bar'})
overlay.addInputFile({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <div>
    <input type="file" id="foo" class="bar" style="display: none"></input>
    <button>Foobar.</button>
  </div>
</body>
- - - - - - - - - -

addP(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a `p` to the overlay. This `p` element will have properties shared between all `p` elements in the overlay. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the `p` that are NOT shared between all overlay `p` elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the `p`.
- - - - - - -
- - - - -
Since:
-
  • 0.43.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all <p> elements have a shared class (e.g. {'className': 'bar'})
overlay.addP({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <p id="foo" class="bar">Foobar.</p>
</body>
- - - - - - - - - -

addSmall(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a `small` to the overlay. This `small` element will have properties shared between all `small` elements in the overlay. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the `small` that are NOT shared between all overlay `small` elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the `small`.
- - - - - - -
- - - - -
Since:
-
  • 0.55.8
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all <small> elements have a shared class (e.g. {'className': 'bar'})
overlay.addSmall({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <small id="foo" class="bar">Foobar.</small>
</body>
- - - - - - - - - -

addTextarea(additionalPropertiesopt, callbackopt) → {Overlay}

- - - - - - -
- Adds a `textarea` to the overlay. This `textarea` element will have properties shared between all `textarea` elements in the overlay. You can override the shared properties by using a callback. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
additionalProperties - - -Object.<string, any> - - - - - - <optional>
- - - - - -
- - {} - - The DOM properties of the `textarea` that are NOT shared between all overlay `textarea` elements. These should be camelCase.
callback - - -function - - - - - - <optional>
- - - - - -
- - ()=>{} - - Additional JS modification to the `textarea`.
- - - - - - -
- - - - -
Since:
-
  • 0.43.13
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
// Assume all <textarea> elements have a shared class (e.g. {'className': 'bar'})
overlay.addTextarea({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <textarea id="foo" class="bar">Foobar.</textarea>
</body>
- - - - - - - - - -

base64ToUint8(base64) → {Uint8Array}

- - - - - - -
- Decodes a base 64 encoded Uint8 array using the browser's built-in ASCII to binary function -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
base64 - - -Uint8Array - - - - The base 64 encoded Uint8Array to convert
- - - - - - -
- - - - -
Since:
-
  • 0.72.9
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- The decoded Uint8Array -
- - - -
-
- Type -
-
- -Uint8Array - - -
-
- - - - - - - - - - - - - -

buildElement() → {Overlay}

- - - - - - -
- Finishes building an element. Call this after you are finished adding children. If the element will have no children, call it anyways. -
- - - - - - - - - - - - - -
- - - - -
Since:
-
  • 0.43.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Overlay class instance (this) -
- - - -
-
- Type -
-
- -Overlay - - -
-
- - - - - - -
Example
- -
overlay
  .addDiv()
    .addHeader(1).buildElement() // Breaks out of the <h1>
    .addP().buildElement() // Breaks out of the <p>
  .buildElement() // Breaks out of the <div>
  .addHr() // Since there are no more elements, calling buildElement() is optional
.buildOverlay(document.body);
- - - - - - - - - -

buildOverlay(parent)

- - - - - - -
- Finishes building the overlay and displays it. Call this when you are done chaining methods. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
parent - - -HTMLElement - - - - The parent HTMLElement this overlay should be appended to as a child.
- - - - - - -
- - - - -
Since:
-
  • 0.43.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Example
- -
overlay
  .addDiv()
    .addP().buildElement()
  .buildElement()
.buildOverlay(document.body); // Adds DOM structure to document body
// <div><p></p></div>
- - - - - - - - - -

buildOverlayMain()

- - - - - - -
- Deploys the overlay to the page with minimize/maximize functionality. Creates a responsive overlay UI that can toggle between full-featured and minimized states. Parent/child relationships in the DOM structure below are indicated by indentation. -
- - - - - - - - - - - - - -
- - - - -
Since:
-
  • 0.58.3
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

consoleError(…args)

- - - - - - -
- Bypasses terser's stripping of console function calls. This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't. However, the distributed version needs to call the console somehow, so this wrapper function is how. This is the same as `console.error()`. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDescription
args - - -any - - - - - - - - - - <repeatable>
- -
Arguments to be passed into the `error()` function of the Console
- - - - - - -
- - - - -
Since:
-
  • 0.58.13
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

consoleLog(…args)

- - - - - - -
- Bypasses terser's stripping of console function calls. This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't. However, the distributed version needs to call the console somehow, so this wrapper function is how. This is the same as `console.log()`. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDescription
args - - -any - - - - - - - - - - <repeatable>
- -
Arguments to be passed into the `log()` function of the Console
- - - - - - -
- - - - -
Since:
-
  • 0.58.9
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

consoleWarn(…args)

- - - - - - -
- Bypasses terser's stripping of console function calls. This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't. However, the distributed version needs to call the console somehow, so this wrapper function is how. This is the same as `console.warn()`. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDescription
args - - -any - - - - - - - - - - <repeatable>
- -
Arguments to be passed into the `warn()` function of the Console
- - - - - - -
- - - - -
Since:
-
  • 0.58.13
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) createJSON() → {Object}

- - - - - - -
- Creates the JSON object to store templates in -
- - - - - - - - - - - - - -
- - - - -
Since:
-
  • 0.65.4
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- The JSON object -
- - - -
-
- Type -
-
- -Object - - -
-
- - - - - - - - - - - - - -

createObserverBody(target) → {Observers}

- - - - - - -
- Creates the MutationObserver for document.body -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
target - - -HTMLElement - - - - Targeted element to watch
- - - - - - -
- - - - -
Since:
-
  • 0.43.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this (Observers class) -
- - - -
-
- Type -
-
- -Observers - - -
-
- - - - - - - - - - - - - -

(async) createTemplate(blob, name, coords)

- - - - - - -
- Creates the template from the inputed file blob -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blob - - -File - - - - The file blob to create a template from
name - - -string - - - - The display name of the template
coords - - -Array.<number, number, number, number> - - - - The coordinates of the top left corner of the template
- - - - - - -
- - - - -
Since:
-
  • 0.65.77
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) createTemplateTiles() → {Object}

- - - - - - -
- Creates chunks of the template for each tile. -
- - - - - - - - - - - - - -
- - - - -
Since:
-
  • 0.65.4
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Collection of template bitmaps & buffers organized by tile coordinates -
- - - -
-
- Type -
-
- -Object - - -
-
- - - - - - - - - - - - - -

deleteTemplate()

- - - - - - -
- Deletes a template from the JSON object. Also delete's the corrosponding Template class instance -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) disableTemplate()

- - - - - - -
- Disables the template from view -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) drawTemplateOnTile(tileBlob, tileCoords)

- - - - - - -
- Draws all templates on the specified tile. This method handles the rendering of template overlays on individual tiles. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tileBlob - - -File - - - - The pixels that are placed on a tile
tileCoords - - -Array.<number> - - - - The tile coordinates [x, y]
- - - - - - -
- - - - -
Since:
-
  • 0.65.77
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

escapeHTML(text) → {string}

- - - - - - -
- Sanitizes HTML to display as plain-text. This prevents some Cross Site Scripting (XSS). This is handy when you are displaying user-made data, and you *must* use innerHTML. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
text - - -string - - - - The text to sanitize
- - - - - - -
- - - - -
Since:
-
  • 0.44.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- HTML escaped string -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - -
Example
- -
const paragraph = document.createElement('p');
paragraph.innerHTML = escapeHTML('<u>Foobar.</u>');
// Output:
// (Does not include the paragraph element)
// (Output is not HTML formatted)
<p>
  "<u>Foobar.</u>"
</p>
- - - - - - - - - -

getObserverBody() → {MutationObserver}

- - - - - - -
- Retrieves the MutationObserver that watches document.body -
- - - - - - - - - - - - - -
- - - - -
Since:
-
  • 0.43.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -MutationObserver - - -
-
- - - - - - - - - - - - - -

handleDisplayError(text)

- - - - - - -
- Handles error display. This will output plain text into the output Status box. Additionally, this will output an error to the console. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
text - - -string - - - - The error text to display.
- - - - - - -
- - - - -
Since:
-
  • 0.41.6
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

handleDisplayStatus(text)

- - - - - - -
- Handles status display. This will output plain text into the output Status box. Additionally, this will output an info message to the console. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
text - - -string - - - - The status text to display.
- - - - - - -
- - - - -
Since:
-
  • 0.58.4
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

handleDrag(moveMe, iMoveThings)

- - - - - - -
- Handles dragging of the overlay. Uses requestAnimationFrame for smooth animations and GPU-accelerated transforms. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
moveMe - - -string - - - - The ID of the element to be moved
iMoveThings - - -string - - - - The ID of the drag handle element
- - - - - - -
- - - - -
Since:
-
  • 0.8.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

importJSON(json)

- - - - - - -
- Imports the JSON object, and appends it to any JSON object already loaded -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
json - - -string - - - - The JSON string to parse
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

inject(callback)

- - - - - - -
- Injects code into the client This code will execute outside of TamperMonkey's sandbox -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
callback - - -* - - - - The code to execute
- - - - - - -
- - - - -
Since:
-
  • 0.11.15
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

negativeSafeModulo(a, b) → {number}

- - - - - - -
- Negative-Safe Modulo. You can pass negative numbers into this. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
a - - -number - - - - The first number
b - - -number - - - - The second number
- - - - - - -
- - - - -
Since:
-
  • 0.55.8
- - - - - - - - - - - - - - - -
Author:
-
-
    -
  • osuplace
  • -
-
- - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Result -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

numberToEncoded(number, encoding) → {string}

- - - - - - -
- Encodes a number into a custom encoded string. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
number - - -number - - - - The number to encode
encoding - - -string - - - - The characters to use when encoding
- - - - - - -
- - - - -
Since:
-
  • 0.65.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Encoded string -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - -
Example
- -
const encode = '012abcABC'; // Base 9
console.log(numberToEncoded(0, encode)); // 0
console.log(numberToEncoded(5, encode)); // c
console.log(numberToEncoded(15, encode)); // 1A
console.log(numberToEncoded(12345, encode)); // 1BCaA
- - - - - - - - - -

observe(observer, watchChildList, watchSubtree)

- - - - - - -
- Observe a MutationObserver -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
observer - - -MutationObserver - - - - - - The MutationObserver
watchChildList - - -boolean - - - - - - false - - (Optional) Should childList be watched? False by default
watchSubtree - - -boolean - - - - - - false - - (Optional) Should childList be watched? False by default
- - - - - - -
- - - - -
Since:
-
  • 0.43.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

observeBlack()

- - - - - - -
- Observe the black color, and add the "Move" button. -
- - - - - - - - - - - - - -
- - - - -
Since:
-
  • 0.66.3
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

serverTPtoDisplayTP(tile, pixel) → {Array.<number>}

- - - - - - -
- Converts the server tile-pixel coordinate system to the displayed tile-pixel coordinate system. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tile - - -Array.<string> - - - - The tile to convert (as an array like ["12", "124"])
pixel - - -Array.<string> - - - - The pixel to convert (as an array like ["12", "124"])
- - - - - - -
- - - - -
Since:
-
  • 0.42.4
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- [tile, pixel] -
- - - -
-
- Type -
-
- -Array.<number> - - -
-
- - - - - - -
Example
- -
console.log(serverTPtoDisplayTP(['12', '123'], ['34', '567'])); // [34, 3567]
- - - - - - - - - -

setApiManager(apiManager)

- - - - - - -
- Populates the apiManager variable with the apiManager class. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
apiManager - - -apiManager - - - - The apiManager class instance
- - - - - - -
- - - - -
Since:
-
  • 0.41.4
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTemplatesShouldBeDrawn(value)

- - - - - - -
- Sets the `templatesShouldBeDrawn` boolean to a value. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
value - - -boolean - - - - The value to set the boolean to
- - - - - - -
- - - - -
Since:
-
  • 0.73.7
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

spontaneousResponseListener(overlay)

- - - - - - -
- Determines if the spontaneously recieved response is something we want. Otherwise, we can ignore it. Note: Due to aggressive compression, make your calls like `data['jsonData']['name']` instead of `data.jsonData.name` -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
overlay - - -Overlay - - - - The Overlay class instance
- - - - - - -
- - - - -
Since:
-
  • 0.11.1
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

uint8ToBase64(uint8) → {Uint8Array}

- - - - - - -
- Converts a Uint8 array to base64 using the browser's built-in binary to ASCII function -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uint8 - - -Uint8Array - - - - The Uint8Array to convert
- - - - - - -
- - - - -
Since:
-
  • 0.72.9
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- The base64 encoded Uint8Array -
- - - -
-
- Type -
-
- -Uint8Array - - -
-
- - - - - - - - - - - - - -

updateInnerHTML(id, html, doSafeopt)

- - - - - - -
- Updates the inner HTML of the element. The element is discovered by it's id. If the element is an `input`, it will modify the value attribute instead. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
id - - -string - - - - - - - - - - - - The ID of the element to change
html - - -string - - - - - - - - - - - - The HTML/text to update with
doSafe - - -boolean - - - - - - <optional>
- - - - - -
- - false - - (Optional) Should `textContent` be used instead of `innerHTML` to avoid XSS? False by default
- - - - - - -
- - - - -
Since:
-
  • 0.24.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 05835e2..0000000 --- a/docs/index.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - JSDoc: Home - - - - - - - - - - -
- -

Home

- - - - - - - - -

- - - - - - - - - - - - - - - - - - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/main.js.html b/docs/main.js.html deleted file mode 100644 index 9a70946..0000000 --- a/docs/main.js.html +++ /dev/null @@ -1,618 +0,0 @@ - - - - - JSDoc: Source: main.js - - - - - - - - - - -
- -

Source: main.js

- - - - - - -
-
-
/** The main file. Everything in the userscript is executed from here.
- * @since 0.0.0
- */
-
-import Overlay from './Overlay.js';
-import Observers from './observers.js';
-import ApiManager from './apiManager.js';
-import TemplateManager from './templateManager.js';
-import { consoleLog, consoleWarn } from './utils.js';
-
-const name = GM_info.script.name.toString(); // Name of userscript
-const version = GM_info.script.version.toString(); // Version of userscript
-const consoleStyle = 'color: cornflowerblue;'; // The styling for the console logs
-
-/** Injects code into the client
- * This code will execute outside of TamperMonkey's sandbox
- * @param {*} callback - The code to execute
- * @since 0.11.15
- */
-function inject(callback) {
-    const script = document.createElement('script');
-    script.setAttribute('bm-name', name); // Passes in the name value
-    script.setAttribute('bm-cStyle', consoleStyle); // Passes in the console style value
-    script.textContent = `(${callback})();`;
-    document.documentElement?.appendChild(script);
-    script.remove();
-}
-
-/** What code to execute instantly in the client (webpage) to spy on fetch calls.
- * This code will execute outside of TamperMonkey's sandbox.
- * @since 0.11.15
- */
-inject(() => {
-
-  const script = document.currentScript; // Gets the current script HTML Script Element
-  const name = script?.getAttribute('bm-name') || 'Blue Marble'; // Gets the name value that was passed in. Defaults to "Blue Marble" if nothing was found
-  const consoleStyle = script?.getAttribute('bm-cStyle') || ''; // Gets the console style value that was passed in. Defaults to no styling if nothing was found
-  const fetchedBlobQueue = new Map(); // Blobs being processed
-
-  window.addEventListener('message', (event) => {
-    const { source, endpoint, blobID, blobData, blink } = event.data;
-
-    const elapsed = Date.now() - blink;
-
-    // Since this code does not run in the userscript, we can't use consoleLog().
-    console.groupCollapsed(`%c${name}%c: ${fetchedBlobQueue.size} Recieved IMAGE message about blob "${blobID}"`, consoleStyle, '');
-    console.log(`Blob fetch took %c${String(Math.floor(elapsed/60000)).padStart(2,'0')}:${String(Math.floor(elapsed/1000) % 60).padStart(2,'0')}.${String(elapsed % 1000).padStart(3,'0')}%c MM:SS.mmm`, consoleStyle, '');
-    console.log(fetchedBlobQueue);
-    console.groupEnd();
-
-    // The modified blob won't have an endpoint, so we ignore any message without one.
-    if ((source == 'blue-marble') && !!blobID && !!blobData && !endpoint) {
-
-      const callback = fetchedBlobQueue.get(blobID); // Retrieves the blob based on the UUID
-
-      // If the blobID is a valid function...
-      if (typeof callback === 'function') {
-
-        callback(blobData); // ...Retrieve the blob data from the blobID function
-      } else {
-        // ...else the blobID is unexpected. We don't know what it is, but we know for sure it is not a blob. This means we ignore it.
-
-        consoleWarn(`%c${name}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`, consoleStyle, '', blobID);
-      }
-
-      fetchedBlobQueue.delete(blobID); // Delete the blob from the queue, because we don't need to process it again
-    }
-  });
-
-  // Spys on "spontaneous" fetch requests made by the client
-  const originalFetch = window.fetch; // Saves a copy of the original fetch
-
-  // Overrides fetch
-  window.fetch = async function(...args) {
-
-    const response = await originalFetch.apply(this, args); // Sends a fetch
-    const cloned = response.clone(); // Makes a copy of the response
-
-    // Retrieves the endpoint name. Unknown endpoint = "ignore"
-    const endpointName = ((args[0] instanceof Request) ? args[0]?.url : args[0]) || 'ignore';
-
-    // Check Content-Type to only process JSON
-    const contentType = cloned.headers.get('content-type') || '';
-    if (contentType.includes('application/json')) {
-
-
-      // Since this code does not run in the userscript, we can't use consoleLog().
-      console.log(`%c${name}%c: Sending JSON message about endpoint "${endpointName}"`, consoleStyle, '');
-
-      // Sends a message about the endpoint it spied on
-      cloned.json()
-        .then(jsonData => {
-          window.postMessage({
-            source: 'blue-marble',
-            endpoint: endpointName,
-            jsonData: jsonData
-          }, '*');
-        })
-        .catch(err => {
-          console.error(`%c${name}%c: Failed to parse JSON: `, consoleStyle, '', err);
-        });
-    } else if (contentType.includes('image/') && (!endpointName.includes('openfreemap'))) {
-      // Fetch custom for all images but opensourcemap
-
-      const blink = Date.now(); // Current time
-
-      const blob = await cloned.blob(); // The original blob
-
-      // Since this code does not run in the userscript, we can't use consoleLog().
-      console.log(`%c${name}%c: ${fetchedBlobQueue.size} Sending IMAGE message about endpoint "${endpointName}"`, consoleStyle, '');
-
-      // Returns the manipulated blob
-      return new Promise((resolve) => {
-        const blobUUID = crypto.randomUUID(); // Generates a random UUID
-
-        // Store the blob while we wait for processing
-        fetchedBlobQueue.set(blobUUID, (blobProcessed) => {
-          // The response that triggers when the blob is finished processing
-
-          // Creates a new response
-          resolve(new Response(blobProcessed, {
-            headers: cloned.headers,
-            status: cloned.status,
-            statusText: cloned.statusText
-          }));
-
-          // Since this code does not run in the userscript, we can't use consoleLog().
-          console.log(`%c${name}%c: ${fetchedBlobQueue.size} Processed blob "${blobUUID}"`, consoleStyle, '');
-        });
-
-        window.postMessage({
-          source: 'blue-marble',
-          endpoint: endpointName,
-          blobID: blobUUID,
-          blobData: blob,
-          blink: blink
-        });
-      }).catch(exception => {
-        const elapsed = Date.now();
-        console.error(`%c${name}%c: Failed to Promise blob!`, consoleStyle, '');
-        console.groupCollapsed(`%c${name}%c: Details of failed blob Promise:`, consoleStyle, '');
-        console.log(`Endpoint: ${endpointName}\nThere are ${fetchedBlobQueue.size} blobs processing...\nBlink: ${blink.toLocaleString()}\nTime Since Blink: ${String(Math.floor(elapsed/60000)).padStart(2,'0')}:${String(Math.floor(elapsed/1000) % 60).padStart(2,'0')}.${String(elapsed % 1000).padStart(3,'0')} MM:SS.mmm`);
-        console.error(`Exception stack:`, exception);
-        console.groupEnd();
-      });
-
-      // cloned.blob().then(blob => {
-      //   window.postMessage({
-      //     source: 'blue-marble',
-      //     endpoint: endpointName,
-      //     blobData: blob
-      //   }, '*');
-      // });
-    }
-
-    return response; // Returns the original response
-  };
-});
-
-// Imports the CSS file from dist folder on github
-const cssOverlay = GM_getResourceText("CSS-BM-File");
-GM_addStyle(cssOverlay);
-
-// Imports the Roboto Mono font family
-var stylesheetLink = document.createElement('link');
-stylesheetLink.href = 'https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap';
-stylesheetLink.rel = 'preload';
-stylesheetLink.as = 'style';
-stylesheetLink.onload = function () {
-  this.onload = null;
-  this.rel = 'stylesheet';
-};
-document.head?.appendChild(stylesheetLink);
-
-// CONSTRUCTORS
-const observers = new Observers(); // Constructs a new Observers object
-const overlayMain = new Overlay(name, version); // Constructs a new Overlay object for the main overlay
-const overlayTabTemplate = new Overlay(name, version); // Constructs a Overlay object for the template tab
-const templateManager = new TemplateManager(name, version, overlayMain); // Constructs a new TemplateManager object
-const apiManager = new ApiManager(templateManager); // Constructs a new ApiManager object
-
-overlayMain.setApiManager(apiManager); // Sets the API manager
-
-const storageTemplates = JSON.parse(GM_getValue('bmTemplates', '{}'));
-console.log(storageTemplates);
-templateManager.importJSON(storageTemplates); // Loads the templates
-
-buildOverlayMain(); // Builds the main overlay
-
-overlayMain.handleDrag('#bm-overlay', '#bm-bar-drag'); // Creates dragging capability on the drag bar for dragging the overlay
-
-apiManager.spontaneousResponseListener(overlayMain); // Reads spontaneous fetch responces
-
-observeBlack(); // Observes the black palette color
-
-consoleLog(`%c${name}%c (${version}) userscript has loaded!`, 'color: cornflowerblue;', '');
-
-/** Observe the black color, and add the "Move" button.
- * @since 0.66.3
- */
-function observeBlack() {
-  const observer = new MutationObserver((mutations, observer) => {
-
-    const black = document.querySelector('#color-1'); // Attempt to retrieve the black color element for anchoring
-
-    if (!black) {return;} // Black color does not exist yet. Kills iteself
-
-    let move = document.querySelector('#bm-button-move'); // Tries to find the move button
-
-    // If the move button does not exist, we make a new one
-    if (!move) {
-      move = document.createElement('button');
-      move.id = 'bm-button-move';
-      move.textContent = 'Move ↑';
-      move.className = 'btn btn-soft';
-      move.onclick = function() {
-        const roundedBox = this.parentNode.parentNode.parentNode.parentNode; // Obtains the rounded box
-        const shouldMoveUp = (this.textContent == 'Move ↑');
-        roundedBox.parentNode.className = roundedBox.parentNode.className.replace(shouldMoveUp ? 'bottom' : 'top', shouldMoveUp ? 'top' : 'bottom'); // Moves the rounded box to the top
-        roundedBox.style.borderTopLeftRadius = shouldMoveUp ? '0px' : 'var(--radius-box)';
-        roundedBox.style.borderTopRightRadius = shouldMoveUp ? '0px' : 'var(--radius-box)';
-        roundedBox.style.borderBottomLeftRadius = shouldMoveUp ? 'var(--radius-box)' : '0px';
-        roundedBox.style.borderBottomRightRadius = shouldMoveUp ? 'var(--radius-box)' : '0px';
-        this.textContent = shouldMoveUp ? 'Move ↓' : 'Move ↑';
-      }
-
-      // Attempts to find the "Paint Pixel" element for anchoring
-      const paintPixel = black.parentNode.parentNode.parentNode.parentNode.querySelector('h2');
-
-      paintPixel.parentNode?.appendChild(move); // Adds the move button
-    }
-  });
-
-  observer.observe(document.body, { childList: true, subtree: true });
-}
-
-/** Deploys the overlay to the page with minimize/maximize functionality.
- * Creates a responsive overlay UI that can toggle between full-featured and minimized states.
- * 
- * Parent/child relationships in the DOM structure below are indicated by indentation.
- * @since 0.58.3
- */
-function buildOverlayMain() {
-  let isMinimized = false; // Overlay state tracker (false = maximized, true = minimized)
-  
-  overlayMain.addDiv({'id': 'bm-overlay', 'style': 'top: 10px; right: 75px;'})
-    .addDiv({'id': 'bm-contain-header'})
-      .addDiv({'id': 'bm-bar-drag'}).buildElement()
-      .addImg({'alt': 'Blue Marble Icon - Click to minimize/maximize', 'src': 'https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png', 'style': 'cursor: pointer;'}, 
-        (instance, img) => {
-          /** Click event handler for overlay minimize/maximize functionality.
-           * 
-           * Toggles between two distinct UI states:
-           * 1. MINIMIZED STATE (60×76px):
-           *    - Shows only the Blue Marble icon and drag bar
-           *    - Hides all input fields, buttons, and status information
-           *    - Applies fixed dimensions for consistent appearance
-           *    - Repositions icon with 3px right offset for visual centering
-           * 
-           * 2. MAXIMIZED STATE (responsive):
-           *    - Restores full functionality with all UI elements
-           *    - Removes fixed dimensions to allow responsive behavior
-           *    - Resets icon positioning to default alignment
-           *    - Shows success message when returning to maximized state
-           * 
-           * @param {Event} event - The click event object (implicit)
-           */
-          img.addEventListener('click', () => {
-            isMinimized = !isMinimized; // Toggle the current state
-
-            const overlay = document.querySelector('#bm-overlay');
-            const header = document.querySelector('#bm-contain-header');
-            const dragBar = document.querySelector('#bm-bar-drag');
-            const coordsContainer = document.querySelector('#bm-contain-coords');
-            const coordsButton = document.querySelector('#bm-button-coords');
-            const createButton = document.querySelector('#bm-button-create');
-            const enableButton = document.querySelector('#bm-button-enable');
-            const disableButton = document.querySelector('#bm-button-disable');
-            const coordInputs = document.querySelectorAll('#bm-contain-coords input');
-            
-            // Pre-restore original dimensions when switching to maximized state
-            // This ensures smooth transition and prevents layout issues
-            if (!isMinimized) {
-              overlay.style.width = "auto";
-              overlay.style.maxWidth = "300px";
-              overlay.style.minWidth = "200px";
-              overlay.style.padding = "10px";
-            }
-            
-            // Define elements that should be hidden/shown during state transitions
-            // Each element is documented with its purpose for maintainability
-            const elementsToToggle = [
-              '#bm-overlay h1',                    // Main title "Blue Marble"
-              '#bm-contain-userinfo',              // User information section (username, droplets, level)
-              '#bm-overlay hr',                    // Visual separator lines
-              '#bm-contain-automation > *:not(#bm-contain-coords)', // Automation section excluding coordinates
-              '#bm-input-file-template',           // Template file upload interface
-              '#bm-contain-buttons-action',        // Action buttons container
-              `#${instance.outputStatusId}`        // Status log textarea for user feedback
-            ];
-            
-            // Apply visibility changes to all toggleable elements
-            elementsToToggle.forEach(selector => {
-              const elements = document.querySelectorAll(selector);
-              elements.forEach(element => {
-                element.style.display = isMinimized ? 'none' : '';
-              });
-            });
-            // Handle coordinate container and button visibility based on state
-            if (isMinimized) {
-              // ==================== MINIMIZED STATE CONFIGURATION ====================
-              // In minimized state, we hide ALL interactive elements except the icon and drag bar
-              // This creates a clean, unobtrusive interface that maintains only essential functionality
-              
-              // Hide coordinate input container completely
-              if (coordsContainer) {
-                coordsContainer.style.display = 'none';
-              }
-              
-              // Hide coordinate button (pin icon)
-              if (coordsButton) {
-                coordsButton.style.display = 'none';
-              }
-              
-              // Hide create template button
-              if (createButton) {
-                createButton.style.display = 'none';
-              }
-
-              // Hide enable templates button
-              if (enableButton) {
-                enableButton.style.display = 'none';
-              }
-
-              // Hide disable templates button
-              if (disableButton) {
-                disableButton.style.display = 'none';
-              }
-              
-              // Hide all coordinate input fields individually (failsafe)
-              coordInputs.forEach(input => {
-                input.style.display = 'none';
-              });
-              
-              // Apply fixed dimensions for consistent minimized appearance
-              // These dimensions were chosen to accommodate the icon while remaining compact
-              overlay.style.width = '60px';    // Fixed width for consistency
-              overlay.style.height = '76px';   // Fixed height (60px + 16px for better proportions)
-              overlay.style.maxWidth = '60px';  // Prevent expansion
-              overlay.style.minWidth = '60px';  // Prevent shrinking
-              overlay.style.padding = '8px';    // Comfortable padding around icon
-              
-              // Apply icon positioning for better visual centering in minimized state
-              // The 3px offset compensates for visual weight distribution
-              img.style.marginLeft = '3px';
-              
-              // Configure header layout for minimized state
-              header.style.textAlign = 'center';
-              header.style.margin = '0';
-              header.style.marginBottom = '0';
-              
-              // Ensure drag bar remains visible and properly spaced
-              if (dragBar) {
-                dragBar.style.display = '';
-                dragBar.style.marginBottom = '0.25em';
-              }
-            } else {
-              // ==================== MAXIMIZED STATE RESTORATION ====================
-              // In maximized state, we restore all elements to their default functionality
-              // This involves clearing all style overrides applied during minimization
-              
-              // Restore coordinate container to default state
-              if (coordsContainer) {
-                coordsContainer.style.display = '';           // Show container
-                coordsContainer.style.flexDirection = '';     // Reset flex layout
-                coordsContainer.style.justifyContent = '';    // Reset alignment
-                coordsContainer.style.alignItems = '';        // Reset alignment
-                coordsContainer.style.gap = '';               // Reset spacing
-                coordsContainer.style.textAlign = '';         // Reset text alignment
-                coordsContainer.style.margin = '';            // Reset margins
-              }
-              
-              // Restore coordinate button visibility
-              if (coordsButton) {
-                coordsButton.style.display = '';
-              }
-              
-              // Restore create button visibility and reset positioning
-              if (createButton) {
-                createButton.style.display = '';
-                createButton.style.marginTop = '';
-              }
-
-              // Restore enable button visibility and reset positioning
-              if (enableButton) {
-                enableButton.style.display = '';
-                enableButton.style.marginTop = '';
-              }
-
-              // Restore disable button visibility and reset positioning
-              if (disableButton) {
-                disableButton.style.display = '';
-                disableButton.style.marginTop = '';
-              }
-              
-              // Restore all coordinate input fields
-              coordInputs.forEach(input => {
-                input.style.display = '';
-              });
-              
-              // Reset icon positioning to default (remove minimized state offset)
-              img.style.marginLeft = '';
-              
-              // Restore overlay to responsive dimensions
-              overlay.style.padding = '10px';
-              
-              // Reset header styling to defaults
-              header.style.textAlign = '';
-              header.style.margin = '';
-              header.style.marginBottom = '';
-              
-              // Reset drag bar spacing
-              if (dragBar) {
-                dragBar.style.marginBottom = '0.5em';
-              }
-              
-              // Remove all fixed dimensions to allow responsive behavior
-              // This ensures the overlay can adapt to content changes
-              overlay.style.width = '';
-              overlay.style.height = '';
-            }
-            
-            // ==================== ACCESSIBILITY AND USER FEEDBACK ====================
-            // Update accessibility information for screen readers and tooltips
-            
-            // Update alt text to reflect current state for screen readers and tooltips
-            img.alt = isMinimized ? 
-              'Blue Marble Icon - Minimized (Click to maximize)' : 
-              'Blue Marble Icon - Maximized (Click to minimize)';
-            
-            // No status message needed - state change is visually obvious to users
-          });
-        }
-      ).buildElement()
-      .addHeader(1, {'textContent': name}).buildElement()
-    .buildElement()
-
-    .addHr().buildElement()
-
-    .addDiv({'id': 'bm-contain-userinfo'})
-      .addP({'id': 'bm-user-name', 'textContent': 'Username:'}).buildElement()
-      .addP({'id': 'bm-user-droplets', 'textContent': 'Droplets:'}).buildElement()
-      .addP({'id': 'bm-user-nextlevel', 'textContent': 'Next level in...'}).buildElement()
-    .buildElement()
-
-    .addHr().buildElement()
-
-    .addDiv({'id': 'bm-contain-automation'})
-      // .addCheckbox({'id': 'bm-input-stealth', 'textContent': 'Stealth', 'checked': true}).buildElement()
-      // .addButtonHelp({'title': 'Waits for the website to make requests, instead of sending requests.'}).buildElement()
-      // .addBr().buildElement()
-      // .addCheckbox({'id': 'bm-input-possessed', 'textContent': 'Possessed', 'checked': true}).buildElement()
-      // .addButtonHelp({'title': 'Controls the website as if it were possessed.'}).buildElement()
-      // .addBr().buildElement()
-      .addDiv({'id': 'bm-contain-coords'})
-        .addButton({'id': 'bm-button-coords', 'className': 'bm-help', 'style': 'margin-top: 0;', 'innerHTML': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4 6"><circle cx="2" cy="2" r="2"></circle><path d="M2 6 L3.7 3 L0.3 3 Z"></path><circle cx="2" cy="2" r="0.7" fill="white"></circle></svg></svg>'},
-          (instance, button) => {
-            button.onclick = () => {
-              const coords = instance.apiManager?.coordsTilePixel; // Retrieves the coords from the API manager
-              if (!coords?.[0]) {
-                instance.handleDisplayError('Coordinates are malformed! Did you try clicking on the canvas first?');
-                return;
-              }
-              instance.updateInnerHTML('bm-input-tx', coords?.[0] || '');
-              instance.updateInnerHTML('bm-input-ty', coords?.[1] || '');
-              instance.updateInnerHTML('bm-input-px', coords?.[2] || '');
-              instance.updateInnerHTML('bm-input-py', coords?.[3] || '');
-            }
-          }
-        ).buildElement()
-        .addInput({'type': 'number', 'id': 'bm-input-tx', 'placeholder': 'Tl X', 'min': 0, 'max': 2047, 'step': 1, 'required': true}).buildElement()
-        .addInput({'type': 'number', 'id': 'bm-input-ty', 'placeholder': 'Tl Y', 'min': 0, 'max': 2047, 'step': 1, 'required': true}).buildElement()
-        .addInput({'type': 'number', 'id': 'bm-input-px', 'placeholder': 'Px X', 'min': 0, 'max': 2047, 'step': 1, 'required': true}).buildElement()
-        .addInput({'type': 'number', 'id': 'bm-input-py', 'placeholder': 'Px Y', 'min': 0, 'max': 2047, 'step': 1, 'required': true}).buildElement()
-      .buildElement()
-      .addInputFile({'id': 'bm-input-file-template', 'textContent': 'Upload Template', 'accept': 'image/png, image/jpeg, image/webp, image/bmp, image/gif'}).buildElement()
-      .addDiv({'id': 'bm-contain-buttons-template'})
-        .addButton({'id': 'bm-button-enable', 'textContent': 'Enable'}, (instance, button) => {
-          button.onclick = () => {
-            instance.apiManager?.templateManager?.setTemplatesShouldBeDrawn(true);
-            instance.handleDisplayStatus(`Enabled templates!`);
-          }
-        }).buildElement()
-        .addButton({'id': 'bm-button-create', 'textContent': 'Create'}, (instance, button) => {
-          button.onclick = () => {
-            const input = document.querySelector('#bm-input-file-template');
-
-            const coordTlX = document.querySelector('#bm-input-tx');
-            if (!coordTlX.checkValidity()) {coordTlX.reportValidity(); instance.handleDisplayError('Coordinates are malformed! Did you try clicking on the canvas first?'); return;}
-            const coordTlY = document.querySelector('#bm-input-ty');
-            if (!coordTlY.checkValidity()) {coordTlY.reportValidity(); instance.handleDisplayError('Coordinates are malformed! Did you try clicking on the canvas first?'); return;}
-            const coordPxX = document.querySelector('#bm-input-px');
-            if (!coordPxX.checkValidity()) {coordPxX.reportValidity(); instance.handleDisplayError('Coordinates are malformed! Did you try clicking on the canvas first?'); return;}
-            const coordPxY = document.querySelector('#bm-input-py');
-            if (!coordPxY.checkValidity()) {coordPxY.reportValidity(); instance.handleDisplayError('Coordinates are malformed! Did you try clicking on the canvas first?'); return;}
-
-            // Kills itself if there is no file
-            if (!input?.files[0]) {instance.handleDisplayError(`No file selected!`); return;}
-
-            templateManager.createTemplate(input.files[0], input.files[0]?.name.replace(/\.[^/.]+$/, ''), [Number(coordTlX.value), Number(coordTlY.value), Number(coordPxX.value), Number(coordPxY.value)]);
-
-            // console.log(`TCoords: ${apiManager.templateCoordsTilePixel}\nCoords: ${apiManager.coordsTilePixel}`);
-            // apiManager.templateCoordsTilePixel = apiManager.coordsTilePixel; // Update template coords
-            // console.log(`TCoords: ${apiManager.templateCoordsTilePixel}\nCoords: ${apiManager.coordsTilePixel}`);
-            // templateManager.setTemplateImage(input.files[0]);
-
-            instance.handleDisplayStatus(`Drew to canvas!`);
-          }
-        }).buildElement()
-        .addButton({'id': 'bm-button-disable', 'textContent': 'Disable'}, (instance, button) => {
-          button.onclick = () => {
-            instance.apiManager?.templateManager?.setTemplatesShouldBeDrawn(false);
-            instance.handleDisplayStatus(`Disabled templates!`);
-          }
-        }).buildElement()
-      .buildElement()
-      .addTextarea({'id': overlayMain.outputStatusId, 'placeholder': `Status: Sleeping...\nVersion: ${version}`, 'readOnly': true}).buildElement()
-      .addDiv({'id': 'bm-contain-buttons-action'})
-        .addDiv()
-          // .addButton({'id': 'bm-button-teleport', 'className': 'bm-help', 'textContent': '✈'}).buildElement()
-          // .addButton({'id': 'bm-button-favorite', 'className': 'bm-help', 'innerHTML': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><polygon points="10,2 12,7.5 18,7.5 13.5,11.5 15.5,18 10,14 4.5,18 6.5,11.5 2,7.5 8,7.5" fill="white"></polygon></svg>'}).buildElement()
-          // .addButton({'id': 'bm-button-templates', 'className': 'bm-help', 'innerHTML': '🖌'}).buildElement()
-          .addButton({'id': 'bm-button-convert', 'className': 'bm-help', 'innerHTML': '🎨', 'title': 'Template Color Converter'}, 
-            (instance, button) => {
-            button.addEventListener('click', () => {
-              window.open('https://pepoafonso.github.io/color_converter_wplace/', '_blank', 'noopener noreferrer');
-            });
-          }).buildElement()
-        .buildElement()
-        .addSmall({'textContent': 'Made by SwingTheVine', 'style': 'margin-top: auto;'}).buildElement()
-      .buildElement()
-    .buildElement()
-  .buildOverlay(document.body);
-}
-
-function buildOverlayTabTemplate() {
-  overlayTabTemplate.addDiv({'id': 'bm-tab-template', 'style': 'top: 20%; left: 10%;'})
-      .addDiv()
-        .addDiv({'className': 'bm-dragbar'}).buildElement()
-        .addButton({'className': 'bm-button-minimize', 'textContent': '↑'},
-          (instance, button) => {
-            button.onclick = () => {
-              let isMinimized = false;
-              if (button.textContent == '↑') {
-                button.textContent = '↓';
-              } else {
-                button.textContent = '↑';
-                isMinimized = true;
-              }
-
-              
-            }
-          }
-        ).buildElement()
-      .buildElement()
-    .buildElement()
-  .buildOverlay();
-}
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/module.exports.html b/docs/module.exports.html deleted file mode 100644 index b872f47..0000000 --- a/docs/module.exports.html +++ /dev/null @@ -1,1130 +0,0 @@ - - - - - JSDoc: Class: exports - - - - - - - - - - -
- -

Class: exports

- - - - - - -
- -
- -

exports(name, version)

- -
The overlay builder for the Blue Marble script.
- - -
- -
-
- - - - -

Constructor

- - - -

new exports(name, version)

- - - - - - -
- This class handles the overlay UI for the Blue Marble script. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - -string - - - - The name of the userscript
version - - -string - - - - The version of the userscript
- - - - - - -
- - - - -
Since:
-
  • 0.0.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - -
See:
-
-
    -
  • Overlay
  • -
-
- - - -
- - - - - - - - - - - - - - - - - - - -
Example
- -
const overlay = new Overlay();
overlay.addDiv({ 'id': 'overlay' })
  .addDiv({ 'id': 'header' })
    .addHeader(1, {'textContent': 'Your Overlay'}).buildElement()
    .addP({'textContent': 'This is your overlay. It is versatile.'}).buildElement()
  .buildElement() // Marks the end of the header <div>
  .addHr().buildElement()
.buildOverlay(document.body);
// Output:
// (Assume <body> already exists in the webpage)
<body>
  <div id="overlay">
    <div id="header">
      <h1>Your Overlay</h1>
      <p>This is your overlay. It is versatile.</p>
    </div>
    <hr>
  </div>
</body>
- - - - -
- - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - - -
- -
- -

exports()

- -
This class contains all MutationObservers used (which is 1 probably). This is not an object, but rather a "collection" of functions (in a class).
- - -
- -
-
- - - - -

Constructor

- - - -

new exports()

- - - - - - -
- The constructor for the observer class -
- - - - - - - - - - - - - -
- - - - -
Since:
-
  • 0.43.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - - -
- -
- -

exports()

- -
Manages the template system. This class handles all external requests for template modification, creation, and analysis. It serves as the central coordinator between template instances and the user interface.
- - -
- -
-
- - - - -

Constructor

- - - -

new exports()

- - - - - - -
- The constructor for the TemplateManager class. -
- - - - - - - - - - - - - -
- - - - -
Since:
-
  • 0.55.8
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Example
- -
// JSON structure for a template
{
  "whoami": "BlueMarble",
  "scriptVersion": "1.13.0",
  "schemaVersion": "2.1.0",
  "templates": {
    "0 $Z": {
      "name": "My Template",
      "enabled": true,
      "tiles": {
        "1231,0047,183,593": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA",
        "1231,0048,183,000": "data:image/png;AAAFCAYAAACNbyblAAAAHElEQVQI12P4"
      }
    },
    "1 $Z": {
      "name": "My Template",
      "URL": "https://github.com/SwingTheVine/Wplace-BlueMarble/blob/main/dist/assets/Favicon.png",
      "URLType": "template",
      "enabled": false,
      "tiles": {
        "375,1846,276,188": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA",
        "376,1846,000,188": "data:image/png;AAAFCAYAAACNbyblAAAAHElEQVQI12P4"
      }
    }
  }
}
- - - - -
- - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - - -
- -
- -

exports(paramsopt)

- -
An instance of a template. Handles all mathematics, manipulation, and analysis regarding a single template.
- - -
- -
-
- - - - -

Constructor

- - - -

new exports(paramsopt)

- - - - - - -
- The constructor for the Template class with enhanced pixel tracking. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
params - - -Object - - - - - - <optional>
- - - - - -
- - {} - - Object containing all optional parameters -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeAttributesDefaultDescription
displayName - - -string - - - - - - <optional>
- - - - - -
- - 'My template' - - The display name of the template
sortID - - -number - - - - - - <optional>
- - - - - -
- - 0 - - The sort number of the template for rendering priority
authorID - - -string - - - - - - <optional>
- - - - - -
- - '' - - The user ID of the person who exported the template (prevents sort ID collisions)
url - - -string - - - - - - <optional>
- - - - - -
- - '' - - The URL to the source image
file - - -File - - - - - - <optional>
- - - - - -
- - null - - The template file (pre-processed File or processed bitmap)
coords - - -Array.<number> - - - - - - <optional>
- - - - - -
- - null - - The coordinates of the top left corner as (tileX, tileY, pixelX, pixelY)
chunked - - -Object - - - - - - <optional>
- - - - - -
- - null - - The affected chunks of the template, and their template for each chunk
tileSize - - -number - - - - - - <optional>
- - - - - -
- - 1000 - - The size of a tile in pixels (assumes square tiles)
pixelCount - - -number - - - - - - <optional>
- - - - - -
- - 0 - - Total number of pixels in the template (calculated automatically during processing)
- -
- - - - - - -
- - - - -
Since:
-
  • 0.65.2
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/module.exports_module.exports.html b/docs/module.exports_module.exports.html deleted file mode 100644 index 3e0958d..0000000 --- a/docs/module.exports_module.exports.html +++ /dev/null @@ -1,222 +0,0 @@ - - - - - JSDoc: Class: exports - - - - - - - - - - -
- -

Class: exports

- - - - - - -
- -
- -

exports(templateManager)

- - -
- -
-
- - - - - - -

new exports(templateManager)

- - - - - - -
- Constructor for ApiManager class -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
templateManager - - -TemplateManager - - - -
- - - - - - -
- - - - -
Since:
-
  • 0.11.34
- - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/observers.js.html b/docs/observers.js.html deleted file mode 100644 index 7024790..0000000 --- a/docs/observers.js.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - JSDoc: Source: observers.js - - - - - - - - - - -
- -

Source: observers.js

- - - - - - -
-
-
/** This class contains all MutationObservers used (which is 1 probably).
- * This is not an object, but rather a "collection" of functions (in a class).
- * @since 0.43.2
- */
-export default class Observers {
-
-  /** The constructor for the observer class
-   * @since 0.43.2
-   */
-  constructor() {
-    this.observerBody = null;
-    this.observerBodyTarget = null;
-    this.targetDisplayCoords = '#bm-display-coords';
-  }
-
-  /** Creates the MutationObserver for document.body
-   * @param {HTMLElement} target - Targeted element to watch
-   * @returns {Observers} this (Observers class)
-   * @since 0.43.2
-   */
-  createObserverBody(target) {
-
-    this.observerBodyTarget = target;
-
-    this.observerBody = new MutationObserver((mutations) => {
-      for (const mutation of mutations) {
-        for (const node of mutation.addedNodes) {
-
-          if (!(node instanceof HTMLElement)) {continue;} // Does not track non-HTMLElements
-          
-          if (node.matches?.(this.targetDisplayCoords)) {
-
-          }
-        }
-      }
-    })
-
-    return this;
-  }
-
-  /** Retrieves the MutationObserver that watches document.body
-   * @returns {MutationObserver}
-   * @since 0.43.2
-   */
-  getObserverBody() {
-    return this.observerBody;
-  }
-
-  /** Observe a MutationObserver
-   * @param {MutationObserver} observer - The MutationObserver
-   * @param {boolean} watchChildList - (Optional) Should childList be watched? False by default
-   * @param {boolean} watchSubtree - (Optional) Should childList be watched? False by default
-   * @since 0.43.2
-   */
-  observe(observer, watchChildList=false, watchSubtree=false) {
-    observer.observe(this.observerBodyTarget, {
-      childList: watchChildList,
-      subtree: watchSubtree
-    });
-  }
-}
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/scripts/linenumber.js b/docs/scripts/linenumber.js deleted file mode 100644 index 4354785..0000000 --- a/docs/scripts/linenumber.js +++ /dev/null @@ -1,25 +0,0 @@ -/*global document */ -(() => { - const source = document.getElementsByClassName('prettyprint source linenums'); - let i = 0; - let lineNumber = 0; - let lineId; - let lines; - let totalLines; - let anchorHash; - - if (source && source[0]) { - anchorHash = document.location.hash.substring(1); - lines = source[0].getElementsByTagName('li'); - totalLines = lines.length; - - for (; i < totalLines; i++) { - lineNumber++; - lineId = `line${lineNumber}`; - lines[i].id = lineId; - if (lineId === anchorHash) { - lines[i].className += ' selected'; - } - } - } -})(); diff --git a/docs/scripts/prettify/Apache-License-2.0.txt b/docs/scripts/prettify/Apache-License-2.0.txt deleted file mode 100644 index d645695..0000000 --- a/docs/scripts/prettify/Apache-License-2.0.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/docs/scripts/prettify/lang-css.js b/docs/scripts/prettify/lang-css.js deleted file mode 100644 index 041e1f5..0000000 --- a/docs/scripts/prettify/lang-css.js +++ /dev/null @@ -1,2 +0,0 @@ -PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", -/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/docs/scripts/prettify/prettify.js b/docs/scripts/prettify/prettify.js deleted file mode 100644 index eef5ad7..0000000 --- a/docs/scripts/prettify/prettify.js +++ /dev/null @@ -1,28 +0,0 @@ -var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; -(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= -[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), -l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, -q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, -q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, -"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), -a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} -for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], -"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], -H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], -J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ -I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), -["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", -/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), -["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", -hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= -!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p th:last-child { border-right: 1px solid #ddd; } - -.ancestors, .attribs { color: #999; } -.ancestors a, .attribs a -{ - color: #999 !important; - text-decoration: none; -} - -.clear -{ - clear: both; -} - -.important -{ - font-weight: bold; - color: #950B02; -} - -.yes-def { - text-indent: -1000px; -} - -.type-signature { - color: #aaa; -} - -.name, .signature { - font-family: Consolas, Monaco, 'Andale Mono', monospace; -} - -.details { margin-top: 14px; border-left: 2px solid #DDD; } -.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } -.details dd { margin-left: 70px; } -.details ul { margin: 0; } -.details ul { list-style-type: none; } -.details li { margin-left: 30px; padding-top: 6px; } -.details pre.prettyprint { margin: 0 } -.details .object-value { padding-top: 0; } - -.description { - margin-bottom: 1em; - margin-top: 1em; -} - -.code-caption -{ - font-style: italic; - font-size: 107%; - margin: 0; -} - -.source -{ - border: 1px solid #ddd; - width: 80%; - overflow: auto; -} - -.prettyprint.source { - width: inherit; -} - -.source code -{ - font-size: 100%; - line-height: 18px; - display: block; - padding: 4px 12px; - margin: 0; - background-color: #fff; - color: #4D4E53; -} - -.prettyprint code span.line -{ - display: inline-block; -} - -.prettyprint.linenums -{ - padding-left: 70px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.prettyprint.linenums ol -{ - padding-left: 0; -} - -.prettyprint.linenums li -{ - border-left: 3px #ddd solid; -} - -.prettyprint.linenums li.selected, -.prettyprint.linenums li.selected * -{ - background-color: lightyellow; -} - -.prettyprint.linenums li * -{ - -webkit-user-select: text; - -moz-user-select: text; - -ms-user-select: text; - user-select: text; -} - -.params .name, .props .name, .name code { - color: #4D4E53; - font-family: Consolas, Monaco, 'Andale Mono', monospace; - font-size: 100%; -} - -.params td.description > p:first-child, -.props td.description > p:first-child -{ - margin-top: 0; - padding-top: 0; -} - -.params td.description > p:last-child, -.props td.description > p:last-child -{ - margin-bottom: 0; - padding-bottom: 0; -} - -.disabled { - color: #454545; -} diff --git a/docs/styles/prettify-jsdoc.css b/docs/styles/prettify-jsdoc.css deleted file mode 100644 index 5a2526e..0000000 --- a/docs/styles/prettify-jsdoc.css +++ /dev/null @@ -1,111 +0,0 @@ -/* JSDoc prettify.js theme */ - -/* plain text */ -.pln { - color: #000000; - font-weight: normal; - font-style: normal; -} - -/* string content */ -.str { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a keyword */ -.kwd { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* a comment */ -.com { - font-weight: normal; - font-style: italic; -} - -/* a type name */ -.typ { - color: #000000; - font-weight: normal; - font-style: normal; -} - -/* a literal value */ -.lit { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* punctuation */ -.pun { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* lisp open bracket */ -.opn { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* lisp close bracket */ -.clo { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* a markup tag name */ -.tag { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a markup attribute name */ -.atn { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a markup attribute value */ -.atv { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a declaration */ -.dec { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* a variable name */ -.var { - color: #000000; - font-weight: normal; - font-style: normal; -} - -/* a function name */ -.fun { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* Specify class=linenums on a pre to get line numbering */ -ol.linenums { - margin-top: 0; - margin-bottom: 0; -} diff --git a/docs/styles/prettify-tomorrow.css b/docs/styles/prettify-tomorrow.css deleted file mode 100644 index b6f92a7..0000000 --- a/docs/styles/prettify-tomorrow.css +++ /dev/null @@ -1,132 +0,0 @@ -/* Tomorrow Theme */ -/* Original theme - https://github.com/chriskempson/tomorrow-theme */ -/* Pretty printing styles. Used with prettify.js. */ -/* SPAN elements with the classes below are added by prettyprint. */ -/* plain text */ -.pln { - color: #4d4d4c; } - -@media screen { - /* string content */ - .str { - color: #718c00; } - - /* a keyword */ - .kwd { - color: #8959a8; } - - /* a comment */ - .com { - color: #8e908c; } - - /* a type name */ - .typ { - color: #4271ae; } - - /* a literal value */ - .lit { - color: #f5871f; } - - /* punctuation */ - .pun { - color: #4d4d4c; } - - /* lisp open bracket */ - .opn { - color: #4d4d4c; } - - /* lisp close bracket */ - .clo { - color: #4d4d4c; } - - /* a markup tag name */ - .tag { - color: #c82829; } - - /* a markup attribute name */ - .atn { - color: #f5871f; } - - /* a markup attribute value */ - .atv { - color: #3e999f; } - - /* a declaration */ - .dec { - color: #f5871f; } - - /* a variable name */ - .var { - color: #c82829; } - - /* a function name */ - .fun { - color: #4271ae; } } -/* Use higher contrast and text-weight for printable form. */ -@media print, projection { - .str { - color: #060; } - - .kwd { - color: #006; - font-weight: bold; } - - .com { - color: #600; - font-style: italic; } - - .typ { - color: #404; - font-weight: bold; } - - .lit { - color: #044; } - - .pun, .opn, .clo { - color: #440; } - - .tag { - color: #006; - font-weight: bold; } - - .atn { - color: #404; } - - .atv { - color: #060; } } -/* Style */ -/* -pre.prettyprint { - background: white; - font-family: Consolas, Monaco, 'Andale Mono', monospace; - font-size: 12px; - line-height: 1.5; - border: 1px solid #ccc; - padding: 10px; } -*/ - -/* Specify class=linenums on a pre to get line numbering */ -ol.linenums { - margin-top: 0; - margin-bottom: 0; } - -/* IE indents via margin-left */ -li.L0, -li.L1, -li.L2, -li.L3, -li.L4, -li.L5, -li.L6, -li.L7, -li.L8, -li.L9 { - /* */ } - -/* Alternate shading for lines */ -li.L1, -li.L3, -li.L5, -li.L7, -li.L9 { - /* */ } diff --git a/docs/templateManager.js.html b/docs/templateManager.js.html deleted file mode 100644 index 0483daa..0000000 --- a/docs/templateManager.js.html +++ /dev/null @@ -1,444 +0,0 @@ - - - - - JSDoc: Source: templateManager.js - - - - - - - - - - -
- -

Source: templateManager.js

- - - - - - -
-
-
import Template from "./Template";
-import { base64ToUint8, numberToEncoded } from "./utils";
-
-/** Manages the template system.
- * This class handles all external requests for template modification, creation, and analysis.
- * It serves as the central coordinator between template instances and the user interface.
- * @since 0.55.8
- * @example
- * // JSON structure for a template
- * {
- *   "whoami": "BlueMarble",
- *   "scriptVersion": "1.13.0",
- *   "schemaVersion": "2.1.0",
- *   "templates": {
- *     "0 $Z": {
- *       "name": "My Template",
- *       "enabled": true,
- *       "tiles": {
- *         "1231,0047,183,593": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA",
- *         "1231,0048,183,000": "data:image/png;AAAFCAYAAACNbyblAAAAHElEQVQI12P4"
- *       }
- *     },
- *     "1 $Z": {
- *       "name": "My Template",
- *       "URL": "https://github.com/SwingTheVine/Wplace-BlueMarble/blob/main/dist/assets/Favicon.png",
- *       "URLType": "template",
- *       "enabled": false,
- *       "tiles": {
- *         "375,1846,276,188": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA",
- *         "376,1846,000,188": "data:image/png;AAAFCAYAAACNbyblAAAAHElEQVQI12P4"
- *       }
- *     }
- *   }
- * }
- */
-export default class TemplateManager {
-
-  /** The constructor for the {@link TemplateManager} class.
-   * @since 0.55.8
-   */
-  constructor(name, version, overlay) {
-
-    // Meta
-    this.name = name; // Name of userscript
-    this.version = version; // Version of userscript
-    this.overlay = overlay; // The main instance of the Overlay class
-    this.templatesVersion = '1.0.0'; // Version of JSON schema
-    this.userID = null; // The ID of the current user
-    this.encodingBase = '!#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~'; // Characters to use for encoding/decoding
-    this.tileSize = 1000; // The number of pixels in a tile. Assumes the tile is square
-    this.drawMult = 3; // The enlarged size for each pixel. E.g. when "3", a 1x1 pixel becomes a 1x1 pixel inside a 3x3 area. MUST BE ODD
-    
-    // Template
-    this.canvasTemplate = null; // Our canvas
-    this.canvasTemplateZoomed = null; // The template when zoomed out
-    this.canvasTemplateID = 'bm-canvas'; // Our canvas ID
-    this.canvasMainID = 'div#map canvas.maplibregl-canvas'; // The selector for the main canvas
-    this.template = null; // The template image.
-    this.templateState = ''; // The state of the template ('blob', 'proccessing', 'template', etc.)
-    this.templatesArray = []; // All Template instnaces currently loaded (Template)
-    this.templatesJSON = null; // All templates currently loaded (JSON)
-    this.templatesShouldBeDrawn = true; // Should ALL templates be drawn to the canvas?
-  }
-
-  /** Retrieves the pixel art canvas.
-   * If the canvas has been updated/replaced, it retrieves the new one.
-   * @param {string} selector - The CSS selector to use to find the canvas.
-   * @returns {HTMLCanvasElement|null} The canvas as an HTML Canvas Element, or null if the canvas does not exist
-   * @since 0.58.3
-   * @deprecated Not in use since 0.63.25
-   */
-  /* @__PURE__ */getCanvas() {
-
-    // If the stored canvas is "fresh", return the stored canvas
-    if (document.body.contains(this.canvasTemplate)) {return this.canvasTemplate;}
-    // Else, the stored canvas is "stale", get the canvas again
-
-    // Attempt to find and destroy the "stale" canvas
-    document.getElementById(this.canvasTemplateID)?.remove(); 
-
-    const canvasMain = document.querySelector(this.canvasMainID);
-
-    const canvasTemplateNew = document.createElement('canvas');
-    canvasTemplateNew.id = this.canvasTemplateID;
-    canvasTemplateNew.className = 'maplibregl-canvas';
-    canvasTemplateNew.style.position = 'absolute';
-    canvasTemplateNew.style.top = '0';
-    canvasTemplateNew.style.left = '0';
-    canvasTemplateNew.style.height = `${canvasMain?.clientHeight * (window.devicePixelRatio || 1)}px`;
-    canvasTemplateNew.style.width = `${canvasMain?.clientWidth * (window.devicePixelRatio || 1)}px`;
-    canvasTemplateNew.height = canvasMain?.clientHeight * (window.devicePixelRatio || 1);
-    canvasTemplateNew.width = canvasMain?.clientWidth * (window.devicePixelRatio || 1);
-    canvasTemplateNew.style.zIndex = '8999';
-    canvasTemplateNew.style.pointerEvents = 'none';
-    canvasMain?.parentElement?.appendChild(canvasTemplateNew); // Append the newCanvas as a child of the parent of the main canvas
-    this.canvasTemplate = canvasTemplateNew; // Store the new canvas
-
-    window.addEventListener('move', this.onMove);
-    window.addEventListener('zoom', this.onZoom);
-    window.addEventListener('resize', this.onResize);
-
-    return this.canvasTemplate; // Return the new canvas
-  }
-
-  /** Creates the JSON object to store templates in
-   * @returns {{ whoami: string, scriptVersion: string, schemaVersion: string, templates: Object }} The JSON object
-   * @since 0.65.4
-   */
-  async createJSON() {
-    return {
-      "whoami": this.name.replace(' ', ''), // Name of userscript without spaces
-      "scriptVersion": this.version, // Version of userscript
-      "schemaVersion": this.templatesVersion, // Version of JSON schema
-      "templates": {} // The templates
-    };
-  }
-
-  /** Creates the template from the inputed file blob
-   * @param {File} blob - The file blob to create a template from
-   * @param {string} name - The display name of the template
-   * @param {Array<number, number, number, number>} coords - The coordinates of the top left corner of the template
-   * @since 0.65.77
-   */
-  async createTemplate(blob, name, coords) {
-
-    // Creates the JSON object if it does not already exist
-    if (!this.templatesJSON) {this.templatesJSON = await this.createJSON(); console.log(`Creating JSON...`);}
-
-    this.overlay.handleDisplayStatus(`Creating template at ${coords.join(', ')}...`);
-
-    // Creates a new template instance
-    const template = new Template({
-      displayName: name,
-      sortID: 0, // Object.keys(this.templatesJSON.templates).length || 0, // Uncomment this to enable multiple templates (1/2)
-      authorID: numberToEncoded(this.userID || 0, this.encodingBase),
-      file: blob,
-      coords: coords
-    });
-    //template.chunked = await template.createTemplateTiles(this.tileSize); // Chunks the tiles
-    const { templateTiles, templateTilesBuffers } = await template.createTemplateTiles(this.tileSize); // Chunks the tiles
-    template.chunked = templateTiles; // Stores the chunked tile bitmaps
-
-    // Appends a child into the templates object
-    // The child's name is the number of templates already in the list (sort order) plus the encoded player ID
-    this.templatesJSON.templates[`${template.sortID} ${template.authorID}`] = {
-      "name": template.displayName, // Display name of template
-      "coords": coords.join(', '), // The coords of the template
-      "enabled": true,
-      "tiles": templateTilesBuffers // Stores the chunked tile buffers
-    };
-
-    this.templatesArray = []; // Remove this to enable multiple templates (2/2)
-    this.templatesArray.push(template); // Pushes the Template object instance to the Template Array
-
-    // ==================== PIXEL COUNT DISPLAY SYSTEM ====================
-    // Display pixel count statistics with internationalized number formatting
-    // This provides immediate feedback to users about template complexity and size
-    const pixelCountFormatted = new Intl.NumberFormat().format(template.pixelCount);
-    this.overlay.handleDisplayStatus(`Template created at ${coords.join(', ')}! Total pixels: ${pixelCountFormatted}`);
-
-    console.log(Object.keys(this.templatesJSON.templates).length);
-    console.log(this.templatesJSON);
-    console.log(this.templatesArray);
-    console.log(JSON.stringify(this.templatesJSON));
-
-    await this.#storeTemplates();
-  }
-
-  /** Generates a {@link Template} class instance from the JSON object template
-   */
-  #loadTemplate() {
-
-  }
-
-  /** Stores the JSON object of the loaded templates into TamperMonkey (GreaseMonkey) storage.
-   * @since 0.72.7
-   */
-  async #storeTemplates() {
-    GM.setValue('bmTemplates', JSON.stringify(this.templatesJSON));
-  }
-
-  /** Deletes a template from the JSON object.
-   * Also delete's the corrosponding {@link Template} class instance
-   */
-  deleteTemplate() {
-
-  }
-
-  /** Disables the template from view
-   */
-  async disableTemplate() {
-
-    // Creates the JSON object if it does not already exist
-    if (!this.templatesJSON) {this.templatesJSON = await this.createJSON(); console.log(`Creating JSON...`);}
-
-
-  }
-
-  /** Draws all templates on the specified tile.
-   * This method handles the rendering of template overlays on individual tiles.
-   * @param {File} tileBlob - The pixels that are placed on a tile
-   * @param {Array<number>} tileCoords - The tile coordinates [x, y]
-   * @since 0.65.77
-   */
-  async drawTemplateOnTile(tileBlob, tileCoords) {
-
-    // Returns early if no templates should be drawn
-    if (!this.templatesShouldBeDrawn) {return tileBlob;}
-
-    const drawSize = this.tileSize * this.drawMult; // Calculate draw multiplier for scaling
-
-    // Format tile coordinates with proper padding for consistent lookup
-    tileCoords = tileCoords[0].toString().padStart(4, '0') + ',' + tileCoords[1].toString().padStart(4, '0');
-
-    console.log(`Searching for templates in tile: "${tileCoords}"`);
-
-    const templateArray = this.templatesArray; // Stores a copy for sorting
-    console.log(templateArray);
-
-    // Sorts the array of Template class instances. 0 = first = lowest draw priority
-    templateArray.sort((a, b) => {return a.sortID - b.sortID;});
-
-    console.log(templateArray);
-
-    // Retrieves the relavent template tile blobs
-    const templatesToDraw = templateArray
-      .map(template => {
-        const matchingTiles = Object.keys(template.chunked).filter(tile =>
-          tile.startsWith(tileCoords)
-        );
-
-        if (matchingTiles.length === 0) {return null;} // Return null when nothing is found
-
-        // Retrieves the blobs of the templates for this tile
-        const matchingTileBlobs = matchingTiles.map(tile => {
-
-          const coords = tile.split(','); // [x, y, x, y] Tile/pixel coordinates
-          
-          return {
-            bitmap: template.chunked[tile],
-            tileCoords: [coords[0], coords[1]],
-            pixelCoords: [coords[2], coords[3]]
-          }
-        });
-
-        return matchingTileBlobs?.[0];
-      })
-    .filter(Boolean);
-
-    console.log(templatesToDraw);
-
-    const templateCount = templatesToDraw?.length || 0; // Number of templates to draw on this tile
-    console.log(`templateCount = ${templateCount}`);
-
-    if (templateCount > 0) {
-      
-      // Calculate total pixel count for templates actively being displayed in this tile
-      const totalPixels = templateArray
-        .filter(template => {
-          // Filter templates to include only those with tiles matching current coordinates
-          // This ensures we count pixels only for templates actually being rendered
-          const matchingTiles = Object.keys(template.chunked).filter(tile =>
-            tile.startsWith(tileCoords)
-          );
-          return matchingTiles.length > 0;
-        })
-        .reduce((sum, template) => sum + (template.pixelCount || 0), 0);
-      
-      // Format pixel count with locale-appropriate thousands separators for better readability
-      // Examples: "1,234,567" (US), "1.234.567" (DE), "1 234 567" (FR)
-      const pixelCountFormatted = new Intl.NumberFormat().format(totalPixels);
-      
-      // Display status information about the templates being rendered
-      this.overlay.handleDisplayStatus(
-        `Displaying ${templateCount} template${templateCount == 1 ? '' : 's'}.\nTotal pixels: ${pixelCountFormatted}`
-      );
-    } else {
-      this.overlay.handleDisplayStatus(`Displaying ${templateCount} templates.`);
-    }
-    
-    const tileBitmap = await createImageBitmap(tileBlob);
-
-    const canvas = new OffscreenCanvas(drawSize, drawSize);
-    const context = canvas.getContext('2d');
-
-    context.imageSmoothingEnabled = false; // Nearest neighbor
-
-    // Tells the canvas to ignore anything outside of this area
-    context.beginPath();
-    context.rect(0, 0, drawSize, drawSize);
-    context.clip();
-
-    context.clearRect(0, 0, drawSize, drawSize); // Draws transparent background
-    context.drawImage(tileBitmap, 0, 0, drawSize, drawSize);
-
-    // For each template in this tile, draw them.
-    for (const template of templatesToDraw) {
-      console.log(`Template:`);
-      console.log(template);
-
-      // Draws the each template on the tile based on it's relative position
-      context.drawImage(template.bitmap, Number(template.pixelCoords[0]) * this.drawMult, Number(template.pixelCoords[1]) * this.drawMult);
-    }
-
-    return await canvas.convertToBlob({ type: 'image/png' });
-  }
-
-  /** Imports the JSON object, and appends it to any JSON object already loaded
-   * @param {string} json - The JSON string to parse
-   */
-  importJSON(json) {
-
-    console.log(`Importing JSON...`);
-    console.log(json);
-
-    // If the passed in JSON is a Blue Marble template object...
-    if (json?.whoami == 'BlueMarble') {
-      this.#parseBlueMarble(json); // ...parse the template object as Blue Marble
-    }
-  }
-
-  /** Parses the Blue Marble JSON object
-   * @param {string} json - The JSON string to parse
-   * @since 0.72.13
-   */
-  async #parseBlueMarble(json) {
-
-    console.log(`Parsing BlueMarble...`);
-
-    const templates = json.templates;
-
-    console.log(`BlueMarble length: ${Object.keys(templates).length}`);
-
-    if (Object.keys(templates).length > 0) {
-
-      for (const template in templates) {
-
-        const templateKey = template;
-        const templateValue = templates[template];
-        console.log(templateKey);
-
-        if (templates.hasOwnProperty(template)) {
-
-          const templateKeyArray = templateKey.split(' '); // E.g., "0 $Z" -> ["0", "$Z"]
-          const sortID = Number(templateKeyArray?.[0]); // Sort ID of the template
-          const authorID = templateKeyArray?.[1] || '0'; // User ID of the person who exported the template
-          const displayName = templateValue.name || `Template ${sortID || ''}`; // Display name of the template
-          //const coords = templateValue?.coords?.split(',').map(Number); // "1,2,3,4" -> [1, 2, 3, 4]
-          const tilesbase64 = templateValue.tiles;
-          const templateTiles = {}; // Stores the template bitmap tiles for each tile.
-
-          for (const tile in tilesbase64) {
-            console.log(tile);
-            if (tilesbase64.hasOwnProperty(tile)) {
-              const encodedTemplateBase64 = tilesbase64[tile];
-              const templateUint8Array = base64ToUint8(encodedTemplateBase64); // Base 64 -> Uint8Array
-
-              const templateBlob = new Blob([templateUint8Array], { type: "image/png" }); // Uint8Array -> Blob
-              const templateBitmap = await createImageBitmap(templateBlob) // Blob -> Bitmap
-              templateTiles[tile] = templateBitmap;
-            }
-          }
-
-          // Creates a new Template class instance
-          const template = new Template({
-            displayName: displayName,
-            sortID: sortID || this.templatesArray?.length || 0,
-            authorID: authorID || '',
-            //coords: coords
-          });
-          template.chunked = templateTiles;
-          this.templatesArray.push(template);
-          console.log(this.templatesArray);
-          console.log(`^^^ This ^^^`);
-        }
-      }
-    }
-  }
-
-  /** Parses the OSU! Place JSON object
-   */
-  #parseOSU() {
-
-  }
-
-  /** Sets the `templatesShouldBeDrawn` boolean to a value.
-   * @param {boolean} value - The value to set the boolean to
-   * @since 0.73.7
-   */
-  setTemplatesShouldBeDrawn(value) {
-    this.templatesShouldBeDrawn = value;
-  }
-}
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/utils.js.html b/docs/utils.js.html deleted file mode 100644 index 7d5a74f..0000000 --- a/docs/utils.js.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - - JSDoc: Source: utils.js - - - - - - - - - - -
- -

Source: utils.js

- - - - - - -
-
-

-
-/** Sanitizes HTML to display as plain-text.
- * This prevents some Cross Site Scripting (XSS).
- * This is handy when you are displaying user-made data, and you *must* use innerHTML.
- * @param {string} text - The text to sanitize
- * @returns {string} HTML escaped string
- * @since 0.44.2
- * @example
- * const paragraph = document.createElement('p');
- * paragraph.innerHTML = escapeHTML('<u>Foobar.</u>');
- * // Output:
- * // (Does not include the paragraph element)
- * // (Output is not HTML formatted)
- * <p>
- *   "<u>Foobar.</u>"
- * </p>
- */
-export function escapeHTML(text) {
-  const div = document.createElement('div'); // Creates a div
-  div.textContent = text; // Puts the text in a PLAIN-TEXT property
-  return div.innerHTML; // Returns the HTML property of the div
-}
-
-/** Converts the server tile-pixel coordinate system to the displayed tile-pixel coordinate system.
- * @param {string[]} tile - The tile to convert (as an array like ["12", "124"])
- * @param {string[]} pixel - The pixel to convert (as an array like ["12", "124"])
- * @returns {number[]} [tile, pixel]
- * @since 0.42.4
- * @example
- * console.log(serverTPtoDisplayTP(['12', '123'], ['34', '567'])); // [34, 3567]
- */
-export function serverTPtoDisplayTP(tile, pixel) {
-  return [((parseInt(tile[0]) % 4) * 1000) + parseInt(pixel[0]), ((parseInt(tile[1]) % 4) * 1000) + parseInt(pixel[1])];
-}
-
-/** Negative-Safe Modulo. You can pass negative numbers into this.
- * @param {number} a - The first number
- * @param {number} b - The second number
- * @returns {number} Result
- * @author osuplace
- * @since 0.55.8
- */
-export function negativeSafeModulo(a, b) {
-  return (a % b + b) % b;
-}
-
-/** Bypasses terser's stripping of console function calls.
- * This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't.
- * However, the distributed version needs to call the console somehow, so this wrapper function is how.
- * This is the same as `console.log()`.
- * @param {...any} args - Arguments to be passed into the `log()` function of the Console
- * @since 0.58.9
- */
-export function consoleLog(...args) {((consoleLog) => consoleLog(...args))(console.log);}
-
-/** Bypasses terser's stripping of console function calls.
- * This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't.
- * However, the distributed version needs to call the console somehow, so this wrapper function is how.
- * This is the same as `console.error()`.
- * @param {...any} args - Arguments to be passed into the `error()` function of the Console
- * @since 0.58.13
- */
-export function consoleError(...args) {((consoleError) => consoleError(...args))(console.error);}
-
-/** Bypasses terser's stripping of console function calls.
- * This is so the non-obfuscated code will contain debugging console calls, but the distributed version won't.
- * However, the distributed version needs to call the console somehow, so this wrapper function is how.
- * This is the same as `console.warn()`.
- * @param {...any} args - Arguments to be passed into the `warn()` function of the Console
- * @since 0.58.13
- */
-export function consoleWarn(...args) {((consoleWarn) => consoleWarn(...args))(console.warn);}
-
-/** Encodes a number into a custom encoded string.
- * @param {number} number - The number to encode
- * @param {string} encoding - The characters to use when encoding
- * @since 0.65.2
- * @returns {string} Encoded string
- * @example
- * const encode = '012abcABC'; // Base 9
- * console.log(numberToEncoded(0, encode)); // 0
- * console.log(numberToEncoded(5, encode)); // c
- * console.log(numberToEncoded(15, encode)); // 1A
- * console.log(numberToEncoded(12345, encode)); // 1BCaA
- */
-export function numberToEncoded(number, encoding) {
-
-  if (number === 0) return encoding[0]; // End quickly if number equals 0. No special calculation needed
-
-  let result = ''; // The encoded string
-  const base = encoding.length; // The number of characters used, which determines the base
-
-  // Base conversion algorithm
-  while (number > 0) {
-    result = encoding[number % base] + result; // Find's the character's encoded value determined by the modulo of the base
-    number = Math.floor(number / base); // Divides the number by the base so the next iteration can find the next modulo character
-  }
-
-  return result; // The final encoded string
-}
-
-/** Converts a Uint8 array to base64 using the browser's built-in binary to ASCII function
- * @param {Uint8Array} uint8 - The Uint8Array to convert
- * @returns {Uint8Array} The base64 encoded Uint8Array
- * @since 0.72.9
- */
-export function uint8ToBase64(uint8) {
-  let binary = '';
-  for (let i = 0; i < uint8.length; i++) {
-    binary += String.fromCharCode(uint8[i]);
-  }
-  return btoa(binary); // Binary to ASCII
-}
-
-/** Decodes a base 64 encoded Uint8 array using the browser's built-in ASCII to binary function
- * @param {Uint8Array} base64 - The base 64 encoded Uint8Array to convert
- * @returns {Uint8Array} The decoded Uint8Array
- * @since 0.72.9
- */
-export function base64ToUint8(base64) {
-  const binary = atob(base64); // ASCII to Binary
-  const array = new Uint8Array(binary.length);
-  for (let i = 0; i < binary.length; i++) {
-    array[i] = binary.charCodeAt(i);
-  }
-  return array;
-}
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 4.0.4 on Fri Aug 08 2025 16:09:33 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/jsdoc.json b/jsdoc.json new file mode 100644 index 0000000..12a834e --- /dev/null +++ b/jsdoc.json @@ -0,0 +1,17 @@ +{ + "source": { + "include": ["src"], + "exclude": ["node_modules", "build", "dist"] + }, + "opts": { + "destination": "docs", + "template": "node_modules/minami", + "recurse": true, + "encoding": "utf8" + }, + "plugins": [], + "templates": { + "cleverLinks": false, + "monospaceLinks": false + } +} \ No newline at end of file