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 |
* A javascript module to handle calendar drag and drop in the calendar
|
|
|
18 |
* month view navigation.
|
|
|
19 |
*
|
|
|
20 |
* This code is run each time the calendar month view is re-rendered. We
|
|
|
21 |
* only register the event handlers once per page load so that the in place
|
|
|
22 |
* DOM updates that happen on month change don't continue to register handlers.
|
|
|
23 |
*
|
|
|
24 |
* @module core_calendar/month_navigation_drag_drop
|
|
|
25 |
* @copyright 2017 Ryan Wyllie <ryan@moodle.com>
|
|
|
26 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
27 |
*/
|
|
|
28 |
define([
|
|
|
29 |
'jquery',
|
|
|
30 |
'core_calendar/drag_drop_data_store',
|
|
|
31 |
],
|
|
|
32 |
function(
|
|
|
33 |
$,
|
|
|
34 |
DataStore
|
|
|
35 |
) {
|
|
|
36 |
|
|
|
37 |
var SELECTORS = {
|
|
|
38 |
DRAGGABLE: '[draggable="true"][data-region="event-item"]',
|
|
|
39 |
DROP_ZONE: '[data-drop-zone="nav-link"]',
|
|
|
40 |
};
|
|
|
41 |
var HOVER_CLASS = 'bg-primary text-white';
|
|
|
42 |
var TARGET_CLASS = 'drop-target';
|
|
|
43 |
var HOVER_TIME = 1000; // 1 second hover to change month.
|
|
|
44 |
|
|
|
45 |
// We store some static variables at the module level because this
|
|
|
46 |
// module is called each time the calendar month view is reloaded but
|
|
|
47 |
// we want some actions to only occur ones.
|
|
|
48 |
|
|
|
49 |
/* @var {bool} registered If the event listeners have been added */
|
|
|
50 |
var registered = false;
|
|
|
51 |
/* @var {int} hoverTimer The timeout id of any timeout waiting for hover */
|
|
|
52 |
var hoverTimer = null;
|
|
|
53 |
/* @var {object} root The root nav element we're operating on */
|
|
|
54 |
var root = null;
|
|
|
55 |
|
|
|
56 |
/**
|
|
|
57 |
* Add or remove the appropriate styling to indicate whether
|
|
|
58 |
* the drop target is being hovered over.
|
|
|
59 |
*
|
|
|
60 |
* @param {object} target The target drop zone element
|
|
|
61 |
* @param {bool} hovered If the element is hovered over ot not
|
|
|
62 |
*/
|
|
|
63 |
var updateHoverState = function(target, hovered) {
|
|
|
64 |
if (hovered) {
|
|
|
65 |
target.addClass(HOVER_CLASS);
|
|
|
66 |
} else {
|
|
|
67 |
target.removeClass(HOVER_CLASS);
|
|
|
68 |
}
|
|
|
69 |
};
|
|
|
70 |
|
|
|
71 |
/**
|
|
|
72 |
* Add some styling to the UI to indicate that the nav links
|
|
|
73 |
* are an acceptable drop target.
|
|
|
74 |
*/
|
|
|
75 |
var addDropZoneIndicator = function() {
|
|
|
76 |
root.find(SELECTORS.DROP_ZONE).addClass(TARGET_CLASS);
|
|
|
77 |
};
|
|
|
78 |
|
|
|
79 |
/**
|
|
|
80 |
* Remove the styling from the nav links.
|
|
|
81 |
*/
|
|
|
82 |
var removeDropZoneIndicator = function() {
|
|
|
83 |
root.find(SELECTORS.DROP_ZONE).removeClass(TARGET_CLASS);
|
|
|
84 |
};
|
|
|
85 |
|
|
|
86 |
/**
|
|
|
87 |
* Get the drop zone target from the event, if one is found.
|
|
|
88 |
*
|
|
|
89 |
* @param {event} e Javascript event
|
|
|
90 |
* @return {object|null}
|
|
|
91 |
*/
|
|
|
92 |
var getTargetFromEvent = function(e) {
|
|
|
93 |
var target = $(e.target).closest(SELECTORS.DROP_ZONE);
|
|
|
94 |
return (target.length) ? target : null;
|
|
|
95 |
};
|
|
|
96 |
|
|
|
97 |
/**
|
|
|
98 |
* This will add a visual indicator to the calendar UI to
|
|
|
99 |
* indicate which nav link is a valid drop zone.
|
|
|
100 |
*
|
|
|
101 |
* @param {Event} e
|
|
|
102 |
*/
|
|
|
103 |
var dragstartHandler = function(e) {
|
|
|
104 |
// Make sure the drag event is for a calendar event.
|
|
|
105 |
var eventElement = $(e.target).closest(SELECTORS.DRAGGABLE);
|
|
|
106 |
|
|
|
107 |
if (eventElement.length) {
|
|
|
108 |
addDropZoneIndicator();
|
|
|
109 |
}
|
|
|
110 |
};
|
|
|
111 |
|
|
|
112 |
/**
|
|
|
113 |
* Update the hover state of the target nav element when
|
|
|
114 |
* the user is dragging an event over it.
|
|
|
115 |
*
|
|
|
116 |
* This will add a visual indicator to the calendar UI to
|
|
|
117 |
* indicate which nav link is being hovered.
|
|
|
118 |
*
|
|
|
119 |
* @param {event} e The dragover event
|
|
|
120 |
*/
|
|
|
121 |
var dragoverHandler = function(e) {
|
|
|
122 |
// Ignore dragging of non calendar events.
|
|
|
123 |
if (!DataStore.hasEventId()) {
|
|
|
124 |
return;
|
|
|
125 |
}
|
|
|
126 |
|
|
|
127 |
e.preventDefault();
|
|
|
128 |
var target = getTargetFromEvent(e);
|
|
|
129 |
|
|
|
130 |
if (!target) {
|
|
|
131 |
return;
|
|
|
132 |
}
|
|
|
133 |
|
|
|
134 |
// If we're not draggin a calendar event then
|
|
|
135 |
// ignore it.
|
|
|
136 |
if (!DataStore.hasEventId()) {
|
|
|
137 |
return;
|
|
|
138 |
}
|
|
|
139 |
|
|
|
140 |
if (!hoverTimer) {
|
|
|
141 |
hoverTimer = setTimeout(function() {
|
|
|
142 |
target.click();
|
|
|
143 |
hoverTimer = null;
|
|
|
144 |
}, HOVER_TIME);
|
|
|
145 |
}
|
|
|
146 |
|
|
|
147 |
updateHoverState(target, true);
|
|
|
148 |
removeDropZoneIndicator();
|
|
|
149 |
};
|
|
|
150 |
|
|
|
151 |
/**
|
|
|
152 |
* Update the hover state of the target nav element that was
|
|
|
153 |
* previously dragged over but has is no longer a drag target.
|
|
|
154 |
*
|
|
|
155 |
* This will remove the visual indicator from the calendar UI
|
|
|
156 |
* that was added by the dragoverHandler.
|
|
|
157 |
*
|
|
|
158 |
* @param {event} e The dragstart event
|
|
|
159 |
*/
|
|
|
160 |
var dragleaveHandler = function(e) {
|
|
|
161 |
// Ignore dragging of non calendar events.
|
|
|
162 |
if (!DataStore.hasEventId()) {
|
|
|
163 |
return;
|
|
|
164 |
}
|
|
|
165 |
|
|
|
166 |
var target = getTargetFromEvent(e);
|
|
|
167 |
|
|
|
168 |
if (!target) {
|
|
|
169 |
return;
|
|
|
170 |
}
|
|
|
171 |
|
|
|
172 |
if (hoverTimer) {
|
|
|
173 |
clearTimeout(hoverTimer);
|
|
|
174 |
hoverTimer = null;
|
|
|
175 |
}
|
|
|
176 |
|
|
|
177 |
updateHoverState(target, false);
|
|
|
178 |
addDropZoneIndicator();
|
|
|
179 |
e.preventDefault();
|
|
|
180 |
};
|
|
|
181 |
|
|
|
182 |
/**
|
|
|
183 |
* Remove the visual indicator from the calendar UI that was
|
|
|
184 |
* added by the dragoverHandler.
|
|
|
185 |
*
|
|
|
186 |
* @param {event} e The drop event
|
|
|
187 |
*/
|
|
|
188 |
var dropHandler = function(e) {
|
|
|
189 |
// Ignore dragging of non calendar events.
|
|
|
190 |
if (!DataStore.hasEventId()) {
|
|
|
191 |
return;
|
|
|
192 |
}
|
|
|
193 |
|
|
|
194 |
removeDropZoneIndicator();
|
|
|
195 |
var target = getTargetFromEvent(e);
|
|
|
196 |
|
|
|
197 |
if (!target) {
|
|
|
198 |
return;
|
|
|
199 |
}
|
|
|
200 |
|
|
|
201 |
updateHoverState(target, false);
|
|
|
202 |
e.preventDefault();
|
|
|
203 |
};
|
|
|
204 |
|
|
|
205 |
return {
|
|
|
206 |
/**
|
|
|
207 |
* Initialise the event handlers for the drag events.
|
|
|
208 |
*
|
|
|
209 |
* @param {object} rootElement The element containing calendar nav links
|
|
|
210 |
*/
|
|
|
211 |
init: function(rootElement) {
|
|
|
212 |
// Only register the handlers once on the first load.
|
|
|
213 |
if (!registered) {
|
|
|
214 |
// These handlers are only added the first time the module
|
|
|
215 |
// is loaded because we don't want to have a new listener
|
|
|
216 |
// added each time the "init" function is called otherwise we'll
|
|
|
217 |
// end up with lots of stale handlers.
|
|
|
218 |
document.addEventListener('dragstart', dragstartHandler, false);
|
|
|
219 |
document.addEventListener('dragover', dragoverHandler, false);
|
|
|
220 |
document.addEventListener('dragleave', dragleaveHandler, false);
|
|
|
221 |
document.addEventListener('drop', dropHandler, false);
|
|
|
222 |
document.addEventListener('dragend', removeDropZoneIndicator, false);
|
|
|
223 |
registered = true;
|
|
|
224 |
}
|
|
|
225 |
|
|
|
226 |
// Update the module variable to operate on the given
|
|
|
227 |
// root element.
|
|
|
228 |
root = $(rootElement);
|
|
|
229 |
|
|
|
230 |
// If we're currently dragging then add the indicators.
|
|
|
231 |
if (DataStore.hasEventId()) {
|
|
|
232 |
addDropZoneIndicator();
|
|
|
233 |
}
|
|
|
234 |
},
|
|
|
235 |
};
|
|
|
236 |
});
|