bbpro
Version:
BrowserBox - remote browser isolation tool
355 lines (310 loc) • 8 kB
HTML
<title>View Document</title>
<meta charset=utf-8>
<meta name=viewport content=width=device-width,initial-scale=1>
<style>
:root {
background: whitesmoke;
font-family: system-ui, Arial, Times;
}
body {
margin: 4.5rem 0;
}
img {
display: block;
box-shadow: 0 1px 2px silver;
margin: 3em auto;
width: 61.8%;
}
header {
position: fixed;
width: 100%;
top: 0;
left: 0;
display: flex;
flex-direction: row;
align-items: stretch;
justify-content: space-between;
zoom: reset;
background: white;
padding: 0.25em;
box-shadow: 0 1px 1px silver;
}
header nav {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: space-between;
}
header div {
text-align: right;
}
header div a {
font-size: smaller;
}
header, .controls {
font-size: 16pt;
}
section.document * {
font-size: 14pt;
}
header button {
}
header button strong {
display: block;
}
header button strong.pop {
}
nav .zoomer {
cursor: zoom-in ;
}
strong.flip {
}
#loading {
margin-top: 1.5rem;
cursor: wait ;
text-align: center;
}
nav section {
display: flex;
align-items: center;
}
nav section > * {
margin: 0 0.15rem;
}
.download {
cursor: pointer ;
}
.download a {
text-decoration: none;
color: dodgerblue;
}
* a {
text-decoration: none;
}
a .link-text {
text-decoration: underline;
display: inline-block;
}
a strong {
display: inline-block;
height: 1.5em;
}
.download strong {
transform: translate(0,9%);
}
.hex-view strong {
transform: translate(0,-11%) scale(1.168);
margin-left: 1.5px;
}
section.controls * {
font-size: 16pt;
}
button {
text-align: center;
color: dodgerblue;
font-weight: bold;
}
.controls span.rot {
transform: rotate(80deg) translate(0, -2px);
display: block;
}
nav {
padding: 0.5rem 0.5rem 0.5rem 0.25rem;
}
input[type="range"] {
margin-left: 0.45rem;
accent-color: dodgerblue;
max-width: 30%;
}
::-webkit-slider-runnable-track {
background: whitesmoke;
border: 1px solid gray;
height: 0.5rem;
border-radius: 0.5rem;
}
::-webkit-slider-thumb {
transform: translate(0,-30%);
accent-color: dodgerblue;
}
::-moz-range-track {
background: whitesmoke;
border: 1px solid gray;
height: 0.5rem;
border-radius: 0.5rem;
}
::-moz-range-thumb {
background: dodgerblue;
border-radius: 1rem;
border-color: dodgerblue;
height: 1rem;
width: 1rem;
}
@media screen and (max-width: 375px) {
nav .link-text {
display: none;
}
}
:is(button, input, a):focus {
outline-color: dodgerblue;
}
</style>
<header>
<nav>
<section class=controls>
<button id=prev title="Previous page">
<
</button>
<button id=next title="Next page">
>
</button>
<button id=rotate title="Rotate page">
<span class=rot>
↻
</span>
</button>
<span id=pagenumber></span>
<input type="range" id="resizeSlider" min="15" max="200" value="61.8" style="max-width: 30vw;" title="Zoom" class=zoomer>
</section>
<section class=document>
<div class=hex-view>
<a id=hex-view-link title="View hex of original" href="/hex/command" target=_blank>
<span class=link-text>HexView</span>
<strong>⬢</strong>
</a>
</div>
</section>
<section class=document>
<div class=download>
<a id=download-link title="Download original" rel=canonical download href=#download>
<span class=link-text>Download</span>
<strong>︾</strong>
</a>
</div>
</section>
</nav>
</header>
<p id=loading>
Converting…
</p>
<img id=page>
<script>
const FORMAT = `$$FORMAT$$`;
const path = location.pathname;
const imgUrl = i => path.replace(/\.html$/,`-${i.toString().padStart(4,'0')}.${FORMAT}`);
const documentFileName = path.replace(/\.html$/, '');
const noConvertUrl = documentFileName + '.noconvert';
console.log({documentFileName});
const hexView = document.querySelector('#hex-view-link');
const anchor = document.querySelector('#download-link');
anchor.setAttribute('href', documentFileName);
const CRAM_WAIT = 349;
const MAX_TIME_TO_WAIT_FOR_CONVERSION = 10*60*1000; // ten minutes
let noCram = false;
let succeeded = false;
let failed = false;
let pageNumber = 0;
let ang = 0;
let stopCheck = false;
let hexLink = new URL(hexView.href);
hexLink.searchParams.set('filePath', documentFileName);
hexLink.searchParams.set('command', 'next');
hexView.href = hexLink;
hexView.target = btoa(documentFileName);
page.onerror = () => {
if ( stopCheck ) return;
setTimeout(checkFirstPage, 1001);
}
page.onload = () => {
succeeded = true;
loading.innerText = '';
pagenumber.innerText = `page ${(pageNumber + 1)}`;
page.onerror = checkFirstPage;
}
checkFirstPage();
prev.onclick = () => {
const nextUrl = imgUrl(--pageNumber);
if ( noCram ) {
clearTimeout(noCram);
noCram = setTimeout(() => {
noCram = false;
page.src = nextUrl;
}, CRAM_WAIT);
} else {
page.src = nextUrl;
}
if ( pageNumber >= 0 ) {
pagenumber.innerText = `page ${(pageNumber + 1)}`;
}
};
next.onclick = () => {
const nextUrl = imgUrl(++pageNumber);
if ( noCram ) {
clearTimeout(noCram);
noCram = setTimeout(() => {
noCram = false;
page.src = nextUrl;
}, CRAM_WAIT);
} else {
page.src = nextUrl;
}
pagenumber.innerText = `page ${(pageNumber + 1)}`;
}
rotate.onclick = () => {
ang = (ang + 90) % 360;
page.style.transform = `rotate(${ang}deg)`;
}
function checkFirstPage() {
if ( failed ) {
loading.innerText = 'No such file, or conversion failed.';
return;
} else if ( stopCheck ) {
return;
}
checkNoConvert();
pageNumber = 0;
page.src = imgUrl(pageNumber);
loading.innerHTML = 'Converting…';
}
setTimeout(() => {
if ( ! succeeded ) {
failed = true;
}
}, MAX_TIME_TO_WAIT_FOR_CONVERSION);
// Function to resize image based on slider value
function resizeImage() {
const slider = document.getElementById("resizeSlider");
const image = document.getElementById("page");
const zoomLevel = slider.value;
image.style.width = zoomLevel + "%";
}
// Add event listener to the slider
document.addEventListener("DOMContentLoaded", function() {
const slider = document.getElementById("resizeSlider");
slider.addEventListener("input", resizeImage);
});
document.addEventListener("DOMContentLoaded", function() {
const downloadLink = document.getElementById("download-link"); // Replace with the actual ID of your Download anchor link
downloadLink.addEventListener("click", function(event) {
const userConfirmed = confirm("This file could harm your computer. Are you sure you want to download?");
if (!userConfirmed) {
event.preventDefault();
}
});
});
async function checkNoConvert() {
console.log(noConvertUrl);
const resp = await fetch(noConvertUrl);
if ( resp.ok ) {
const reason = await resp.text() || 'reasons unkown';
console.warn(`File did not convert. Reason: ${reason}`);
console.log(`Stopping checking for the first page...`);
stopCheck = true;
clearTimeout(noCram);
console.log(`Stopped.`);
loading.innerHTML = `Document did not convert. Please see the hex viewer if you want to review its contents.`;
// remove the image element used to display the current page
globalThis?.page?.remove?.();
}
}
</script>