[FramesBrowser] add multiple windows

This commit is contained in:
octospacc 2023-09-23 00:46:50 +02:00
parent 3deeb7a122
commit 4d740b1627

View File

@ -6,8 +6,11 @@
<title>Frames Browser (WIP)</title> <title>Frames Browser (WIP)</title>
<style> <style>
:root { :root {
--BtnHeight: 2em; --BaseMargin: 8px;
--BtnActionHeight: 3em; --BtnHeight: calc(1rem + var(--BaseMargin));
--BtnActionHeight: calc(2rem + var(--BaseMargin));
--ColorBg: #f0f0f0;
--ColorFg: #0f0f0f;
} }
* { * {
box-sizing: border-box; box-sizing: border-box;
@ -27,22 +30,45 @@
height: calc(100vh - var(--BtnActionHeight)); height: calc(100vh - var(--BtnActionHeight));
position: relative; position: relative;
} }
#BoxControls {
overflow: auto;
}
#BoxControls table, #BoxControls table td, #BoxControls table td > * { #BoxControls table, #BoxControls table td, #BoxControls table td > * {
height: var(--BtnActionHeight); height: var(--BtnActionHeight);
min-width: var(--BtnActionHeight); min-width: var(--BtnActionHeight);
padding-top: 0;
padding-bottom: 0;
border-spacing: 0; border-spacing: 0;
} }
.BoxPopup { .BoxPopup {
position: absolute;
top: 0;
left: 0; left: 0;
right: 0; right: 0;
} }
.BoxPopup.Container {
position: absolute;
top: 10vh;
z-index: 1;
max-height: 80vh;
overflow: auto;
text-align: center;
}
.BoxPopup.Content {
position: relative;
margin-left: auto;
margin-right: auto;
width: fit-content;
box-shadow: gray 4px 4px 4px 0px;
color: var(--ColorFg);
background-color: var(--ColorBg);
}
.BtnAction {
height: var(--BtnActionHeight);
}
</style> </style>
<script> <script>
var FrameZoomLevels = [50, 200]; var FrameZoomLevels = [50, 200];
var AppInfoString = ` var AppInfoString = `
Frames Browser v2023-09-21.3 (WIP). Frames Browser v2023-09-22 (WIP).
`.trim(); `.trim();
</script> </script>
</head> </head>
@ -54,42 +80,102 @@ Frames Browser v2023-09-21.3 (WIP).
<input type="file" hidden="hidden" style="display: none;" onchange="LoadFile(this.files[0])"/> <input type="file" hidden="hidden" style="display: none;" onchange="LoadFile(this.files[0])"/>
</td> </td>
<td><button onclick="ZoomFrame()">🔍️ Zoom</button></td> <td><button onclick="ZoomFrame()">🔍️ Zoom</button></td>
<!--<td><button onclick="ListFrames()">🪟 Frames</button></td>--> <td><button onclick="ListFrames()">🪟 Frames</button></td>
<td style="width: 100%;"><input type="text" style="width: 100%;"/></td> <td style="width: 100%;"><input type="text" style="min-width: 100%;" hint="🔗️ Enter URI..."/></td>
<td><button onclick="LoadFrame()">↩️ Load</button></td> <td><button onclick="LoadFrame()">↩️ Load</button></td>
<td><button onclick="ExciseFrame()">↗️ Excise</button></td> <td><button onclick="ExciseFrame()">↗️ Excise</button></td>
<tr></table></div> <tr></table></div>
<noscript><p class="NoScript">
This is an actual app, not a badly-made website.
<br>
It needs JavaScript to work, so you need to enable it.
<br>
The code is fully open, and you can review it with "View Page Source".
</p></noscript>
<div id="BoxHandy"></div>
<div><iframe></iframe></div> <div><iframe></iframe></div>
<script> <script>
var CurrentFrames = [];
var FrameIndexes = [-1];
var FrameZoomIndex = -1; var FrameZoomIndex = -1;
//function $rule(prop){ function $new(tag, props){
// return getComputedStyle(document.body).getPropertyValue(prop); var el = document.createElement(tag);
//}; if (props) {
Object.keys(props).forEach(function(key){
function $new(tag){ el[key] = props[key];
return document.createElement(tag); });
};
return el;
}; };
function ShowAppInfo(){ function ShowAppInfo(){
alert(AppInfoString); alert(AppInfoString);
}; };
function ShowFrame(index){
ListFramesClose();
FrameIndexes = [index];
SaveCurrentFrames();
document.querySelector('iframe').hidden = false;
document.querySelector('iframe').style.display = '';
document.querySelector('input[type="text"]').value = CurrentFrames[index];
document.querySelector('input[type="text"]').disabled = false;
document.querySelector('iframe').src = CurrentFrames[index];
};
function ShowRootFrame(){
ListFramesClose();
FrameIndexes = [-1];
SaveCurrentFrames();
document.querySelector('iframe').hidden = true;
document.querySelector('iframe').style.display = 'none';
document.querySelector('input[type="text"]').disabled = true;
document.querySelector('input[type="text"]').value = '';
document.querySelector('iframe').src = '';
};
function SaveUrl(){ function SaveUrl(){
var url = document.querySelector('input[type="text"]').value; var url = document.querySelector('input[type="text"]').value;
localStorage.setItem('FramesBrowser.url', url); localStorage.setItem('FramesBrowser.url', url);
CurrentFrames[FrameIndexes[0]] = url;
SaveCurrentFrames();
return url; return url;
} };
function AddFrame(){
CurrentFrames = CurrentFrames.concat(['']);
ListFrames(); //ListFrames();
ShowFrame(CurrentFrames.length - 1);
SaveCurrentFrames();
};
function CloseFrame(index){
CurrentFrames.pop(index);
if (FrameIndexes[0] === index) {
ShowRootFrame();
} else if (FrameIndexes[0] > index) {
FrameIndexes[0] --;
};
ListFrames(); ListFrames();
SaveCurrentFrames();
};
function SaveCurrentFrames(){
localStorage.setItem('FramesBrowser.CurrentFrames', JSON.stringify(CurrentFrames));
localStorage.setItem('FramesBrowser.FrameIndexes', JSON.stringify(FrameIndexes));
};
function LoadFrame(){ function LoadFrame(){
document.querySelector('iframe').src = SaveUrl(); document.querySelector('iframe').src = SaveUrl();
}; };
function ExciseFrame(){ function ExciseFrame(){
var url = SaveUrl(); var uri = SaveUrl();
var extwindow = open(url, '_blank'); if (uri.toLowerCase().startsWith('data:')) {
if (url.toLowerCase().startsWith('data:')) { opendatauri(uri);
extwindow.document.write(`<style>body { margin: 0; } iframe { width: 100vw; height: 100vh; border: none; }</style><iframe src="${url}" frameborder="0"></iframe>`); } else {
open(uri, '_blank');
}; };
}; };
@ -103,7 +189,7 @@ Frames Browser v2023-09-21.3 (WIP).
}; };
function ZoomFrame(){ function ZoomFrame(){
if (FrameZoomIndex == FrameZoomLevels.length - 1) { if (FrameZoomIndex === FrameZoomLevels.length - 1) {
FrameZoomIndex = -1; FrameZoomIndex = -1;
} else { } else {
FrameZoomIndex ++; FrameZoomIndex ++;
@ -114,35 +200,76 @@ Frames Browser v2023-09-21.3 (WIP).
? `right: ${level}vw; bottom: calc(${level}vh - 16px);` ? `right: ${level}vw; bottom: calc(${level}vh - 16px);`
: `left: ${levelopp/2}vw; top: calc(${levelopp/2}vh - 8px);` : `left: ${levelopp/2}vw; top: calc(${levelopp/2}vh - 8px);`
); );
document.querySelector('iframe').style = (FrameZoomIndex == -1 document.querySelector('iframe').style = (FrameZoomIndex === -1
? '' ? ''
: `scale: ${level/100}; width: ${levelopp}vw; height: calc(${levelopp}vh - (var(--BtnActionHeight) * ${levelopp / 100})); ${stylepos}` : `scale: ${level/100}; width: ${levelopp}vw; height: calc(${levelopp}vh - (var(--BtnActionHeight) * ${levelopp / 100})); ${stylepos}`
); );
}; };
function ListFrames(){ function ListFrames(){
var Box = NewBoxPopup(); if (!ListFramesClose()){
var BtnAdd = $new('button'); var Box = NewBoxPopup('BoxFramesList');
BtnAdd.innerHTML = ' Add'; var BtnAdd = $new('button', { className: 'BtnAction', innerHTML: ' Add', onclick: AddFrame });
Box.appendChild(BtnAdd); Box.Content.appendChild(BtnAdd);
var BtnMain = $new('button'); var BoxList = $new('ul');
BtnMain.innerHTML = 'No Frame'; Box.Content.appendChild(BoxList);
Box.appendChild(BtnMain); var LiMain = $new('li');
BoxList.appendChild(LiMain);
var BtnMain = $new('button', { innerHTML: 'Root Window', onclick: ShowRootFrame, disabled: FrameIndexes[0] === -1 });
LiMain.appendChild(BtnMain);
for (var i=0; i<CurrentFrames.length; i++) {
var li = $new('li');
li.ItemIndex = i;
BoxList.appendChild(li);
var open = $new('button', { innerHTML: `&nbsp;${CurrentFrames[i].slice(0, 16)}&nbsp;`, onclick: function(){ShowFrame(this.parentElement.ItemIndex)}, disabled: FrameIndexes[0] === i });
li.append(open);
var close = $new('button', { innerHTML: '✖️', onclick: function(){CloseFrame(this.parentElement.ItemIndex)} });
li.append(close);
};
};
}; };
function NewBoxPopup(){ function ListFramesClose(){
var Box = $new('div'); var exist = document.querySelector('#BoxFramesList');
Box.className = 'BoxPopup'; if (exist) {
var BtnClose = $new('button'); BoxFramesList.remove();
BtnClose.innerHTML = '❌ Close'; };
BtnClose.onclick = function(){ this.parentElement.remove() }; return exist;
Box.appendChild(BtnClose); };
document.body.appendChild(Box);
return Box; function NewBoxPopup(id){
var Container = $new('div', { id: id, className: 'BoxPopup Container' });
var Content = $new('div', { className: 'BoxPopup Content' });
Container.appendChild(Content);
var BtnClose = $new('button', { className: 'BtnAction', innerHTML: '❌ Close', onclick: function(){this.parentElement.parentElement.remove()} });
Content.appendChild(BtnClose);
BoxHandy.appendChild(Container);
return { Container: Container, Content: Content };
};
window.opendatauri = function opendatauri(data){
var head = data.split(',')[0].split('data:')[1];
var [mime, encoding] = head.split(';');
data = data.split(',').slice(1).join(',');
if (encoding.toLowerCase() === 'base64') {
data = atob(data);
};
var bytes = new Array(data.length);
for (var i = 0; i < data.length; i++) {
bytes[i] = data.charCodeAt(i);
};
window.open(URL.createObjectURL(
new Blob([new Uint8Array(bytes)], { type: `${mime};${encoding ? encoding : 'utf8'}` })
), '_blank');
}; };
onload = function(){ onload = function(){
Array.from(document.querySelectorAll('noscript, .NoScript')).forEach(function(el){ el.remove() });
CurrentFrames = (JSON.parse(localStorage.getItem('FramesBrowser.CurrentFrames')) || []);
FrameIndexes = (JSON.parse(localStorage.getItem('FramesBrowser.FrameIndexes')) || [-1]);
document.querySelector('input[type="text"]').value = localStorage.getItem('FramesBrowser.url'); document.querySelector('input[type="text"]').value = localStorage.getItem('FramesBrowser.url');
var frame0 = FrameIndexes[0];
frame0 === -1 ? ShowRootFrame() : ShowFrame(frame0);
}; };
</script> </script>
</body> </body>