",s.innerHTML+=u}c.appendChild(s);var f=tippy(t[0],{arrow:!0,content:c,placement:"auto",interactive:!0,delay:[500,300],theme:"calendar-event",appendTo:document.body,onShow:function(){if(!window.calendarPopupsEnabled)return!1;e.repeats&&$.ajax({cache:!1,url:Craft.getCpUrl("calendar/events/api/first-occurrence-date"),type:"post",dataType:"json",data:n({eventId:e.id},Craft.csrfTokenName,Craft.csrfTokenValue),success:function(e){if(e.success&&e.event&&e.event.hasOwnProperty("readableRepeatRule")){var t=c.querySelector(".event-repeats");t&&(t.innerHTML=" "+e.event.readableRepeatRule)}}})}});c.querySelector(".sc-event-popup__close").addEventListener("click",(function(){return f.hide()}));var p=c.querySelector(".delete-event");p&&p.addEventListener("click",(function(e){e.preventDefault(),confirm(Craft.t("calendar","Are you sure you want to delete this event?"))&&$.ajax({url:this.href,type:"post",dataType:"json",data:n({eventId:this.dataset.id},Craft.csrfTokenName,Craft.csrfTokenValue),success:function(t){if(!t.error)return $("*[data-calendar-instance]").fullCalendar("removeEvents",e.id),void f.destroy();console.warn(t.error)}})}));var v=c.querySelector(".delete-event-occurrence");v&&v.addEventListener("click",(function(e){e.preventDefault(),confirm(Craft.t("calendar","Are you sure?"))&&$.ajax({url:this.href,type:"post",dataType:"json",data:n({eventId:this.dataset.id,date:this.dataset.date},Craft.csrfTokenName,Craft.csrfTokenValue),success:function(e){if(!e.error)return $("*[data-calendar-instance]").fullCalendar("refetchEvents"),void f.destroy();console.warn(e.error)}})}))}},d=function(e){return new Date(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds())}},,function(e,t,a){"use strict";a.r(t);var n=a(0),r=a(1);function l(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var a=e&&("undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"]);if(null==a)return;var n,r,l=[],i=!0,o=!1;try{for(a=a.call(e);!(i=(n=a.next()).done)&&(l.push(n.value),!t||l.length!==t);i=!0);}catch(e){o=!0,r=e}finally{try{i||null==a.return||a.return()}finally{if(o)throw r}}return l}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var a=Object.prototype.toString.call(e).slice(8,-1);"Object"===a&&e.constructor&&(a=e.constructor.name);if("Map"===a||"Set"===a)return Array.from(e);if("Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a))return i(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var a=0,n=new Array(t);a",{class:"menu"}).insertAfter(e.currentTarget),r=$("
").appendTo(n);for(var l in a)a.hasOwnProperty(l)&&$("
",u.innerHTML+=f}i.appendChild(u);var p=tippy(t[0],{arrow:!0,content:i,placement:"auto",interactive:!0,delay:[500,300],theme:"calendar-event",appendTo:document.body,onDestroy:function(){c.delete(p)},onShow:function(){if(!window.calendarPopupsEnabled)return!1;e.repeats&&$.ajax({cache:!1,url:Craft.getCpUrl("calendar/events/api/first-occurrence-date"),type:"post",dataType:"json",data:n({eventId:e.id},Craft.csrfTokenName,Craft.csrfTokenValue),success:function(e){if(e.success&&e.event&&e.event.hasOwnProperty("readableRepeatRule")){var t=i.querySelector(".event-repeats");t&&(t.innerHTML=" "+e.event.readableRepeatRule)}}})}});c.add(p),i.querySelector(".sc-event-popup__close").addEventListener("click",(function(){return p.hide()}));var m=i.querySelector(".delete-event");m&&m.addEventListener("click",(function(e){e.preventDefault(),confirm(Craft.t("calendar","Are you sure you want to delete this event?"))&&$.ajax({url:this.href,type:"post",dataType:"json",data:n({eventId:this.dataset.id},Craft.csrfTokenName,Craft.csrfTokenValue),success:function(t){if(!t.error)return $("*[data-calendar-instance]").fullCalendar("removeEvents",e.id),void p.destroy();console.warn(t.error)}})}));var v=i.querySelector(".delete-event-occurrence");v&&v.addEventListener("click",(function(e){e.preventDefault(),confirm(Craft.t("calendar","Are you sure?"))&&$.ajax({url:this.href,type:"post",dataType:"json",data:n({eventId:this.dataset.id,date:this.dataset.date},Craft.csrfTokenName,Craft.csrfTokenValue),success:function(e){if(!e.error)return $("*[data-calendar-instance]").fullCalendar("refetchEvents"),void p.destroy();console.warn(e.error)}})}))}},s=function(){c.forEach((function(e){return e.destroy()})),c.clear()},u=function(e){return new Date(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds())}},1:function(e,t,a){"use strict";a.r(t),a.d(t,"renderEvent",(function(){return d})),a.d(t,"today",(function(){return i})),a.d(t,"renderDay",(function(){return s})),a.d(t,"renderView",(function(){return u})),a.d(t,"eventRepositioned",(function(){return f})),a.d(t,"eventDateChange",(function(){return p})),a.d(t,"eventDurationChange",(function(){return m})),a.d(t,"eventClick",(function(){return v})),a.d(t,"getDayViewLink",(function(){return y})),a.d(t,"getEvents",(function(){return h})),a.d(t,"closeAllPopups",(function(){return C})),a.d(t,"enablePopups",(function(){return b})),a.d(t,"getSpinner",(function(){return g}));var n=a(0);function r(e){return function(e){if(Array.isArray(e))return o(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return o(e,t);var a=Object.prototype.toString.call(e).slice(8,-1);"Object"===a&&e.constructor&&(a=e.constructor.name);if("Map"===a||"Set"===a)return Array.from(e);if("Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a))return o(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var a=0,n=new Array(t);a").addClass("fc-color-icon").css("background-color",e.backgroundColor).css("border-color",e.borderColor);$(".fc-content",t).prepend(a)}e.enabled||t.addClass("fc-event-disabled"),t.addClass("fc-color-"+e.textColor);var r=c.data(),o=r.timeFormat,l=r.isMultiSite;Object(n.buildEventPopup)(e,t,o,void 0!==l)}},i=new moment,s=function(e,t){var a=t.parents(".fc-bg:first").siblings(".fc-content-skeleton").find("thead > tr > td:eq("+t.index()+")"),n=y(e),r=$("").attr("href",n).html(a.html());a.html(r)},u=function(e,t){var a=t.parents("#solspace-calendar"),n=new moment(a.data("current-day"));"agendaWeek"===e.name&&$(".fc-day-header.fc-widget-header",t).each((function(){var e=$(this).html(),t=e.split(" ");e=t[0]+" "+t[1]+"";var a=new moment($(this).data("date")),r=y(a),o=$("").attr("href",r).html(e);n.format("YYYYMMDD")===a.format("YYYYMMDD")&&o.addClass("fc-title-today"),$(this).html(o)}));$(".fc-localeButton-button",c).addClass("menubtn btn"),"agendaDay"===e.name&&$("thead.fc-head",t).remove()},f=function(e,t,a,n){var r,o,c;$.ajax({url:Craft.getCpUrl("calendar/events/api/modify-"+e),type:"post",dataType:"json",data:(r={eventId:t.id,siteId:t.site.id,isAllDay:t.allDay,startDate:t.start.toISOString(),endDate:t.end?t.end.toISOString():null,deltaSeconds:parseInt(a.as("seconds"),10)},o=Craft.csrfTokenName,c=Craft.csrfTokenValue,o in r?Object.defineProperty(r,o,{value:c,enumerable:!0,configurable:!0,writable:!0}):r[o]=c,r),success:function(e){e.error?n():t.repeats&&$calendar.fullCalendar("refetchEvents")},error:function(){n()}})},p=function(e,t,a){f("date",e,t,a)},m=function(e,t,a){f("duration",e,t,a)},v=function(e){window.location.href=Craft.getCpUrl("calendar/events/"+e.id+"/"+e.site.handle)},y=function(e){if(e.isValid()){var t=e.format("YYYY"),a=e.format("MM"),n=e.format("DD");return Craft.getCpUrl("calendar/view/day/"+t+"/"+a+"/"+n)}return""},h=function(e,t,a,n){g().fadeIn("fast");var o=$("ul.calendar-list"),c="*";o.length&&(c=$("input:checked",o).map((function(){return $(this).val()})).get().join());var l=$("#solspace-calendar").data().currentSiteId,d=$("form.calendar-filters"),i=[].concat(r(d.serializeArray()),[{name:"rangeStart",value:e.toISOString()},{name:"rangeEnd",value:t.toISOString()},{name:"calendars",value:c},{name:"siteId",value:l},{name:[Craft.csrfTokenName],value:Craft.csrfTokenValue}]);$.ajax({url:Craft.getCpUrl("calendar/month"),data:$.param(i),type:"post",dataType:"json",success:function(e){for(var t=0;t'),l=$("#solspace-calendar-spinner")),l}},9:function(e,t,a){"use strict";a.r(t);var n=a(1);document.querySelectorAll("*[data-mini-cal]").forEach((function(e){var t=(e=$(e)).data(),a=t.overlapThreshold,o=void 0===a?5:a,c=t.firstDayOfWeek,l=void 0===c?0:c,d=t.locale,i=void 0===d?"en":d,s=t.currentDay,u=void 0===s?new moment:s;e.fullCalendar({now:new moment,defaultDate:u,defaultView:"month",nextDayThreshold:"0"+o+":00:01",fixedWeekCount:!1,showNonCurrentDates:!0,eventLimit:1,firstDay:l,lang:i,height:"auto",columnFormat:"dd",viewRender:r,windowResize:r,eventClick:n.eventClick,dayClick:function(e){window.location.href=Craft.getCpUrl("calendar/view/day/"+e.format("YYYY/MM/DD"))},events:function(t,a){var n,r,o;$.ajax({url:Craft.getCpUrl("calendar/month"),data:(n={rangeStart:t.toISOString(),rangeEnd:a.toISOString(),nonEditable:!0,calendars:e.data("calendars"),siteId:e.data("siteId")},r=Craft.csrfTokenName,o=Craft.csrfTokenValue,r in n?Object.defineProperty(n,r,{value:o,enumerable:!0,configurable:!0,writable:!0}):n[r]=o,n),type:"post",dataType:"json",success:function(e){$(".fc-content-skeleton .fc-day-top.fc-has-event").removeClass("fc-has-event");for(var t=0;tgetSettingsModel()->showDisabledEvents;
}
+ public function allowEventsToBeModifiedByDragAndDrop(): bool
+ {
+ return $this->getSettingsModel()->allowEventsToBeModifiedByDragAndDrop;
+ }
+
public function isQuickCreateEnabled(): bool
{
return $this->getSettingsModel()->quickCreateEnabled;
diff --git a/packages/plugin/src/templates/settings/_general.html b/packages/plugin/src/templates/settings/_general.html
index 7fbdb51b..b8fe5f64 100644
--- a/packages/plugin/src/templates/settings/_general.html
+++ b/packages/plugin/src/templates/settings/_general.html
@@ -77,6 +77,15 @@
errors: settings.getErrors('showDisabledEvents')
}) }}
+ {{ forms.lightswitchField({
+ label: "Allow events to be modified by drag and drop in Month/Week/Day views?"|t('calendar'),
+ instructions: "Allows all users with event creation privileges to use drag and drop to modify events."|t('calendar'),
+ id: 'allowEventsToBeModifiedByDragAndDrop',
+ name: 'settings[allowEventsToBeModifiedByDragAndDrop]',
+ on: settings.allowEventsToBeModifiedByDragAndDrop,
+ errors: settings.getErrors('allowEventsToBeModifiedByDragAndDrop')
+ }) }}
+
{{ forms.lightswitchField({
label: "Allow new events to be created in Month/Week/Day views?"|t('calendar'),
instructions: "Allows all users with event creation privileges to use the Quick Create event feature."|t('calendar'),
diff --git a/packages/plugin/src/templates/view/calendar.html b/packages/plugin/src/templates/view/calendar.html
index 857a0753..eb38fbe4 100644
--- a/packages/plugin/src/templates/view/calendar.html
+++ b/packages/plugin/src/templates/view/calendar.html
@@ -104,6 +104,7 @@
data-current-site-id="{{ selectedSiteId }}"
data-current-day="{{ currentDay.toDateString }}"
data-site-map="{{ siteMap|json_encode }}"
+ {% if allowEventsToBeModifiedByDragAndDrop %}data-allow-events-to-be-modified-by-drag-and-drop{% endif %}
{% if isQuickCreateEnabled %}data-can-quick-create{% endif %}
{% if isMultiSite %}data-is-multi-site{% endif %}
{% if currentUser and currentUser.can('calendar-manageEvents') and calendarOptions is not empty %}
diff --git a/packages/plugin/src/translations/de/calendar.php b/packages/plugin/src/translations/de/calendar.php
index 20e2d6f7..d6e580aa 100755
--- a/packages/plugin/src/translations/de/calendar.php
+++ b/packages/plugin/src/translations/de/calendar.php
@@ -196,6 +196,8 @@
'Displays a side menu with mini calendar and list of calendars, allowing you to filter your event results.' => 'Zeigt ein seitliches Menü mit dem Mini-Kalender und einer Liste aller Kalender an, mit der Ereignisse gefiltert werden können.',
'Include Disabled Events in Month/Week/Day views?' => 'Deaktivierte Ereignisse in Monats-/Wochen-/Tagesansicht anzeigen?',
'Events that are disabled will be displayed in the views with faded styles.' => 'Deaktivierte Ereignisse werden mit einem ausgegrautem Stil angezeigt.',
+ 'Allow events to be modified by drag and drop in Month/Week/Day views?' => 'Soll es möglich sein, Ereignisse in der Monats-/Wochen-/Tagesansicht per Drag & Drop zu bearbeiten?',
+ 'Allows all users with event creation privileges to use drag and drop to modify events.' => 'Ermöglicht allen Benutzern mit Berechtigung zum Erstellen von Ereignissen, Ereignisse per Drag & Drop zu bearbeiten.',
'Default View' => 'Standardansicht',
'The default page to go to when clicking the Calendar nav item.' => 'Die Standardansicht, wenn im Menü auf den Kalendereintrag geklickt wird.',
'Allow new events to be created in Month/Week/Day views?' => 'Das Erstellen neuer Ereignisse in der Monats-/Wochen-/Tagesansicht zulassen?',
diff --git a/packages/plugin/src/translations/en-US/calendar.php b/packages/plugin/src/translations/en-US/calendar.php
index 1b339aa6..55f0f0cc 100644
--- a/packages/plugin/src/translations/en-US/calendar.php
+++ b/packages/plugin/src/translations/en-US/calendar.php
@@ -207,6 +207,8 @@
'Displays a side menu with mini calendar and list of calendars, allowing you to filter your event results.' => 'Displays a side menu with mini calendar and list of calendars, allowing you to filter your event results.',
'Include Disabled Events in Month/Week/Day views?' => 'Include Disabled Events in Month/Week/Day views?',
'Events that are disabled will be displayed in the views with faded styles.' => 'Events that are disabled will be displayed in the views with faded styles.',
+ 'Allow events to be modified by drag and drop in Month/Week/Day views?' => 'Allow events to be modified by drag and drop in Month/Week/Day views?',
+ 'Allows all users with event creation privileges to use drag and drop to modify events.' => 'Allows all users with event creation privileges to use drag and drop to modify events.',
'Default View' => 'Default View',
'The default page to go to when clicking the Calendar nav item.' => 'The default page to go to when clicking the Calendar nav item.',
'Allow new events to be created in Month/Week/Day views?' => 'Allow new events to be created in Month/Week/Day views?',
diff --git a/packages/plugin/src/translations/lv/calendar.php b/packages/plugin/src/translations/lv/calendar.php
index f1f1d420..68ba3bc2 100644
--- a/packages/plugin/src/translations/lv/calendar.php
+++ b/packages/plugin/src/translations/lv/calendar.php
@@ -190,6 +190,8 @@
'Displays a side menu with mini calendar and list of calendars, allowing you to filter your event results.' => 'Parāda sānu izvēlni ar mini kalendāru un kalendāru sarakstu, ļaujot filtrēt pasākumus pēc kalendāra.',
'Include Disabled Events in Month/Week/Day views?' => 'Iekļaut izslēgtos pasājumus mēneša/nedēļas/dienas skatos?',
'Events that are disabled will be displayed in the views with faded styles.' => 'Izslēgtie pasākumi tiks atrādīti kalendāra skatos caurspīdīgāki.',
+ 'Allow events to be modified by drag and drop in Month/Week/Day views?' => 'Vai atļaut notikumus mainīt, velkot un nometot tos mēneša/nedēļas/dienas skatos?',
+ 'Allows all users with event creation privileges to use drag and drop to modify events.' => 'Atļauj visiem lietotājiem ar notikumu izveides privilēģijām modificēt notikumus, izmantojot vilkšanas un nomešanas funkciju.',
'Default View' => 'Kalendāra skats pēc noklusējuma',
'The default page to go to when clicking the Calendar nav item.' => 'Lapa uz kuru doties spiežot uz Kalendāra navigācijas pogas',
'Allow new events to be created in Month/Week/Day views?' => 'Vai atļaut izveidot pasākumus kalendāra mēneša/nedēļas/dienas skatos',
diff --git a/packages/plugin/src/translations/nl/calendar.php b/packages/plugin/src/translations/nl/calendar.php
index 386c66cd..5ed24b21 100644
--- a/packages/plugin/src/translations/nl/calendar.php
+++ b/packages/plugin/src/translations/nl/calendar.php
@@ -189,6 +189,8 @@
'Displays a side menu with mini calendar and list of calendars, allowing you to filter your event results.' => 'Toont een menu in de zijbalk met een minikalender en kalenderlijst waarmee gefilderd kan worden binnen evenementen.',
'Include Disabled Events in Month/Week/Day views?' => 'Include Disabled Events in Month/Week/Day views?',
'Events that are disabled will be displayed in the views with faded styles.' => 'Events that are disabled will be displayed in the views with faded styles.',
+ 'Allow events to be modified by drag and drop in Month/Week/Day views?' => 'Is het mogelijk om evenementen te bewerken door ze te verslepen in de maand-, week- en dagweergave?',
+ 'Allows all users with event creation privileges to use drag and drop to modify events.' => 'Hiermee kunnen alle gebruikers met de juiste rechten om evenementen aan te maken, deze via drag-and-drop wijzigen.',
'Default View' => 'Default View',
'The default page to go to when clicking the Calendar nav item.' => 'The default page to go to when clicking the Calendar nav item.',
'Allow new events to be created in Month/Week/Day views?' => 'Allow new events to be created in Month/Week/Day views?',
diff --git a/packages/scripts/src/calendars/fullcalendar-methods.js b/packages/scripts/src/calendars/fullcalendar-methods.js
index 41e72814..ca4000b6 100644
--- a/packages/scripts/src/calendars/fullcalendar-methods.js
+++ b/packages/scripts/src/calendars/fullcalendar-methods.js
@@ -1,4 +1,4 @@
-import { buildEventPopup } from './popups';
+import { buildEventPopup, hideAllPopups } from './popups';
const $solspaceCalendar = $('#solspace-calendar');
let $solspaceCalendarSpinner = null;
@@ -245,7 +245,7 @@ export const getEvents = (start, end, timezone, callback) => {
export const closeAllPopups = () => {
window.calendarPopupsEnabled = false;
- tippy.hideAll();
+ hideAllPopups();
};
export const enablePopups = () => {
diff --git a/packages/scripts/src/calendars/main.js b/packages/scripts/src/calendars/main.js
index c3d38776..96d3ac0c 100644
--- a/packages/scripts/src/calendars/main.js
+++ b/packages/scripts/src/calendars/main.js
@@ -10,9 +10,10 @@ $(() => {
'use strict';
const { currentDay, siteMap, overlapThreshold, language, firstDayOfWeek, timeFormat } = $calendar.data();
- let { currentSiteId, canEditEvents, canQuickCreate, isMultiSite } = $calendar.data();
+ let { currentSiteId, canEditEvents, allowEventsToBeModifiedByDragAndDrop, canQuickCreate, isMultiSite } = $calendar.data();
canEditEvents = canEditEvents !== undefined;
+ allowEventsToBeModifiedByDragAndDrop = allowEventsToBeModifiedByDragAndDrop !== undefined;
canQuickCreate = canQuickCreate !== undefined;
isMultiSite = isMultiSite !== undefined;
@@ -135,7 +136,7 @@ $(() => {
showNonCurrentDates: true,
eventLimit: 5,
aspectRatio: 1.3,
- editable: canEditEvents,
+ editable: canEditEvents && allowEventsToBeModifiedByDragAndDrop,
lang: language,
views: viewSpecificOptions,
firstDay: firstDayOfWeek,
diff --git a/packages/scripts/src/calendars/popups.js b/packages/scripts/src/calendars/popups.js
index 3f5c7dd3..56975907 100644
--- a/packages/scripts/src/calendars/popups.js
+++ b/packages/scripts/src/calendars/popups.js
@@ -1,5 +1,6 @@
let eventCreatorShown = false;
const $calendar = $('#solspace-calendar');
+const popupInstances = new Set();
const closeEventCreatorModal = (backdrop, modal) => {
document.body.removeChild(backdrop);
@@ -174,6 +175,14 @@ export const buildEventPopup = (event, element, calendarTimeFormat, isMultiSite
return;
}
+ if (!window.calendarPopupsEnabled) {
+ return;
+ }
+
+ if (element[0]._tippy) {
+ element[0]._tippy.destroy();
+ }
+
const start = moment(event.start);
const end = moment(event.end);
@@ -226,7 +235,7 @@ export const buildEventPopup = (event, element, calendarTimeFormat, isMultiSite
body.innerHTML += '
';
}
- if (event.editable) {
+ if (event.canEdit) {
let buttonsHtml =
'