mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 06:18:28 +01:00
Merge branch 'MDL-59394-master-2' of git://github.com/ryanwyllie/moodle
This commit is contained in:
commit
8c2465eaf0
2
calendar/amd/build/calendar.min.js
vendored
2
calendar/amd/build/calendar.min.js
vendored
@ -1 +1 @@
|
||||
define(["jquery","core/ajax","core/str","core/templates","core/notification","core/custom_interaction_events","core/modal_events","core/modal_factory","core_calendar/modal_event_form","core_calendar/summary_modal","core_calendar/repository","core_calendar/events","core_calendar/view_manager"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){var n={ROOT:"[data-region='calendar']",DAY:"[data-region='day']",EVENT_ITEM:"[data-region='event-item']",EVENT_LINK:"[data-action='view-event']",NEW_EVENT_BUTTON:"[data-action='new-event-button']",DAY_CONTENT:"[data-region='day-content']",LOADING_ICON:".loading-icon",VIEW_DAY_LINK:"[data-action='view-day-link']"},o=function(a){var b="type"+a;return c.get_string(b,"core_calendar").then(function(a){return a})},p=function(a){return c.get_string("subsource","core_calendar",a).then(function(b){return a.url?'<a href="'+a.url+'">'+b+"</a>":b})},q=function(b){k.getEventById(b).then(function(c){if(!c.event)throw new Error("Error encountered while trying to fetch calendar event with ID: "+b);var d=c.event,e=o(d.eventtype);if(d.displayeventsource){d.subscription=JSON.parse(d.subscription);var f={url:d.subscription.url,name:d.subscription.name},g=p(f);return a.when(e,g).then(function(a,b){return d.eventtype=a,d.source=b,d})}return e.then(function(a){return d.eventtype=a,d})}).then(function(a){var b={title:a.name,type:j.TYPE,body:d.render("core_calendar/event_summary_body",a),templateContext:{canedit:a.canedit,candelete:a.candelete}};return h.create(b)}).done(function(a){a.getRoot().on(g.hidden,function(){a.destroy()}),a.show()}).fail(e.exception)},r=function(b,c,f,g){var h=c.attr("data-event-id"),i=f.attr("data-day-timestamp"),j=g.attr("data-day-timestamp");i!=j&&d.render("core/loading",{}).then(function(a,b){f.find(n.DAY_CONTENT).addClass("hidden"),g.find(n.DAY_CONTENT).addClass("hidden"),d.appendNodeContents(f,a,b),d.appendNodeContents(g,a,b)}).then(function(){return k.updateEventStartDay(h,j)}).then(function(){a("body").trigger(l.eventMoved,[c,f,g])}).always(function(){var a=f.find(n.LOADING_ICON),b=g.find(n.LOADING_ICON);f.find(n.DAY_CONTENT).removeClass("hidden"),g.find(n.DAY_CONTENT).removeClass("hidden"),d.replaceNode(a,"",""),d.replaceNode(b,"","")}).fail(e.exception)},s=function(a){var b=a.find(n.NEW_EVENT_BUTTON),c=b.attr("data-context-id");return h.create({type:i.TYPE,large:!0,templateContext:{contextid:c}},[a,n.NEW_EVENT_BUTTON])},t=function(b,c){var d=a("body");d.on(l.created,function(){m.reloadCurrentMonth(b)}),d.on(l.deleted,function(){m.reloadCurrentMonth(b)}),d.on(l.updated,function(){m.reloadCurrentMonth(b)}),d.on(l.editActionEvent,function(a,b){window.location.assign(b)}),d.on(l.moveEvent,r),d.on(l.eventMoved,function(){window.location.reload()}),c.then(function(a){d.on(l.editEvent,function(b,c){a.setEventId(c),a.show()})})},u=function(){var b=a(n.ROOT);b.on("click",n.EVENT_ITEM,function(b){b.preventDefault(),b.stopPropagation();var c=a(b.target),d=null;d=c.is(n.EVENT_LINK)?c.attr("data-event-id"):c.find(n.EVENT_LINK).attr("data-event-id"),q(d)});var c=s(b);t(b,c),b.on("click",n.DAY,function(b){var d=a(b.target);if(!d.is(n.VIEW_DAY_LINK)){var e=a(this).attr("data-new-event-timestamp");c.then(function(a){a.setStartTime(e),a.show()}),b.preventDefault()}})};return{init:function(){m.init(),u()}}});
|
||||
define(["jquery","core/ajax","core/str","core/templates","core/notification","core/custom_interaction_events","core/modal_events","core/modal_factory","core_calendar/modal_event_form","core_calendar/summary_modal","core_calendar/repository","core_calendar/events","core_calendar/view_manager"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){var n={ROOT:"[data-region='calendar']",DAY:"[data-region='day']",EVENT_ITEM:"[data-region='event-item']",EVENT_LINK:"[data-action='view-event']",NEW_EVENT_BUTTON:"[data-action='new-event-button']",DAY_CONTENT:"[data-region='day-content']",LOADING_ICON:".loading-icon",VIEW_DAY_LINK:"[data-action='view-day-link']"},o=function(a){var b="type"+a;return c.get_string(b,"core_calendar").then(function(a){return a})},p=function(a){return c.get_string("subsource","core_calendar",a).then(function(b){return a.url?'<a href="'+a.url+'">'+b+"</a>":b})},q=function(b){k.getEventById(b).then(function(c){if(!c.event)throw new Error("Error encountered while trying to fetch calendar event with ID: "+b);var d=c.event,e=o(d.eventtype);if(d.displayeventsource){d.subscription=JSON.parse(d.subscription);var f={url:d.subscription.url,name:d.subscription.name},g=p(f);return a.when(e,g).then(function(a,b){return d.eventtype=a,d.source=b,d})}return e.then(function(a){return d.eventtype=a,d})}).then(function(a){var b={title:a.name,type:j.TYPE,body:d.render("core_calendar/event_summary_body",a),templateContext:{canedit:a.canedit,candelete:a.candelete}};return h.create(b)}).done(function(a){a.getRoot().on(g.hidden,function(){a.destroy()}),a.show()}).fail(e.exception)},r=function(b,c,f,g){var h=null,i=g.attr("data-day-timestamp");f&&(h=f.attr("data-day-timestamp")),f&&h==i||d.render("core/loading",{}).then(function(a,b){g.find(n.DAY_CONTENT).addClass("hidden"),d.appendNodeContents(g,a,b),f&&(f.find(n.DAY_CONTENT).addClass("hidden"),d.appendNodeContents(f,a,b))}).then(function(){return k.updateEventStartDay(c,i)}).then(function(){a("body").trigger(l.eventMoved,[c,f,g])}).always(function(){var a=g.find(n.LOADING_ICON);if(g.find(n.DAY_CONTENT).removeClass("hidden"),d.replaceNode(a,"",""),f){var b=f.find(n.LOADING_ICON);f.find(n.DAY_CONTENT).removeClass("hidden"),d.replaceNode(b,"","")}}).fail(e.exception)},s=function(a){var b=a.find(n.NEW_EVENT_BUTTON),c=b.attr("data-context-id");return h.create({type:i.TYPE,large:!0,templateContext:{contextid:c}},[a,n.NEW_EVENT_BUTTON])},t=function(b,c){var d=a("body");d.on(l.created,function(){m.reloadCurrentMonth(b)}),d.on(l.deleted,function(){m.reloadCurrentMonth(b)}),d.on(l.updated,function(){m.reloadCurrentMonth(b)}),d.on(l.editActionEvent,function(a,b){window.location.assign(b)}),d.on(l.moveEvent,r),d.on(l.eventMoved,function(){m.reloadCurrentMonth(b)}),c.then(function(a){d.on(l.editEvent,function(b,c){a.setEventId(c),a.show()})})},u=function(){var b=a(n.ROOT);b.on("click",n.EVENT_ITEM,function(b){b.preventDefault(),b.stopPropagation();var c=a(b.target),d=null;d=c.is(n.EVENT_LINK)?c.attr("data-event-id"):c.find(n.EVENT_LINK).attr("data-event-id"),q(d)});var c=s(b);t(b,c),b.on("click",n.DAY,function(b){var d=a(b.target);if(!d.is(n.VIEW_DAY_LINK)){var e=a(this).attr("data-new-event-timestamp");c.then(function(a){a.setStartTime(e),a.show()}),b.preventDefault()}})};return{init:function(){m.init(),u()}}});
|
1
calendar/amd/build/drag_drop.min.js
vendored
1
calendar/amd/build/drag_drop.min.js
vendored
@ -1 +0,0 @@
|
||||
define(["jquery","core_calendar/events"],function(a,b){var c={ROOT:"[data-region='calendar']",DRAGGABLE:'[draggable="true"]',DROP_ZONE:'[data-drop-zone="true"]',WEEK:'[data-region="month-view-week"]'},d="bg-primary",e=null,f=null,g=function(b,e,h){var i=a(b).closest(c.DROP_ZONE);if("undefined"==typeof h&&(h=f),e?i.addClass(d):i.removeClass(d),h--,h>0){var j=i.next();if(!j.length){var k=i.closest(c.WEEK).next();k.length&&(j=k.children(c.DROP_ZONE).first())}j.length&&g(j,e,h)}},h=function(b){var d=a(b.target);d.is("[data-event-id]")||(d=d.find("[data-event-id]")),e=d.attr("data-event-id");var g=c.ROOT+' [data-event-id="'+e+'"]';f=a(g).length,b.dataTransfer.effectAllowed="move",b.dataTransfer.dropEffect="move",b.dataTransfer.setData("text/plain",e),b.dropEffect="move"},i=function(a){a.preventDefault(),g(a.target,!0)},j=function(a){a.preventDefault(),g(a.target,!1)},k=function(d){d.preventDefault();var f=c.ROOT+' [data-event-id="'+e+'"]',h=a(f),i=h.closest(c.DROP_ZONE),j=a(d.target).closest(c.DROP_ZONE);g(d.target,!1),a("body").trigger(b.moveEvent,[h,i,j])};return{init:function(b){b=a(b),b.find(c.DRAGGABLE).each(function(a,b){b.addEventListener("dragstart",h,!0)}),b.find(c.DROP_ZONE).each(function(a,b){b.addEventListener("dragover",i,!0),b.addEventListener("dragleave",j,!0),b.addEventListener("drop",k,!0)})}}});
|
1
calendar/amd/build/drag_drop_data_store.min.js
vendored
Normal file
1
calendar/amd/build/drag_drop_data_store.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
define([],function(){var a=null,b=null,c=function(b){a=b},d=function(){return a},e=function(){return null!==a},f=function(a){b=a},g=function(){return b},h=function(){c(null),f(null)};return{setEventId:c,getEventId:d,hasEventId:e,setDurationDays:f,getDurationDays:g,clearAll:h}});
|
1
calendar/amd/build/month_navigation_drag_drop.min.js
vendored
Normal file
1
calendar/amd/build/month_navigation_drag_drop.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
define(["jquery","core_calendar/drag_drop_data_store"],function(a,b){var c={DRAGGABLE:'[draggable="true"][data-region="event-item"]',DROP_ZONE:'[data-drop-zone="nav-link"]'},d="bg-primary text-white",e="drop-target",f=1e3,g=!1,h=null,i=null,j=function(a,b){b?a.addClass(d):a.removeClass(d)},k=function(){i.find(c.DROP_ZONE).addClass(e)},l=function(){i.find(c.DROP_ZONE).removeClass(e)},m=function(b){var d=a(b.target).closest(c.DROP_ZONE);return d.length?d:null},n=function(b){var d=a(b.target).closest(c.DRAGGABLE);d.length&&k()},o=function(a){a.preventDefault();var c=m(a);c&&b.hasEventId()&&(h||(h=setTimeout(function(){c.click(),h=null},f)),j(c,!0),l())},p=function(a){var b=m(a);b&&(h&&(clearTimeout(h),h=null),j(b,!1),k(),a.preventDefault())},q=function(a){l();var b=m(a);b&&(j(b,!1),a.preventDefault())};return{init:function(c){g||(document.addEventListener("dragstart",n,!1),document.addEventListener("dragover",o,!1),document.addEventListener("dragleave",p,!1),document.addEventListener("drop",q,!1),document.addEventListener("dragend",l,!1),g=!0),i=a(c),b.hasEventId()&&k()}}});
|
1
calendar/amd/build/month_view_drag_drop.min.js
vendored
Normal file
1
calendar/amd/build/month_view_drag_drop.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
define(["jquery","core_calendar/events","core_calendar/drag_drop_data_store"],function(a,b,c){var d={ROOT:"[data-region='calendar']",DRAGGABLE:'[draggable="true"][data-region="event-item"]',DROP_ZONE:'[data-drop-zone="month-view-day"]',WEEK:'[data-region="month-view-week"]'},e="bg-primary text-white",f=!1,g=function(b){var c=a(b.target).closest(d.DROP_ZONE);return c.length?c:null},h=function(a,b,f){if("undefined"==typeof f&&(f=c.getDurationDays()),b?a.addClass(e):a.removeClass(e),f--,f>0){var g=a.next();if(!g.length){var i=a.closest(d.WEEK).next();i.length&&(g=i.children(d.DROP_ZONE).first())}g.length&&h(g,b,f)}},i=function(b){var e=a(b.target).closest(d.DRAGGABLE);if(e.length){e=e.find("[data-event-id]");var f=e.attr("data-event-id"),g=d.ROOT+' [data-event-id="'+f+'"]',h=a(g).length;c.setEventId(f),c.setDurationDays(h),b.dataTransfer.effectAllowed="move",b.dataTransfer.dropEffect="move",b.dataTransfer.setData("text/plain",f),b.dropEffect="move"}},j=function(a){a.preventDefault();var b=g(a);b&&h(b,!0)},k=function(a){var b=g(a);b&&(h(b,!1),a.preventDefault())},l=function(e){var f=g(e);if(!f)return void c.clearAll();var i=c.getEventId(),j=d.ROOT+' [data-event-id="'+i+'"]',k=a(j),l=null,m=a(e.target).closest(d.DROP_ZONE);k.length&&(l=k.closest(d.DROP_ZONE)),h(f,!1),a("body").trigger(b.moveEvent,[i,l,m]),c.clearAll(),e.preventDefault()};return{init:function(){f||(document.addEventListener("dragstart",i,!1),document.addEventListener("dragover",j,!1),document.addEventListener("dragleave",k,!1),document.addEventListener("drop",l,!1),f=!0)}}});
|
@ -168,24 +168,30 @@ define([
|
||||
* updated.
|
||||
*
|
||||
* @param {event} e The calendar move event
|
||||
* @param {object} eventElement The jQuery element with the event id
|
||||
* @param {object} originElement The jQuery element for where the event is moving from
|
||||
* @param {int} eventId The event id being moved
|
||||
* @param {object|null} originElement The jQuery element for where the event is moving from
|
||||
* @param {object} destinationElement The jQuery element for where the event is moving to
|
||||
*/
|
||||
var handleMoveEvent = function(e, eventElement, originElement, destinationElement) {
|
||||
var eventId = eventElement.attr('data-event-id');
|
||||
var originTimestamp = originElement.attr('data-day-timestamp');
|
||||
var handleMoveEvent = function(e, eventId, originElement, destinationElement) {
|
||||
var originTimestamp = null;
|
||||
var destinationTimestamp = destinationElement.attr('data-day-timestamp');
|
||||
|
||||
if (originElement) {
|
||||
originTimestamp = originElement.attr('data-day-timestamp');
|
||||
}
|
||||
|
||||
// If the event has actually changed day.
|
||||
if (originTimestamp != destinationTimestamp) {
|
||||
if (!originElement || originTimestamp != destinationTimestamp) {
|
||||
Templates.render('core/loading', {})
|
||||
.then(function(html, js) {
|
||||
// First we show some loading icons in each of the days being affected.
|
||||
originElement.find(SELECTORS.DAY_CONTENT).addClass('hidden');
|
||||
destinationElement.find(SELECTORS.DAY_CONTENT).addClass('hidden');
|
||||
Templates.appendNodeContents(originElement, html, js);
|
||||
Templates.appendNodeContents(destinationElement, html, js);
|
||||
|
||||
if (originElement) {
|
||||
originElement.find(SELECTORS.DAY_CONTENT).addClass('hidden');
|
||||
Templates.appendNodeContents(originElement, html, js);
|
||||
}
|
||||
return;
|
||||
})
|
||||
.then(function() {
|
||||
@ -195,19 +201,21 @@ define([
|
||||
.then(function() {
|
||||
// If the update was successful then broadcast an event letting the calendar
|
||||
// know that an event has been moved.
|
||||
$('body').trigger(CalendarEvents.eventMoved, [eventElement, originElement, destinationElement]);
|
||||
$('body').trigger(CalendarEvents.eventMoved, [eventId, originElement, destinationElement]);
|
||||
return;
|
||||
})
|
||||
.always(function() {
|
||||
// Always remove the loading icons regardless of whether the update
|
||||
// request was successful or not.
|
||||
var originLoadingElement = originElement.find(SELECTORS.LOADING_ICON);
|
||||
var destinationLoadingElement = destinationElement.find(SELECTORS.LOADING_ICON);
|
||||
originElement.find(SELECTORS.DAY_CONTENT).removeClass('hidden');
|
||||
destinationElement.find(SELECTORS.DAY_CONTENT).removeClass('hidden');
|
||||
|
||||
Templates.replaceNode(originLoadingElement, '', '');
|
||||
Templates.replaceNode(destinationLoadingElement, '', '');
|
||||
|
||||
if (originElement) {
|
||||
var originLoadingElement = originElement.find(SELECTORS.LOADING_ICON);
|
||||
originElement.find(SELECTORS.DAY_CONTENT).removeClass('hidden');
|
||||
Templates.replaceNode(originLoadingElement, '', '');
|
||||
}
|
||||
return;
|
||||
})
|
||||
.fail(Notification.exception);
|
||||
@ -265,7 +273,7 @@ define([
|
||||
body.on(CalendarEvents.moveEvent, handleMoveEvent);
|
||||
// When an event is successfully moved we should updated the UI.
|
||||
body.on(CalendarEvents.eventMoved, function() {
|
||||
window.location.reload();
|
||||
CalendarViewManager.reloadCurrentMonth(root);
|
||||
});
|
||||
|
||||
eventFormModalPromise.then(function(modal) {
|
||||
|
95
calendar/amd/src/drag_drop_data_store.js
Normal file
95
calendar/amd/src/drag_drop_data_store.js
Normal file
@ -0,0 +1,95 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A javascript module to store calendar drag and drop data.
|
||||
*
|
||||
* This module is unfortunately required because of the limitations
|
||||
* of the HTML5 drag and drop API and it's ability to provide data
|
||||
* between the different stages of the drag/drop lifecycle.
|
||||
*
|
||||
* @module core_calendar/drag_drop_data_store
|
||||
* @package core_calendar
|
||||
* @copyright 2017 Ryan Wyllie <ryan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define([], function() {
|
||||
/* @var {int|null} eventId The id of the event being dragged */
|
||||
var eventId = null;
|
||||
/* @var {int|null} durationDays How many days the event spans */
|
||||
var durationDays = null;
|
||||
|
||||
/**
|
||||
* Store the id of the event being dragged.
|
||||
*
|
||||
* @param {int} id The event id
|
||||
*/
|
||||
var setEventId = function(id) {
|
||||
eventId = id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the stored event id.
|
||||
*
|
||||
* @return {int|null}
|
||||
*/
|
||||
var getEventId = function() {
|
||||
return eventId;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the store has an event id.
|
||||
*
|
||||
* @return {bool}
|
||||
*/
|
||||
var hasEventId = function() {
|
||||
return eventId !== null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Store the duration (in days) of the event being dragged.
|
||||
*
|
||||
* @param {int} days Number of days the event spans
|
||||
*/
|
||||
var setDurationDays = function(days) {
|
||||
durationDays = days;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the stored number of days.
|
||||
*
|
||||
* @return {int|null}
|
||||
*/
|
||||
var getDurationDays = function() {
|
||||
return durationDays;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset all of the stored values.
|
||||
*/
|
||||
var clearAll = function() {
|
||||
setEventId(null);
|
||||
setDurationDays(null);
|
||||
};
|
||||
|
||||
return {
|
||||
setEventId: setEventId,
|
||||
getEventId: getEventId,
|
||||
hasEventId: hasEventId,
|
||||
setDurationDays: setDurationDays,
|
||||
getDurationDays: getDurationDays,
|
||||
clearAll: clearAll
|
||||
};
|
||||
});
|
221
calendar/amd/src/month_navigation_drag_drop.js
Normal file
221
calendar/amd/src/month_navigation_drag_drop.js
Normal file
@ -0,0 +1,221 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A javascript module to handle calendar drag and drop in the calendar
|
||||
* month view navigation.
|
||||
*
|
||||
* This code is run each time the calendar month view is re-rendered. We
|
||||
* only register the event handlers once per page load so that the in place
|
||||
* DOM updates that happen on month change don't continue to register handlers.
|
||||
*
|
||||
* @module core_calendar/month_navigation_drag_drop
|
||||
* @class month_navigation_drag_drop
|
||||
* @package core_calendar
|
||||
* @copyright 2017 Ryan Wyllie <ryan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define([
|
||||
'jquery',
|
||||
'core_calendar/drag_drop_data_store',
|
||||
],
|
||||
function(
|
||||
$,
|
||||
DataStore
|
||||
) {
|
||||
|
||||
var SELECTORS = {
|
||||
DRAGGABLE: '[draggable="true"][data-region="event-item"]',
|
||||
DROP_ZONE: '[data-drop-zone="nav-link"]',
|
||||
};
|
||||
var HOVER_CLASS = 'bg-primary text-white';
|
||||
var TARGET_CLASS = 'drop-target';
|
||||
var HOVER_TIME = 1000; // 1 second hover to change month.
|
||||
|
||||
// We store some static variables at the module level because this
|
||||
// module is called each time the calendar month view is reloaded but
|
||||
// we want some actions to only occur ones.
|
||||
|
||||
/* @var {bool} registered If the event listeners have been added */
|
||||
var registered = false;
|
||||
/* @var {int} hoverTimer The timeout id of any timeout waiting for hover */
|
||||
var hoverTimer = null;
|
||||
/* @var {object} root The root nav element we're operating on */
|
||||
var root = null;
|
||||
|
||||
/**
|
||||
* Add or remove the appropriate styling to indicate whether
|
||||
* the drop target is being hovered over.
|
||||
*
|
||||
* @param {object} target The target drop zone element
|
||||
* @param {bool} hovered If the element is hovered over ot not
|
||||
*/
|
||||
var updateHoverState = function(target, hovered) {
|
||||
if (hovered) {
|
||||
target.addClass(HOVER_CLASS);
|
||||
} else {
|
||||
target.removeClass(HOVER_CLASS);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add some styling to the UI to indicate that the nav links
|
||||
* are an acceptable drop target.
|
||||
*/
|
||||
var addDropZoneIndicator = function() {
|
||||
root.find(SELECTORS.DROP_ZONE).addClass(TARGET_CLASS);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the styling from the nav links.
|
||||
*/
|
||||
var removeDropZoneIndicator = function() {
|
||||
root.find(SELECTORS.DROP_ZONE).removeClass(TARGET_CLASS);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the drop zone target from the event, if one is found.
|
||||
*
|
||||
* @param {event} e Javascript event
|
||||
* @return {object|null}
|
||||
*/
|
||||
var getTargetFromEvent = function(e) {
|
||||
var target = $(e.target).closest(SELECTORS.DROP_ZONE);
|
||||
return (target.length) ? target : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* This will add a visual indicator to the calendar UI to
|
||||
* indicate which nav link is a valid drop zone.
|
||||
*/
|
||||
var dragstartHandler = function(e) {
|
||||
// Make sure the drag event is for a calendar event.
|
||||
var eventElement = $(e.target).closest(SELECTORS.DRAGGABLE);
|
||||
|
||||
if (eventElement.length) {
|
||||
addDropZoneIndicator();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the hover state of the target nav element when
|
||||
* the user is dragging an event over it.
|
||||
*
|
||||
* This will add a visual indicator to the calendar UI to
|
||||
* indicate which nav link is being hovered.
|
||||
*
|
||||
* @param {event} e The dragover event
|
||||
*/
|
||||
var dragoverHandler = function(e) {
|
||||
e.preventDefault();
|
||||
var target = getTargetFromEvent(e);
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're not draggin a calendar event then
|
||||
// ignore it.
|
||||
if (!DataStore.hasEventId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hoverTimer) {
|
||||
hoverTimer = setTimeout(function() {
|
||||
target.click();
|
||||
hoverTimer = null;
|
||||
}, HOVER_TIME);
|
||||
}
|
||||
|
||||
updateHoverState(target, true);
|
||||
removeDropZoneIndicator();
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the hover state of the target nav element that was
|
||||
* previously dragged over but has is no longer a drag target.
|
||||
*
|
||||
* This will remove the visual indicator from the calendar UI
|
||||
* that was added by the dragoverHandler.
|
||||
*
|
||||
* @param {event} e The dragstart event
|
||||
*/
|
||||
var dragleaveHandler = function(e) {
|
||||
var target = getTargetFromEvent(e);
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hoverTimer) {
|
||||
clearTimeout(hoverTimer);
|
||||
hoverTimer = null;
|
||||
}
|
||||
|
||||
updateHoverState(target, false);
|
||||
addDropZoneIndicator();
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the visual indicator from the calendar UI that was
|
||||
* added by the dragoverHandler.
|
||||
*
|
||||
* @param {event} e The drop event
|
||||
*/
|
||||
var dropHandler = function(e) {
|
||||
removeDropZoneIndicator();
|
||||
var target = getTargetFromEvent(e);
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateHoverState(target, false);
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
return {
|
||||
/**
|
||||
* Initialise the event handlers for the drag events.
|
||||
*
|
||||
* @param {object} rootElement The element containing calendar nav links
|
||||
*/
|
||||
init: function(rootElement) {
|
||||
// Only register the handlers once on the first load.
|
||||
if (!registered) {
|
||||
// These handlers are only added the first time the module
|
||||
// is loaded because we don't want to have a new listener
|
||||
// added each time the "init" function is called otherwise we'll
|
||||
// end up with lots of stale handlers.
|
||||
document.addEventListener('dragstart', dragstartHandler, false);
|
||||
document.addEventListener('dragover', dragoverHandler, false);
|
||||
document.addEventListener('dragleave', dragleaveHandler, false);
|
||||
document.addEventListener('drop', dropHandler, false);
|
||||
document.addEventListener('dragend', removeDropZoneIndicator, false);
|
||||
registered = true;
|
||||
}
|
||||
|
||||
// Update the module variable to operate on the given
|
||||
// root element.
|
||||
root = $(rootElement);
|
||||
|
||||
// If we're currently dragging then add the indicators.
|
||||
if (DataStore.hasEventId()) {
|
||||
addDropZoneIndicator();
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
@ -14,44 +14,47 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A javascript module to handle calendar drag and drop. This module
|
||||
* unfortunately requires some state to be maintained because of the
|
||||
* limitations of the HTML5 drag and drop API which means it can't
|
||||
* be used multiple times with the current implementation.
|
||||
* A javascript module to handle calendar drag and drop in the calendar
|
||||
* month view.
|
||||
*
|
||||
* @module core_calendar/drag_drop
|
||||
* @class drag_drop
|
||||
* @module core_calendar/month_view_drag_drop
|
||||
* @class month_view_drag_drop
|
||||
* @package core_calendar
|
||||
* @copyright 2017 Ryan Wyllie <ryan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define([
|
||||
'jquery',
|
||||
'core_calendar/events'
|
||||
'core_calendar/events',
|
||||
'core_calendar/drag_drop_data_store'
|
||||
],
|
||||
function(
|
||||
$,
|
||||
CalendarEvents
|
||||
CalendarEvents,
|
||||
DataStore
|
||||
) {
|
||||
|
||||
var SELECTORS = {
|
||||
ROOT: "[data-region='calendar']",
|
||||
DRAGGABLE: '[draggable="true"]',
|
||||
DROP_ZONE: '[data-drop-zone="true"]',
|
||||
DRAGGABLE: '[draggable="true"][data-region="event-item"]',
|
||||
DROP_ZONE: '[data-drop-zone="month-view-day"]',
|
||||
WEEK: '[data-region="month-view-week"]',
|
||||
};
|
||||
var HOVER_CLASS = 'bg-primary';
|
||||
var HOVER_CLASS = 'bg-primary text-white';
|
||||
/* @var {bool} registered If the event listeners have been added */
|
||||
var registered = false;
|
||||
|
||||
// Unfortunately we are required to maintain some module
|
||||
// level state due to the limitations of the HTML5 drag
|
||||
// and drop API. Specifically the inability to pass data
|
||||
// between the dragstate and dragover events handlers
|
||||
// using the DataTransfer object in the event.
|
||||
|
||||
/** @var int eventId The event id being moved. */
|
||||
var eventId = null;
|
||||
/** @var int duration The number of days the event spans */
|
||||
var duration = null;
|
||||
/**
|
||||
* Get the correct drop zone element from the given javascript
|
||||
* event.
|
||||
*
|
||||
* @param {event} e The javascript event
|
||||
* @return {object|null}
|
||||
*/
|
||||
var getDropZoneFromEvent = function(e) {
|
||||
var dropZone = $(e.target).closest(SELECTORS.DROP_ZONE);
|
||||
return (dropZone.length) ? dropZone : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the hover state for the event in the calendar to reflect
|
||||
@ -70,11 +73,10 @@ define([
|
||||
* @param {bool} hovered If the target is hovered or not
|
||||
* @param {int} count How many days to highlight (default to duration)
|
||||
*/
|
||||
var updateHoverState = function(target, hovered, count) {
|
||||
var dropZone = $(target).closest(SELECTORS.DROP_ZONE);
|
||||
var updateHoverState = function(dropZone, hovered, count) {
|
||||
if (typeof count === 'undefined') {
|
||||
// This is how many days we need to highlight.
|
||||
count = duration;
|
||||
count = DataStore.getDurationDays();
|
||||
}
|
||||
|
||||
if (hovered) {
|
||||
@ -115,16 +117,20 @@ define([
|
||||
* @param {event} e The dragstart event
|
||||
*/
|
||||
var dragstartHandler = function(e) {
|
||||
var eventElement = $(e.target);
|
||||
var eventElement = $(e.target).closest(SELECTORS.DRAGGABLE);
|
||||
|
||||
if (!eventElement.is('[data-event-id]')) {
|
||||
eventElement = eventElement.find('[data-event-id]');
|
||||
if (!eventElement.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
eventId = eventElement.attr('data-event-id');
|
||||
eventElement = eventElement.find('[data-event-id]');
|
||||
|
||||
var eventId = eventElement.attr('data-event-id');
|
||||
var eventsSelector = SELECTORS.ROOT + ' [data-event-id="' + eventId + '"]';
|
||||
duration = $(eventsSelector).length;
|
||||
var duration = $(eventsSelector).length;
|
||||
|
||||
DataStore.setEventId(eventId);
|
||||
DataStore.setDurationDays(duration);
|
||||
|
||||
e.dataTransfer.effectAllowed = "move";
|
||||
e.dataTransfer.dropEffect = "move";
|
||||
@ -145,7 +151,14 @@ define([
|
||||
*/
|
||||
var dragoverHandler = function(e) {
|
||||
e.preventDefault();
|
||||
updateHoverState(e.target, true);
|
||||
|
||||
var dropZone = getDropZoneFromEvent(e);
|
||||
|
||||
if (!dropZone) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateHoverState(dropZone, true);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -158,8 +171,14 @@ define([
|
||||
* @param {event} e The dragstart event
|
||||
*/
|
||||
var dragleaveHandler = function(e) {
|
||||
var dropZone = getDropZoneFromEvent(e);
|
||||
|
||||
if (!dropZone) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateHoverState(dropZone, false);
|
||||
e.preventDefault();
|
||||
updateHoverState(e.target, false);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -174,35 +193,46 @@ define([
|
||||
* @param {event} e The dragstart event
|
||||
*/
|
||||
var dropHandler = function(e) {
|
||||
e.preventDefault();
|
||||
var dropZone = getDropZoneFromEvent(e);
|
||||
|
||||
if (!dropZone) {
|
||||
DataStore.clearAll();
|
||||
return;
|
||||
}
|
||||
|
||||
var eventId = DataStore.getEventId();
|
||||
var eventElementSelector = SELECTORS.ROOT + ' [data-event-id="' + eventId + '"]';
|
||||
var eventElement = $(eventElementSelector);
|
||||
var origin = eventElement.closest(SELECTORS.DROP_ZONE);
|
||||
var origin = null;
|
||||
var destination = $(e.target).closest(SELECTORS.DROP_ZONE);
|
||||
|
||||
updateHoverState(e.target, false);
|
||||
$('body').trigger(CalendarEvents.moveEvent, [eventElement, origin, destination]);
|
||||
if (eventElement.length) {
|
||||
origin = eventElement.closest(SELECTORS.DROP_ZONE);
|
||||
}
|
||||
|
||||
updateHoverState(dropZone, false);
|
||||
$('body').trigger(CalendarEvents.moveEvent, [eventId, origin, destination]);
|
||||
DataStore.clearAll();
|
||||
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
return {
|
||||
/**
|
||||
* Initialise the event handlers for the drag events.
|
||||
*
|
||||
* @param {object} root The root calendar element that containers the drag drop elements
|
||||
*/
|
||||
init: function(root) {
|
||||
root = $(root);
|
||||
|
||||
root.find(SELECTORS.DRAGGABLE).each(function(index, element) {
|
||||
element.addEventListener('dragstart', dragstartHandler, true);
|
||||
});
|
||||
|
||||
root.find(SELECTORS.DROP_ZONE).each(function(index, element) {
|
||||
element.addEventListener('dragover', dragoverHandler, true);
|
||||
element.addEventListener('dragleave', dragleaveHandler, true);
|
||||
element.addEventListener('drop', dropHandler, true);
|
||||
});
|
||||
init: function() {
|
||||
if (!registered) {
|
||||
// These handlers are only added the first time the module
|
||||
// is loaded because we don't want to have a new listener
|
||||
// added each time the "init" function is called otherwise we'll
|
||||
// end up with lots of stale handlers.
|
||||
document.addEventListener('dragstart', dragstartHandler, false);
|
||||
document.addEventListener('dragover', dragoverHandler, false);
|
||||
document.addEventListener('dragleave', dragleaveHandler, false);
|
||||
document.addEventListener('drop', dropHandler, false);
|
||||
registered = true;
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
@ -2175,6 +2175,7 @@ function calendar_get_link_previous($text, $linkbase, $d, $m, $y, $accesshide =
|
||||
|
||||
$attrs = [
|
||||
'data-time' => calendar_get_timestamp($d, $m, $y, $time),
|
||||
'data-drop-zone' => 'nav-link',
|
||||
];
|
||||
|
||||
return link_arrow_left($text, $href->out(false), $accesshide, 'previous', $attrs);
|
||||
@ -2202,6 +2203,7 @@ function calendar_get_link_next($text, $linkbase, $d, $m, $y, $accesshide = fals
|
||||
|
||||
$attrs = [
|
||||
'data-time' => calendar_get_timestamp($d, $m, $y, $time),
|
||||
'data-drop-zone' => 'nav-link',
|
||||
];
|
||||
|
||||
return link_arrow_right($text, $href->out(false), $accesshide, 'next', $attrs);
|
||||
|
@ -31,11 +31,11 @@
|
||||
{
|
||||
}
|
||||
}}
|
||||
<div id="month-detailed-{{uniqid}}" class="calendarwrapper" data-courseid="{{courseid}}" data-current-time="{{time}}">
|
||||
<div class="calendarwrapper" data-courseid="{{courseid}}" data-current-time="{{time}}">
|
||||
{{> core_calendar/month_header }}
|
||||
{{> core_calendar/month_navigation }}
|
||||
{{> core/overlay_loading}}
|
||||
<table class="calendarmonth calendartable card-deck m-b-0">
|
||||
<table id="month-detailed-{{uniqid}}" class="calendarmonth calendartable card-deck m-b-0">
|
||||
<thead>
|
||||
<tr>
|
||||
{{# daynames }}
|
||||
@ -59,7 +59,7 @@
|
||||
}}{{#durationevents}} duration_{{.}}{{/durationevents}}{{!
|
||||
}}"
|
||||
data-day-timestamp="{{timestamp}}"
|
||||
data-drop-zone="true"
|
||||
data-drop-zone="month-view-day"
|
||||
data-region="day"
|
||||
data-new-event-timestamp="{{neweventtimestamp}}">
|
||||
<div class="hidden-sm-down text-xs-center">
|
||||
@ -113,7 +113,7 @@
|
||||
</table>
|
||||
</div>
|
||||
{{#js}}
|
||||
require(['jquery', 'core_calendar/drag_drop'], function($, DragDrop) {
|
||||
require(['jquery', 'core_calendar/month_view_drag_drop'], function($, DragDrop) {
|
||||
var root = $('#month-detailed-{{uniqid}}');
|
||||
DragDrop.init(root);
|
||||
});
|
||||
|
@ -32,7 +32,13 @@
|
||||
}
|
||||
}}
|
||||
{{#navigation}}
|
||||
<div class="controls" data-view="{{view}}">
|
||||
<div id="month-navigation-{{uniqid}}" class="controls" data-view="{{view}}">
|
||||
{{{navigation}}}
|
||||
</div>
|
||||
{{/navigation}}
|
||||
{{#js}}
|
||||
require(['jquery', 'core_calendar/month_navigation_drag_drop'], function($, DragDrop) {
|
||||
var root = $('#month-navigation-{{uniqid}}');
|
||||
DragDrop.init(root);
|
||||
});
|
||||
{{/js}}
|
||||
|
@ -48,6 +48,7 @@ $calendarEventUserColor: #dce7ec !default; // Pale blue.
|
||||
|
||||
.previous {
|
||||
text-align: left;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.current {
|
||||
@ -57,6 +58,12 @@ $calendarEventUserColor: #dce7ec !default; // Pale blue.
|
||||
|
||||
.next {
|
||||
text-align: right;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.drop-target {
|
||||
box-sizing: border-box;
|
||||
border: 1px dashed $brand-primary;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,3 +254,46 @@
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.text-white {
|
||||
color: @white;
|
||||
}
|
||||
|
||||
// Bg utilities.
|
||||
.bg {
|
||||
// Important (red)
|
||||
&-danger {
|
||||
background-color: @errorText;
|
||||
}
|
||||
&-danger[href] {
|
||||
background-color: darken(@errorText, 10%);
|
||||
}
|
||||
// Warnings (orange)
|
||||
&-warning {
|
||||
background-color: @orange;
|
||||
}
|
||||
&-warning[href] {
|
||||
background-color: darken(@orange, 10%);
|
||||
}
|
||||
// Success (green)
|
||||
&-success {
|
||||
background-color: @successText;
|
||||
}
|
||||
&-success[href] {
|
||||
background-color: darken(@successText, 10%);
|
||||
}
|
||||
// Info (turquoise)
|
||||
&-info {
|
||||
background-color: @infoText;
|
||||
}
|
||||
&-info[href] {
|
||||
background-color: darken(@infoText, 10%);
|
||||
}
|
||||
// Primary (blue)
|
||||
&-primary {
|
||||
background-color: @blue;
|
||||
}
|
||||
&-primary[href] {
|
||||
background-color: darken(@blue, 10%);
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,8 @@
|
||||
}
|
||||
.previous {
|
||||
text-align: left;
|
||||
border: 1px solid transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.current {
|
||||
text-align: center;
|
||||
@ -49,6 +51,12 @@
|
||||
}
|
||||
.next {
|
||||
text-align: right;
|
||||
border: 1px solid transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.drop-target {
|
||||
box-sizing: border-box;
|
||||
border: 1px dashed @blue;
|
||||
}
|
||||
}
|
||||
.filters {
|
||||
|
@ -2407,3 +2407,7 @@ h3.sectionname .inplaceeditable.inplaceeditingon .editinstructions {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-drag-type="move"] {
|
||||
cursor: move;
|
||||
}
|
||||
|
@ -4795,6 +4795,9 @@ h3.sectionname .inplaceeditable.inplaceeditingon .editinstructions {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
[data-drag-type="move"] {
|
||||
cursor: move;
|
||||
}
|
||||
/* admin.less */
|
||||
.formtable tbody th {
|
||||
font-weight: normal;
|
||||
@ -5591,6 +5594,8 @@ img.iconsmall {
|
||||
}
|
||||
.path-calendar .calendar-controls .previous {
|
||||
text-align: left;
|
||||
border: 1px solid transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.path-calendar .calendar-controls .current {
|
||||
text-align: center;
|
||||
@ -5598,6 +5603,12 @@ img.iconsmall {
|
||||
}
|
||||
.path-calendar .calendar-controls .next {
|
||||
text-align: right;
|
||||
border: 1px solid transparent;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.path-calendar .calendar-controls .drop-target {
|
||||
box-sizing: border-box;
|
||||
border: 1px dashed #049cdb;
|
||||
}
|
||||
.path-calendar .filters table {
|
||||
border-collapse: separate;
|
||||
@ -21854,3 +21865,36 @@ ul.indented-list {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.text-white {
|
||||
color: #fff;
|
||||
}
|
||||
.bg-danger {
|
||||
background-color: #b94a48;
|
||||
}
|
||||
.bg-danger[href] {
|
||||
background-color: #953b39;
|
||||
}
|
||||
.bg-warning {
|
||||
background-color: #f89406;
|
||||
}
|
||||
.bg-warning[href] {
|
||||
background-color: #c67605;
|
||||
}
|
||||
.bg-success {
|
||||
background-color: #468847;
|
||||
}
|
||||
.bg-success[href] {
|
||||
background-color: #356635;
|
||||
}
|
||||
.bg-info {
|
||||
background-color: #3a87ad;
|
||||
}
|
||||
.bg-info[href] {
|
||||
background-color: #2d6987;
|
||||
}
|
||||
.bg-primary {
|
||||
background-color: #049cdb;
|
||||
}
|
||||
.bg-primary[href] {
|
||||
background-color: #0378a9;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user