Last active
January 14, 2022 04:12
-
-
Save Utopiah/60d55c12138dcadf2f42f33419160656 to your computer and use it in GitHub Desktop.
code for Whiteboard
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"><!-- as PmWiki tmpl file --> | |
<head> | |
<meta charset="utf-8"> | |
<title>$WikiTitle | {$Group} / {$Title} $ActionTitle</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta name="description" content=""> | |
<meta name="author" content=""> | |
<meta name="monetization" content="$ilp.gatehub.net/360717042"> | |
<!-- Le styles --> | |
<!--HTMLHeader--> | |
<!-- HTML5 shim, for IE6-8 support of HTML5 elements --> | |
<!--[if lt IE 9]> | |
<script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script> | |
<![endif]--> | |
<!-- Fav and touch icons --> | |
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="$SkinDirUrl/images/ico/apple-touch-icon-144-precomposed.png"> | |
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="$SkinDirUrl/images/ico/apple-touch-icon-114-precomposed.png"> | |
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="$SkinDirUrl/images/ico/apple-touch-icon-72-precomposed.png"> | |
<link rel="apple-touch-icon-precomposed" href="$SkinDirUrl/images/ico/apple-touch-icon-57-precomposed.png"> | |
<link rel="shortcut icon" href="//fabien.benetou.fr/favicon.ico" type="image/x-icon" /> | |
<link rel="stylesheet" href="//fabien.benetou.fr/pub/reveal.js-master/css/reveal.css" type="text/css"> | |
<script src="https://unpkg.com/[email protected]/dist/peerjs.min.js"></script> | |
<script src='https://meet.benetou.fr/external_api.js'></script> | |
</head> | |
<body> | |
<style> | |
.span4 { margin:0; } | |
.grid { height: 100%; width: 100%; margin: 0; } | |
.grid { | |
background-image: | |
repeating-linear-gradient(#ccc 0 1px, transparent 1px 100%), | |
repeating-linear-gradient(90deg, #ccc 0 1px, transparent 1px 100%); | |
background-size: 100px 100px; | |
display:none; | |
} | |
</style> | |
<div class="grid"></div> | |
<span id="remotepointer" style="z-index:999; display:none; position:absolute; top:0px; left:0px;">▲</span> | |
<div onclick="connect()" id="connect" style="display:none; opacity:0.3; position: absolute; top:0px; height: 100px; left:100px">Getting peer ID</div> | |
<div onclick="joinVideoCall(this)" id="videocall" style="position: absolute; top:0px; height: 100px; left:200px">Join video call</div> | |
<div onclick="toggleGridAndSnap(this)" id="snap" style="position: absolute; top:0px; height: 100px; left:400px">Disable snapping</div> | |
<div onclick="generatePresentation()" id="generate" style="position: absolute; top:0px; height: 100px;">Present</div> | |
<div onclick="whiteboard()" id="whiteboard" style="z-index:100; position: Absolute; bottom:0px; ;height: 20px;">whiteboard</div> | |
<div id="strip" style="position: absolute; top:100px; width: 100%; opacity: 0.7; background-color: #ccc;height: 600px;"></div> | |
<div id="listslides" style="position: absolute; top:200px; width: 10%; opacity: 0.7; background-color: #ccc;height: 400px;"></div> | |
<div class="reveal" style="display:none"><div class="slides"></div></div> | |
<!--PageText--> | |
<script src="whiteboard.js"></script> | |
<script src="//fabien.benetou.fr/pub/reveal.js-master/js/reveal.js"></script> | |
<!-- Le javascript | |
================================================== --> | |
<!-- Placed at the end of the document so the pages load faster --> | |
<script src="$SkinDirUrl/javascripts/jquery-1.8.3.min.js"></script> | |
<script src="$SkinDirUrl/javascripts/bootstrap.min.js"></script> | |
<!--HTMLFooter--> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// see also ~/Prototypes/pim-add-url-webextension for on the fly presentation preparation | |
// and more permanent online saving | |
// see https://fabien.benetou.fr/Tools/Ffmpeg?action=serverrender for per page image rendering to avoid iframes | |
var selectedElement = null; | |
var presentation = [] | |
var peerId = null | |
var conn | |
var peer = new Peer() // somehow worked at the beginning of the week... but not anymore?! | |
var jitsiAPI | |
var snap = false | |
//getLinksFromBucket() | |
// tricky with CSP/CORS/etc so might have to solely rely on server side generated preview | |
const urlParams = new URLSearchParams(window.location.search); | |
const peerTargetId = urlParams.get('peertargetid') | |
function getLinksFromBucket(){ | |
fetch('https://fabien.benetou.fr/PIMVRdata/URLBucketTest?action=source').then( | |
response => { return response.text() } ).then( | |
data => { addCards(data.split("\n")) }) | |
} | |
function addCards(cards){ | |
for (var url of cards){ | |
var el = document.createElement("div") | |
el.className = "span4" | |
var h2 = document.createElement("h2") | |
h2.innerText = url | |
el.appendChild(h2) | |
var iframe = document.createElement("iframe") | |
iframe.src = url | |
el.appendChild(iframe) | |
// could add a iframe vignettes as span4 | |
el.style = `border: dotted; position: absolute; top: ${Math.random()*1000}px; left: ${Math.random()*4000}px;` | |
document.querySelector("#wikitext").appendChild( el ) | |
} | |
} | |
function toggleGridAndSnap(el){ | |
snap = !snap | |
if (snap) { | |
el.innerText = "Disable snapping" | |
document.querySelector(".grid").style.display = "block" | |
} else { | |
el.innerText = "Enable snapping" | |
document.querySelector(".grid").style.display = "none" | |
} | |
} | |
function joinVideoCall(el){ | |
el.style.opacity = 0.3 | |
el.innerText = "Joining call" | |
el.innerText += " (click to close)" | |
jitsiAPI = new JitsiMeetExternalAPI('meet.benetou.fr', { | |
roomName:'whiteboard'+window.location.pathname.replaceAll("/","_"), | |
width: '600px', | |
height: '400px', | |
}) | |
jitsiAPI.getIFrame().style.position = "absolute" | |
jitsiAPI.getIFrame().style.right = "0px" | |
jitsiAPI.addListener("participantJoined", e => { | |
el.innerText = jitsiAPI.getNumberOfParticipants() + " participants in call" | |
el.innerText += " (click to close)" | |
}) | |
jitsiAPI.addListener("participantLeft", e => { | |
el.innerText = jitsiAPI.getNumberOfParticipants() + " participants in call" | |
el.innerText += " (click to close)" | |
}) | |
el.onclick = e => { jitsiAPI.dispose(); el.innerText = "Closed call" } | |
} | |
peer.on('connection', function(conn) { | |
var p = document.querySelector("#remotepointer") | |
p.style.display = "block" | |
conn.on('data', function(data){ | |
console.log('peerjs', data) | |
if (data.x){ | |
p.style.top = data.y + 'px' | |
p.style.left = data.x + 'px' | |
// could update card if moving | |
} | |
}) | |
document.querySelector("#connect").style.opacity = 0.3 | |
document.querySelector("#connect").innerText = "Connected" | |
document.querySelector("#connect").onclick = {} | |
}) | |
peer.on('open', function(id) { | |
peerId = id | |
document.querySelector("#connect").style.opacity = 1 | |
if (peerTargetId) conn = peer.connect(peerTargetId) | |
if (conn) { | |
document.querySelector("#connect").style.opacity = 0.3 | |
document.querySelector("#connect").innerText = "Connected" | |
document.querySelector("#connect").onclick = {} | |
} | |
}) | |
function connect(){ | |
if (peerId) window.open(window.location.href+'&peertargetid='+peerId) | |
} | |
function updatePresentation(){ | |
presentation = [] | |
document.querySelector("#listslides").innerText = "" | |
for (var el of document.querySelectorAll(".span4")){ | |
var h2 = el.querySelector("h2") | |
if (h2) { | |
var title = h2.innerText | |
var top = Number(el.style.top.replace("px","")) | |
var left = Number(el.style.left.replace("px","")) | |
if (top && top >= 100 && top < 100+600) presentation.push({title:title, top:top, left:left, el:el}) | |
} | |
} | |
presentation = presentation.sort( (a,b) => (a.left>b.left)) | |
var list = document.createElement("ol") | |
for (var slide of presentation) { | |
var item = document.createElement("li") | |
item.innerText = slide.title | |
list.appendChild(item) | |
} | |
document.querySelector("#listslides").appendChild(list) | |
} | |
function generatePresentation(){ | |
var slides = document.querySelector(".slides") | |
slides.innerHTML = "" | |
for (var slide of presentation){ | |
var section = document.createElement("section") | |
//section.innerHTML = slide.title | |
slide.el.className = "" | |
slide.el.style.formerTop = slide.el.style.top | |
slide.el.style.formerLeft = slide.el.style.left | |
slide.el.style = "" | |
section.appendChild( slide.el ) | |
// cloning doesnt work with an iframe and importing doesn't work due to CSP | |
//section.appendChild( slide.el.cloneNode(true) ) | |
//section.appendChild( document.importNode(slide.el.querySelector('iframe').contentWindow.document, true) ) | |
slides.appendChild(section) | |
} | |
document.querySelector(".reveal").style.display = "block" | |
document.querySelector("#strip").style.display = "none" | |
document.querySelector("#wikitext").style.display = "none" | |
for (var el of document.querySelectorAll(".span4")) el.parentNode.style.display = "none" | |
Reveal.initialize() | |
el.innerText = "" | |
document.querySelector(".grid").style.display = "none" | |
} | |
function whiteboard(){ | |
var snapEl = document.querySelector("#snap") | |
if (snap) { | |
snapEl.innerText = "Disable snapping" | |
document.querySelector(".grid").style.display = "block" | |
} else { | |
snapEl.innerText = "Enable snapping" | |
document.querySelector(".grid").style.display = "none" | |
} | |
document.querySelector(".reveal").style.display = "none" | |
document.querySelector("#strip").style.display = "block" | |
document.querySelector("#wikitext").style.display = "block" | |
for (var el of document.querySelectorAll(".span4")) el.parentNode.style.display = "block" | |
for (var slide of presentation){ | |
slide.el.className = "span4" | |
slide.el.style.top = slide.el.style.formerTop | |
slide.el.style.left = slide.el.style.formerLeft | |
slide.el.style.border = 'dotted' | |
slide.el.style.position = 'absolute' | |
document.querySelector("#wikitext").appendChild( slide.el ) | |
} | |
var slides = document.querySelector(".slides") | |
slides.innerHTML = "" | |
} | |
// could adapt to a function, would have to see if it can be done again for new embed live | |
// otherwise wrapper | |
for (var el of document.querySelector("#wikitext").children) | |
el.style.display = "none" | |
for (var el of document.querySelectorAll(".span8")) | |
el.style.display = "none" | |
for (var el of document.querySelectorAll(".row-fluid")) | |
el.className = "" | |
for (var el of document.querySelectorAll(".span4")){ | |
el.parentNode.style.display = "block" // enough for twitter Cards | |
el.parentNode.parentNode.style.display = "block" // used for PoCs e.g. Portfolio page | |
// could traverse safely instead... | |
var h2 = el.querySelector("h2") | |
if (!h2) { | |
el.style.display = "none" | |
} else { | |
var title = h2.innerText | |
var coords = JSON.parse(localStorage.getItem('wb' + title)) | |
el.style = `border: dotted; position: absolute; top: ${Math.random()*1000}px; left: ${Math.random()*4000}px;` | |
if (coords) { | |
el.style.top = coords.top | |
el.style.left = coords.left | |
var ttop = Number(coords.top.replace("px","")) | |
if (ttop > 100 && ttop < 100+600) { el.style.border = "solid"; updatePresentation(); } | |
} | |
} | |
} | |
window.onmousemove = e => { | |
var title | |
if (selectedElement) { | |
title = selectedElement.querySelector("h2").innerText | |
selectedElement.style.margin = "1px"; | |
selectedElement.style.top = e.clientY+'px'; | |
selectedElement.style.left = e.clientX+'px'; } | |
if (conn) { | |
conn.send({x:e.clientX, y:e.clientY }) | |
//conn.send({x:e.clientX, y:e.clientY, movingElTitle: title}) | |
} | |
/* | |
if (document.body.style.transform.indexOf("scale(1)")>-1) | |
document.body.style.transform += "translate(" + e.movementX + "px, " + e.movementY + "px)" | |
*/ | |
} | |
ontouchstart = e => { | |
onclick(e) | |
} | |
ontouchend = e => { | |
if (selectedElement) { | |
// releasing currently moving entity | |
var title = selectedElement.querySelector("h2").innerText | |
localStorage.setItem('wb' + title, JSON.stringify({top: selectedElement.style.top, left:selectedElement.style.left })); | |
// could be saved back on the wiki instead for a shared/public mode | |
selectedElement.style.border = "dotted" | |
var top = Number(selectedElement.style.top.replace("px","")) | |
var left = Number(selectedElement.style.left.replace("px","")) | |
if (top && top > 100 && top < 100+600) { | |
selectedElement.style.border = "solid" | |
} | |
updatePresentation() | |
} | |
} | |
ontouchmove = e => { | |
if (selectedElement) { selectedElement.style.top = e.touches[0].clientY+'px'; selectedElement.style.left = e.touches[0].clientX+'px'; } | |
} | |
onwheel = e => { | |
e.preventDefault() | |
var scale = Number(document.body.style.transform.replace("scale(",'').replace(")",'')) | |
document.body.style.transform = "scale(" + (scale + e.deltaY/30) + ")" | |
// somwhow getting 3 or -3, might be system specific due to margins... | |
} | |
onclick = e => { | |
if (selectedElement) { | |
// releasing currently moving entity | |
var title = selectedElement.querySelector("h2").innerText | |
localStorage.setItem('wb' + title, JSON.stringify({top: selectedElement.style.top, left:selectedElement.style.left })); | |
// could be saved back on the wiki instead for a shared/public mode | |
selectedElement.style.border = "dotted" | |
var top = Number(selectedElement.style.top.replace("px","")) | |
var left = Number(selectedElement.style.left.replace("px","")) | |
if (snap) { | |
selectedElement.style.top = Math.round(top / 100) * 100 + "px" | |
selectedElement.style.left = Math.round(left / 100) * 100 + "px" | |
} | |
if (top && top > 100 && top < 100+600) { | |
selectedElement.style.border = "solid" | |
} | |
updatePresentation() | |
} | |
if (e.target.className == "span4") | |
selectedElement = e.target; | |
else { | |
selectedElement = null; | |
if (e.target.parentNode.className && e.target.parentNode.className == "span4") | |
selectedElement = e.target.parentNode | |
/* could keep on checking with older parents */ | |
} | |
if (selectedElement) selectedElement.style.border = "dashed" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Could be generalized to be used on any page (not just as a PmWiki skin) by :
#span4
toli
)Motivation : transform https://fabien.benetou.fr/innovativ.it/www/HistoricalArchives/Seedea/Content/Newconcepts to memorable flashcards.