MDL-59920 calendar: Allow user to choose if deleting one or all events

This commit is contained in:
Andrew Nicols 2017-09-12 15:46:18 +08:00
parent 91cbdda6af
commit 2dbfb484aa
12 changed files with 286 additions and 30 deletions

View File

@ -1 +1 @@
define([],function(){return{created:"calendar-events:created",deleted:"calendar-events:deleted",updated:"calendar-events:updated",editEvent:"calendar-events:edit_event",editActionEvent:"calendar-events:edit_action_event",eventMoved:"calendar-events:event_moved",monthChanged:"calendar-events:month_changed",moveEvent:"calendar-events:move_event",filterChanged:"calendar-events:filter_changed",viewUpdated:"calendar-events:view_updated"}});
define([],function(){return{created:"calendar-events:created",deleted:"calendar-events:deleted",deleteAll:"calendar-events:delete_all",updated:"calendar-events:updated",editEvent:"calendar-events:edit_event",editActionEvent:"calendar-events:edit_action_event",eventMoved:"calendar-events:event_moved",monthChanged:"calendar-events:month_changed",moveEvent:"calendar-events:move_event",filterChanged:"calendar-events:filter_changed",viewUpdated:"calendar-events:view_updated"}});

View File

@ -0,0 +1 @@
define(["jquery","core/notification","core/custom_interaction_events","core/modal","core/modal_events","core/modal_registry","core_calendar/events"],function(a,b,c,d,e,f,g){var h=!1,i={DELETE_ONE_BUTTON:'[data-action="deleteone"]',DELETE_ALL_BUTTON:'[data-action="deleteall"]',CANCEL_BUTTON:'[data-action="cancel"]'},j=function(a){d.call(this,a)};return j.TYPE="core_calendar-modal_delete",j.prototype=Object.create(d.prototype),j.prototype.constructor=j,j.prototype.registerEventListeners=function(){d.prototype.registerEventListeners.call(this),this.getModal().on(c.events.activate,i.DELETE_ONE_BUTTON,function(b,c){var d=a.Event(e.save);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this)),this.getModal().on(c.events.activate,i.DELETE_ALL_BUTTON,function(b,c){var d=a.Event(g.deleteAll);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this)),this.getModal().on(c.events.activate,i.CANCEL_BUTTON,function(b,c){var d=a.Event(e.cancel);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this))},h||(f.register(j.TYPE,j,"calendar/event_delete_modal"),h=!0),j});

View File

@ -1 +1 @@
define(["jquery","core/ajax"],function(a,b){var c=function(a){var c={methodname:"core_calendar_delete_calendar_events",args:{events:[{eventid:a,repeat:1}]}};return b.call([c])[0]},d=function(a){var c={methodname:"core_calendar_get_calendar_event_by_id",args:{eventid:a}};return b.call([c])[0]},e=function(a){var c={methodname:"core_calendar_submit_create_update_form",args:{formdata:a}};return b.call([c])[0]},f=function(a,c){var d={methodname:"core_calendar_get_calendar_monthly_view",args:{time:a,courseid:c}};return b.call([d])[0]},g=function(a,c){var d={methodname:"core_calendar_update_event_start_day",args:{eventid:a,daytimestamp:c}};return b.call([d])[0]};return{getEventById:d,deleteEvent:c,updateEventStartDay:g,submitCreateUpdateForm:e,getCalendarMonthData:f}});
define(["jquery","core/ajax"],function(a,b){var c=function(a,c){"undefined"==typeof c&&(c=!1);var d={methodname:"core_calendar_delete_calendar_events",args:{events:[{eventid:a,repeat:c}]}};return b.call([d])[0]},d=function(a){var c={methodname:"core_calendar_get_calendar_event_by_id",args:{eventid:a}};return b.call([c])[0]},e=function(a){var c={methodname:"core_calendar_submit_create_update_form",args:{formdata:a}};return b.call([c])[0]},f=function(a,c){var d={methodname:"core_calendar_get_calendar_monthly_view",args:{time:a,courseid:c}};return b.call([d])[0]},g=function(a,c){var d={methodname:"core_calendar_update_event_start_day",args:{eventid:a,daytimestamp:c}};return b.call([d])[0]};return{getEventById:d,deleteEvent:c,updateEventStartDay:g,submitCreateUpdateForm:e,getCalendarMonthData:f}});

View File

@ -1 +1 @@
define(["jquery","core/str","core/notification","core/custom_interaction_events","core/modal","core/modal_registry","core/modal_factory","core/modal_events","core_calendar/repository","core_calendar/events"],function(a,b,c,d,e,f,g,h,i,j){function k(d,e){var f=[{key:"deleteevent",component:"calendar"},{key:"confirmeventdelete",component:"calendar",param:e}],k=d.getEventId(),l=b.get_strings(f),m=g.create({type:g.types.SAVE_CANCEL},d.getDeleteButton());a.when(l,m).then(function(b,e){return e.setTitle(b[0]),e.setBody(b[1]),e.setSaveButtonText(b[0]),e.getRoot().on(h.save,function(){i.deleteEvent(k).then(function(){a("body").trigger(j.deleted,[k]),d.hide()})["catch"](c.exception)}),e}).fail(c.exception)}var l=!1,m={ROOT:"[data-region='summary-modal-container']",EDIT_BUTTON:'[data-action="edit"]',DELETE_BUTTON:'[data-action="delete"]'},n=function(a){e.call(this,a)};return n.TYPE="core_calendar-event_summary",n.prototype=Object.create(e.prototype),n.prototype.constructor=n,n.prototype.getEditButton=function(){return"undefined"==typeof this.editButton&&(this.editButton=this.getFooter().find(m.EDIT_BUTTON)),this.editButton},n.prototype.getDeleteButton=function(){return"undefined"==typeof this.deleteButton&&(this.deleteButton=this.getFooter().find(m.DELETE_BUTTON)),this.deleteButton},n.prototype.getEventId=function(){return this.getBody().find(m.ROOT).attr("data-event-id")},n.prototype.getEditUrl=function(){return this.getBody().find(m.ROOT).attr("data-edit-url")},n.prototype.isActionEvent=function(){return"true"==this.getBody().find(m.ROOT).attr("data-action-event")},n.prototype.registerEventListeners=function(){e.prototype.registerEventListeners.call(this),this.getRoot().on(h.bodyRendered,function(){var a=this.getBody().find(m.ROOT).attr("data-event-title");k(this,a)}.bind(this)),d.define(this.getEditButton(),[d.events.activate]),this.getEditButton().on(d.events.activate,function(b,c){this.isActionEvent()?a("body").trigger(j.editActionEvent,[this.getEditUrl()]):a("body").trigger(j.editEvent,[this.getEventId()]),this.hide(),b.preventDefault(),b.stopPropagation(),c.originalEvent.preventDefault(),c.originalEvent.stopPropagation()}.bind(this))},l||(f.register(n.TYPE,n,"core_calendar/event_summary_modal"),l=!0),n});
define(["jquery","core/str","core/notification","core/custom_interaction_events","core/modal","core/modal_registry","core/modal_factory","core/modal_events","core_calendar/repository","core_calendar/events","core_calendar/modal_delete"],function(a,b,c,d,e,f,g,h,i,j,k){function l(d,e){var f,l=[{key:"deleteevent",component:"calendar"}],m=parseInt(d.getEventCount(),10),n=m>1;n?(l.push({key:"confirmeventseriesdelete",component:"calendar",param:{name:e,count:m}}),f=g.create({type:k.TYPE},d.getDeleteButton())):(l.push({key:"confirmeventdelete",component:"calendar",param:e}),f=g.create({type:g.types.SAVE_CANCEL},d.getDeleteButton()));var o=d.getEventId(),p=b.get_strings(l);a.when(p,f).then(function(b,e){return e.setTitle(b[0]),e.setBody(b[1]),n||e.setSaveButtonText(b[0]),e.getRoot().on(h.save,function(){i.deleteEvent(o,!1).then(function(){a("body").trigger(j.deleted,[o,!1]),d.hide()})["catch"](c.exception)}),e.getRoot().on(j.deleteAll,function(){i.deleteEvent(o,!0).then(function(){a("body").trigger(j.deleted,[o,!0]),d.hide()})["catch"](c.exception)}),e}).fail(c.exception)}var m=!1,n={ROOT:"[data-region='summary-modal-container']",EDIT_BUTTON:'[data-action="edit"]',DELETE_BUTTON:'[data-action="delete"]'},o=function(a){e.call(this,a)};return o.TYPE="core_calendar-event_summary",o.prototype=Object.create(e.prototype),o.prototype.constructor=o,o.prototype.getEditButton=function(){return"undefined"==typeof this.editButton&&(this.editButton=this.getFooter().find(n.EDIT_BUTTON)),this.editButton},o.prototype.getDeleteButton=function(){return"undefined"==typeof this.deleteButton&&(this.deleteButton=this.getFooter().find(n.DELETE_BUTTON)),this.deleteButton},o.prototype.getEventId=function(){return this.getBody().find(n.ROOT).attr("data-event-id")},o.prototype.getEventCount=function(){return this.getBody().find(n.ROOT).attr("data-event-event-count")},o.prototype.getEditUrl=function(){return this.getBody().find(n.ROOT).attr("data-edit-url")},o.prototype.isActionEvent=function(){return"true"==this.getBody().find(n.ROOT).attr("data-action-event")},o.prototype.registerEventListeners=function(){e.prototype.registerEventListeners.call(this),this.getRoot().on(h.bodyRendered,function(){var a=this.getBody().find(n.ROOT).attr("data-event-title");l(this,a)}.bind(this)),d.define(this.getEditButton(),[d.events.activate]),this.getEditButton().on(d.events.activate,function(b,c){this.isActionEvent()?a("body").trigger(j.editActionEvent,[this.getEditUrl()]):a("body").trigger(j.editEvent,[this.getEventId()]),this.hide(),b.preventDefault(),b.stopPropagation(),c.originalEvent.preventDefault(),c.originalEvent.stopPropagation()}.bind(this))},m||(f.register(o.TYPE,o,"core_calendar/event_summary_modal"),m=!0),o});

View File

@ -26,6 +26,7 @@ define([], function() {
return {
created: 'calendar-events:created',
deleted: 'calendar-events:deleted',
deleteAll: 'calendar-events:delete_all',
updated: 'calendar-events:updated',
editEvent: 'calendar-events:edit_event',
editActionEvent: 'calendar-events:edit_action_event',

View File

@ -0,0 +1,112 @@
// 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/>.
/**
* Contain the logic for the save/cancel modal.
*
* @module core_calendar/modal_delete
* @class modal_delete
* @package core_calendar
* @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
'jquery',
'core/notification',
'core/custom_interaction_events',
'core/modal',
'core/modal_events',
'core/modal_registry',
'core_calendar/events',
],
function(
$,
Notification,
CustomEvents,
Modal,
ModalEvents,
ModalRegistry,
CalendarEvents
) {
var registered = false;
var SELECTORS = {
DELETE_ONE_BUTTON: '[data-action="deleteone"]',
DELETE_ALL_BUTTON: '[data-action="deleteall"]',
CANCEL_BUTTON: '[data-action="cancel"]',
};
/**
* Constructor for the Modal.
*
* @param {object} root The root jQuery element for the modal
*/
var ModalDelete = function(root) {
Modal.call(this, root);
};
ModalDelete.TYPE = 'core_calendar-modal_delete';
ModalDelete.prototype = Object.create(Modal.prototype);
ModalDelete.prototype.constructor = ModalDelete;
/**
* Set up all of the event handling for the modal.
*
* @method registerEventListeners
*/
ModalDelete.prototype.registerEventListeners = function() {
// Apply parent event listeners.
Modal.prototype.registerEventListeners.call(this);
this.getModal().on(CustomEvents.events.activate, SELECTORS.DELETE_ONE_BUTTON, function(e, data) {
var saveEvent = $.Event(ModalEvents.save);
this.getRoot().trigger(saveEvent, this);
if (!saveEvent.isDefaultPrevented()) {
this.hide();
data.originalEvent.preventDefault();
}
}.bind(this));
this.getModal().on(CustomEvents.events.activate, SELECTORS.DELETE_ALL_BUTTON, function(e, data) {
var saveEvent = $.Event(CalendarEvents.deleteAll);
this.getRoot().trigger(saveEvent, this);
if (!saveEvent.isDefaultPrevented()) {
this.hide();
data.originalEvent.preventDefault();
}
}.bind(this));
this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, function(e, data) {
var cancelEvent = $.Event(ModalEvents.cancel);
this.getRoot().trigger(cancelEvent, this);
if (!cancelEvent.isDefaultPrevented()) {
this.hide();
data.originalEvent.preventDefault();
}
}.bind(this));
};
// Automatically register with the modal registry the first time this module is imported so that you can create modals
// of this type using the modal factory.
if (!registered) {
ModalRegistry.register(ModalDelete.TYPE, ModalDelete, 'calendar/event_delete_modal');
registered = true;
}
return ModalDelete;
});

View File

@ -29,16 +29,19 @@ define(['jquery', 'core/ajax'], function($, Ajax) {
*
* @method deleteEvent
* @param {int} eventId The event id.
* @arapm {bool} deleteSeries Whether to delete all events in the series
* @return {promise} Resolved with requested calendar event
*/
var deleteEvent = function(eventId) {
var deleteEvent = function(eventId, deleteSeries) {
if (typeof deleteSeries === 'undefined') {
deleteSeries = false;
}
var request = {
methodname: 'core_calendar_delete_calendar_events',
args: {
events: [{
eventid: eventId,
repeat: 1
repeat: deleteSeries,
}]
}
};

View File

@ -21,11 +21,32 @@
* @copyright 2017 Simey Lameze <simey@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/str', 'core/notification', 'core/custom_interaction_events', 'core/modal',
'core/modal_registry', 'core/modal_factory', 'core/modal_events', 'core_calendar/repository',
'core_calendar/events'],
function($, Str, Notification, CustomEvents, Modal, ModalRegistry, ModalFactory, ModalEvents, CalendarRepository,
CalendarEvents) {
define([
'jquery',
'core/str',
'core/notification',
'core/custom_interaction_events',
'core/modal',
'core/modal_registry',
'core/modal_factory',
'core/modal_events',
'core_calendar/repository',
'core_calendar/events',
'core_calendar/modal_delete',
],
function(
$,
Str,
Notification,
CustomEvents,
Modal,
ModalRegistry,
ModalFactory,
ModalEvents,
CalendarRepository,
CalendarEvents,
ModalDelete
) {
var registered = false;
var SELECTORS = {
@ -89,6 +110,18 @@ define(['jquery', 'core/str', 'core/notification', 'core/custom_interaction_even
return this.getBody().find(SELECTORS.ROOT).attr('data-event-id');
};
/**
* Get the number of events in the series for the event being shown in
* this modal. This value is not cached because it will change
* depending on which event is being displayed.
*
* @method getEventCount
* @return {int}
*/
ModalEventSummary.prototype.getEventCount = function() {
return this.getBody().find(SELECTORS.ROOT).attr('data-event-event-count');
};
/**
* Get the url for the event being shown in this modal.
*
@ -163,34 +196,76 @@ define(['jquery', 'core/str', 'core/notification', 'core/custom_interaction_even
key: 'deleteevent',
component: 'calendar'
},
{
];
var eventCount = parseInt(summaryModal.getEventCount(), 10);
var deletePromise;
var isRepeatedEvent = eventCount > 1;
if (isRepeatedEvent) {
deleteStrings.push({
key: 'confirmeventseriesdelete',
component: 'calendar',
param: {
name: eventTitle,
count: eventCount,
},
});
deletePromise = ModalFactory.create(
{
type: ModalDelete.TYPE
},
summaryModal.getDeleteButton()
);
} else {
deleteStrings.push({
key: 'confirmeventdelete',
component: 'calendar',
param: eventTitle
}
];
});
deletePromise = ModalFactory.create(
{
type: ModalFactory.types.SAVE_CANCEL
},
summaryModal.getDeleteButton()
);
}
var eventId = summaryModal.getEventId();
var stringsPromise = Str.get_strings(deleteStrings);
var deletePromise = ModalFactory.create(
{
type: ModalFactory.types.SAVE_CANCEL
},
summaryModal.getDeleteButton()
);
$.when(stringsPromise, deletePromise).then(function(strings, deleteModal) {
$.when(stringsPromise, deletePromise)
.then(function(strings, deleteModal) {
deleteModal.setTitle(strings[0]);
deleteModal.setBody(strings[1]);
deleteModal.setSaveButtonText(strings[0]);
if (!isRepeatedEvent) {
deleteModal.setSaveButtonText(strings[0]);
}
deleteModal.getRoot().on(ModalEvents.save, function() {
CalendarRepository.deleteEvent(eventId).then(function() {
$('body').trigger(CalendarEvents.deleted, [eventId]);
summaryModal.hide();
return;
}).catch(Notification.exception);
CalendarRepository.deleteEvent(eventId, false)
.then(function() {
$('body').trigger(CalendarEvents.deleted, [eventId, false]);
summaryModal.hide();
return;
})
.catch(Notification.exception);
});
deleteModal.getRoot().on(CalendarEvents.deleteAll, function() {
CalendarRepository.deleteEvent(eventId, true)
.then(function() {
$('body').trigger(CalendarEvents.deleted, [eventId, true]);
summaryModal.hide();
return;
})
.catch(Notification.exception);
});
return deleteModal;
}).fail(Notification.exception);
})
.fail(Notification.exception);
}
// Automatically register with the modal registry the first time this module is imported so that you can create modals

View File

@ -87,6 +87,7 @@ class event_exporter_base extends exporter {
if ($repeats = $event->get_repeats()) {
$data->repeatid = $repeats->get_id();
$data->eventcount = $repeats->get_num() + 1;
}
if ($cm = $event->get_course_module()) {
@ -136,6 +137,12 @@ class event_exporter_base extends exporter {
'default' => null,
'null' => NULL_ALLOWED
],
'eventcount' => [
'type' => PARAM_INT,
'optional' => true,
'default' => null,
'null' => NULL_ALLOWED
],
'modulename' => [
'type' => PARAM_TEXT,
'optional' => true,

View File

@ -0,0 +1,47 @@
{{!
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/>.
}}
{{!
@template core_calendar/event_delete_modal
Moodle modal template with save and cancel buttons.
The purpose of this template is to render a modal.
Classes required for JS:
* none
Data attributes required for JS:
* none
Context variables required for this template:
* title A cleaned string (use clean_text()) to display.
* body HTML content for the boday
Example context (json):
{
"title": "Example delete event seriesmodal",
"body": "Do you want to delete this event, or all events in the series?"
}
}}
{{< core/modal }}
{{$footer}}
<button type="button" class="btn btn-primary" data-action="deleteone">{{#str}} deleteoneevent, core_calendar {{/str}}</button>
<button type="button" class="btn btn-secondary" data-action="deleteall">{{#str}} deleteallevents, core_calendar {{/str}}</button>
<button type="button" class="btn btn-secondary" data-action="cancel">{{#str}} cancel {{/str}}</button>
{{/footer}}
{{/ core/modal }}

View File

@ -28,8 +28,15 @@
"groupname": "Group 1"
}
}}
<div data-region="summary-modal-container" data-event-id="{{id}}" data-event-title="{{name}}"
data-action-event="{{isactionevent}}" data-edit-url="{{editurl}}">
<div{{!
}} data-region="summary-modal-container"{{!
}} data-event-id="{{id}}"{{!
}} data-event-title="{{name}}"{{!
}} data-event-event-count="{{eventcount}}"{{!
}} data-event-="{{repeatid}}"{{!
}} data-action-event="{{isactionevent}}"{{!
}} data-edit-url="{{editurl}}"{{!
}}>
<h4>{{#str}} when, core_calendar {{/str}}</h4>
{{#userdate}} {{timestart}}, {{#str}} strftimerecentfull {{/str}} {{/userdate}}
<br>

View File

@ -40,6 +40,7 @@ $string['colpoll'] = 'Update';
$string['colactions'] = 'Actions';
$string['commontasks'] = 'Options';
$string['confirmeventdelete'] = 'Are you sure you want to delete the "{$a}" event?';
$string['confirmeventseriesdelete'] = 'The "{$a->name}" event is part of a series. Do you want to delete just this event, or all {$a->count} events in the series?';
$string['course'] = 'Course';
$string['courseevent'] = 'Course event';
$string['courseevents'] = 'Course events';
@ -52,6 +53,8 @@ $string['daywithnoevents'] = 'There are no events this day.';
$string['default'] = 'Default';
$string['deleteevent'] = 'Delete event';
$string['deleteevents'] = 'Delete events';
$string['deleteoneevent'] = 'Delete this event';
$string['deleteallevents'] = 'Delete all events';
$string['detailedmonthviewfor'] = 'Detailed month view for:';
$string['detailedmonthviewtitle'] = 'Detailed month view: {$a}';
$string['durationminutes'] = 'Duration in minutes';