MDL-59784 core: Modal factory should listen before fetching templates
[moodle.git] / lib / amd / src / modal_factory.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 * Create a modal.
18 *
19 * @module core/modal_factory
20 * @class modal_factory
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 */
0531ce1a
RW
25define(['jquery', 'core/modal_events', 'core/modal_registry', 'core/modal',
26 'core/modal_save_cancel', 'core/modal_confirm', 'core/modal_cancel',
10ea8270 27 'core/templates', 'core/notification', 'core/custom_interaction_events'],
0531ce1a
RW
28 function($, ModalEvents, ModalRegistry, Modal, ModalSaveCancel, ModalConfirm,
29 ModalCancel, Templates, Notification, CustomEvents) {
2bcef559
RW
30
31 // The templates for each type of modal.
32 var TEMPLATES = {
33 DEFAULT: 'core/modal',
34 SAVE_CANCEL: 'core/modal_save_cancel',
10ea8270 35 CONFIRM: 'core/modal_confirm',
be2247fb 36 CANCEL: 'core/modal_cancel',
2bcef559
RW
37 };
38
2bcef559
RW
39 // The available types of modals.
40 var TYPES = {
41 DEFAULT: 'DEFAULT',
42 SAVE_CANCEL: 'SAVE_CANCEL',
10ea8270 43 CONFIRM: 'CONFIRM',
be2247fb 44 CANCEL: 'CANCEL',
2bcef559
RW
45 };
46
0531ce1a
RW
47 // Register the common set of modals.
48 ModalRegistry.register(TYPES.DEFAULT, Modal, TEMPLATES.DEFAULT);
49 ModalRegistry.register(TYPES.SAVE_CANCEL, ModalSaveCancel, TEMPLATES.SAVE_CANCEL);
50 ModalRegistry.register(TYPES.CONFIRM, ModalConfirm, TEMPLATES.CONFIRM);
51 ModalRegistry.register(TYPES.CANCEL, ModalCancel, TEMPLATES.CANCEL);
52
2bcef559
RW
53 /**
54 * Set up the events required to show the modal and return focus when the modal
55 * is closed.
56 *
57 * @method setUpTrigger
72835770 58 * @param {Promise} modalPromise The modal instance
2bcef559
RW
59 * @param {object} triggerElement The jQuery element to open the modal
60 */
72835770 61 var setUpTrigger = function(modalPromise, triggerElement) {
2bcef559 62 if (typeof triggerElement != 'undefined') {
6a7ad2cb
RW
63 if (Array.isArray(triggerElement)) {
64 var selector = triggerElement[1];
65 triggerElement = triggerElement[0];
66
67 CustomEvents.define(triggerElement, [CustomEvents.events.activate]);
68 triggerElement.on(CustomEvents.events.activate, selector, function(e, data) {
72835770
AN
69 modalPromise.then(function(modal) {
70 modal.show();
71
72 return modal;
73 });
6a7ad2cb
RW
74 data.originalEvent.preventDefault();
75 });
76 } else {
77 CustomEvents.define(triggerElement, [CustomEvents.events.activate]);
78 triggerElement.on(CustomEvents.events.activate, function(e, data) {
72835770
AN
79 modalPromise.then(function(modal) {
80 modal.show();
81
82 return modal;
83 });
6a7ad2cb
RW
84 data.originalEvent.preventDefault();
85 });
86 }
2bcef559 87
72835770
AN
88 modalPromise.then(function(modal) {
89 modal.getRoot().on(ModalEvents.hidden, function() {
90 triggerElement.focus();
91 });
92
93 return modal;
2bcef559
RW
94 });
95 }
96 };
97
98 /**
99 * Create the correct instance of a modal based on the givem type. Sets up
100 * the trigger between the modal and the trigger element.
101 *
102 * @method createFromElement
0531ce1a 103 * @param {object} registryConf A config from the ModalRegistry
2bcef559
RW
104 * @param {object} modalElement The modal HTML jQuery object
105 * @param {object} triggerElement The trigger HTML jQuery object
106 * @return {object} Modal instance
107 */
72835770 108 var createFromElement = function(registryConf, modalElement) {
2bcef559 109 modalElement = $(modalElement);
0531ce1a
RW
110 var module = registryConf.module;
111 var modal = new module(modalElement);
2bcef559
RW
112
113 return modal;
114 };
115
116 /**
117 * Create the correct modal instance for the given type, including loading
118 * the correct template and setting up the trigger relationship with the
119 * trigger element.
120 *
121 * @method createFromType
0531ce1a 122 * @param {object} registryConf A config from the ModalRegistry
2bcef559
RW
123 * @param {object} triggerElement The trigger HTML jQuery object
124 * @return {promise} Resolved with a Modal instance
125 */
a50768b9 126 var createFromType = function(registryConf, templateContext, triggerElement) {
0531ce1a 127 var templateName = registryConf.template;
2bcef559 128
72835770 129 var modalPromise = Templates.render(templateName, templateContext)
2bcef559
RW
130 .then(function(html) {
131 var modalElement = $(html);
72835770 132 return createFromElement(registryConf, modalElement);
2bcef559
RW
133 })
134 .fail(Notification.exception);
72835770
AN
135
136 setUpTrigger(modalPromise, triggerElement);
137
138 return modalPromise;
2bcef559
RW
139 };
140
141 /**
142 * Create a Modal instance.
143 *
144 * @method create
145 * @param {object} modalConfig The configuration to create the modal instance
146 * @param {object} triggerElement The trigger HTML jQuery object
147 * @return {promise} Resolved with a Modal instance
148 */
149 var create = function(modalConfig, triggerElement) {
150 var type = modalConfig.type || TYPES.DEFAULT;
151 var isLarge = modalConfig.large ? true : false;
0531ce1a 152 var registryConf = null;
a50768b9 153 var templateContext = {};
0531ce1a
RW
154
155 registryConf = ModalRegistry.get(type);
2bcef559 156
0531ce1a
RW
157 if (!registryConf) {
158 Notification.exception({message: 'Unable to find modal of type: ' + type});
2bcef559
RW
159 }
160
a50768b9
RW
161 if (typeof modalConfig.templateContext != 'undefined') {
162 templateContext = modalConfig.templateContext;
163 }
164
165 return createFromType(registryConf, templateContext, triggerElement)
2bcef559
RW
166 .then(function(modal) {
167 if (typeof modalConfig.title != 'undefined') {
168 modal.setTitle(modalConfig.title);
169 }
170
171 if (typeof modalConfig.body != 'undefined') {
172 modal.setBody(modalConfig.body);
173 }
174
175 if (typeof modalConfig.footer != 'undefined') {
176 modal.setFooter(modalConfig.footer);
177 }
178
179 if (isLarge) {
180 modal.setLarge();
181 }
182
183 return modal;
184 });
185 };
186
187 return {
188 create: create,
189 types: TYPES,
190 };
191});