Update Calendar to Full Calendar 6.1.10

This commit is contained in:
o-psi 2024-02-14 20:21:19 +00:00
parent 20845d72da
commit 1f3799ebe3
51 changed files with 33178 additions and 125 deletions

View File

@ -8,7 +8,7 @@ if (isset($_GET['calendar_id'])) {
}
?>
<link href='plugins/fullcalendar/main.min.css' rel='stylesheet' />
<link href='plugins/fullcalendar-6.1.10/dist/index.global.js' rel='stylesheet' />
<!-- So that when hovering over a created event it turns into a hand instead of cursor -->
<style>
@ -48,136 +48,161 @@ while ($row = mysqli_fetch_array($sql)) {
<?php require_once "footer.php";
?>
<script src='plugins/fullcalendar/main.min.js'></script>
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@6.1.10/index.global.min.js'></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
themeSystem: 'bootstrap',
defaultView: 'dayGridMonth',
customButtons: {
addEvent: {
bootstrapFontAwesome: 'fa fa-plus',
click: function() {
$("#addCalendarEventModal").modal();
}
},
addCalendar: {
bootstrapFontAwesome: 'fa fa-calendar-plus',
click: function() {
$("#addCalendarModal").modal();
}
}
},
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth addEvent addCalendar'
},
events: [
<?php
$sql = mysqli_query($mysqli, "SELECT * FROM events LEFT JOIN calendars ON event_calendar_id = calendar_id");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['event_id']);
$event_title = json_encode($row['event_title']);
$event_start = json_encode($row['event_start']);
$event_end = json_encode($row['event_end']);
$calendar_id = intval($row['calendar_id']);
$calendar_name = json_encode($row['calendar_name']);
$calendar_color = json_encode($row['calendar_color']);
echo "{ id: $event_id, title: $event_title, start: $event_start, end: $event_end, color: $calendar_color },";
}
//Invoices Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN invoices ON client_id = invoice_client_id");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['invoice_id']);
$event_title = json_encode($row['invoice_prefix'] . $row['invoice_number'] . " " . $row['invoice_scope']);
$event_start = json_encode($row['invoice_date']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: 'blue', url: 'invoice.php?invoice_id=$event_id' },";
}
//Quotes Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN quotes ON client_id = quote_client_id");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['quote_id']);
$event_title = json_encode($row['quote_prefix'] . $row['quote_number'] . " " . $row['quote_scope']);
$event_start = json_encode($row['quote_date']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: 'purple', url: 'quote.php?quote_id=$event_id' },";
}
//Tickets Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN tickets ON client_id = ticket_client_id");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['ticket_id']);
$event_title = json_encode($row['ticket_prefix'] . $row['ticket_number'] . " " . $row['ticket_subject']);
$event_start = json_encode($row['ticket_created_at']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: 'orange', url: 'ticket.php?ticket_id=$event_id' },";
}
//Tickets Scheduled
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN tickets ON client_id = ticket_client_id LEFT JOIN users ON ticket_assigned_to = user_id WHERE ticket_schedule IS NOT NULL");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['ticket_id']);
if (empty($username)) {
$username = "Unassigned";
} else {
$username = $row['user_name'];
}
if (strtotime($row['ticket_schedule']) < time()) {
if ($row['ticket_status'] == 'Scheduled') {
$event_color = "red";
} else {
$event_color = "green";
}
} else {
$event_color = "grey";
}
$event_title = json_encode($row['ticket_prefix'] . $row['ticket_number'] . " " . $row['ticket_subject'] . " [" . $username . "]");
$event_start = json_encode($row['ticket_schedule']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'ticket.php?ticket_id=$event_id' },";
}
//Vendors Added Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN vendors ON client_id = vendor_client_id WHERE vendor_template = 0");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['vendor_id']);
$client_id = intval($row['client_id']);
$event_title = json_encode($row['vendor_name']);
$event_start = json_encode($row['vendor_created_at']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: 'brown', url: 'client_vendors.php?client_id=$client_id' },";
}
//Clients Added
$sql = mysqli_query($mysqli, "SELECT * FROM clients");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['client_id']);
$event_title = json_encode($row['client_name']);
$event_start = json_encode($row['client_created_at']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: 'green', url: 'client_overview.php?client_id=$event_id' },";
}
?>
],
eventClick: function(editEvent) {
var calendar = new FullCalendar.Calendar(calendarEl, {
themeSystem: 'bootstrap',
defaultView: 'dayGridMonth',
customButtons: {
addEvent: {
text: 'Add Event',
bootstrapFontAwesome: 'fa fa-plus',
click: function() {
$("#addCalendarEventModal").modal();
}
},
addCalendar: {
text: 'Add Calendar',
bootstrapFontAwesome: 'fa fa-calendar-plus',
click: function() {
$("#addCalendarModal").modal();
}
}
},
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth addEvent addCalendar'
},
<?php if(!$session_mobile) {
?>aspectRatio: 2.5,<?php
} else {
?>aspectRatio: 0.75,<?php
}
?>
//initialDate: '2023-01-12',
navLinks: true, // can click day/week names to navigate views
selectable: true,
selectMirror: true,
eventClick: function(editEvent) {
$('#editEventModal' + editEvent.event.id).modal();
}
});
},
dayMaxEvents: true, // allow "more" link when too many events
views: {
timeGrid: {
dayMaxEventRows: 5, // adjust to 6 only for timeGridWeek/timeGridDay
expandRows: true,
nowIndicator: true,
},
dayGrid: {
dayMaxEvents: 5, // adjust to 6 only for timeGridWeek/timeGridDay
expandRows: true,
},
calendar.render();
},
events: [
<?php
$sql = mysqli_query($mysqli, "SELECT * FROM events LEFT JOIN calendars ON event_calendar_id = calendar_id");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['event_id']);
$event_title = json_encode($row['event_title']);
$event_start = json_encode($row['event_start']);
$event_end = json_encode($row['event_end']);
$calendar_id = intval($row['calendar_id']);
$calendar_name = json_encode($row['calendar_name']);
$calendar_color = json_encode($row['calendar_color']);
echo "{ id: $event_id, title: $event_title, start: $event_start, end: $event_end, color: $calendar_color },";
}
//Invoices Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN invoices ON client_id = invoice_client_id");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['invoice_id']);
$event_title = json_encode($row['invoice_prefix'] . $row['invoice_number'] . " " . $row['invoice_scope']);
$event_start = json_encode($row['invoice_date']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: 'blue', url: 'invoice.php?invoice_id=$event_id' },";
}
//Quotes Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN quotes ON client_id = quote_client_id");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['quote_id']);
$event_title = json_encode($row['quote_prefix'] . $row['quote_number'] . " " . $row['quote_scope']);
$event_start = json_encode($row['quote_date']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: 'purple', url: 'quote.php?quote_id=$event_id' },";
}
//Tickets Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN tickets ON client_id = ticket_client_id");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['ticket_id']);
$event_title = json_encode($row['ticket_prefix'] . $row['ticket_number'] . " " . $row['ticket_subject']);
$event_start = json_encode($row['ticket_created_at']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: 'orange', url: 'ticket.php?ticket_id=$event_id' },";
}
//Tickets Scheduled
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN tickets ON client_id = ticket_client_id LEFT JOIN users ON ticket_assigned_to = user_id WHERE ticket_schedule IS NOT NULL");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['ticket_id']);
if (empty($username)) {
$username = "Unassigned";
} else {
$username = $row['user_name'];
}
if (strtotime($row['ticket_schedule']) < time()) {
if ($row['ticket_status'] == 'Scheduled') {
$event_color = "red";
} else {
$event_color = "green";
}
} else {
$event_color = "grey";
}
$event_title = json_encode($row['ticket_prefix'] . $row['ticket_number'] . " " . $row['ticket_subject'] . " [" . $username . "]");
$event_start = json_encode($row['ticket_schedule']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'ticket.php?ticket_id=$event_id' },";
}
//Vendors Added Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN vendors ON client_id = vendor_client_id WHERE vendor_template = 0");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['vendor_id']);
$client_id = intval($row['client_id']);
$event_title = json_encode($row['vendor_name']);
$event_start = json_encode($row['vendor_created_at']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: 'brown', url: 'client_vendors.php?client_id=$client_id' },";
}
//Clients Added
$sql = mysqli_query($mysqli, "SELECT * FROM clients");
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['client_id']);
$event_title = json_encode($row['client_name']);
$event_start = json_encode($row['client_created_at']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: 'green', url: 'client_overview.php?client_id=$event_id' },";
}
?>
]
});
calendar.render();
});
</script>
<!-- Automatically set new event end date to 1 hr after start date -->

View File

@ -75,6 +75,9 @@ if ($iPod || $iPhone || $iPad) {
$session_map_source = "google";
}
//Check if mobile device
$session_mobile = isMobile();
//Get Notification Count for the badge on the top nav
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('notification_id') AS num FROM notifications WHERE (notification_user_id = $session_user_id OR notification_user_id = 0) AND notification_dismissed_at IS NULL"));
$num_notifications = $row['num'];

View File

@ -1085,3 +1085,9 @@ function createiCalStr($datetime, $title, $description, $location)
// Return the iCal string
return $cal_event->export();
}
function isMobile()
{
// Check if the user agent is a mobile device
return preg_match('/(android|avantgo|blackberry|bolt|boost|cricket|docomo|fone|hiptop|mini|opera mini|palm|phone|pie|tablet|up.browser|up.link|webos|wos)/i', $_SERVER['HTTP_USER_AGENT']);
}

View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2021 Adam Shaw
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,74 @@
# FullCalendar
Full-sized drag & drop calendar in JavaScript
- [Project Website](https://fullcalendar.io/)
- [Documentation](https://fullcalendar.io/docs)
- [Changelog](CHANGELOG.md)
- [Support](https://fullcalendar.io/support)
- [License](LICENSE.md)
- [Roadmap](https://fullcalendar.io/roadmap)
Connectors:
- [React](https://github.com/fullcalendar/fullcalendar-react)
- [Angular](https://github.com/fullcalendar/fullcalendar-angular)
- [Vue 3](https://github.com/fullcalendar/fullcalendar-vue) |
[2](https://github.com/fullcalendar/fullcalendar-vue2)
## Bundle
The [FullCalendar Standard Bundle](bundle) is easier to install than individual plugins, though filesize will be larger. It works well with a CDN.
## Installation
Install the FullCalendar core package and any plugins you plan to use:
```sh
npm install @fullcalendar/core @fullcalendar/interaction @fullcalendar/daygrid
```
## Usage
Instantiate a Calendar with plugins and options:
```js
import { Calendar } from '@fullcalendar/core'
import interactionPlugin from '@fullcalendar/interaction'
import dayGridPlugin from '@fullcalendar/daygrid'
const calendarEl = document.getElementById('calendar')
const calendar = new Calendar(calendarEl, {
plugins: [
interactionPlugin,
dayGridPlugin
],
initialView: 'timeGridWeek',
editable: true,
events: [
{ title: 'Meeting', start: new Date() }
]
})
calendar.render()
```
## Development
You must install this repo with [PNPM](https://pnpm.io/):
```
pnpm install
```
Available scripts (via `pnpm run <script>`):
- `build` - build production-ready dist files
- `dev` - build & watch development dist files
- `test` - test headlessly
- `test:dev` - test interactively
- `lint`
- `clean`
[Info about contributing code &raquo;](CONTRIBUTING.md)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,64 @@
/*!
FullCalendar Bootstrap 4 Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/bootstrap4
(c) 2023 Adam Shaw
*/
FullCalendar.Bootstrap = (function (exports, core, internal$1) {
'use strict';
class BootstrapTheme extends internal$1.Theme {
}
BootstrapTheme.prototype.classes = {
root: 'fc-theme-bootstrap',
table: 'table-bordered',
tableCellShaded: 'table-active',
buttonGroup: 'btn-group',
button: 'btn btn-primary',
buttonActive: 'active',
popover: 'popover',
popoverHeader: 'popover-header',
popoverContent: 'popover-body',
};
BootstrapTheme.prototype.baseIconClass = 'fa';
BootstrapTheme.prototype.iconClasses = {
close: 'fa-times',
prev: 'fa-chevron-left',
next: 'fa-chevron-right',
prevYear: 'fa-angle-double-left',
nextYear: 'fa-angle-double-right',
};
BootstrapTheme.prototype.rtlIconClasses = {
prev: 'fa-chevron-right',
next: 'fa-chevron-left',
prevYear: 'fa-angle-double-right',
nextYear: 'fa-angle-double-left',
};
BootstrapTheme.prototype.iconOverrideOption = 'bootstrapFontAwesome'; // TODO: make TS-friendly. move the option-processing into this plugin
BootstrapTheme.prototype.iconOverrideCustomButtonOption = 'bootstrapFontAwesome';
BootstrapTheme.prototype.iconOverridePrefix = 'fa-';
var css_248z = ".fc-theme-bootstrap a:not([href]){color:inherit}.fc-theme-bootstrap .fc-more-link:hover{text-decoration:none}";
internal$1.injectStyles(css_248z);
var plugin = core.createPlugin({
name: '@fullcalendar/bootstrap',
themeClasses: {
bootstrap: BootstrapTheme,
},
});
var internal = {
__proto__: null,
BootstrapTheme: BootstrapTheme
};
core.globalPlugins.push(plugin);
exports.Internal = internal;
exports["default"] = plugin;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, FullCalendar.Internal);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Bootstrap 4 Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/bootstrap4
(c) 2023 Adam Shaw
*/
FullCalendar.Bootstrap=function(e,t,o){"use strict";class r extends o.Theme{}r.prototype.classes={root:"fc-theme-bootstrap",table:"table-bordered",tableCellShaded:"table-active",buttonGroup:"btn-group",button:"btn btn-primary",buttonActive:"active",popover:"popover",popoverHeader:"popover-header",popoverContent:"popover-body"},r.prototype.baseIconClass="fa",r.prototype.iconClasses={close:"fa-times",prev:"fa-chevron-left",next:"fa-chevron-right",prevYear:"fa-angle-double-left",nextYear:"fa-angle-double-right"},r.prototype.rtlIconClasses={prev:"fa-chevron-right",next:"fa-chevron-left",prevYear:"fa-angle-double-right",nextYear:"fa-angle-double-left"},r.prototype.iconOverrideOption="bootstrapFontAwesome",r.prototype.iconOverrideCustomButtonOption="bootstrapFontAwesome",r.prototype.iconOverridePrefix="fa-";o.injectStyles(".fc-theme-bootstrap a:not([href]){color:inherit}.fc-theme-bootstrap .fc-more-link:hover{text-decoration:none}");var a=t.createPlugin({name:"@fullcalendar/bootstrap",themeClasses:{bootstrap:r}}),n={__proto__:null,BootstrapTheme:r};return t.globalPlugins.push(a),e.Internal=n,e.default=a,Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,FullCalendar.Internal);

View File

@ -0,0 +1,64 @@
/*!
FullCalendar Bootstrap 5 Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/bootstrap5
(c) 2023 Adam Shaw
*/
FullCalendar.Bootstrap5 = (function (exports, core, internal$1) {
'use strict';
class BootstrapTheme extends internal$1.Theme {
}
BootstrapTheme.prototype.classes = {
root: 'fc-theme-bootstrap5',
tableCellShaded: 'fc-theme-bootstrap5-shaded',
buttonGroup: 'btn-group',
button: 'btn btn-primary',
buttonActive: 'active',
popover: 'popover',
popoverHeader: 'popover-header',
popoverContent: 'popover-body',
};
BootstrapTheme.prototype.baseIconClass = 'bi';
BootstrapTheme.prototype.iconClasses = {
close: 'bi-x-lg',
prev: 'bi-chevron-left',
next: 'bi-chevron-right',
prevYear: 'bi-chevron-double-left',
nextYear: 'bi-chevron-double-right',
};
BootstrapTheme.prototype.rtlIconClasses = {
prev: 'bi-chevron-right',
next: 'bi-chevron-left',
prevYear: 'bi-chevron-double-right',
nextYear: 'bi-chevron-double-left',
};
// wtf
BootstrapTheme.prototype.iconOverrideOption = 'buttonIcons'; // TODO: make TS-friendly
BootstrapTheme.prototype.iconOverrideCustomButtonOption = 'icon';
BootstrapTheme.prototype.iconOverridePrefix = 'bi-';
var css_248z = ".fc-theme-bootstrap5 a:not([href]){color:inherit;text-decoration:inherit}.fc-theme-bootstrap5 .fc-list,.fc-theme-bootstrap5 .fc-scrollgrid,.fc-theme-bootstrap5 td,.fc-theme-bootstrap5 th{border:1px solid var(--bs-gray-400)}.fc-theme-bootstrap5 .fc-scrollgrid{border-bottom-width:0;border-right-width:0}.fc-theme-bootstrap5-shaded{background-color:var(--bs-gray-200)}";
internal$1.injectStyles(css_248z);
var plugin = core.createPlugin({
name: '@fullcalendar/bootstrap5',
themeClasses: {
bootstrap5: BootstrapTheme,
},
});
var internal = {
__proto__: null,
BootstrapTheme: BootstrapTheme
};
core.globalPlugins.push(plugin);
exports.Internal = internal;
exports["default"] = plugin;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, FullCalendar.Internal);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Bootstrap 5 Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/bootstrap5
(c) 2023 Adam Shaw
*/
FullCalendar.Bootstrap5=function(e,t,o){"use strict";class r extends o.Theme{}r.prototype.classes={root:"fc-theme-bootstrap5",tableCellShaded:"fc-theme-bootstrap5-shaded",buttonGroup:"btn-group",button:"btn btn-primary",buttonActive:"active",popover:"popover",popoverHeader:"popover-header",popoverContent:"popover-body"},r.prototype.baseIconClass="bi",r.prototype.iconClasses={close:"bi-x-lg",prev:"bi-chevron-left",next:"bi-chevron-right",prevYear:"bi-chevron-double-left",nextYear:"bi-chevron-double-right"},r.prototype.rtlIconClasses={prev:"bi-chevron-right",next:"bi-chevron-left",prevYear:"bi-chevron-double-right",nextYear:"bi-chevron-double-left"},r.prototype.iconOverrideOption="buttonIcons",r.prototype.iconOverrideCustomButtonOption="icon",r.prototype.iconOverridePrefix="bi-";o.injectStyles(".fc-theme-bootstrap5 a:not([href]){color:inherit;text-decoration:inherit}.fc-theme-bootstrap5 .fc-list,.fc-theme-bootstrap5 .fc-scrollgrid,.fc-theme-bootstrap5 td,.fc-theme-bootstrap5 th{border:1px solid var(--bs-gray-400)}.fc-theme-bootstrap5 .fc-scrollgrid{border-bottom-width:0;border-right-width:0}.fc-theme-bootstrap5-shaded{background-color:var(--bs-gray-200)}");var a=t.createPlugin({name:"@fullcalendar/bootstrap5",themeClasses:{bootstrap5:r}}),n={__proto__:null,BootstrapTheme:r};return t.globalPlugins.push(a),e.Internal=n,e.default=a,Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,FullCalendar.Internal);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,29 @@
/*!
FullCalendar Core v6.1.10
Docs & License: https://fullcalendar.io
(c) 2023 Adam Shaw
*/
(function (index_js) {
'use strict';
var locale = {
code: 'en-au',
week: {
dow: 1,
doy: 4, // The week that contains Jan 4th is the first week of the year.
},
buttonHints: {
prev: 'Previous $0',
next: 'Next $0',
today: 'This $0',
},
viewHint: '$0 view',
navLinkHint: 'Go to $0',
moreLinkHint(eventCnt) {
return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`;
},
};
index_js.globalLocales.push(locale);
})(FullCalendar);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Core v6.1.10
Docs & License: https://fullcalendar.io
(c) 2023 Adam Shaw
*/
!function(e){"use strict";var n={code:"en-au",week:{dow:1,doy:4},buttonHints:{prev:"Previous $0",next:"Next $0",today:"This $0"},viewHint:"$0 view",navLinkHint:"Go to $0",moreLinkHint:e=>`Show ${e} more event${1===e?"":"s"}`};FullCalendar.globalLocales.push(n)}();

View File

@ -0,0 +1,29 @@
/*!
FullCalendar Core v6.1.10
Docs & License: https://fullcalendar.io
(c) 2023 Adam Shaw
*/
(function (index_js) {
'use strict';
var locale = {
code: 'en-gb',
week: {
dow: 1,
doy: 4, // The week that contains Jan 4th is the first week of the year.
},
buttonHints: {
prev: 'Previous $0',
next: 'Next $0',
today: 'This $0',
},
viewHint: '$0 view',
navLinkHint: 'Go to $0',
moreLinkHint(eventCnt) {
return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`;
},
};
index_js.globalLocales.push(locale);
})(FullCalendar);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Core v6.1.10
Docs & License: https://fullcalendar.io
(c) 2023 Adam Shaw
*/
!function(e){"use strict";var n={code:"en-gb",week:{dow:1,doy:4},buttonHints:{prev:"Previous $0",next:"Next $0",today:"This $0"},viewHint:"$0 view",navLinkHint:"Go to $0",moreLinkHint:e=>`Show ${e} more event${1===e?"":"s"}`};FullCalendar.globalLocales.push(n)}();

View File

@ -0,0 +1,29 @@
/*!
FullCalendar Core v6.1.10
Docs & License: https://fullcalendar.io
(c) 2023 Adam Shaw
*/
(function (index_js) {
'use strict';
var locale = {
code: 'en-nz',
week: {
dow: 1,
doy: 4, // The week that contains Jan 4th is the first week of the year.
},
buttonHints: {
prev: 'Previous $0',
next: 'Next $0',
today: 'This $0',
},
viewHint: '$0 view',
navLinkHint: 'Go to $0',
moreLinkHint(eventCnt) {
return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`;
},
};
index_js.globalLocales.push(locale);
})(FullCalendar);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Core v6.1.10
Docs & License: https://fullcalendar.io
(c) 2023 Adam Shaw
*/
!function(e){"use strict";var n={code:"en-nz",week:{dow:1,doy:4},buttonHints:{prev:"Previous $0",next:"Next $0",today:"This $0"},viewHint:"$0 view",navLinkHint:"Go to $0",moreLinkHint:e=>`Show ${e} more event${1===e?"":"s"}`};FullCalendar.globalLocales.push(n)}();

View File

@ -0,0 +1,35 @@
/*!
FullCalendar Core v6.1.10
Docs & License: https://fullcalendar.io
(c) 2023 Adam Shaw
*/
(function (index_js) {
'use strict';
var locale = {
code: 'uk',
week: {
dow: 1,
doy: 7, // The week that contains Jan 1st is the first week of the year.
},
buttonText: {
prev: 'Попередній',
next: 'далі',
today: 'Сьогодні',
year: 'рік',
month: 'Місяць',
week: 'Тиждень',
day: 'День',
list: 'Порядок денний',
},
weekText: 'Тиж',
allDayText: 'Увесь день',
moreLinkText(n) {
return '+ще ' + n + '...';
},
noEventsText: 'Немає подій для відображення',
};
index_js.globalLocales.push(locale);
})(FullCalendar);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Core v6.1.10
Docs & License: https://fullcalendar.io
(c) 2023 Adam Shaw
*/
!function(e){"use strict";var t={code:"uk",week:{dow:1,doy:7},buttonText:{prev:"Попередній",next:"далі",today:"Сьогодні",year:"рік",month:"Місяць",week:"Тиждень",day:"День",list:"Порядок денний"},weekText:"Тиж",allDayText:"Увесь день",moreLinkText:e=>"+ще "+e+"...",noEventsText:"Немає подій для відображення"};FullCalendar.globalLocales.push(t)}();

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,150 @@
/*!
FullCalendar Google Calendar Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/google-calendar
(c) 2023 Adam Shaw
*/
FullCalendar.GoogleCalendar = (function (exports, core, internal) {
'use strict';
// TODO: expose somehow
const API_BASE = 'https://www.googleapis.com/calendar/v3/calendars';
const eventSourceDef = {
parseMeta(refined) {
let { googleCalendarId } = refined;
if (!googleCalendarId && refined.url) {
googleCalendarId = parseGoogleCalendarId(refined.url);
}
if (googleCalendarId) {
return {
googleCalendarId,
googleCalendarApiKey: refined.googleCalendarApiKey,
googleCalendarApiBase: refined.googleCalendarApiBase,
extraParams: refined.extraParams,
};
}
return null;
},
fetch(arg, successCallback, errorCallback) {
let { dateEnv, options } = arg.context;
let meta = arg.eventSource.meta;
let apiKey = meta.googleCalendarApiKey || options.googleCalendarApiKey;
if (!apiKey) {
errorCallback(new Error('Specify a googleCalendarApiKey. See https://fullcalendar.io/docs/google-calendar'));
}
else {
let url = buildUrl(meta);
// TODO: make DRY with json-feed-event-source
let { extraParams } = meta;
let extraParamsObj = typeof extraParams === 'function' ? extraParams() : extraParams;
let requestParams = buildRequestParams(arg.range, apiKey, extraParamsObj, dateEnv);
return internal.requestJson('GET', url, requestParams).then(([body, response]) => {
if (body.error) {
errorCallback(new core.JsonRequestError('Google Calendar API: ' + body.error.message, response));
}
else {
successCallback({
rawEvents: gcalItemsToRawEventDefs(body.items, requestParams.timeZone),
response,
});
}
}, errorCallback);
}
},
};
function parseGoogleCalendarId(url) {
let match;
// detect if the ID was specified as a single string.
// will match calendars like "asdf1234@calendar.google.com" in addition to person email calendars.
if (/^[^/]+@([^/.]+\.)*(google|googlemail|gmail)\.com$/.test(url)) {
return url;
}
if ((match = /^https:\/\/www.googleapis.com\/calendar\/v3\/calendars\/([^/]*)/.exec(url)) ||
(match = /^https?:\/\/www.google.com\/calendar\/feeds\/([^/]*)/.exec(url))) {
return decodeURIComponent(match[1]);
}
return null;
}
function buildUrl(meta) {
let apiBase = meta.googleCalendarApiBase;
if (!apiBase) {
apiBase = API_BASE;
}
return apiBase + '/' + encodeURIComponent(meta.googleCalendarId) + '/events';
}
function buildRequestParams(range, apiKey, extraParams, dateEnv) {
let params;
let startStr;
let endStr;
if (dateEnv.canComputeOffset) {
// strings will naturally have offsets, which GCal needs
startStr = dateEnv.formatIso(range.start);
endStr = dateEnv.formatIso(range.end);
}
else {
// when timezone isn't known, we don't know what the UTC offset should be, so ask for +/- 1 day
// from the UTC day-start to guarantee we're getting all the events
// (start/end will be UTC-coerced dates, so toISOString is okay)
startStr = internal.addDays(range.start, -1).toISOString();
endStr = internal.addDays(range.end, 1).toISOString();
}
params = Object.assign(Object.assign({}, (extraParams || {})), { key: apiKey, timeMin: startStr, timeMax: endStr, singleEvents: true, maxResults: 9999 });
if (dateEnv.timeZone !== 'local') {
params.timeZone = dateEnv.timeZone;
}
return params;
}
function gcalItemsToRawEventDefs(items, gcalTimezone) {
return items.map((item) => gcalItemToRawEventDef(item, gcalTimezone));
}
function gcalItemToRawEventDef(item, gcalTimezone) {
let url = item.htmlLink || null;
// make the URLs for each event show times in the correct timezone
if (url && gcalTimezone) {
url = injectQsComponent(url, 'ctz=' + gcalTimezone);
}
return {
id: item.id,
title: item.summary,
start: item.start.dateTime || item.start.date,
end: item.end.dateTime || item.end.date,
url,
location: item.location,
description: item.description,
attachments: item.attachments || [],
extendedProps: (item.extendedProperties || {}).shared || {},
};
}
// Injects a string like "arg=value" into the querystring of a URL
// TODO: move to a general util file?
function injectQsComponent(url, component) {
// inject it after the querystring but before the fragment
return url.replace(/(\?.*?)?(#|$)/, (whole, qs, hash) => (qs ? qs + '&' : '?') + component + hash);
}
const OPTION_REFINERS = {
googleCalendarApiKey: String,
};
const EVENT_SOURCE_REFINERS = {
googleCalendarApiKey: String,
googleCalendarId: String,
googleCalendarApiBase: String,
extraParams: internal.identity,
};
var plugin = core.createPlugin({
name: '@fullcalendar/google-calendar',
eventSourceDefs: [eventSourceDef],
optionRefiners: OPTION_REFINERS,
eventSourceRefiners: EVENT_SOURCE_REFINERS,
});
core.globalPlugins.push(plugin);
exports["default"] = plugin;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, FullCalendar.Internal);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Google Calendar Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/google-calendar
(c) 2023 Adam Shaw
*/
FullCalendar.GoogleCalendar=function(e,a,t){"use strict";const n={parseMeta(e){let{googleCalendarId:a}=e;return!a&&e.url&&(a=function(e){let a;if(/^[^/]+@([^/.]+\.)*(google|googlemail|gmail)\.com$/.test(e))return e;if((a=/^https:\/\/www.googleapis.com\/calendar\/v3\/calendars\/([^/]*)/.exec(e))||(a=/^https?:\/\/www.google.com\/calendar\/feeds\/([^/]*)/.exec(e)))return decodeURIComponent(a[1]);return null}(e.url)),a?{googleCalendarId:a,googleCalendarApiKey:e.googleCalendarApiKey,googleCalendarApiBase:e.googleCalendarApiBase,extraParams:e.extraParams}:null},fetch(e,n,r){let{dateEnv:o,options:l}=e.context,s=e.eventSource.meta,i=s.googleCalendarApiKey||l.googleCalendarApiKey;if(i){let l=function(e){let a=e.googleCalendarApiBase;a||(a="https://www.googleapis.com/calendar/v3/calendars");return a+"/"+encodeURIComponent(e.googleCalendarId)+"/events"}(s),{extraParams:d}=s,g="function"==typeof d?d():d,c=function(e,a,n,r){let o,l,s;r.canComputeOffset?(l=r.formatIso(e.start),s=r.formatIso(e.end)):(l=t.addDays(e.start,-1).toISOString(),s=t.addDays(e.end,1).toISOString());o=Object.assign(Object.assign({},n||{}),{key:a,timeMin:l,timeMax:s,singleEvents:!0,maxResults:9999}),"local"!==r.timeZone&&(o.timeZone=r.timeZone);return o}(e.range,i,g,o);return t.requestJson("GET",l,c).then(([e,t])=>{var o,l;e.error?r(new a.JsonRequestError("Google Calendar API: "+e.error.message,t)):n({rawEvents:(o=e.items,l=c.timeZone,o.map(e=>function(e,a){let t=e.htmlLink||null;t&&a&&(t=function(e,a){return e.replace(/(\?.*?)?(#|$)/,(e,t,n)=>(t?t+"&":"?")+a+n)}(t,"ctz="+a));return{id:e.id,title:e.summary,start:e.start.dateTime||e.start.date,end:e.end.dateTime||e.end.date,url:t,location:e.location,description:e.description,attachments:e.attachments||[],extendedProps:(e.extendedProperties||{}).shared||{}}}(e,l))),response:t})},r)}r(new Error("Specify a googleCalendarApiKey. See https://fullcalendar.io/docs/google-calendar"))}};const r={googleCalendarApiKey:String},o={googleCalendarApiKey:String,googleCalendarId:String,googleCalendarApiBase:String,extraParams:t.identity};var l=a.createPlugin({name:"@fullcalendar/google-calendar",eventSourceDefs:[n],optionRefiners:r,eventSourceRefiners:o});return a.globalPlugins.push(l),e.default=l,Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,FullCalendar.Internal);

View File

@ -0,0 +1,225 @@
/*!
FullCalendar iCalendar Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/icalendar
(c) 2023 Adam Shaw
*/
FullCalendar.ICalendar = (function (exports, core, internal, ICAL) {
'use strict';
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return n;
}
var ICAL__namespace = /*#__PURE__*/_interopNamespace(ICAL);
/* eslint-disable */
class IcalExpander {
constructor(opts) {
this.maxIterations = opts.maxIterations != null ? opts.maxIterations : 1000;
this.skipInvalidDates = opts.skipInvalidDates != null ? opts.skipInvalidDates : false;
this.jCalData = ICAL__namespace.parse(opts.ics);
this.component = new ICAL__namespace.Component(this.jCalData);
this.events = this.component.getAllSubcomponents('vevent').map(vevent => new ICAL__namespace.Event(vevent));
if (this.skipInvalidDates) {
this.events = this.events.filter((evt) => {
try {
evt.startDate.toJSDate();
evt.endDate.toJSDate();
return true;
}
catch (err) {
// skipping events with invalid time
return false;
}
});
}
}
between(after, before) {
function isEventWithinRange(startTime, endTime) {
return (!after || endTime >= after.getTime()) &&
(!before || startTime <= before.getTime());
}
function getTimes(eventOrOccurrence) {
const startTime = eventOrOccurrence.startDate.toJSDate().getTime();
let endTime = eventOrOccurrence.endDate.toJSDate().getTime();
// If it is an all day event, the end date is set to 00:00 of the next day
// So we need to make it be 23:59:59 to compare correctly with the given range
if (eventOrOccurrence.endDate.isDate && (endTime > startTime)) {
endTime -= 1;
}
return { startTime, endTime };
}
const exceptions = [];
this.events.forEach((event) => {
if (event.isRecurrenceException())
exceptions.push(event);
});
const ret = {
events: [],
occurrences: [],
};
this.events.filter(e => !e.isRecurrenceException()).forEach((event) => {
const exdates = [];
event.component.getAllProperties('exdate').forEach((exdateProp) => {
const exdate = exdateProp.getFirstValue();
exdates.push(exdate.toJSDate().getTime());
});
// Recurring event is handled differently
if (event.isRecurring()) {
const iterator = event.iterator();
let next;
let i = 0;
do {
i += 1;
next = iterator.next();
if (next) {
const occurrence = event.getOccurrenceDetails(next);
const { startTime, endTime } = getTimes(occurrence);
const isOccurrenceExcluded = exdates.indexOf(startTime) !== -1;
// TODO check that within same day?
const exception = exceptions.find(ex => ex.uid === event.uid && ex.recurrenceId.toJSDate().getTime() === occurrence.startDate.toJSDate().getTime());
// We have passed the max date, stop
if (before && startTime > before.getTime())
break;
// Check that we are within our range
if (isEventWithinRange(startTime, endTime)) {
if (exception) {
ret.events.push(exception);
}
else if (!isOccurrenceExcluded) {
ret.occurrences.push(occurrence);
}
}
}
} while (next && (!this.maxIterations || i < this.maxIterations));
return;
}
// Non-recurring event:
const { startTime, endTime } = getTimes(event);
if (isEventWithinRange(startTime, endTime))
ret.events.push(event);
});
return ret;
}
before(before) {
return this.between(undefined, before);
}
after(after) {
return this.between(after);
}
all() {
return this.between();
}
}
const eventSourceDef = {
parseMeta(refined) {
if (refined.url && refined.format === 'ics') {
return {
url: refined.url,
format: 'ics',
};
}
return null;
},
fetch(arg, successCallback, errorCallback) {
let meta = arg.eventSource.meta;
let { internalState } = meta;
/*
NOTE: isRefetch is a HACK. we would do the recurring-expanding in a separate plugin hook,
but we couldn't leverage built-in allDay-guessing, among other things.
*/
if (!internalState || arg.isRefetch) {
internalState = meta.internalState = {
response: null,
iCalExpanderPromise: fetch(meta.url, { method: 'GET' }).then((response) => {
return response.text().then((icsText) => {
internalState.response = response;
return new IcalExpander({
ics: icsText,
skipInvalidDates: true,
});
});
}),
};
}
internalState.iCalExpanderPromise.then((iCalExpander) => {
successCallback({
rawEvents: expandICalEvents(iCalExpander, arg.range),
response: internalState.response,
});
}, errorCallback);
},
};
function expandICalEvents(iCalExpander, range) {
// expand the range. because our `range` is timeZone-agnostic UTC
// or maybe because ical.js always produces dates in local time? i forget
let rangeStart = internal.addDays(range.start, -1);
let rangeEnd = internal.addDays(range.end, 1);
let iCalRes = iCalExpander.between(rangeStart, rangeEnd); // end inclusive. will give extra results
let expanded = [];
// TODO: instead of using startDate/endDate.toString to communicate allDay,
// we can query startDate/endDate.isDate. More efficient to avoid formatting/reparsing.
// single events
for (let iCalEvent of iCalRes.events) {
expanded.push(Object.assign(Object.assign({}, buildNonDateProps(iCalEvent)), { start: iCalEvent.startDate.toString(), end: (specifiesEnd(iCalEvent) && iCalEvent.endDate)
? iCalEvent.endDate.toString()
: null }));
}
// recurring event instances
for (let iCalOccurence of iCalRes.occurrences) {
let iCalEvent = iCalOccurence.item;
expanded.push(Object.assign(Object.assign({}, buildNonDateProps(iCalEvent)), { start: iCalOccurence.startDate.toString(), end: (specifiesEnd(iCalEvent) && iCalOccurence.endDate)
? iCalOccurence.endDate.toString()
: null }));
}
return expanded;
}
function buildNonDateProps(iCalEvent) {
return {
title: iCalEvent.summary,
url: extractEventUrl(iCalEvent),
extendedProps: {
location: iCalEvent.location,
organizer: iCalEvent.organizer,
description: iCalEvent.description,
},
};
}
function extractEventUrl(iCalEvent) {
let urlProp = iCalEvent.component.getFirstProperty('url');
return urlProp ? urlProp.getFirstValue() : '';
}
function specifiesEnd(iCalEvent) {
return Boolean(iCalEvent.component.getFirstProperty('dtend')) ||
Boolean(iCalEvent.component.getFirstProperty('duration'));
}
var plugin = core.createPlugin({
name: '@fullcalendar/icalendar',
eventSourceDefs: [eventSourceDef],
});
core.globalPlugins.push(plugin);
exports["default"] = plugin;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, FullCalendar.Internal, ICAL);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar iCalendar Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/icalendar
(c) 2023 Adam Shaw
*/
FullCalendar.ICalendar=function(e,t,n,r){"use strict";function a(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})}})),t.default=e,t}var s=a(r);class i{constructor(e){this.maxIterations=null!=e.maxIterations?e.maxIterations:1e3,this.skipInvalidDates=null!=e.skipInvalidDates&&e.skipInvalidDates,this.jCalData=s.parse(e.ics),this.component=new s.Component(this.jCalData),this.events=this.component.getAllSubcomponents("vevent").map(e=>new s.Event(e)),this.skipInvalidDates&&(this.events=this.events.filter(e=>{try{return e.startDate.toJSDate(),e.endDate.toJSDate(),!0}catch(e){return!1}}))}between(e,t){function n(n,r){return(!e||r>=e.getTime())&&(!t||n<=t.getTime())}function r(e){const t=e.startDate.toJSDate().getTime();let n=e.endDate.toJSDate().getTime();return e.endDate.isDate&&n>t&&(n-=1),{startTime:t,endTime:n}}const a=[];this.events.forEach(e=>{e.isRecurrenceException()&&a.push(e)});const s={events:[],occurrences:[]};return this.events.filter(e=>!e.isRecurrenceException()).forEach(e=>{const i=[];if(e.component.getAllProperties("exdate").forEach(e=>{const t=e.getFirstValue();i.push(t.toJSDate().getTime())}),e.isRecurring()){const o=e.iterator();let c,l=0;do{if(l+=1,c=o.next(),c){const o=e.getOccurrenceDetails(c),{startTime:l,endTime:u}=r(o),d=-1!==i.indexOf(l),p=a.find(t=>t.uid===e.uid&&t.recurrenceId.toJSDate().getTime()===o.startDate.toJSDate().getTime());if(t&&l>t.getTime())break;n(l,u)&&(p?s.events.push(p):d||s.occurrences.push(o))}}while(c&&(!this.maxIterations||l<this.maxIterations));return}const{startTime:o,endTime:c}=r(e);n(o,c)&&s.events.push(e)}),s}before(e){return this.between(void 0,e)}after(e){return this.between(e)}all(){return this.between()}}const o={parseMeta:e=>e.url&&"ics"===e.format?{url:e.url,format:"ics"}:null,fetch(e,t,n){let r=e.eventSource.meta,{internalState:a}=r;a&&!e.isRefetch||(a=r.internalState={response:null,iCalExpanderPromise:fetch(r.url,{method:"GET"}).then(e=>e.text().then(t=>(a.response=e,new i({ics:t,skipInvalidDates:!0}))))}),a.iCalExpanderPromise.then(n=>{t({rawEvents:c(n,e.range),response:a.response})},n)}};function c(e,t){let r=n.addDays(t.start,-1),a=n.addDays(t.end,1),s=e.between(r,a),i=[];for(let e of s.events)i.push(Object.assign(Object.assign({},l(e)),{start:e.startDate.toString(),end:d(e)&&e.endDate?e.endDate.toString():null}));for(let e of s.occurrences){let t=e.item;i.push(Object.assign(Object.assign({},l(t)),{start:e.startDate.toString(),end:d(t)&&e.endDate?e.endDate.toString():null}))}return i}function l(e){return{title:e.summary,url:u(e),extendedProps:{location:e.location,organizer:e.organizer,description:e.description}}}function u(e){let t=e.component.getFirstProperty("url");return t?t.getFirstValue():""}function d(e){return Boolean(e.component.getFirstProperty("dtend"))||Boolean(e.component.getFirstProperty("duration"))}var p=t.createPlugin({name:"@fullcalendar/icalendar",eventSourceDefs:[o]});return t.globalPlugins.push(p),e.default=p,Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,FullCalendar.Internal,ICAL);

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,332 @@
/*!
FullCalendar List View Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/list-view
(c) 2023 Adam Shaw
*/
FullCalendar.List = (function (exports, core, internal$1, preact) {
'use strict';
class ListViewHeaderRow extends internal$1.BaseComponent {
constructor() {
super(...arguments);
this.state = {
textId: internal$1.getUniqueDomId(),
};
}
render() {
let { theme, dateEnv, options, viewApi } = this.context;
let { cellId, dayDate, todayRange } = this.props;
let { textId } = this.state;
let dayMeta = internal$1.getDateMeta(dayDate, todayRange);
// will ever be falsy?
let text = options.listDayFormat ? dateEnv.format(dayDate, options.listDayFormat) : '';
// will ever be falsy? also, BAD NAME "alt"
let sideText = options.listDaySideFormat ? dateEnv.format(dayDate, options.listDaySideFormat) : '';
let renderProps = Object.assign({ date: dateEnv.toDate(dayDate), view: viewApi, textId,
text,
sideText, navLinkAttrs: internal$1.buildNavLinkAttrs(this.context, dayDate), sideNavLinkAttrs: internal$1.buildNavLinkAttrs(this.context, dayDate, 'day', false) }, dayMeta);
// TODO: make a reusable HOC for dayHeader (used in daygrid/timegrid too)
return (preact.createElement(internal$1.ContentContainer, { elTag: "tr", elClasses: [
'fc-list-day',
...internal$1.getDayClassNames(dayMeta, theme),
], elAttrs: {
'data-date': internal$1.formatDayString(dayDate),
}, renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInnerContent, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, (InnerContent) => ( // TODO: force-hide top border based on :first-child
preact.createElement("th", { scope: "colgroup", colSpan: 3, id: cellId, "aria-labelledby": textId },
preact.createElement(InnerContent, { elTag: "div", elClasses: [
'fc-list-day-cushion',
theme.getClass('tableCellShaded'),
] })))));
}
}
function renderInnerContent(props) {
return (preact.createElement(preact.Fragment, null,
props.text && (preact.createElement("a", Object.assign({ id: props.textId, className: "fc-list-day-text" }, props.navLinkAttrs), props.text)),
props.sideText && ( /* not keyboard tabbable */preact.createElement("a", Object.assign({ "aria-hidden": true, className: "fc-list-day-side-text" }, props.sideNavLinkAttrs), props.sideText))));
}
const DEFAULT_TIME_FORMAT = internal$1.createFormatter({
hour: 'numeric',
minute: '2-digit',
meridiem: 'short',
});
class ListViewEventRow extends internal$1.BaseComponent {
render() {
let { props, context } = this;
let { options } = context;
let { seg, timeHeaderId, eventHeaderId, dateHeaderId } = props;
let timeFormat = options.eventTimeFormat || DEFAULT_TIME_FORMAT;
return (preact.createElement(internal$1.EventContainer, Object.assign({}, props, { elTag: "tr", elClasses: [
'fc-list-event',
seg.eventRange.def.url && 'fc-event-forced-url',
], defaultGenerator: () => renderEventInnerContent(seg, context) /* weird */, seg: seg, timeText: "", disableDragging: true, disableResizing: true }), (InnerContent, eventContentArg) => (preact.createElement(preact.Fragment, null,
buildTimeContent(seg, timeFormat, context, timeHeaderId, dateHeaderId),
preact.createElement("td", { "aria-hidden": true, className: "fc-list-event-graphic" },
preact.createElement("span", { className: "fc-list-event-dot", style: {
borderColor: eventContentArg.borderColor || eventContentArg.backgroundColor,
} })),
preact.createElement(InnerContent, { elTag: "td", elClasses: ['fc-list-event-title'], elAttrs: { headers: `${eventHeaderId} ${dateHeaderId}` } })))));
}
}
function renderEventInnerContent(seg, context) {
let interactiveAttrs = internal$1.getSegAnchorAttrs(seg, context);
return (preact.createElement("a", Object.assign({}, interactiveAttrs), seg.eventRange.def.title));
}
function buildTimeContent(seg, timeFormat, context, timeHeaderId, dateHeaderId) {
let { options } = context;
if (options.displayEventTime !== false) {
let eventDef = seg.eventRange.def;
let eventInstance = seg.eventRange.instance;
let doAllDay = false;
let timeText;
if (eventDef.allDay) {
doAllDay = true;
}
else if (internal$1.isMultiDayRange(seg.eventRange.range)) { // TODO: use (!isStart || !isEnd) instead?
if (seg.isStart) {
timeText = internal$1.buildSegTimeText(seg, timeFormat, context, null, null, eventInstance.range.start, seg.end);
}
else if (seg.isEnd) {
timeText = internal$1.buildSegTimeText(seg, timeFormat, context, null, null, seg.start, eventInstance.range.end);
}
else {
doAllDay = true;
}
}
else {
timeText = internal$1.buildSegTimeText(seg, timeFormat, context);
}
if (doAllDay) {
let renderProps = {
text: context.options.allDayText,
view: context.viewApi,
};
return (preact.createElement(internal$1.ContentContainer, { elTag: "td", elClasses: ['fc-list-event-time'], elAttrs: {
headers: `${timeHeaderId} ${dateHeaderId}`,
}, renderProps: renderProps, generatorName: "allDayContent", customGenerator: options.allDayContent, defaultGenerator: renderAllDayInner, classNameGenerator: options.allDayClassNames, didMount: options.allDayDidMount, willUnmount: options.allDayWillUnmount }));
}
return (preact.createElement("td", { className: "fc-list-event-time" }, timeText));
}
return null;
}
function renderAllDayInner(renderProps) {
return renderProps.text;
}
/*
Responsible for the scroller, and forwarding event-related actions into the "grid".
*/
class ListView extends internal$1.DateComponent {
constructor() {
super(...arguments);
this.computeDateVars = internal$1.memoize(computeDateVars);
this.eventStoreToSegs = internal$1.memoize(this._eventStoreToSegs);
this.state = {
timeHeaderId: internal$1.getUniqueDomId(),
eventHeaderId: internal$1.getUniqueDomId(),
dateHeaderIdRoot: internal$1.getUniqueDomId(),
};
this.setRootEl = (rootEl) => {
if (rootEl) {
this.context.registerInteractiveComponent(this, {
el: rootEl,
});
}
else {
this.context.unregisterInteractiveComponent(this);
}
};
}
render() {
let { props, context } = this;
let { dayDates, dayRanges } = this.computeDateVars(props.dateProfile);
let eventSegs = this.eventStoreToSegs(props.eventStore, props.eventUiBases, dayRanges);
return (preact.createElement(internal$1.ViewContainer, { elRef: this.setRootEl, elClasses: [
'fc-list',
context.theme.getClass('table'),
context.options.stickyHeaderDates !== false ?
'fc-list-sticky' :
'',
], viewSpec: context.viewSpec },
preact.createElement(internal$1.Scroller, { liquid: !props.isHeightAuto, overflowX: props.isHeightAuto ? 'visible' : 'hidden', overflowY: props.isHeightAuto ? 'visible' : 'auto' }, eventSegs.length > 0 ?
this.renderSegList(eventSegs, dayDates) :
this.renderEmptyMessage())));
}
renderEmptyMessage() {
let { options, viewApi } = this.context;
let renderProps = {
text: options.noEventsText,
view: viewApi,
};
return (preact.createElement(internal$1.ContentContainer, { elTag: "div", elClasses: ['fc-list-empty'], renderProps: renderProps, generatorName: "noEventsContent", customGenerator: options.noEventsContent, defaultGenerator: renderNoEventsInner, classNameGenerator: options.noEventsClassNames, didMount: options.noEventsDidMount, willUnmount: options.noEventsWillUnmount }, (InnerContent) => (preact.createElement(InnerContent, { elTag: "div", elClasses: ['fc-list-empty-cushion'] }))));
}
renderSegList(allSegs, dayDates) {
let { theme, options } = this.context;
let { timeHeaderId, eventHeaderId, dateHeaderIdRoot } = this.state;
let segsByDay = groupSegsByDay(allSegs); // sparse array
return (preact.createElement(internal$1.NowTimer, { unit: "day" }, (nowDate, todayRange) => {
let innerNodes = [];
for (let dayIndex = 0; dayIndex < segsByDay.length; dayIndex += 1) {
let daySegs = segsByDay[dayIndex];
if (daySegs) { // sparse array, so might be undefined
let dayStr = internal$1.formatDayString(dayDates[dayIndex]);
let dateHeaderId = dateHeaderIdRoot + '-' + dayStr;
// append a day header
innerNodes.push(preact.createElement(ListViewHeaderRow, { key: dayStr, cellId: dateHeaderId, dayDate: dayDates[dayIndex], todayRange: todayRange }));
daySegs = internal$1.sortEventSegs(daySegs, options.eventOrder);
for (let seg of daySegs) {
innerNodes.push(preact.createElement(ListViewEventRow, Object.assign({ key: dayStr + ':' + seg.eventRange.instance.instanceId /* are multiple segs for an instanceId */, seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: false, timeHeaderId: timeHeaderId, eventHeaderId: eventHeaderId, dateHeaderId: dateHeaderId }, internal$1.getSegMeta(seg, todayRange, nowDate))));
}
}
}
return (preact.createElement("table", { className: 'fc-list-table ' + theme.getClass('table') },
preact.createElement("thead", null,
preact.createElement("tr", null,
preact.createElement("th", { scope: "col", id: timeHeaderId }, options.timeHint),
preact.createElement("th", { scope: "col", "aria-hidden": true }),
preact.createElement("th", { scope: "col", id: eventHeaderId }, options.eventHint))),
preact.createElement("tbody", null, innerNodes)));
}));
}
_eventStoreToSegs(eventStore, eventUiBases, dayRanges) {
return this.eventRangesToSegs(internal$1.sliceEventStore(eventStore, eventUiBases, this.props.dateProfile.activeRange, this.context.options.nextDayThreshold).fg, dayRanges);
}
eventRangesToSegs(eventRanges, dayRanges) {
let segs = [];
for (let eventRange of eventRanges) {
segs.push(...this.eventRangeToSegs(eventRange, dayRanges));
}
return segs;
}
eventRangeToSegs(eventRange, dayRanges) {
let { dateEnv } = this.context;
let { nextDayThreshold } = this.context.options;
let range = eventRange.range;
let allDay = eventRange.def.allDay;
let dayIndex;
let segRange;
let seg;
let segs = [];
for (dayIndex = 0; dayIndex < dayRanges.length; dayIndex += 1) {
segRange = internal$1.intersectRanges(range, dayRanges[dayIndex]);
if (segRange) {
seg = {
component: this,
eventRange,
start: segRange.start,
end: segRange.end,
isStart: eventRange.isStart && segRange.start.valueOf() === range.start.valueOf(),
isEnd: eventRange.isEnd && segRange.end.valueOf() === range.end.valueOf(),
dayIndex,
};
segs.push(seg);
// detect when range won't go fully into the next day,
// and mutate the latest seg to the be the end.
if (!seg.isEnd && !allDay &&
dayIndex + 1 < dayRanges.length &&
range.end <
dateEnv.add(dayRanges[dayIndex + 1].start, nextDayThreshold)) {
seg.end = range.end;
seg.isEnd = true;
break;
}
}
}
return segs;
}
}
function renderNoEventsInner(renderProps) {
return renderProps.text;
}
function computeDateVars(dateProfile) {
let dayStart = internal$1.startOfDay(dateProfile.renderRange.start);
let viewEnd = dateProfile.renderRange.end;
let dayDates = [];
let dayRanges = [];
while (dayStart < viewEnd) {
dayDates.push(dayStart);
dayRanges.push({
start: dayStart,
end: internal$1.addDays(dayStart, 1),
});
dayStart = internal$1.addDays(dayStart, 1);
}
return { dayDates, dayRanges };
}
// Returns a sparse array of arrays, segs grouped by their dayIndex
function groupSegsByDay(segs) {
let segsByDay = []; // sparse array
let i;
let seg;
for (i = 0; i < segs.length; i += 1) {
seg = segs[i];
(segsByDay[seg.dayIndex] || (segsByDay[seg.dayIndex] = []))
.push(seg);
}
return segsByDay;
}
const OPTION_REFINERS = {
listDayFormat: createFalsableFormatter,
listDaySideFormat: createFalsableFormatter,
noEventsClassNames: internal$1.identity,
noEventsContent: internal$1.identity,
noEventsDidMount: internal$1.identity,
noEventsWillUnmount: internal$1.identity,
// noEventsText is defined in base options
};
function createFalsableFormatter(input) {
return input === false ? null : internal$1.createFormatter(input);
}
var css_248z = ":root{--fc-list-event-dot-width:10px;--fc-list-event-hover-bg-color:#f5f5f5}.fc-theme-standard .fc-list{border:1px solid var(--fc-border-color)}.fc .fc-list-empty{align-items:center;background-color:var(--fc-neutral-bg-color);display:flex;height:100%;justify-content:center}.fc .fc-list-empty-cushion{margin:5em 0}.fc .fc-list-table{border-style:hidden;width:100%}.fc .fc-list-table tr>*{border-left:0;border-right:0}.fc .fc-list-sticky .fc-list-day>*{background:var(--fc-page-bg-color);position:sticky;top:0}.fc .fc-list-table thead{left:-10000px;position:absolute}.fc .fc-list-table tbody>tr:first-child th{border-top:0}.fc .fc-list-table th{padding:0}.fc .fc-list-day-cushion,.fc .fc-list-table td{padding:8px 14px}.fc .fc-list-day-cushion:after{clear:both;content:\"\";display:table}.fc-theme-standard .fc-list-day-cushion{background-color:var(--fc-neutral-bg-color)}.fc-direction-ltr .fc-list-day-text,.fc-direction-rtl .fc-list-day-side-text{float:left}.fc-direction-ltr .fc-list-day-side-text,.fc-direction-rtl .fc-list-day-text{float:right}.fc-direction-ltr .fc-list-table .fc-list-event-graphic{padding-right:0}.fc-direction-rtl .fc-list-table .fc-list-event-graphic{padding-left:0}.fc .fc-list-event.fc-event-forced-url{cursor:pointer}.fc .fc-list-event:hover td{background-color:var(--fc-list-event-hover-bg-color)}.fc .fc-list-event-graphic,.fc .fc-list-event-time{white-space:nowrap;width:1px}.fc .fc-list-event-dot{border:calc(var(--fc-list-event-dot-width)/2) solid var(--fc-event-border-color);border-radius:calc(var(--fc-list-event-dot-width)/2);box-sizing:content-box;display:inline-block;height:0;width:0}.fc .fc-list-event-title a{color:inherit;text-decoration:none}.fc .fc-list-event.fc-event-forced-url:hover a{text-decoration:underline}";
internal$1.injectStyles(css_248z);
var plugin = core.createPlugin({
name: '@fullcalendar/list',
optionRefiners: OPTION_REFINERS,
views: {
list: {
component: ListView,
buttonTextKey: 'list',
listDayFormat: { month: 'long', day: 'numeric', year: 'numeric' }, // like "January 1, 2016"
},
listDay: {
type: 'list',
duration: { days: 1 },
listDayFormat: { weekday: 'long' }, // day-of-week is all we need. full date is probably in headerToolbar
},
listWeek: {
type: 'list',
duration: { weeks: 1 },
listDayFormat: { weekday: 'long' },
listDaySideFormat: { month: 'long', day: 'numeric', year: 'numeric' },
},
listMonth: {
type: 'list',
duration: { month: 1 },
listDaySideFormat: { weekday: 'long' }, // day-of-week is nice-to-have
},
listYear: {
type: 'list',
duration: { year: 1 },
listDaySideFormat: { weekday: 'long' }, // day-of-week is nice-to-have
},
},
});
var internal = {
__proto__: null,
ListView: ListView
};
core.globalPlugins.push(plugin);
exports.Internal = internal;
exports["default"] = plugin;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, FullCalendar.Internal, FullCalendar.Preact);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,128 @@
/*!
FullCalendar Luxon 1 Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/luxon1
(c) 2023 Adam Shaw
*/
FullCalendar.Luxon = (function (exports, core, luxon, internal) {
'use strict';
function toLuxonDateTime(date, calendar) {
if (!(calendar instanceof internal.CalendarImpl)) {
throw new Error('must supply a CalendarApi instance');
}
let { dateEnv } = calendar.getCurrentData();
return luxon.DateTime.fromJSDate(date, {
zone: dateEnv.timeZone,
locale: dateEnv.locale.codes[0],
});
}
function toLuxonDuration(duration, calendar) {
if (!(calendar instanceof internal.CalendarImpl)) {
throw new Error('must supply a CalendarApi instance');
}
let { dateEnv } = calendar.getCurrentData();
return luxon.Duration.fromObject(Object.assign(Object.assign({}, duration), { locale: dateEnv.locale.codes[0] }));
}
// Internal Utils
function luxonToArray(datetime) {
return [
datetime.year,
datetime.month - 1,
datetime.day,
datetime.hour,
datetime.minute,
datetime.second,
datetime.millisecond,
];
}
function arrayToLuxon(arr, timeZone, locale) {
return luxon.DateTime.fromObject({
zone: timeZone,
locale,
year: arr[0],
month: arr[1] + 1,
day: arr[2],
hour: arr[3],
minute: arr[4],
second: arr[5],
millisecond: arr[6],
});
}
class LuxonNamedTimeZone extends internal.NamedTimeZoneImpl {
offsetForArray(a) {
return arrayToLuxon(a, this.timeZoneName).offset;
}
timestampToArray(ms) {
return luxonToArray(luxon.DateTime.fromMillis(ms, {
zone: this.timeZoneName,
}));
}
}
function formatWithCmdStr(cmdStr, arg) {
let cmd = parseCmdStr(cmdStr);
if (arg.end) {
let start = arrayToLuxon(arg.start.array, arg.timeZone, arg.localeCodes[0]);
let end = arrayToLuxon(arg.end.array, arg.timeZone, arg.localeCodes[0]);
return formatRange(cmd, start.toFormat.bind(start), end.toFormat.bind(end), arg.defaultSeparator);
}
return arrayToLuxon(arg.date.array, arg.timeZone, arg.localeCodes[0]).toFormat(cmd.whole);
}
function parseCmdStr(cmdStr) {
let parts = cmdStr.match(/^(.*?)\{(.*)\}(.*)$/); // TODO: lookbehinds for escape characters
if (parts) {
let middle = parseCmdStr(parts[2]);
return {
head: parts[1],
middle,
tail: parts[3],
whole: parts[1] + middle.whole + parts[3],
};
}
return {
head: null,
middle: null,
tail: null,
whole: cmdStr,
};
}
function formatRange(cmd, formatStart, formatEnd, separator) {
if (cmd.middle) {
let startHead = formatStart(cmd.head);
let startMiddle = formatRange(cmd.middle, formatStart, formatEnd, separator);
let startTail = formatStart(cmd.tail);
let endHead = formatEnd(cmd.head);
let endMiddle = formatRange(cmd.middle, formatStart, formatEnd, separator);
let endTail = formatEnd(cmd.tail);
if (startHead === endHead && startTail === endTail) {
return startHead +
(startMiddle === endMiddle ? startMiddle : startMiddle + separator + endMiddle) +
startTail;
}
}
let startWhole = formatStart(cmd.whole);
let endWhole = formatEnd(cmd.whole);
if (startWhole === endWhole) {
return startWhole;
}
return startWhole + separator + endWhole;
}
var plugin = core.createPlugin({
name: '@fullcalendar/luxon',
cmdFormatter: formatWithCmdStr,
namedTimeZonedImpl: LuxonNamedTimeZone,
});
core.globalPlugins.push(plugin);
exports["default"] = plugin;
exports.toLuxonDateTime = toLuxonDateTime;
exports.toLuxonDuration = toLuxonDuration;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, luxon, FullCalendar.Internal);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Luxon 1 Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/luxon1
(c) 2023 Adam Shaw
*/
FullCalendar.Luxon=function(e,t,n,a){"use strict";function l(e,t,a){return n.DateTime.fromObject({zone:t,locale:a,year:e[0],month:e[1]+1,day:e[2],hour:e[3],minute:e[4],second:e[5],millisecond:e[6]})}class r extends a.NamedTimeZoneImpl{offsetForArray(e){return l(e,this.timeZoneName).offset}timestampToArray(e){return[(t=n.DateTime.fromMillis(e,{zone:this.timeZoneName})).year,t.month-1,t.day,t.hour,t.minute,t.second,t.millisecond];var t}}var o=t.createPlugin({name:"@fullcalendar/luxon",cmdFormatter:function(e,t){let n=function e(t){let n=t.match(/^(.*?)\{(.*)\}(.*)$/);if(n){let t=e(n[2]);return{head:n[1],middle:t,tail:n[3],whole:n[1]+t.whole+n[3]}}return{head:null,middle:null,tail:null,whole:t}}(e);if(t.end){let e=l(t.start.array,t.timeZone,t.localeCodes[0]),a=l(t.end.array,t.timeZone,t.localeCodes[0]);return function e(t,n,a,l){if(t.middle){let r=n(t.head),o=e(t.middle,n,a,l),i=n(t.tail),u=a(t.head),d=e(t.middle,n,a,l),m=a(t.tail);if(r===u&&i===m)return r+(o===d?o:o+l+d)+i}let r=n(t.whole),o=a(t.whole);if(r===o)return r;return r+l+o}(n,e.toFormat.bind(e),a.toFormat.bind(a),t.defaultSeparator)}return l(t.date.array,t.timeZone,t.localeCodes[0]).toFormat(n.whole)},namedTimeZonedImpl:r});return t.globalPlugins.push(o),e.default=o,e.toLuxonDateTime=function(e,t){if(!(t instanceof a.CalendarImpl))throw new Error("must supply a CalendarApi instance");let{dateEnv:l}=t.getCurrentData();return n.DateTime.fromJSDate(e,{zone:l.timeZone,locale:l.locale.codes[0]})},e.toLuxonDuration=function(e,t){if(!(t instanceof a.CalendarImpl))throw new Error("must supply a CalendarApi instance");let{dateEnv:l}=t.getCurrentData();return n.Duration.fromObject(Object.assign(Object.assign({},e),{locale:l.locale.codes[0]}))},Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,luxon,FullCalendar.Internal);

View File

@ -0,0 +1,131 @@
/*!
FullCalendar Luxon 2 Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/luxon2
(c) 2023 Adam Shaw
*/
FullCalendar.Luxon2 = (function (exports, core, luxon, internal) {
'use strict';
function toLuxonDateTime(date, calendar) {
if (!(calendar instanceof internal.CalendarImpl)) {
throw new Error('must supply a CalendarApi instance');
}
let { dateEnv } = calendar.getCurrentData();
return luxon.DateTime.fromJSDate(date, {
zone: dateEnv.timeZone,
locale: dateEnv.locale.codes[0],
});
}
function toLuxonDuration(duration, calendar) {
if (!(calendar instanceof internal.CalendarImpl)) {
throw new Error('must supply a CalendarApi instance');
}
let { dateEnv } = calendar.getCurrentData();
return luxon.Duration.fromObject(duration, {
locale: dateEnv.locale.codes[0],
});
}
// Internal Utils
function luxonToArray(datetime) {
return [
datetime.year,
datetime.month - 1,
datetime.day,
datetime.hour,
datetime.minute,
datetime.second,
datetime.millisecond,
];
}
function arrayToLuxon(arr, timeZone, locale) {
return luxon.DateTime.fromObject({
year: arr[0],
month: arr[1] + 1,
day: arr[2],
hour: arr[3],
minute: arr[4],
second: arr[5],
millisecond: arr[6],
}, {
locale,
zone: timeZone,
});
}
class LuxonNamedTimeZone extends internal.NamedTimeZoneImpl {
offsetForArray(a) {
return arrayToLuxon(a, this.timeZoneName).offset;
}
timestampToArray(ms) {
return luxonToArray(luxon.DateTime.fromMillis(ms, {
zone: this.timeZoneName,
}));
}
}
function formatWithCmdStr(cmdStr, arg) {
let cmd = parseCmdStr(cmdStr);
if (arg.end) {
let start = arrayToLuxon(arg.start.array, arg.timeZone, arg.localeCodes[0]);
let end = arrayToLuxon(arg.end.array, arg.timeZone, arg.localeCodes[0]);
return formatRange(cmd, start.toFormat.bind(start), end.toFormat.bind(end), arg.defaultSeparator);
}
return arrayToLuxon(arg.date.array, arg.timeZone, arg.localeCodes[0]).toFormat(cmd.whole);
}
function parseCmdStr(cmdStr) {
let parts = cmdStr.match(/^(.*?)\{(.*)\}(.*)$/); // TODO: lookbehinds for escape characters
if (parts) {
let middle = parseCmdStr(parts[2]);
return {
head: parts[1],
middle,
tail: parts[3],
whole: parts[1] + middle.whole + parts[3],
};
}
return {
head: null,
middle: null,
tail: null,
whole: cmdStr,
};
}
function formatRange(cmd, formatStart, formatEnd, separator) {
if (cmd.middle) {
let startHead = formatStart(cmd.head);
let startMiddle = formatRange(cmd.middle, formatStart, formatEnd, separator);
let startTail = formatStart(cmd.tail);
let endHead = formatEnd(cmd.head);
let endMiddle = formatRange(cmd.middle, formatStart, formatEnd, separator);
let endTail = formatEnd(cmd.tail);
if (startHead === endHead && startTail === endTail) {
return startHead +
(startMiddle === endMiddle ? startMiddle : startMiddle + separator + endMiddle) +
startTail;
}
}
let startWhole = formatStart(cmd.whole);
let endWhole = formatEnd(cmd.whole);
if (startWhole === endWhole) {
return startWhole;
}
return startWhole + separator + endWhole;
}
var plugin = core.createPlugin({
name: '@fullcalendar/luxon2',
cmdFormatter: formatWithCmdStr,
namedTimeZonedImpl: LuxonNamedTimeZone,
});
core.globalPlugins.push(plugin);
exports["default"] = plugin;
exports.toLuxonDateTime = toLuxonDateTime;
exports.toLuxonDuration = toLuxonDuration;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, luxon, FullCalendar.Internal);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Luxon 2 Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/luxon2
(c) 2023 Adam Shaw
*/
FullCalendar.Luxon2=function(e,t,n,a){"use strict";function l(e,t,a){return n.DateTime.fromObject({year:e[0],month:e[1]+1,day:e[2],hour:e[3],minute:e[4],second:e[5],millisecond:e[6]},{locale:a,zone:t})}class r extends a.NamedTimeZoneImpl{offsetForArray(e){return l(e,this.timeZoneName).offset}timestampToArray(e){return[(t=n.DateTime.fromMillis(e,{zone:this.timeZoneName})).year,t.month-1,t.day,t.hour,t.minute,t.second,t.millisecond];var t}}var o=t.createPlugin({name:"@fullcalendar/luxon2",cmdFormatter:function(e,t){let n=function e(t){let n=t.match(/^(.*?)\{(.*)\}(.*)$/);if(n){let t=e(n[2]);return{head:n[1],middle:t,tail:n[3],whole:n[1]+t.whole+n[3]}}return{head:null,middle:null,tail:null,whole:t}}(e);if(t.end){let e=l(t.start.array,t.timeZone,t.localeCodes[0]),a=l(t.end.array,t.timeZone,t.localeCodes[0]);return function e(t,n,a,l){if(t.middle){let r=n(t.head),o=e(t.middle,n,a,l),i=n(t.tail),u=a(t.head),d=e(t.middle,n,a,l),m=a(t.tail);if(r===u&&i===m)return r+(o===d?o:o+l+d)+i}let r=n(t.whole),o=a(t.whole);if(r===o)return r;return r+l+o}(n,e.toFormat.bind(e),a.toFormat.bind(a),t.defaultSeparator)}return l(t.date.array,t.timeZone,t.localeCodes[0]).toFormat(n.whole)},namedTimeZonedImpl:r});return t.globalPlugins.push(o),e.default=o,e.toLuxonDateTime=function(e,t){if(!(t instanceof a.CalendarImpl))throw new Error("must supply a CalendarApi instance");let{dateEnv:l}=t.getCurrentData();return n.DateTime.fromJSDate(e,{zone:l.timeZone,locale:l.locale.codes[0]})},e.toLuxonDuration=function(e,t){if(!(t instanceof a.CalendarImpl))throw new Error("must supply a CalendarApi instance");let{dateEnv:l}=t.getCurrentData();return n.Duration.fromObject(e,{locale:l.locale.codes[0]})},Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,luxon,FullCalendar.Internal);

View File

@ -0,0 +1,131 @@
/*!
FullCalendar Luxon 3 Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/luxon
(c) 2023 Adam Shaw
*/
FullCalendar.Luxon3 = (function (exports, core, luxon, internal) {
'use strict';
function toLuxonDateTime(date, calendar) {
if (!(calendar instanceof internal.CalendarImpl)) {
throw new Error('must supply a CalendarApi instance');
}
let { dateEnv } = calendar.getCurrentData();
return luxon.DateTime.fromJSDate(date, {
zone: dateEnv.timeZone,
locale: dateEnv.locale.codes[0],
});
}
function toLuxonDuration(duration, calendar) {
if (!(calendar instanceof internal.CalendarImpl)) {
throw new Error('must supply a CalendarApi instance');
}
let { dateEnv } = calendar.getCurrentData();
return luxon.Duration.fromObject(duration, {
locale: dateEnv.locale.codes[0],
});
}
// Internal Utils
function luxonToArray(datetime) {
return [
datetime.year,
datetime.month - 1,
datetime.day,
datetime.hour,
datetime.minute,
datetime.second,
datetime.millisecond,
];
}
function arrayToLuxon(arr, timeZone, locale) {
return luxon.DateTime.fromObject({
year: arr[0],
month: arr[1] + 1,
day: arr[2],
hour: arr[3],
minute: arr[4],
second: arr[5],
millisecond: arr[6],
}, {
locale,
zone: timeZone,
});
}
class LuxonNamedTimeZone extends internal.NamedTimeZoneImpl {
offsetForArray(a) {
return arrayToLuxon(a, this.timeZoneName).offset;
}
timestampToArray(ms) {
return luxonToArray(luxon.DateTime.fromMillis(ms, {
zone: this.timeZoneName,
}));
}
}
function formatWithCmdStr(cmdStr, arg) {
let cmd = parseCmdStr(cmdStr);
if (arg.end) {
let start = arrayToLuxon(arg.start.array, arg.timeZone, arg.localeCodes[0]);
let end = arrayToLuxon(arg.end.array, arg.timeZone, arg.localeCodes[0]);
return formatRange(cmd, start.toFormat.bind(start), end.toFormat.bind(end), arg.defaultSeparator);
}
return arrayToLuxon(arg.date.array, arg.timeZone, arg.localeCodes[0]).toFormat(cmd.whole);
}
function parseCmdStr(cmdStr) {
let parts = cmdStr.match(/^(.*?)\{(.*)\}(.*)$/); // TODO: lookbehinds for escape characters
if (parts) {
let middle = parseCmdStr(parts[2]);
return {
head: parts[1],
middle,
tail: parts[3],
whole: parts[1] + middle.whole + parts[3],
};
}
return {
head: null,
middle: null,
tail: null,
whole: cmdStr,
};
}
function formatRange(cmd, formatStart, formatEnd, separator) {
if (cmd.middle) {
let startHead = formatStart(cmd.head);
let startMiddle = formatRange(cmd.middle, formatStart, formatEnd, separator);
let startTail = formatStart(cmd.tail);
let endHead = formatEnd(cmd.head);
let endMiddle = formatRange(cmd.middle, formatStart, formatEnd, separator);
let endTail = formatEnd(cmd.tail);
if (startHead === endHead && startTail === endTail) {
return startHead +
(startMiddle === endMiddle ? startMiddle : startMiddle + separator + endMiddle) +
startTail;
}
}
let startWhole = formatStart(cmd.whole);
let endWhole = formatEnd(cmd.whole);
if (startWhole === endWhole) {
return startWhole;
}
return startWhole + separator + endWhole;
}
var plugin = core.createPlugin({
name: '@fullcalendar/luxon3',
cmdFormatter: formatWithCmdStr,
namedTimeZonedImpl: LuxonNamedTimeZone,
});
core.globalPlugins.push(plugin);
exports["default"] = plugin;
exports.toLuxonDateTime = toLuxonDateTime;
exports.toLuxonDuration = toLuxonDuration;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, luxon, FullCalendar.Internal);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Luxon 3 Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/luxon
(c) 2023 Adam Shaw
*/
FullCalendar.Luxon3=function(e,t,n,a){"use strict";function l(e,t,a){return n.DateTime.fromObject({year:e[0],month:e[1]+1,day:e[2],hour:e[3],minute:e[4],second:e[5],millisecond:e[6]},{locale:a,zone:t})}class r extends a.NamedTimeZoneImpl{offsetForArray(e){return l(e,this.timeZoneName).offset}timestampToArray(e){return[(t=n.DateTime.fromMillis(e,{zone:this.timeZoneName})).year,t.month-1,t.day,t.hour,t.minute,t.second,t.millisecond];var t}}var o=t.createPlugin({name:"@fullcalendar/luxon3",cmdFormatter:function(e,t){let n=function e(t){let n=t.match(/^(.*?)\{(.*)\}(.*)$/);if(n){let t=e(n[2]);return{head:n[1],middle:t,tail:n[3],whole:n[1]+t.whole+n[3]}}return{head:null,middle:null,tail:null,whole:t}}(e);if(t.end){let e=l(t.start.array,t.timeZone,t.localeCodes[0]),a=l(t.end.array,t.timeZone,t.localeCodes[0]);return function e(t,n,a,l){if(t.middle){let r=n(t.head),o=e(t.middle,n,a,l),i=n(t.tail),u=a(t.head),d=e(t.middle,n,a,l),m=a(t.tail);if(r===u&&i===m)return r+(o===d?o:o+l+d)+i}let r=n(t.whole),o=a(t.whole);if(r===o)return r;return r+l+o}(n,e.toFormat.bind(e),a.toFormat.bind(a),t.defaultSeparator)}return l(t.date.array,t.timeZone,t.localeCodes[0]).toFormat(n.whole)},namedTimeZonedImpl:r});return t.globalPlugins.push(o),e.default=o,e.toLuxonDateTime=function(e,t){if(!(t instanceof a.CalendarImpl))throw new Error("must supply a CalendarApi instance");let{dateEnv:l}=t.getCurrentData();return n.DateTime.fromJSDate(e,{zone:l.timeZone,locale:l.locale.codes[0]})},e.toLuxonDuration=function(e,t){if(!(t instanceof a.CalendarImpl))throw new Error("must supply a CalendarApi instance");let{dateEnv:l}=t.getCurrentData();return n.Duration.fromObject(e,{locale:l.locale.codes[0]})},Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,luxon,FullCalendar.Internal);

View File

@ -0,0 +1,35 @@
/*!
FullCalendar Moment Timezone Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/moment-timezone-plugin
(c) 2023 Adam Shaw
*/
FullCalendar.MomentTimezone = (function (exports, core, moment, internal) {
'use strict';
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
var moment__default = /*#__PURE__*/_interopDefault(moment);
class MomentNamedTimeZone extends internal.NamedTimeZoneImpl {
offsetForArray(a) {
return moment__default["default"].tz(a, this.timeZoneName).utcOffset();
}
timestampToArray(ms) {
return moment__default["default"].tz(ms, this.timeZoneName).toArray();
}
}
var plugin = core.createPlugin({
name: '@fullcalendar/moment-timezone',
namedTimeZonedImpl: MomentNamedTimeZone,
});
core.globalPlugins.push(plugin);
exports["default"] = plugin;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, moment, FullCalendar.Internal);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Moment Timezone Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/moment-timezone-plugin
(c) 2023 Adam Shaw
*/
FullCalendar.MomentTimezone=function(e,t,n,a){"use strict";function l(e){return e&&e.__esModule?e:{default:e}}var r=l(n);class u extends a.NamedTimeZoneImpl{offsetForArray(e){return r.default.tz(e,this.timeZoneName).utcOffset()}timestampToArray(e){return r.default.tz(e,this.timeZoneName).toArray()}}var m=t.createPlugin({name:"@fullcalendar/moment-timezone",namedTimeZonedImpl:u});return t.globalPlugins.push(m),e.default=m,Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,moment,FullCalendar.Internal);

View File

@ -0,0 +1,113 @@
/*!
FullCalendar Moment Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/moment-plugin
(c) 2023 Adam Shaw
*/
FullCalendar.Moment = (function (exports, core, moment, internal) {
'use strict';
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
var moment__default = /*#__PURE__*/_interopDefault(moment);
function toMoment(date, calendar) {
if (!(calendar instanceof internal.CalendarImpl)) {
throw new Error('must supply a CalendarApi instance');
}
let { dateEnv } = calendar.getCurrentData();
return convertToMoment(date, dateEnv.timeZone, null, dateEnv.locale.codes[0]);
}
function toMomentDuration(fcDuration) {
return moment__default["default"].duration(fcDuration); // moment accepts all the props that fc.Duration already has!
}
// Internal Utils
function convertToMoment(input, timeZone, timeZoneOffset, locale) {
let mom;
if (timeZone === 'local') {
mom = moment__default["default"](input);
}
else if (timeZone === 'UTC') {
mom = moment__default["default"].utc(input);
}
else if (moment__default["default"].tz) {
mom = moment__default["default"].tz(input, timeZone);
}
else {
mom = moment__default["default"].utc(input);
if (timeZoneOffset != null) {
mom.utcOffset(timeZoneOffset);
}
}
mom.locale(locale);
return mom;
}
function formatWithCmdStr(cmdStr, arg) {
let cmd = parseCmdStr(cmdStr);
if (arg.end) {
let startMom = convertToMoment(arg.start.array, arg.timeZone, arg.start.timeZoneOffset, arg.localeCodes[0]);
let endMom = convertToMoment(arg.end.array, arg.timeZone, arg.end.timeZoneOffset, arg.localeCodes[0]);
return formatRange(cmd, createMomentFormatFunc(startMom), createMomentFormatFunc(endMom), arg.defaultSeparator);
}
return convertToMoment(arg.date.array, arg.timeZone, arg.date.timeZoneOffset, arg.localeCodes[0]).format(cmd.whole); // TODO: test for this
}
function createMomentFormatFunc(mom) {
return (cmdStr) => (cmdStr ? mom.format(cmdStr) : '' // because calling with blank string results in ISO8601 :(
);
}
function parseCmdStr(cmdStr) {
let parts = cmdStr.match(/^(.*?)\{(.*)\}(.*)$/); // TODO: lookbehinds for escape characters
if (parts) {
let middle = parseCmdStr(parts[2]);
return {
head: parts[1],
middle,
tail: parts[3],
whole: parts[1] + middle.whole + parts[3],
};
}
return {
head: null,
middle: null,
tail: null,
whole: cmdStr,
};
}
function formatRange(cmd, formatStart, formatEnd, separator) {
if (cmd.middle) {
let startHead = formatStart(cmd.head);
let startMiddle = formatRange(cmd.middle, formatStart, formatEnd, separator);
let startTail = formatStart(cmd.tail);
let endHead = formatEnd(cmd.head);
let endMiddle = formatRange(cmd.middle, formatStart, formatEnd, separator);
let endTail = formatEnd(cmd.tail);
if (startHead === endHead && startTail === endTail) {
return startHead +
(startMiddle === endMiddle ? startMiddle : startMiddle + separator + endMiddle) +
startTail;
}
}
let startWhole = formatStart(cmd.whole);
let endWhole = formatEnd(cmd.whole);
if (startWhole === endWhole) {
return startWhole;
}
return startWhole + separator + endWhole;
}
var plugin = core.createPlugin({
name: '@fullcalendar/moment',
cmdFormatter: formatWithCmdStr,
});
core.globalPlugins.push(plugin);
exports["default"] = plugin;
exports.toMoment = toMoment;
exports.toMomentDuration = toMomentDuration;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, moment, FullCalendar.Internal);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Moment Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/moment-plugin
(c) 2023 Adam Shaw
*/
FullCalendar.Moment=function(e,t,l,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}var r=a(l);function u(e,t,l,n){let a;return"local"===t?a=r.default(e):"UTC"===t?a=r.default.utc(e):r.default.tz?a=r.default.tz(e,t):(a=r.default.utc(e),null!=l&&a.utcOffset(l)),a.locale(n),a}function o(e){return t=>t?e.format(t):""}var d=t.createPlugin({name:"@fullcalendar/moment",cmdFormatter:function(e,t){let l=function e(t){let l=t.match(/^(.*?)\{(.*)\}(.*)$/);if(l){let t=e(l[2]);return{head:l[1],middle:t,tail:l[3],whole:l[1]+t.whole+l[3]}}return{head:null,middle:null,tail:null,whole:t}}(e);if(t.end){let e=u(t.start.array,t.timeZone,t.start.timeZoneOffset,t.localeCodes[0]),n=u(t.end.array,t.timeZone,t.end.timeZoneOffset,t.localeCodes[0]);return function e(t,l,n,a){if(t.middle){let r=l(t.head),u=e(t.middle,l,n,a),o=l(t.tail),d=n(t.head),i=e(t.middle,l,n,a),f=n(t.tail);if(r===d&&o===f)return r+(u===i?u:u+a+i)+o}let r=l(t.whole),u=n(t.whole);if(r===u)return r;return r+a+u}(l,o(e),o(n),t.defaultSeparator)}return u(t.date.array,t.timeZone,t.date.timeZoneOffset,t.localeCodes[0]).format(l.whole)}});return t.globalPlugins.push(d),e.default=d,e.toMoment=function(e,t){if(!(t instanceof n.CalendarImpl))throw new Error("must supply a CalendarApi instance");let{dateEnv:l}=t.getCurrentData();return u(e,l.timeZone,null,l.locale.codes[0])},e.toMomentDuration=function(e){return r.default.duration(e)},Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,moment,FullCalendar.Internal);

View File

@ -0,0 +1,249 @@
/*!
FullCalendar Multi-Month Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/multimonth-grid
(c) 2023 Adam Shaw
*/
FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact) {
'use strict';
class SingleMonth extends internal.DateComponent {
constructor() {
super(...arguments);
this.buildDayTableModel = internal.memoize(internal$1.buildDayTableModel);
this.slicer = new internal$1.DayTableSlicer();
this.state = {
labelId: internal.getUniqueDomId(),
};
}
render() {
const { props, state, context } = this;
const { dateProfile, forPrint } = props;
const { options } = context;
const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
// ensure single-month has aspect ratio
const tableHeight = props.tableWidth != null ? props.tableWidth / options.aspectRatio : null;
const rowCnt = dayTableModel.cells.length;
const rowHeight = tableHeight != null ? tableHeight / rowCnt : null;
return (preact.createElement("div", { ref: props.elRef, "data-date": props.isoDateStr, className: "fc-multimonth-month", style: { width: props.width }, role: "grid", "aria-labelledby": state.labelId },
preact.createElement("div", { className: "fc-multimonth-header", style: { marginBottom: rowHeight }, role: "presentation" },
preact.createElement("div", { className: "fc-multimonth-title", id: state.labelId }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
preact.createElement("table", { className: [
'fc-multimonth-header-table',
context.theme.getClass('table'),
].join(' '), role: "presentation" },
preact.createElement("thead", { role: "rowgroup" },
preact.createElement(internal.DayHeader, { dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: false })))),
preact.createElement("div", { className: [
'fc-multimonth-daygrid',
'fc-daygrid',
'fc-daygrid-body',
!forPrint && 'fc-daygrid-body-balanced',
forPrint && 'fc-daygrid-body-unbalanced',
forPrint && 'fc-daygrid-body-natural',
].join(' '), style: { marginTop: -rowHeight } },
preact.createElement("table", { className: [
'fc-multimonth-daygrid-table',
context.theme.getClass('table'),
].join(' '), style: { height: forPrint ? '' : tableHeight }, role: "presentation" },
preact.createElement("tbody", { role: "rowgroup" },
preact.createElement(internal$1.TableRows, Object.assign({}, slicedProps, { dateProfile: dateProfile, cells: dayTableModel.cells, eventSelection: props.eventSelection, dayMaxEvents: !forPrint, dayMaxEventRows: !forPrint, showWeekNumbers: options.weekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: forPrint })))))));
}
}
class MultiMonthView extends internal.DateComponent {
constructor() {
super(...arguments);
this.splitDateProfileByMonth = internal.memoize(splitDateProfileByMonth);
this.buildMonthFormat = internal.memoize(buildMonthFormat);
this.scrollElRef = preact.createRef();
this.firstMonthElRef = preact.createRef();
this.needsScrollReset = false;
this.handleSizing = (isForced) => {
if (isForced) {
this.updateSize();
}
};
}
render() {
const { context, props, state } = this;
const { options } = context;
const { clientWidth, clientHeight } = state;
const monthHPadding = state.monthHPadding || 0;
const colCount = Math.min(clientWidth != null ?
Math.floor(clientWidth / (options.multiMonthMinWidth + monthHPadding)) :
1, options.multiMonthMaxColumns) || 1;
const monthWidthPct = (100 / colCount) + '%';
const monthTableWidth = clientWidth == null ? null :
(clientWidth / colCount) - monthHPadding;
const isLegitSingleCol = clientWidth != null && colCount === 1;
const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, isLegitSingleCol ? false : options.fixedWeekCount, options.showNonCurrentDates);
const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
const rootClassNames = [
'fc-multimonth',
isLegitSingleCol ?
'fc-multimonth-singlecol' :
'fc-multimonth-multicol',
(monthTableWidth != null && monthTableWidth < 400) ?
'fc-multimonth-compact' :
'',
];
return (preact.createElement(internal.ViewContainer, { elRef: this.scrollElRef, elClasses: rootClassNames, viewSpec: context.viewSpec }, monthDateProfiles.map((monthDateProfile, i) => {
const monthStr = internal.formatIsoMonthStr(monthDateProfile.currentRange.start);
return (preact.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, isoDateStr: monthStr, elRef: i === 0 ? this.firstMonthElRef : undefined, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidthPct, tableWidth: monthTableWidth, clientWidth: clientWidth, clientHeight: clientHeight })));
})));
}
componentDidMount() {
this.updateSize();
this.context.addResizeHandler(this.handleSizing);
this.requestScrollReset();
}
componentDidUpdate(prevProps) {
if (!internal.isPropsEqual(prevProps, this.props)) { // an external change?
this.handleSizing(false);
}
if (prevProps.dateProfile !== this.props.dateProfile) {
this.requestScrollReset();
}
else {
this.flushScrollReset();
}
}
componentWillUnmount() {
this.context.removeResizeHandler(this.handleSizing);
}
updateSize() {
const scrollEl = this.scrollElRef.current;
const firstMonthEl = this.firstMonthElRef.current;
if (scrollEl) {
this.setState({
clientWidth: scrollEl.clientWidth,
clientHeight: scrollEl.clientHeight,
});
}
if (firstMonthEl && scrollEl) {
if (this.state.monthHPadding == null) { // always remember initial non-zero value
this.setState({
monthHPadding: scrollEl.clientWidth - // go within padding
firstMonthEl.firstChild.offsetWidth,
});
}
}
}
requestScrollReset() {
this.needsScrollReset = true;
this.flushScrollReset();
}
flushScrollReset() {
if (this.needsScrollReset &&
this.state.monthHPadding != null // indicates sizing already happened
) {
const { currentDate } = this.props.dateProfile;
const scrollEl = this.scrollElRef.current;
const monthEl = scrollEl.querySelector(`[data-date="${internal.formatIsoMonthStr(currentDate)}"]`);
scrollEl.scrollTop = monthEl.getBoundingClientRect().top -
this.firstMonthElRef.current.getBoundingClientRect().top;
this.needsScrollReset = false;
}
}
// workaround for when queued setState render (w/ clientWidth) gets cancelled because
// subsequent update and shouldComponentUpdate says not to render :(
shouldComponentUpdate() {
return true;
}
}
// date profile
// -------------------------------------------------------------------------------------------------
const oneMonthDuration = internal.createDuration(1, 'month');
function splitDateProfileByMonth(dateProfileGenerator, dateProfile, dateEnv, fixedWeekCount, showNonCurrentDates) {
const { start, end } = dateProfile.currentRange;
let monthStart = start;
const monthDateProfiles = [];
while (monthStart.valueOf() < end.valueOf()) {
const monthEnd = dateEnv.add(monthStart, oneMonthDuration);
const currentRange = {
// yuck
start: dateProfileGenerator.skipHiddenDays(monthStart),
end: dateProfileGenerator.skipHiddenDays(monthEnd, -1, true),
};
let renderRange = internal$1.buildDayTableRenderRange({
currentRange,
snapToWeek: true,
fixedWeekCount,
dateEnv,
});
renderRange = {
// yuck
start: dateProfileGenerator.skipHiddenDays(renderRange.start),
end: dateProfileGenerator.skipHiddenDays(renderRange.end, -1, true),
};
const activeRange = dateProfile.activeRange ?
internal.intersectRanges(dateProfile.activeRange, showNonCurrentDates ? renderRange : currentRange) :
null;
monthDateProfiles.push({
currentDate: dateProfile.currentDate,
isValid: dateProfile.isValid,
validRange: dateProfile.validRange,
renderRange,
activeRange,
currentRange,
currentRangeUnit: 'month',
isRangeAllDay: true,
dateIncrement: dateProfile.dateIncrement,
slotMinTime: dateProfile.slotMaxTime,
slotMaxTime: dateProfile.slotMinTime,
});
monthStart = monthEnd;
}
return monthDateProfiles;
}
// date formatting
// -------------------------------------------------------------------------------------------------
const YEAR_MONTH_FORMATTER = internal.createFormatter({ year: 'numeric', month: 'long' });
const YEAR_FORMATTER = internal.createFormatter({ month: 'long' });
function buildMonthFormat(formatOverride, monthDateProfiles) {
return formatOverride ||
((monthDateProfiles[0].currentRange.start.getUTCFullYear() !==
monthDateProfiles[monthDateProfiles.length - 1].currentRange.start.getUTCFullYear())
? YEAR_MONTH_FORMATTER
: YEAR_FORMATTER);
}
const OPTION_REFINERS = {
multiMonthTitleFormat: internal.createFormatter,
multiMonthMaxColumns: Number,
multiMonthMinWidth: Number,
};
var css_248z = ".fc .fc-multimonth{border:1px solid var(--fc-border-color);display:flex;flex-wrap:wrap;overflow-x:hidden;overflow-y:auto}.fc .fc-multimonth-title{font-size:1.2em;font-weight:700;padding:1em 0;text-align:center}.fc .fc-multimonth-daygrid{background:var(--fc-page-bg-color)}.fc .fc-multimonth-daygrid-table,.fc .fc-multimonth-header-table{table-layout:fixed;width:100%}.fc .fc-multimonth-daygrid-table{border-top-style:hidden!important}.fc .fc-multimonth-singlecol .fc-multimonth{position:relative}.fc .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:relative;top:0;z-index:2}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid{position:relative;z-index:1}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid-table,.fc .fc-multimonth-singlecol .fc-multimonth-header-table{border-left-style:hidden;border-right-style:hidden}.fc .fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-daygrid-table{border-bottom-style:hidden}.fc .fc-multimonth-multicol{line-height:1}.fc .fc-multimonth-multicol .fc-multimonth-month{padding:0 1.2em 1.2em}.fc .fc-multimonth-multicol .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);display:block;float:none;padding:1px}.fc .fc-multimonth-compact{line-height:1}.fc .fc-multimonth-compact .fc-multimonth-daygrid-table,.fc .fc-multimonth-compact .fc-multimonth-header-table{font-size:.9em}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{position:sticky}.fc-media-print .fc-multimonth{overflow:visible}";
internal.injectStyles(css_248z);
var plugin = core.createPlugin({
name: '@fullcalendar/multimonth',
initialView: 'multiMonthYear',
optionRefiners: OPTION_REFINERS,
views: {
multiMonth: {
component: MultiMonthView,
dateProfileGeneratorClass: internal$1.TableDateProfileGenerator,
multiMonthMinWidth: 350,
multiMonthMaxColumns: 3,
},
multiMonthYear: {
type: 'multiMonth',
duration: { years: 1 },
fixedWeekCount: true,
showNonCurrentDates: false,
},
},
});
core.globalPlugins.push(plugin);
exports["default"] = plugin;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, FullCalendar.DayGrid.Internal, FullCalendar.Internal, FullCalendar.Preact);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,165 @@
/*!
FullCalendar RRule Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/rrule-plugin
(c) 2023 Adam Shaw
*/
FullCalendar.RRule = (function (exports, core, rruleLib, internal) {
'use strict';
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return n;
}
var rruleLib__namespace = /*#__PURE__*/_interopNamespace(rruleLib);
const recurringType = {
parse(eventProps, dateEnv) {
if (eventProps.rrule != null) {
let eventRRuleData = parseEventRRule(eventProps, dateEnv);
if (eventRRuleData) {
return {
typeData: { rruleSet: eventRRuleData.rruleSet, isTimeZoneSpecified: eventRRuleData.isTimeZoneSpecified },
allDayGuess: !eventRRuleData.isTimeSpecified,
duration: eventProps.duration,
};
}
}
return null;
},
expand(eventRRuleData, framingRange, dateEnv) {
let dates;
if (eventRRuleData.isTimeZoneSpecified) {
dates = eventRRuleData.rruleSet.between(dateEnv.toDate(framingRange.start), // rrule lib will treat as UTC-zoned
dateEnv.toDate(framingRange.end), // (same)
true).map((date) => dateEnv.createMarker(date)); // convert UTC-zoned-date to locale datemarker
}
else {
// when no timezone in given start/end, the rrule lib will assume UTC,
// which is same as our DateMarkers. no need to manipulate
dates = eventRRuleData.rruleSet.between(framingRange.start, framingRange.end, true);
}
return dates;
},
};
function parseEventRRule(eventProps, dateEnv) {
let rruleSet;
let isTimeSpecified = false;
let isTimeZoneSpecified = false;
if (typeof eventProps.rrule === 'string') {
let res = parseRRuleString(eventProps.rrule);
rruleSet = res.rruleSet;
isTimeSpecified = res.isTimeSpecified;
isTimeZoneSpecified = res.isTimeZoneSpecified;
}
if (typeof eventProps.rrule === 'object' && eventProps.rrule) { // non-null object
let res = parseRRuleObject(eventProps.rrule, dateEnv);
rruleSet = new rruleLib__namespace.RRuleSet();
rruleSet.rrule(res.rrule);
isTimeSpecified = res.isTimeSpecified;
isTimeZoneSpecified = res.isTimeZoneSpecified;
}
// convery to arrays. TODO: general util?
let exdateInputs = [].concat(eventProps.exdate || []);
let exruleInputs = [].concat(eventProps.exrule || []);
for (let exdateInput of exdateInputs) {
let res = internal.parseMarker(exdateInput);
isTimeSpecified = isTimeSpecified || !res.isTimeUnspecified;
isTimeZoneSpecified = isTimeZoneSpecified || res.timeZoneOffset !== null;
rruleSet.exdate(new Date(res.marker.valueOf() - (res.timeZoneOffset || 0) * 60 * 1000));
}
// TODO: exrule is deprecated. what to do? (https://icalendar.org/iCalendar-RFC-5545/a-3-deprecated-features.html)
for (let exruleInput of exruleInputs) {
let res = parseRRuleObject(exruleInput, dateEnv);
isTimeSpecified = isTimeSpecified || res.isTimeSpecified;
isTimeZoneSpecified = isTimeZoneSpecified || res.isTimeZoneSpecified;
rruleSet.exrule(res.rrule);
}
return { rruleSet, isTimeSpecified, isTimeZoneSpecified };
}
function parseRRuleObject(rruleInput, dateEnv) {
let isTimeSpecified = false;
let isTimeZoneSpecified = false;
function processDateInput(dateInput) {
if (typeof dateInput === 'string') {
let markerData = internal.parseMarker(dateInput);
if (markerData) {
isTimeSpecified = isTimeSpecified || !markerData.isTimeUnspecified;
isTimeZoneSpecified = isTimeZoneSpecified || markerData.timeZoneOffset !== null;
return new Date(markerData.marker.valueOf() - (markerData.timeZoneOffset || 0) * 60 * 1000); // NOT DRY
}
return null;
}
return dateInput; // TODO: what about number timestamps?
}
let rruleOptions = Object.assign(Object.assign({}, rruleInput), { dtstart: processDateInput(rruleInput.dtstart), until: processDateInput(rruleInput.until), freq: convertConstant(rruleInput.freq), wkst: rruleInput.wkst == null
? (dateEnv.weekDow - 1 + 7) % 7 // convert Sunday-first to Monday-first
: convertConstant(rruleInput.wkst), byweekday: convertConstants(rruleInput.byweekday) });
return { rrule: new rruleLib__namespace.RRule(rruleOptions), isTimeSpecified, isTimeZoneSpecified };
}
function parseRRuleString(str) {
let rruleSet = rruleLib__namespace.rrulestr(str, { forceset: true });
let analysis = analyzeRRuleString(str);
return Object.assign({ rruleSet }, analysis);
}
function analyzeRRuleString(str) {
let isTimeSpecified = false;
let isTimeZoneSpecified = false;
function processMatch(whole, introPart, datePart) {
let result = internal.parseMarker(datePart);
isTimeSpecified = isTimeSpecified || !result.isTimeUnspecified;
isTimeZoneSpecified = isTimeZoneSpecified || result.timeZoneOffset !== null;
}
str.replace(/\b(DTSTART:)([^\n]*)/, processMatch);
str.replace(/\b(EXDATE:)([^\n]*)/, processMatch);
str.replace(/\b(UNTIL=)([^;\n]*)/, processMatch);
return { isTimeSpecified, isTimeZoneSpecified };
}
function convertConstants(input) {
if (Array.isArray(input)) {
return input.map(convertConstant);
}
return convertConstant(input);
}
function convertConstant(input) {
if (typeof input === 'string') {
return rruleLib__namespace.RRule[input.toUpperCase()];
}
return input;
}
const RRULE_EVENT_REFINERS = {
rrule: internal.identity,
exrule: internal.identity,
exdate: internal.identity,
duration: internal.createDuration,
};
var plugin = core.createPlugin({
name: '@fullcalendar/rrule',
recurringTypes: [recurringType],
eventRefiners: RRULE_EVENT_REFINERS,
});
core.globalPlugins.push(plugin);
exports["default"] = plugin;
Object.defineProperty(exports, '__esModule', { value: true });
return exports;
})({}, FullCalendar, rrule, FullCalendar.Internal);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar RRule Plugin v6.1.10
Docs & License: https://fullcalendar.io/docs/rrule-plugin
(c) 2023 Adam Shaw
*/
FullCalendar.RRule=function(e,r,t,i){"use strict";function n(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var i=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,i.get?i:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,r}var l=n(t);const u={parse(e,r){if(null!=e.rrule){let t=function(e,r){let t,n=!1,u=!1;if("string"==typeof e.rrule){let r=function(e){let r=l.rrulestr(e,{forceset:!0}),t=function(e){let r=!1,t=!1;function n(e,n,l){let u=i.parseMarker(l);r=r||!u.isTimeUnspecified,t=t||null!==u.timeZoneOffset}return e.replace(/\b(DTSTART:)([^\n]*)/,n),e.replace(/\b(EXDATE:)([^\n]*)/,n),e.replace(/\b(UNTIL=)([^;\n]*)/,n),{isTimeSpecified:r,isTimeZoneSpecified:t}}(e);return Object.assign({rruleSet:r},t)}(e.rrule);t=r.rruleSet,n=r.isTimeSpecified,u=r.isTimeZoneSpecified}if("object"==typeof e.rrule&&e.rrule){let i=a(e.rrule,r);t=new l.RRuleSet,t.rrule(i.rrule),n=i.isTimeSpecified,u=i.isTimeZoneSpecified}let f=[].concat(e.exdate||[]),s=[].concat(e.exrule||[]);for(let e of f){let r=i.parseMarker(e);n=n||!r.isTimeUnspecified,u=u||null!==r.timeZoneOffset,t.exdate(new Date(r.marker.valueOf()-60*(r.timeZoneOffset||0)*1e3))}for(let e of s){let i=a(e,r);n=n||i.isTimeSpecified,u=u||i.isTimeZoneSpecified,t.exrule(i.rrule)}return{rruleSet:t,isTimeSpecified:n,isTimeZoneSpecified:u}}(e,r);if(t)return{typeData:{rruleSet:t.rruleSet,isTimeZoneSpecified:t.isTimeZoneSpecified},allDayGuess:!t.isTimeSpecified,duration:e.duration}}return null},expand(e,r,t){let i;return i=e.isTimeZoneSpecified?e.rruleSet.between(t.toDate(r.start),t.toDate(r.end),!0).map(e=>t.createMarker(e)):e.rruleSet.between(r.start,r.end,!0),i}};function a(e,r){let t=!1,n=!1;function u(e){if("string"==typeof e){let r=i.parseMarker(e);return r?(t=t||!r.isTimeUnspecified,n=n||null!==r.timeZoneOffset,new Date(r.marker.valueOf()-60*(r.timeZoneOffset||0)*1e3)):null}return e}let a=Object.assign(Object.assign({},e),{dtstart:u(e.dtstart),until:u(e.until),freq:s(e.freq),wkst:null==e.wkst?(r.weekDow-1+7)%7:s(e.wkst),byweekday:f(e.byweekday)});return{rrule:new l.RRule(a),isTimeSpecified:t,isTimeZoneSpecified:n}}function f(e){return Array.isArray(e)?e.map(s):s(e)}function s(e){return"string"==typeof e?l.RRule[e.toUpperCase()]:e}const c={rrule:i.identity,exrule:i.identity,exdate:i.identity,duration:i.createDuration};var o=r.createPlugin({name:"@fullcalendar/rrule",recurringTypes:[u],eventRefiners:c});return r.globalPlugins.push(o),e.default=o,Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,rrule,FullCalendar.Internal);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,79 @@
/*!
FullCalendar Web Component v6.1.10
Docs & License: https://fullcalendar.io/docs/web-component
(c) 2023 Adam Shaw
*/
(function (core) {
'use strict';
class FullCalendarElement extends HTMLElement {
constructor() {
super(...arguments);
this._calendar = null;
this._options = null;
}
connectedCallback() {
this._handleOptionsStr(this.getAttribute('options'));
}
disconnectedCallback() {
this._handleOptionsStr(null);
}
attributeChangedCallback(name, oldVal, newVal) {
if (name === 'options' &&
this._calendar // initial render happened
) {
this._handleOptionsStr(newVal);
}
}
get options() {
return this._options;
}
set options(options) {
this._handleOptions(options);
}
getApi() {
return this._calendar;
}
_handleOptionsStr(optionsStr) {
this._handleOptions(optionsStr ? JSON.parse(optionsStr) : null);
}
_handleOptions(options) {
if (options) {
if (this._calendar) {
this._calendar.resetOptions(options);
}
else {
let root;
if (this.hasAttribute('shadow')) {
this.attachShadow({ mode: 'open' });
root = this.shadowRoot;
}
else {
// eslint-disable-next-line @typescript-eslint/no-this-alias
root = this;
}
root.innerHTML = '<div></div>';
let calendarEl = root.querySelector('div');
let calendar = new core.Calendar(calendarEl, options);
calendar.render();
this._calendar = calendar;
}
this._options = options;
}
else {
if (this._calendar) {
this._calendar.destroy();
this._calendar = null;
}
this._options = null;
}
}
static get observedAttributes() {
return ['options'];
}
}
globalThis.FullCalendarElement = FullCalendarElement;
customElements.define('full-calendar', FullCalendarElement);
})(FullCalendar);

View File

@ -0,0 +1,6 @@
/*!
FullCalendar Web Component v6.1.10
Docs & License: https://fullcalendar.io/docs/web-component
(c) 2023 Adam Shaw
*/
!function(t){"use strict";class e extends HTMLElement{constructor(){super(...arguments),this._calendar=null,this._options=null}connectedCallback(){this._handleOptionsStr(this.getAttribute("options"))}disconnectedCallback(){this._handleOptionsStr(null)}attributeChangedCallback(t,e,n){"options"===t&&this._calendar&&this._handleOptionsStr(n)}get options(){return this._options}set options(t){this._handleOptions(t)}getApi(){return this._calendar}_handleOptionsStr(t){this._handleOptions(t?JSON.parse(t):null)}_handleOptions(e){if(e){if(this._calendar)this._calendar.resetOptions(e);else{let n;this.hasAttribute("shadow")?(this.attachShadow({mode:"open"}),n=this.shadowRoot):n=this,n.innerHTML="<div></div>";let s=n.querySelector("div"),i=new t.Calendar(s,e);i.render(),this._calendar=i}this._options=e}else this._calendar&&(this._calendar.destroy(),this._calendar=null),this._options=null}static get observedAttributes(){return["options"]}}globalThis.FullCalendarElement=e,customElements.define("full-calendar",e)}(FullCalendar);