PageSourceSearch

https://www.northampton.edu/events/_files/js/hh-events.js

js northampton.edu collected 2026-10-01 13:54:47 UTC 96,108 bytes, 2,082 lines download raw bytes

1/* calendar */
2var urlHashes = ['v=', 'f1=', 'f2=', 'f3=', 'f4=', 'f5=', 'f6=', 'f7=', 'f8=', 'f9=', 'f10='];
3var vHashes = [];
4var f1Hashes = [];
5var f2Hashes = [];
6var f3Hashes = [];
7var f4Hashes = [];
8var f5Hashes = [];
9var f6Hashes = [];
10var f7Hashes = [];
11var f8Hashes = [];
12var f9Hashes = [];
13var f10Hashes = [];
14var allHashes = "";
15var today = moment();
16var currentDate = today.format('D');
17var currentMonth = today.format('MM');
18var currentYear = today.format('YYYY');
19var nextMonth = today.add(1, 'month').format('MM');
20if (nextMonth == "01") {
21    var nextMonthYear = today.add(1, 'year').format('YYYY');
22} else {
23    var nextMonthYear = today.format('YYYY');
24}
25var previousMonth = today.subtract(1, 'month').format('MM');
26if (previousMonth == "12") {
27    var previousMonthYear = today.subtract(1, 'year').format('YYYY');
28} else {
29    var previousMonthYear = today.format('YYYY');
30}
31var checkedEvents = [];
32var allData = [];
33var allDataURLs = [];
34var currentDataURLs = [];
35var currentData = [];
36var sideFeatures = [];
37var sideFeaturesURL = [];
38var currentLoadedView = defaultView;
39var lastLoadedMonth = "";
40var lastLoadedYear = "";
41var currentURL = window.location.href;
42var hash = "";
43var newHash = "";
44var hashClass = "";
45var hashArray = [];
46var newHashArray = [];
47var newSetHashArray = [];
48var setFiltersLoad = "";
49var $eventsContainer = $(".events .events-list");
50var $featuredEventsContainer = $(".featured-events-list");
51var eventList = "";
52var eventItem = "";
53var $loadMoreContainer = $(".events .load-more");
54var $eventViewHeader = $("#events-view");
55var $eventViewCountDisplay = $(".events-results .event-count");
56var $eventFilterViewCountDisplay = $(".events-results .filter-count");
57var $eventsMessageContainer = $(".events-results .events-message");
58var eventsMessage = "";
59var errorMessage = false;
60var rangeDates = [];
61var rangeDateStart = "";
62var rangeDateEnd = "";
63var startYearRange = "";
64var endYearRange = "";
65var startMonthRange = "";
66var endMonthRange = "";
67var startDayRange = "";
68var endDayRange = "";
69var singleDate = "";
70var singleDateYear = "";
71var singleDateMonth = "";
72var singleDateDay = "";
73var startDate = "";
74var endDate = "";
75
76$(document).ready(function() {
77    $(window).scroll(function() {
78        if ($(this).scrollTop() > 100) {
79            $(".hh-module #back-to-top").fadeIn();
80        } else {
81            $(".hh-module  #back-to-top").fadeOut();
82        }
83    });
84    $(".hh-module  #back-to-top").click(function() {
85        $("body,html").animate({
86            scrollTop: 0
87        }, 800);
88        return false;
89    });
90    if ($('.events-listing').length) {
91        $('#mini-calendar .input-daterange').datepicker({
92            todayHighlight: true,
93        });
94        $('#startDate').datepicker().on('changeDate', function(startDateData) {
95            $eventsContainer.empty();
96            startDate = moment(startDateData.date).format("MM/DD/YYYY");
97            if (endDate == "" || endDate == startDate) {
98                setHash("v=", "replace", startDate, function() {
99                    eventCount();
100                    loadView(startDate).then(function(results) {
101                        showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
102                    });
103                });
104            } else {
105                setHash("v=", "replace", startDate + "-" + endDate, function() {
106                    eventCount();
107                    loadView(startDate + "-" + endDate).then(function(results) {
108                        showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
109                    });
110                });
111            }
112        });
113        $('#endDate').datepicker().on('changeDate', function(endDateData) {
114            $eventsContainer.empty();
115            if (startDate != "") {
116                endDate = moment(endDateData.date).format("MM/DD/YYYY");
117                if (startDate == endDate) {
118                    setHash("v=", "replace", startDate, function() {
119                        loadView(startDate).then(function(results) {
120                            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
121                        });
122                    });
123                } else {
124                    setHash("v=", "replace", startDate + "-" + endDate, function() {
125                        loadView(startDate + "-" + endDate).then(function(results) {
126                            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
127                        });
128                    });
129                }
130            }
131        });
132        $(".date-views button").click(function() {
133            $(".date-views button").each(function() {
134                $(this).removeClass("active");
135            });
136            $(this).addClass("active");
137        });
138        $eventsContainer.tooltip({
139            selector: "[data-toggle='tooltip']"
140        });
141        $(".hh-events .plus-toggle").click(function() {
142            $(".hh-events .plus-toggle").toggleClass("fa-plus-circle fa-minus-circle");
143            $(".hh-events .sidebar").toggleClass("expanded collapsed");
144            if ($(".hh-events .sidebar").hasClass("expanded")) {
145                $(".hh-events .plus-toggle").attr("title", "Collapse");
146                $(".hh-events .plus-toggle ~ span").html("Collapse");
147            } else {
148                $(".hh-events .plus-toggle").attr("title", "Expand");
149                $(".hh-events .plus-toggle ~ span").html("Expand");
150            }
151        });
152        $(".checkboxes input").click(function() {
153            $(this).blur();
154        });
155        $(".events").on('click', '.loadMoreEvents', function() {
156            if (debugMode) {
157                console.log("------------------------");
158                console.log("loadMoreEvents");
159            }
160            showEvents(currentData, currentLoadedView, $eventsContainer, loadMoreCount, "loadMore");
161            searchText($("#search").val().toLowerCase());
162        });
163        $(".events").on('click', '.loadAllEvents', function() {
164            if (debugMode) {
165                console.log("------------------------");
166                console.log("loadAllEvents");
167            }
168            showEvents(currentData, currentLoadedView, $eventsContainer, "all", "loadAll");
169            searchText($("#search").val().toLowerCase());
170        });
171        $(".clearAll").on("click", function() {
172            if (debugMode) {
173                console.log("------------------------");
174                console.log("clearAll");
175            }
176            $(this).blur();
177            $eventFilterViewCountDisplay.empty();
178            $eventViewCountDisplay.empty();
179            $('.input-daterange input').datepicker('update', null);
180            $('.input-daterange').datepicker('updateDates');
181            removeHash();
182            $("#search").val('');
183            setViewsLoad = "";
184            setFiltersLoad = "";
185            $("select.loadFilter").val("*");
186            $(".loadFilter:checkbox:checked").each(function() {
187                $(this).prop("checked", false);
188            });
189            $(".date-views button").each(function() {
190                $(this).removeClass("active");
191            });
192            loadView(defaultView, "", "", "clearAll").then(function(results) {
193                showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
194            });
195        });
196        checkHash();
197        $(window).on('popstate', function() {
198            checkHash();
199        });
200    }
201    if ($('.events-detail').length) {
202        $('.events-detail').tooltip({
203            selector: "[data-toggle='tooltip']"
204        });
205        if ($('.events-detail .sTime').length) {
206            var sZone = moment.tz.guess();
207            var sTimezone = moment.tz(sZone).zoneAbbr();
208            $(".events-detail .sTime").append(timeOutput(thisCurrentEvent[0].startDate, thisCurrentEvent[0].endDate, thisCurrentEvent[0].allDay, thisCurrentEvent[0].originalStart, thisCurrentEvent[0].originalEnd));
209            if (thisCurrentEvent[0].allDay != "true") {
210                $(".events-detail .sTime").append(" " + sTimezone);
211            }
212        }
213        if ($('.events-detail .rDate').length) {
214            currentRecurringEvent();
215            $("#rDates").change(function(e) {
216                $(".save-row .feeds").empty();
217                $(".save-row .feeds").append(saveLinkOutput($(this).find(':selected').data('title'), $(this).find(':selected').data('desc'), $(this).find(':selected').data('start'), $(this).find(':selected').data('end'), $(this).find(':selected').data('timezone'), $(this).find(':selected').data('allDay'), "google"));
218                $(".save-row .feeds").append(saveLinkOutput($(this).find(':selected').data('title'), $(this).find(':selected').data('desc'), $(this).find(':selected').data('start'), $(this).find(':selected').data('end'), $(this).find(':selected').data('timezone'), $(this).find(':selected').data('allDay'), "outlook"));
219                $(".save-row .feeds").append(saveLinkOutput($(this).find(':selected').data('title'), $(this).find(':selected').data('desc'), $(this).find(':selected').data('start'), $(this).find(':selected').data('end'), $(this).find(':selected').data('timezone'), $(this).find(':selected').data('allDay'), "yahoo"));
220                $(".save-row .feeds").append(saveLinkOutput($(this).find(':selected').data('title'), $(this).find(':selected').data('desc'), $(this).find(':selected').data('start'), $(this).find(':selected').data('end'), $(this).find(':selected').data('timezone'), $(this).find(':selected').data('allDay'), "ics"));
221            });
222            setTimeout(function() {
223                if ($('.events-detail .related-events').length) {
224                    relatedEventsAjax();
225                }
226            }, 300);
227        } else {
228            if ($('.events-detail .related-events').length) {
229                relatedEventsAjax();
230            }
231        }
232    }
233    if ($('.hh-events-block').length) {
234        blockEvents();
235    }
236});
237
238/* data */
239
240function checkDataURLs(data, view, target, showLimit, origin) {
241    return new Promise(function(resolve, reject) {
242        if (debugMode) {
243            console.log("checkDataURLs");
244        }
245        awaitAll(data, getDataFromURLs).then(function(results) {
246            var URLData = [];
247            for (let i = 0; i < results.length; i++) {
248                URLData = URLData.concat(results[i]);
249            }
250            URLData = _.uniqBy(URLData, 'id');
251            calculateRecurrences(URLData).then(function(resultsR) {
252                eventDateChecker(URLData, resultsR, view).then(function(results) {
253                    jsonToCurrentData(results).then(function(results) {
254                        results.jsonToCurrentDataEvents.sort(function(a, b) {
255                            return +new Date(a.startDate) - +new Date(b.startDate);
256                        });
257                        resolve({
258                            "events": results.jsonToCurrentDataEvents,
259                            "view": view,
260                            "target": target,
261                            "showLimit": showLimit,
262                            "origin": origin
263                        });
264                    });
265                });
266            });
267        });
268    })
269}
270
271function getFeaturedDataFromURLs(currentDataURL) {
272    return new Promise(function(resolve, reject) {
273        if (debugMode) {
274            console.log("getFeaturedDataFromURLs: " + currentDataURL);
275        }
276        $.ajax({
277            url: currentDataURL,
278            success: function(data) {
279                resolve(data.events);
280            },
281            error: function(data) {
282                if (data.status == 200) {
283                    resolve({
284                        Error: "JSON Not Valid: " + currentDataURL
285                    });
286                    console.log("JSON Not Valid: " + currentDataURL);
287                } else {
288                    resolve({
289                        Error: "Data URL Not Found: " + currentDataURL
290                    });
291                    console.log("Data URL Not Found: " + currentDataURL);
292                }
293            }
294        });
295    })
296}
297
298function getDataFromURLs(currentDataURL) {
299    return new Promise(function(resolve, reject) {
300        if (_.includes(allDataURLs, currentDataURL)) {
301            if (debugMode) {
302                console.log("getDataFromURLs bypassed: " + currentDataURL);
303                console.log({
304                    "allDataIn": allData
305                });
306            }
307            resolve(allData);
308        } else {
309            if (debugMode) {
310                console.log("getDataFromURLs: " + currentDataURL);
311            }
312            $.ajax({
313                url: currentDataURL,
314                success: function(data) {
315                    if (debugMode) {
316                        console.log({
317                            "allDataOut": allData
318                        });
319                        console.log({
320                            "newDataIn": data.events
321                        });
322                    }
323                    if(data.events != undefined){
324                        allData = allData.concat(data.events);
325                    }
326                    
327                    // allData = _.filter(allData, _.isEmpty);
328                    if (debugMode) {
329                        console.log({
330                            "allData": allData
331                        });
332                    }
333                    resolve(allData);
334                
335                    // resolve(data.events);
336                    allDataURLs.push(currentDataURL);
337                },
338                error: function(data) {
339                    if (data.status == 200) {
340                        resolve({
341                            Error: "JSON Not Valid: " + currentDataURL
342                        });
343                        console.log("JSON Not Valid: " + currentDataURL);
344                    } else {
345                        resolve({
346                            Error: "Data URL Not Found: " + currentDataURL
347                        });
348                        console.log("Data URL Not Found: " + currentDataURL);
349                    }
350                }
351            });
352        }
353    })
354}
355
356function eventDateChecker(data, dataR, view) {
357    return new Promise(function(resolve, reject) {
358        checkedEvents = [];
359        if (debugMode) {
360            console.log("eventDateChecker: " + view);
361        }
362        if (view === "featured" || view === "side-featured-events") {
363            if (data != undefined && data.length != 0) {
364                for (let i = 0; i < data.length; i++) {
365                    if (data[i] != undefined && data[i].featured == "true" && data[i].recurringEvent != "true") {
366                        eventDateCheck(data[i], view);
367                    }
368                }
369            }
370            if (dataR != undefined && dataR.length != 0) {
371                for (let i = 0; i < dataR.length; i++) {
372                    if (dataR[i] != undefined && dataR[i].featured == "true") {
373                        eventDateCheck(dataR[i], view);
374                    }
375                }
376            }
377        } else {
378            if (data != undefined && data.length != 0) {
379                for (let i = 0; i < data.length; i++) {
380                    if (data[i] != undefined){
381                        if(data[i].recurringEvent != undefined && data[i].recurringEvent != "true") {
382                            eventDateCheck(data[i], view);
383                        }
384                    }
385                }
386            }
387            if (dataR != undefined && dataR.length != 0) {
388                for (let i = 0; i < dataR.length; i++) {
389                    eventDateCheck(dataR[i], view);
390                }
391            }
392        }
393        if (debugMode) {
394            console.log({"checkedEvents": checkedEvents});
395        }
396        resolve(checkedEvents);
397    });
398}
399
400function eventDateCheck(v, view) {
401    if (v.startDate != undefined) {
402        var startDateM = moment(v.startDate);
403        if (view === "upcoming-events" || view === "featured" || view === "side-featured-events" || view === "related-events" || view === "current-recurring-event" || view === "hh-events-block") {
404            if (startDateM.isSameOrAfter(moment())) {
405                checkedEvents.push(v);
406            }
407        } else if (view === "today") {
408            if (moment().isSame(startDateM, 'date')) {
409                checkedEvents.push(v);
410            }
411        } else if (view === "tomorrow") {
412            if (moment(moment().add(1, 'days')).isSame(startDateM, 'date')) {
413                checkedEvents.push(v);
414            }
415        } else if (view === "this-week") {
416            if (moment(startDateM).isSameOrAfter(moment().weekday(0), "day") && moment(startDateM).isSameOrBefore(moment().weekday(6), "day")) {
417                checkedEvents.push(v);
418            }
419        } else if (view === "this-weekend") {
420            if (moment(startDateM).isSameOrAfter(moment().weekday(5), "day") && moment(startDateM).isSameOrBefore(moment().weekday(7), "day")) {
421                checkedEvents.push(v);
422            }
423        } else if (view === "next-week") {
424            if (moment(startDateM).isSameOrAfter(moment().weekday(7), "day") && moment(startDateM).isSameOrBefore(moment().weekday(13), "day")) {
425                checkedEvents.push(v);
426            }
427        } else if (view === "this-month") {
428            if (moment().isSame(startDateM, 'month')) {
429                checkedEvents.push(v);
430            }
431        } else if (view === "next-month") {
432            if (moment().add(1, 'months').isSame(startDateM, 'month')) {
433                checkedEvents.push(v);
434            }
435        } else {
436            if (view === undefined || view == "") {
437                checkedEvents.push(v);
438            } else {;
439                if (view.indexOf("-") > -1) {
440                    if (startDateM.isSameOrAfter(moment(rangeDateStart, "MM/DD/YYYY"), 'day') && startDateM.isSameOrBefore(moment(rangeDateEnd, "MM/DD/YYYY"), 'day')) {
441                        checkedEvents.push(v);
442                    }
443                } else {
444                    if (startDateM.isSame(moment(view, "MM/DD/YYYY"), "day")) {
445                        checkedEvents.push(v);
446                    }
447                }
448            }
449        }
450    }
451}
452
453function jsonToCurrentData(data, view) {
454    return new Promise(function(resolve, reject) {
455        var jsonToCurrentDataEvents = [];
456        for (let i = 0; i < data.length; i++) {
457            cdEvent = {};
458            cdEvent.id = data[i].id;
459            cdEvent.title = data[i].title;
460            cdEvent.startDate = data[i].startDate;
461            cdEvent.endDate = data[i].endDate;
462            cdEvent.originalStart = data[i].originalStart;
463            cdEvent.originalEnd = data[i].originalEnd;
464            cdEvent.allDay = data[i].allDay;
465            cdEvent.description = data[i].description;
466            cdEvent.recurringEvent = data[i].recurringEvent;
467            cdEvent.tooltip = data[i].tooltip;
468            cdEvent.image = data[i].image;
469            cdEvent.alt = data[i].alt;
470            cdEvent.featured = data[i].featured;
471            if (filter1) {
472                cdEvent.filter1 = data[i].filter1;
473            }
474            if (filter2) {
475                cdEvent.filter2 = data[i].filter2;
476            }
477            if (filter3) {
478                cdEvent.filter3 = data[i].filter3;
479            }
480            if (filter4) {
481                cdEvent.filter4 = data[i].filter4;
482            }
483            if (filter5) {
484                cdEvent.filter5 = data[i].filter5;
485            }
486            if (filter6) {
487                cdEvent.filter6 = data[i].filter6;
488            }
489            if (filter7) {
490                cdEvent.filter7 = data[i].filter7;
491            }
492            if (filter8) {
493                cdEvent.filter8 = data[i].filter8;
494            }
495            if (filter9) {
496                cdEvent.filter9 = data[i].filter9;
497            }
498            if (filter10) {
499                cdEvent.filter10 = data[i].filter10;
500            }
501            cdEvent.url = data[i].url;
502            jsonToCurrentDataEvents.push(cdEvent);
503
504        }
505        resolve({
506            jsonToCurrentDataEvents: jsonToCurrentDataEvents
507        });
508    });
509}
510
511function eventCount() {
512    $eventsMessageContainer.empty();
513    $eventViewCountDisplay.empty();
514    $eventFilterViewCountDisplay.empty();
515    var $eventsList = $(".events-list");
516    var $filterMatch = $eventsList.find(".filter-match");
517    var $allEvents = $eventsList.find(".event");
518    if ($allEvents.length != $filterMatch.length) {
519        $eventViewCountDisplay.html("Loaded <span>" + $allEvents.length + "</span> event(s)");
520        $eventFilterViewCountDisplay.html(", showing <span>" + $filterMatch.length + "</span> that meet your filter/search criteria. ");
521    } else {
522        $eventViewCountDisplay.html("Showing <span>" + $allEvents.length + "</span> event(s). ")
523    }
524    if ($allEvents.length <= 4 || $filterMatch.length <= 4) {
525        $(".events-results2").removeClass("show-hhe").addClass("hide-hhe");
526    } else {
527        $(".events-results2").removeClass("hide-hhe").addClass("show-hhe");
528    }
529}
530
531/* details */
532
533function eventHTML(v, col) {
534    if (col == undefined) {
535        col = 4;
536    }
537    eventItem = '';
538	let divisible = 12/col;
539    eventItem += '<div class="col-sm-6 col-md-' + col + ' event">';
540    eventItem += '<a href="' + v.url + '" target="_parent">';
541    eventItem += imageOutput(v.image, v.startDate);
542    eventItem += '<h3 class="title">';
543    eventItem += v.title;
544    eventItem += '</h3>';
545    eventItem += '</a>';
546    eventItem += '<div class="details">';
547    if (v.featured == "true") {
548        eventItem += '<div class="featured">';
549        eventItem += '<span class="far fa-star" aria-hidden="true"></span>';
550        eventItem += '</div>';
551    }
552    if (v.recurringEvent == "true") {
553        eventItem += '<div class="recurrence">';
554        eventItem += '<span class="fas fa-sync-alt" title="' + v.tooltip + '" data-toggle="tooltip" data-placement="bottom" tabindex="0">';
555        eventItem += '</span>';
556        eventItem += '</div>';
557    }
558    eventItem += '<div class="time">' + timeOutput(v.startDate, v.endDate, v.allDay, v.originalStart, v.originalEnd) + '</div>';
559    eventItem += '<div class="date">' + dateOutput(v.startDate, v.endDate) + '</div>';
560    eventItem += '</div>';
561    eventItem += '</div>';
562    return eventItem;
563}
564
565function getRelatedEvents(data) {
566    return new Promise(function(resolve) {
567        for (let i = 0; i < data.length; i++) {
568            eventList += eventHTML(data[i], 4);
569        };
570        resolve({
571            data: data,
572            events: eventList
573        });
574    })
575}
576
577/* event */
578
579function showEvents(data, view, target, showLimit, origin) {
580    getEvents(data, showLimit, origin).then(function(results) {
581        if (debugMode) {
582            console.log("showEvents:", view);
583        }
584        // target.empty();
585        // target.append(results.events);
586        target.html(results.events);
587        if (view != "side-featured-events") {
588            if (setFiltersLoad.length > 0) {
589                showFilter(setFiltersLoad, "showEvents")
590            }
591            searchText($("#search").val().toLowerCase());
592            eventCount();
593            currentData = [];
594            $loadMoreContainer.removeClass("show-hhe").addClass("hide-hhe");
595            if (showLimit != "all") {
596                currentData = _.drop(results.data, showLimit);
597                if (currentData.length > 0) {
598                    if (debugMode) {
599                        console.log("show loadMore");
600                    }
601                    $loadMoreContainer.removeClass("hide-hhe").addClass("show-hhe");
602                }
603            }
604            if (debugMode) {
605                console.log("------------------------");
606            }
607        }
608    })
609}
610
611function getEvents(data, showLimit, origin) {
612    return new Promise(function(resolve, reject) {
613        if (debugMode) {
614            console.log("getEvents");
615        }
616        for (let iE = 0; iE < data.length; iE++) {
617            var eventsListFilterDots = [];
618            var eventsListFilterTexts = [];
619            var filterClasses = [];
620            var filterData = [
621                { name: "f1", data: data[iE].filter1, eList: filter1EventsList}, { name: "f2", data: data[iE].filter2, eList: filter2EventsList }, { name: "f3", data: data[iE].filter3, eList: filter3EventsList }, { name: "f4", data: data[iE].filter4, eList: filter4EventsList }, { name: "f5", data: data[iE].filter5, eList: filter5EventsList }, { name: "f6", data: data[iE].filter6, eList: filter6EventsList }, { name: "f7", data: data[iE].filter7, eList: filter7EventsList }, { name: "f8", data: data[iE].filter8, eList: filter8EventsList }, { name: "f9", data: data[iE].filter9, eList: filter9EventsList }, { name: "f10", data: data[iE].filter10, eList: filter10EventsList }
622            ];
623            for (let iFD = 0; iFD < filterData.length; iFD++) {
624                if (filterData[iFD].data) {
625                    for (let iFDF = 0; iFDF < filterData[iFD].data.length; iFDF++) {
626                        filterClasses.push(filterData[iFD].data[iFDF].replace(/\s/g, "").replace(/&/g, "and").replace(/[^0-9a-z\-]/gi, "").toLowerCase());
627                    }
628                    
629                    for (let iFDF = 0; iFDF < filterData[iFD].data.length; iFDF++) {
630                        if(filterData[iFD].eList == "dots"){
631                            eventsListFilterDots.push({
632                            "name": filterData[iFD].data[iFDF],
633                            "filter": filterData[iFD].name
634                            });
635                        }
636                        
637                    }
638                    for (let iFDF = 0; iFDF < filterData[iFD].data.length; iFDF++) {
639                        if(filterData[iFD].eList == "text"){
640                            eventsListFilterTexts.push(filterData[iFD].data[iFDF]);
641                        }
642                    }
643                }
644            }
645            eventItem = '';
646            eventItem += '<div class="row event filter-match ' + filterClasses.join(' ') + '">';
647            eventItem += '<a href="' + data[iE].url + '" target="_parent">';
648            eventItem += '<div class="col-xs-12 col-sm-4 image">';
649            eventItem += imageOutput(data[iE].image, data[iE].startDate);
650            eventItem += '</div>';
651            eventItem += '<div class="col-xs-12 col-sm-8"><div class="event-details"><div>';
652            eventItem += '<h3 class="title">';
653            eventItem += data[iE].title;
654            eventItem += '</h3>';
655            eventItem += '<div class="details">';
656            if (data[iE].featured === "true") {
657                eventItem += '<div class="featured">';
658                eventItem += '<span class="far fa-star" aria-hidden="true"></span>';
659                eventItem += '</div>';
660            }
661            if (data[iE].recurringEvent === "true") {
662                eventItem += '<div class="recurrence">';
663                eventItem += '<span class="fas fa-sync-alt" title="' + data[iE].tooltip + '" data-toggle="tooltip" data-placement="bottom" tabindex="0">';
664                eventItem += '</span>';
665                eventItem += '</div>';
666            }
667            eventItem += '<div class="time">' + timeOutput(data[iE].startDate, data[iE].endDate, data[iE].allDay, data[iE].originalStart, data[iE].originalEnd) + '</div>';
668            eventItem += '<div class="date">' + dateOutput(data[iE].startDate, data[iE].endDate) + '</div>';
669            if (eventsListFilterTexts.length > 0) {
670                if (eventsListFilterTexts.length > 1) {
671                    eventItem += '<div class="location listFilterText">' + eventsListFilterTexts.join(', ') + '</div>';
672                } else {
673                    eventItem += '<div class="location listFilterText">' + eventsListFilterTexts.join('') + '</div>';
674                }
675            }
676            if (eventsListFilterDots.length > 0) {
677                // console.log(eventsListFilterDots);
678                eventItem += '<div class="categories listFilterDots">';
679                for (let i = 0; i < eventsListFilterDots.length; i++) {
680                    eventItem += '<span class="fas fa-circle dot ' + eventsListFilterDots[i].filter + "-" + eventsListFilterDots[i].name.toLowerCase().replaceAll("&amp;","and").replaceAll("&","and").replaceAll(/[^A-Za-z0-9]/gi, "") + '-color" title="' + eventsListFilterDots[i].name + '" data-toggle="tooltip" data-placement="bottom" tabindex="0"></span>';
681                };
682                eventItem += '</div>';
683            }
684            eventItem += '</div>';
685            if (data[iE].description != undefined) {
686                eventItem += '<p class="summary">' + data[iE].description + '</p>';
687            }
688            eventItem += '</div></div></div>';
689            eventItem += '</a>';
690            eventItem += '</div>';
691            eventList += eventItem;
692            if (showLimit != "all" && iE == (showLimit - 1)) {
693                break;
694            }
695        }
696        resolve({
697            data: data,
698            events: eventList
699        });
700    })
701}
702
703/* filters */
704
705$(".loadFilter:checkbox").change(function(e) {
706    if (e.originalEvent !== undefined) {
707        if (debugMode) {
708            console.log("------------------------");
709            console.log("applyFilter: " + $(this).val());
710        }
711        var thisChecked = $(this).val().replace(/\s/g, "-").replace(/,/g, "").replace(/&/g, "and").replace(/[^0-9a-z\-]/gi, "").toLowerCase();
712        var hashChecked = $(this).data('hash') + "=";;
713        loadView(currentLoadedView, "", "all", "filter").then(function(results) {
714            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
715            if (window.location.hash) {
716                if (!_.includes(window.location.hash, hashChecked)) {
717                    if (debugMode) {
718                        console.log("filter add: " + hashChecked + thisChecked);
719                    }
720                    getHash(window.location.hash, hashChecked, function() {
721                        setHash(hashChecked, "add", thisChecked, function() {
722                            showFilter(setFiltersLoad, "loadView 1")
723                        });
724                    });
725                } else if (_.includes(window.location.hash, hashChecked)) {
726                    if (_.includes(window.location.hash, thisChecked)) {
727                        if (debugMode) {
728                            console.log("filter remove: " + thisChecked + " from " + hashChecked);
729                        }
730                        getHash(window.location.hash, hashChecked, function() {
731                            setHash(hashChecked, "remove", thisChecked, function() {
732                                showFilter(setFiltersLoad, "loadView 3")
733                            });
734                        });
735                    } else {
736                        if (debugMode) {
737                            console.log("filter add: " + thisChecked + " to " + hashChecked);
738                        }
739                        getHash(window.location.hash, hashChecked, function() {
740                            setHash(hashChecked, "add", thisChecked, function() {
741                                showFilter(setFiltersLoad, "loadView 2")
742                            });
743                        });
744                    }
745                }
746            } else {
747                if (debugMode) {
748                    console.log("filter add: " + hashChecked + thisChecked);
749                }
750                getHash(window.location.hash, hashChecked, function() {
751                    setHash(hashChecked, "add", thisChecked, function() {
752                        showFilter(setFiltersLoad, "loadView 1")
753                    });
754                });
755            }
756        });
757    }
758});
759
760$("select.loadFilter").change(function(e) {
761    if (e.originalEvent !== undefined) {
762        if (debugMode) {
763            console.log("------------------------");
764            console.log("applyFilter: " + $(this).val());
765        }
766        var thisSelected = $(this).val().replace(/\s/g, "-").replace(/,/g, "").replace(/&/g, "and").replace(/[^0-9a-z\-]/gi, "").toLowerCase();
767        var selectedHash = $(this).data('hash') + "=";
768        loadView(currentLoadedView, "", "all", "filter").then(function(results) {
769            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
770            if (_.includes(window.location.hash, selectedHash)) {
771                if (debugMode) {
772                    console.log("filter replace " + selectedHash + thisSelected);
773                }
774                getHash(window.location.hash, selectedHash, function() {
775                    setHash(selectedHash, "replace", thisSelected, function() {
776                        showFilter(setFiltersLoad, "select.loadFilter");
777                    });
778                });
779            } else {
780                if (debugMode) {
781                    console.log("filter add " + selectedHash + thisSelected);
782                }
783                getHash(window.location.hash, selectedHash, function() {
784                    setHash(selectedHash, "add", thisSelected, function() {
785                        showFilter(setFiltersLoad, "select.loadFilter 2");
786                    });
787                });
788            }
789        });
790    };
791});
792
793let searchInput = document.getElementById('search');
794let searchTimeout = null;
795if(searchInput) {
796    searchInput.addEventListener('keyup', function(e) {
797        clearTimeout(searchTimeout);
798        searchTimeout = setTimeout(function() {
799            loadView(currentLoadedView, "", "all", "searchText").then(function(results) {
800                showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
801                searchText($("#search").val().toLowerCase());
802            });
803        }, 300);
804    });
805}
806
807function searchText(textSearch) {
808    var doesEventContainText = function(eventElement) {
809        var innerSelectors = ['.title', '.details', '.summary'];
810        var innerElementMatchesText = function(selector) {
811            var element = eventElement.querySelector(selector) || {
812                innerText: ""
813            };
814            return element.innerText.toLowerCase().match(textSearch);
815        };
816        for (var i = 0; i < innerSelectors.length; i++) {
817            if (innerElementMatchesText(innerSelectors[i])) {
818                return true;
819            }
820        }
821        return false;
822    };
823    if (debugMode) {
824        console.log("searchText:", textSearch);
825    }
826    if (textSearch.length) {
827        var $filterMatches = $eventsContainer.find('.filter-match');
828        for (var i = 0; i < $filterMatches.length; i++) {
829            var element = $filterMatches[i];
830            if (!doesEventContainText(element)) {
831                element.classList.remove("filter-match");
832            }
833        }
834        eventCount();
835    }
836}
837
838function showFilter(filter, origin) {
839    if (debugMode) {
840        console.log("showFilter");
841        console.log("filter: " + filter);
842        console.log("origin: " + origin);
843    }
844    if (filter.length > 1) {
845        $eventsContainer.find('.row.event').removeClass("filter-match");
846        $eventsContainer.find(filter).addClass("filter-match");
847        eventCount();
848        checkFilter(filter);
849    } else {
850        $eventsContainer.find('.row.event').addClass("filter-match");
851        eventCount();
852    }
853}
854
855function checkFilter(filter) {
856    if (debugMode) {
857        console.log("checkfilter");
858        console.log(filter);
859    }
860    checkFilters = filter.replace(/, /g, '');
861    checkFilters = checkFilters.split(".");
862    checkFilters = _.compact(checkFilters);
863    if (debugMode) {
864        console.log(checkFilters);
865    }
866    for (let i = 0; i < checkFilters.length; i++) {
867        $(".loadFilter:checkbox[value=" + checkFilters[i] + "]").prop("checked", "true");
868    };
869    for (let i = 0; i < checkFilters.length; i++) {
870        var selectLoadFilters = document.querySelectorAll('select.loadFilter');
871        for (iSLF = 0; iSLF < selectLoadFilters.length; ++iSLF) {
872            for (iSO = 0; iSO < selectLoadFilters[iSLF].options.length; ++iSO) {
873                if (checkFilters[i] == selectLoadFilters[iSLF].options[iSO].value) {
874                    selectLoadFilters[iSLF].value = checkFilters[i];
875                }
876            };
877        };
878    };
879}
880
881/* hash */
882
883function newHashF(newHash) {
884    if (newHash !== window.location.hash) {
885        removeHash();
886        history.pushState(null, document.title, window.location.pathname + newHash);
887    }
888}
889
890function getHash(hash, type, callback) {
891    vHashes = [];
892    f1Hashes = [];
893    f2Hashes = [];
894    f3Hashes = [];
895    f4Hashes = [];
896    f5Hashes = [];
897    f6Hashes = [];
898    f7Hashes = [];
899    f8Hashes = [];
900    f9Hashes = [];
901    f10Hashes = [];
902    if (hash) {
903        getHashArray = hash + "&";
904        getHashArray = getHashArray.replace("#", "").split("&");
905        getHashArray = _.compact(getHashArray);
906
907        for (let i = 0; i < getHashArray.length; i++) {
908            if (_.includes(getHashArray[i], "v=")) {
909                vHashes.push(getHashArray[i]);
910            } else if (_.includes(getHashArray[i], "f1=")) {
911                f1Hashes.push(getHashArray[i]);
912            } else if (_.includes(getHashArray[i], "f2=")) {
913                f2Hashes.push(getHashArray[i]);
914            } else if (_.includes(getHashArray[i], "f3=")) {
915                f3Hashes.push(getHashArray[i]);
916            } else if (_.includes(getHashArray[i], "f4=")) {
917                f4Hashes.push(getHashArray[i]);
918            } else if (_.includes(getHashArray[i], "f5=")) {
919                f5Hashes.push(getHashArray[i]);
920            } else if (_.includes(getHashArray[i], "f6=")) {
921                f6Hashes.push(getHashArray[i]);
922            } else if (_.includes(getHashArray[i], "f7=")) {
923                f7Hashes.push(getHashArray[i]);
924            } else if (_.includes(getHashArray[i], "f8=")) {
925                f8Hashes.push(getHashArray[i]);
926            } else if (_.includes(getHashArray[i], "f9=")) {
927                f9Hashes.push(getHashArray[i]);
928            } else if (_.includes(getHashArray[i], "f10=")) {
929                f10Hashes.push(getHashArray[i]);
930            }
931        };
932    }
933    if (callback) {
934        callback();
935    }
936}
937
938function setHash(type, action, value, callback) {
939    setViews = "";
940    setViewsLoad = "";
941    setFilters = "";
942    setFiltersClean = "";
943    setFiltersMerged = "";
944    setFiltersLoad = "";
945    if (type === "v=") {
946        vHashes = [];
947        vHashes.push(type + value);
948    } else if (type === "f1=") {
949        if (_.includes(f1Hashes.toString(), type)) {
950            if (action === "add") {
951                f1HashesString = f1Hashes.toString() + "," + value;
952                f1Hashes = [];
953                f1Hashes.push(f1HashesString);
954            } else if (action === "remove") {
955                f1HashesString = f1Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
956                f1Hashes = [];
957                if (f1HashesString != "f1=") {
958                    f1Hashes.push(f1HashesString);
959                }
960            } else if (action === "replace") {
961                f1Hashes = [];
962                f1HashesString = type + value;
963                if (f1HashesString != "f1=") {
964                    f1Hashes.push(f1HashesString);
965                }
966            }
967        } else {
968            f1Hashes.push(type + value);
969        }
970    } else if (type === "f2=") {
971        if (_.includes(f2Hashes.toString(), type)) {
972            if (action === "add") {
973                f2HashesString = f2Hashes.toString() + "," + value;
974                f2Hashes = [];
975                f2Hashes.push(f2HashesString);
976            } else if (action === "remove") {
977                f2HashesString = f2Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
978                f2Hashes = [];
979                if (f2HashesString != "f2=") {
980                    f2Hashes.push(f2HashesString);
981                }
982            } else if (action === "replace") {
983                f2Hashes = [];
984                f2HashesString = type + value;
985                if (f2HashesString != "f2=") {
986                    f2Hashes.push(f2HashesString);
987                }
988            }
989        } else {
990            f2Hashes.push(type + value);
991        }
992    } else if (type === "f3=") {
993        if (_.includes(f3Hashes.toString(), type)) {
994            if (action === "add") {
995                f3HashesString = f3Hashes.toString() + "," + value;
996                f3Hashes = [];
997                f3Hashes.push(f3HashesString);
998            } else if (action === "remove") {
999                f3HashesString = f3Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
1000                f3Hashes = [];
1001                if (f3HashesString != "f3=") {
1002                    f3Hashes.push(f3HashesString);
1003                }
1004            } else if (action === "replace") {
1005                f3Hashes = [];
1006                f3HashesString = type + value;
1007                if (f3HashesString != "f3=") {
1008                    f3Hashes.push(f3HashesString);
1009                }
1010            }
1011        } else {
1012            f3Hashes.push(type + value);
1013        }
1014    } else if (type === "f4=") {
1015        if (_.includes(f4Hashes.toString(), type)) {
1016            if (action === "add") {
1017                f4HashesString = f4Hashes.toString() + "," + value;
1018                f4Hashes = [];
1019                f4Hashes.push(f4HashesString);
1020            } else if (action === "remove") {
1021                f4HashesString = f4Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
1022                f4Hashes = [];
1023                if (f4HashesString != "f4=") {
1024                    f4Hashes.push(f4HashesString);
1025                }
1026            } else if (action === "replace") {
1027                f4Hashes = [];
1028                f4HashesString = type + value;
1029                if (f4HashesString != "f4=") {
1030                    f4Hashes.push(f4HashesString);
1031                }
1032            }
1033        } else {
1034            f4Hashes.push(type + value);
1035        }
1036    } else if (type === "f5=") {
1037        if (_.includes(f5Hashes.toString(), type)) {
1038            if (action === "add") {
1039                f5HashesString = f5Hashes.toString() + "," + value;
1040                f5Hashes = [];
1041                f5Hashes.push(f5HashesString);
1042            } else if (action === "remove") {
1043                f5HashesString = f5Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
1044                f5Hashes = [];
1045                if (f5HashesString != "f5=") {
1046                    f5Hashes.push(f5HashesString);
1047                }
1048            } else if (action === "replace") {
1049                f5Hashes = [];
1050                f5HashesString = type + value;
1051                if (f5HashesString != "f5=") {
1052                    f5Hashes.push(f5HashesString);
1053                }
1054            }
1055        } else {
1056            f5Hashes.push(type + value);
1057        }
1058    } else if (type === "f6=") {
1059        if (_.includes(f6Hashes.toString(), type)) {
1060            if (action === "add") {
1061                f6HashesString = f6Hashes.toString() + "," + value;
1062                f6Hashes = [];
1063                f6Hashes.push(f6HashesString);
1064            } else if (action === "remove") {
1065                f6HashesString = f6Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
1066                f6Hashes = [];
1067                if (f6HashesString != "f6=") {
1068                    f6Hashes.push(f6HashesString);
1069                }
1070            } else if (action === "replace") {
1071                f6Hashes = [];
1072                f6HashesString = type + value;
1073                if (f6HashesString != "f6=") {
1074                    f6Hashes.push(f6HashesString);
1075                }
1076            }
1077        } else {
1078            f6Hashes.push(type + value);
1079        }
1080    } else if (type === "f7=") {
1081        if (_.includes(f7Hashes.toString(), type)) {
1082            if (action === "add") {
1083                f7HashesString = f7Hashes.toString() + "," + value;
1084                f7Hashes = [];
1085                f7Hashes.push(f7HashesString);
1086            } else if (action === "remove") {
1087                f7HashesString = f7Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
1088                f7Hashes = [];
1089                if (f7HashesString != "f7=") {
1090                    f7Hashes.push(f7HashesString);
1091                }
1092            } else if (action === "replace") {
1093                f7Hashes = [];
1094                f7HashesString = type + value;
1095                if (f7HashesString != "f7=") {
1096                    f7Hashes.push(f7HashesString);
1097                }
1098            }
1099        } else {
1100            f7Hashes.push(type + value);
1101        }
1102    } else if (type === "f8=") {
1103        if (_.includes(f8Hashes.toString(), type)) {
1104            if (action === "add") {
1105                f8HashesString = f8Hashes.toString() + "," + value;
1106                f8Hashes = [];
1107                f8Hashes.push(f8HashesString);
1108            } else if (action === "remove") {
1109                f8HashesString = f8Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
1110                f8Hashes = [];
1111                if (f8HashesString != "f8=") {
1112                    f8Hashes.push(f8HashesString);
1113                }
1114            } else if (action === "replace") {
1115                f8Hashes = [];
1116                f8HashesString = type + value;
1117                if (f8HashesString != "f8=") {
1118                    f8Hashes.push(f8HashesString);
1119                }
1120            }
1121        } else {
1122            f8Hashes.push(type + value);
1123        }
1124    } else if (type === "f9=") {
1125        if (_.includes(f9Hashes.toString(), type)) {
1126            if (action === "add") {
1127                f9HashesString = f9Hashes.toString() + "," + value;
1128                f9Hashes = [];
1129                f9Hashes.push(f9HashesString);
1130            } else if (action === "remove") {
1131                f9HashesString = f9Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
1132                f9Hashes = [];
1133                if (f9HashesString != "f9=") {
1134                    f9Hashes.push(f9HashesString);
1135                }
1136            } else if (action === "replace") {
1137                f9Hashes = [];
1138                f9HashesString = type + value;
1139                if (f9HashesString != "f9=") {
1140                    f9Hashes.push(f9HashesString);
1141                }
1142            }
1143        } else {
1144            f9Hashes.push(type + value);
1145        }
1146    } else if (type === "f10=") {
1147        if (_.includes(f10Hashes.toString(), type)) {
1148            if (action === "add") {
1149                f10HashesString = f10Hashes.toString() + "," + value;
1150                f10Hashes = [];
1151                f10Hashes.push(f10HashesString);
1152            } else if (action === "remove") {
1153                f10HashesString = f10Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
1154                f10Hashes = [];
1155                if (f10HashesString != "f10=") {
1156                    f10Hashes.push(f10HashesString);
1157                }
1158            } else if (action === "replace") {
1159                f10Hashes = [];
1160                f10HashesString = type + value;
1161                if (f10HashesString != "f10=") {
1162                    f10Hashes.push(f10HashesString);
1163                }
1164            }
1165        } else {
1166            f10Hashes.push(type + value);
1167        }
1168    }
1169    setViews = vHashes.join();
1170    setViewsLoad = setViews.replace("v=", "");
1171    setFiltersMerged = "";
1172    setFilters = _.concat(f1Hashes, f2Hashes, f3Hashes, f4Hashes, f5Hashes, f6Hashes, f7Hashes, f8Hashes, f9Hashes, f10Hashes);
1173    setFiltersClean = _.compact(setFilters);
1174    setFiltersMerged = "&" + setFiltersClean.join("&");
1175    setFiltersLoad = setFiltersMerged;
1176    for (let i = 0; i < urlHashes.length; i++) {
1177        setFiltersLoad = setFiltersLoad.replace(urlHashes[i], "");
1178    };
1179    setFiltersLoad = setFiltersLoad.substring(1);
1180    setFiltersLoad = "." + setFiltersLoad;
1181    setFiltersLoad = setFiltersLoad.replace(/&/g, filterLogic).replace(/=/g, ".").replace(/,/g, filterLogic).replace(/\.\./g, ".").replace(/\. \./g, ".");
1182    if (debugMode) {
1183        console.log("------------------------");
1184        console.log({
1185            setViews
1186        });
1187        console.log({
1188            setViewsLoad
1189        });
1190        console.log({
1191            setFilters
1192        });
1193        console.log({
1194            setFiltersClean
1195        });
1196        console.log({
1197            setFiltersMerged
1198        });
1199        console.log({
1200            urlHashes
1201        });
1202        console.log({
1203            setFiltersLoad
1204        });
1205    }
1206    if (setFiltersLoad === ".") {
1207        setFiltersLoad = "";
1208    }
1209    if (setFiltersClean.length > 0) {
1210        if (setViews.length > 0) {
1211            setURLHash = "#" + setViews + setFiltersMerged;
1212        } else {
1213            setURLHash = "#" + setFiltersMerged.substring(1);
1214        }
1215    } else {
1216        setURLHash = "#" + setViews
1217    }
1218    if (setURLHash === "#") {
1219        newHashF("");
1220    } else {
1221        newHashF(setURLHash);
1222    }
1223    if (callback) {
1224        callback();
1225    }
1226}
1227
1228function removeHash(callback) {
1229    history.pushState("", document.title, window.location.pathname + window.location.search);
1230    if (callback) {
1231        callback();
1232    }
1233}
1234
1235/* recurring */
1236
1237function calculateRecurrences(data) {
1238    if (debugMode) {
1239        console.log({
1240            "recurDataIn": data
1241        });
1242    }
1243    return new Promise(function(resolve, reject) {
1244        var recurringData = [];
1245        var daysArray = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
1246        var fullDayArray = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
1247        for (let i = 0; i < data.length; i++) {
1248            // console.log(data[i]);
1249            if (data[i] != undefined && data[i].recurringEvent === "true") { /* Get the date data */
1250                var startMoment = moment.parseZone(data[i].startDate);
1251                var _startMoment = startMoment.clone();
1252                var endMoment = moment.parseZone(data[i].endDate);
1253                var difference = endMoment.diff(startMoment);
1254                var untilMoment = moment.parseZone(data[i].recurringDetails.recurUntilDate); /* Get cancellations of recurring event */
1255                var cancellations = [];
1256                for (let iC = 0; iC < data[i].recurringDetails.recurCancellations.length; iC++) {
1257                    cancellations.push(data[i].recurringDetails.recurCancellations[iC])
1258                }; /* Calculate the recurring events */
1259                if (data[i].recurringDetails.recurFrequency === "daily") {
1260                    if (data[i].recurringDetails.recurInterval > 1) {
1261                        data[i].tooltip = "Every " + data[i].recurringDetails.recurInterval + " days";
1262                    } else {
1263                        data[i].tooltip = "Daily";
1264                    }
1265                    while (untilMoment.diff(startMoment, "s") >= 0) { /* Add the current event */
1266                        var thisRecurrence = $.extend({}, data[i]);
1267                        thisRecurrence.startDate = startMoment.valueOf();
1268                        thisRecurrence.endDate = endMoment.valueOf();
1269                        if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
1270                            recurringData.push(thisRecurrence);
1271                        } /* Increment by X days */
1272                        startMoment.add(data[i].recurringDetails.recurInterval, "days").valueOf();
1273                        endMoment.add(data[i].recurringDetails.recurInterval, "days").valueOf();
1274                    }
1275                } else if (data[i].recurringDetails.recurFrequency === "weekly") {
1276                    if (data[i].recurringDetails.recurInterval > 1) {
1277                        data[i].tooltip = "Every " + data[i].recurringDetails.recurInterval + " weeks";
1278                    } else {
1279                        data[i].tooltip = "Weekly";
1280                    }
1281                    var untilMomentRecurs = untilMoment.clone().add(data[i].recurringDetails.recurInterval, "weeks"); /* Incase event stops recurring during the week it still has events */
1282                    if (data[i].recurringDetails.recurDays != undefined && data[i].recurringDetails.recurDays.length > 0) {
1283                        data[i].tooltip += " on ";
1284                        for (var day = 0; day < data[i].recurringDetails.recurDays.length; day++) {
1285                            data[i].tooltip += data[i].recurringDetails.recurDays[day];
1286                            if (day < data[i].recurringDetails.recurDays.length - 2) {
1287                                data[i].tooltip += ", ";
1288                            }
1289                            if (day == data[i].recurringDetails.recurDays.length - 2) {
1290                                data[i].tooltip += " & ";
1291                            }
1292                        }
1293                        while (untilMomentRecurs.diff(startMoment, "s") >= 0) { /* Loop over the selected days of the week */
1294                            for (var day = 0; day < data[i].recurringDetails.recurDays.length; day++) {
1295                                var thisDay = data[i].recurringDetails.recurDays[day];
1296                                startMoment.date(startMoment.date() + (daysArray.indexOf(thisDay) - startMoment.day()));
1297                                endMoment = startMoment.clone().add(difference, "ms"); /* Only add occurrences that are after the actual start date & before the actual until date */
1298                                if (startMoment.diff(_startMoment, "s") >= 0 && startMoment.diff(untilMoment, "s") <= 0) {
1299                                    var thisRecurrence = $.extend({}, data[i]);
1300                                    thisRecurrence.startDate = startMoment.valueOf();
1301                                    thisRecurrence.endDate = endMoment.valueOf();
1302                                    if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
1303                                        recurringData.push(thisRecurrence);
1304                                    }
1305                                }
1306                            } /* Increment by X weeks */
1307                            startMoment.add(data[i].recurringDetails.recurInterval, "weeks");
1308                            endMoment.add(data[i].recurringDetails.recurInterval, "weeks");
1309                        }
1310                    } else {
1311                        while (untilMomentRecurs.diff(startMoment, "s") >= 0) { /* Add the current event */ /* Only add occurrences that are before the actual until date */
1312                            if (startMoment.diff(untilMoment, "s") <= 0) {
1313                                var thisRecurrence = $.extend({}, data[i]);
1314                                thisRecurrence.startDate = startMoment.valueOf();
1315                                thisRecurrence.endDate = endMoment.valueOf();
1316                                if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
1317                                    recurringData.push(thisRecurrence);
1318                                }
1319                            } /* Increment by X weeks */
1320                            startMoment.add(data[i].recurringDetails.recurInterval, "weeks").valueOf();
1321                            endMoment.add(data[i].recurringDetails.recurInterval, "weeks").valueOf();
1322                        }
1323                    }
1324                } else if (data[i].recurringDetails.recurFrequency === "monthly") {
1325                    if (data[i].recurringDetails.recurInterval > 1) {
1326                        data[i].tooltip = "Every " + data[i].recurringDetails.recurInterval + " months";
1327                    } else {
1328                        data[i].tooltip = "Monthly";
1329                    }
1330                    if (data[i].recurringDetails.recurMonth === "day of the month") { /* The same day of the month on each month (1st, 2nd, etc) */
1331                        data[i].tooltip += " on the " + startMoment.format('Do') + " day";
1332                        while (untilMoment.diff(startMoment, "s") >= 0) { /* Ensure the date exists within the current month */
1333                            if (startMoment.date() == _startMoment.date()) {
1334                                var thisRecurrence = $.extend({}, data[i]);
1335                                thisRecurrence.startDate = startMoment.valueOf();
1336                                thisRecurrence.endDate = endMoment.valueOf();
1337                                if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
1338                                    recurringData.push(thisRecurrence);
1339                                }
1340                            } /* Increment by X months */
1341                            startMoment.add(data[i].recurringDetails.recurInterval, "months");
1342                            if (startMoment.daysInMonth() >= _startMoment.date()) {
1343                                startMoment.date(_startMoment.date());
1344                            }
1345                            endMoment = startMoment.clone().add(difference, "ms");
1346                        }
1347                    } else if (data[i].recurringDetails.recurMonth === "day of the week") { /* The same day of the week of the month (2nd Tues of month) */
1348                        data[i].tooltip += " on the " + nth(Math.ceil(startMoment.date() / 7)) + " " + fullDayArray[startMoment.day()]; /* Add a monthly occurrence based on the original event's day of the week */ /* Determine the position of this day in the month (ie 1st, 2nd ...) */
1349                        var theWeek = Math.floor(startMoment.date() / 7),
1350                            theDay = startMoment.day() + 1,
1351                            tempMonth = startMoment.month();
1352                        while (untilMoment.diff(startMoment, "s") >= 0) { /* If we didn't roll over into the next month, add the event */
1353                            if (tempMonth === startMoment.month()) {
1354                                var thisRecurrence = $.extend({}, data[i]);
1355                                thisRecurrence.startDate = startMoment.valueOf();
1356                                thisRecurrence.endDate = endMoment.valueOf();
1357                                if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
1358                                    recurringData.push(thisRecurrence);
1359                                }
1360                            } /* Figure out where the next month's first day lies and add the difference in days with the weekly position */
1361                            startMoment.add(data[i].recurringDetails.recurInterval, "months").date(1);
1362                            tempMonth = startMoment.month();
1363                            if (theDay <= startMoment.day()) {
1364                                startMoment.date((theDay - startMoment.day() + ((theWeek + 1) * 7)));
1365                            } else {
1366                                startMoment.date((theDay - startMoment.day() + (theWeek * 7)));
1367                            }
1368                            endMoment = startMoment.clone().add(difference, "ms");
1369                        }
1370                    }
1371                } else if (data[i].recurringDetails.recurFrequency === "yearly") {
1372                    if (data[i].recurringDetails.recurInterval > 1) {
1373                        data[i].tooltip = "Every " + data[i].recurringDetails.recurInterval + " years";
1374                    } else {
1375                        data[i].tooltip = "Yearly";
1376                    }
1377                    while (untilMoment.diff(startMoment, "s") >= 0) { /* Add the current event */
1378                        var thisRecurrence = $.extend({}, data[i]);
1379                        thisRecurrence.startDate = startMoment.valueOf();
1380                        thisRecurrence.endDate = endMoment.valueOf();
1381                        if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
1382                            recurringData.push(thisRecurrence);
1383                        } /* Increment by X years */
1384                        startMoment.add(data[i].recurringDetails.recurInterval, "years").valueOf();
1385                        endMoment.add(data[i].recurringDetails.recurInterval, "years").valueOf();
1386                    }
1387                }
1388            }
1389        };
1390        if (debugMode) {
1391            console.log({
1392                "recurDataOut": recurringData
1393            });
1394        }
1395        resolve(recurringData);
1396    })
1397}
1398
1399function checkCancellations(cancellations, checkDate) {
1400    var cancelled = false;
1401    if (cancellations.length > 0) {
1402        for (let i = 0; i < cancellations.length; i++) {
1403            cancelled = moment.parseZone(checkDate).isSame(cancellations[i], 'day');
1404            if (cancelled) {
1405                break;
1406            }
1407        };
1408    }
1409    return cancelled;
1410}
1411
1412function nth(n) {
1413    return n + ["st", "nd", "rd"][((n + 90) % 100 - 10) % 10 - 1] || "th"
1414}
1415
1416function recurringURLs(view) {
1417    if (debugMode) {
1418        console.log("recurringData");
1419    }
1420    return new Promise(function(resolve, reject) {
1421        viewChecker(view).then(function(results) {
1422            resolve(results);
1423        });
1424    })
1425}
1426
1427/* view */
1428
1429$(".loadView").on("click", function() {
1430    if (debugMode) {
1431        console.log("------------------------");
1432        console.log("clicked: " + $(this).text());
1433    }
1434    $(this).blur();
1435    $('.input-daterange input').datepicker('update', null);
1436    $('.input-daterange').datepicker('updateDates');
1437    clickedView = $(this).text().replace(/All /gi, "").replace(/\s/g, "-").replace(/,/g, "").replace(/&/g, "and").replace(/[^0-9a-z\-]/gi, "").toLowerCase();
1438    getHash(window.location.hash, "", function() {
1439        setHash("v=", "replace", clickedView, function() {
1440            loadView(clickedView).then(function(results) {
1441                showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
1442            });
1443        });
1444    });
1445});
1446
1447function loadView(view, target, showLimit, origin) {
1448    return new Promise(function(resolve, reject) {
1449        if (debugMode) {
1450            console.log("loadView: " + view);
1451        }
1452        if (target === undefined || target == "") {
1453            target = $eventsContainer;
1454        }
1455        if (showLimit === undefined || showLimit == "") {
1456            showLimit = defaultViewCount;
1457        }
1458        if (view != "side-featured-events") {
1459            currentLoadedView = view;
1460        }
1461        eventList = "";
1462        // currentDataURLs = []; // weirdly fixes date range issue
1463        viewChecker(view).then(function(results) {
1464            if (view === "upcoming-events") {
1465                $eventViewHeader.html("Upcoming Events");
1466                checkDataURLs(results, view, target, showLimit, origin).then(function(results) {
1467                    resolve({
1468                        "events": results.events,
1469                        "view": results.view,
1470                        "target": results.target,
1471                        "showLimit": results.showLimit,
1472                        "origin": results.origin
1473                    });
1474                });
1475            } else if (view === "this-month") {
1476                $eventViewHeader.html("This Month's Events");
1477                checkDataURLs(results, view, target, "all").then(function(results) {
1478                    resolve({
1479                        "events": results.events,
1480                        "view": results.view,
1481                        "target": results.target,
1482                        "showLimit": results.showLimit,
1483                        "origin": results.origin
1484                    });
1485                });
1486            } else if (view === "today") {
1487                $eventViewHeader.html("Today's Events");
1488                checkDataURLs(results, view, target, "all").then(function(results) {
1489                    resolve({
1490                        "events": results.events,
1491                        "view": results.view,
1492                        "target": results.target,
1493                        "showLimit": results.showLimit,
1494                        "origin": results.origin
1495                    });
1496                });
1497            } else if (view === "tomorrow") {
1498                $eventViewHeader.html("Tomorrow's Events");
1499                checkDataURLs(results, view, target, "all").then(function(results) {
1500                    resolve({
1501                        "events": results.events,
1502                        "view": results.view,
1503                        "target": results.target,
1504                        "showLimit": results.showLimit,
1505                        "origin": results.origin
1506                    });
1507                });
1508            } else if (view === "this-week") {
1509                $eventViewHeader.html("This Week's Events");
1510                checkDataURLs(results, view, target, "all").then(function(results) {
1511                    resolve({
1512                        "events": results.events,
1513                        "view": results.view,
1514                        "target": results.target,
1515                        "showLimit": results.showLimit,
1516                        "origin": results.origin
1517                    });
1518                });
1519            } else if (view === "this-weekend") {
1520                $eventViewHeader.html("This Weekend's Events");
1521                checkDataURLs(results, view, target, "all").then(function(results) {
1522                    resolve({
1523                        "events": results.events,
1524                        "view": results.view,
1525                        "target": results.target,
1526                        "showLimit": results.showLimit,
1527                        "origin": results.origin
1528                    });
1529                });
1530            } else if (view === "next-week") {
1531                $eventViewHeader.html("Next Week's Events");
1532                checkDataURLs(results, view, target, "all").then(function(results) {
1533                    resolve({
1534                        "events": results.events,
1535                        "view": results.view,
1536                        "target": results.target,
1537                        "showLimit": results.showLimit,
1538                        "origin": results.origin
1539                    });
1540                });
1541            } else if (view === "this-month") {
1542                $eventViewHeader.html("This Month's Events");
1543                checkDataURLs(results, view, target, "all").then(function(results) {
1544                    resolve({
1545                        "events": results.events,
1546                        "view": results.view,
1547                        "target": results.target,
1548                        "showLimit": results.showLimit,
1549                        "origin": results.origin
1550                    });
1551                });
1552            } else if (view === "next-month") {
1553                $eventViewHeader.html("Next Month's Events");
1554                checkDataURLs(results, view, target, "all").then(function(results) {
1555                    resolve({
1556                        "events": results.events,
1557                        "view": results.view,
1558                        "target": results.target,
1559                        "showLimit": results.showLimit,
1560                        "origin": results.origin
1561                    });
1562                });
1563            } else if (view === "featured" || view === "featured-events") {
1564                view = "featured";
1565                $eventViewHeader.html("Upcoming Featured Events");
1566                checkDataURLs(results, view, target, showLimit, origin).then(function(results) {
1567                    resolve({
1568                        "events": results.events,
1569                        "view": results.view,
1570                        "target": results.target,
1571                        "showLimit": results.showLimit,
1572                        "origin": results.origin
1573                    });
1574                });
1575            } else if (view === "side-featured-events") {
1576                checkDataURLs(results, view, target, "3", origin).then(function(results) {
1577                    resolve({
1578                        "events": results.events,
1579                        "view": results.view,
1580                        "target": results.target,
1581                        "showLimit": results.showLimit,
1582                        "origin": results.origin
1583                    });
1584                });
1585            } else {
1586                $eventViewHeader.html(view);
1587                checkDataURLs(results, view, target, "all").then(function(results) {
1588                    resolve({
1589                        "events": results.events,
1590                        "view": results.view,
1591                        "target": results.target,
1592                        "showLimit": results.showLimit,
1593                        "origin": results.origin
1594                    });
1595                });
1596            }
1597        });
1598    })
1599}
1600
1601function viewChecker(view) {
1602    return new Promise(function(resolve, reject) {
1603        var currentDataUrlsViews = ["upcoming-events", "this-month", "today", "tomorrow", "this-week", "this-weekend", "next-week", "this-month", "next-month", "featured", "side-featured-events"];
1604        var pushToCurrentDataURLsIfRangeApplies = function(yearRange, monthRange) {
1605            if (currentYear === yearRange && monthRange >= previousMonth) {
1606                currentDataURLs.push(currentDataURL.replace(/&amp;/g, '&'));
1607            } else {
1608                for (let i = 0; i < dataFiles.length; i++) {
1609                    if (dataFiles[i].name === yearRange + "") {
1610                        currentDataURLs.push(dataFiles[i].link.replace(/&amp;/g, '&'));
1611                    }
1612                };
1613            }
1614        };
1615        if (currentDataUrlsViews.includes(view)) {
1616            currentDataURLs.push(currentDataURL.replace(/&amp;/g, '&'));
1617        } else {
1618            if (view.indexOf("-") > -1) {
1619                rangeDates = [];
1620                rangeDateStart = "";
1621                rangeDateEnd = "";
1622                startYearRange = "";
1623                endYearRange = "";
1624                startMonthRange = "";
1625                endMonthRange = "";
1626                startDayRange = "";
1627                endDayRange = "";
1628                rangeDates = view.split("-");
1629                rangeDateStart = rangeDates[0];
1630                rangeDateEnd = rangeDates[1];
1631                var rangeDateStartM = moment(rangeDateStart, "MM/DD/YYYY", true);
1632                var rangeDateEndM = moment(rangeDateEnd, "MM/DD/YYYY", true);
1633                if (!rangeDateStartM.isValid() && !moment(rangeDateEnd, "MM/DD/YYYY", true).isValid()) {
1634                    eventsMessage = rangeDateStart + "-" + rangeDateStart + " is not a valid date range.";
1635                    errorMessage = true;
1636                } else {
1637                    if (!rangeDateStartM.isValid()) {
1638                        eventsMessage = rangeDateStart + " is not a valid start date.";
1639                        errorMessage = true;
1640                    }
1641                    if (!rangeDateEndM) {
1642                        eventsMessage = rangeDateEnd + " is not a valid end date.";
1643                        errorMessage = true;
1644                    }
1645                }
1646                if (errorMessage) {
1647                    $eventsMessageContainer.html('<p>' + eventsMessage + '</p>').removeClass("hide-hhe").addClass("show-hhe");
1648                } else {
1649                    $eventsMessageContainer.removeClass("show-hhe").addClass("hide-hhe").empty();
1650                    startYearRange = rangeDateStartM.year();
1651                    endYearRange = rangeDateEndM.year();
1652                    startMonthRange = rangeDateStartM.month();
1653                    endMonthRange = rangeDateEndM.month();
1654                    startDayRange = rangeDateStartM.date();
1655                    endDayRange = rangeDateEndM.date();
1656                    if (startYearRange === endYearRange) {
1657                        if (startMonthRange === endMonthRange) {
1658                            pushToCurrentDataURLsIfRangeApplies(startYearRange, startMonthRange);
1659                        } else {
1660                            pushToCurrentDataURLsIfRangeApplies(startYearRange, startMonthRange);
1661                            pushToCurrentDataURLsIfRangeApplies(endYearRange, endMonthRange);
1662                        }
1663                    } else {
1664                        if (currentYear === startYearRange && startMonthRange >= previousMonth) {
1665                            currentDataURLs.push(currentDataURL.replace(/&amp;/g, '&'));
1666                        } else {
1667                            for (i = startYearRange; i <= endYearRange; ++i) {
1668                                for (let iDF = 0; iDF < dataFiles.length; iDF++) {
1669                                    if (dataFiles[iDF].name == i + "") {
1670                                        currentDataURLs.push(dataFiles[iDF].link.replace(/&amp;/g, '&'));
1671                                    }
1672                                };
1673                            }
1674                        }
1675                    }
1676                }
1677            } else {
1678                singleDateYear = "";
1679                singleDateMonth = "";
1680                singleDateDay = "";
1681                singleDate = "";
1682                var viewDateM = moment(view, "MM/DD/YYYY", true);
1683                if (!viewDateM.isValid()) {
1684                    errorMessage = true;
1685                    eventsMessage = '"' + view + '"' + " is not a valid view.";
1686                    $eventsMessageContainer.html(eventsMessage).removeClass("hide-hhe").addClass("show-hhe");
1687                } else {
1688                    $eventsMessageContainer.removeClass("show-hhe").addClass("hide-hhe").empty();
1689                }
1690                if (!errorMessage) {
1691                    singleDate = viewDateM.format('MM/DD/YYYY');
1692                    singleDateYear = viewDateM.year();
1693                    singleDateMonth = viewDateM.month();
1694                    singleDateDay = viewDateM.date();
1695                    pushToCurrentDataURLsIfRangeApplies(singleDateYear, singleDateMonth);
1696                }
1697            }
1698        }
1699        if (debugMode) {
1700            console.log(currentDataURLs);
1701        }
1702        resolve(currentDataURLs);
1703    })
1704}
1705
1706function awaitAll(list, asyncFn) {
1707    const promises = [];
1708    for (let i = 0; i < list.length; i++) {
1709        promises.push(asyncFn(list[i]));
1710    };
1711    return Promise.all(promises);
1712}
1713
1714function urlText(s, preserveCR) {
1715    preserveCR = preserveCR ? '&#13;' : '\n';
1716    return ('' + s).replace(/%/g, '%25').replace(/&amp;/g, '%26').replace(/&/g, '%26').replace(/'/g, '%27').replace(/"/g, '%22').replace(/</g, '%20').replace(/>/g, '%3E').replace(/#/g, '%23').replace(/ /g, '%20').replace(/\r\n/g, preserveCR).replace(/[\r\n]/g, preserveCR);
1717}
1718
1719function saveLinkOutput(title, description, startDate, endDate, timezone, allDay, calendar) {
1720    var startDateO = moment(startDate);
1721    var endDateO = moment(endDate);
1722    if (allDay == "true") {
1723        var ssd = startDateO.format('YYYYMMDD');
1724        var sed = endDateO.add(1, "days").format('YYYYMMDD');
1725        if (calendar == "outlook") {
1726            var ssd = startDateO.format('YYYY-MM-DD');
1727            var sed = endDateO.add(1, "days").format('YYYY-MM-DD');
1728        }
1729    } else {
1730        var ssd = startDateO.format('YYYYMMDDTHHmmZ');
1731        var sed = endDateO.format('YYYYMMDDTHHmmZ');
1732        if (calendar == "outlook") {
1733            var ssd = startDateO.format('YYYY-MM-DDTHH:mmZ');
1734            var sed = endDateO.add(1, "days").format('YYYY-MM-DDTHH:mmZ');
1735        }
1736    }
1737    var saveLinkOutput = "";
1738    if (calendar == "google") {
1739        saveLinkOutput += "<a href='https://calendar.google.com/calendar/r/eventedit?text=" + urlText(title) + "&amp;dates=" + ssd + "/" + sed + "&amp;details=" + urlText(description) + " ' target='_blank'>";
1740        saveLinkOutput += "<span class='fab fa-google' aria-hidden='true'></span> <span class='sr-only'>Add to</span>Google</a>";
1741    } else if (calendar == "outlook") {
1742        saveLinkOutput += "<a target='_blank' href='https://outlook.live.com/owa/?path=/calendar/action/compose&amp;startdt=" + ssd + "&amp;enddt=" + sed + "&amp;subject=" + urlText(title) + "&amp;body=" + urlText(description) + "&amp;allday=" + allDay + " ' target='_blank'>";
1743        saveLinkOutput += "<span class='fab fa-windows' aria-hidden='true'></span> <span class='sr-only'>Add to</span>Outlook</a>";
1744    } else if (calendar == "yahoo") {
1745        if (allDay == "true") {
1746            saveLinkOutput += "<a href='https://calendar.yahoo.com/?v=60&amp;view=d&amp;type=20&amp;title=" + urlText(title) + "&amp;st=" + ssd + "&amp;et=" + sed + "&amp;desc=" + urlText(description) + "&amp;dur=allday' target='_blank'>";
1747        } else {
1748            saveLinkOutput += "<a href='https://calendar.yahoo.com/?v=60&amp;view=d&amp;type=20&amp;title=" + urlText(title) + "&amp;st=" + ssd + "&amp;et=" + sed + "&amp;desc=" + urlText(description) + "' target='_blank'>";
1749        }
1750        saveLinkOutput += "<span class='fab fa-yahoo' aria-hidden='true'></span> <span class='sr-only'>Add to</span>Yahoo</a>";
1751    } else if (calendar == "ics") {
1752        saveLinkOutput += "<a href='" + thisCurrentEvent[0].ics + "' target='_blank'><span class='far fa-calendar-plus' aria-hidden='true'></span> <span class='sr-only'>Download as</span>iCal</a>";
1753    }
1754    return saveLinkOutput;
1755}
1756
1757function currentRecurringEvent() {
1758    calculateRecurrences(thisCurrentEvent).then(function(resultsR) {
1759        eventDateChecker("", resultsR, "current-recurring-event").then(function(results) {
1760            jsonToCurrentData(results).then(function(results) {
1761                var rJCDE = results.jsonToCurrentDataEvents;
1762                if (rJCDE.length > 0) {
1763                    rJCDE.sort(function(a, b) {
1764                        return +new Date(a.startDate) - +new Date(b.startDate);
1765                    });
1766
1767                    for (let i = 0; i < rJCDE.length; i++) {
1768                        $('.rDate').append("Next Occurrence:<br/>" + dateOutput(rJCDE[i].startDate, rJCDE[i].endDate, "full"));
1769                        $('#rDates').append('<option selected="selected" role="listitem" value="' + dateOutput(rJCDE[i].startDate, rJCDE[i].endDate, "full") + '" data-title="' + rJCDE[i].title + '" data-desc="' + rJCDE[i].description + '" data-start="' + rJCDE[i].startDate + '" data-end="' + rJCDE[i].endDate + '" data-timezone="' + thisCurrentEvent[0].timezone + '" data-allDay="' + rJCDE[i].allDay + '">' + dateOutput(rJCDE[i].startDate, rJCDE[i].endDate, "full") + '</option>');
1770                        $(".save-row .feeds").append(saveLinkOutput(rJCDE[i].title, rJCDE[i].description, rJCDE[i].startDate, rJCDE[i].endDate, thisCurrentEvent[0].timezone, rJCDE[i].allDay, "google"));
1771                        $(".save-row .feeds").append(saveLinkOutput(rJCDE[i].title, rJCDE[i].description, rJCDE[i].startDate, rJCDE[i].endDate, thisCurrentEvent[0].timezone, rJCDE[i].allDay, "outlook"));
1772                        $(".save-row .feeds").append(saveLinkOutput(rJCDE[i].title, rJCDE[i].description, rJCDE[i].startDate, rJCDE[i].endDate, thisCurrentEvent[0].timezone, rJCDE[i].allDay, "yahoo"));
1773                        $(".save-row .feeds").append(saveLinkOutput(rJCDE[i].title, rJCDE[i].description, rJCDE[i].startDate, rJCDE[i].endDate, thisCurrentEvent[0].timezone, rJCDE[i].allDay, "ics"));
1774                        if (i == 0) {
1775                            break;
1776                        }
1777                    };
1778                    for (let i = 0; i < rJCDE.length; i++) {
1779                        if (i > 0) {
1780                            $('#rDates').append('<option role="listitem"  value="' + dateOutput(rJCDE[i].startDate, rJCDE[i].endDate, "full") + '" data-title="' + rJCDE[i].title + '" data-desc="' + rJCDE[i].description + '" data-start="' + rJCDE[i].startDate + '" data-end="' + rJCDE[i].endDate + '" data-timezone="' + thisCurrentEvent[0].timezone + '" data-allDay="' + rJCDE[i].allDay + '">' + dateOutput(rJCDE[i].startDate, rJCDE[i].endDate, "full") + '</option>');
1781                        }
1782                    };
1783                } else {
1784                    $('#rDates').remove();
1785                    $('.save-row').remove();
1786                    $('.rDate').append("This event has ended. It ran from<br/>" + moment(thisCurrentEvent[0].startDate).format('MMM D, YYYY') + " to " + moment(thisCurrentEvent[0].recurringDetails.recurUntilDate).format('MMM D, YYYY') + ".");
1787                }
1788            });
1789        });
1790    });
1791}
1792
1793function checkHash() {
1794    if (window.location.hash) {
1795        loadView("side-featured-events", $featuredEventsContainer, sideFeaturedCount).then(function(results) {
1796            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
1797            if (debugMode) {
1798                console.log("------------------------");
1799                console.log("pageLoadHash");
1800            }
1801            getHash(window.location.hash, "", function() {
1802                setViews = vHashes.join();
1803                setViewsLoad = setViews.replace("v=", "");
1804                if (setViewsLoad.length < 1) {
1805                    setViewsLoad = defaultView;
1806                };
1807                setFiltersMerged = "";
1808                setFilters = _.concat(f1Hashes, f2Hashes, f3Hashes, f4Hashes, f5Hashes, f6Hashes, f7Hashes, f8Hashes, f9Hashes, f10Hashes);
1809                setFiltersClean = _.compact(setFilters);
1810                setFiltersMerged = "&" + setFiltersClean.join("&");
1811                setFiltersLoad = setFiltersMerged;
1812                for (let i = 0; i < urlHashes.length; i++) {
1813                    setFiltersLoad = setFiltersLoad.replace(urlHashes[i], "");
1814                };
1815                setFiltersLoad = setFiltersLoad.replace(/&/g, ".").replace(/=/g, ".").replace(/,/g, filterLogic).replace(/\.\./g, ".");
1816                if (setFiltersLoad === ".") {
1817                    setFiltersLoad = "";
1818                }
1819                loadView(setViewsLoad, "", "all", "pageLoad").then(function(results) {
1820                    showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
1821                });
1822            });
1823        });
1824    } else {
1825        if (debugMode) {
1826            console.log("pageLoad: " + defaultView);
1827            console.log("------------------------");
1828        }
1829        loadView("side-featured-events", $featuredEventsContainer, sideFeaturedCount).then(function(results) {
1830            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
1831            if (debugMode) {
1832                console.log("------------------------");
1833            }
1834            loadView(defaultView, "", "", "pageLoad").then(function(results) {
1835                showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
1836            });
1837        });
1838    }
1839}
1840
1841function dateOutput(startDateIn, endDateIn, type) {
1842    var startDateM = moment(startDateIn);
1843    var endDateM = moment(endDateIn);
1844    if (startDateM.isSame(endDateM,'day')) {
1845        if (type == "full") {
1846            var dateOutput = startDateM.format('MMMM D, YYYY');
1847        } else {
1848            var dateOutput = startDateM.format('MMM D YYYY');
1849        }
1850    } else {
1851        if (startDateM.isSame(endDateM, 'year')) {
1852            if (startDateM.isSame(endDateM, 'month')) {
1853                var dateOutput = startDateM.format('MMM D') + ' - ' + endDateM.format('D YYYY');
1854            } else {
1855                var dateOutput = startDateM.format('MMM D') + ' - ' + endDateM.format('MMM D YYYY');
1856            }
1857        } else {
1858            var dateOutput = startDateM.format('MMM D YYYY') + ' - ' + endDateM.format('MMM D YYYY');
1859        }
1860    }
1861    return dateOutput;
1862}
1863
1864function imgWeekDay(day) {
1865    var daysOfWeek = ["Mon<span>day</span>", "Tue<span>sday</span>", "Wed<span>nesday</span>", "Thur<span>sday</span>", "Fri<span>day</span>", "Sat<span>urday</span>", "Sun<span>day</span>"];
1866    return daysOfWeek[day - 1];
1867}
1868
1869function imageOutput(image, startDateIn) {
1870    var startDateM = moment(startDateIn);
1871    if (image) {
1872        var imageOuput = '<div class="event-image" style="background-image:url(\'' + image.url + '\');"></div>';
1873    } else {
1874        var imageOuput = '<div class="event-image date-img"><div class="month">' + startDateM.format('MMM') + '</div><div class="day">' + startDateM.format('D') + '<div class="weekday">' + imgWeekDay(startDateM.isoWeekday()) + '</div></div></div>';
1875    }
1876    return imageOuput;
1877}
1878
1879function timeOutput(startDateIn, endDateIn, allDayIn, originalStart, originalEnd) {
1880    var timeOutput = "";
1881    if (allDayIn === "true") {
1882        timeOutput = 'All Day';
1883    } else {
1884        var startDateInM = moment(startDateIn);
1885        var originalStartM = moment(originalStart);
1886        var endDateInM = moment(endDateIn);
1887        var originalEndM = moment(originalEnd);
1888        var startDateStdOffset; /*Fix to remove daylight savings time*/
1889        if (!moment().isDST()) {
1890            if (startDateInM.isSame(originalStartM)) {
1891                startDateStdOffset = originalStartM.utcOffset();
1892            } else {
1893                startDateStdOffset = startDateInM.utcOffset();
1894            }
1895            var endDateStdOffset;
1896            if (endDateInM.isSame(originalStartM)) {
1897                endDateStdOffset = originalEndM.utcOffset();
1898            } else {
1899                endDateStdOffset = endDateInM.utcOffset();
1900            }
1901            var startDateInOffsetM = startDateInM.utcOffset(startDateStdOffset);
1902            var endDateInOffsetM = endDateInM.utcOffset(endDateStdOffset);
1903        } else {
1904            var startDateInOffsetM = originalStartM;
1905            var endDateInOffsetM = originalEndM;
1906        }
1907        var startFormat = ["h"];
1908        var endFormat = [];
1909        if (startDateInOffsetM.minute() > 0) {
1910            startFormat.push(":mm");
1911        }
1912        if (startDateInOffsetM.isSame(endDateInOffsetM)) {
1913            startFormat.push(" A");
1914        } else {
1915            if (startDateInOffsetM.format('A') != endDateInOffsetM.format('A')) {
1916                startFormat.push(" A");
1917            }
1918            endFormat.push("h");
1919            if (endDateInOffsetM.minute() > 0) {
1920                endFormat.push(":mm");
1921            }
1922            endFormat.push(" A");
1923        }
1924        timeOutput = startDateInOffsetM.format(startFormat.join(""));
1925        if (endFormat.length) {
1926            timeOutput += " - " + endDateInOffsetM.format(endFormat.join(""));
1927        }
1928    }
1929    return timeOutput;
1930}
1931
1932function filterCheck(fcLogic, fcPush, fcEvent) {
1933    if (debugMode) {
1934        console.log("filterCheck");
1935    }
1936    var fMatch = 0;
1937    for (let i = 0; i < filterTexts.length; i++) {
1938        if (filterTexts[i]) {
1939            for (let iFT = 0; iFT < filterTexts[i].length; iFT++) {
1940                if (filterTexts[i][iFT]) {
1941                    var eventFilter = fcEvent['filter' + (i + 1)];
1942                    var eventFilterCheck = [];
1943                    if (Array.isArray(eventFilter)) {
1944
1945                        for (let iEF = 0; iEF < eventFilter.length; iEF++) {
1946                            eventFilterCheck.push(eventFilter[iEF].toLowerCase().replace(/[^A-Za-z0-9]/g, ""));
1947                        };
1948                        if ($.inArray(filterTexts[i][iFT], eventFilterCheck) != -1) {
1949                            fMatch++
1950                        }
1951                    }
1952                }
1953            };
1954        }
1955    };
1956    if (fcLogic === "Or") {
1957        if (fMatch > 0) {
1958            fcPush.push(fcEvent);
1959        }
1960    } else if (fcLogic === "And") {
1961        if (fMatch == filterTextsAll.length) {
1962            fcPush.push(fcEvent);
1963        }
1964    }
1965}
1966
1967function relatedEventsAjax() {
1968    $.ajax({
1969        url: currentDataURL.replace(/&amp;/g, '&'),
1970        success: function(URLData) {
1971            calculateRecurrences(URLData.events).then(function(resultsR) {
1972                eventDateChecker(URLData.events, resultsR, "related-events").then(function(results) {
1973                    jsonToCurrentData(results).then(function(results) {
1974                        var rJCDE = results.jsonToCurrentDataEvents;
1975                        rJCDE.sort(function(a, b) {
1976                            return +new Date(a.startDate) - +new Date(b.startDate);
1977                        });
1978                        for (let i = 0; i < rJCDE.length; i++) {
1979                            if (rJCDE[i].id != currentEventID) {
1980                                if (moment(rJCDE[i].startDate).diff() > 0) {
1981                                    filterCheck(relatedEventsFilterLogic, relatedEvents, rJCDE[i]);
1982                                }
1983                            }
1984                            if (relatedEvents.length >= 6) {
1985                                break;
1986                            }
1987                        };
1988                        if (relatedEvents.length > 0) {
1989                            getRelatedEvents(relatedEvents).then(function(results) {
1990                                $('.related-events .events').empty();
1991                                $('.related-events .events').append(results.events);
1992                                if (typeof afterHHRelatedEventsLoad == 'function') {
1993                                    setTimeout(function() {
1994                                        afterHHRelatedEventsLoad();
1995                                    }, 50);
1996                                }
1997                            });
1998                        } else {
1999                            $('.related-events .events').empty();
2000                            $('.related-events .events').append('<div><p style="text-align:center">No upcoming related events found.</p></div>');
2001                        }
2002                    });
2003                });
2004            });
2005        },
2006        error: function(data) {
2007            if (data.status == 200) {
2008                console.log("JSON Not Valid: " + currentDataURL);
2009            } else {
2010                console.log("Data URL Not Found: " + currentDataURL);
2011            }
2012        }
2013    });
2014}
2015
2016function afterHHRelatedEventsLoad(){
2017    $('.hh-events .related-events .event').matchHeight();
2018}
2019
2020function afterHHEventsLoad(){
2021    $('.hh-events.hh-events-block .event').matchHeight();
2022}
2023
2024function blockEvents() {
2025    $.ajax({
2026        url: currentDataURL.replace(/&amp;/g, '&'),
2027        success: function(URLData) {
2028            calculateRecurrences(URLData.events).then(function(resultsR) {
2029                eventDateChecker(URLData.events, resultsR, "hh-events-block").then(function(results) {
2030                    jsonToCurrentData(results).then(function(results) {
2031                        var rJCDE = results.jsonToCurrentDataEvents;
2032                        rJCDE.sort(function(a, b) {
2033                            return +new Date(a.startDate) - +new Date(b.startDate);
2034                        });
2035                        var blockEventsCount = 0;
2036                        if (hhEventsType == "current") {
2037                            for (let i = 0; i < rJCDE.length; i++) {
2038                                if (moment(rJCDE[i].startDate).diff() > 0) {
2039                                    blockEventsCount++;
2040                                    hhEvents.push(rJCDE[i]);
2041                                    if (blockEventsCount == hhEventsLimit) {
2042                                        break;
2043                                    }
2044                                }
2045                            };
2046                        } else {
2047                            for (let i = 0; i < rJCDE.length; i++) {
2048                                if (moment(rJCDE[i].startDate).diff() > 0) {
2049                                    filterCheck(hhEventsFilterLogic, hhEvents, rJCDE[i]);
2050                                }
2051                                if (hhEvents.length >= hhEventsLimit) {
2052                                    break;
2053                                }
2054                            };
2055                        }
2056                        if (hhEvents.length > 0) {
2057                            getBlockEvents(hhEvents).then(function(results) {
2058                                $('.hh-events-block .row.events').empty();
2059                                $('.hh-events-block .row.events').append(results.events);
2060                                if (typeof afterHHEventsLoad == 'function') {
2061                                    setTimeout(function() {
2062                                        afterHHEventsLoad();
2063                                    }, 50);
2064                                }
2065                            });
2066                        } else {
2067                            $('.hh-events-block .row.events').empty();
2068                            $('.hh-events-block .row.events').append('<div><p style="text-align:center">No upcoming events found.</p></div>');
2069                        }
2070                    });
2071                });
2072            });
2073        },
2074        error: function(data) {
2075            if (data.status == 200) {
2076                console.log("JSON Not Valid: " + currentDataURL);
2077            } else {
2078                console.log("Data URL Not Found: " + currentDataURL);
2079            }
2080        }
2081    });
2082}

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.