2022-10-20 04:47:36 +00:00
import * as bitty from '/bitty.js' ;
2023-02-11 16:32:12 +00:00
import * as bitty _menu from '/bitty-menu.js' ;
2022-01-29 19:40:35 +00:00
2022-06-09 05:53:37 +00:00
window . bitty = bitty ;
2022-05-17 15:38:05 +00:00
// if ('serviceWorker' in navigator) {
// navigator.serviceWorker
// .register('/worker.js')
// .then(function() { console.debug("Service Worker Registered"); });
// }
2022-01-29 19:40:35 +00:00
2022-06-30 14:25:05 +00:00
const isFramed = window . self !== window . top ;
2022-06-29 15:34:17 +00:00
2022-05-20 15:37:00 +00:00
function addToast ( ) {
// `<div id="toast">
// itty.bitty is experimental technology that renders linked content from outside sources.
// <a href="http://toast.bitty.site" target="_blank">Learn more</a>.
// <br><br>This content is only as trustworthy as its source, and it should be treated with the caution you would show any insecure web page.
// <br><br><button onclick="dismiss()">I understand</button> <input id="never" type="checkbox"><label for="never">Never show this</label>
// </div>`
}
2022-06-30 14:25:05 +00:00
// function dismiss() {
// if (document.getElementById("never").checked) window.localStorage.setItem('toasted', true);
// document.body.classList.remove("toasting")
// }
2023-02-11 16:32:12 +00:00
function getIframe ( ) {
if ( ! document . iframe ) {
let iframe = document . createElement ( 'iframe' ) ;
iframe . id = "iframe" ;
iframe . sandbox = "allow-same-origin allow-scripts allow-forms allow-top-navigation allow-popups allow-modals allow-popups-to-escape-sandbox" ;
if ( iframe . sandbox . supports ( 'allow-downloads' ) ) iframe . sandbox . add ( 'allow-downloads' ) ;
document . body . appendChild ( iframe ) ;
document . iframe = iframe ;
}
return document . iframe ;
}
async function getMenu ( ) {
if ( ! document . menuButton ) {
let menuButton = document . createElement ( 'div' ) ;
menuButton . id = "menu" ;
menuButton . innerHTML = ` <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><g fill-rule="evenodd" class="logo" clip-rule="evenodd"><path fill="#fff" d="M6.5 19.5a2 2 0 0 1-2-2v-11a2 2 0 0 1 2-2h8a5 5 0 0 1 4.33 7.5 5 5 0 0 1-4.33 7.5h-8Z" class="outer"/><path fill="#16161D" d="M6.5 5.5a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1h2v-13h-2Zm8 3h-2v2h2a1 1 0 1 0 0-2Zm-5 0v10h5a4 4 0 0 0 3.123-6.5A4 4 0 0 0 14.5 5.5h-5v3Zm3 5h2a1 1 0 1 1 0 2h-2v-2Z" class="inner"/></g></svg> `
menuButton . onclick = ( ) => {
let menu = new bitty _menu . Menu ( menuButton ) ;
console . log ( "men" , menu )
menu . show ( )
}
document . body . appendChild ( menuButton ) ;
document . menuButton = menuButton ;
}
return document . menuButton ;
}
getMenu ( )
2022-12-04 18:03:10 +00:00
let autohideTimeout ;
2022-06-29 15:34:17 +00:00
function showLoader ( state ) {
let loader = document . getElementById ( "loader" ) ;
2022-12-04 18:03:10 +00:00
if ( autohideTimeout ) {
clearTimeout ( autohideTimeout ) ;
autohideTimeout = undefined ;
}
2022-06-29 15:34:17 +00:00
if ( state ) {
if ( ! loader ) {
loader = document . createElement ( "div" ) ;
loader . id = "loader" ;
document . body . appendChild ( loader ) ;
2022-12-04 18:03:10 +00:00
}
autohideTimeout = setTimeout ( ( ) => { showLoader ( false ) } , 3000 )
2022-06-30 14:25:05 +00:00
} else if ( loader ) {
2022-12-04 18:03:10 +00:00
setTimeout ( ( ) => loader ? . parentElement ? . removeChild ( loader ) , 1000 )
2022-06-29 15:34:17 +00:00
}
2022-12-04 18:03:10 +00:00
setTimeout ( ( ) => document . body . classList . toggle ( "loading" , state ) , 500 )
2022-06-11 15:48:32 +00:00
}
2022-06-29 15:34:17 +00:00
window . showLoader = showLoader ;
2022-01-12 14:49:23 +00:00
2022-06-30 15:50:57 +00:00
// Document Attribute Setters
2022-06-11 05:29:43 +00:00
function setThemeColor ( color ) {
2022-06-15 14:52:10 +00:00
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 ;
2022-06-11 05:29:43 +00:00
}
2022-01-29 19:40:35 +00:00
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>'
2022-01-19 07:57:49 +00:00
}
2022-12-23 03:50:09 +00:00
window . el = bitty . el ;
2022-02-15 23:28:50 +00:00
const renderers = {
2022-12-04 18:03:10 +00:00
"application/ld+json" : { script : "/render/recipe.html" } ,
2022-07-02 21:28:23 +00:00
"text/canvas+javascript" : { script : "canvas" } ,
"text/javascript" : { script : "script" } ,
2023-05-29 05:55:31 +00:00
// "text/vcard": {script:"/render/contact.html"},
2023-06-06 19:05:48 +00:00
"mecard" : { script : "/render/contact.html" } ,
2022-07-09 15:33:14 +00:00
"application/bitsy" : { script : "/render/bitsy.html" , sandbox : "bitsy" } ,
2022-07-02 21:28:23 +00:00
"c" : { script : "color" } ,
2022-12-04 18:03:10 +00:00
"e" : { rewrite : "data:text/html;cipher=aes;format=gz;base64," } ,
2022-05-12 05:35:27 +00:00
"text/rawhtml" : { script : "parse" } ,
2022-02-17 17:54:22 +00:00
"javascript" : { script : "bookmarklet" } ,
2022-06-15 14:52:10 +00:00
"ipfs" : { script : "ipfs" , sandbox : "ipfs" } ,
"web3" : { script : "web3" } ,
2023-02-11 17:02:41 +00:00
"text/directory" : { script : "download" , args : { extension : "vcf" , filename : "contact" } } ,
"text/calendar" : { script : "download" , args : { extension : "ics" , filename : "calendar" } }
2022-06-09 05:53:37 +00:00
}
2022-01-29 19:40:35 +00:00
2022-06-15 14:52:10 +00:00
function share ( info ) { // {title, text, url}
2023-02-11 16:32:12 +00:00
let menu = new bitty _menu . Menu ( ) ;
console . log ( "men" , menu )
menu . show ( info )
return ;
}
function systemShare ( info ) {
2022-06-15 14:52:10 +00:00
if ( ! info . url ) info = { title : document . title , text : document . title , url : location . href } ;
2022-12-23 03:50:09 +00:00
2022-06-15 14:52:10 +00:00
if ( navigator . share ) {
navigator . share ( info )
2022-12-04 18:03:10 +00:00
. then ( ( ) => { console . log ( 'Shared!' ) ; } )
2022-06-15 14:52:10 +00:00
. 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" ) ;
} , 2000 ) ;
}
2022-06-20 13:58:13 +00:00
let wakeLock ;
const getWakeLock = async ( ) => {
try {
2022-08-07 20:27:01 +00:00
if ( navigator . wakeLock ) {
wakeLock = await navigator . wakeLock . request ( ) ;
wakeLock . addEventListener ( 'release' , ( ) => { } ) ;
2022-12-04 18:03:10 +00:00
console . log ( '💡 Keeping Screen Awake:' , ! wakeLock . released ) ;
2022-08-07 20:27:01 +00:00
} else {
// keepAwake();
}
2022-06-20 13:58:13 +00:00
} catch ( err ) {
console . error ( ` ${ err . name } , ${ err . message } ` ) ;
}
} ;
2022-08-07 20:27:01 +00:00
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 ( ) ;
}
2022-06-20 13:58:13 +00:00
const handleVisibilityChange = async ( ) => {
if ( wakeLock !== null && document . visibilityState === 'visible' ) {
await getWakeLock ( ) ;
}
} ;
document . addEventListener ( 'visibilitychange' , handleVisibilityChange ) ;
2022-06-15 14:52:10 +00:00
2022-01-29 19:40:35 +00:00
window . addEventListener ( "message" , function ( e ) {
2023-02-11 16:32:12 +00:00
console . debug ( "Message:" , e . origin , e . data , e )
2022-09-08 06:03:11 +00:00
showLoader ( false ) ;
if ( e . data . loading != undefined ) showLoader ( e . data . loading ) ;
2022-01-29 19:40:35 +00:00
if ( e . data . title ) document . title = e . data . title ;
if ( e . data . favicon ) setFavicon ( e . data . favicon ) ;
2022-06-11 05:29:43 +00:00
if ( e . data . themeColor ) setThemeColor ( e . data . themeColor ) ;
2022-04-29 03:10:15 +00:00
if ( e . data . updateURL ) {
2022-09-08 06:03:11 +00:00
let path = bitty . metadataToPath ( e . data ) + window . location . hash ;
window . history . replaceState ( null , null , path ) ;
2022-05-17 15:38:05 +00:00
}
2022-06-09 05:53:37 +00:00
2022-06-15 14:52:10 +00:00
if ( e . data . share ) {
share ( e . data . share ) ;
}
2022-06-20 13:58:13 +00:00
if ( e . data . wakeLock ) {
getWakeLock ( ) ;
}
2022-07-02 21:44:18 +00:00
if ( e . data . updateHash ) {
window . history . replaceState ( null , null , e . data . updateHash ) ;
}
2022-05-17 15:38:05 +00:00
if ( e . data . replaceURL ) {
2022-06-09 05:53:37 +00:00
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 ( ) ;
}
2022-04-29 03:10:15 +00:00
}
2022-12-23 03:50:09 +00:00
if ( e . data . error ) {
showError ( e . data . error )
}
2022-01-29 19:40:35 +00:00
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 )
2022-05-17 15:38:05 +00:00
} , false ) ;
2022-12-23 03:50:09 +00:00
function showError ( error ) {
console . warn ( "🛑" , error )
2023-02-11 16:32:12 +00:00
let dialog = el ( "dialog.dialog" ,
2022-12-23 03:50:09 +00:00
el ( "div" , { } , error ) ,
el ( "form" , { method : "dialog" } ,
2022-12-23 04:07:22 +00:00
el ( "button" , { onclick : ( ) => location . href = "https://parse.bitty.site" } , "Learn More" ) ,
2022-12-23 03:50:09 +00:00
el ( "button" , { onclick : history . back . bind ( history ) } , "Go Back" ) ) ) ;
document . body . appendChild ( dialog )
dialog . showModal ( ) ;
}
2022-06-29 15:34:17 +00:00
async function renderContent ( ) {
2022-12-04 18:03:10 +00:00
2022-06-29 15:34:17 +00:00
showLoader ( true )
2022-06-30 14:25:05 +00:00
2022-04-28 03:01:03 +00:00
var fragment = window . location . hash . substring ( 1 ) ;
2022-12-04 18:03:10 +00:00
let content = null //sessionStorage.getItem("editor-content");
if ( content || ( fragment . length < 3 && ! isFramed ) ) {
2022-06-30 14:25:05 +00:00
return location . href = "/edit" ;
}
2022-01-29 19:40:35 +00:00
if ( window . location . search ) { // Redirect search to path (coming out of server opengraph forwarding)
2022-04-28 03:01:03 +00:00
window . history . replaceState ( null , null , window . location . search . substring ( 1 ) + "#" + fragment ) ;
2022-01-29 19:40:35 +00:00
}
var isIE = navigator . userAgent . match ( /rv:11/ ) ;
var isEdge = navigator . userAgent . match ( /Edge\// ) ;
2022-09-19 04:23:37 +00:00
var isWatch = ( window . outerWidth < 220 ) ;
2022-01-29 19:40:35 +00:00
2022-06-30 14:25:05 +00:00
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 ;
2022-01-29 19:40:35 +00:00
}
2019-06-24 20:10:27 +00:00
// if (!window.localStorage.getItem('toasted')) document.body.classList.add("toasting");
2018-07-11 05:38:55 +00:00
2023-02-11 16:32:12 +00:00
var iframe = getIframe ( ) ;
2022-01-29 19:40:35 +00:00
var dataPrefix = undefined ;
2022-01-21 23:08:26 +00:00
var renderMode = "data" ;
2022-06-11 03:48:44 +00:00
var renderer ;
2018-07-08 15:17:48 +00:00
2022-05-18 05:36:38 +00:00
let components = window . location . pathname . substring ( 1 ) . split ( "/" ) ;
let info = { }
2022-05-20 15:37:00 +00:00
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 ] ) ;
2022-05-18 05:36:38 +00:00
if ( key . length && value . length ) info [ key ] = value ;
2022-05-20 15:37:00 +00:00
}
info . d = info . d ? . replace ( /-/g , " " ) . replace ( /– /g , "-" ) ;
2022-05-18 05:36:38 +00:00
2022-05-20 15:56:39 +00:00
if ( info . f ) setFavicon ( info . f ) ;
2022-05-18 05:36:38 +00:00
2022-01-29 19:40:35 +00:00
var slashIndex = fragment . indexOf ( "/" ) ;
2022-05-20 15:56:39 +00:00
var title = fragment . substring ( 0 , slashIndex ) || info . title ;
2022-05-17 15:38:05 +00:00
if ( title ) title = decodeURIComponent ( title . replace ( /_/g , " " ) )
var type = undefined ;
var description = undefined ;
document . title = title ? ? location . hostname ;
2018-07-08 15:17:48 +00:00
2022-01-29 19:40:35 +00:00
fragment = fragment . substring ( slashIndex + 1 ) ;
var editable = fragment . charAt ( 0 ) == "?" ;
2022-02-15 23:28:50 +00:00
var link = document . getElementById ( "edit" ) ;
2018-07-08 15:17:48 +00:00
if ( editable ) {
2022-01-29 19:40:35 +00:00
fragment = fragment . substring ( 1 ) ;
2022-02-15 23:28:50 +00:00
document . body . appendChild ( el ( "a" , { id : "edit" , onclick : function ( ) { location . href = "/edit" + location . hash } } ) )
// link.href = "/edit" + location.hash;
2018-07-08 16:18:51 +00:00
}
2022-02-15 23:28:50 +00:00
2022-01-29 19:40:35 +00:00
if ( fragment . startsWith ( "data:" ) ) {
2022-04-28 03:01:03 +00:00
2022-06-30 14:25:05 +00:00
renderer = durl . params ? . render ? { script : durl . params . render , sandbox : "hash" } : renderers [ durl . mediatype ] ;
2022-07-02 21:28:23 +00:00
2022-12-24 07:22:29 +00:00
//if (render.script == "parse") renderer.sandbox = "none"
2022-06-30 14:25:05 +00:00
type = "data:" + durl . mediaype ;
if ( durl . mediatype == "text/html" ) {
2023-02-11 16:32:12 +00:00
dataPrefix = bitty . HEAD _TAGS ( durl . params ? . prefix ) ;
2022-06-30 14:25:05 +00:00
} else if ( durl . mediatype == "text/plain" || durl . mediatype == undefined ) {
dataPrefix = bitty . HEAD _TAGS _EXTENDED ( ) ;
durl . mediatype = "text/html" ;
// fragment = fragment.replace("text/plain,", "text/html").replace(",", "text/html");
2022-02-15 23:28:50 +00:00
renderMode = "data" ;
2022-06-30 14:25:05 +00:00
} else if ( durl . type == "text" ) {
} else if ( durl . type == "image" ) {
} else if ( durl . type == undefined ) {
2022-04-28 03:01:03 +00:00
} else if ( ! renderer ) {
2022-02-15 23:28:50 +00:00
console . log ( "unknown type, rendering as download" )
2023-02-11 17:09:40 +00:00
renderer = { script : "download" }
2022-01-29 19:40:35 +00:00
}
2022-12-04 18:03:10 +00:00
if ( durl . params . style == "default" ) {
dataPrefix = bitty . HEAD _TAGS _EXTENDED ( ) ;
}
2022-02-15 23:28:50 +00:00
if ( renderer ) {
2022-06-11 03:48:44 +00:00
var script = renderer . script ;
2022-02-15 23:28:50 +00:00
if ( script . indexOf ( "/" ) == - 1 ) script = location . origin + '/render/' + script + '.js'
renderMode = "script" ;
}
2022-01-29 19:40:35 +00:00
} else {
var colon = fragment . indexOf ( ":" ) ;
2019-03-17 00:14:49 +00:00
if ( colon > 0 && colon < 15 ) {
document . body . classList . remove ( "toasting" ) ;
2022-02-15 23:28:50 +00:00
let scheme = fragment . substring ( 0 , colon ) ;
2022-05-17 15:38:05 +00:00
type = scheme ;
2023-05-29 05:55:31 +00:00
let renderer = renderers [ scheme . toLowerCase ( ) ] ;
2022-02-15 23:28:50 +00:00
if ( renderer ) {
2022-06-15 14:52:10 +00:00
return renderContentWithScript ( { renderer , title , info , body : fragment , url : fragment } ) ;
2022-02-15 23:28:50 +00:00
}
2022-01-29 19:40:35 +00:00
return window . location . replace ( fragment ) ;
2019-03-17 00:14:49 +00:00
}
2022-02-15 23:28:50 +00:00
2018-07-08 15:17:48 +00:00
var compressed = true ;
2022-06-30 14:25:05 +00:00
dataPrefix = bitty . HEAD _TAGS _EXTENDED ( ) ;
2022-06-09 05:53:37 +00:00
let encoding = ! compressed ? "base64," : ( fragment . startsWith ( "XQA" ) ? bitty . LZMA _MARKER : bitty . GZIP _MARKER ) ;
2022-06-30 14:25:05 +00:00
durl = new bitty . DataURL ( ` data:text/html;charset=utf-8;format= ${ encoding } ;base64, ${ fragment } ` ) ;
2018-07-08 16:18:51 +00:00
}
2022-02-15 23:28:50 +00:00
2018-07-08 15:17:48 +00:00
if ( ( isEdge || isIE ) && location . href . length == 2083 ) {
2022-02-15 23:28:50 +00:00
let element = document . getElementById ( "warning" ) || document . body . appendChild ( el ( "div" , { id : "warning" } ) )
element . innerHTML =
2018-07-08 16:18:51 +00:00
'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>' ;
}
2022-02-15 23:28:50 +00:00
2022-12-04 18:03:10 +00:00
await durl . decompress ( )
if ( durl . error ) {
writeDocContent ( iframe . contentWindow . document , atob ( bitty . HEAD _TAGS _EXTENDED ( ) ) + ` <style>.error{color:red; background:pink; max-width:320px; margin:auto; padding:1em;}</style><div class="error"> ${ durl . error } </div> ` )
showLoader ( false )
return
}
2022-06-09 05:53:37 +00:00
durl . dataPrefix = dataPrefix ;
let dataURL = durl . href ;
let dataContent = durl . rawData ;
2022-06-15 14:52:10 +00:00
if ( ! dataURL ) return ;
if ( isIE && renderMode == "data" ) renderMode = "frame" ;
2022-12-28 07:44:40 +00:00
let overwriteSelf = isWatch && ! params . script . endsWith ( ".html" ) ;
2022-12-24 07:22:29 +00:00
2022-07-02 21:28:23 +00:00
console . log ( "🖋 Rendering mode: " + "\x1B[1m" + renderMode , { url : durl } )
2022-12-04 18:03:10 +00:00
2023-02-11 17:09:40 +00:00
if ( renderMode == "data" ) {
2022-06-15 14:52:10 +00:00
iframe . src = dataURL ;
2022-06-29 15:34:17 +00:00
showLoader ( false )
2022-06-15 14:52:10 +00:00
} else {
bitty . dataToString ( dataURL , function ( content ) {
if ( renderMode == "frame" ) {
2022-12-24 07:22:29 +00:00
writeDocContent ( overwriteSelf ? document : iframe . contentWindow . document , content )
2022-06-15 14:52:10 +00:00
} else if ( renderMode == "script" ) {
2022-12-24 07:22:29 +00:00
renderContentWithScript ( { renderer , title , info , body : content , url : dataURL , overwrite : overwriteSelf } ) ;
2022-06-15 14:52:10 +00:00
}
} ) ;
2022-06-09 05:53:37 +00:00
}
2022-05-17 15:38:05 +00:00
2022-06-28 15:43:25 +00:00
let recordHistory = true
2022-06-30 14:25:05 +00:00
if ( ! isFramed && recordHistory ) recordToHistory ( durl ) ;
2022-01-29 19:40:35 +00:00
} ;
2022-06-29 15:34:17 +00:00
window . addEventListener ( 'DOMContentLoaded' , renderContent ) ;
window . addEventListener ( 'hashchange' , renderContent ) ;
2022-05-17 15:38:05 +00:00
2022-06-09 05:53:37 +00:00
2022-02-17 17:54:22 +00:00
const SCRIPT _LOADER = ` <!doctype html><meta charset=utf-8><script src=" ${ location . origin } /render.js"></script> `
2022-06-15 14:52:10 +00:00
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'
2022-06-09 05:53:37 +00:00
2022-06-15 14:52:10 +00:00
if ( params . overwrite ) {
2022-12-28 07:44:40 +00:00
if ( params . script . endsWith ( ".html" ) ) {
fetch ( params . script , /*, options */ )
. then ( ( response ) => response . text ( ) )
. then ( ( html ) => {
console . log ( "html" , html )
document . documentElement . innerHTML = html ;
} )
. catch ( ( error ) => {
console . warn ( error ) ;
} ) ;
} else {
// Overwrite the current page with the script. Dangerous, but required for browsers on apple watch to scroll.
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 ) ;
}
2022-06-15 14:52:10 +00:00
} else {
// Render in an iframe, either via sandboxed subdomain or a data url (disables storage APIs)
2022-06-09 05:53:37 +00:00
iframe . onload = ( ( ) => {
2022-06-15 14:52:10 +00:00
iframe . contentWindow . postMessage ( params , "*" ) ;
2022-06-09 05:53:37 +00:00
delete iframe . onload
2022-06-28 15:43:25 +00:00
iframe . contentWindow . focus ( ) ;
2022-09-08 06:03:11 +00:00
// showLoader(false)
2022-06-09 05:53:37 +00:00
} ) ;
// writeDocContent(iframe.contentWindow.document, SCRIPT_LOADER)
// iframe.srcdoc = SCRIPT_LOADER;
2022-02-15 23:28:50 +00:00
2022-06-17 01:48:41 +00:00
let src = window . scriptDomain ? ? location . origin ;
src += "/render" ;
2022-07-09 15:33:14 +00:00
2022-10-20 04:47:36 +00:00
let sandbox = params . renderer ? . sandbox ;
2022-07-09 15:33:14 +00:00
if ( params . script . endsWith ( ".html" ) ) {
src = params . script ;
2022-10-20 04:47:36 +00:00
if ( ! sandbox ) sandbox = "none" ;
2022-07-09 15:33:14 +00:00
}
2022-10-20 04:47:36 +00:00
if ( sandbox == "none" ) { // passthrough
} else if ( sandbox == "hash" ) { // Generate sandbox based off of body hash
2022-06-15 14:52:10 +00:00
let hash = await bitty . hashString ( params . body ) ;
src = src . replace ( "https://" , "https://script-" + hash + "." ) ;
} else if ( sandbox ) { // Use named sandbox
src = src . replace ( "https://" , "https://" + sandbox + "." ) ;
} else { // Render using data url (storage disabled)
src = "data:text/html," + SCRIPT _LOADER ;
}
2022-12-04 18:03:10 +00:00
console . log ( " Loading script with source:" , src )
2022-06-15 14:52:10 +00:00
iframe . src = src ;
}
2018-07-08 15:17:48 +00:00
}
2022-05-17 15:38:05 +00:00
2022-06-15 14:52:10 +00:00
function writeDocContent ( doc , content ) {
2022-12-04 18:03:10 +00:00
return doc . documentElement . innerHTML = content ;
doc . open ( ) ;
doc . write ( content ) ;
doc . close ( ) ;
2022-06-15 14:52:10 +00:00
}
2022-05-17 15:38:05 +00:00
2022-06-28 15:43:25 +00:00
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 ) ;
}
2022-12-04 18:03:10 +00:00
async function recordToHistory ( durl ) {
2022-06-28 15:43:25 +00:00
let type = durl . mediatype ;
2022-12-04 18:03:10 +00:00
let hash = await bitty . hashString ( durl . href ) ;
2022-06-28 15:43:25 +00:00
let metadata = bitty . pathToMetadata ( location . pathname ) ;
2022-12-04 18:03:10 +00:00
if ( ! metadata . title && ! metadata . title . length ) {
if ( ! durl . rawData ) durl = await durl . decompress ( ) ;
let dom = await durl . parseDom ( ) ;
2022-06-28 15:43:25 +00:00
2022-06-30 14:25:05 +00:00
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 ( ) ;
2022-06-29 15:34:17 +00:00
}
2022-06-28 15:43:25 +00:00
2022-07-02 21:28:23 +00:00
console . debug ( "Extracting metadata from content" , metadata ) ;
2022-06-28 15:43:25 +00:00
}
2022-05-17 15:38:05 +00:00
if ( navigator . storage && navigator . storage . persist )
navigator . storage . persist ( ) . then ( granted => {
if ( granted )
2022-06-29 15:34:17 +00:00
console . debug ( "Storage will not be cleared except by explicit user action" ) ;
2022-05-17 15:38:05 +00:00
else
2022-06-29 15:34:17 +00:00
console . debug ( "Storage may be cleared by the UA under storage pressure." ) ;
2022-05-17 15:38:05 +00:00
} ) ;
2022-06-28 15:43:25 +00:00
let openRequest = indexedDB . open ( "history" , 3 ) ;
2022-05-17 15:38:05 +00:00
openRequest . onupgradeneeded = function ( event ) {
2022-06-28 15:43:25 +00:00
console . log ( "Upgrading Database" , event )
2022-05-17 15:38:05 +00:00
const db = event . target . result ;
const transaction = event . target . transaction ;
let objectStore ;
2022-06-28 15:43:25 +00:00
if ( ! db . objectStoreNames . contains ( 'urls' ) ) {
objectStore = db . createObjectStore ( 'urls' , { keyPath : 'id' } ) ;
2022-05-17 15:38:05 +00:00
} else {
2022-06-28 15:43:25 +00:00
objectStore = transaction . objectStore ( 'urls' ) ;
2022-05-17 15:38:05 +00:00
}
objectStore . createIndex ( "created" , "created" ) ;
objectStore . createIndex ( "type" , "type" ) ;
2022-06-28 15:43:25 +00:00
objectStore . createIndex ( "terms" , "terms" , { multiEntry : true } ) ;
2022-05-17 15:38:05 +00:00
} ;
openRequest . onerror = function ( ) {
console . error ( "Error" , openRequest . error ) ;
} ;
openRequest . onsuccess = ( ) => {
let db = openRequest . result ;
2022-06-28 15:43:25 +00:00
let transaction = db . transaction ( "urls" , "readwrite" ) ; // (1)
2022-05-17 15:38:05 +00:00
2022-06-28 15:43:25 +00:00
let history = transaction . objectStore ( "urls" ) ; // (2)
2022-05-17 15:38:05 +00:00
let hashCode = s => s . split ( '' ) . reduce ( ( a , b ) => { a = ( ( a << 5 ) - a ) + b . charCodeAt ( 0 ) ; return a & a } , 0 )
2022-06-28 15:43:25 +00:00
let terms = extractTerms ( metadata . title , metadata . description ) ;
2022-05-17 15:38:05 +00:00
let entry = {
2022-06-28 15:43:25 +00:00
id : hash ,
2022-05-17 15:38:05 +00:00
url : location . href ,
2022-06-28 15:43:25 +00:00
title : metadata . title || '' ,
text : metadata . description ? . substring ( 0 , 256 ) ,
type : type ,
terms : terms ,
2022-05-17 15:38:05 +00:00
created : new Date ( )
} ;
2022-07-02 21:28:23 +00:00
console . log ( "🕙 Adding history" , { entry } )
2022-06-28 15:43:25 +00:00
let request = history . put ( entry ) ; // (3)
2022-05-17 15:38:05 +00:00
request . onsuccess = function ( ) { // (4)
2022-07-02 21:28:23 +00:00
console . debug ( "entry added to the history" , request . result ) ;
2022-05-17 15:38:05 +00:00
} ;
request . onerror = function ( ) {
console . log ( "Error" , request . error ) ;
} ;
// continue working with database using db object
} ;
}