mirror of
https://github.com/arfct/itty-bitty.git
synced 2026-03-11 08:54:33 +00:00
24 lines
29 KiB
HTML
24 lines
29 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8"/>
|
||
<meta name="viewport" content="width=device-width, viewport-fit=cover">
|
||
<meta name="description" content="itty bitty things can be conveyed in a link.">
|
||
<link id="favicon" rel="icon" href="/favicon.svg">
|
||
<style>body{font-family:sans-serif}@media(prefers-color-scheme:dark){body{color:white;background-color:#121212}}#iframe{border:0;position:absolute;top:0;left:0;width:100%;height:100%}#edit{font-family:monospace;font-weight:bold;color:rgba(0,0,0,0.54);position:absolute;z-index:100;position:absolute;top:.85em;right:1em;display:none}#edit:not(:hover){text-decoration:none}#warning{position:absolute;border-radius:4px;background-color:#feecc2;padding:1em;font-size:16px;width:20em;z-index:100;top:10vh;left:50vw;margin-left:-10em}#warning:empty{display:none}body.toasting #iframe,body.toasting #edit{opacity:.5;pointer-events:none}body.toasting #toast{box-sizing:border-box;background-color:#feecc2;border-radius:4px;font-size:13px;left:50%;top:10px;margin-left:-160px;padding:1em;position:absolute;max-width:320px;z-index:101}body:not(.toasting) #toast,body.toasting #warning{display:none}body:not(.download) #download{display:none}#download{background:#fafafa;width:100vw;height:100vh;position:absolute;top:0;left:0;display:flex;text-decoration:none;color:black;justify-content:center;align-items:center;flex-direction:column;font-size:14px}#dl-image{width:128px;height:128px;background-position:center;background-repeat:no-repeat;background-image:url("data:image/svg+xml,%0A%3Csvg width='128' height='128' viewBox='0 0 128 128' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cmask id='path-1-outside-1_116_2' maskUnits='userSpaceOnUse' x='27' y='15' width='74' height='98' fill='black'%3E%3Crect fill='white' x='27' y='15' width='74' height='98'/%3E%3Cpath d='M80 16H28V112H100V36L80 16Z'/%3E%3C/mask%3E%3Cpath d='M80 16H28V112H100V36L80 16Z' fill='white'/%3E%3Cpath d='M28 16V15H27V16H28ZM80 16L80.7071 15.2929L80.4142 15H80V16ZM28 112H27V113H28V112ZM100 112V113H101V112H100ZM100 36H101V35.5858L100.707 35.2929L100 36ZM28 17H80V15H28V17ZM29 112V16H27V112H29ZM100 111H28V113H100V111ZM99 36V112H101V36H99ZM100.707 35.2929L80.7071 15.2929L79.2929 16.7071L99.2929 36.7071L100.707 35.2929Z' fill='black' fill-opacity='0.15' mask='url(%23path-1-outside-1_116_2)'/%3E%3C/svg%3E%0A");padding:20px 32px;box-sizing:border-box;display:flex;justify-content:center;align-items:center;color:rgba(0,0,0,0.3);font-weight:bold}#dl-button{text-decoration:none;background:gray;color:white;padding:.5em 1em;border-radius:2em;display:none}#dl-button:hover{background:black}#dl-name{margin-bottom:2em}body:not(.loading) #loader{opacity:.0}#loader{border-radius:50%;width:1em;height:1em;font-size:10px;margin:0 auto;position:relative;text-indent:-9999em;color:white;opacity:1;transition:opacity 500ms;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation:turntable 2.8s infinite ease-in-out;animation:turntable 2.8s infinite ease-in-out;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation-delay:-0.16s;animation-delay:-0.16s;animation-timing-function:ease-in-out;--ld0:.00em 2.25em 0 .20em rgba(127,127,127,1.50);--ld1:.93em 2.24em 0 .20em rgba(127,127,127,1.45);--ld2:1.76em 2.20em 0 .18em rgba(127,127,127,1.31);--ld3:2.43em 2.15em 0 .16em rgba(127,127,127,1.09);--ld4:2.85em 2.08em 0 .13em rgba(127,127,127,0.81);--ld5:3.00em 2.00em 0 .10em rgba(127,127,127,0.50);--ld6:2.85em 1.92em 0 .07em rgba(127,127,127,0.19);--ld7:2.43em 1.85em 0 .04em rgba(127,127,127,-0.09);--ld8:1.76em 1.80em 0 .02em rgba(127,127,127,-0.31);--ld9:.93em 1.76em 0 .00em rgba(127,127,127,-0.45);--ld10:.00em 1.75em 0 .00em rgba(127,127,127,-0.50);--ld11:-0.93em 1.76em 0 .00em rgba(127,127,127,-0.45);--ld12:-1.76em 1.80em 0 .02em rgba(127,127,127,-0.31);--ld13:-2.43em 1.85em 0 .04em rgba(127,127,127,-0.09);--ld14:-2.85em 1.92em 0 .07em rgba(127,127,127,0.19);--ld15:-3.00em 2.00em 0 .10em rgba(127,127,127,0.50);--ld16:-2.85em 2.08em 0 .13em rgba(127,127,127,0.81);--ld17:-2.43em 2.15em 0 .16em rgba(127,127,127,1.09);--ld18:-1.76em 2.20em 0 .18em rgba(127,127,127,1.31);--ld19:-0.93em 2.24em 0 .20em rgba(127,127,127,1.45)}@keyframes turntable{100%,0%{box-shadow:var(--ld0),var(--ld4),var(--ld8),var(--ld12),var(--ld16)}5%{box-shadow:var(--ld1),var(--ld5),var(--ld9),var(--ld13),var(--ld17)}10%{box-shadow:var(--ld2),var(--ld6),var(--ld10),var(--ld14),var(--ld18)}15%{box-shadow:var(--ld3),var(--ld7),var(--ld11),var(--ld15),var(--ld19)}20%{box-shadow:var(--ld4),var(--ld8),var(--ld12),var(--ld16),var(--ld0)}25%{box-shadow:var(--ld5),var(--ld9),var(--ld13),var(--ld17),var(--ld1)}30%{box-shadow:var(--ld6),var(--ld10),var(--ld14),var(--ld18),var(--ld2)}35%{box-shadow:var(--ld7),var(--ld11),var(--ld15),var(--ld19),var(--ld3)}40%{box-shadow:var(--ld8),var(--ld12),var(--ld16),var(--ld0),var(--ld4)}45%{box-shadow:var(--ld9),var(--ld13),var(--ld17),var(--ld1),var(--ld5)}50%{box-shadow:var(--ld10),var(--ld14),var(--ld18),var(--ld2),var(--ld6)}55%{box-shadow:var(--ld11),var(--ld15),var(--ld19),var(--ld3),var(--ld7)}60%{box-shadow:var(--ld12),var(--ld16),var(--ld0),var(--ld4),var(--ld8)}65%{box-shadow:var(--ld13),var(--ld17),var(--ld1),var(--ld5),var(--ld9)}70%{box-shadow:var(--ld14),var(--ld18),var(--ld2),var(--ld6),var(--ld10)}75%{box-shadow:var(--ld15),var(--ld19),var(--ld3),var(--ld7),var(--ld11)}80%{box-shadow:var(--ld16),var(--ld0),var(--ld4),var(--ld8),var(--ld12)}85%{box-shadow:var(--ld17),var(--ld1),var(--ld5),var(--ld9),var(--ld13)}90%{box-shadow:var(--ld18),var(--ld2),var(--ld6),var(--ld10),var(--ld14)}95%{box-shadow:var(--ld19),var(--ld3),var(--ld7),var(--ld11),var(--ld15)}}
|
||
</style>
|
||
<link rel="preload" href="render/recipe.js" as="script" />
|
||
<meta id="themeColor" name="theme-color" content="white" media="(prefers-color-scheme: light)">
|
||
<meta id="themeColorDark" name="theme-color" content="#121212" media="(prefers-color-scheme: dark)">
|
||
<!-- <link rel="manifest" href="/manifest.json"> -->
|
||
<script src="/js/lzma/lzma-d-min.js"></script>
|
||
<script type="module" >const padForBase64=(s,c=" ")=>s.padEnd(s.length+(3-s.length%3)%3,c);const HEAD_TAGS=()=>btoa(padForBase64('<base target="_top">\n'));const HEAD_TAGS_EXTENDED=()=>btoa(padForBase64(`<meta charset="utf-8"><meta name="viewport" content="width=device-width"><base target="_top"><style type="text/css">body{margin:0 auto;padding:12vmin 10vmin;max-width:35em;line-height:1.5em;font-family:-apple-system,BlinkMacSystemFont,sans-serif;word-wrap:break-word;}@media(prefers-color-scheme: dark){body{color:white;background-color:black;}}</style>`));const dataUrlRE=/^data:(?<mediatype>(?<type>[a-z]+)\/(?<subtype>[a-z+\-]+))?(?<params>(?:;[^;,]+=[^;,]+)*)?(?:;(?<encoding>\w+64))?,(?<data>.*)$/;let schemeMappings={r:"application/ld+json;charset=utf-8;format=gz;base64,",h:"text/html;charset=utf-8;format=gz;base64,",t:","};class DataURL{constructor(url){this.initString=url;var colon=url.substring(0,15).indexOf(":");if(colon!=-1){this.scheme=url.substring(0,colon);if(schemeMappings[this.scheme]){url=`data:${schemeMappings[this.scheme]},${url}`}}else{if(url.charAt(0)=="?"){this.editable=true;url=url.substring(1)}this.dataPrefix=HEAD_TAGS_EXTENDED();let encoding=url.startsWith("XQA")?bitty.LZMA_MARKER:bitty.GZIP_MARKER;url=`data:text/html;charset=utf-8;format=${encoding};base64,${url}`}let match=url.match(dataUrlRE);this.params={};if(match){let info=match.groups;Object.assign(this,info);this.params=info.params?JSON.parse('{"'+decodeURI(info.params?.substring(1)).replace(/"/g,'\\"').replace(/;/g,'","').replace(/=/g,'":"')+'"}'):{}}if(this.encoding){this.data=this.data.replace(/=/g,"")}else{this.data=decodeURIComponent(this.data)}}get href(){let urlString="data:";if(this.mediatype)urlString+=this.mediatype;if(this.params)Object.entries(this.params).forEach((e=>urlString+=`;${e[0]}=${e[1]}`));if(this.encoding)urlString+=";"+this.encoding;if(!this.encoding&&this.dataPrefix){this.dataPrefix=atob(this.dataPrefix)}urlString+=","+(this.dataPrefix||"")+this.data;return urlString}get format(){return this.params.format||this.encoding}clone=()=>{var clone=Object.assign(Object.create(Object.getPrototypeOf(this)),this);clone.params={...this.params};return clone};decompress=async()=>{if(this.params.cipher){console.log(this.params.cipher,decryptData);this.data=await decryptData(this.params.cipher,this.data)}if(this.format&&this.format!="base64"){let bytes=base64ToByteArray(this.data);this.rawData=await decompressData(bytes,this.format);this.data=await dataToBase64(this.rawData);delete this.params.format;this.encoding=BASE64_MARKER}return this};compress=async(format=GZIP_MARKER)=>{let rawData=this.encoding?await base64ToByteArray(this.data):stringToByteArray(this.data);let compressedData=await compressData(rawData,format);var base64String=dataToBase64(compressedData);base64String=base64String.replace(/=+$/,"");this.data=base64String;this.params.format=format;return this};parseDom=async()=>{try{const parser=new DOMParser;const doc=parser.parseFromString(`<?xml version="1.0" encoding="UTF-8"?>`+atob(this.data),this.mediatype);return doc}catch(e){}}}function parseBittyURL(url){if(typeof url==="string")url=new URL(url);let location=url.location;let fragment=url.hash;let path=url.pathname;var slashIndex=fragment.indexOf("/");var hashTitle=decodePrettyComponent(fragment.substring(1,slashIndex));var hashData=fragment.substring(slashIndex+1);return{path:path,hashTitle:hashTitle,hashData:hashData}}async function testCompression(rawData){let gz=await compressData(rawData,GZIP_MARKER);console.log(gz.length,typeof gz,dataToBase64(gz).length);let xz=await compressData(rawData,LZMA_MARKER);console.log(xz.length,typeof xz,dataToBase64(xz).length);let ungz=await decompressData(gz,GZIP_MARKER);let unxz=await decompressData(xz,LZMA_MARKER);console.log("unzip",ungz==rawData,unxz==rawData,{ungz:ungz,unxz:unxz,rawData:rawData,raw:byteArrayToString(rawData).substring(684),ungzs:byteArrayToString(ungz).substring(684),unxzs:byteArrayToString(unxz).substring(684)},byteArrayToString(ungz)==byteArrayToString(unxz))}async function compressData(data,encoding=GZIP_MARKER,callback){console.debug("Compressing with",encoding);if(encoding==GZIP_MARKER){return import("/js/gzip/pako.min.js").then((module=>pako.deflate(data,{level:"9"})))}else if(encoding==BROT_MARKER){}else if(encoding==LZMA_MARKER){return new Promise((function(resolve,reject){console.log({xz:data});LZMA.compress(data,9,(function(result,error){if(error)reject(error);resolve(result)}))}))}}function stringToByteArray(string){return(new TextEncoder).encode(string);return Uint8Array.from(string,(c=>c.charCodeAt(0)))}function byteArrayToString(bytes){return(new TextDecoder).decode(bytes);return String.fromCharCode.apply(null,new Uint8Array(bytes))}function browserDecompressData(data){const cs=new DecompressionStream("gzip");const writer=cs.writable.getWriter();writer.write(data);writer.close();return new Response(cs.readable).arrayBuffer().then((function(arrayBuffer){return(new TextDecoder).decode(arrayBuffer)}))}async function decompressData(data,encoding,callback){if(encoding==GZIP_MARKER){return import("/js/gzip/pako.min.js").then((module=>{let byteArray=pako.inflate(data);return byteArray}))}else if(encoding==BROT_MARKER){return import("/js/brotli/decode.js").then((module=>module.BrotliDecode(data)))}else if(encoding==LZMA_MARKER||encoding==LZMA64_MARKER){return new Promise((function(resolve,reject){LZMA.decompress(data,((result,error)=>{if(error)reject(error);resolve(stringToByteArray(result))}))}))}}async function decryptData(cipher,base64){return new Promise(((resolve,reject)=>{loadScript("/js/crypto-js.min.js",(()=>{console.log("decrypting",cipher);let pass=prompt("This page is encrypted. What's the passcode?");if(!pass)resolve(base64);let decrypted=CryptoJS[cipher.toUpperCase()].decrypt(base64,pass);return resolve(CryptoJS.enc.Base64.stringify(decrypted))}))}))}function infoForDataURL(url){return new DataURL(url)}var BASE64_MARKER="base64";var LZMA64_MARKER="bxze64";var BASE_MARKER="bs";var LZMA_MARKER="xz";var GZIP_MARKER="gz";var BROT_MARKER="br";function base64ToByteArray(base64){return Uint8Array.from(atob(base64),(c=>c.charCodeAt(0)))}function loadScript(src,callback){let script=el("script",{src:src});script.addEventListener("load",(function(e){console.debug("Loaded script",src);if(callback)callback(e)}));document.head.appendChild(script)}function escapeStringForIMessage(str){var matches=str.match(/[^\/+=]{1,300}/g);if(matches)str=matches.join("=");return str}async function hashString(string,base=36){const arrayBuffer=await(new TextEncoder).encode(string);const hashAsArrayBuffer=await crypto.subtle.digest("SHA-256",arrayBuffer);const uint8ViewOfHash=new Uint8Array(hashAsArrayBuffer);const hashAsHex=Array.from(uint8ViewOfHash).map((b=>b.toString(16).padStart(2,"0"))).join("");if(base==16)return hashAsHex;if(base==36){const guid=BigInt("0x"+hashAsHex);const asBase36=guid.toString(36).toLowerCase();return asBase36}const hashAsBase64=btoa(String.fromCharCode.apply(null,uint8ViewOfHash));hashAsBase64.replace(/=/g,"").replace(/[\+\/+]/g,"-").toLowerCase();return hashAsBase64}function dataToBase64(data){return btoa(String.fromCharCode.apply(null,new Uint8Array(data)))}function dataToBase64FR(data){return new Promise(((resolve,reject)=>{if(!data||!data.length)return resolve("");var fr=new FileReader;fr.onload=()=>resolve(fr.result.split(",")[1]);fr.onerror=reject;fr.readAsDataURL(new Blob([data],{encoding:"UTF-8",type:"text/html;charset=UTF-8"}))}))}function dataURLToString(durl){return fetch(durl).then((r=>r.blob())).then((blob=>new Promise(((resolve,reject)=>{var fr=new FileReader;fr.onload=()=>resolve(fr.result);fr.onerror=reject;fr.readAsText(blob)}))))}function stringToData(string,callback){if(!string.length)return callback("");var a=new FileReader;a.onload=function(e){callback(e.target.result.replace())};a.readAsDataURL(new Blob([string],{encoding:"UTF-8",type:"text/html;charset=UTF-8"}))}function dataToString(data,callback){return newDataURLtoBlob(data).then((blob=>{var reader=new FileReader;reader.onload=function(e){callback(reader.result)};reader.readAsText(blob)}))}function newDataURLtoBlob(dataURL){return fetch(dataURL).then((r=>r.blob()))}function dataURLtoBlob(dataURL){var byteString=window.atob(dataURL.split(",")[1]);var mimeString=dataURL.split(",")[0].split(":")[1].split(";")[0];var arrayBuffer=new ArrayBuffer(byteString.length);var _ia=new Uint8Array(arrayBuffer);for(var i=0;i<byteString.length;i++){_ia[i]=byteString.charCodeAt(i)}var dataView=new DataView(arrayBuffer);var blob=new Blob([dataView.buffer],{type:mimeString});return blob}function encodePrettyComponent(s){let replacements={" - ":"---","-":"--"," ":"-"};let re=new RegExp("("+Object.keys(replacements).join("|")+")","g");return encodeURIComponent(s.replace(re,(e=>replacements[e]??"-"))).replace(/[!'()*]/g,(c=>"%"+c.charCodeAt(0).toString(16)))}function decodePrettyComponent(s){let replacements={"---":" - ","--":"-","-":" "};return decodeURIComponent(s.replace(/-+/g,(e=>replacements[e]??"-")))}function pathToMetadata(path){let components=path.substring(1).split("/");let info={title:decodePrettyComponent(components.shift())};for(let i=0;i<components.length;i+=2){let key=components[i];let value=components[i+1];if(!value)continue;if(key=="d"){value=decodePrettyComponent(value)}else if(value.includes("%")){value=decodeURIComponent(value)}if(key.length&&value.length)info[key]=value}return info}function metadataToPath(data){if(!data||!data.title)return"/";let path=["/"+encodePrettyComponent(data.title)];if(data.description)path.push("d/"+encodePrettyComponent(data.description.substring(0,200).split(". ").shift()));if(data.favicon)path.push("f/"+encodeURIComponent(data.favicon));if(data.image)path.push("i/"+encodeURIComponent(btoa(data.image).replace(/=/g,"")));return path.join("/")+"/"}const el=(selector,...args)=>{var attrs=args[0]&&typeof args[0]==="object"&&!Array.isArray(args[0])&&!(args[0]instanceof HTMLElement)?args.shift():{};let classes=selector.split(".");if(classes.length>0)selector=classes.shift();if(classes.length)attrs.className=classes.join(" ");let id=selector.split("#");if(id.length>0)selector=id.shift();if(id.length)attrs.id=id[0];var node=document.createElement(selector.length>0?selector:"div");for(let prop in attrs){if(attrs.hasOwnProperty(prop)&&attrs[prop]!=undefined){if(prop.indexOf("data-")==0){let dataProp=prop.substring(5).replace(/-([a-z])/g,(function(g){return g[1].toUpperCase()}));node.dataset[dataProp]=attrs[prop]}else{node[prop]=attrs[prop]}}}const append=child=>{if(Array.isArray(child))return child.forEach(append);if(typeof child=="string")child=document.createTextNode(child);if(child)node.appendChild(child)};args.forEach(append);return node};export{DataURL,infoForDataURL,stringToData,dataToString,hashString,encodePrettyComponent,decodePrettyComponent,metadataToPath,pathToMetadata,parseBittyURL,el,BASE64_MARKER,LZMA64_MARKER,BASE_MARKER,LZMA_MARKER,GZIP_MARKER,BROT_MARKER,HEAD_TAGS,HEAD_TAGS_EXTENDED};
|
||
</script>
|
||
<script type="module" >import*as bitty from"/bitty.js";window.bitty=bitty;const isFramed=window.self!==window.top;function addToast(){}function showLoader(state){let loader=document.getElementById("loader");if(state){if(!loader){loader=document.createElement("div");loader.id="loader";document.body.appendChild(loader)}}else if(loader){setTimeout((()=>loader?.parentElement?.removeChild(loader)),500)}setTimeout((()=>document.body.classList.toggle("loading",state)),1)}window.showLoader=showLoader;function setThemeColor(color){let el=document.getElementById("themeColor");if(!el){el=document.createElement("meta");el.name="theme-color";el.id="themeColor";document.head.appendChild(el)}el.content=color}function setFavicon(favicon){document.getElementById("favicon").href='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em"><text y=".9em">'+favicon+"</text></svg>"}window.el=function(tagName,attrs,...children){let l=document.createElement(tagName);Object.entries(attrs).forEach((([k,v])=>l[k]=v));children.forEach((c=>l.appendChild(c)));return l};const renderers={"application/ld+json":{script:"/render/recipe.html"},"text/canvas+javascript":{script:"canvas"},"text/javascript":{script:"script"},"application/bitsy":{script:"/render/bitsy.html",sandbox:"bitsy"},c:{script:"color"},"text/rawhtml":{script:"parse"},javascript:{script:"bookmarklet"},ipfs:{script:"ipfs",sandbox:"ipfs"},web3:{script:"web3"},"text/directory":{script:"download",args:{extension:"vcf",filename:"contact"}}};function share(info){if(!info.url)info={title:document.title,text:document.title,url:location.href};console.log("Share",info);if(navigator.share){navigator.share(info).then((()=>{console.log("Thanks for sharing!")})).catch(console.error)}else{copyLink(info)}}function copyLink(info){var text=info.url;var dummy=document.createElement("input");document.body.appendChild(dummy);dummy.value=text;dummy.select();document.execCommand("copy");document.body.removeChild(dummy);document.body.classList.add("copied");setTimeout((function(){document.body.classList.remove("copied")}),2e3)}let wakeLock;const getWakeLock=async()=>{try{if(navigator.wakeLock){wakeLock=await navigator.wakeLock.request();wakeLock.addEventListener("release",(()=>{}));console.log("Keeping Screen Awake:",!wakeLock.released)}else{}}catch(err){console.error(`${err.name}, ${err.message}`)}};function keepAwake(){let ctx=new AudioContext;let bufferSize=2*ctx.sampleRate,emptyBuffer=ctx.createBuffer(1,bufferSize,ctx.sampleRate),output=emptyBuffer.getChannelData(0);for(let i=0;i<bufferSize;i++)output[i]=0;let source=ctx.createBufferSource();source.buffer=emptyBuffer;source.loop=true;let node=ctx.createMediaStreamDestination();source.connect(node);let audio=document.createElement("audio");audio.style.display="none";document.body.appendChild(audio);audio.srcObject=node.stream;audio.play()}const handleVisibilityChange=async()=>{if(wakeLock!==null&&document.visibilityState==="visible"){await getWakeLock()}};document.addEventListener("visibilitychange",handleVisibilityChange);window.addEventListener("message",(function(e){console.debug("Message:",e.origin,e.data);showLoader(false);if(e.data.loading!=undefined)showLoader(e.data.loading);if(e.data.title)document.title=e.data.title;if(e.data.favicon)setFavicon(e.data.favicon);if(e.data.themeColor)setThemeColor(e.data.themeColor);if(e.data.updateURL){let path=bitty.metadataToPath(e.data)+window.location.hash;window.history.replaceState(null,null,path)}if(e.data.share){share(e.data.share)}if(e.data.wakeLock){getWakeLock()}if(e.data.updateHash){window.history.replaceState(null,null,e.data.updateHash)}if(e.data.replaceURL){if(e.data.compressURL){let durl=new bitty.DataURL(e.data.replaceURL);durl.compress().then((arg=>{window.history.replaceState(null,null,"/#/"+arg.href);renderContent()}))}else{window.history.replaceState(null,null,e.data.replaceURL);renderContent()}}if(e.data.setStorage)document.localStorage.setItem(contentHash,e.data.set);if(e.data.getStorage)document.getElementById("iframe").postMessage(document.localStorage.getItem(contentHash),e.origin)}),false);async function renderContent(){showLoader(true);var fragment=window.location.hash.substring(1);if(fragment.length<3&&!isFramed){return location.href="/edit"}if(window.location.search){window.history.replaceState(null,null,window.location.search.substring(1)+"#"+fragment)}var isIE=navigator.userAgent.match(/rv:11/);var isEdge=navigator.userAgent.match(/Edge\//);var isWatch=window.outerWidth<220;let bittyInfo=bitty.parseBittyURL(location);let durl=new bitty.DataURL(bittyInfo.hashData);if(durl.params.compress){console.log("Compressing URL",durl);delete durl.params.compress;durl.compress(bitty.GZIP_MARKER).then((arg=>{window.history.replaceState(null,null,"/#/"+arg.href);renderContent()}));return}var iframe=document.getElementById("iframe");var dataPrefix=undefined;var renderMode="data";var renderer;let components=window.location.pathname.substring(1).split("/");let info={};info.title=decodeURIComponent(components.shift()).replace(/-/g," ").replace(/–/g,"-");let i;for(i=0;i<components.length;i+=2){let key=components[i];let value=decodeURIComponent(components[i+1]);if(key.length&&value.length)info[key]=value}info.d=info.d?.replace(/-/g," ").replace(/–/g,"-");if(info.f)setFavicon(info.f);var slashIndex=fragment.indexOf("/");var title=fragment.substring(0,slashIndex)||info.title;if(title)title=decodeURIComponent(title.replace(/_/g," "));var type=undefined;var description=undefined;document.title=title??location.hostname;fragment=fragment.substring(slashIndex+1);var editable=fragment.charAt(0)=="?";var link=document.getElementById("edit");if(editable){fragment=fragment.substring(1);document.body.appendChild(el("a",{id:"edit",onclick:function(){location.href="/edit"+location.hash}}))}if(fragment.startsWith("data:")){renderer=durl.params?.render?{script:durl.params.render,sandbox:"hash"}:renderers[durl.mediatype];type="data:"+durl.mediaype;if(durl.mediatype=="text/html"){dataPrefix=bitty.HEAD_TAGS()}else if(durl.mediatype=="text/plain"||durl.mediatype==undefined){dataPrefix=bitty.HEAD_TAGS_EXTENDED();durl.mediatype="text/html";renderMode="data"}else if(durl.type=="text"){}else if(durl.type=="image"){}else if(durl.type==undefined){}else if(!renderer){console.log("unknown type, rendering as download");renderMode="download"}if(renderer){var script=renderer.script;if(script.indexOf("/")==-1)script=location.origin+"/render/"+script+".js";renderMode="script"}}else{var colon=fragment.indexOf(":");if(colon>0&&colon<15){document.body.classList.remove("toasting");let scheme=fragment.substring(0,colon);type=scheme;let renderer=renderers[scheme];if(renderer){return renderContentWithScript({renderer:renderer,title:title,info:info,body:fragment,url:fragment})}return window.location.replace(fragment)}var compressed=true;dataPrefix=bitty.HEAD_TAGS_EXTENDED();let encoding=!compressed?"base64,":fragment.startsWith("XQA")?bitty.LZMA_MARKER:bitty.GZIP_MARKER;durl=new bitty.DataURL(`data:text/html;charset=utf-8;format=${encoding};base64,${fragment}`)}if((isEdge||isIE)&&location.href.length==2083){let element=document.getElementById("warning")||document.body.appendChild(el("div",{id:"warning"}));element.innerHTML='Edge only supports shorter URLs (maximum 2083 bytes).<br>Larger sites may require a different browser.<br><a href="http://reference.bitty.site">Learn more</a>'}await durl.decompress();durl.dataPrefix=dataPrefix;let dataURL=durl.href;let dataContent=durl.rawData;if(!dataURL)return;iframe.sandbox="allow-same-origin allow-downloads allow-scripts allow-forms allow-top-navigation allow-popups allow-modals allow-popups-to-escape-sandbox";if(isIE&&renderMode=="data")renderMode="frame";let contentTarget;if(isWatch){console.log("Rendering for watch");contentTarget=document}console.log("🖋 Rendering mode: "+"[1m"+renderMode,{url:durl});if(renderMode=="download"){try{let extension=title.split(".");let dl=el("a",{id:"download",href:dataURL,download:title},el("div",{id:"dl-image",innerText:extension.pop()??""}),el("div",{id:"dl-name",innerText:"title"}),el("div",{id:"dl-button"}));document.body.append(dl);document.body.classList.add("download");dl.click();return}catch(e){console.log("DL error",e);iframe.src=dataURL;showLoader(false)}}else if(renderMode=="data"){iframe.src=dataURL;showLoader(false)}else{bitty.dataToString(dataURL,(function(content){if(renderMode=="frame"){writeDocContent(contentTarget,content)}else if(renderMode=="script"){renderContentWithScript({renderer:renderer,title:title,info:info,body:content,url:dataURL,overwrite:contentTarget==document})}}))}let recordHistory=true;if(!isFramed&&recordHistory)recordToHistory(durl)}window.addEventListener("DOMContentLoaded",renderContent);window.addEventListener("hashchange",renderContent);const SCRIPT_LOADER=`<!doctype html><meta charset=utf-8><script src="${location.origin}/render.js"><\/script>`;async function renderContentWithScript(params){params.script=params.renderer.script;params.originalURL=location.href;if(params.script.indexOf("/")==-1)params.script=location.origin+"/render/"+params.script+".js";if(params.overwrite){let scriptEl=document.createElement("script");scriptEl.src="/render.js";scriptEl.addEventListener("load",(function(e){console.log("Loaded script",scriptEl.src);renderScriptContent(params,"*")}));document.head.appendChild(scriptEl)}else{iframe.onload=()=>{iframe.contentWindow.postMessage(params,"*");delete iframe.onload;iframe.contentWindow.focus()};let src=window.scriptDomain??location.origin;src+="/render";let sandbox=params.renderer?.sandbox;if(params.script.endsWith(".html")){src=params.script;if(!sandbox)sandbox="none"}if(sandbox=="none"){}else if(sandbox=="hash"){let hash=await bitty.hashString(params.body);src=src.replace("https://","https://script-"+hash+".")}else if(sandbox){src=src.replace("https://","https://"+sandbox+".")}else{src="data:text/html,"+SCRIPT_LOADER}console.log("📜 Loading script with source:",src);iframe.src=src}}function writeDocContent(doc,content){doc.open();doc.write(content);doc.close()}function extractTerms(...args){let wordSet={};args.forEach((string=>{if(string)string.split(/\s/).forEach((word=>{if(word.length>2)wordSet[word.toLowerCase()]=true}))}));return Object.keys(wordSet)}async function recordToHistory(){let location=window.location;let fragment=location.hash;fragment=fragment.substring(fragment.indexOf("/")+1);let hash=await bitty.hashString(fragment);let durl=new bitty.DataURL(fragment);let type=durl.mediatype;let metadata=bitty.pathToMetadata(location.pathname);if(!metadata.title){let dom=await(await durl.decompress()).parseDom();if(dom){for(let el of dom.getElementsByTagName("script")){el.parentNode.removeChild(el)}metadata.title=dom.title;metadata.description=dom.body?.innerText.trim();if(!metadata.title.length){metadata.title=dom.body?.children[0]?.innerText.trim()?.split("\n").pop()}metadata.description=metadata.description?.replace(metadata.title,"").trim()}console.debug("Extracting metadata from content",metadata)}if(navigator.storage&&navigator.storage.persist)navigator.storage.persist().then((granted=>{if(granted)console.debug("Storage will not be cleared except by explicit user action");else console.debug("Storage may be cleared by the UA under storage pressure.")}));let openRequest=indexedDB.open("history",3);openRequest.onupgradeneeded=function(event){console.log("Upgrading Database",event);const db=event.target.result;const transaction=event.target.transaction;let objectStore;if(!db.objectStoreNames.contains("urls")){objectStore=db.createObjectStore("urls",{keyPath:"id"})}else{objectStore=transaction.objectStore("urls")}objectStore.createIndex("created","created");objectStore.createIndex("type","type");objectStore.createIndex("terms","terms",{multiEntry:true})};openRequest.onerror=function(){console.error("Error",openRequest.error)};openRequest.onsuccess=()=>{let db=openRequest.result;let transaction=db.transaction("urls","readwrite");let history=transaction.objectStore("urls");let hashCode=s=>s.split("").reduce(((a,b)=>{a=(a<<5)-a+b.charCodeAt(0);return a&a}),0);let terms=extractTerms(metadata.title,metadata.description);let entry={id:hash,url:location.href,title:metadata.title||"",text:metadata.description?.substring(0,256),type:type,terms:terms,created:new Date};console.log("🕙 Adding history",{entry:entry});let request=history.put(entry);request.onsuccess=function(){console.debug("entry added to the history",request.result)};request.onerror=function(){console.log("Error",request.error)}}}
|
||
</script>
|
||
<script type="module" src="/js/gzip/pako.min.js" ></script>
|
||
<script nomodule> location.href = "/v1/" + location.hash </script>
|
||
<noscript>itty.bitty requires JavaScript.</noscript>
|
||
</head>
|
||
<iframe id="iframe" sandbox="allow-same-origin allow-downloads allow-scripts allow-forms allow-top-navigation allow-popups allow-modals allow-popups-to-escape-sandbox"></iframe>
|
||
</html>
|