MDL-67513 core: Only move modal to body if currently attached
[moodle.git] / lib / amd / src / modal_backdrop.js
CommitLineData
2bcef559
RW
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 * Contain the logic for modal backdrops.
18 *
19 * @module core/modal_backdrop
20 * @class modal_backdrop
21 * @package core
22 * @copyright 2016 Ryan Wyllie <ryan@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
a2dcfd5b
NM
25define(['jquery', 'core/templates', 'core/notification', 'core/fullscreen'],
26 function($, Templates, Notification, Fullscreen) {
2bcef559
RW
27
28 var SELECTORS = {
29 ROOT: '[data-region="modal-backdrop"]',
30 };
31
32 /**
33 * Constructor for ModalBackdrop.
34 *
35 * @param {object} root The root element for the modal backdrop
36 */
37 var ModalBackdrop = function(root) {
38 this.root = $(root);
39 this.isAttached = false;
40
41 if (!this.root.is(SELECTORS.ROOT)) {
42 Notification.exception({message: 'Element is not a modal backdrop'});
43 }
44 };
45
46 /**
47 * Get the root element of this modal backdrop.
48 *
49 * @method getRoot
50 * @return {object} jQuery object
51 */
52 ModalBackdrop.prototype.getRoot = function() {
53 return this.root;
54 };
55
a2dcfd5b
NM
56 /**
57 * Gets the jQuery wrapped node that the Modal should be attached to.
58 *
59 * @returns {jQuery}
60 */
61 ModalBackdrop.prototype.getAttachmentPoint = function() {
62 return $(Fullscreen.getElement() || document.body);
63 };
64
2bcef559
RW
65 /**
66 * Add the modal backdrop to the page, if it hasn't already been added.
67 *
68 * @method attachToDOM
69 */
70 ModalBackdrop.prototype.attachToDOM = function() {
a2dcfd5b
NM
71 this.getAttachmentPoint().append(this.root);
72
2bcef559
RW
73 if (this.isAttached) {
74 return;
75 }
76
2bcef559
RW
77 this.isAttached = true;
78 };
79
80 /**
81 * Set the z-index value for this backdrop.
82 *
83 * @method setZIndex
84 * @param {int} value The z-index value
85 */
86 ModalBackdrop.prototype.setZIndex = function(value) {
87 this.root.css('z-index', value);
88 };
89
90 /**
91 * Check if this backdrop is visible.
92 *
93 * @method isVisible
94 * @return {bool}
95 */
96 ModalBackdrop.prototype.isVisible = function() {
97 return this.root.hasClass('show');
98 };
99
100 /**
101 * Check if this backdrop has CSS transitions applied.
102 *
103 * @method hasTransitions
104 * @return {bool}
105 */
106 ModalBackdrop.prototype.hasTransitions = function() {
107 return this.getRoot().hasClass('fade');
108 };
109
110 /**
111 * Display this backdrop. The backdrop will be attached to the DOM if it hasn't
112 * already been.
113 *
114 * @method show
115 */
116 ModalBackdrop.prototype.show = function() {
117 if (this.isVisible()) {
118 return;
119 }
120
a2dcfd5b 121 this.attachToDOM();
2bcef559
RW
122
123 this.root.removeClass('hide').addClass('show');
124 };
125
126 /**
127 * Hide this backdrop.
128 *
129 * @method hide
130 */
131 ModalBackdrop.prototype.hide = function() {
132 if (!this.isVisible()) {
133 return;
134 }
135
136 if (this.hasTransitions()) {
137 // Wait for CSS transitions to complete before hiding the element.
138 this.getRoot().one('transitionend webkitTransitionEnd oTransitionEnd', function() {
139 this.getRoot().removeClass('show').addClass('hide');
140 }.bind(this));
141 } else {
142 this.getRoot().removeClass('show').addClass('hide');
143 }
a2dcfd5b 144
be2afb52
AN
145 // Ensure the modal is moved onto the body node if it is still attached to the DOM.
146 if ($(document.body).find(this.getRoot()).length) {
147 $(document.body).append(this.getRoot());
148 }
2bcef559
RW
149 };
150
151 /**
152 * Remove this backdrop from the DOM.
153 *
154 * @method destroy
155 */
156 ModalBackdrop.prototype.destroy = function() {
157 this.root.remove();
158 };
159
160 return ModalBackdrop;
161});