Compare commits

..

No commits in common. "master" and "add-lib" have entirely different histories.

7 changed files with 5 additions and 468 deletions

View File

@ -1,61 +0,0 @@
body {
background-color: black;
color: white;
font-family: sans-serif;
font-size: 18px;
height: 100%;
margin: 0;
overflow: hidden;
width: 100%;
}
.base {
z-index: 1;
background: black;
position: absolute;
width: 100%;
height: 100%;
}
.slide {
z-index: 0;
position: absolute;
width: 100%;
height: 100%;
text-shadow:
-2px -2px 0 #000,
2px -2px 0 #000,
-2px 2px 0 #000,
2px 2px 0 #000;
}
.title {
font-size: 48px;
margin-left: 16px;
margin-right: 16px;
margin-top: 30%;
text-align: center;
position: fixed;
z-index: 10;
height: 56px;
width: 100%;
}
.video {
position: fixed;
width: 100%;
height: 100%;
}
.video iframe {
width: 100%;
height: 100%;
border: 0;
margin: 0;
padding: 0;
}
.audio iframe {
height: 0;
border: 0;
}

View File

@ -1,302 +0,0 @@
class Slide {
constructor(slide, idx) {
this.isAudioLoaded = this.isVideoLoaded = false
this.el = slide
this.idx = idx
this.duration = slide.dataset.duration
const video = slide.querySelector('.video')
if (video) {
this.video = load_urls(video.dataset)
if (this.video.length > 1 || this.video[0].includes('document')) {
this.isDocument = true
}
this.videoVolume = video.dataset.volume ? parseFloat(video.dataset.volume) : 1
this.videoContainer = video
if (this.video.length > 1) {
this.zooms = this.video.map(url => url.split('/').pop().split('#')[0].split(',').map(a => Math.round(a)))
}
}
const audio = slide.querySelector('.audio')
if (audio) {
this.audio = audio.dataset.url // audio does not need to be an array
this.audioVolume = audio.dataset.volume ? parseFloat(audio.dataset.volume) : 1
this.audioContainer = audio
this.audioContinue = !!audio.dataset.continue
}
this.initEmbeds()
return this
}
initEmbeds() {
if (this.video) {
const videoEmbed = this.videoEmbed = new PandoraEmbed({
id: 'slide-' + this.idx,
url: this.video[0],
container: this.videoContainer
})
videoEmbed.on('init', () => {
if (this.isDocument) {
this.isVideoLoaded = true
}
})
videoEmbed.on('loaded', () => {
console.log('loaded called on embed')
this.isVideoLoaded = true
})
videoEmbed.on('playing', (positionData) => {
if (!this.videoStart) {
this.videoStart = positionData.position
}
})
}
if (this.audio) {
const audioEmbed = this.audioEmbed = new PandoraEmbed({
id: 'audio-' + this.idx,
url: this.audio,
container: this.audioContainer
})
audioEmbed.on('loaded', () => {
console.log('loaded called on audio embed')
this.isAudioLoaded = true
})
audioEmbed.on('playing', (positionData) => {
if (!this.audioStart) {
this.audioStart = positionData.position
}
})
}
return this;
}
isReady() {
console.log('isReady called');
if (this.video && this.audio) {
return this.isVideoLoaded && this.isAudioLoaded
} else if (this.video) {
return this.isVideoLoaded
} else if (this.audio) {
return this.isAudioLoaded
} else {
return true
}
}
sendToBack() {
this.el.style.zIndex = 0
return this
}
bringToFront() {
this.el.style.zIndex = 10
return this
}
start() {
console.log('called start', this.isReady())
if (this.zooms) {
this.startZoom()
} else if (this.video && this.video.length) {
this.startVideo()
}
if (this.audioContainer) { // if there is an audio container, we always stop current audio
reset_active_audio()
}
if (this.audio) {
this.startAudio()
}
return this
}
stop() {
if (this.zooms) {
this.resetZoom()
} else if (this.video && this.video.length) {
this.resetVideo()
}
if (this.audio && !this.audioContinue) {
this.resetAudio()
}
return this
}
startZoom() {
for (var i=1; i<this.zooms.length; i++) {
this.zoomTimeouts = [];
((j) => {
this.zoomTimeouts.push(setTimeout(() => {
this.videoEmbed.postMessage('options', {
'area': this.zooms[j]
})
}, Math.round(1000 * (this.duration / this.zooms.length) * j)))
})(i);
}
return this
}
startVideo() {
this.videoEmbed.postMessage('options', {
'paused': false,
'volume': this.videoVolume
})
return this
}
startAudio() {
this.audioEmbed.postMessage('options', {
'paused': false,
'volume': this.audioVolume
})
activeAudio = this
return this
}
resetZoom() {
this.zoomTimeouts.forEach(timeout => clearTimeout(timeout))
this.videoEmbed.postMessage('options', {
'area': this.zooms[0]
})
return this
}
resetVideo() {
this.videoEmbed.postMessage('options', {
'paused': true,
'position': this.start || 0
})
return this
}
resetAudio() {
this.audioEmbed.postMessage('options', {
'paused': true,
'position': 0 //FIXME: figure correct audio reset
})
activeAudio = null;
return this
}
}
var slides = [],
current = 0,
activeAudio,
timeout;
let textbUrl = new URLSearchParams(window.location.search).get('textb') || 'https://textb.org/r/housingplaylist2/'
// use raw version of page
textbUrl = textbUrl.replace('/t/', '/r/')
if (!textbUrl.endsWith('/')) textbUrl += '/'
fetch(textbUrl)
.then(response => response.text())
.then(loadYaml)
.then(init)
.catch(err => {
console.log('error', err)
alert('error loading YAML')
})
function loadYaml(txt) {
const html = txt.split('\n\n')
.filter(chunk => chunk.trim())
.map(chunk => {
const obj = jsyaml.load(chunk)
return obj
})
.map(jsonToHTML)
.join('')
document.body.innerHTML = `
<div class="base"></div>
${html}
`
return true
}
function init() {
document.querySelectorAll('.slide').forEach(function(slide, idx) {
slides.push(new Slide(slide, idx))
})
go(0)
}
function go(idx) {
if (!slides[idx].isReady()) {
console.log('slide not ready');
return setTimeout(() => {
go(idx)
}, 250)
}
var old = current
slides[current].sendToBack()
slides[idx].bringToFront()
current = idx
if (timeout) {
clearTimeout(timeout)
timeout = null
}
timeout = setTimeout(next, Math.round(slides[current].duration) * 1000)
slides[old].stop()
slides[current].start()
}
function next() {
var idx = (current + 1) % slides.length
console.log(current, idx)
go(idx)
}
function previous() {
var idx = (current - 1) % slides.length
if (idx < 0) {
idx += slides.length
}
go(idx)
}
function load_urls(dataset) {
var urls = [], idx = 0
while (dataset['url_' + idx]) {
urls.push(dataset['url_' + idx])
idx += 1
}
return urls
}
window.addEventListener('blur', function(){
setTimeout(function(){
// using the 'setTimout' to let the event pass the run loop
if (document.activeElement instanceof HTMLIFrameElement) {
window.focus();
}
},0);
}, false);
function reset_active_audio() {
if (activeAudio) {
activeAudio.resetAudio()
}
}
document.addEventListener('keydown', function(event) {
if (event.key == 'ArrowRight') {
next()
event.preventDefault()
} else if (event.key == 'ArrowLeft') {
previous()
event.preventDefault()
}
}, false)

View File

@ -1,9 +0,0 @@
<meta charset="utf-8">
<script src="../lib/PandoraEmbed.js"></script>
<link type="text/css" href="example.css" rel="stylesheet" />
<!-- YAML parser from: https://github.com/nodeca/js-yaml-->
<script src="../lib/js-yaml.min.js"></script>
<script src="../lib/json-to-html.js"></script>
<script src="example.js"></script>

View File

@ -4,7 +4,7 @@
<title>Subscribe to events from pad.ma iframe embed</title> <title>Subscribe to events from pad.ma iframe embed</title>
</head> </head>
<body> <body>
<iframe width="640" height="360" src="https://pad.ma/BVF/editor/F#embed" frameborder="0" allowfullscreen id="padembed"></iframe> <iframe width="640" height="360" src="http://10.0.3.230/A/editor/C#embed" frameborder="0" allowfullscreen id="padembed"></iframe>
<button id="setUrl"> <button id="setUrl">
Set Iframe URL Set Iframe URL
</button> </button>
@ -50,7 +50,7 @@ document.getElementById('setUrl').addEventListener('click', function(e) {
$iframe.addEventListener('load', () => { $iframe.addEventListener('load', () => {
let timeout; let timeout;
/* /*
We can't be sure that the JS inside the iframe will be fully loaded and ready to receive messages. Therefore, we need to keep resending the init event until we are sure we've received the acknowledgement reply from the embed. This function calls itself every 250ms until `isInit` on the iframe object is set to true. The listener above sets this to true once it received the init acknowledgement. We can't be sure that the JS inside the iframe will be fully loaded and ready to receive messages. Therefore, we need to keep resending the init event until we are sure we've received the acknowledgement reply from the embed. This function calls itself every 250ms until `isInit` on the iframe object is set to true. The listener above sets this to true once it received the init acknowledgement.
*/ */
function init() { function init() {

View File

@ -16,7 +16,7 @@ var PandoraEmbed = function(options) {
this.boundFns = {}; this.boundFns = {};
var width = options.width || 640; var width = options.width || 640;
var height = options.height || 360; var height = options.height || 360;
var container = options.container || document.body; var container = options.container || document;
if (!options.url) { if (!options.url) {
alert('no embed url specified'); alert('no embed url specified');
return; return;
@ -40,7 +40,7 @@ var PandoraEmbed = function(options) {
init(); init();
}); });
window.addEventListener('message', this.listener.bind(this), false); window.addEventListener('message', that.listener.bind(this), false);
container.appendChild($iframe); container.appendChild($iframe);
return this; return this;
}; };

1
lib/js-yaml.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,90 +0,0 @@
(function() {
window.jsonToHTML = getHTML
function getHTML(slideData) {
let video = audio = ''
if (!slideData.title) slideData.title = ''
title = `
<div class="title">
${slideData.title}
</div>
`
if (slideData.video) {
video = getVideoHtml(slideData.video)
}
if (slideData.audio) {
audio = getAudioHtml(slideData.audio)
}
const duration = `data-duration="${slideData.duration ? slideData.duration : 5}"`
return `
<div class="slide" ${duration}>
${title}
${video}
${audio}
</div>
`
}
function getVideoHtml(videoData) {
let urls = []
let volume = ''
if (typeof(videoData) === 'string') {
urls.push(videoData)
} else { // video is an object
if (videoData.hasOwnProperty('url')) {
urls.push(videoData.url)
} else if (videoData.hasOwnProperty('zoom')) {
urls = videoData.zoom
}
if (videoData.volume) {
volume = `data-volume="${videoData.volume}"`
}
}
const urlsHtml = urls.map((url, index) => {
return `data-url_${index}="${makeEmbed(url)}"`
}).join('\n')
return `
<div class="video" ${urlsHtml} ${volume}> </div>
`
}
function getAudioHtml(audioData) {
let url = continueStr = volume = ''
// short circuit to return an empty div if audioData is null or not an object
// this is useful for user to specify empty audio track to cause existing
// audio to pause
if (!audioData || !(typeof(audioData === 'object'))) {
return `<div class="audio></div>`
}
if (audioData.url) {
url = `data-url="${makeEmbed(audioData.url)}"`
}
if (audioData.volume) {
volume = `data-volume="${audioData.volume}"`
}
if (audioData['continue']) {
continueStr = `data-continue="true"`
}
return `
<div class="audio" ${url} ${volume} ${continueStr}></div>
`
}
function makeEmbed(url) {
if (!url.endsWith('#embed')) {
return `${url}#embed`
} else {
return url
}
}
})();