MDL-66893 mod_forum: update navigation bar in grader UI
[moodle.git] / mod / forum / amd / src / local / layout / fullscreen.js
1 // This file is part of Moodle - http://moodle.org/
2 //
3 // Moodle is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // Moodle is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16 /**
17  * Full screen window layout.
18  *
19  * @copyright  2019 Andrew Nicols <andrew@nicols.co.uk>
20  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
21  */
23 import {addIconToContainer} from 'core/loadingicon';
25 /**
26  * @param {string} templateName
27  * @param {object} context
28  * @return {object}
29  */
30 const getComposedLayout = ({
31     fullscreen = true,
32     showLoader = false,
33 } = {}) => {
34     const container = document.createElement('div');
35     document.body.append(container);
36     container.classList.add('layout');
37     container.classList.add('fullscreen');
38     container.setAttribute('aria-role', 'application');
40     // Lock scrolling on the document body.
41     lockBodyScroll();
43     const helpers = getLayoutHelpers(container);
45     if (showLoader) {
46         helpers.showLoadingIcon();
47     }
49     if (fullscreen) {
50         helpers.requestFullscreen();
51     }
53     return helpers;
54 };
56 const getLayoutHelpers = (layoutNode) => {
57     const contentNode = document.createElement('div');
58     layoutNode.append(contentNode);
60     const loadingNode = document.createElement('div');
61     layoutNode.append(loadingNode);
63     /**
64      * Close and destroy the window container.
65      */
66     const close = () => {
67         exitFullscreen();
68         unlockBodyScroll();
70         layoutNode.remove();
71     };
73     /**
74      * Attempt to make the conatiner full screen.
75      */
76     const requestFullscreen = () => {
77         if (layoutNode.requestFullscreen) {
78             layoutNode.requestFullscreen();
79         } else if (layoutNode.msRequestFullscreen) {
80             layoutNode.msRequestFullscreen();
81         } else if (layoutNode.mozRequestFullscreen) {
82             layoutNode.mozRequestFullscreen();
83         } else if (layoutNode.webkitRequestFullscreen) {
84             layoutNode.webkitRequestFullscreen();
85         } else {
86             // Not supported.
87             // Hack to make this act like full-screen as much as possible.
88             layoutNode.setTop(0);
89         }
90     };
92     /**
93      * Exit full screen but do not close the container fully.
94      */
95     const exitFullscreen = () => {
96         if (document.exitRequestFullScreen) {
97             if (document.fullScreenElement !== layoutNode) {
98                 return;
99             }
100             document.exitRequestFullScreen();
101         } else if (document.msExitFullscreen) {
102             if (document.msFullscreenElement !== layoutNode) {
103                 return;
104             }
105             document.msExitFullscreen();
106         } else if (document.mozCancelFullScreen) {
107             if (document.mozFullScreenElement !== layoutNode) {
108                 return;
109             }
110             document.mozCancelFullScreen();
111         } else if (document.webkitExitFullscreen) {
112             if (document.webkitFullscreenElement !== layoutNode) {
113                 return;
114             }
115             document.webkitExitFullscreen();
116         }
117     };
119     const toggleFullscreen = () => {
120         if (document.exitRequestFullScreen) {
121             if (document.fullScreenElement === layoutNode) {
122                 exitFullscreen();
123             } else {
124                 requestFullscreen();
125             }
126         } else if (document.msExitFullscreen) {
127             if (document.msFullscreenElement === layoutNode) {
128                 exitFullscreen();
129             } else {
130                 requestFullscreen();
131             }
132         } else if (document.mozCancelFullScreen) {
133             if (document.mozFullScreenElement === layoutNode) {
134                 exitFullscreen();
135             } else {
136                 requestFullscreen();
137             }
138         } else if (document.webkitExitFullscreen) {
139             if (document.webkitFullscreenElement === layoutNode) {
140                 exitFullscreen();
141             } else {
142                 requestFullscreen();
143             }
144         }
145     };
147     /**
148      * Get the Node which is fullscreen.
149      *
150      * @return {Element}
151      */
152     const getContainer = () => {
153         return contentNode;
154     };
156     const setContent = (content) => {
157         hideLoadingIcon();
159         // Note: It would be better to use replaceWith, but this is not compatible with IE.
160         let child = contentNode.lastElementChild;
161         while (child) {
162             contentNode.removeChild(child);
163             child = contentNode.lastElementChild;
164         }
165         contentNode.append(content);
166     };
168     const showLoadingIcon = () => {
169         addIconToContainer(loadingNode);
170     };
172     const hideLoadingIcon = () => {
173         // Hide the loading container.
174         let child = loadingNode.lastElementChild;
175         while (child) {
176             loadingNode.removeChild(child);
177             child = loadingNode.lastElementChild;
178         }
179     };
181     /**
182      * @return {Object}
183      */
184     return {
185         close,
187         toggleFullscreen,
188         requestFullscreen,
189         exitFullscreen,
191         getContainer,
192         setContent,
194         showLoadingIcon,
195         hideLoadingIcon,
196     };
197 };
199 const lockBodyScroll = () => {
200     document.querySelector('body').classList.add('overflow-hidden');
201 };
203 const unlockBodyScroll = () => {
204     document.querySelector('body').classList.remove('overflow-hidden');
205 };
207 export const createLayout = getComposedLayout;