backdrop-contrib / fullcalendar_views

Views style plugin to render all sorts of date fields as event calendar with FullCalendar
https://backdropcms.org/project/fullcalendar_views
GNU General Public License v2.0
2 stars 4 forks source link

Better expose FullCalendar instances for easier interaction #44

Closed indigoxela closed 1 month ago

indigoxela commented 2 months ago

Currently there's the possibility to override (static) options in JS via $.extend(). The disadvantage is, that this only allows to override properties, no callbacks. And only before the calendar instance has been created, so no dynamic properties (values by callbacks).

And the calendar's API also isn't exposed.

But there's a way to do that, to allow more flexibility for adaptions by modules or themes.

indigoxela commented 1 month ago

So, here's the PR with my idea:

After the calendar instance has been created, also put it into global Backdrop space and dispatch a custom event.

Now, what would modules do with that?

An example (module foobar):

foobar.info

name = Foobar Calendar
description = Playing with hooks.
type = module
backdrop = 1.x

dependencies[] = fullcalendar_views
scripts[] = js/foobar.js

js/foobar.js

(function ($) {
  "use strict";

  Backdrop.behaviors.foobarFullcalendarCustom = {
    attach: function () {
      // This requires changes in fullcalendar_views module (this PR).
      $(document).on('fullCalendar:created', function (e, data) {
        let storageName = 'fullCalendar_' + data.calendarId;
        let calendar = Backdrop.fullcalendarInstances[data.calendarId];

        // Listen to one of FullCalendar's own events.
        calendar.on('datesSet', function (event) {
          let midDate = new Date((event.start.getTime() + event.end.getTime()) / 2);
          // In localStorage the value survives page reloads.
          localStorage.setItem(storageName, midDate.toISOString());
        });
        // Caution, this stays in there until actively purged.
        // If you need something that expires, have a look at sessionStorage instead.
        if (localStorage.getItem(storageName)) {
          let initialDate = localStorage.getItem(storageName);
          // initialDate cannot be set dynamically, we have to "go there".
          // @see https://fullcalendar.io/docs/dynamic-options
          calendar.gotoDate(initialDate);
        }
      });
    }
  };
})(jQuery);

This saves the currently active date in calendar navigation to localStorage, so the selected month (or week, or day) "survives" a page reload, which includes applying a views exposed filter, for example. The "datesSet" event gets emitted, whenever the calendar navigation is clicked, so a new active date is set.

@laryn this may fix your problem - if I got things right.

This PR also makes it easier to adapt the calendar instance, for example to add custom buttons outside the calendar to interact with the calendar. Or use any methods of the FullCalendar API.

indigoxela commented 1 month ago

this may fix your problem...

Or maybe not. Anyway, it's a small change, that brings lots of flexibility - when using code to extend. So I'll go ahead and merge.