<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Video Frame</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<section>
<iframe src="videoframe.html" width='100%' height='100%' scrolling='no' frameborder='0' allowfullscreen
allow="autoplay; fullscreen"></iframe>
</section>
<form id='control'>
<fieldset>
<select id='tX'>
<option value='Timeslot'>Select</option>
<optgroup label='Command'>
<option>Play</option>
<option>Pause</option>
<option>Stop</option>
</optgroup>
<optgroup label='Load Media'>
<option>Video 1</option>
<option>Video 2</option>
<option>Video 3</option>
</optgroup>
<optgroup label="Test">
<option>Messages</option>
<option>Controls</option>
</optgroup>
</select>
<button>Send</button>
</fieldset>
</form>
</main>
<script>
window.onload = function(e) {
var ctrl = document.forms.control;
var cX = ctrl.elements;
var tX = cX.tX;
ctrl.addEventListener('submit', function(e) {
e.preventDefault();
window.frames[0].postMessage(tX.value, "https://"+location.hostname);
console.log(tX.value);
});
};
</script>
</body>
</html>
html,
body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
font: 400 16px/1.5 Consolas;
overflow: hidden;
}
main {
width: 100%;
height: auto;
padding: 10px;
}
section {
height: 0;
width: 100%;
position: relative;
padding-bottom: 56.25%;
margin: 15px auto 5px;
}
fieldset {
width: fit-content;
padding: 5px;
}
iframe {
height: 100%;
width: 100%;
overflow: hidden;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
select,
button {
font: inherit;
padding: 0 3px;
line-height: 1.2;
}
#msg {
position: absolute;
z-index: 1;
background: rgba(0, 0, 0, 0.5);
}
#time,
#rX {
display: block;
float: left;
color: gold;
padding: 0 5px;
width: 70px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Video iframe</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<aside id='msg'>
<output id='rX'></output>
<time id='time'></time>
</aside>
<video id='vX' src='about:blank' width='96%' muted autoplay></video>
<script>
var v = document.getElementById('vX');
var vid =
'https://storage04.dropshots.com/photos6000/photos/1381926/20170326/';
var r = document.getElementById('rX');
var t = document.getElementById('time');
(function() {
loadVideo();
})();
window.addEventListener("message", rXMsg);
function rXMsg(e) {
var msg = e.data;
switch (msg) {
case 'Play':
playMedia();
break;
case 'Pause':
v.pause();
break;
case 'Stop':
v.pause();
v.currentTime = 0;
break;
case 'Video 1':
v.src = vid + '005609.mp4';
v.load();
break;
case 'Video 2':
v.src = vid + '005610.mp4';
v.load();
break;
case 'Video 3':
v.src = vid + '005612.mp4';
v.load();
break;
case 'Messages':
toggleAttr('#msg', 'hidden');
break;
case 'Controls':
toggleAttr('#vX', 'controls');
break;
default:
loadVideo();
break;
}
stamp(msg);
}
function loadVideo() {
var hrs = stamp();
// 05:00 - 09:59
if (hrs >= 5 && hrs < 10) {
v.src = vid + '005609.mp4';
v.load();
}
// 10:00 - 21:59
else if (hrs >= 10 && hrs < 22) {
v.src = vid + '005610.mp4';
v.load();
}
// 22:00 - 04:59
else {
v.src = vid + '005612.mp4';
v.load();
}
stamp('Autoload');
}
async function playMedia() {
try {
await v.play();
} catch (err) {
stamp('Promise Rejected');
}
}
function toggleAttr(selector, attr) {
var node = document.querySelector(selector);
var prop = node.getAttribute(attr);
if (!prop) {
node.setAttribute(attr, true);
} else {
node.removeAttribute(attr);
}
}
function stamp(str) {
var now = new Date();
var hrs = now.getHours();
var min = now.getMinutes();
var sec = now.getSeconds();
var h = hrs > 9 ? "" + hrs : "0" + hrs;
var m = min > 9 ? "" + min : "0" + min;
var s = sec > 9 ? "" + sec : "0" + sec;
var time = h + ":" + m + ":" + s;
r.textContent = str;
t.textContent = time;
return hrs;
}
</script>
</body>
</html>
`<iframe>` & `<video>`
==========================
Autoplay
--------
Autoplay ain't what it used to be. There's too [many restrictions and various criteria](https://developers.google.com/web/updates/2017/09/autoplay-policy-changes) involved in getting a `<video>` tag to autoplay. Here's what was needed:
`<video>` tag needs `[muted]` and `[autoplay]` attributes
<video ... muted autoplay></video>
`<iframe>` tag needs `[allow="autoplay"]` attribute. Full screen is optional
<iframe ... allowfullscreen allow="autoplay; fullscreen"></iframe>
`loadVideo()` is the function that loads a MP4 file to the `<video>` tag's `[src]` according to the current time. Autoloading media from an `<iframe>` is trickier because they are one of the last of the DOM content to load. It's best to run the function from the child page (`videoframe.html`) in an [IIFE (Immediately-invoked Function Expression)](https://medium.com/@vvkchandra/essential-javascript-mastering-immediately-invoked-function-expressions-67791338ddc6).
(function() {
loadVideo();
})();
Promises
--------
In order to invoke `play()` method, you'll need to use the [Promise API](https://javascript.info/promise-api). This is another instance when something works and [engineers want to overcomplicate it](https://developers.google.com/web/updates/2016/03/play-returns-promise).
async function promisePlay() {
try {
await document.querySelector('video').play();
} catch (err) {
...
}
}
postMessage
-----------
For cross-domain communication using the [postMessage API via `<iframe>`](https://www.dyn-web.com/tutorials/iframes/postmessage/), the developer must have ownership of both domains. Ownership doesn't necessarily mean full administrative privileges, just enough so that both pages can actually be edited. There are some APIs that'll meet you halfway like YouTube and Vimeo as well.
Basically the parent page (`index.html`) will send a message:
window.frames[0].postMessage(data, origin);
1. `window.frames[0]` will get the first `<iframe>` and access it's window content, an equivalent to: `document.querySelector('iframe').contentWindow;`.
2. `data` is just a string.
3. `origin` is usually the [`location.protocol` and `location.hostname` or `location.origin`](https://developer.mozilla.org/en-US/docs/Web/API/Location) of the parent page (`index.html`): `https://www.example.com`.
The child page (`videoframe.html`) recieves the `data` (just a typical string) by listening for the `message` event on it's [Window Object](https://developer.mozilla.org/en-US/docs/Web/API/Window):
window.addEventListener("message", callback);
Most examples show how a message is sent and received, and the result of the message being displayed on the child page -- lame. Here's what a callback would look like if it were actually useful:
function callback(event) {
var string = event.data;
// Optional-------------------------
var from = event.origin;
if (from !== 'https://www.example.com') {
document.querySelector('#displayMsg').textContent = `MESSAGE REJECTED`;
return;
}
//----------------------------------
if (string === "play") {
promisePlay();
} else if (string === "pause") {
document.querySelector('video').pause();
} else if (string === "stop") {
document.querySelector('video').pause();
document.querySelector('video').currentTime = 0;
} else {
document.querySelector('#displayMsg').textContent = `ERROR: ${string} is not a command.`;
}
}