PageSourceSearch

https://nichbelize.org/wp-content/plugins/pie-calendar/includes/js/piecal.js?ver=1.3.1

js nichbelize.org collected 2026-09-25 18:16:24 UTC 11,418 bytes, 282 lines download raw bytes

1let piecalJS = (function() {
2    const { __ } = wp.i18n;
3    
4    function init( options ) {
5        if( typeof options !== 'object' ) {
6            throw new Error('Options must be an object');
7        }
8
9        if( !options.mode || !getAllowedModes().includes(options.mode) ) {
10            throw new Error('Mode must be one of: ' + getAllowedModes().join(', '));
11        }
12
13        if( !options.container ) {
14            throw new Error('Container must be provided');
15        }
16
17        window.calendarInstances = window.calendarInstances || [];
18
19        let containers = document.querySelectorAll('[data-piecal-instance]');
20        let instance = -1;
21
22        for( let container of containers ) {
23            instance++;
24            container.dataset.piecalInstance = instance;
25
26        let calendar = new FullCalendar.Calendar(container, {
27            headerToolbar: false,
28            initialView: getModeInitialView(options.mode),
29            editable: false,
30            locale: options.locale,
31            contentHeight: 'auto',
32            events: options.events,
33            views: {
34                listMonth: {
35                    duration: {
36                        days: options.lookahead || 30
37                    }
38                }
39            },
40            eventClick: options.eventClick
41        });
42
43        calendar.render();
44
45        window.calendarInstances.push(calendar);
46        }
47    }
48
49    function getAllowedModes() {
50        return ['recurrence-list', 'full'];
51    }
52
53    function getModeInitialView( mode ) {
54        let modeViewMap = {
55            'recurrence-list': 'listMonth',
56            'full': 'dayGridMonth'
57        };
58
59        return modeViewMap[mode];
60    }
61
62    function validateOptions( options ) {
63        let validOptions = {
64            calendarIndex: 'int',
65            appendOffset: 'boolean',
66            useAdaptiveTimezones: 'boolean'
67        };
68    }
69
70    function eventClick( info, options = {} ) {
71        Alpine.store("calendarEngine").eventTitle = info.event._def.title;
72        Alpine.store("calendarEngine").eventStart = info.event.start;
73        Alpine.store("calendarEngine").eventEnd = info.event.end;
74        Alpine.store("calendarEngine").eventDetails = info.event._def.extendedProps.details ?? '';
75        Alpine.store("calendarEngine").eventUrl = info.event._def.extendedProps.permalink;
76        Alpine.store("calendarEngine").eventAllDay = info.event.allDay;
77        Alpine.store("calendarEngine").eventType = info.event._def.extendedProps.postType;
78        Alpine.store('calendarEngine').showPopover = true;
79        Alpine.store('calendarEngine').eventActualEnd = info.event._def.extendedProps.actualEnd;
80        Alpine.store('calendarEngine').appendOffset = options.appendOffset;
81
82        // Always pass through event data via the URL if it's a recurring instance, or if adaptive timezones are enabled.
83        // Do not pass through event data via the URL if it's a non-recurring instance and adaptive timezones are disabled.
84        if( info.event._def.extendedProps.isRecurringInstance || 
85            ( !info.event._def.extendedProps.isRecurringInstance && piecalVars.useAdaptiveTimezones && Alpine.store('calendarEngine').appendOffset ) &&
86            info.event._def.extendedProps.permalink ) {
87
88            // Construct the URL with parameters
89            const baseUrl    = info.event._def.extendedProps.permalink;
90            const eventStart = new Date( info.event.start );
91            const eventEnd   = new Date( info.event.end );
92            const viewerTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
93
94
95            const url        = new URL( baseUrl );
96            url.searchParams.append( 'eventstart', Math.floor( eventStart.getTime() / 1000 ) );
97            url.searchParams.append( 'eventend', Math.floor( eventEnd.getTime() / 1000 ) );
98            url.searchParams.append( 'timezone', viewerTimezone );
99
100            // Assign the constructed URL to the store
101            Alpine.store("calendarEngine").eventUrl = url.toString();
102        }
103
104        if( info.jsEvent.type == "keydown" ) {
105            setTimeout( () => {
106                document.querySelector('.piecal-popover__inner > button').focus();
107            }, 100);
108        }
109
110        return info;
111    }
112
113    function eventDidMount( info, options = {} ) {
114        let link = info.el;
115
116        const locale = info.view.dateEnv.locale.codeArg;
117
118        const formattedTime = new Intl.DateTimeFormat(locale, {
119            hour: 'numeric',
120            minute: 'numeric',
121            hour12: true
122        });
123
124        const formattedDate = new Intl.DateTimeFormat(locale, {
125            day: 'numeric',
126            month: 'numeric',
127            year: 'numeric'
128        });
129
130        if( link.tagName == 'TR' ) {
131            link = info.el.querySelector('a');
132        }
133
134        if( !link || link.tagName != "A" ) return;
135
136        link.setAttribute('role', 'button');
137        link.setAttribute('href', 'javascript:void(0)');
138
139        if( info.event.allDay ) {
140            const allDayDescriptionText = __('All-day event', 'piecal');
141
142            link.setAttribute('aria-label', `${allDayDescriptionText} - ${info.event.title}`);
143        }
144
145        // Handle multi-day event aria label to let screen readers know the event spans multiple days
146        if( info.event.end && (info.event.end - info.event.start) > (24 * 60 * 60 * 1000) ) {
147            const startDate = formattedDate.format(info.event.start);
148            const startTime = info.event.allDay ? '' : formattedTime.format(info.event.start);
149
150            const endDate = formattedDate.format(info.event.end);
151            const endTime = info.event.allDay ? '' :formattedTime.format(info.event.end);
152
153            /* Translators: Text describing span of multi-day event. */
154            const spanText = __('to', 'piecal');
155
156            /* Translators: Text for multi-day event description. */
157            const multiDayDescriptionText = __('Multi-day event running from', 'piecal'); // <?php _e("'Multi-day event running from'", 'piecal'); ?>;
158
159            /* Translators: Text for multi-day all-day event description. */
160            const multiDayAllDayDescriptionText = __('Multi-day, all-day event running from', 'piecal'); // <?php _e("'Multi-day, all-day event running from'", 'piecal'); ?>;
161
162            const descriptionText = info.event.allDay ? multiDayAllDayDescriptionText : multiDayDescriptionText;
163
164            /* Translators: Text describing span of multi-day event. */
165            link.setAttribute('aria-label', `${descriptionText} ${startDate} ${startTime} ${spanText} ${endDate} ${endTime} - ${info.event.title}`);
166        }
167
168        return info;
169    }
170
171    function dayCellDidMount( info, options = {} ) {
172        let dayLink = info.el.querySelector('.fc-daygrid-day-top a');
173
174        if( !dayLink ) return;
175
176        dayLink.setAttribute('role', 'button');
177        dayLink.setAttribute('href', 'javascript:void(0)');
178
179        // Prevent double read out of button label
180        dayLink.closest('td').removeAttribute('aria-labelledby');
181        
182        setTimeout( () => {
183            if( info.el.querySelector('.fc-daygrid-day-events .fc-daygrid-event-harness') ) {
184                dayLink.setAttribute('aria-label', dayLink.getAttribute('aria-label') + ', has events.');
185            }
186        }, 100);
187
188        dayLink.addEventListener('keydown', (event) => {
189            if( event.key == "Enter" || event.key == ' ' ) {
190                event.preventDefault();
191                window.calendar.gotoDate(info.date);
192                piecalChangeView('listDay');
193
194                setTimeout( () => {
195                    let focusTarget = document.querySelector('.fc-list-day-text');
196                    focusTarget?.setAttribute('tabindex', '0');
197                    focusTarget?.focus();
198                }, 100);
199            }
200        })
201
202        return info;
203    }
204
205    function eventDataTransform( event, options = {} ) {
206         // Safely decode encoded HTML entities for output as titles
207         let scrubber = document.createElement('textarea');
208         scrubber.innerHTML = event.title;
209         event.title = scrubber.value;
210
211         // Extend end date for all day events that span multiple days
212         let { actualEnd, end } = piecalUtils.getAlldayMultidayEventEnd( event ) ?? {};
213
214         if( actualEnd && end ) {    
215             event.actualEnd = actualEnd;
216             event.end = end;
217         }
218
219         return event;
220    }
221
222    function dateClick( info, options = {} ) {
223        if( info.jsEvent.target.tagName != 'A' ) return;
224
225        if( !options.calendarIndex ) {
226            window.calendar.gotoDate(info.dateStr);
227        } else {
228            window.calendarInstances[options.calendarIndex].gotoDate(info.dateStr);
229        }
230
231        piecalChangeView('listDay');
232
233        return info;
234    }
235
236    function dayHeaderContent( info, options = {} ) {
237        let overriddenDayHeaderViews = ['dayGridMonth', 'timeGridWeek', 'dayGridWeek'];
238
239        if( overriddenDayHeaderViews.includes(info.view.type) ) {
240            return '';
241        }
242
243        return info;
244    }
245
246    function dayHeaderDidMount( info, options = {} ) {
247        let dayHeaderLink = info.el.querySelector('a');
248
249        if( !dayHeaderLink ) return;
250
251        let fullDayName = piecalUtils.getLocalizedDayNames(info.text, 'full', options.locale );
252        let shortDayName = piecalUtils.getLocalizedDayNames(info.text, 'short', options.locale );
253        let singleLetterDayName = piecalUtils.getLocalizedDayNames(info.text, 'single', options.locale );
254
255        let shortenableViews = ['dayGridMonth', 'timeGridWeek', 'dayGridWeek', 'listWeek'];
256        let viewsWithDates = ['timeGridWeek', 'listWeek', 'dayGridWeek'];
257
258        if( shortenableViews.includes(info.view.type) ) {
259            if( viewsWithDates.includes(info.view.type) && options.showDates != false ) {
260                // Format the date from info.date
261                const dateFormatter = new Intl.DateTimeFormat(info.view.dateEnv.locale.codeArg, {
262                    month: 'numeric',
263                    day: 'numeric'
264                });
265                const formattedDate = dateFormatter.format(info.date);
266
267                dayHeaderLink.innerHTML = `<span class="piecal-grid-day-header-text piecal-grid-day-header-text--full">${fullDayName} ${formattedDate}</span>
268                                           <span class="piecal-grid-day-header-text piecal-grid-day-header-text--short">${shortDayName} ${formattedDate}</span>
269                                           <span class="piecal-grid-day-header-text piecal-grid-day-header-text--single-letter">${singleLetterDayName} ${formattedDate}</span>`;
270            } else {
271                dayHeaderLink.innerHTML = `<span class="piecal-grid-day-header-text piecal-grid-day-header-text--full">${fullDayName}</span>
272                                           <span class="piecal-grid-day-header-text piecal-grid-day-header-text--short">${shortDayName}</span>
273                                           <span class="piecal-grid-day-header-text piecal-grid-day-header-text--single-letter">${singleLetterDayName}</span>`;
274            }
275        }
276
277        return info;
278    }
279
280    // Return methods that should be accessible when invoking piecalJS.
281    return {init, eventDidMount, dayCellDidMount, eventClick, eventDataTransform, dateClick, dayHeaderContent, dayHeaderDidMount};
282})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.