aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--resources/media-controls.css9
-rw-r--r--resources/media-controls.js75
2 files changed, 63 insertions, 21 deletions
diff --git a/resources/media-controls.css b/resources/media-controls.css
index cbea462157c..62c39164747 100644
--- a/resources/media-controls.css
+++ b/resources/media-controls.css
@@ -16,7 +16,7 @@ button {
display: block;
position: relative;
min-height: 40px;
- min-width: 200px;
+ min-width: 230px;
}
.controls {
@@ -52,3 +52,10 @@ button {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAQAAAD8x0bcAAAAy0lEQVR4AayRtUICUBRA7a7Jye5RF7u+wM4vsF2s0e7O37BzkZqZ+AF2WGk4XLqZeO/dPq/TUtuoZSki7mIgFloFlv3+icgOoKE8GlsH1sVOgOgy9jGjpzIuRjqv/rgNI3/hQCuD0t+8WK7Eywx6NfSGIAX+5t90CwOF5ODgNj4EO2TzxbDkdXwlgmCdLOolr+UlEbTn37QAK0fRBz8BAImvEYwMnmiJfdRzHxTAYoAQJjqPWWxJMf+3vHEAzCf+8A4avXYR9xSpm5QAaOvUDhZuhCsAAAAASUVORK5CYII=") no-repeat;
}
+.fullscreen {
+ background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAa1JREFUSA3Vlj1Ow0AQhW1OAFUaKmoqOEAklCIlJQ3nyBFyBahc0IAEEnUUunQWVLiloqEKNzDfmJ2V7Z1JlpKRRrt+82bezq7/yrZtH4qiOMUt2wJelWX5aQXJnYDf4UdWHOyjgFTjlm0Bz53ECAsHF65lzUFkDiffXM5Y+esQTq8CZ0ZEchLzBF5gviVsBwgiz2aYvrwtuiFWmkkjEN7S2h+wpn8Gso/ViLhXBP64+COYnkkUiAdqJLgiHhdcD74TWAnQ79pL/AsniGxki+ReTswQmSuJ2BTvm9klhGPNMUcIur+LMYHYIiiYxcd895oiUy9IbI5n3WlejX+OS/uyDV4bxNzt83IiHorfMortOuRlTLImJCe3EpisXIsz7Syulis53L6ZIhAm8hxs8PigMbeKDwpkcuRpXolAg3evipxE3YVdXGL6qqhVAKwTeZJJzwYr1+I6wrO6rcD1ZTcQ6NXtpjuL7xHRWq5ApQVyRqpJJ+PuRaT2vmiXBOPBZ4icwbmweJ7AIeR1jkjgrOFLTmLSmvy2nCSRX0B+W6755n5ZcXLlGbrHvd+W9x/rQiZUwmH0RgAAAABJRU5ErkJggg==') no-repeat;
+}
+
+.fullscreen.fullscreen-active {
+ background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABGdBTUEAALGPC/xhBQAAAbtJREFUSA3tlj0vBFEUhnd8hFhrE4mPbSREovIfdFQ6hcJ/EJVColP6GRoqhZbEFqKmET2xDSpWYjxncu915u6ZzWS20DjJ6577no/3zL1mqNWwNE1HwKb4g5rrdcjayHo54oxVbG8QAepl0FNphLVBQ6bflZ2ySiLU6+a+3bY/Hq/qA0EEog4m4ieDmwOzwrNazUOPwgQKpfkVWDAEVuHvQAsUDhjqSLKmeIQXKxKQ2Jv8UPY7eejuHJIsEantJ6B6l/glIXsKvOgq/DICT+Rld6IHH9IbEursz8GM5kv68+RdxiKJLibYYr+sOeffJknyqXlyZbhJzTn/g9yuwf9Tf3QC8SUPM8eoMUuXi/vWPJcsuSuac36H3I7BZ98UeQduQGwbcQEJ03ES+3vQ8y7kakkQkQegrYzAKwXyLuQs96K5yDrrYi6r3KZJ2jEicnS2EdwCX8Dbu3P6PcGzT3brCWuvCGTc/BpOPsVyJ0UC2ZkT3wfa8iJErObZZ4BYEyzFzww3DsKF4tsiBNaAPhaZ3PrGxBo9e0PkQP6ajYELIFa5uVejh3+SNn74z0JEjkClyX1zv9Jnxzf/AaCJ561FockLAAAAAElFTkSuQmCC') no-repeat;
+}
diff --git a/resources/media-controls.js b/resources/media-controls.js
index 383b025ee0e..b8f100c6f05 100644
--- a/resources/media-controls.js
+++ b/resources/media-controls.js
@@ -5,19 +5,6 @@
(() => {
"use strict";
- const MARKUP = `
- <div class="controls">
- <button id="play-pause-button"></button>
- <input id="progress" type="range" value="0" min="0" max="100" step="1"></input>
- <span id="position-duration-box" class="hidden">
- <span id="position-text">#1</span>
- <span id="duration"> / #2</span>
- </span>
- <button id="volume-switch"></button>
- <input id="volume-level" type="range" value="100" min="0" max="100" step="1"></input>
- </div>
- `;
-
// States.
const BUFFERING = "buffering";
const ENDED = "ended";
@@ -50,6 +37,22 @@
}
};
+ function generateMarkup(isAudioOnly) {
+ return `
+ <div class="controls">
+ <button id="play-pause-button"></button>
+ <input id="progress" type="range" value="0" min="0" max="100" step="1"></input>
+ <span id="position-duration-box" class="hidden">
+ <span id="position-text">#1</span>
+ <span id="duration"> / #2</span>
+ </span>
+ <button id="volume-switch"></button>
+ <input id="volume-level" type="range" value="100" min="0" max="100" step="1"></input>
+ ${isAudioOnly ? "" : '<button id="fullscreen-switch" class="fullscreen"></button>'}
+ </div>
+ `;
+ }
+
function camelCase(str) {
const rdashes = /-(.)/g;
return str.replace(rdashes, (str, p1) => {
@@ -89,15 +92,16 @@
attributeFilter: ["controls"]
});
+ this.isAudioOnly = this.media.localName == "audio";
+
// Create root element and load markup.
this.root = document.createElement("div");
this.root.classList.add("root");
- this.root.innerHTML = MARKUP;
+ this.root.innerHTML = generateMarkup(this.isAudioOnly);
this.controls.appendChild(this.root);
- // Import elements.
- this.elements = {};
- [
+
+ const elementNames = [
"duration",
"play-pause-button",
"position-duration-box",
@@ -105,7 +109,15 @@
"progress",
"volume-switch",
"volume-level"
- ].forEach(id => {
+ ];
+
+ if (!this.isAudioOnly) {
+ elementNames.push("fullscreen-switch");
+ }
+
+ // Import elements.
+ this.elements = {};
+ elementNames.forEach(id => {
this.elements[camelCase(id)] = this.controls.getElementById(id);
});
@@ -182,6 +194,11 @@
{ el: this.elements.volumeSwitch, type: "click" },
{ el: this.elements.volumeLevel, type: "input" }
];
+
+ if (!this.isAudioOnly) {
+ this.controlEvents.push({ el: this.elements.fullscreenSwitch, type: "click" });
+ }
+
this.controlEvents.forEach(({ el, type }) => {
el.addEventListener(type, this);
});
@@ -238,8 +255,7 @@
}
render(from = this.state) {
- const isAudioOnly = this.media.localName == "audio";
- if (!isAudioOnly) {
+ if (!this.isAudioOnly) {
// XXX This should ideally use clientHeight/clientWidth,
// but for some reason I couldn't figure out yet,
// using it breaks layout.
@@ -312,6 +328,9 @@
case this.elements.volumeSwitch:
this.toggleMuted();
break;
+ case this.elements.fullscreenSwitch:
+ this.toggleFullscreen();
+ break;
}
break;
case "input":
@@ -368,6 +387,22 @@
this.media.muted = !this.media.muted;
}
+ toggleFullscreen() {
+ const { fullscreenEnabled, fullscreenElement } = document;
+
+ const isElementFullscreen = fullscreenElement && fullscreenElement === this.media;
+
+ if (fullscreenEnabled && isElementFullscreen) {
+ document.exitFullscreen().then(() => {
+ this.elements.fullscreenSwitch.classList.remove("fullscreen-active");
+ });
+ } else {
+ this.media.requestFullscreen().then(() => {
+ this.elements.fullscreenSwitch.classList.add("fullscreen-active");
+ });
+ }
+ }
+
changeVolume() {
const volume = parseInt(this.elements.volumeLevel.value);
if (!isNaN(volume)) {