Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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/>.
15
 
16
/**
17
 * Full screen window layout.
18
 *
19
 * @module mod_forum/local/layout/fullscreen
20
 * @copyright  2019 Andrew Nicols <andrew@nicols.co.uk>
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
 
24
import {addIconToContainer} from 'core/loadingicon';
25
import {addToastRegion} from 'core/toast';
26
import * as FocusLockManager from 'core/local/aria/focuslock';
27
 
28
/**
29
 * Get the composed layout.
30
 *
31
 * @method
32
 * @param {string} templateName
33
 * @param {object} context
34
 * @returns {LayoutHelper}
35
 */
36
 
37
export const createLayout = ({
38
    fullscreen = true,
39
    showLoader = false,
40
    focusOnClose = null,
41
} = {}) => {
42
    const container = document.createElement('div');
43
    document.body.append(container);
44
    container.classList.add('layout');
45
    container.classList.add('fullscreen');
46
    container.setAttribute('role', 'application');
47
    addToastRegion(container);
48
 
49
    // Lock scrolling on the document body.
50
    lockBodyScroll();
51
 
52
    // Lock tab control.
53
    FocusLockManager.trapFocus(container);
54
 
55
    const helpers = getLayoutHelpers(container, FocusLockManager, focusOnClose);
56
 
57
    if (showLoader) {
58
        helpers.showLoadingIcon();
59
    }
60
 
61
    if (fullscreen) {
62
        helpers.requestFullscreen();
63
    }
64
 
65
    return helpers;
66
};
67
 
68
/**
69
 * LayoutHelper A helper object containing functions for managing the current fullscreen layout
70
 *
71
 * @typedef {object}
72
 * @property {Function} close A function to close the fullscreen layout
73
 * @property {Function} toggleFullscreen A function to toggle the fullscreen from active to disabled and back
74
 * @property {Function} requestFullscreen Make a request to the browser to make the window full screen.
75
 * Note: This must be called in response to a direct user action
76
 * @property {Function} exitFullscreen Exit the fullscreen mode
77
 * @property {Function} getContainer Get the container of the fullscreen layout
78
 * @property {Function} setContent Set the content of the fullscreen layout
79
 * @property {Function} showLoadingIcon Display the loading icon
80
 * @property {Function} hideLoadingIcon Hide the loading icon
81
 */
82
 
83
/**
84
 * Get the layout helpers.
85
 *
86
 * @method
87
 * @private
88
 * @param {HTMLElement} layoutNode
89
 * @param {FocusLockManager} FocusLockManager
90
 * @param {Boolean} focusOnClose
91
 * @returns {LayoutHelper}
92
 */
93
const getLayoutHelpers = (layoutNode, FocusLockManager, focusOnClose) => {
94
    const contentNode = document.createElement('div');
95
    layoutNode.append(contentNode);
96
 
97
    const loadingNode = document.createElement('div');
98
    layoutNode.append(loadingNode);
99
 
100
    /**
101
     * Close and destroy the window container.
102
     */
103
    const close = () => {
104
        exitFullscreen();
105
        unlockBodyScroll();
106
        FocusLockManager.untrapFocus();
107
 
108
        layoutNode.remove();
109
 
110
        if (focusOnClose) {
111
            try {
112
                focusOnClose.focus();
113
            } catch (e) {
114
                // eslint-disable-line
115
            }
116
        }
117
    };
118
 
119
    /**
120
     * Attempt to make the conatiner full screen.
121
     */
122
    const requestFullscreen = () => {
123
        if (layoutNode.requestFullscreen) {
124
            layoutNode.requestFullscreen();
125
        } else if (layoutNode.msRequestFullscreen) {
126
            layoutNode.msRequestFullscreen();
127
        } else if (layoutNode.mozRequestFullscreen) {
128
            layoutNode.mozRequestFullscreen();
129
        } else if (layoutNode.webkitRequestFullscreen) {
130
            layoutNode.webkitRequestFullscreen();
131
        } else {
132
            // Not supported.
133
            // Hack to make this act like full-screen as much as possible.
134
            layoutNode.setTop(0);
135
        }
136
    };
137
 
138
    /**
139
     * Exit full screen but do not close the container fully.
140
     */
141
    const exitFullscreen = () => {
142
        if (document.exitRequestFullScreen) {
143
            if (document.fullScreenElement !== layoutNode) {
144
                return;
145
            }
146
            document.exitRequestFullScreen();
147
        } else if (document.msExitFullscreen) {
148
            if (document.msFullscreenElement !== layoutNode) {
149
                return;
150
            }
151
            document.msExitFullscreen();
152
        } else if (document.mozCancelFullScreen) {
153
            if (document.mozFullScreenElement !== layoutNode) {
154
                return;
155
            }
156
            document.mozCancelFullScreen();
157
        } else if (document.webkitExitFullscreen) {
158
            if (document.webkitFullscreenElement !== layoutNode) {
159
                return;
160
            }
161
            document.webkitExitFullscreen();
162
        }
163
    };
164
 
165
    const toggleFullscreen = () => {
166
        if (document.exitRequestFullScreen) {
167
            if (document.fullScreenElement === layoutNode) {
168
                exitFullscreen();
169
            } else {
170
                requestFullscreen();
171
            }
172
        } else if (document.msExitFullscreen) {
173
            if (document.msFullscreenElement === layoutNode) {
174
                exitFullscreen();
175
            } else {
176
                requestFullscreen();
177
            }
178
        } else if (document.mozCancelFullScreen) {
179
            if (document.mozFullScreenElement === layoutNode) {
180
                exitFullscreen();
181
            } else {
182
                requestFullscreen();
183
            }
184
        } else if (document.webkitExitFullscreen) {
185
            if (document.webkitFullscreenElement === layoutNode) {
186
                exitFullscreen();
187
            } else {
188
                requestFullscreen();
189
            }
190
        }
191
    };
192
 
193
    /**
194
     * Get the Node which is fullscreen.
195
     *
196
     * @return {Element}
197
     */
198
    const getContainer = () => {
199
        return contentNode;
200
    };
201
 
202
    const setContent = (content) => {
203
        hideLoadingIcon();
204
 
205
        // Note: It would be better to use replaceWith, but this is not compatible with IE.
206
        let child = contentNode.lastElementChild;
207
        while (child) {
208
            contentNode.removeChild(child);
209
            child = contentNode.lastElementChild;
210
        }
211
        contentNode.append(content);
212
    };
213
 
214
    const showLoadingIcon = () => {
215
        addIconToContainer(loadingNode);
216
    };
217
 
218
    const hideLoadingIcon = () => {
219
        // Hide the loading container.
220
        let child = loadingNode.lastElementChild;
221
        while (child) {
222
            loadingNode.removeChild(child);
223
            child = loadingNode.lastElementChild;
224
        }
225
    };
226
 
227
    /**
228
     * @return {Object}
229
     */
230
    return {
231
        close,
232
 
233
        toggleFullscreen,
234
        requestFullscreen,
235
        exitFullscreen,
236
 
237
        getContainer,
238
        setContent,
239
 
240
        showLoadingIcon,
241
        hideLoadingIcon,
242
    };
243
};
244
 
245
const lockBodyScroll = () => {
246
    document.querySelector('body').classList.add('overflow-hidden');
247
};
248
 
249
const unlockBodyScroll = () => {
250
    document.querySelector('body').classList.remove('overflow-hidden');
251
};