Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/www/js/fullscreen.js

4.3 KiB, 1 run

created by r2519314175:1365, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1/* ============================================================
2 Daimond — the app-wide full-screen toggle (phone only)
3 ------------------------------------------------------------
4 Firefox on Android does not install the PWA standalone, so an
5 old device stuck on it has no immersive view at all. The
6 browser Fullscreen API is the one way there: it hides the
7 address bar, the tabs and the status bar together. Desktop
8 already has F11 and a real standalone install, so this control
9 never shows there.
10
11 Nothing is persisted -- full screen is transient, and the
12 browser drops it on navigation and on the system back gesture.
13 The button's face is kept true by listening for
14 `fullscreenchange`, so leaving by the back gesture (no click)
15 still flips the icon and label back.
16
17 Gated on `DaimondShell.isPhone()`, the app's own layout signal
18 (the single 760 cliff), so the control appears and vanishes
19 with the phone layout and stays off the landscape breakpoint
20 gap a naive innerWidth check would fall into.
21 ============================================================ */
22(function () {
23 'use strict';
24
25 var docEl = document.documentElement;
26
27 /// The element currently filling the screen, across vendor prefixes.
28 function fsElement() {
29 return document.fullscreenElement
30 || document.webkitFullscreenElement
31 || document.mozFullScreenElement
32 || document.msFullscreenElement
33 || null;
34 }
35
36 /// Does this browser offer the Fullscreen API at all?
37 function canFull() {
38 return !!(docEl.requestFullscreen || docEl.webkitRequestFullscreen
39 || docEl.mozRequestFullScreen || docEl.msRequestFullscreen);
40 }
41
42 function enter() {
43 var fn = docEl.requestFullscreen || docEl.webkitRequestFullscreen
44 || docEl.mozRequestFullScreen || docEl.msRequestFullscreen;
45 if (fn) try { fn.call(docEl); } catch (e) { /* denied, or no user gesture */ }
46 }
47
48 function leave() {
49 var fn = document.exitFullscreen || document.webkitExitFullscreen
50 || document.mozCancelFullScreen || document.msExitFullscreen;
51 if (fn) try { fn.call(document); } catch (e) { /* already out */ }
52 }
53
54 /// A translated string, or the English fallback if the key is absent.
55 function t(key, fallback) {
56 return (window.DaimondI18n && DaimondI18n.has && DaimondI18n.has(key))
57 ? DaimondI18n.t(key) : fallback;
58 }
59
60 /// Phone only, decided by the app's own signal rather than a width read of
61 /// our own -- one 760 cliff, shared with the rail and the sheet.
62 function isPhone() {
63 return !!(window.DaimondShell && DaimondShell.isPhone && DaimondShell.isPhone());
64 }
65
66 var btn = null;
67
68 /// Show or hide the control for the width, and say which state it is in.
69 function sync() {
70 if (!btn) return;
71 // No API, or not the phone layout: the control has no business on screen.
72 if (!canFull() || !isPhone()) { btn.style.display = 'none'; return; }
73 btn.style.display = '';
74 var on = !!fsElement();
75 // The label names the destination while the mode is on: "Exit full
76 // screen", not "Full screen (on)".
77 var label = on ? t('fullscreen.exit', 'Exit full screen')
78 : t('fullscreen.enter', 'Full screen');
79 btn.classList.toggle('on', on);
80 btn.setAttribute('aria-pressed', on ? 'true' : 'false');
81 btn.setAttribute('aria-label', label);
82 btn.title = label;
83 }
84
85 function init() {
86 btn = document.getElementById('fullscreen-btn');
87 if (!btn) return;
88 // A browser without the API never sees the button.
89 if (!canFull()) { btn.style.display = 'none'; return; }
90
91 btn.addEventListener('click', function () {
92 if (fsElement()) leave(); else enter();
93 });
94
95 // Keep the face true even when the user leaves by the system back
96 // gesture, which fires a change event but never a click.
97 ['fullscreenchange', 'webkitfullscreenchange',
98 'mozfullscreenchange', 'MSFullscreenChange'].forEach(function (ev) {
99 document.addEventListener(ev, sync);
100 });
101
102 // The 760 cliff, watched the same way the shell watches it.
103 var mq = window.matchMedia('(max-width: 760px)');
104 if (mq.addEventListener) mq.addEventListener('change', sync);
105 else if (mq.addListener) mq.addListener(sync);
106
107 // Re-label on a language change.
108 if (window.DaimondI18n && DaimondI18n.onChange) DaimondI18n.onChange(sync);
109
110 sync();
111 }
112
113 if (document.readyState === 'loading') {
114 document.addEventListener('DOMContentLoaded', init);
115 } else {
116 init();
117 }
118})();