diff --git a/app/assets/javascripts/property_hire_calendar_frontend.js b/app/assets/javascripts/property_hire_calendar_frontend.js index 87cdd39..750f25a 100644 --- a/app/assets/javascripts/property_hire_calendar_frontend.js +++ b/app/assets/javascripts/property_hire_calendar_frontend.js @@ -1,8 +1,112 @@ -var Calendar = function(dom,property_id){ +window.auto_close_popup = false; +$.fn.fullCalendar = function(args){ + var self = this[0] + if(!self.calendar_args) + self.calendar_args = args; + else + args = Object.assign(self.calendar_args, args); + var calendar = new FullCalendar.Calendar(self,args); + calendar.render(); + $(window).on("load",function(){ + calendar.render(); + }) + this.calendar = calendar; + self.calendar = calendar; + $.fullCalendar = calendar; + return calendar; +}; +function correct_date(date){ + var new_date = new Date(); + new_date.setTime(date.getTime() + date.getTimezoneOffset() * 60 * 1000); + return new_date; +} +FullCalendar.Calendar.prototype.get_all_events = function(){ + this.currentData.all_events = []; + var all_events = this.currentData.all_events; + if(this.currentData.eventStore && this.currentData.eventStore.instances){ + var instances = this.currentData.eventStore.instances; + Object.keys(instances).forEach(function(k){ + var instance = instances[k]; + var range = Object.assign({},instance.range); + range.start = correct_date(range.start); + range.end = correct_date(range.end); + all_events.push(range); + }) + } + return this.currentData.all_events; +} +FullCalendar.Calendar.prototype.isAnOverlapEvent = function(eventStartDay, eventEndDay){ + eventStartDay = eventStartDay || eventEndDay; + eventEndDay = eventEndDay || eventStartDay; + if((typeof(eventStartDay)).toLowerCase() == "string") + eventStartDay = new Date(eventStartDay); + if((typeof(eventEndDay)).toLowerCase() == "string") + eventEndDay = new Date(eventEndDay); + var events = this.get_all_events(); + for (var i = 0; i < events.length; i++) { + var eventA = events[i]; + // start-time in between any of the events + if (eventStartDay >= eventA.start && eventStartDay <= eventA.end) { + return true; + } + //end-time in between any of the events + if (eventEndDay >= eventA.start && eventEndDay <= eventA.end) { + return true; + } + //any of the events in between/on the start-time and end-time + if (eventStartDay <= eventA.start && eventEndDay >= eventA.end) { + return true; + } + } + return false; +} +window.is_chinese = ( I18n && I18n.locale.indexOf('zh') != -1 ); +window.datetime_format = is_chinese ? 'y M d h:m b' : 'd M, y h:m b'; +window.date_format = is_chinese ? 'y M d' : 'd M, y'; +window.time_format = "h:m b"; +window.date_time_str_format = 'y/MM/d H:m'; +window.short_day = (is_chinese ? "d (w)" : "w d") +window.short_date = (is_chinese ? "M d (w)" : "w d, M") +window.getDateString = function(date, format,is_chinese) { + var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + var week_days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']; + if(is_chinese){ + months = []; + for(var i=0;i<12;i++){ + months.push((i+1)+"月"); + } + week_days = ["週日","週一","週二","週三","週四","週五","週六"] + } + var getPaddedComp = function(comp) { + return ((parseInt(comp) < 10) ? ('0' + comp) : comp) + }, + formattedDate = format, + o = { + "y+": date.getFullYear() + (is_chinese ? "年" : ""), // year + "MM+": getPaddedComp(date.getMonth() + 1), //raw month + "M+": months[date.getMonth()], //month + "d+": (is_chinese ? (date.getDate() + "日") : getPaddedComp(date.getDate())), //day + "w+": week_days[date.getDay()], //weekday + "h+": getPaddedComp((date.getHours() > 12) ? date.getHours() % 12 : date.getHours()), //hour + "H+": getPaddedComp(date.getHours()), //hour + "m+": getPaddedComp(date.getMinutes()), //minute + "s+": getPaddedComp(date.getSeconds()), //second + "S+": getPaddedComp(date.getMilliseconds()), //millisecond, + "b+": (date.getHours() >= 12) ? 'PM' : 'AM' + }; + + for (var k in o) { + if (new RegExp("(" + k + ")").test(format)) { + formattedDate = formattedDate.replace(RegExp.$1, o[k]); + } + } + return formattedDate; +}; +var Calendar = function(dom,property_id,currentView){ c = this; this.title = $("#current_title"); - this.calendar = $(dom); + this.calendar_dom = $(dom); this.nextBtn = $("#next_month_btn"); this.prevBtn = $("#prev_month_btn"); this.todayBtn = $("#today_btn"); @@ -11,7 +115,7 @@ var Calendar = function(dom,property_id){ this.dialog = new EventDialog(c); this.loading = $('#calendar-loading'); this.agenda_space = $("#calendar_agenda"); - this.currentView = "month"; + this.currentView = currentView || "dayGridMonth"; this.property_id = property_id; this.navigation = $("#navigation"); this.rangeSelection = $("#range_selection"); @@ -22,43 +126,89 @@ var Calendar = function(dom,property_id){ var d = date.getDate(); var m = date.getMonth(); var y = date.getFullYear(); - var dview = (c.currentView == "agenda" ? "month" : c.currentView); - c.calendar.fullCalendar({ + var dview = (c.currentView == "agenda" ? "dayGridMonth" : c.currentView); + c.calendar_dom.css("overflow","visible"); + c.calendar_dom.fullCalendar({ + themeSystem: 'bootstrap', editable: false, - selectable: false, - events: "/xhr/property_hires/get_bookings?property_id="+c.property_id, - header: false, - default: dview, - height: $("body").height() - 141, + selectable: true, + width: "100%", + events: function(args, success_callback, fail_callback) { + var start = args.start; + var end = args.end; + $.ajax({ + url: "/xhr/property_hires/get_bookings?property_id="+c.property_id, + dataType: 'json', + type: 'GET', + data: { + start: Math.round(start.getTime() / 1000), + end: Math.round(end.getTime() / 1000), + _: Date.now() + }, + success: function(json) { + // json = json.map(function(obj){ + // obj.start = new Date(obj.start).toJSON(); + // obj.end = new Date(obj.end).toJSON(); + // return obj; + // }) + success_callback(json); + } + }); + }, + // events: 'https://fullcalendar.io/demo-events.json', + headerToolbar: false, + fixedWeekCount: false, + initialView: dview, loading: function(bool) { - if (bool) c.loading.css("left",($(window).width()/2 - 60) + "px").show(); + if (bool) c.loading.show(); else c.loading.hide(); + if(this.currentData) + $('#current_title').html(this.currentData.viewTitle); }, windowResize : function(view){ - view.setHeight($("body").height() - 141); - c.calendar.fullCalendar("refetchEvents"); + c.calendar_dom.calendar.refetchEvents(); }, - viewDisplay: function(view) { - c.title.html(view.title); - }, + eventTimeFormat: { hour12: true, hour: '2-digit', minute: '2-digit', omitZeroMinute: true, meridiem: 'narrow' }, eventClick: function(calEvent, e, view) { + if(calEvent.jsEvent && !e){ + e = {"originalEvent": calEvent.jsEvent} + } c.dialog.dismiss(); c.dialog.inflate(calEvent); c.dialog.show({"x":e.originalEvent.clientX,"y":e.originalEvent.clientY}); - } + }, + dateClick: function(ev) { + var calendar = this; + var calendar_dom = $(this.el); + if(c.calendar_dom.hasClass("active_picker")){ + var date = ev.date, + date_str = getDateString(date,date_time_str_format), + day_element = ev.dayEl, + jsEvent = ev.jsEvent; + var time_str = date_str.split(" ")[1]; + var date_str = date_str.split(" ")[0]; + calendar_dom.trigger("init_time",[time_str]); + calendar_dom.trigger("select_time",[date_str]); + } + }, + views: { + dayGridMonth: { + dayMaxEvents: true + } + } }); c.nextBtn.click(function(){ c.dialog.dismiss(); - c.calendar.fullCalendar('next'); + c.calendar_dom.calendar.next(); }); c.prevBtn.click(function(){ c.dialog.dismiss(); - c.calendar.fullCalendar('prev'); + c.calendar_dom.calendar.prev(); }); c.todayBtn.click(function(){ c.dialog.dismiss(); - c.calendar.fullCalendar('today'); + c.calendar_dom.calendar.today(); }); c.modeBtns.click(function(){ c.dialog.dismiss(); @@ -69,7 +219,7 @@ var Calendar = function(dom,property_id){ if(c.currentView == "agenda") agendaView.refresh(); else - c.calendar.fullCalendar("refetchEvents"); + c.calendar_dom.calendar.refetchEvents(); }); var toggleViews = function(view){ @@ -85,7 +235,7 @@ var Calendar = function(dom,property_id){ // $("#sec3").addClass("span4").removeClass("span5"); agendaView.hide(); } - c.calendar.fullCalendar('changeView',view); + c.calendar_dom.calendar.changeView(view); }else{ // $("#sec1").addClass("span7").removeClass("span3"); $("#sec2").hide(); @@ -94,19 +244,25 @@ var Calendar = function(dom,property_id){ } c.currentView = view; if(loadeventsonviewchange){ - c.calendar.fullCalendar("refetchEvents"); + c.calendar_dom.calendar.refetchEvents(); loadeventsonviewchange = false; } + if(c.calendar_dom.calendar.currentData){ + var viewTitle = c.calendar_dom.calendar.currentData.viewTitle; + if(view == "timeGridDay" && $('.fc-col-header-cell-cushion ').text() != "") + viewTitle = $('.fc-col-header-cell-cushion ').text() + ', ' + viewTitle; + $('#current_title').html(viewTitle); + } + c.calendar_dom.calendar.render(); //Rerender to fix layout }; if(c.currentView == "agenda"){toggleViews("agenda");loadeventsonviewchange = true;} - }; this.renderEvent = function(eventStick){ if(eventStick.recurring === true) - c.calendar.fullCalendar("refetchEvents"); + c.calendar_dom.calendar.refetchEvents(); else - c.calendar.fullCalendar("renderEvent",eventStick); + c.calendar_dom.calendar.renderEvent(eventStick); }; @@ -120,31 +276,48 @@ var EventDialog = function(calendar,event){ var event_quick_view = null; var template = ""; var _this_event = null; - var month_names = ["Jan","Feb","March","April","May","June","July","Aug","Sep","Oct","Nov","Dec"]; this.inflate = function(_event){ if(!_event) throw new UserException("EventStick can't be null!"); + _event.allDay = _event.event.allDay; + _event._start = _event.event.start; + _event._end = (_event.event.end ? _event.event.end : _event.event.start); + // var start_date = getDateString(_event._start,date_format); + // var end_date = getDateString(_event._end,date_format); + if(_event._end - _event._start > 86400 * 1000){ + _event.allDay = true; + } + _event.title = _event.event.title; + _event.hiring_person_name = _event.event.extendedProps.hiring_person_name; + _event.error_message = _event.event.extendedProps.error_message; + if(!_event.hiring_person_name) + _event.hiring_person_name = ""; + _event.note = _event.event.extendedProps.note; _this_event = _event; var start_time = "", - end_time = "", - time_string = null; - + end_time = "", + time_string = null; if(_event.allDay) { - start_time = $.fullCalendar.formatDate(_event._start,"MMM dd, yyyy"); + start_time = getDateString(_event._start,datetime_format, is_chinese); if(_event._end) - end_time = $.fullCalendar.formatDate(_event._end,"MMM dd, yyyy"); - time_string = (_event._start === _event._end || !_event._end ? "

" + start_time + "

" : " " + start_time + " " + end_time + ""); + end_time = getDateString(_event._end,datetime_format, is_chinese); + time_string = (_event._start === _event._end || !_event._end ? "

" + start_time + "

" : "" + start_time + "
" + end_time + ""); } else { - var sh = _event._start.getHours() > 12 ? _event._start.getHours() - 12 : _event._start.getHours(), - eh = _event._end.getHours() > 12 ? _event._end.getHours() - 12 : _event._end.getHours(), - sm = _event._start.getMinutes() < 10 ? '0' + _event._start.getMinutes() : _event._start.getMinutes(), - em = _event._end.getMinutes() < 10 ? '0' + _event._end.getMinutes() : _event._end.getMinutes(), - stime = _event._start.getHours() > 12 ? sh + ':' + sm + " PM" : sh + ':' + sm + " AM", - etime = _event._end.getHours() > 12 ? eh + ':' + em + " PM" : eh + ':' + em + " AM", - same = (_event._start.getDate() == _event._end.getDate() && _event._start.getMonth() == _event._end.getMonth() && _event._start.getFullYear() == _event._end.getFullYear()); - start_time = month_names[_event._start.getMonth()] + " " + _event._start.getDate() + ", " + _event._start.getFullYear(); - end_time = month_names[_event._end.getMonth()] + " " + _event._end.getDate() + ", " + _event._end.getFullYear(); - - time_string = (same ? "

" + start_time + "

" + stime + " " + etime : "

" + start_time + "" + stime + "

" + end_time + "" + etime + "

"); + start_time = getDateString(_event._start,date_format, is_chinese); + end_time = getDateString(_event._end,date_format, is_chinese); + var stime = getDateString(_event._start,time_format, is_chinese), + etime = getDateString(_event._end,time_format, is_chinese), + same = (start_time == end_time); + if( same ){ + time_string = "

" + + start_time + + "

" + stime + + " " + etime ; + }else{ + time_string = "" + start_time + " " + stime + + "
" + + end_time + " " + etime + "" + } + // time_string = (same ? "

" + start_time + "

" + stime + " " + etime : "

" + start_time + "" + stime + "

" + end_time + "" + etime + "

"); } event_quick_view = $(''); template = '' + '' + ''; @@ -161,6 +335,7 @@ var EventDialog = function(calendar,event){ this.show = function(pos){ + event_quick_view.css({width: '',height: ''}); if(pos){ var pos = getPosition(pos); event_quick_view.css({"left":pos.x+"px","top":pos.y+"px"}); @@ -169,6 +344,38 @@ var EventDialog = function(calendar,event){ event_quick_view.find(".event-close-btn").one("click",function(){_t.dismiss();}); event_quick_view.find("a.delete").one("click",function(){calendar.deleteEvent(_this_event.delete_url,_this_event._id);return false;}); event_quick_view.find("a.edit").one("click",function(){calendar.editEvent(_this_event.edit_url,_this_event.allDay);return false;}); + var window_width = $(window).width(), + window_height = $(window).height(); + var offset = event_quick_view.offset(); + var dialog_width = event_quick_view.width(), + dialog_height = event_quick_view.height(); + var new_offset = Object.assign({},offset); + var need_redisplay = false; + var new_width = null, new_height = null; + var padding = 20; + if(offset.left + dialog_width > window_width){ + new_offset.left = window_width - dialog_width - padding; + need_redisplay = true; + } + if(new_offset.left < padding){ + new_width = dialog_width - (padding - new_offset.left); + new_offset.left = padding; + need_redisplay = true; + } + if(offset.top + dialog_height > window_height){ + new_offset.top = window_height - dialog_height - padding; + need_redisplay = true; + } + if(new_offset.top < padding){ + new_height = dialog_height - (padding - new_offset.top); + new_offset.top = padding; + need_redisplay = true; + } + if(need_redisplay){ + event_quick_view.offset(new_offset); + event_quick_view.width(new_width); + event_quick_view.height(new_height); + } } this.dismiss = function(){ @@ -238,6 +445,7 @@ var AgendaView = function(calendar){ 'Date' + 'Time' + 'Events' + + 'Borrower' + '' + '' + '' + @@ -250,11 +458,9 @@ var AgendaView = function(calendar){ var head_template = '
' + '' + - '' + + ''+ '' + - '' + + ''+ '' + '
'; @@ -264,6 +470,7 @@ var AgendaView = function(calendar){ '' + '
' + '' + + ''+ ''; // var month_template = '

SunMonTueWedThuFriSat
'; @@ -282,7 +489,7 @@ var AgendaView = function(calendar){ this.inflate = function(forceInflation){ loading(true); - _calendar.calendar.hide(); + _calendar.calendar_dom.hide(); _calendar.navigation.hide(); if(!forceInflation){ @@ -299,10 +506,12 @@ var AgendaView = function(calendar){ _calendar.rangeSelection.append(renderHead().html()).show(); _calendar.rangeSelection.find("button#show_events").click(function(){ show_event_clicked = true; - start_month = parseInt($("select[name=start_month]").val()); - end_month = parseInt($("select[name=end_month]").val()); - start_year = parseInt($("select[name=start_year]").val()); - end_year = parseInt($("select[name=end_year]").val()); + var starts = $("#agenda_start").val().split("/"), + ends = $("#agenda_end").val().split("/"); + start_month = parseInt(starts[1]) - 1; + end_month = parseInt(ends[1]) - 1; + start_year = parseInt(starts[0]); + end_year = parseInt(ends[0]); av.inflate(true); }) } @@ -336,7 +545,7 @@ var AgendaView = function(calendar){ _calendar.rangeSelection.hide(); agenda_space.hide(); _calendar.navigation.show(); - _calendar.calendar.show(); + _calendar.calendar_dom.show(); } this.show = function(){ @@ -347,7 +556,7 @@ var AgendaView = function(calendar){ return x.clone(); } var eventsManager = function(){ - var url = "/xhr/calendars/agenda", + var url = "/xhr/property_hires/get_bookings?property_id="+_calendar.property_id, sd = new Date(start_year,start_month,1), ed = new Date(end_year,end_month+1,0), usd = Math.round(sd/1000), @@ -355,9 +564,39 @@ var AgendaView = function(calendar){ $.ajax({ type : "get", url : url, - data : {"agenda_start":sd.toLocaleString(),"agenda_end":ed.toLocaleString(),"page_id" : _calendar.page_id,"unix_start":usd,"unix_end":ued}, + dataType : "json", + data : {"agenda_start":sd.toLocaleString(),"agenda_end":ed.toLocaleString(),"page_id" : _calendar.page_id,"start":usd,"end":ued}, success : function(data){ - $.each(data.events,function(i,e){ + $("#agenda_start,#agenda_end").datepicker({ + dateFormat: "yy/mm", + onChangeMonthYear: function( year, month, inst ){ + $(this).val($.datepicker.formatDate('yy/mm', new Date(year, month-1, 1))); + }, + gotoCurrent: true + }); + $("#agenda_start,#agenda_end").on("focus",function(){ + var input = this; + var inst = $(this).data("datepicker"); + var year_month = $(input).val().split("/"); + if(year_month.length == 2){ + inst.selectedYear = parseInt(year_month[0]); + inst.selectedMonth = parseInt(year_month[1]) - 1; + inst.drawYear = inst.selectedYear; + inst.drawMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + inst.currentMonth = inst.selectedMonth; + } + $.datepicker._updateDatepicker(inst); + }) + $("#agenda_start,#agenda_end").focus(function () { + $(".ui-datepicker-calendar").hide(); + $("#ui-datepicker-div").position({ + my: "center top", + at: "center bottom", + of: $(this) + }); + }); + $.each(data,function(i,e){ var ed = eventDom(e), s = new Date(e.start), e = new Date(e.end), @@ -414,14 +653,16 @@ var AgendaView = function(calendar){ var e_t = $(event_template), s = new Date(event.start), e = new Date(event.end), - dateFormat = ""; + dateFormat = "", + hiring_person_name = event.hiring_person_name; if(s.getDate() == e.getDate() && s.getMonth() == s.getMonth() && e.getFullYear() == e.getFullYear()) - dateFormat = $.fullCalendar.formatDate(s, "ddd dd"); + dateFormat = getDateString(s, short_day,is_chinese); else - dateFormat = $.fullCalendar.formatDates(s, e, "ddd dd, MMM - {ddd dd, MMM}"); + dateFormat = getDateString(s,short_date,is_chinese) + ' - ' + getDateString(e,short_date,is_chinese); e_t.find("td:first").text(dateFormat); - e_t.find("td.event_time").text((event.allDay ? "All Day" : $.fullCalendar.formatDate(s, "hh:mm"))); + e_t.find("td.event_time").text((event.allDay ? "All Day" : (getDateString(s, "h:m b")+"~"+getDateString(e, "h:m b")))); e_t.find("div.event").text(event.title).css("color",event.color); + e_t.find("td.Borrower").text(hiring_person_name); return e_t; } diff --git a/app/assets/javascripts/property_hire_fullcalendar.js b/app/assets/javascripts/property_hire_fullcalendar.js new file mode 100644 index 0000000..a1988a6 --- /dev/null +++ b/app/assets/javascripts/property_hire_fullcalendar.js @@ -0,0 +1,20319 @@ +/*! +FullCalendar Scheduler v5.8.0 +Docs & License: https://fullcalendar.io/scheduler +(c) 2021 Adam Shaw +*/ +var ie_args = navigator && navigator.userAgent.match(/MSIE\s+(\d+)/); +var is_below_es6 = false; +if(ie_args){ + var ie_ver = parseInt(ie_args[1]); + if(ie_ver <= 10 || !Object.__proto__){ + Object.setPrototypeOf = function(obj, proto) { + obj.prototype = Object.create(proto.prototype); + obj.prototype.constructor = obj; + obj.__proto__ = proto; + var own_props = Object.getOwnPropertyNames(proto); + own_props.forEach(function(prop){ + try{ + if(prop == "caller" || prop == "length" || prop == "arguments") + return; + obj[prop] = proto[prop]; + }catch(e){}; + }) + return obj; + } + var global = (((typeof(globalThis)).toLowerCase() == "undefined") ? window : globalThis); + if((typeof(DOMTokenList)).toLowerCase() == "undefined"){ + /** + * Polyfill of DOMTokenList for IE < 9 + * Monkey patch of .add, .remove for IE 10 / 11, Firefox < 26 to support multiple arguments + * Monkey patch of .toggle for IE 10 / 11, Firefox < 24 to support second argument + */ + /*global define: false, module: false */ + /*jslint nomen: true */ + (function domTokenListModule(global, definition) { // non-exporting module magic dance + 'use strict'; + + var + amd = 'amd', + exports = 'exports'; // keeps the method names for CommonJS / AMD from being compiled to single character variable + + if (typeof define === 'function' && define[amd]) { + define(function definer() { + return definition(global); + }); + } else if (typeof module === 'function' && module[exports]) { + module[exports] = definition(global); + } else { + definition(global); + } + }(this, function domTokenListPolyfill(global) { + 'use strict'; + + if (!global.Element) { + return; + } + + var + document = global.document, + id = 0, + lists = {}, + test = document.createElement('_'); + + /** + * @private + */ + function createMethod(method) { + var + original = this.prototype[method]; + + this.prototype[method] = function override() { + var + counter, + length, + token; + + for (counter = 0, length = arguments.length; counter < length; counter += 1) { + token = arguments[counter]; + original.call(this, token); + } + }; + } + + /** + * @private + * @param {string} token Token to search for + */ + function indexOf(token) { + var + arrayPrototype = Array.prototype, + counter; + + if (!!arrayPrototype.indexOf) { + return arrayPrototype.indexOf.call(this, token); + } + + counter = this.length - 1; + while (counter > -1) { + if (this[counter] === token) { + return counter; + } + + counter -= 1; + } + + return -1; + } + + /** + * @private + */ + function newId() { + id += 1; + + return id; + } + + /** + * @private + */ + function onchange() { + var + classes = this.classes, + classesString = classes.join(' '); + + if (this.isSVG) { + this.setAttribute('class', classesString); + } else { + this.element.className = classesString; + } + + this.list.length = classes.length; + } + + /** + * @param {string} token Token to find + */ + function contains(token) { + return indexOf.call(lists[this.id].classes, token) !== -1; + } + + function add() { + var + counter = 0, + item = lists[this.id], + classes = item.classes, + length = arguments.length, + token, + updated = false; + + while (counter < length) { + token = arguments[counter]; + if (indexOf.call(classes, token) === -1) { + classes.push(token); + updated = true; + } + + counter += 1; + } + + if (updated) { + onchange.call(item); + } + } + + /** + * @param {number} index Index of list to return value + */ + function item(index) { + return lists[this.id].classes[index] || null; + } + + function remove() { + var + counter = arguments.length - 1, + entry = lists[this.id], + classes = entry.classes, + index, + token, + updated = false; + + while (counter > -1) { + token = arguments[counter]; + index = indexOf.call(classes, token); + if (index !== -1) { + classes.splice(index, 1); + updated = true; + } + + counter -= 1; + } + + if (updated) { + onchange.call(entry); + } + } + + function toString() { + var + entry = lists[this.id]; + + onchange.call(entry); + return entry.element.className; + } + + /** + * @param {string} token Token to toggle + * @param {force=} force Flag to force toggle + */ + function toggle(token, force) { + var + hasToken = indexOf.call(lists[this.id].classes, token) !== -1, + method; + + if (hasToken) { + if (force !== true) { + method = 'remove'; + } + } else { + if (force !== false) { + method = 'add'; + } + } + + if (method) { + this[method](token); + } + + return (force === true || force === false) ? force : !hasToken; + } + + /** + * @constructor + */ + function DOMTokenList(element) { + var + className, + listId, + isSVG; + + listId = element.domTokenListId; + if (listId && (listId in lists)) { + return lists[listId].list; + } + + isSVG = typeof element.className === 'object'; + className = element.className; + className = String(isSVG ? className.baseVal : className).replace(/^\s+|\s+$/, ''); + listId = newId(); + + lists[listId] = { + classes: className.length !== 0 ? className.split(/\s+/) : [], + element: element, + list: this, + isSVG: isSVG + }; + this.id = listId; + this.length = lists[listId].classes.length; + element.domTokenListId = listId; // apply id lookup reference to element + } + + if (!('classList' in test)) { + (function () { + var + counter, + elementPrototype = global.Element.prototype, + methodList = [add, contains, item, remove, toString, toggle], + methods = ['add', 'contains', 'item', 'remove', 'toString', 'toggle'], + propertyDescriptor, + prototype = DOMTokenList.prototype; + + function get() { + var + thisId = this.domTokenListId; + + return thisId && (thisId in lists) ? lists[thisId].list : new DOMTokenList(this); + } + + counter = methods.length - 1; + while (counter > -1) { + prototype[methods[counter]] = methodList[counter]; + counter -= 1; + } + + propertyDescriptor = { + get: get, + configurable: true, + enumerable: true + }; + + if (Object.defineProperty) { + try { + Object.defineProperty(elementPrototype, 'classList', propertyDescriptor); + } catch (ex) { + if (ex.number === -0x7FF5EC54) { // IE 8 doesn't like it to be enumerable + propertyDescriptor.enumerable = false; + Object.defineProperty(elementPrototype, 'classList', propertyDescriptor); + } + } + } else if (Object.prototype.__defineGetter__) { + elementPrototype.__defineGetter__('classList', propertyDescriptor); + } + + global.DOMTokenList = DOMTokenList; + }()); + } else { + test.classList.add('c1', 'c2'); + + if (!test.classList.contains('c2')) { // IE 10 / 11, Firefox < 26 + createMethod.call(global.DOMTokenList, 'add'); + createMethod.call(global.DOMTokenList, 'remove'); + } + + test.classList.toggle('c3', false); + if (test.classList.contains('c3')) { // IE 10 / 11, Firefox < 24 + global.DOMTokenList.prototype.toggle = (function () { + var + original = global.DOMTokenList.prototype.toggle; + + return function toggle(token, force) { + var + notForce = !force; + + return (arguments.length > 1 && !(this.contains(token) === notForce)) ? force : original.call(this, token); + }; + }()); + } + + test = null; + } + })); + } + is_below_es6 = true; + } +} +var FullCalendar = (function (exports) { + 'use strict'; + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + ***************************************************************************** */ + /* global Reflect, Promise */ + + var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + + function __extends(d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + d.__proto__ = b; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + } + + var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); + }; + + function __spreadArray(to, from) { + for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) + to[j] = from[i]; + return to; + } + + var n,u,i$1,t,o,r$1={},f$1=[],e$1=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function c$1(n,l){for(var u in l)n[u]=l[u];return n}function s(n){var l=n.parentNode;l&&l.removeChild(n);}function a$1(n,l,u){var i,t,o,r=arguments,f={};for(o in l)"key"==o?i=l[o]:"ref"==o?t=l[o]:f[o]=l[o];if(arguments.length>3)for(u=[u],o=3;o0?v$1(k.type,k.props,k.key,null,k.__v):k)){if(k.__=u,k.__b=u.__b+1,null===(_=A[h])||_&&k.key==_.key&&k.type===_.type)A[h]=void 0;else for(p=0;p3;)e.pop()();if(e[1]>>1,1),t.i.removeChild(n);}}),N(a$1(T,{context:t.context},n.__v),t.l)):t.l&&t.componentWillUnmount();}function I(n,t){return a$1(j,{__v:n,i:t})}(F.prototype=new p).__e=function(n){var t=this,e=U(t.__v),r=t.o.get(n);return r[0]++,function(u){var o=function(){t.props.revealOrder?(r.push(u),M(t,n,r)):u();};e?e(o):o();}},F.prototype.render=function(n){this.u=null,this.o=new Map;var t=w$1(n.children);n.revealOrder&&"b"===n.revealOrder[0]&&t.reverse();for(var e=t.length;e--;)this.o.set(t[e],this.u=[1,0,this.u]);return n.children},F.prototype.componentDidUpdate=F.prototype.componentDidMount=function(){var n=this;this.o.forEach(function(t,e){M(n,e,t);});};var W="undefined"!=typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103,P=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|fill|flood|font|glyph(?!R)|horiz|marker(?!H|W|U)|overline|paint|stop|strikethrough|stroke|text(?!L)|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,V=function(n){return ("undefined"!=typeof Symbol&&"symbol"==typeof Symbol()?/fil|che|rad/i:/fil|che|ra/i).test(n)};p.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(n){Object.defineProperty(p.prototype,n,{configurable:!0,get:function(){return this["UNSAFE_"+n]},set:function(t){Object.defineProperty(this,n,{configurable:!0,writable:!0,value:t});}});});var H=n.event;function Z(){}function Y(){return this.cancelBubble}function $(){return this.defaultPrevented}n.event=function(n){return H&&(n=H(n)),n.persist=Z,n.isPropagationStopped=Y,n.isDefaultPrevented=$,n.nativeEvent=n};var G={configurable:!0,get:function(){return this.class}},J=n.vnode;n.vnode=function(n){var t=n.type,e=n.props,r=e;if("string"==typeof t){for(var u in r={},e){var o=e[u];"value"===u&&"defaultValue"in e&&null==o||("defaultValue"===u&&"value"in e&&null==e.value?u="value":"download"===u&&!0===o?o="":/ondoubleclick/i.test(u)?u="ondblclick":/^onchange(textarea|input)/i.test(u+t)&&!V(e.type)?u="oninput":/^on(Ani|Tra|Tou|BeforeInp)/.test(u)?u=u.toLowerCase():P.test(u)?u=u.replace(/[A-Z0-9]/,"-$&").toLowerCase():null===o&&(o=void 0),r[u]=o);}"select"==t&&r.multiple&&Array.isArray(r.value)&&(r.value=w$1(e.children).forEach(function(n){n.props.selected=-1!=r.value.indexOf(n.props.value);})),"select"==t&&null!=r.defaultValue&&(r.value=w$1(e.children).forEach(function(n){n.props.selected=r.multiple?-1!=r.defaultValue.indexOf(n.props.value):r.defaultValue==n.props.value;})),n.props=r;}t&&e.class!=e.className&&(G.enumerable="className"in e,null!=e.className&&(r.class=e.className),Object.defineProperty(r,"className",G)),n.$$typeof=W,J&&J(n);};var K=n.__r;n.__r=function(n){K&&K(n);};"object"==typeof performance&&"function"==typeof performance.now?performance.now.bind(performance):function(){return Date.now()}; + + var globalObj = typeof globalThis !== 'undefined' ? globalThis : window; // // TODO: streamline when killing IE11 support + if (globalObj.FullCalendarVDom) { + console.warn('FullCalendar VDOM already loaded'); + } + else { + globalObj.FullCalendarVDom = { + Component: p, + createElement: a$1, + render: N, + createRef: h, + Fragment: y, + createContext: createContext$1, + createPortal: I, + flushToDom: flushToDom$1, + unmountComponentAtNode: unmountComponentAtNode$1, + }; + } + // HACKS... + // TODO: lock version + // TODO: link gh issues + function flushToDom$1() { + var oldDebounceRendering = n.debounceRendering; // orig + var callbackQ = []; + function execCallbackSync(callback) { + callbackQ.push(callback); + } + n.debounceRendering = execCallbackSync; + N(a$1(FakeComponent, {}), document.createElement('div')); + while (callbackQ.length) { + callbackQ.shift()(); + } + n.debounceRendering = oldDebounceRendering; + } + var FakeComponent = /** @class */ (function (_super) { + __extends(FakeComponent, _super); + function FakeComponent() { + return _super !== null && _super.apply(this, arguments) || this; + } + FakeComponent.prototype.render = function () { return a$1('div', {}); }; + FakeComponent.prototype.componentDidMount = function () { this.setState({}); }; + return FakeComponent; + }(p)); + function createContext$1(defaultValue) { + var ContextType = q(defaultValue); + var origProvider = ContextType.Provider; + ContextType.Provider = function () { + var _this = this; + var isNew = !this.getChildContext; + var children = origProvider.apply(this, arguments); // eslint-disable-line prefer-rest-params + if (isNew) { + var subs_1 = []; + this.shouldComponentUpdate = function (_props) { + if (_this.props.value !== _props.value) { + subs_1.forEach(function (c) { + c.context = _props.value; + c.forceUpdate(); + }); + } + }; + this.sub = function (c) { + subs_1.push(c); + var old = c.componentWillUnmount; + c.componentWillUnmount = function () { + subs_1.splice(subs_1.indexOf(c), 1); + old && old.call(c); + }; + }; + } + return children; + }; + return ContextType; + } + function unmountComponentAtNode$1(node) { + N(null, node); + } + + // no public types yet. when there are, export from: + // import {} from './api-type-deps' + var EventSourceApi = /** @class */ (function () { + function EventSourceApi(context, internalEventSource) { + this.context = context; + this.internalEventSource = internalEventSource; + } + EventSourceApi.prototype.remove = function () { + this.context.dispatch({ + type: 'REMOVE_EVENT_SOURCE', + sourceId: this.internalEventSource.sourceId, + }); + }; + EventSourceApi.prototype.refetch = function () { + this.context.dispatch({ + type: 'FETCH_EVENT_SOURCES', + sourceIds: [this.internalEventSource.sourceId], + isRefetch: true, + }); + }; + Object.defineProperty(EventSourceApi.prototype, "id", { + get: function () { + return this.internalEventSource.publicId; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventSourceApi.prototype, "url", { + get: function () { + return this.internalEventSource.meta.url; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventSourceApi.prototype, "format", { + get: function () { + return this.internalEventSource.meta.format; // TODO: bad. not guaranteed + }, + enumerable: false, + configurable: true + }); + return EventSourceApi; + }()); + + function removeElement(el) { + if (el.parentNode) { + el.parentNode.removeChild(el); + } + } + // Querying + // ---------------------------------------------------------------------------------------------------------------- + function elementClosest(el, selector) { + if (el.closest) { + return el.closest(selector); + // really bad fallback for IE + // from https://developer.mozilla.org/en-US/docs/Web/API/Element/closest + } + if (!document.documentElement.contains(el)) { + return null; + } + do { + if (elementMatches(el, selector)) { + return el; + } + el = (el.parentElement || el.parentNode); + } while (el !== null && el.nodeType === 1); + return null; + } + function elementMatches(el, selector) { + var method = el.matches || el.matchesSelector || el.msMatchesSelector; + return method.call(el, selector); + } + // accepts multiple subject els + // returns a real array. good for methods like forEach + // TODO: accept the document + function findElements(container, selector) { + var containers = container instanceof HTMLElement ? [container] : container; + var allMatches = []; + for (var i = 0; i < containers.length; i += 1) { + var matches = containers[i].querySelectorAll(selector); + for (var j = 0; j < matches.length; j += 1) { + allMatches.push(matches[j]); + } + } + return allMatches; + } + // accepts multiple subject els + // only queries direct child elements // TODO: rename to findDirectChildren! + function findDirectChildren(parent, selector) { + var parents = parent instanceof HTMLElement ? [parent] : parent; + var allMatches = []; + for (var i = 0; i < parents.length; i += 1) { + var childNodes = parents[i].children; // only ever elements + for (var j = 0; j < childNodes.length; j += 1) { + var childNode = childNodes[j]; + if (!selector || elementMatches(childNode, selector)) { + allMatches.push(childNode); + } + } + } + return allMatches; + } + // Style + // ---------------------------------------------------------------------------------------------------------------- + var PIXEL_PROP_RE = /(top|left|right|bottom|width|height)$/i; + function applyStyle(el, props) { + for (var propName in props) { + applyStyleProp(el, propName, props[propName]); + } + } + function applyStyleProp(el, name, val) { + if (val == null) { + el.style[name] = ''; + } + else if (typeof val === 'number' && PIXEL_PROP_RE.test(name)) { + el.style[name] = val + "px"; + } + else { + el.style[name] = val; + } + } + // Event Handling + // ---------------------------------------------------------------------------------------------------------------- + // if intercepting bubbled events at the document/window/body level, + // and want to see originating element (the 'target'), use this util instead + // of `ev.target` because it goes within web-component boundaries. + function getEventTargetViaRoot(ev) { + var _a, _b; + return (_b = (_a = ev.composedPath) === null || _a === void 0 ? void 0 : _a.call(ev)[0]) !== null && _b !== void 0 ? _b : ev.target; + } + + // Stops a mouse/touch event from doing it's native browser action + function preventDefault(ev) { + ev.preventDefault(); + } + // Event Delegation + // ---------------------------------------------------------------------------------------------------------------- + function buildDelegationHandler(selector, handler) { + return function (ev) { + var matchedChild = elementClosest(ev.target, selector); + if (matchedChild) { + handler.call(matchedChild, ev, matchedChild); + } + }; + } + function listenBySelector(container, eventType, selector, handler) { + var attachedHandler = buildDelegationHandler(selector, handler); + container.addEventListener(eventType, attachedHandler); + return function () { + container.removeEventListener(eventType, attachedHandler); + }; + } + function listenToHoverBySelector(container, selector, onMouseEnter, onMouseLeave) { + var currentMatchedChild; + return listenBySelector(container, 'mouseover', selector, function (mouseOverEv, matchedChild) { + if (matchedChild !== currentMatchedChild) { + currentMatchedChild = matchedChild; + onMouseEnter(mouseOverEv, matchedChild); + var realOnMouseLeave_1 = function (mouseLeaveEv) { + currentMatchedChild = null; + onMouseLeave(mouseLeaveEv, matchedChild); + matchedChild.removeEventListener('mouseleave', realOnMouseLeave_1); + }; + // listen to the next mouseleave, and then unattach + matchedChild.addEventListener('mouseleave', realOnMouseLeave_1); + } + }); + } + // Animation + // ---------------------------------------------------------------------------------------------------------------- + var transitionEventNames = [ + 'webkitTransitionEnd', + 'otransitionend', + 'oTransitionEnd', + 'msTransitionEnd', + 'transitionend', + ]; + // triggered only when the next single subsequent transition finishes + function whenTransitionDone(el, callback) { + var realCallback = function (ev) { + callback(ev); + transitionEventNames.forEach(function (eventName) { + el.removeEventListener(eventName, realCallback); + }); + }; + transitionEventNames.forEach(function (eventName) { + el.addEventListener(eventName, realCallback); // cross-browser way to determine when the transition finishes + }); + } + + var guidNumber = 0; + function guid() { + guidNumber += 1; + return String(guidNumber); + } + /* FullCalendar-specific DOM Utilities + ----------------------------------------------------------------------------------------------------------------------*/ + // Make the mouse cursor express that an event is not allowed in the current area + function disableCursor() { + document.body.classList.add('fc-not-allowed'); + } + // Returns the mouse cursor to its original look + function enableCursor() { + document.body.classList.remove('fc-not-allowed'); + } + /* Selection + ----------------------------------------------------------------------------------------------------------------------*/ + function preventSelection(el) { + el.classList.add('fc-unselectable'); + el.addEventListener('selectstart', preventDefault); + } + function allowSelection(el) { + el.classList.remove('fc-unselectable'); + el.removeEventListener('selectstart', preventDefault); + } + /* Context Menu + ----------------------------------------------------------------------------------------------------------------------*/ + function preventContextMenu(el) { + el.addEventListener('contextmenu', preventDefault); + } + function allowContextMenu(el) { + el.removeEventListener('contextmenu', preventDefault); + } + function parseFieldSpecs(input) { + var specs = []; + var tokens = []; + var i; + var token; + if (typeof input === 'string') { + tokens = input.split(/\s*,\s*/); + } + else if (typeof input === 'function') { + tokens = [input]; + } + else if (Array.isArray(input)) { + tokens = input; + } + for (i = 0; i < tokens.length; i += 1) { + token = tokens[i]; + if (typeof token === 'string') { + specs.push(token.charAt(0) === '-' ? + { field: token.substring(1), order: -1 } : + { field: token, order: 1 }); + } + else if (typeof token === 'function') { + specs.push({ func: token }); + } + } + return specs; + } + function compareByFieldSpecs(obj0, obj1, fieldSpecs) { + var i; + var cmp; + for (i = 0; i < fieldSpecs.length; i += 1) { + cmp = compareByFieldSpec(obj0, obj1, fieldSpecs[i]); + if (cmp) { + return cmp; + } + } + return 0; + } + function compareByFieldSpec(obj0, obj1, fieldSpec) { + if (fieldSpec.func) { + return fieldSpec.func(obj0, obj1); + } + return flexibleCompare(obj0[fieldSpec.field], obj1[fieldSpec.field]) + * (fieldSpec.order || 1); + } + function flexibleCompare(a, b) { + if (!a && !b) { + return 0; + } + if (b == null) { + return -1; + } + if (a == null) { + return 1; + } + if (typeof a === 'string' || typeof b === 'string') { + return String(a).localeCompare(String(b)); + } + return a - b; + } + /* String Utilities + ----------------------------------------------------------------------------------------------------------------------*/ + function padStart(val, len) { + var s = String(val); + return '000'.substr(0, len - s.length) + s; + } + /* Number Utilities + ----------------------------------------------------------------------------------------------------------------------*/ + function compareNumbers(a, b) { + return a - b; + } + function isInt(n) { + return n % 1 === 0; + } + /* FC-specific DOM dimension stuff + ----------------------------------------------------------------------------------------------------------------------*/ + function computeSmallestCellWidth(cellEl) { + var allWidthEl = cellEl.querySelector('.fc-scrollgrid-shrink-frame'); + var contentWidthEl = cellEl.querySelector('.fc-scrollgrid-shrink-cushion'); + if (!allWidthEl) { + throw new Error('needs fc-scrollgrid-shrink-frame className'); // TODO: use const + } + if (!contentWidthEl) { + throw new Error('needs fc-scrollgrid-shrink-cushion className'); + } + return cellEl.getBoundingClientRect().width - allWidthEl.getBoundingClientRect().width + // the cell padding+border + contentWidthEl.getBoundingClientRect().width; + } + + var DAY_IDS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']; + // Adding + function addWeeks(m, n) { + var a = dateToUtcArray(m); + a[2] += n * 7; + return arrayToUtcDate(a); + } + function addDays(m, n) { + var a = dateToUtcArray(m); + a[2] += n; + return arrayToUtcDate(a); + } + function addMs(m, n) { + var a = dateToUtcArray(m); + a[6] += n; + return arrayToUtcDate(a); + } + // Diffing (all return floats) + // TODO: why not use ranges? + function diffWeeks(m0, m1) { + return diffDays(m0, m1) / 7; + } + function diffDays(m0, m1) { + return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60 * 24); + } + function diffHours(m0, m1) { + return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60); + } + function diffMinutes(m0, m1) { + return (m1.valueOf() - m0.valueOf()) / (1000 * 60); + } + function diffSeconds(m0, m1) { + return (m1.valueOf() - m0.valueOf()) / 1000; + } + function diffDayAndTime(m0, m1) { + var m0day = startOfDay(m0); + var m1day = startOfDay(m1); + return { + years: 0, + months: 0, + days: Math.round(diffDays(m0day, m1day)), + milliseconds: (m1.valueOf() - m1day.valueOf()) - (m0.valueOf() - m0day.valueOf()), + }; + } + // Diffing Whole Units + function diffWholeWeeks(m0, m1) { + var d = diffWholeDays(m0, m1); + if (d !== null && d % 7 === 0) { + return d / 7; + } + return null; + } + function diffWholeDays(m0, m1) { + if (timeAsMs(m0) === timeAsMs(m1)) { + return Math.round(diffDays(m0, m1)); + } + return null; + } + // Start-Of + function startOfDay(m) { + return arrayToUtcDate([ + m.getUTCFullYear(), + m.getUTCMonth(), + m.getUTCDate(), + ]); + } + function startOfHour(m) { + return arrayToUtcDate([ + m.getUTCFullYear(), + m.getUTCMonth(), + m.getUTCDate(), + m.getUTCHours(), + ]); + } + function startOfMinute(m) { + return arrayToUtcDate([ + m.getUTCFullYear(), + m.getUTCMonth(), + m.getUTCDate(), + m.getUTCHours(), + m.getUTCMinutes(), + ]); + } + function startOfSecond(m) { + return arrayToUtcDate([ + m.getUTCFullYear(), + m.getUTCMonth(), + m.getUTCDate(), + m.getUTCHours(), + m.getUTCMinutes(), + m.getUTCSeconds(), + ]); + } + // Week Computation + function weekOfYear(marker, dow, doy) { + var y = marker.getUTCFullYear(); + var w = weekOfGivenYear(marker, y, dow, doy); + if (w < 1) { + return weekOfGivenYear(marker, y - 1, dow, doy); + } + var nextW = weekOfGivenYear(marker, y + 1, dow, doy); + if (nextW >= 1) { + return Math.min(w, nextW); + } + return w; + } + function weekOfGivenYear(marker, year, dow, doy) { + var firstWeekStart = arrayToUtcDate([year, 0, 1 + firstWeekOffset(year, dow, doy)]); + var dayStart = startOfDay(marker); + var days = Math.round(diffDays(firstWeekStart, dayStart)); + return Math.floor(days / 7) + 1; // zero-indexed + } + // start-of-first-week - start-of-year + function firstWeekOffset(year, dow, doy) { + // first-week day -- which january is always in the first week (4 for iso, 1 for other) + var fwd = 7 + dow - doy; + // first-week day local weekday -- which local weekday is fwd + var fwdlw = (7 + arrayToUtcDate([year, 0, fwd]).getUTCDay() - dow) % 7; + return -fwdlw + fwd - 1; + } + // Array Conversion + function dateToLocalArray(date) { + return [ + date.getFullYear(), + date.getMonth(), + date.getDate(), + date.getHours(), + date.getMinutes(), + date.getSeconds(), + date.getMilliseconds(), + ]; + } + function arrayToLocalDate(a) { + return new Date(a[0], a[1] || 0, a[2] == null ? 1 : a[2], // day of month + a[3] || 0, a[4] || 0, a[5] || 0); + } + function dateToUtcArray(date) { + return [ + date.getUTCFullYear(), + date.getUTCMonth(), + date.getUTCDate(), + date.getUTCHours(), + date.getUTCMinutes(), + date.getUTCSeconds(), + date.getUTCMilliseconds(), + ]; + } + function arrayToUtcDate(a) { + // according to web standards (and Safari), a month index is required. + // massage if only given a year. + if (a.length === 1) { + a = a.concat([0]); + } + return new Date(Date.UTC.apply(Date, a)); + } + // Other Utils + function isValidDate$1(m) { + return !isNaN(m.valueOf()); + } + function timeAsMs(m) { + return m.getUTCHours() * 1000 * 60 * 60 + + m.getUTCMinutes() * 1000 * 60 + + m.getUTCSeconds() * 1000 + + m.getUTCMilliseconds(); + } + + function createEventInstance(defId, range, forcedStartTzo, forcedEndTzo) { + return { + instanceId: guid(), + defId: defId, + range: range, + forcedStartTzo: forcedStartTzo == null ? null : forcedStartTzo, + forcedEndTzo: forcedEndTzo == null ? null : forcedEndTzo, + }; + } + + var hasOwnProperty = Object.prototype.hasOwnProperty; + // Merges an array of objects into a single object. + // The second argument allows for an array of property names who's object values will be merged together. + function mergeProps(propObjs, complexPropsMap) { + var dest = {}; + if (complexPropsMap) { + for (var name_1 in complexPropsMap) { + var complexObjs = []; + // collect the trailing object values, stopping when a non-object is discovered + for (var i = propObjs.length - 1; i >= 0; i -= 1) { + var val = propObjs[i][name_1]; + if (typeof val === 'object' && val) { // non-null object + complexObjs.unshift(val); + } + else if (val !== undefined) { + dest[name_1] = val; // if there were no objects, this value will be used + break; + } + } + // if the trailing values were objects, use the merged value + if (complexObjs.length) { + dest[name_1] = mergeProps(complexObjs); + } + } + } + // copy values into the destination, going from last to first + for (var i = propObjs.length - 1; i >= 0; i -= 1) { + var props = propObjs[i]; + for (var name_2 in props) { + if (!(name_2 in dest)) { // if already assigned by previous props or complex props, don't reassign + dest[name_2] = props[name_2]; + } + } + } + return dest; + } + function filterHash(hash, func) { + var filtered = {}; + for (var key in hash) { + if (func(hash[key], key)) { + filtered[key] = hash[key]; + } + } + return filtered; + } + function mapHash(hash, func) { + var newHash = {}; + for (var key in hash) { + newHash[key] = func(hash[key], key); + } + return newHash; + } + function arrayToHash(a) { + var hash = {}; + for (var _i = 0, a_1 = a; _i < a_1.length; _i++) { + var item = a_1[_i]; + hash[item] = true; + } + return hash; + } + function buildHashFromArray(a, func) { + var hash = {}; + for (var i = 0; i < a.length; i += 1) { + var tuple = func(a[i], i); + hash[tuple[0]] = tuple[1]; + } + return hash; + } + function hashValuesToArray(obj) { + var a = []; + for (var key in obj) { + a.push(obj[key]); + } + return a; + } + function isPropsEqual(obj0, obj1) { + if (obj0 === obj1) { + return true; + } + for (var key in obj0) { + if (hasOwnProperty.call(obj0, key)) { + if (!(key in obj1)) { + return false; + } + } + } + for (var key in obj1) { + if (hasOwnProperty.call(obj1, key)) { + if (obj0[key] !== obj1[key]) { + return false; + } + } + } + return true; + } + function getUnequalProps(obj0, obj1) { + var keys = []; + for (var key in obj0) { + if (hasOwnProperty.call(obj0, key)) { + if (!(key in obj1)) { + keys.push(key); + } + } + } + for (var key in obj1) { + if (hasOwnProperty.call(obj1, key)) { + if (obj0[key] !== obj1[key]) { + keys.push(key); + } + } + } + return keys; + } + function compareObjs(oldProps, newProps, equalityFuncs) { + if (equalityFuncs === void 0) { equalityFuncs = {}; } + if (oldProps === newProps) { + return true; + } + for (var key in newProps) { + if (key in oldProps && isObjValsEqual(oldProps[key], newProps[key], equalityFuncs[key])) ; + else { + return false; + } + } + // check for props that were omitted in the new + for (var key in oldProps) { + if (!(key in newProps)) { + return false; + } + } + return true; + } + /* + assumed "true" equality for handler names like "onReceiveSomething" + */ + function isObjValsEqual(val0, val1, comparator) { + if (val0 === val1 || comparator === true) { + return true; + } + if (comparator) { + return comparator(val0, val1); + } + return false; + } + function collectFromHash(hash, startIndex, endIndex, step) { + if (startIndex === void 0) { startIndex = 0; } + if (step === void 0) { step = 1; } + var res = []; + if (endIndex == null) { + endIndex = Object.keys(hash).length; + } + for (var i = startIndex; i < endIndex; i += step) { + var val = hash[i]; + if (val !== undefined) { // will disregard undefined for sparse arrays + res.push(val); + } + } + return res; + } + + function parseRecurring(refined, defaultAllDay, dateEnv, recurringTypes) { + for (var i = 0; i < recurringTypes.length; i += 1) { + var parsed = recurringTypes[i].parse(refined, dateEnv); + if (parsed) { + var allDay = refined.allDay; + if (allDay == null) { + allDay = defaultAllDay; + if (allDay == null) { + allDay = parsed.allDayGuess; + if (allDay == null) { + allDay = false; + } + } + } + return { + allDay: allDay, + duration: parsed.duration, + typeData: parsed.typeData, + typeId: i, + }; + } + } + return null; + } + function expandRecurring(eventStore, framingRange, context) { + var dateEnv = context.dateEnv, pluginHooks = context.pluginHooks, options = context.options; + var defs = eventStore.defs, instances = eventStore.instances; + // remove existing recurring instances + // TODO: bad. always expand events as a second step + instances = filterHash(instances, function (instance) { return !defs[instance.defId].recurringDef; }); + for (var defId in defs) { + var def = defs[defId]; + if (def.recurringDef) { + var duration = def.recurringDef.duration; + if (!duration) { + duration = def.allDay ? + options.defaultAllDayEventDuration : + options.defaultTimedEventDuration; + } + var starts = expandRecurringRanges(def, duration, framingRange, dateEnv, pluginHooks.recurringTypes); + for (var _i = 0, starts_1 = starts; _i < starts_1.length; _i++) { + var start = starts_1[_i]; + var instance = createEventInstance(defId, { + start: start, + end: dateEnv.add(start, duration), + }); + instances[instance.instanceId] = instance; + } + } + } + return { defs: defs, instances: instances }; + } + /* + Event MUST have a recurringDef + */ + function expandRecurringRanges(eventDef, duration, framingRange, dateEnv, recurringTypes) { + var typeDef = recurringTypes[eventDef.recurringDef.typeId]; + var markers = typeDef.expand(eventDef.recurringDef.typeData, { + start: dateEnv.subtract(framingRange.start, duration), + end: framingRange.end, + }, dateEnv); + // the recurrence plugins don't guarantee that all-day events are start-of-day, so we have to + if (eventDef.allDay) { + markers = markers.map(startOfDay); + } + return markers; + } + + var INTERNAL_UNITS = ['years', 'months', 'days', 'milliseconds']; + var PARSE_RE = /^(-?)(?:(\d+)\.)?(\d+):(\d\d)(?::(\d\d)(?:\.(\d\d\d))?)?/; + // Parsing and Creation + function createDuration(input, unit) { + var _a; + if (typeof input === 'string') { + return parseString(input); + } + if (typeof input === 'object' && input) { // non-null object + return parseObject(input); + } + if (typeof input === 'number') { + return parseObject((_a = {}, _a[unit || 'milliseconds'] = input, _a)); + } + return null; + } + function parseString(s) { + var m = PARSE_RE.exec(s); + if (m) { + var sign = m[1] ? -1 : 1; + return { + years: 0, + months: 0, + days: sign * (m[2] ? parseInt(m[2], 10) : 0), + milliseconds: sign * ((m[3] ? parseInt(m[3], 10) : 0) * 60 * 60 * 1000 + // hours + (m[4] ? parseInt(m[4], 10) : 0) * 60 * 1000 + // minutes + (m[5] ? parseInt(m[5], 10) : 0) * 1000 + // seconds + (m[6] ? parseInt(m[6], 10) : 0) // ms + ), + }; + } + return null; + } + function parseObject(obj) { + var duration = { + years: obj.years || obj.year || 0, + months: obj.months || obj.month || 0, + days: obj.days || obj.day || 0, + milliseconds: (obj.hours || obj.hour || 0) * 60 * 60 * 1000 + // hours + (obj.minutes || obj.minute || 0) * 60 * 1000 + // minutes + (obj.seconds || obj.second || 0) * 1000 + // seconds + (obj.milliseconds || obj.millisecond || obj.ms || 0), // ms + }; + var weeks = obj.weeks || obj.week; + if (weeks) { + duration.days += weeks * 7; + duration.specifiedWeeks = true; + } + return duration; + } + // Equality + function durationsEqual(d0, d1) { + return d0.years === d1.years && + d0.months === d1.months && + d0.days === d1.days && + d0.milliseconds === d1.milliseconds; + } + function asCleanDays(dur) { + if (!dur.years && !dur.months && !dur.milliseconds) { + return dur.days; + } + return 0; + } + // Simple Math + function addDurations(d0, d1) { + return { + years: d0.years + d1.years, + months: d0.months + d1.months, + days: d0.days + d1.days, + milliseconds: d0.milliseconds + d1.milliseconds, + }; + } + function subtractDurations(d1, d0) { + return { + years: d1.years - d0.years, + months: d1.months - d0.months, + days: d1.days - d0.days, + milliseconds: d1.milliseconds - d0.milliseconds, + }; + } + function multiplyDuration(d, n) { + return { + years: d.years * n, + months: d.months * n, + days: d.days * n, + milliseconds: d.milliseconds * n, + }; + } + // Conversions + // "Rough" because they are based on average-case Gregorian months/years + function asRoughYears(dur) { + return asRoughDays(dur) / 365; + } + function asRoughMonths(dur) { + return asRoughDays(dur) / 30; + } + function asRoughDays(dur) { + return asRoughMs(dur) / 864e5; + } + function asRoughMinutes(dur) { + return asRoughMs(dur) / (1000 * 60); + } + function asRoughSeconds(dur) { + return asRoughMs(dur) / 1000; + } + function asRoughMs(dur) { + return dur.years * (365 * 864e5) + + dur.months * (30 * 864e5) + + dur.days * 864e5 + + dur.milliseconds; + } + // Advanced Math + function wholeDivideDurations(numerator, denominator) { + var res = null; + for (var i = 0; i < INTERNAL_UNITS.length; i += 1) { + var unit = INTERNAL_UNITS[i]; + if (denominator[unit]) { + var localRes = numerator[unit] / denominator[unit]; + if (!isInt(localRes) || (res !== null && res !== localRes)) { + return null; + } + res = localRes; + } + else if (numerator[unit]) { + // needs to divide by something but can't! + return null; + } + } + return res; + } + function greatestDurationDenominator(dur) { + var ms = dur.milliseconds; + if (ms) { + if (ms % 1000 !== 0) { + return { unit: 'millisecond', value: ms }; + } + if (ms % (1000 * 60) !== 0) { + return { unit: 'second', value: ms / 1000 }; + } + if (ms % (1000 * 60 * 60) !== 0) { + return { unit: 'minute', value: ms / (1000 * 60) }; + } + if (ms) { + return { unit: 'hour', value: ms / (1000 * 60 * 60) }; + } + } + if (dur.days) { + if (dur.specifiedWeeks && dur.days % 7 === 0) { + return { unit: 'week', value: dur.days / 7 }; + } + return { unit: 'day', value: dur.days }; + } + if (dur.months) { + return { unit: 'month', value: dur.months }; + } + if (dur.years) { + return { unit: 'year', value: dur.years }; + } + return { unit: 'millisecond', value: 0 }; + } + + // timeZoneOffset is in minutes + function buildIsoString(marker, timeZoneOffset, stripZeroTime) { + if (stripZeroTime === void 0) { stripZeroTime = false; } + var s = marker.toISOString(); + s = s.replace('.000', ''); + if (stripZeroTime) { + s = s.replace('T00:00:00Z', ''); + } + if (s.length > 10) { // time part wasn't stripped, can add timezone info + if (timeZoneOffset == null) { + s = s.replace('Z', ''); + } + else if (timeZoneOffset !== 0) { + s = s.replace('Z', formatTimeZoneOffset(timeZoneOffset, true)); + } + // otherwise, its UTC-0 and we want to keep the Z + } + return s; + } + // formats the date, but with no time part + // TODO: somehow merge with buildIsoString and stripZeroTime + // TODO: rename. omit "string" + function formatDayString(marker) { + return marker.toISOString().replace(/T.*$/, ''); + } + // TODO: use Date::toISOString and use everything after the T? + function formatIsoTimeString(marker) { + return padStart(marker.getUTCHours(), 2) + ':' + + padStart(marker.getUTCMinutes(), 2) + ':' + + padStart(marker.getUTCSeconds(), 2); + } + function formatTimeZoneOffset(minutes, doIso) { + if (doIso === void 0) { doIso = false; } + var sign = minutes < 0 ? '-' : '+'; + var abs = Math.abs(minutes); + var hours = Math.floor(abs / 60); + var mins = Math.round(abs % 60); + if (doIso) { + return sign + padStart(hours, 2) + ":" + padStart(mins, 2); + } + return "GMT" + sign + hours + (mins ? ":" + padStart(mins, 2) : ''); + } + + // TODO: new util arrayify? + function removeExact(array, exactVal) { + var removeCnt = 0; + var i = 0; + while (i < array.length) { + if (array[i] === exactVal) { + array.splice(i, 1); + removeCnt += 1; + } + else { + i += 1; + } + } + return removeCnt; + } + function isArraysEqual(a0, a1, equalityFunc) { + if (a0 === a1) { + return true; + } + var len = a0.length; + var i; + if (len !== a1.length) { // not array? or not same length? + return false; + } + for (i = 0; i < len; i += 1) { + if (!(equalityFunc ? equalityFunc(a0[i], a1[i]) : a0[i] === a1[i])) { + return false; + } + } + return true; + } + + function memoize(workerFunc, resEquality, teardownFunc) { + var currentArgs; + var currentRes; + return function () { + var newArgs = []; + for (var _i = 0; _i < arguments.length; _i++) { + newArgs[_i] = arguments[_i]; + } + if (!currentArgs) { + currentRes = workerFunc.apply(this, newArgs); + } + else if (!isArraysEqual(currentArgs, newArgs)) { + if (teardownFunc) { + teardownFunc(currentRes); + } + var res = workerFunc.apply(this, newArgs); + if (!resEquality || !resEquality(res, currentRes)) { + currentRes = res; + } + } + currentArgs = newArgs; + return currentRes; + }; + } + function memoizeObjArg(workerFunc, resEquality, teardownFunc) { + var _this = this; + var currentArg; + var currentRes; + return function (newArg) { + if (!currentArg) { + currentRes = workerFunc.call(_this, newArg); + } + else if (!isPropsEqual(currentArg, newArg)) { + if (teardownFunc) { + teardownFunc(currentRes); + } + var res = workerFunc.call(_this, newArg); + if (!resEquality || !resEquality(res, currentRes)) { + currentRes = res; + } + } + currentArg = newArg; + return currentRes; + }; + } + function memoizeArraylike(// used at all? + workerFunc, resEquality, teardownFunc) { + var _this = this; + var currentArgSets = []; + var currentResults = []; + return function (newArgSets) { + var currentLen = currentArgSets.length; + var newLen = newArgSets.length; + var i = 0; + for (; i < currentLen; i += 1) { + if (!newArgSets[i]) { // one of the old sets no longer exists + if (teardownFunc) { + teardownFunc(currentResults[i]); + } + } + else if (!isArraysEqual(currentArgSets[i], newArgSets[i])) { + if (teardownFunc) { + teardownFunc(currentResults[i]); + } + var res = workerFunc.apply(_this, newArgSets[i]); + if (!resEquality || !resEquality(res, currentResults[i])) { + currentResults[i] = res; + } + } + } + for (; i < newLen; i += 1) { + currentResults[i] = workerFunc.apply(_this, newArgSets[i]); + } + currentArgSets = newArgSets; + currentResults.splice(newLen); // remove excess + return currentResults; + }; + } + function memoizeHashlike(// used? + workerFunc, resEquality, teardownFunc) { + var _this = this; + var currentArgHash = {}; + var currentResHash = {}; + return function (newArgHash) { + var newResHash = {}; + for (var key in newArgHash) { + if (!currentResHash[key]) { + newResHash[key] = workerFunc.apply(_this, newArgHash[key]); + } + else if (!isArraysEqual(currentArgHash[key], newArgHash[key])) { + if (teardownFunc) { + teardownFunc(currentResHash[key]); + } + var res = workerFunc.apply(_this, newArgHash[key]); + newResHash[key] = (resEquality && resEquality(res, currentResHash[key])) + ? currentResHash[key] + : res; + } + else { + newResHash[key] = currentResHash[key]; + } + } + currentArgHash = newArgHash; + currentResHash = newResHash; + return newResHash; + }; + } + + var EXTENDED_SETTINGS_AND_SEVERITIES = { + week: 3, + separator: 0, + omitZeroMinute: 0, + meridiem: 0, + omitCommas: 0, + }; + var STANDARD_DATE_PROP_SEVERITIES = { + timeZoneName: 7, + era: 6, + year: 5, + month: 4, + day: 2, + weekday: 2, + hour: 1, + minute: 1, + second: 1, + }; + var MERIDIEM_RE = /\s*([ap])\.?m\.?/i; // eats up leading spaces too + var COMMA_RE = /,/g; // we need re for globalness + var MULTI_SPACE_RE = /\s+/g; + var LTR_RE = /\u200e/g; // control character + var UTC_RE = /UTC|GMT/; + var NativeFormatter = /** @class */ (function () { + function NativeFormatter(formatSettings) { + var standardDateProps = {}; + var extendedSettings = {}; + var severity = 0; + for (var name_1 in formatSettings) { + if (name_1 in EXTENDED_SETTINGS_AND_SEVERITIES) { + extendedSettings[name_1] = formatSettings[name_1]; + severity = Math.max(EXTENDED_SETTINGS_AND_SEVERITIES[name_1], severity); + } + else { + standardDateProps[name_1] = formatSettings[name_1]; + if (name_1 in STANDARD_DATE_PROP_SEVERITIES) { // TODO: what about hour12? no severity + severity = Math.max(STANDARD_DATE_PROP_SEVERITIES[name_1], severity); + } + } + } + this.standardDateProps = standardDateProps; + this.extendedSettings = extendedSettings; + this.severity = severity; + this.buildFormattingFunc = memoize(buildFormattingFunc); + } + NativeFormatter.prototype.format = function (date, context) { + return this.buildFormattingFunc(this.standardDateProps, this.extendedSettings, context)(date); + }; + NativeFormatter.prototype.formatRange = function (start, end, context, betterDefaultSeparator) { + var _a = this, standardDateProps = _a.standardDateProps, extendedSettings = _a.extendedSettings; + var diffSeverity = computeMarkerDiffSeverity(start.marker, end.marker, context.calendarSystem); + if (!diffSeverity) { + return this.format(start, context); + } + var biggestUnitForPartial = diffSeverity; + if (biggestUnitForPartial > 1 && // the two dates are different in a way that's larger scale than time + (standardDateProps.year === 'numeric' || standardDateProps.year === '2-digit') && + (standardDateProps.month === 'numeric' || standardDateProps.month === '2-digit') && + (standardDateProps.day === 'numeric' || standardDateProps.day === '2-digit')) { + biggestUnitForPartial = 1; // make it look like the dates are only different in terms of time + } + var full0 = this.format(start, context); + var full1 = this.format(end, context); + if (full0 === full1) { + return full0; + } + var partialDateProps = computePartialFormattingOptions(standardDateProps, biggestUnitForPartial); + var partialFormattingFunc = buildFormattingFunc(partialDateProps, extendedSettings, context); + var partial0 = partialFormattingFunc(start); + var partial1 = partialFormattingFunc(end); + var insertion = findCommonInsertion(full0, partial0, full1, partial1); + var separator = extendedSettings.separator || betterDefaultSeparator || context.defaultSeparator || ''; + if (insertion) { + return insertion.before + partial0 + separator + partial1 + insertion.after; + } + return full0 + separator + full1; + }; + NativeFormatter.prototype.getLargestUnit = function () { + switch (this.severity) { + case 7: + case 6: + case 5: + return 'year'; + case 4: + return 'month'; + case 3: + return 'week'; + case 2: + return 'day'; + default: + return 'time'; // really? + } + }; + return NativeFormatter; + }()); + function buildFormattingFunc(standardDateProps, extendedSettings, context) { + var standardDatePropCnt = Object.keys(standardDateProps).length; + if (standardDatePropCnt === 1 && standardDateProps.timeZoneName === 'short') { + return function (date) { return (formatTimeZoneOffset(date.timeZoneOffset)); }; + } + if (standardDatePropCnt === 0 && extendedSettings.week) { + return function (date) { return (formatWeekNumber(context.computeWeekNumber(date.marker), context.weekText, context.locale, extendedSettings.week)); }; + } + return buildNativeFormattingFunc(standardDateProps, extendedSettings, context); + } + function buildNativeFormattingFunc(standardDateProps, extendedSettings, context) { + standardDateProps = __assign({}, standardDateProps); // copy + extendedSettings = __assign({}, extendedSettings); // copy + sanitizeSettings(standardDateProps, extendedSettings); + standardDateProps.timeZone = 'UTC'; // we leverage the only guaranteed timeZone for our UTC markers + var normalFormat = new Intl.DateTimeFormat(context.locale.codes, standardDateProps); + var zeroFormat; // needed? + if (extendedSettings.omitZeroMinute) { + var zeroProps = __assign({}, standardDateProps); + delete zeroProps.minute; // seconds and ms were already considered in sanitizeSettings + zeroFormat = new Intl.DateTimeFormat(context.locale.codes, zeroProps); + } + return function (date) { + var marker = date.marker; + var format; + if (zeroFormat && !marker.getUTCMinutes()) { + format = zeroFormat; + } + else { + format = normalFormat; + } + var s = format.format(marker); + return postProcess(s, date, standardDateProps, extendedSettings, context); + }; + } + function sanitizeSettings(standardDateProps, extendedSettings) { + // deal with a browser inconsistency where formatting the timezone + // requires that the hour/minute be present. + if (standardDateProps.timeZoneName) { + if (!standardDateProps.hour) { + standardDateProps.hour = '2-digit'; + } + if (!standardDateProps.minute) { + standardDateProps.minute = '2-digit'; + } + } + // only support short timezone names + if (standardDateProps.timeZoneName === 'long') { + standardDateProps.timeZoneName = 'short'; + } + // if requesting to display seconds, MUST display minutes + if (extendedSettings.omitZeroMinute && (standardDateProps.second || standardDateProps.millisecond)) { + delete extendedSettings.omitZeroMinute; + } + } + function postProcess(s, date, standardDateProps, extendedSettings, context) { + s = s.replace(LTR_RE, ''); // remove left-to-right control chars. do first. good for other regexes + if (standardDateProps.timeZoneName === 'short') { + s = injectTzoStr(s, (context.timeZone === 'UTC' || date.timeZoneOffset == null) ? + 'UTC' : // important to normalize for IE, which does "GMT" + formatTimeZoneOffset(date.timeZoneOffset)); + } + if (extendedSettings.omitCommas) { + s = s.replace(COMMA_RE, '').trim(); + } + if (extendedSettings.omitZeroMinute) { + s = s.replace(':00', ''); // zeroFormat doesn't always achieve this + } + // ^ do anything that might create adjacent spaces before this point, + // because MERIDIEM_RE likes to eat up loading spaces + if (extendedSettings.meridiem === false) { + s = s.replace(MERIDIEM_RE, '').trim(); + } + else if (extendedSettings.meridiem === 'narrow') { // a/p + s = s.replace(MERIDIEM_RE, function (m0, m1) { return m1.toLocaleLowerCase(); }); + } + else if (extendedSettings.meridiem === 'short') { // am/pm + s = s.replace(MERIDIEM_RE, function (m0, m1) { return m1.toLocaleLowerCase() + "m"; }); + } + else if (extendedSettings.meridiem === 'lowercase') { // other meridiem transformers already converted to lowercase + s = s.replace(MERIDIEM_RE, function (m0) { return m0.toLocaleLowerCase(); }); + } + s = s.replace(MULTI_SPACE_RE, ' '); + s = s.trim(); + return s; + } + function injectTzoStr(s, tzoStr) { + var replaced = false; + s = s.replace(UTC_RE, function () { + replaced = true; + return tzoStr; + }); + // IE11 doesn't include UTC/GMT in the original string, so append to end + if (!replaced) { + s += " " + tzoStr; + } + return s; + } + function formatWeekNumber(num, weekText, locale, display) { + var parts = []; + if (display === 'narrow') { + parts.push(weekText); + } + else if (display === 'short') { + parts.push(weekText, ' '); + } + // otherwise, considered 'numeric' + parts.push(locale.simpleNumberFormat.format(num)); + if (locale.options.direction === 'rtl') { // TODO: use control characters instead? + parts.reverse(); + } + return parts.join(''); + } + // Range Formatting Utils + // 0 = exactly the same + // 1 = different by time + // and bigger + function computeMarkerDiffSeverity(d0, d1, ca) { + if (ca.getMarkerYear(d0) !== ca.getMarkerYear(d1)) { + return 5; + } + if (ca.getMarkerMonth(d0) !== ca.getMarkerMonth(d1)) { + return 4; + } + if (ca.getMarkerDay(d0) !== ca.getMarkerDay(d1)) { + return 2; + } + if (timeAsMs(d0) !== timeAsMs(d1)) { + return 1; + } + return 0; + } + function computePartialFormattingOptions(options, biggestUnit) { + var partialOptions = {}; + for (var name_2 in options) { + if (!(name_2 in STANDARD_DATE_PROP_SEVERITIES) || // not a date part prop (like timeZone) + STANDARD_DATE_PROP_SEVERITIES[name_2] <= biggestUnit) { + partialOptions[name_2] = options[name_2]; + } + } + return partialOptions; + } + function findCommonInsertion(full0, partial0, full1, partial1) { + var i0 = 0; + while (i0 < full0.length) { + var found0 = full0.indexOf(partial0, i0); + if (found0 === -1) { + break; + } + var before0 = full0.substr(0, found0); + i0 = found0 + partial0.length; + var after0 = full0.substr(i0); + var i1 = 0; + while (i1 < full1.length) { + var found1 = full1.indexOf(partial1, i1); + if (found1 === -1) { + break; + } + var before1 = full1.substr(0, found1); + i1 = found1 + partial1.length; + var after1 = full1.substr(i1); + if (before0 === before1 && after0 === after1) { + return { + before: before0, + after: after0, + }; + } + } + } + return null; + } + + function expandZonedMarker(dateInfo, calendarSystem) { + var a = calendarSystem.markerToArray(dateInfo.marker); + return { + marker: dateInfo.marker, + timeZoneOffset: dateInfo.timeZoneOffset, + array: a, + year: a[0], + month: a[1], + day: a[2], + hour: a[3], + minute: a[4], + second: a[5], + millisecond: a[6], + }; + } + + function createVerboseFormattingArg(start, end, context, betterDefaultSeparator) { + var startInfo = expandZonedMarker(start, context.calendarSystem); + var endInfo = end ? expandZonedMarker(end, context.calendarSystem) : null; + return { + date: startInfo, + start: startInfo, + end: endInfo, + timeZone: context.timeZone, + localeCodes: context.locale.codes, + defaultSeparator: betterDefaultSeparator || context.defaultSeparator, + }; + } + + /* + TODO: fix the terminology of "formatter" vs "formatting func" + */ + /* + At the time of instantiation, this object does not know which cmd-formatting system it will use. + It receives this at the time of formatting, as a setting. + */ + var CmdFormatter = /** @class */ (function () { + function CmdFormatter(cmdStr) { + this.cmdStr = cmdStr; + } + CmdFormatter.prototype.format = function (date, context, betterDefaultSeparator) { + return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(date, null, context, betterDefaultSeparator)); + }; + CmdFormatter.prototype.formatRange = function (start, end, context, betterDefaultSeparator) { + return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(start, end, context, betterDefaultSeparator)); + }; + return CmdFormatter; + }()); + + var FuncFormatter = /** @class */ (function () { + function FuncFormatter(func) { + this.func = func; + } + FuncFormatter.prototype.format = function (date, context, betterDefaultSeparator) { + return this.func(createVerboseFormattingArg(date, null, context, betterDefaultSeparator)); + }; + FuncFormatter.prototype.formatRange = function (start, end, context, betterDefaultSeparator) { + return this.func(createVerboseFormattingArg(start, end, context, betterDefaultSeparator)); + }; + return FuncFormatter; + }()); + + function createFormatter(input) { + if (typeof input === 'object' && input) { // non-null object + return new NativeFormatter(input); + } + if (typeof input === 'string') { + return new CmdFormatter(input); + } + if (typeof input === 'function') { + return new FuncFormatter(input); + } + return null; + } + + // base options + // ------------ + var BASE_OPTION_REFINERS = { + navLinkDayClick: identity, + navLinkWeekClick: identity, + duration: createDuration, + bootstrapFontAwesome: identity, + buttonIcons: identity, + customButtons: identity, + defaultAllDayEventDuration: createDuration, + defaultTimedEventDuration: createDuration, + nextDayThreshold: createDuration, + scrollTime: createDuration, + scrollTimeReset: Boolean, + slotMinTime: createDuration, + slotMaxTime: createDuration, + dayPopoverFormat: createFormatter, + slotDuration: createDuration, + snapDuration: createDuration, + headerToolbar: identity, + footerToolbar: identity, + defaultRangeSeparator: String, + titleRangeSeparator: String, + forceEventDuration: Boolean, + dayHeaders: Boolean, + dayHeaderFormat: createFormatter, + dayHeaderClassNames: identity, + dayHeaderContent: identity, + dayHeaderDidMount: identity, + dayHeaderWillUnmount: identity, + dayCellClassNames: identity, + dayCellContent: identity, + dayCellDidMount: identity, + dayCellWillUnmount: identity, + initialView: String, + aspectRatio: Number, + weekends: Boolean, + weekNumberCalculation: identity, + weekNumbers: Boolean, + weekNumberClassNames: identity, + weekNumberContent: identity, + weekNumberDidMount: identity, + weekNumberWillUnmount: identity, + editable: Boolean, + viewClassNames: identity, + viewDidMount: identity, + viewWillUnmount: identity, + nowIndicator: Boolean, + nowIndicatorClassNames: identity, + nowIndicatorContent: identity, + nowIndicatorDidMount: identity, + nowIndicatorWillUnmount: identity, + showNonCurrentDates: Boolean, + lazyFetching: Boolean, + startParam: String, + endParam: String, + timeZoneParam: String, + timeZone: String, + locales: identity, + locale: identity, + themeSystem: String, + dragRevertDuration: Number, + dragScroll: Boolean, + allDayMaintainDuration: Boolean, + unselectAuto: Boolean, + dropAccept: identity, + eventOrder: parseFieldSpecs, + eventOrderStrict: Boolean, + handleWindowResize: Boolean, + windowResizeDelay: Number, + longPressDelay: Number, + eventDragMinDistance: Number, + expandRows: Boolean, + height: identity, + contentHeight: identity, + direction: String, + weekNumberFormat: createFormatter, + eventResizableFromStart: Boolean, + displayEventTime: Boolean, + displayEventEnd: Boolean, + weekText: String, + progressiveEventRendering: Boolean, + businessHours: identity, + initialDate: identity, + now: identity, + eventDataTransform: identity, + stickyHeaderDates: identity, + stickyFooterScrollbar: identity, + viewHeight: identity, + defaultAllDay: Boolean, + eventSourceFailure: identity, + eventSourceSuccess: identity, + eventDisplay: String, + eventStartEditable: Boolean, + eventDurationEditable: Boolean, + eventOverlap: identity, + eventConstraint: identity, + eventAllow: identity, + eventBackgroundColor: String, + eventBorderColor: String, + eventTextColor: String, + eventColor: String, + eventClassNames: identity, + eventContent: identity, + eventDidMount: identity, + eventWillUnmount: identity, + selectConstraint: identity, + selectOverlap: identity, + selectAllow: identity, + droppable: Boolean, + unselectCancel: String, + slotLabelFormat: identity, + slotLaneClassNames: identity, + slotLaneContent: identity, + slotLaneDidMount: identity, + slotLaneWillUnmount: identity, + slotLabelClassNames: identity, + slotLabelContent: identity, + slotLabelDidMount: identity, + slotLabelWillUnmount: identity, + dayMaxEvents: identity, + dayMaxEventRows: identity, + dayMinWidth: Number, + slotLabelInterval: createDuration, + allDayText: String, + allDayClassNames: identity, + allDayContent: identity, + allDayDidMount: identity, + allDayWillUnmount: identity, + slotMinWidth: Number, + navLinks: Boolean, + eventTimeFormat: createFormatter, + rerenderDelay: Number, + moreLinkText: identity, + selectMinDistance: Number, + selectable: Boolean, + selectLongPressDelay: Number, + eventLongPressDelay: Number, + selectMirror: Boolean, + eventMaxStack: Number, + eventMinHeight: Number, + eventMinWidth: Number, + eventShortHeight: Number, + slotEventOverlap: Boolean, + plugins: identity, + firstDay: Number, + dayCount: Number, + dateAlignment: String, + dateIncrement: createDuration, + hiddenDays: identity, + monthMode: Boolean, + fixedWeekCount: Boolean, + validRange: identity, + visibleRange: identity, + titleFormat: identity, + // only used by list-view, but languages define the value, so we need it in base options + noEventsText: String, + moreLinkClick: identity, + moreLinkClassNames: identity, + moreLinkContent: identity, + moreLinkDidMount: identity, + moreLinkWillUnmount: identity, + }; + // do NOT give a type here. need `typeof BASE_OPTION_DEFAULTS` to give real results. + // raw values. + var BASE_OPTION_DEFAULTS = { + eventDisplay: 'auto', + defaultRangeSeparator: ' - ', + titleRangeSeparator: ' \u2013 ', + defaultTimedEventDuration: '01:00:00', + defaultAllDayEventDuration: { day: 1 }, + forceEventDuration: false, + nextDayThreshold: '00:00:00', + dayHeaders: true, + initialView: '', + aspectRatio: 1.35, + headerToolbar: { + start: 'title', + center: '', + end: 'today prev,next', + }, + weekends: true, + weekNumbers: false, + weekNumberCalculation: 'local', + editable: false, + nowIndicator: false, + scrollTime: '06:00:00', + scrollTimeReset: true, + slotMinTime: '00:00:00', + slotMaxTime: '24:00:00', + showNonCurrentDates: true, + lazyFetching: true, + startParam: 'start', + endParam: 'end', + timeZoneParam: 'timeZone', + timeZone: 'local', + locales: [], + locale: '', + themeSystem: 'standard', + dragRevertDuration: 500, + dragScroll: true, + allDayMaintainDuration: false, + unselectAuto: true, + dropAccept: '*', + eventOrder: 'start,-duration,allDay,title', + dayPopoverFormat: { month: 'long', day: 'numeric', year: 'numeric' }, + handleWindowResize: true, + windowResizeDelay: 100, + longPressDelay: 1000, + eventDragMinDistance: 5, + expandRows: false, + navLinks: false, + selectable: false, + eventMinHeight: 15, + eventMinWidth: 30, + eventShortHeight: 30, + }; + // calendar listeners + // ------------------ + var CALENDAR_LISTENER_REFINERS = { + datesSet: identity, + eventsSet: identity, + eventAdd: identity, + eventChange: identity, + eventRemove: identity, + windowResize: identity, + eventClick: identity, + eventMouseEnter: identity, + eventMouseLeave: identity, + select: identity, + unselect: identity, + loading: identity, + // internal + _unmount: identity, + _beforeprint: identity, + _afterprint: identity, + _noEventDrop: identity, + _noEventResize: identity, + _resize: identity, + _scrollRequest: identity, + }; + // calendar-specific options + // ------------------------- + var CALENDAR_OPTION_REFINERS = { + buttonText: identity, + views: identity, + plugins: identity, + initialEvents: identity, + events: identity, + eventSources: identity, + }; + var COMPLEX_OPTION_COMPARATORS = { + headerToolbar: isBoolComplexEqual, + footerToolbar: isBoolComplexEqual, + buttonText: isBoolComplexEqual, + buttonIcons: isBoolComplexEqual, + }; + function isBoolComplexEqual(a, b) { + if (typeof a === 'object' && typeof b === 'object' && a && b) { // both non-null objects + return isPropsEqual(a, b); + } + return a === b; + } + // view-specific options + // --------------------- + var VIEW_OPTION_REFINERS = { + type: String, + component: identity, + buttonText: String, + buttonTextKey: String, + dateProfileGeneratorClass: identity, + usesMinMaxTime: Boolean, + classNames: identity, + content: identity, + didMount: identity, + willUnmount: identity, + }; + // util funcs + // ---------------------------------------------------------------------------------------------------- + function mergeRawOptions(optionSets) { + return mergeProps(optionSets, COMPLEX_OPTION_COMPARATORS); + } + function refineProps(input, refiners) { + var refined = {}; + var extra = {}; + for (var propName in refiners) { + if (propName in input) { + refined[propName] = refiners[propName](input[propName]); + } + } + for (var propName in input) { + if (!(propName in refiners)) { + extra[propName] = input[propName]; + } + } + return { refined: refined, extra: extra }; + } + function identity(raw) { + return raw; + } + + function parseEvents(rawEvents, eventSource, context, allowOpenRange) { + var eventStore = createEmptyEventStore(); + var eventRefiners = buildEventRefiners(context); + for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { + var rawEvent = rawEvents_1[_i]; + var tuple = parseEvent(rawEvent, eventSource, context, allowOpenRange, eventRefiners); + if (tuple) { + eventTupleToStore(tuple, eventStore); + } + } + return eventStore; + } + function eventTupleToStore(tuple, eventStore) { + if (eventStore === void 0) { eventStore = createEmptyEventStore(); } + eventStore.defs[tuple.def.defId] = tuple.def; + if (tuple.instance) { + eventStore.instances[tuple.instance.instanceId] = tuple.instance; + } + return eventStore; + } + // retrieves events that have the same groupId as the instance specified by `instanceId` + // or they are the same as the instance. + // why might instanceId not be in the store? an event from another calendar? + function getRelevantEvents(eventStore, instanceId) { + var instance = eventStore.instances[instanceId]; + if (instance) { + var def_1 = eventStore.defs[instance.defId]; + // get events/instances with same group + var newStore = filterEventStoreDefs(eventStore, function (lookDef) { return isEventDefsGrouped(def_1, lookDef); }); + // add the original + // TODO: wish we could use eventTupleToStore or something like it + newStore.defs[def_1.defId] = def_1; + newStore.instances[instance.instanceId] = instance; + return newStore; + } + return createEmptyEventStore(); + } + function isEventDefsGrouped(def0, def1) { + return Boolean(def0.groupId && def0.groupId === def1.groupId); + } + function createEmptyEventStore() { + return { defs: {}, instances: {} }; + } + function mergeEventStores(store0, store1) { + return { + defs: __assign(__assign({}, store0.defs), store1.defs), + instances: __assign(__assign({}, store0.instances), store1.instances), + }; + } + function filterEventStoreDefs(eventStore, filterFunc) { + var defs = filterHash(eventStore.defs, filterFunc); + var instances = filterHash(eventStore.instances, function (instance) { return (defs[instance.defId] // still exists? + ); }); + return { defs: defs, instances: instances }; + } + function excludeSubEventStore(master, sub) { + var defs = master.defs, instances = master.instances; + var filteredDefs = {}; + var filteredInstances = {}; + for (var defId in defs) { + if (!sub.defs[defId]) { // not explicitly excluded + filteredDefs[defId] = defs[defId]; + } + } + for (var instanceId in instances) { + if (!sub.instances[instanceId] && // not explicitly excluded + filteredDefs[instances[instanceId].defId] // def wasn't filtered away + ) { + filteredInstances[instanceId] = instances[instanceId]; + } + } + return { + defs: filteredDefs, + instances: filteredInstances, + }; + } + + function normalizeConstraint(input, context) { + if (Array.isArray(input)) { + return parseEvents(input, null, context, true); // allowOpenRange=true + } + if (typeof input === 'object' && input) { // non-null object + return parseEvents([input], null, context, true); // allowOpenRange=true + } + if (input != null) { + return String(input); + } + return null; + } + + function parseClassNames(raw) { + if (Array.isArray(raw)) { + return raw; + } + if (typeof raw === 'string') { + return raw.split(/\s+/); + } + return []; + } + + // TODO: better called "EventSettings" or "EventConfig" + // TODO: move this file into structs + // TODO: separate constraint/overlap/allow, because selection uses only that, not other props + var EVENT_UI_REFINERS = { + display: String, + editable: Boolean, + startEditable: Boolean, + durationEditable: Boolean, + constraint: identity, + overlap: identity, + allow: identity, + className: parseClassNames, + classNames: parseClassNames, + color: String, + backgroundColor: String, + borderColor: String, + textColor: String, + }; + var EMPTY_EVENT_UI = { + display: null, + startEditable: null, + durationEditable: null, + constraints: [], + overlap: null, + allows: [], + backgroundColor: '', + borderColor: '', + textColor: '', + classNames: [], + }; + function createEventUi(refined, context) { + var constraint = normalizeConstraint(refined.constraint, context); + return { + display: refined.display || null, + startEditable: refined.startEditable != null ? refined.startEditable : refined.editable, + durationEditable: refined.durationEditable != null ? refined.durationEditable : refined.editable, + constraints: constraint != null ? [constraint] : [], + overlap: refined.overlap != null ? refined.overlap : null, + allows: refined.allow != null ? [refined.allow] : [], + backgroundColor: refined.backgroundColor || refined.color || '', + borderColor: refined.borderColor || refined.color || '', + textColor: refined.textColor || '', + classNames: (refined.className || []).concat(refined.classNames || []), // join singular and plural + }; + } + // TODO: prevent against problems with <2 args! + function combineEventUis(uis) { + return uis.reduce(combineTwoEventUis, EMPTY_EVENT_UI); + } + function combineTwoEventUis(item0, item1) { + return { + display: item1.display != null ? item1.display : item0.display, + startEditable: item1.startEditable != null ? item1.startEditable : item0.startEditable, + durationEditable: item1.durationEditable != null ? item1.durationEditable : item0.durationEditable, + constraints: item0.constraints.concat(item1.constraints), + overlap: typeof item1.overlap === 'boolean' ? item1.overlap : item0.overlap, + allows: item0.allows.concat(item1.allows), + backgroundColor: item1.backgroundColor || item0.backgroundColor, + borderColor: item1.borderColor || item0.borderColor, + textColor: item1.textColor || item0.textColor, + classNames: item0.classNames.concat(item1.classNames), + }; + } + + var EVENT_NON_DATE_REFINERS = { + id: String, + groupId: String, + title: String, + url: String, + }; + var EVENT_DATE_REFINERS = { + start: identity, + end: identity, + date: identity, + allDay: Boolean, + }; + var EVENT_REFINERS$1 = __assign(__assign(__assign({}, EVENT_NON_DATE_REFINERS), EVENT_DATE_REFINERS), { extendedProps: identity }); + function parseEvent(raw, eventSource, context, allowOpenRange, refiners) { + if (refiners === void 0) { refiners = buildEventRefiners(context); } + var _a = refineEventDef(raw, context, refiners), refined = _a.refined, extra = _a.extra; + var defaultAllDay = computeIsDefaultAllDay(eventSource, context); + var recurringRes = parseRecurring(refined, defaultAllDay, context.dateEnv, context.pluginHooks.recurringTypes); + if (recurringRes) { + var def = parseEventDef(refined, extra, eventSource ? eventSource.sourceId : '', recurringRes.allDay, Boolean(recurringRes.duration), context); + def.recurringDef = { + typeId: recurringRes.typeId, + typeData: recurringRes.typeData, + duration: recurringRes.duration, + }; + return { def: def, instance: null }; + } + var singleRes = parseSingle(refined, defaultAllDay, context, allowOpenRange); + if (singleRes) { + var def = parseEventDef(refined, extra, eventSource ? eventSource.sourceId : '', singleRes.allDay, singleRes.hasEnd, context); + var instance = createEventInstance(def.defId, singleRes.range, singleRes.forcedStartTzo, singleRes.forcedEndTzo); + return { def: def, instance: instance }; + } + return null; + } + function refineEventDef(raw, context, refiners) { + if (refiners === void 0) { refiners = buildEventRefiners(context); } + return refineProps(raw, refiners); + } + function buildEventRefiners(context) { + return __assign(__assign(__assign({}, EVENT_UI_REFINERS), EVENT_REFINERS$1), context.pluginHooks.eventRefiners); + } + /* + Will NOT populate extendedProps with the leftover properties. + Will NOT populate date-related props. + */ + function parseEventDef(refined, extra, sourceId, allDay, hasEnd, context) { + var def = { + title: refined.title || '', + groupId: refined.groupId || '', + publicId: refined.id || '', + url: refined.url || '', + recurringDef: null, + defId: guid(), + sourceId: sourceId, + allDay: allDay, + hasEnd: hasEnd, + ui: createEventUi(refined, context), + extendedProps: __assign(__assign({}, (refined.extendedProps || {})), extra), + }; + for (var _i = 0, _a = context.pluginHooks.eventDefMemberAdders; _i < _a.length; _i++) { + var memberAdder = _a[_i]; + __assign(def, memberAdder(refined)); + } + // help out EventApi from having user modify props + Object.freeze(def.ui.classNames); + Object.freeze(def.extendedProps); + return def; + } + function parseSingle(refined, defaultAllDay, context, allowOpenRange) { + var allDay = refined.allDay; + var startMeta; + var startMarker = null; + var hasEnd = false; + var endMeta; + var endMarker = null; + var startInput = refined.start != null ? refined.start : refined.date; + startMeta = context.dateEnv.createMarkerMeta(startInput); + if (startMeta) { + startMarker = startMeta.marker; + } + else if (!allowOpenRange) { + return null; + } + if (refined.end != null) { + endMeta = context.dateEnv.createMarkerMeta(refined.end); + } + if (allDay == null) { + if (defaultAllDay != null) { + allDay = defaultAllDay; + } + else { + // fall back to the date props LAST + allDay = (!startMeta || startMeta.isTimeUnspecified) && + (!endMeta || endMeta.isTimeUnspecified); + } + } + if (allDay && startMarker) { + startMarker = startOfDay(startMarker); + } + if (endMeta) { + endMarker = endMeta.marker; + if (allDay) { + endMarker = startOfDay(endMarker); + } + if (startMarker && endMarker <= startMarker) { + endMarker = null; + } + } + if (endMarker) { + hasEnd = true; + } + else if (!allowOpenRange) { + hasEnd = context.options.forceEventDuration || false; + endMarker = context.dateEnv.add(startMarker, allDay ? + context.options.defaultAllDayEventDuration : + context.options.defaultTimedEventDuration); + } + return { + allDay: allDay, + hasEnd: hasEnd, + range: { start: startMarker, end: endMarker }, + forcedStartTzo: startMeta ? startMeta.forcedTzo : null, + forcedEndTzo: endMeta ? endMeta.forcedTzo : null, + }; + } + function computeIsDefaultAllDay(eventSource, context) { + var res = null; + if (eventSource) { + res = eventSource.defaultAllDay; + } + if (res == null) { + res = context.options.defaultAllDay; + } + return res; + } + + /* Date stuff that doesn't belong in datelib core + ----------------------------------------------------------------------------------------------------------------------*/ + // given a timed range, computes an all-day range that has the same exact duration, + // but whose start time is aligned with the start of the day. + function computeAlignedDayRange(timedRange) { + var dayCnt = Math.floor(diffDays(timedRange.start, timedRange.end)) || 1; + var start = startOfDay(timedRange.start); + var end = addDays(start, dayCnt); + return { start: start, end: end }; + } + // given a timed range, computes an all-day range based on how for the end date bleeds into the next day + // TODO: give nextDayThreshold a default arg + function computeVisibleDayRange(timedRange, nextDayThreshold) { + if (nextDayThreshold === void 0) { nextDayThreshold = createDuration(0); } + var startDay = null; + var endDay = null; + if (timedRange.end) { + endDay = startOfDay(timedRange.end); + var endTimeMS = timedRange.end.valueOf() - endDay.valueOf(); // # of milliseconds into `endDay` + // If the end time is actually inclusively part of the next day and is equal to or + // beyond the next day threshold, adjust the end to be the exclusive end of `endDay`. + // Otherwise, leaving it as inclusive will cause it to exclude `endDay`. + if (endTimeMS && endTimeMS >= asRoughMs(nextDayThreshold)) { + endDay = addDays(endDay, 1); + } + } + if (timedRange.start) { + startDay = startOfDay(timedRange.start); // the beginning of the day the range starts + // If end is within `startDay` but not past nextDayThreshold, assign the default duration of one day. + if (endDay && endDay <= startDay) { + endDay = addDays(startDay, 1); + } + } + return { start: startDay, end: endDay }; + } + // spans from one day into another? + function isMultiDayRange(range) { + var visibleRange = computeVisibleDayRange(range); + return diffDays(visibleRange.start, visibleRange.end) > 1; + } + function diffDates(date0, date1, dateEnv, largeUnit) { + if (largeUnit === 'year') { + return createDuration(dateEnv.diffWholeYears(date0, date1), 'year'); + } + if (largeUnit === 'month') { + return createDuration(dateEnv.diffWholeMonths(date0, date1), 'month'); + } + return diffDayAndTime(date0, date1); // returns a duration + } + + function parseRange(input, dateEnv) { + var start = null; + var end = null; + if (input.start) { + start = dateEnv.createMarker(input.start); + } + if (input.end) { + end = dateEnv.createMarker(input.end); + } + if (!start && !end) { + return null; + } + if (start && end && end < start) { + return null; + } + return { start: start, end: end }; + } + // SIDE-EFFECT: will mutate ranges. + // Will return a new array result. + function invertRanges(ranges, constraintRange) { + var invertedRanges = []; + var start = constraintRange.start; // the end of the previous range. the start of the new range + var i; + var dateRange; + // ranges need to be in order. required for our date-walking algorithm + ranges.sort(compareRanges); + for (i = 0; i < ranges.length; i += 1) { + dateRange = ranges[i]; + // add the span of time before the event (if there is any) + if (dateRange.start > start) { // compare millisecond time (skip any ambig logic) + invertedRanges.push({ start: start, end: dateRange.start }); + } + if (dateRange.end > start) { + start = dateRange.end; + } + } + // add the span of time after the last event (if there is any) + if (start < constraintRange.end) { // compare millisecond time (skip any ambig logic) + invertedRanges.push({ start: start, end: constraintRange.end }); + } + return invertedRanges; + } + function compareRanges(range0, range1) { + return range0.start.valueOf() - range1.start.valueOf(); // earlier ranges go first + } + function intersectRanges(range0, range1) { + var start = range0.start, end = range0.end; + var newRange = null; + if (range1.start !== null) { + if (start === null) { + start = range1.start; + } + else { + start = new Date(Math.max(start.valueOf(), range1.start.valueOf())); + } + } + if (range1.end != null) { + if (end === null) { + end = range1.end; + } + else { + end = new Date(Math.min(end.valueOf(), range1.end.valueOf())); + } + } + if (start === null || end === null || start < end) { + newRange = { start: start, end: end }; + } + return newRange; + } + function rangesEqual(range0, range1) { + return (range0.start === null ? null : range0.start.valueOf()) === (range1.start === null ? null : range1.start.valueOf()) && + (range0.end === null ? null : range0.end.valueOf()) === (range1.end === null ? null : range1.end.valueOf()); + } + function rangesIntersect(range0, range1) { + return (range0.end === null || range1.start === null || range0.end > range1.start) && + (range0.start === null || range1.end === null || range0.start < range1.end); + } + function rangeContainsRange(outerRange, innerRange) { + return (outerRange.start === null || (innerRange.start !== null && innerRange.start >= outerRange.start)) && + (outerRange.end === null || (innerRange.end !== null && innerRange.end <= outerRange.end)); + } + function rangeContainsMarker(range, date) { + return (range.start === null || date >= range.start) && + (range.end === null || date < range.end); + } + // If the given date is not within the given range, move it inside. + // (If it's past the end, make it one millisecond before the end). + function constrainMarkerToRange(date, range) { + if (range.start != null && date < range.start) { + return range.start; + } + if (range.end != null && date >= range.end) { + return new Date(range.end.valueOf() - 1); + } + return date; + } + + /* + Specifying nextDayThreshold signals that all-day ranges should be sliced. + */ + function sliceEventStore(eventStore, eventUiBases, framingRange, nextDayThreshold) { + var inverseBgByGroupId = {}; + var inverseBgByDefId = {}; + var defByGroupId = {}; + var bgRanges = []; + var fgRanges = []; + var eventUis = compileEventUis(eventStore.defs, eventUiBases); + for (var defId in eventStore.defs) { + var def = eventStore.defs[defId]; + var ui = eventUis[def.defId]; + if (ui.display === 'inverse-background') { + if (def.groupId) { + inverseBgByGroupId[def.groupId] = []; + if (!defByGroupId[def.groupId]) { + defByGroupId[def.groupId] = def; + } + } + else { + inverseBgByDefId[defId] = []; + } + } + } + for (var instanceId in eventStore.instances) { + var instance = eventStore.instances[instanceId]; + var def = eventStore.defs[instance.defId]; + var ui = eventUis[def.defId]; + var origRange = instance.range; + var normalRange = (!def.allDay && nextDayThreshold) ? + computeVisibleDayRange(origRange, nextDayThreshold) : + origRange; + var slicedRange = intersectRanges(normalRange, framingRange); + if (slicedRange) { + if (ui.display === 'inverse-background') { + if (def.groupId) { + inverseBgByGroupId[def.groupId].push(slicedRange); + } + else { + inverseBgByDefId[instance.defId].push(slicedRange); + } + } + else if (ui.display !== 'none') { + (ui.display === 'background' ? bgRanges : fgRanges).push({ + def: def, + ui: ui, + instance: instance, + range: slicedRange, + isStart: normalRange.start && normalRange.start.valueOf() === slicedRange.start.valueOf(), + isEnd: normalRange.end && normalRange.end.valueOf() === slicedRange.end.valueOf(), + }); + } + } + } + for (var groupId in inverseBgByGroupId) { // BY GROUP + var ranges = inverseBgByGroupId[groupId]; + var invertedRanges = invertRanges(ranges, framingRange); + for (var _i = 0, invertedRanges_1 = invertedRanges; _i < invertedRanges_1.length; _i++) { + var invertedRange = invertedRanges_1[_i]; + var def = defByGroupId[groupId]; + var ui = eventUis[def.defId]; + bgRanges.push({ + def: def, + ui: ui, + instance: null, + range: invertedRange, + isStart: false, + isEnd: false, + }); + } + } + for (var defId in inverseBgByDefId) { + var ranges = inverseBgByDefId[defId]; + var invertedRanges = invertRanges(ranges, framingRange); + for (var _a = 0, invertedRanges_2 = invertedRanges; _a < invertedRanges_2.length; _a++) { + var invertedRange = invertedRanges_2[_a]; + bgRanges.push({ + def: eventStore.defs[defId], + ui: eventUis[defId], + instance: null, + range: invertedRange, + isStart: false, + isEnd: false, + }); + } + } + return { bg: bgRanges, fg: fgRanges }; + } + function hasBgRendering(def) { + return def.ui.display === 'background' || def.ui.display === 'inverse-background'; + } + function setElSeg(el, seg) { + el.fcSeg = seg; + } + function getElSeg(el) { + return el.fcSeg || + el.parentNode.fcSeg || // for the harness + null; + } + // event ui computation + function compileEventUis(eventDefs, eventUiBases) { + return mapHash(eventDefs, function (eventDef) { return compileEventUi(eventDef, eventUiBases); }); + } + function compileEventUi(eventDef, eventUiBases) { + var uis = []; + if (eventUiBases['']) { + uis.push(eventUiBases['']); + } + if (eventUiBases[eventDef.defId]) { + uis.push(eventUiBases[eventDef.defId]); + } + uis.push(eventDef.ui); + return combineEventUis(uis); + } + function sortEventSegs(segs, eventOrderSpecs) { + var objs = segs.map(buildSegCompareObj); + objs.sort(function (obj0, obj1) { return compareByFieldSpecs(obj0, obj1, eventOrderSpecs); }); + return objs.map(function (c) { return c._seg; }); + } + // returns a object with all primitive props that can be compared + function buildSegCompareObj(seg) { + var eventRange = seg.eventRange; + var eventDef = eventRange.def; + var range = eventRange.instance ? eventRange.instance.range : eventRange.range; + var start = range.start ? range.start.valueOf() : 0; // TODO: better support for open-range events + var end = range.end ? range.end.valueOf() : 0; // " + return __assign(__assign(__assign({}, eventDef.extendedProps), eventDef), { id: eventDef.publicId, start: start, + end: end, duration: end - start, allDay: Number(eventDef.allDay), _seg: seg }); + } + function computeSegDraggable(seg, context) { + var pluginHooks = context.pluginHooks; + var transformers = pluginHooks.isDraggableTransformers; + var _a = seg.eventRange, def = _a.def, ui = _a.ui; + var val = ui.startEditable; + for (var _i = 0, transformers_1 = transformers; _i < transformers_1.length; _i++) { + var transformer = transformers_1[_i]; + val = transformer(val, def, ui, context); + } + return val; + } + function computeSegStartResizable(seg, context) { + return seg.isStart && seg.eventRange.ui.durationEditable && context.options.eventResizableFromStart; + } + function computeSegEndResizable(seg, context) { + return seg.isEnd && seg.eventRange.ui.durationEditable; + } + function buildSegTimeText(seg, timeFormat, context, defaultDisplayEventTime, // defaults to true + defaultDisplayEventEnd, // defaults to true + startOverride, endOverride) { + var dateEnv = context.dateEnv, options = context.options; + var displayEventTime = options.displayEventTime, displayEventEnd = options.displayEventEnd; + var eventDef = seg.eventRange.def; + var eventInstance = seg.eventRange.instance; + if (displayEventTime == null) { + displayEventTime = defaultDisplayEventTime !== false; + } + if (displayEventEnd == null) { + displayEventEnd = defaultDisplayEventEnd !== false; + } + var wholeEventStart = eventInstance.range.start; + var wholeEventEnd = eventInstance.range.end; + var segStart = startOverride || seg.start || seg.eventRange.range.start; + var segEnd = endOverride || seg.end || seg.eventRange.range.end; + var isStartDay = startOfDay(wholeEventStart).valueOf() === startOfDay(segStart).valueOf(); + var isEndDay = startOfDay(addMs(wholeEventEnd, -1)).valueOf() === startOfDay(addMs(segEnd, -1)).valueOf(); + if (displayEventTime && !eventDef.allDay && (isStartDay || isEndDay)) { + segStart = isStartDay ? wholeEventStart : segStart; + segEnd = isEndDay ? wholeEventEnd : segEnd; + if (displayEventEnd && eventDef.hasEnd) { + return dateEnv.formatRange(segStart, segEnd, timeFormat, { + forcedStartTzo: startOverride ? null : eventInstance.forcedStartTzo, + forcedEndTzo: endOverride ? null : eventInstance.forcedEndTzo, + }); + } + return dateEnv.format(segStart, timeFormat, { + forcedTzo: startOverride ? null : eventInstance.forcedStartTzo, // nooooo, same + }); + } + return ''; + } + function getSegMeta(seg, todayRange, nowDate) { + var segRange = seg.eventRange.range; + return { + isPast: segRange.end < (nowDate || todayRange.start), + isFuture: segRange.start >= (nowDate || todayRange.end), + isToday: todayRange && rangeContainsMarker(todayRange, segRange.start), + }; + } + function getEventClassNames(props) { + var classNames = ['fc-event']; + if (props.isMirror) { + classNames.push('fc-event-mirror'); + } + if (props.isDraggable) { + classNames.push('fc-event-draggable'); + } + if (props.isStartResizable || props.isEndResizable) { + classNames.push('fc-event-resizable'); + } + if (props.isDragging) { + classNames.push('fc-event-dragging'); + } + if (props.isResizing) { + classNames.push('fc-event-resizing'); + } + if (props.isSelected) { + classNames.push('fc-event-selected'); + } + if (props.isStart) { + classNames.push('fc-event-start'); + } + if (props.isEnd) { + classNames.push('fc-event-end'); + } + if (props.isPast) { + classNames.push('fc-event-past'); + } + if (props.isToday) { + classNames.push('fc-event-today'); + } + if (props.isFuture) { + classNames.push('fc-event-future'); + } + return classNames; + } + function buildEventRangeKey(eventRange) { + return eventRange.instance + ? eventRange.instance.instanceId + : eventRange.def.defId + ":" + eventRange.range.start.toISOString(); + // inverse-background events don't have specific instances. TODO: better solution + } + + var STANDARD_PROPS = { + start: identity, + end: identity, + allDay: Boolean, + }; + function parseDateSpan(raw, dateEnv, defaultDuration) { + var span = parseOpenDateSpan(raw, dateEnv); + var range = span.range; + if (!range.start) { + return null; + } + if (!range.end) { + if (defaultDuration == null) { + return null; + } + range.end = dateEnv.add(range.start, defaultDuration); + } + return span; + } + /* + TODO: somehow combine with parseRange? + Will return null if the start/end props were present but parsed invalidly. + */ + function parseOpenDateSpan(raw, dateEnv) { + var _a = refineProps(raw, STANDARD_PROPS), standardProps = _a.refined, extra = _a.extra; + var startMeta = standardProps.start ? dateEnv.createMarkerMeta(standardProps.start) : null; + var endMeta = standardProps.end ? dateEnv.createMarkerMeta(standardProps.end) : null; + var allDay = standardProps.allDay; + if (allDay == null) { + allDay = (startMeta && startMeta.isTimeUnspecified) && + (!endMeta || endMeta.isTimeUnspecified); + } + return __assign({ range: { + start: startMeta ? startMeta.marker : null, + end: endMeta ? endMeta.marker : null, + }, allDay: allDay }, extra); + } + function isDateSpansEqual(span0, span1) { + return rangesEqual(span0.range, span1.range) && + span0.allDay === span1.allDay && + isSpanPropsEqual(span0, span1); + } + // the NON-DATE-RELATED props + function isSpanPropsEqual(span0, span1) { + for (var propName in span1) { + if (propName !== 'range' && propName !== 'allDay') { + if (span0[propName] !== span1[propName]) { + return false; + } + } + } + // are there any props that span0 has that span1 DOESN'T have? + // both have range/allDay, so no need to special-case. + for (var propName in span0) { + if (!(propName in span1)) { + return false; + } + } + return true; + } + function buildDateSpanApi(span, dateEnv) { + return __assign(__assign({}, buildRangeApi(span.range, dateEnv, span.allDay)), { allDay: span.allDay }); + } + function buildRangeApiWithTimeZone(range, dateEnv, omitTime) { + return __assign(__assign({}, buildRangeApi(range, dateEnv, omitTime)), { timeZone: dateEnv.timeZone }); + } + function buildRangeApi(range, dateEnv, omitTime) { + return { + start: dateEnv.toDate(range.start), + end: dateEnv.toDate(range.end), + startStr: dateEnv.formatIso(range.start, { omitTime: omitTime }), + endStr: dateEnv.formatIso(range.end, { omitTime: omitTime }), + }; + } + function fabricateEventRange(dateSpan, eventUiBases, context) { + var res = refineEventDef({ editable: false }, context); + var def = parseEventDef(res.refined, res.extra, '', // sourceId + dateSpan.allDay, true, // hasEnd + context); + return { + def: def, + ui: compileEventUi(def, eventUiBases), + instance: createEventInstance(def.defId, dateSpan.range), + range: dateSpan.range, + isStart: true, + isEnd: true, + }; + } + + function triggerDateSelect(selection, pev, context) { + context.emitter.trigger('select', __assign(__assign({}, buildDateSpanApiWithContext(selection, context)), { jsEvent: pev ? pev.origEvent : null, view: context.viewApi || context.calendarApi.view })); + } + function triggerDateUnselect(pev, context) { + context.emitter.trigger('unselect', { + jsEvent: pev ? pev.origEvent : null, + view: context.viewApi || context.calendarApi.view, + }); + } + function buildDateSpanApiWithContext(dateSpan, context) { + var props = {}; + for (var _i = 0, _a = context.pluginHooks.dateSpanTransforms; _i < _a.length; _i++) { + var transform = _a[_i]; + __assign(props, transform(dateSpan, context)); + } + __assign(props, buildDateSpanApi(dateSpan, context.dateEnv)); + return props; + } + // Given an event's allDay status and start date, return what its fallback end date should be. + // TODO: rename to computeDefaultEventEnd + function getDefaultEventEnd(allDay, marker, context) { + var dateEnv = context.dateEnv, options = context.options; + var end = marker; + if (allDay) { + end = startOfDay(end); + end = dateEnv.add(end, options.defaultAllDayEventDuration); + } + else { + end = dateEnv.add(end, options.defaultTimedEventDuration); + } + return end; + } + + // applies the mutation to ALL defs/instances within the event store + function applyMutationToEventStore(eventStore, eventConfigBase, mutation, context) { + var eventConfigs = compileEventUis(eventStore.defs, eventConfigBase); + var dest = createEmptyEventStore(); + for (var defId in eventStore.defs) { + var def = eventStore.defs[defId]; + dest.defs[defId] = applyMutationToEventDef(def, eventConfigs[defId], mutation, context); + } + for (var instanceId in eventStore.instances) { + var instance = eventStore.instances[instanceId]; + var def = dest.defs[instance.defId]; // important to grab the newly modified def + dest.instances[instanceId] = applyMutationToEventInstance(instance, def, eventConfigs[instance.defId], mutation, context); + } + return dest; + } + function applyMutationToEventDef(eventDef, eventConfig, mutation, context) { + var standardProps = mutation.standardProps || {}; + // if hasEnd has not been specified, guess a good value based on deltas. + // if duration will change, there's no way the default duration will persist, + // and thus, we need to mark the event as having a real end + if (standardProps.hasEnd == null && + eventConfig.durationEditable && + (mutation.startDelta || mutation.endDelta)) { + standardProps.hasEnd = true; // TODO: is this mutation okay? + } + var copy = __assign(__assign(__assign({}, eventDef), standardProps), { ui: __assign(__assign({}, eventDef.ui), standardProps.ui) }); + if (mutation.extendedProps) { + copy.extendedProps = __assign(__assign({}, copy.extendedProps), mutation.extendedProps); + } + for (var _i = 0, _a = context.pluginHooks.eventDefMutationAppliers; _i < _a.length; _i++) { + var applier = _a[_i]; + applier(copy, mutation, context); + } + if (!copy.hasEnd && context.options.forceEventDuration) { + copy.hasEnd = true; + } + return copy; + } + function applyMutationToEventInstance(eventInstance, eventDef, // must first be modified by applyMutationToEventDef + eventConfig, mutation, context) { + var dateEnv = context.dateEnv; + var forceAllDay = mutation.standardProps && mutation.standardProps.allDay === true; + var clearEnd = mutation.standardProps && mutation.standardProps.hasEnd === false; + var copy = __assign({}, eventInstance); + if (forceAllDay) { + copy.range = computeAlignedDayRange(copy.range); + } + if (mutation.datesDelta && eventConfig.startEditable) { + copy.range = { + start: dateEnv.add(copy.range.start, mutation.datesDelta), + end: dateEnv.add(copy.range.end, mutation.datesDelta), + }; + } + if (mutation.startDelta && eventConfig.durationEditable) { + copy.range = { + start: dateEnv.add(copy.range.start, mutation.startDelta), + end: copy.range.end, + }; + } + if (mutation.endDelta && eventConfig.durationEditable) { + copy.range = { + start: copy.range.start, + end: dateEnv.add(copy.range.end, mutation.endDelta), + }; + } + if (clearEnd) { + copy.range = { + start: copy.range.start, + end: getDefaultEventEnd(eventDef.allDay, copy.range.start, context), + }; + } + // in case event was all-day but the supplied deltas were not + // better util for this? + if (eventDef.allDay) { + copy.range = { + start: startOfDay(copy.range.start), + end: startOfDay(copy.range.end), + }; + } + // handle invalid durations + if (copy.range.end < copy.range.start) { + copy.range.end = getDefaultEventEnd(eventDef.allDay, copy.range.start, context); + } + return copy; + } + + // no public types yet. when there are, export from: + // import {} from './api-type-deps' + var ViewApi = /** @class */ (function () { + function ViewApi(type, getCurrentData, dateEnv) { + this.type = type; + this.getCurrentData = getCurrentData; + this.dateEnv = dateEnv; + } + Object.defineProperty(ViewApi.prototype, "calendar", { + get: function () { + return this.getCurrentData().calendarApi; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ViewApi.prototype, "title", { + get: function () { + return this.getCurrentData().viewTitle; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ViewApi.prototype, "activeStart", { + get: function () { + return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.start); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ViewApi.prototype, "activeEnd", { + get: function () { + return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.end); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ViewApi.prototype, "currentStart", { + get: function () { + return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.start); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ViewApi.prototype, "currentEnd", { + get: function () { + return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.end); + }, + enumerable: false, + configurable: true + }); + ViewApi.prototype.getOption = function (name) { + return this.getCurrentData().options[name]; // are the view-specific options + }; + return ViewApi; + }()); + + var EVENT_SOURCE_REFINERS$1 = { + id: String, + defaultAllDay: Boolean, + url: String, + format: String, + events: identity, + eventDataTransform: identity, + // for any network-related sources + success: identity, + failure: identity, + }; + function parseEventSource(raw, context, refiners) { + if (refiners === void 0) { refiners = buildEventSourceRefiners(context); } + var rawObj; + if (typeof raw === 'string') { + rawObj = { url: raw }; + } + else if (typeof raw === 'function' || Array.isArray(raw)) { + rawObj = { events: raw }; + } + else if (typeof raw === 'object' && raw) { // not null + rawObj = raw; + } + if (rawObj) { + var _a = refineProps(rawObj, refiners), refined = _a.refined, extra = _a.extra; + var metaRes = buildEventSourceMeta(refined, context); + if (metaRes) { + return { + _raw: raw, + isFetching: false, + latestFetchId: '', + fetchRange: null, + defaultAllDay: refined.defaultAllDay, + eventDataTransform: refined.eventDataTransform, + success: refined.success, + failure: refined.failure, + publicId: refined.id || '', + sourceId: guid(), + sourceDefId: metaRes.sourceDefId, + meta: metaRes.meta, + ui: createEventUi(refined, context), + extendedProps: extra, + }; + } + } + return null; + } + function buildEventSourceRefiners(context) { + return __assign(__assign(__assign({}, EVENT_UI_REFINERS), EVENT_SOURCE_REFINERS$1), context.pluginHooks.eventSourceRefiners); + } + function buildEventSourceMeta(raw, context) { + var defs = context.pluginHooks.eventSourceDefs; + for (var i = defs.length - 1; i >= 0; i -= 1) { // later-added plugins take precedence + var def = defs[i]; + var meta = def.parseMeta(raw); + if (meta) { + return { sourceDefId: i, meta: meta }; + } + } + return null; + } + + function reduceCurrentDate(currentDate, action) { + switch (action.type) { + case 'CHANGE_DATE': + return action.dateMarker; + default: + return currentDate; + } + } + function getInitialDate(options, dateEnv) { + var initialDateInput = options.initialDate; + // compute the initial ambig-timezone date + if (initialDateInput != null) { + return dateEnv.createMarker(initialDateInput); + } + return getNow(options.now, dateEnv); // getNow already returns unzoned + } + function getNow(nowInput, dateEnv) { + if (typeof nowInput === 'function') { + nowInput = nowInput(); + } + if (nowInput == null) { + return dateEnv.createNowMarker(); + } + return dateEnv.createMarker(nowInput); + } + + var CalendarApi = /** @class */ (function () { + function CalendarApi() { + } + CalendarApi.prototype.getCurrentData = function () { + return this.currentDataManager.getCurrentData(); + }; + CalendarApi.prototype.dispatch = function (action) { + return this.currentDataManager.dispatch(action); + }; + Object.defineProperty(CalendarApi.prototype, "view", { + get: function () { return this.getCurrentData().viewApi; } // for public API + , + enumerable: false, + configurable: true + }); + CalendarApi.prototype.batchRendering = function (callback) { + callback(); + }; + CalendarApi.prototype.updateSize = function () { + this.trigger('_resize', true); + }; + // Options + // ----------------------------------------------------------------------------------------------------------------- + CalendarApi.prototype.setOption = function (name, val) { + this.dispatch({ + type: 'SET_OPTION', + optionName: name, + rawOptionValue: val, + }); + }; + CalendarApi.prototype.getOption = function (name) { + return this.currentDataManager.currentCalendarOptionsInput[name]; + }; + CalendarApi.prototype.getAvailableLocaleCodes = function () { + return Object.keys(this.getCurrentData().availableRawLocales); + }; + // Trigger + // ----------------------------------------------------------------------------------------------------------------- + CalendarApi.prototype.on = function (handlerName, handler) { + var currentDataManager = this.currentDataManager; + if (currentDataManager.currentCalendarOptionsRefiners[handlerName]) { + currentDataManager.emitter.on(handlerName, handler); + } + else { + console.warn("Unknown listener name '" + handlerName + "'"); + } + }; + CalendarApi.prototype.off = function (handlerName, handler) { + this.currentDataManager.emitter.off(handlerName, handler); + }; + // not meant for public use + CalendarApi.prototype.trigger = function (handlerName) { + var _a; + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + (_a = this.currentDataManager.emitter).trigger.apply(_a, __spreadArray([handlerName], args)); + }; + // View + // ----------------------------------------------------------------------------------------------------------------- + CalendarApi.prototype.changeView = function (viewType, dateOrRange) { + var _this = this; + this.batchRendering(function () { + _this.unselect(); + if (dateOrRange) { + if (dateOrRange.start && dateOrRange.end) { // a range + _this.dispatch({ + type: 'CHANGE_VIEW_TYPE', + viewType: viewType, + }); + _this.dispatch({ + type: 'SET_OPTION', + optionName: 'visibleRange', + rawOptionValue: dateOrRange, + }); + } + else { + var dateEnv = _this.getCurrentData().dateEnv; + _this.dispatch({ + type: 'CHANGE_VIEW_TYPE', + viewType: viewType, + dateMarker: dateEnv.createMarker(dateOrRange), + }); + } + } + else { + _this.dispatch({ + type: 'CHANGE_VIEW_TYPE', + viewType: viewType, + }); + } + }); + }; + // Forces navigation to a view for the given date. + // `viewType` can be a specific view name or a generic one like "week" or "day". + // needs to change + CalendarApi.prototype.zoomTo = function (dateMarker, viewType) { + var state = this.getCurrentData(); + var spec; + viewType = viewType || 'day'; // day is default zoom + spec = state.viewSpecs[viewType] || this.getUnitViewSpec(viewType); + this.unselect(); + if (spec) { + this.dispatch({ + type: 'CHANGE_VIEW_TYPE', + viewType: spec.type, + dateMarker: dateMarker, + }); + } + else { + this.dispatch({ + type: 'CHANGE_DATE', + dateMarker: dateMarker, + }); + } + }; + // Given a duration singular unit, like "week" or "day", finds a matching view spec. + // Preference is given to views that have corresponding buttons. + CalendarApi.prototype.getUnitViewSpec = function (unit) { + var _a = this.getCurrentData(), viewSpecs = _a.viewSpecs, toolbarConfig = _a.toolbarConfig; + var viewTypes = [].concat(toolbarConfig.viewsWithButtons); + var i; + var spec; + for (var viewType in viewSpecs) { + viewTypes.push(viewType); + } + for (i = 0; i < viewTypes.length; i += 1) { + spec = viewSpecs[viewTypes[i]]; + if (spec) { + if (spec.singleUnit === unit) { + return spec; + } + } + } + return null; + }; + // Current Date + // ----------------------------------------------------------------------------------------------------------------- + CalendarApi.prototype.prev = function () { + this.unselect(); + this.dispatch({ type: 'PREV' }); + }; + CalendarApi.prototype.next = function () { + this.unselect(); + this.dispatch({ type: 'NEXT' }); + }; + CalendarApi.prototype.prevYear = function () { + var state = this.getCurrentData(); + this.unselect(); + this.dispatch({ + type: 'CHANGE_DATE', + dateMarker: state.dateEnv.addYears(state.currentDate, -1), + }); + }; + CalendarApi.prototype.nextYear = function () { + var state = this.getCurrentData(); + this.unselect(); + this.dispatch({ + type: 'CHANGE_DATE', + dateMarker: state.dateEnv.addYears(state.currentDate, 1), + }); + }; + CalendarApi.prototype.today = function () { + var state = this.getCurrentData(); + this.unselect(); + this.dispatch({ + type: 'CHANGE_DATE', + dateMarker: getNow(state.calendarOptions.now, state.dateEnv), + }); + }; + CalendarApi.prototype.gotoDate = function (zonedDateInput) { + var state = this.getCurrentData(); + this.unselect(); + this.dispatch({ + type: 'CHANGE_DATE', + dateMarker: state.dateEnv.createMarker(zonedDateInput), + }); + }; + CalendarApi.prototype.incrementDate = function (deltaInput) { + var state = this.getCurrentData(); + var delta = createDuration(deltaInput); + if (delta) { // else, warn about invalid input? + this.unselect(); + this.dispatch({ + type: 'CHANGE_DATE', + dateMarker: state.dateEnv.add(state.currentDate, delta), + }); + } + }; + // for external API + CalendarApi.prototype.getDate = function () { + var state = this.getCurrentData(); + return state.dateEnv.toDate(state.currentDate); + }; + // Date Formatting Utils + // ----------------------------------------------------------------------------------------------------------------- + CalendarApi.prototype.formatDate = function (d, formatter) { + var dateEnv = this.getCurrentData().dateEnv; + return dateEnv.format(dateEnv.createMarker(d), createFormatter(formatter)); + }; + // `settings` is for formatter AND isEndExclusive + CalendarApi.prototype.formatRange = function (d0, d1, settings) { + var dateEnv = this.getCurrentData().dateEnv; + return dateEnv.formatRange(dateEnv.createMarker(d0), dateEnv.createMarker(d1), createFormatter(settings), settings); + }; + CalendarApi.prototype.formatIso = function (d, omitTime) { + var dateEnv = this.getCurrentData().dateEnv; + return dateEnv.formatIso(dateEnv.createMarker(d), { omitTime: omitTime }); + }; + // Date Selection / Event Selection / DayClick + // ----------------------------------------------------------------------------------------------------------------- + // this public method receives start/end dates in any format, with any timezone + // NOTE: args were changed from v3 + CalendarApi.prototype.select = function (dateOrObj, endDate) { + var selectionInput; + if (endDate == null) { + if (dateOrObj.start != null) { + selectionInput = dateOrObj; + } + else { + selectionInput = { + start: dateOrObj, + end: null, + }; + } + } + else { + selectionInput = { + start: dateOrObj, + end: endDate, + }; + } + var state = this.getCurrentData(); + var selection = parseDateSpan(selectionInput, state.dateEnv, createDuration({ days: 1 })); + if (selection) { // throw parse error otherwise? + this.dispatch({ type: 'SELECT_DATES', selection: selection }); + triggerDateSelect(selection, null, state); + } + }; + // public method + CalendarApi.prototype.unselect = function (pev) { + var state = this.getCurrentData(); + if (state.dateSelection) { + this.dispatch({ type: 'UNSELECT_DATES' }); + triggerDateUnselect(pev, state); + } + }; + // Public Events API + // ----------------------------------------------------------------------------------------------------------------- + CalendarApi.prototype.addEvent = function (eventInput, sourceInput) { + if (eventInput instanceof EventApi) { + var def = eventInput._def; + var instance = eventInput._instance; + var currentData = this.getCurrentData(); + // not already present? don't want to add an old snapshot + if (!currentData.eventStore.defs[def.defId]) { + this.dispatch({ + type: 'ADD_EVENTS', + eventStore: eventTupleToStore({ def: def, instance: instance }), // TODO: better util for two args? + }); + this.triggerEventAdd(eventInput); + } + return eventInput; + } + var state = this.getCurrentData(); + var eventSource; + if (sourceInput instanceof EventSourceApi) { + eventSource = sourceInput.internalEventSource; + } + else if (typeof sourceInput === 'boolean') { + if (sourceInput) { // true. part of the first event source + eventSource = hashValuesToArray(state.eventSources)[0]; + } + } + else if (sourceInput != null) { // an ID. accepts a number too + var sourceApi = this.getEventSourceById(sourceInput); // TODO: use an internal function + if (!sourceApi) { + console.warn("Could not find an event source with ID \"" + sourceInput + "\""); // TODO: test + return null; + } + eventSource = sourceApi.internalEventSource; + } + var tuple = parseEvent(eventInput, eventSource, state, false); + if (tuple) { + var newEventApi = new EventApi(state, tuple.def, tuple.def.recurringDef ? null : tuple.instance); + this.dispatch({ + type: 'ADD_EVENTS', + eventStore: eventTupleToStore(tuple), + }); + this.triggerEventAdd(newEventApi); + return newEventApi; + } + return null; + }; + CalendarApi.prototype.triggerEventAdd = function (eventApi) { + var _this = this; + var emitter = this.getCurrentData().emitter; + emitter.trigger('eventAdd', { + event: eventApi, + relatedEvents: [], + revert: function () { + _this.dispatch({ + type: 'REMOVE_EVENTS', + eventStore: eventApiToStore(eventApi), + }); + }, + }); + }; + // TODO: optimize + CalendarApi.prototype.getEventById = function (id) { + var state = this.getCurrentData(); + var _a = state.eventStore, defs = _a.defs, instances = _a.instances; + id = String(id); + for (var defId in defs) { + var def = defs[defId]; + if (def.publicId === id) { + if (def.recurringDef) { + return new EventApi(state, def, null); + } + for (var instanceId in instances) { + var instance = instances[instanceId]; + if (instance.defId === def.defId) { + return new EventApi(state, def, instance); + } + } + } + } + return null; + }; + CalendarApi.prototype.getEvents = function () { + var currentData = this.getCurrentData(); + return buildEventApis(currentData.eventStore, currentData); + }; + CalendarApi.prototype.removeAllEvents = function () { + this.dispatch({ type: 'REMOVE_ALL_EVENTS' }); + }; + // Public Event Sources API + // ----------------------------------------------------------------------------------------------------------------- + CalendarApi.prototype.getEventSources = function () { + var state = this.getCurrentData(); + var sourceHash = state.eventSources; + var sourceApis = []; + for (var internalId in sourceHash) { + sourceApis.push(new EventSourceApi(state, sourceHash[internalId])); + } + return sourceApis; + }; + CalendarApi.prototype.getEventSourceById = function (id) { + var state = this.getCurrentData(); + var sourceHash = state.eventSources; + id = String(id); + for (var sourceId in sourceHash) { + if (sourceHash[sourceId].publicId === id) { + return new EventSourceApi(state, sourceHash[sourceId]); + } + } + return null; + }; + CalendarApi.prototype.addEventSource = function (sourceInput) { + var state = this.getCurrentData(); + if (sourceInput instanceof EventSourceApi) { + // not already present? don't want to add an old snapshot + if (!state.eventSources[sourceInput.internalEventSource.sourceId]) { + this.dispatch({ + type: 'ADD_EVENT_SOURCES', + sources: [sourceInput.internalEventSource], + }); + } + return sourceInput; + } + var eventSource = parseEventSource(sourceInput, state); + if (eventSource) { // TODO: error otherwise? + this.dispatch({ type: 'ADD_EVENT_SOURCES', sources: [eventSource] }); + return new EventSourceApi(state, eventSource); + } + return null; + }; + CalendarApi.prototype.removeAllEventSources = function () { + this.dispatch({ type: 'REMOVE_ALL_EVENT_SOURCES' }); + }; + CalendarApi.prototype.refetchEvents = function () { + this.dispatch({ type: 'FETCH_EVENT_SOURCES', isRefetch: true }); + }; + // Scroll + // ----------------------------------------------------------------------------------------------------------------- + CalendarApi.prototype.scrollToTime = function (timeInput) { + var time = createDuration(timeInput); + if (time) { + this.trigger('_scrollRequest', { time: time }); + } + }; + return CalendarApi; + }()); + + var EventApi = /** @class */ (function () { + // instance will be null if expressing a recurring event that has no current instances, + // OR if trying to validate an incoming external event that has no dates assigned + function EventApi(context, def, instance) { + this._context = context; + this._def = def; + this._instance = instance || null; + } + /* + TODO: make event struct more responsible for this + */ + EventApi.prototype.setProp = function (name, val) { + var _a, _b; + if (name in EVENT_DATE_REFINERS) { + console.warn('Could not set date-related prop \'name\'. Use one of the date-related methods instead.'); + // TODO: make proper aliasing system? + } + else if (name === 'id') { + val = EVENT_NON_DATE_REFINERS[name](val); + this.mutate({ + standardProps: { publicId: val }, // hardcoded internal name + }); + } + else if (name in EVENT_NON_DATE_REFINERS) { + val = EVENT_NON_DATE_REFINERS[name](val); + this.mutate({ + standardProps: (_a = {}, _a[name] = val, _a), + }); + } + else if (name in EVENT_UI_REFINERS) { + var ui = EVENT_UI_REFINERS[name](val); + if (name === 'color') { + ui = { backgroundColor: val, borderColor: val }; + } + else if (name === 'editable') { + ui = { startEditable: val, durationEditable: val }; + } + else { + ui = (_b = {}, _b[name] = val, _b); + } + this.mutate({ + standardProps: { ui: ui }, + }); + } + else { + console.warn("Could not set prop '" + name + "'. Use setExtendedProp instead."); + } + }; + EventApi.prototype.setExtendedProp = function (name, val) { + var _a; + this.mutate({ + extendedProps: (_a = {}, _a[name] = val, _a), + }); + }; + EventApi.prototype.setStart = function (startInput, options) { + if (options === void 0) { options = {}; } + var dateEnv = this._context.dateEnv; + var start = dateEnv.createMarker(startInput); + if (start && this._instance) { // TODO: warning if parsed bad + var instanceRange = this._instance.range; + var startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity); // what if parsed bad!? + if (options.maintainDuration) { + this.mutate({ datesDelta: startDelta }); + } + else { + this.mutate({ startDelta: startDelta }); + } + } + }; + EventApi.prototype.setEnd = function (endInput, options) { + if (options === void 0) { options = {}; } + var dateEnv = this._context.dateEnv; + var end; + if (endInput != null) { + end = dateEnv.createMarker(endInput); + if (!end) { + return; // TODO: warning if parsed bad + } + } + if (this._instance) { + if (end) { + var endDelta = diffDates(this._instance.range.end, end, dateEnv, options.granularity); + this.mutate({ endDelta: endDelta }); + } + else { + this.mutate({ standardProps: { hasEnd: false } }); + } + } + }; + EventApi.prototype.setDates = function (startInput, endInput, options) { + if (options === void 0) { options = {}; } + var dateEnv = this._context.dateEnv; + var standardProps = { allDay: options.allDay }; + var start = dateEnv.createMarker(startInput); + var end; + if (!start) { + return; // TODO: warning if parsed bad + } + if (endInput != null) { + end = dateEnv.createMarker(endInput); + if (!end) { // TODO: warning if parsed bad + return; + } + } + if (this._instance) { + var instanceRange = this._instance.range; + // when computing the diff for an event being converted to all-day, + // compute diff off of the all-day values the way event-mutation does. + if (options.allDay === true) { + instanceRange = computeAlignedDayRange(instanceRange); + } + var startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity); + if (end) { + var endDelta = diffDates(instanceRange.end, end, dateEnv, options.granularity); + if (durationsEqual(startDelta, endDelta)) { + this.mutate({ datesDelta: startDelta, standardProps: standardProps }); + } + else { + this.mutate({ startDelta: startDelta, endDelta: endDelta, standardProps: standardProps }); + } + } + else { // means "clear the end" + standardProps.hasEnd = false; + this.mutate({ datesDelta: startDelta, standardProps: standardProps }); + } + } + }; + EventApi.prototype.moveStart = function (deltaInput) { + var delta = createDuration(deltaInput); + if (delta) { // TODO: warning if parsed bad + this.mutate({ startDelta: delta }); + } + }; + EventApi.prototype.moveEnd = function (deltaInput) { + var delta = createDuration(deltaInput); + if (delta) { // TODO: warning if parsed bad + this.mutate({ endDelta: delta }); + } + }; + EventApi.prototype.moveDates = function (deltaInput) { + var delta = createDuration(deltaInput); + if (delta) { // TODO: warning if parsed bad + this.mutate({ datesDelta: delta }); + } + }; + EventApi.prototype.setAllDay = function (allDay, options) { + if (options === void 0) { options = {}; } + var standardProps = { allDay: allDay }; + var maintainDuration = options.maintainDuration; + if (maintainDuration == null) { + maintainDuration = this._context.options.allDayMaintainDuration; + } + if (this._def.allDay !== allDay) { + standardProps.hasEnd = maintainDuration; + } + this.mutate({ standardProps: standardProps }); + }; + EventApi.prototype.formatRange = function (formatInput) { + var dateEnv = this._context.dateEnv; + var instance = this._instance; + var formatter = createFormatter(formatInput); + if (this._def.hasEnd) { + return dateEnv.formatRange(instance.range.start, instance.range.end, formatter, { + forcedStartTzo: instance.forcedStartTzo, + forcedEndTzo: instance.forcedEndTzo, + }); + } + return dateEnv.format(instance.range.start, formatter, { + forcedTzo: instance.forcedStartTzo, + }); + }; + EventApi.prototype.mutate = function (mutation) { + var instance = this._instance; + if (instance) { + var def = this._def; + var context_1 = this._context; + var eventStore_1 = context_1.getCurrentData().eventStore; + var relevantEvents = getRelevantEvents(eventStore_1, instance.instanceId); + var eventConfigBase = { + '': { + display: '', + startEditable: true, + durationEditable: true, + constraints: [], + overlap: null, + allows: [], + backgroundColor: '', + borderColor: '', + textColor: '', + classNames: [], + }, + }; + relevantEvents = applyMutationToEventStore(relevantEvents, eventConfigBase, mutation, context_1); + var oldEvent = new EventApi(context_1, def, instance); // snapshot + this._def = relevantEvents.defs[def.defId]; + this._instance = relevantEvents.instances[instance.instanceId]; + context_1.dispatch({ + type: 'MERGE_EVENTS', + eventStore: relevantEvents, + }); + context_1.emitter.trigger('eventChange', { + oldEvent: oldEvent, + event: this, + relatedEvents: buildEventApis(relevantEvents, context_1, instance), + revert: function () { + context_1.dispatch({ + type: 'RESET_EVENTS', + eventStore: eventStore_1, + }); + }, + }); + } + }; + EventApi.prototype.remove = function () { + var context = this._context; + var asStore = eventApiToStore(this); + context.dispatch({ + type: 'REMOVE_EVENTS', + eventStore: asStore, + }); + context.emitter.trigger('eventRemove', { + event: this, + relatedEvents: [], + revert: function () { + context.dispatch({ + type: 'MERGE_EVENTS', + eventStore: asStore, + }); + }, + }); + }; + Object.defineProperty(EventApi.prototype, "source", { + get: function () { + var sourceId = this._def.sourceId; + if (sourceId) { + return new EventSourceApi(this._context, this._context.getCurrentData().eventSources[sourceId]); + } + return null; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "start", { + get: function () { + return this._instance ? + this._context.dateEnv.toDate(this._instance.range.start) : + null; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "end", { + get: function () { + return (this._instance && this._def.hasEnd) ? + this._context.dateEnv.toDate(this._instance.range.end) : + null; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "startStr", { + get: function () { + var instance = this._instance; + if (instance) { + return this._context.dateEnv.formatIso(instance.range.start, { + omitTime: this._def.allDay, + forcedTzo: instance.forcedStartTzo, + }); + } + return ''; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "endStr", { + get: function () { + var instance = this._instance; + if (instance && this._def.hasEnd) { + return this._context.dateEnv.formatIso(instance.range.end, { + omitTime: this._def.allDay, + forcedTzo: instance.forcedEndTzo, + }); + } + return ''; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "id", { + // computable props that all access the def + // TODO: find a TypeScript-compatible way to do this at scale + get: function () { return this._def.publicId; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "groupId", { + get: function () { return this._def.groupId; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "allDay", { + get: function () { return this._def.allDay; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "title", { + get: function () { return this._def.title; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "url", { + get: function () { return this._def.url; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "display", { + get: function () { return this._def.ui.display || 'auto'; } // bad. just normalize the type earlier + , + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "startEditable", { + get: function () { return this._def.ui.startEditable; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "durationEditable", { + get: function () { return this._def.ui.durationEditable; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "constraint", { + get: function () { return this._def.ui.constraints[0] || null; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "overlap", { + get: function () { return this._def.ui.overlap; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "allow", { + get: function () { return this._def.ui.allows[0] || null; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "backgroundColor", { + get: function () { return this._def.ui.backgroundColor; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "borderColor", { + get: function () { return this._def.ui.borderColor; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "textColor", { + get: function () { return this._def.ui.textColor; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "classNames", { + // NOTE: user can't modify these because Object.freeze was called in event-def parsing + get: function () { return this._def.ui.classNames; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(EventApi.prototype, "extendedProps", { + get: function () { return this._def.extendedProps; }, + enumerable: false, + configurable: true + }); + EventApi.prototype.toPlainObject = function (settings) { + if (settings === void 0) { settings = {}; } + var def = this._def; + var ui = def.ui; + var _a = this, startStr = _a.startStr, endStr = _a.endStr; + var res = {}; + if (def.title) { + res.title = def.title; + } + if (startStr) { + res.start = startStr; + } + if (endStr) { + res.end = endStr; + } + if (def.publicId) { + res.id = def.publicId; + } + if (def.groupId) { + res.groupId = def.groupId; + } + if (def.url) { + res.url = def.url; + } + if (ui.display && ui.display !== 'auto') { + res.display = ui.display; + } + // TODO: what about recurring-event properties??? + // TODO: include startEditable/durationEditable/constraint/overlap/allow + if (settings.collapseColor && ui.backgroundColor && ui.backgroundColor === ui.borderColor) { + res.color = ui.backgroundColor; + } + else { + if (ui.backgroundColor) { + res.backgroundColor = ui.backgroundColor; + } + if (ui.borderColor) { + res.borderColor = ui.borderColor; + } + } + if (ui.textColor) { + res.textColor = ui.textColor; + } + if (ui.classNames.length) { + res.classNames = ui.classNames; + } + if (Object.keys(def.extendedProps).length) { + if (settings.collapseExtendedProps) { + __assign(res, def.extendedProps); + } + else { + res.extendedProps = def.extendedProps; + } + } + return res; + }; + EventApi.prototype.toJSON = function () { + return this.toPlainObject(); + }; + return EventApi; + }()); + function eventApiToStore(eventApi) { + var _a, _b; + var def = eventApi._def; + var instance = eventApi._instance; + return { + defs: (_a = {}, _a[def.defId] = def, _a), + instances: instance + ? (_b = {}, _b[instance.instanceId] = instance, _b) : {}, + }; + } + function buildEventApis(eventStore, context, excludeInstance) { + var defs = eventStore.defs, instances = eventStore.instances; + var eventApis = []; + var excludeInstanceId = excludeInstance ? excludeInstance.instanceId : ''; + for (var id in instances) { + var instance = instances[id]; + var def = defs[instance.defId]; + if (instance.instanceId !== excludeInstanceId) { + eventApis.push(new EventApi(context, def, instance)); + } + } + return eventApis; + } + + var calendarSystemClassMap = {}; + function registerCalendarSystem(name, theClass) { + calendarSystemClassMap[name] = theClass; + } + function createCalendarSystem(name) { + return new calendarSystemClassMap[name](); + } + var GregorianCalendarSystem = /** @class */ (function () { + function GregorianCalendarSystem() { + } + GregorianCalendarSystem.prototype.getMarkerYear = function (d) { + return d.getUTCFullYear(); + }; + GregorianCalendarSystem.prototype.getMarkerMonth = function (d) { + return d.getUTCMonth(); + }; + GregorianCalendarSystem.prototype.getMarkerDay = function (d) { + return d.getUTCDate(); + }; + GregorianCalendarSystem.prototype.arrayToMarker = function (arr) { + return arrayToUtcDate(arr); + }; + GregorianCalendarSystem.prototype.markerToArray = function (marker) { + return dateToUtcArray(marker); + }; + return GregorianCalendarSystem; + }()); + registerCalendarSystem('gregory', GregorianCalendarSystem); + + var ISO_RE = /^\s*(\d{4})(-?(\d{2})(-?(\d{2})([T ](\d{2}):?(\d{2})(:?(\d{2})(\.(\d+))?)?(Z|(([-+])(\d{2})(:?(\d{2}))?))?)?)?)?$/; + function parse(str) { + var m = ISO_RE.exec(str); + if (m) { + var marker = new Date(Date.UTC(Number(m[1]), m[3] ? Number(m[3]) - 1 : 0, Number(m[5] || 1), Number(m[7] || 0), Number(m[8] || 0), Number(m[10] || 0), m[12] ? Number("0." + m[12]) * 1000 : 0)); + if (isValidDate$1(marker)) { + var timeZoneOffset = null; + if (m[13]) { + timeZoneOffset = (m[15] === '-' ? -1 : 1) * (Number(m[16] || 0) * 60 + + Number(m[18] || 0)); + } + return { + marker: marker, + isTimeUnspecified: !m[6], + timeZoneOffset: timeZoneOffset, + }; + } + } + return null; + } + + var DateEnv = /** @class */ (function () { + function DateEnv(settings) { + var timeZone = this.timeZone = settings.timeZone; + var isNamedTimeZone = timeZone !== 'local' && timeZone !== 'UTC'; + if (settings.namedTimeZoneImpl && isNamedTimeZone) { + this.namedTimeZoneImpl = new settings.namedTimeZoneImpl(timeZone); + } + this.canComputeOffset = Boolean(!isNamedTimeZone || this.namedTimeZoneImpl); + this.calendarSystem = createCalendarSystem(settings.calendarSystem); + this.locale = settings.locale; + this.weekDow = settings.locale.week.dow; + this.weekDoy = settings.locale.week.doy; + if (settings.weekNumberCalculation === 'ISO') { + this.weekDow = 1; + this.weekDoy = 4; + } + if (typeof settings.firstDay === 'number') { + this.weekDow = settings.firstDay; + } + if (typeof settings.weekNumberCalculation === 'function') { + this.weekNumberFunc = settings.weekNumberCalculation; + } + this.weekText = settings.weekText != null ? settings.weekText : settings.locale.options.weekText; + this.cmdFormatter = settings.cmdFormatter; + this.defaultSeparator = settings.defaultSeparator; + } + // Creating / Parsing + DateEnv.prototype.createMarker = function (input) { + var meta = this.createMarkerMeta(input); + if (meta === null) { + return null; + } + return meta.marker; + }; + DateEnv.prototype.createNowMarker = function () { + if (this.canComputeOffset) { + return this.timestampToMarker(new Date().valueOf()); + } + // if we can't compute the current date val for a timezone, + // better to give the current local date vals than UTC + return arrayToUtcDate(dateToLocalArray(new Date())); + }; + DateEnv.prototype.createMarkerMeta = function (input) { + if (typeof input === 'string') { + return this.parse(input); + } + var marker = null; + if (typeof input === 'number') { + marker = this.timestampToMarker(input); + } + else if (input instanceof Date) { + input = input.valueOf(); + if (!isNaN(input)) { + marker = this.timestampToMarker(input); + } + } + else if (Array.isArray(input)) { + marker = arrayToUtcDate(input); + } + if (marker === null || !isValidDate$1(marker)) { + return null; + } + return { marker: marker, isTimeUnspecified: false, forcedTzo: null }; + }; + DateEnv.prototype.parse = function (s) { + var parts = parse(s); + if (parts === null) { + return null; + } + var marker = parts.marker; + var forcedTzo = null; + if (parts.timeZoneOffset !== null) { + if (this.canComputeOffset) { + marker = this.timestampToMarker(marker.valueOf() - parts.timeZoneOffset * 60 * 1000); + } + else { + forcedTzo = parts.timeZoneOffset; + } + } + return { marker: marker, isTimeUnspecified: parts.isTimeUnspecified, forcedTzo: forcedTzo }; + }; + // Accessors + DateEnv.prototype.getYear = function (marker) { + return this.calendarSystem.getMarkerYear(marker); + }; + DateEnv.prototype.getMonth = function (marker) { + return this.calendarSystem.getMarkerMonth(marker); + }; + // Adding / Subtracting + DateEnv.prototype.add = function (marker, dur) { + var a = this.calendarSystem.markerToArray(marker); + a[0] += dur.years; + a[1] += dur.months; + a[2] += dur.days; + a[6] += dur.milliseconds; + return this.calendarSystem.arrayToMarker(a); + }; + DateEnv.prototype.subtract = function (marker, dur) { + var a = this.calendarSystem.markerToArray(marker); + a[0] -= dur.years; + a[1] -= dur.months; + a[2] -= dur.days; + a[6] -= dur.milliseconds; + return this.calendarSystem.arrayToMarker(a); + }; + DateEnv.prototype.addYears = function (marker, n) { + var a = this.calendarSystem.markerToArray(marker); + a[0] += n; + return this.calendarSystem.arrayToMarker(a); + }; + DateEnv.prototype.addMonths = function (marker, n) { + var a = this.calendarSystem.markerToArray(marker); + a[1] += n; + return this.calendarSystem.arrayToMarker(a); + }; + // Diffing Whole Units + DateEnv.prototype.diffWholeYears = function (m0, m1) { + var calendarSystem = this.calendarSystem; + if (timeAsMs(m0) === timeAsMs(m1) && + calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1) && + calendarSystem.getMarkerMonth(m0) === calendarSystem.getMarkerMonth(m1)) { + return calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0); + } + return null; + }; + DateEnv.prototype.diffWholeMonths = function (m0, m1) { + var calendarSystem = this.calendarSystem; + if (timeAsMs(m0) === timeAsMs(m1) && + calendarSystem.getMarkerDay(m0) === calendarSystem.getMarkerDay(m1)) { + return (calendarSystem.getMarkerMonth(m1) - calendarSystem.getMarkerMonth(m0)) + + (calendarSystem.getMarkerYear(m1) - calendarSystem.getMarkerYear(m0)) * 12; + } + return null; + }; + // Range / Duration + DateEnv.prototype.greatestWholeUnit = function (m0, m1) { + var n = this.diffWholeYears(m0, m1); + if (n !== null) { + return { unit: 'year', value: n }; + } + n = this.diffWholeMonths(m0, m1); + if (n !== null) { + return { unit: 'month', value: n }; + } + n = diffWholeWeeks(m0, m1); + if (n !== null) { + return { unit: 'week', value: n }; + } + n = diffWholeDays(m0, m1); + if (n !== null) { + return { unit: 'day', value: n }; + } + n = diffHours(m0, m1); + if (isInt(n)) { + return { unit: 'hour', value: n }; + } + n = diffMinutes(m0, m1); + if (isInt(n)) { + return { unit: 'minute', value: n }; + } + n = diffSeconds(m0, m1); + if (isInt(n)) { + return { unit: 'second', value: n }; + } + return { unit: 'millisecond', value: m1.valueOf() - m0.valueOf() }; + }; + DateEnv.prototype.countDurationsBetween = function (m0, m1, d) { + // TODO: can use greatestWholeUnit + var diff; + if (d.years) { + diff = this.diffWholeYears(m0, m1); + if (diff !== null) { + return diff / asRoughYears(d); + } + } + if (d.months) { + diff = this.diffWholeMonths(m0, m1); + if (diff !== null) { + return diff / asRoughMonths(d); + } + } + if (d.days) { + diff = diffWholeDays(m0, m1); + if (diff !== null) { + return diff / asRoughDays(d); + } + } + return (m1.valueOf() - m0.valueOf()) / asRoughMs(d); + }; + // Start-Of + // these DON'T return zoned-dates. only UTC start-of dates + DateEnv.prototype.startOf = function (m, unit) { + if (unit === 'year') { + return this.startOfYear(m); + } + if (unit === 'month') { + return this.startOfMonth(m); + } + if (unit === 'week') { + return this.startOfWeek(m); + } + if (unit === 'day') { + return startOfDay(m); + } + if (unit === 'hour') { + return startOfHour(m); + } + if (unit === 'minute') { + return startOfMinute(m); + } + if (unit === 'second') { + return startOfSecond(m); + } + return null; + }; + DateEnv.prototype.startOfYear = function (m) { + return this.calendarSystem.arrayToMarker([ + this.calendarSystem.getMarkerYear(m), + ]); + }; + DateEnv.prototype.startOfMonth = function (m) { + return this.calendarSystem.arrayToMarker([ + this.calendarSystem.getMarkerYear(m), + this.calendarSystem.getMarkerMonth(m), + ]); + }; + DateEnv.prototype.startOfWeek = function (m) { + return this.calendarSystem.arrayToMarker([ + this.calendarSystem.getMarkerYear(m), + this.calendarSystem.getMarkerMonth(m), + m.getUTCDate() - ((m.getUTCDay() - this.weekDow + 7) % 7), + ]); + }; + // Week Number + DateEnv.prototype.computeWeekNumber = function (marker) { + if (this.weekNumberFunc) { + return this.weekNumberFunc(this.toDate(marker)); + } + return weekOfYear(marker, this.weekDow, this.weekDoy); + }; + // TODO: choke on timeZoneName: long + DateEnv.prototype.format = function (marker, formatter, dateOptions) { + if (dateOptions === void 0) { dateOptions = {}; } + return formatter.format({ + marker: marker, + timeZoneOffset: dateOptions.forcedTzo != null ? + dateOptions.forcedTzo : + this.offsetForMarker(marker), + }, this); + }; + DateEnv.prototype.formatRange = function (start, end, formatter, dateOptions) { + if (dateOptions === void 0) { dateOptions = {}; } + if (dateOptions.isEndExclusive) { + end = addMs(end, -1); + } + return formatter.formatRange({ + marker: start, + timeZoneOffset: dateOptions.forcedStartTzo != null ? + dateOptions.forcedStartTzo : + this.offsetForMarker(start), + }, { + marker: end, + timeZoneOffset: dateOptions.forcedEndTzo != null ? + dateOptions.forcedEndTzo : + this.offsetForMarker(end), + }, this, dateOptions.defaultSeparator); + }; + /* + DUMB: the omitTime arg is dumb. if we omit the time, we want to omit the timezone offset. and if we do that, + might as well use buildIsoString or some other util directly + */ + DateEnv.prototype.formatIso = function (marker, extraOptions) { + if (extraOptions === void 0) { extraOptions = {}; } + var timeZoneOffset = null; + if (!extraOptions.omitTimeZoneOffset) { + if (extraOptions.forcedTzo != null) { + timeZoneOffset = extraOptions.forcedTzo; + } + else { + timeZoneOffset = this.offsetForMarker(marker); + } + } + return buildIsoString(marker, timeZoneOffset, extraOptions.omitTime); + }; + // TimeZone + DateEnv.prototype.timestampToMarker = function (ms) { + if (this.timeZone === 'local') { + return arrayToUtcDate(dateToLocalArray(new Date(ms))); + } + if (this.timeZone === 'UTC' || !this.namedTimeZoneImpl) { + return new Date(ms); + } + return arrayToUtcDate(this.namedTimeZoneImpl.timestampToArray(ms)); + }; + DateEnv.prototype.offsetForMarker = function (m) { + if (this.timeZone === 'local') { + return -arrayToLocalDate(dateToUtcArray(m)).getTimezoneOffset(); // convert "inverse" offset to "normal" offset + } + if (this.timeZone === 'UTC') { + return 0; + } + if (this.namedTimeZoneImpl) { + return this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m)); + } + return null; + }; + // Conversion + DateEnv.prototype.toDate = function (m, forcedTzo) { + if (this.timeZone === 'local') { + return arrayToLocalDate(dateToUtcArray(m)); + } + if (this.timeZone === 'UTC') { + return new Date(m.valueOf()); // make sure it's a copy + } + if (!this.namedTimeZoneImpl) { + return new Date(m.valueOf() - (forcedTzo || 0)); + } + return new Date(m.valueOf() - + this.namedTimeZoneImpl.offsetForArray(dateToUtcArray(m)) * 1000 * 60); + }; + return DateEnv; + }()); + + var globalLocales = []; + + var RAW_EN_LOCALE = { + code: 'en', + week: { + dow: 0, + doy: 4, // 4 days need to be within the year to be considered the first week + }, + direction: 'ltr', + buttonText: { + prev: 'prev', + next: 'next', + prevYear: 'prev year', + nextYear: 'next year', + year: 'year', + today: 'today', + month: 'month', + week: 'week', + day: 'day', + list: 'list', + }, + weekText: 'W', + allDayText: 'all-day', + moreLinkText: 'more', + noEventsText: 'No events to display', + }; + function organizeRawLocales(explicitRawLocales) { + var defaultCode = explicitRawLocales.length > 0 ? explicitRawLocales[0].code : 'en'; + var allRawLocales = globalLocales.concat(explicitRawLocales); + var rawLocaleMap = { + en: RAW_EN_LOCALE, // necessary? + }; + for (var _i = 0, allRawLocales_1 = allRawLocales; _i < allRawLocales_1.length; _i++) { + var rawLocale = allRawLocales_1[_i]; + rawLocaleMap[rawLocale.code] = rawLocale; + } + return { + map: rawLocaleMap, + defaultCode: defaultCode, + }; + } + function buildLocale(inputSingular, available) { + if (typeof inputSingular === 'object' && !Array.isArray(inputSingular)) { + return parseLocale(inputSingular.code, [inputSingular.code], inputSingular); + } + return queryLocale(inputSingular, available); + } + function queryLocale(codeArg, available) { + var codes = [].concat(codeArg || []); // will convert to array + var raw = queryRawLocale(codes, available) || RAW_EN_LOCALE; + return parseLocale(codeArg, codes, raw); + } + function queryRawLocale(codes, available) { + for (var i = 0; i < codes.length; i += 1) { + var parts = codes[i].toLocaleLowerCase().split('-'); + for (var j = parts.length; j > 0; j -= 1) { + var simpleId = parts.slice(0, j).join('-'); + if (available[simpleId]) { + return available[simpleId]; + } + } + } + return null; + } + function parseLocale(codeArg, codes, raw) { + var merged = mergeProps([RAW_EN_LOCALE, raw], ['buttonText']); + delete merged.code; // don't want this part of the options + var week = merged.week; + delete merged.week; + return { + codeArg: codeArg, + codes: codes, + week: week, + simpleNumberFormat: new Intl.NumberFormat(codeArg), + options: merged, + }; + } + + function formatDate(dateInput, options) { + if (options === void 0) { options = {}; } + var dateEnv = buildDateEnv$1(options); + var formatter = createFormatter(options); + var dateMeta = dateEnv.createMarkerMeta(dateInput); + if (!dateMeta) { // TODO: warning? + return ''; + } + return dateEnv.format(dateMeta.marker, formatter, { + forcedTzo: dateMeta.forcedTzo, + }); + } + function formatRange(startInput, endInput, options) { + var dateEnv = buildDateEnv$1(typeof options === 'object' && options ? options : {}); // pass in if non-null object + var formatter = createFormatter(options); + var startMeta = dateEnv.createMarkerMeta(startInput); + var endMeta = dateEnv.createMarkerMeta(endInput); + if (!startMeta || !endMeta) { // TODO: warning? + return ''; + } + return dateEnv.formatRange(startMeta.marker, endMeta.marker, formatter, { + forcedStartTzo: startMeta.forcedTzo, + forcedEndTzo: endMeta.forcedTzo, + isEndExclusive: options.isEndExclusive, + defaultSeparator: BASE_OPTION_DEFAULTS.defaultRangeSeparator, + }); + } + // TODO: more DRY and optimized + function buildDateEnv$1(settings) { + var locale = buildLocale(settings.locale || 'en', organizeRawLocales([]).map); // TODO: don't hardcode 'en' everywhere + return new DateEnv(__assign(__assign({ timeZone: BASE_OPTION_DEFAULTS.timeZone, calendarSystem: 'gregory' }, settings), { locale: locale })); + } + + var DEF_DEFAULTS = { + startTime: '09:00', + endTime: '17:00', + daysOfWeek: [1, 2, 3, 4, 5], + display: 'inverse-background', + classNames: 'fc-non-business', + groupId: '_businessHours', // so multiple defs get grouped + }; + /* + TODO: pass around as EventDefHash!!! + */ + function parseBusinessHours(input, context) { + return parseEvents(refineInputs(input), null, context); + } + function refineInputs(input) { + var rawDefs; + if (input === true) { + rawDefs = [{}]; // will get DEF_DEFAULTS verbatim + } + else if (Array.isArray(input)) { + // if specifying an array, every sub-definition NEEDS a day-of-week + rawDefs = input.filter(function (rawDef) { return rawDef.daysOfWeek; }); + } + else if (typeof input === 'object' && input) { // non-null object + rawDefs = [input]; + } + else { // is probably false + rawDefs = []; + } + rawDefs = rawDefs.map(function (rawDef) { return (__assign(__assign({}, DEF_DEFAULTS), rawDef)); }); + return rawDefs; + } + + function pointInsideRect(point, rect) { + return point.left >= rect.left && + point.left < rect.right && + point.top >= rect.top && + point.top < rect.bottom; + } + // Returns a new rectangle that is the intersection of the two rectangles. If they don't intersect, returns false + function intersectRects(rect1, rect2) { + var res = { + left: Math.max(rect1.left, rect2.left), + right: Math.min(rect1.right, rect2.right), + top: Math.max(rect1.top, rect2.top), + bottom: Math.min(rect1.bottom, rect2.bottom), + }; + if (res.left < res.right && res.top < res.bottom) { + return res; + } + return false; + } + function translateRect(rect, deltaX, deltaY) { + return { + left: rect.left + deltaX, + right: rect.right + deltaX, + top: rect.top + deltaY, + bottom: rect.bottom + deltaY, + }; + } + // Returns a new point that will have been moved to reside within the given rectangle + function constrainPoint(point, rect) { + return { + left: Math.min(Math.max(point.left, rect.left), rect.right), + top: Math.min(Math.max(point.top, rect.top), rect.bottom), + }; + } + // Returns a point that is the center of the given rectangle + function getRectCenter(rect) { + return { + left: (rect.left + rect.right) / 2, + top: (rect.top + rect.bottom) / 2, + }; + } + // Subtracts point2's coordinates from point1's coordinates, returning a delta + function diffPoints(point1, point2) { + return { + left: point1.left - point2.left, + top: point1.top - point2.top, + }; + } + + var canVGrowWithinCell; + function getCanVGrowWithinCell() { + if (canVGrowWithinCell == null) { + canVGrowWithinCell = computeCanVGrowWithinCell(); + } + return canVGrowWithinCell; + } + function computeCanVGrowWithinCell() { + // for SSR, because this function is call immediately at top-level + // TODO: just make this logic execute top-level, immediately, instead of doing lazily + if (typeof document === 'undefined') { + return true; + } + var el = document.createElement('div'); + el.style.position = 'absolute'; + el.style.top = '0px'; + el.style.left = '0px'; + el.innerHTML = '
'; + el.querySelector('table').style.height = '100px'; + el.querySelector('div').style.height = '100%'; + document.body.appendChild(el); + var div = el.querySelector('div'); + var possible = div.offsetHeight > 0; + document.body.removeChild(el); + return possible; + } + + var EMPTY_EVENT_STORE = createEmptyEventStore(); // for purecomponents. TODO: keep elsewhere + var Splitter = /** @class */ (function () { + function Splitter() { + this.getKeysForEventDefs = memoize(this._getKeysForEventDefs); + this.splitDateSelection = memoize(this._splitDateSpan); + this.splitEventStore = memoize(this._splitEventStore); + this.splitIndividualUi = memoize(this._splitIndividualUi); + this.splitEventDrag = memoize(this._splitInteraction); + this.splitEventResize = memoize(this._splitInteraction); + this.eventUiBuilders = {}; // TODO: typescript protection + } + Splitter.prototype.splitProps = function (props) { + var _this = this; + var keyInfos = this.getKeyInfo(props); + var defKeys = this.getKeysForEventDefs(props.eventStore); + var dateSelections = this.splitDateSelection(props.dateSelection); + var individualUi = this.splitIndividualUi(props.eventUiBases, defKeys); // the individual *bases* + var eventStores = this.splitEventStore(props.eventStore, defKeys); + var eventDrags = this.splitEventDrag(props.eventDrag); + var eventResizes = this.splitEventResize(props.eventResize); + var splitProps = {}; + this.eventUiBuilders = mapHash(keyInfos, function (info, key) { return _this.eventUiBuilders[key] || memoize(buildEventUiForKey); }); + for (var key in keyInfos) { + var keyInfo = keyInfos[key]; + var eventStore = eventStores[key] || EMPTY_EVENT_STORE; + var buildEventUi = this.eventUiBuilders[key]; + splitProps[key] = { + businessHours: keyInfo.businessHours || props.businessHours, + dateSelection: dateSelections[key] || null, + eventStore: eventStore, + eventUiBases: buildEventUi(props.eventUiBases[''], keyInfo.ui, individualUi[key]), + eventSelection: eventStore.instances[props.eventSelection] ? props.eventSelection : '', + eventDrag: eventDrags[key] || null, + eventResize: eventResizes[key] || null, + }; + } + return splitProps; + }; + Splitter.prototype._splitDateSpan = function (dateSpan) { + var dateSpans = {}; + if (dateSpan) { + var keys = this.getKeysForDateSpan(dateSpan); + for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) { + var key = keys_1[_i]; + dateSpans[key] = dateSpan; + } + } + return dateSpans; + }; + Splitter.prototype._getKeysForEventDefs = function (eventStore) { + var _this = this; + return mapHash(eventStore.defs, function (eventDef) { return _this.getKeysForEventDef(eventDef); }); + }; + Splitter.prototype._splitEventStore = function (eventStore, defKeys) { + var defs = eventStore.defs, instances = eventStore.instances; + var splitStores = {}; + for (var defId in defs) { + for (var _i = 0, _a = defKeys[defId]; _i < _a.length; _i++) { + var key = _a[_i]; + if (!splitStores[key]) { + splitStores[key] = createEmptyEventStore(); + } + splitStores[key].defs[defId] = defs[defId]; + } + } + for (var instanceId in instances) { + var instance = instances[instanceId]; + for (var _b = 0, _c = defKeys[instance.defId]; _b < _c.length; _b++) { + var key = _c[_b]; + if (splitStores[key]) { // must have already been created + splitStores[key].instances[instanceId] = instance; + } + } + } + return splitStores; + }; + Splitter.prototype._splitIndividualUi = function (eventUiBases, defKeys) { + var splitHashes = {}; + for (var defId in eventUiBases) { + if (defId) { // not the '' key + for (var _i = 0, _a = defKeys[defId]; _i < _a.length; _i++) { + var key = _a[_i]; + if (!splitHashes[key]) { + splitHashes[key] = {}; + } + splitHashes[key][defId] = eventUiBases[defId]; + } + } + } + return splitHashes; + }; + Splitter.prototype._splitInteraction = function (interaction) { + var splitStates = {}; + if (interaction) { + var affectedStores_1 = this._splitEventStore(interaction.affectedEvents, this._getKeysForEventDefs(interaction.affectedEvents)); + // can't rely on defKeys because event data is mutated + var mutatedKeysByDefId = this._getKeysForEventDefs(interaction.mutatedEvents); + var mutatedStores_1 = this._splitEventStore(interaction.mutatedEvents, mutatedKeysByDefId); + var populate = function (key) { + if (!splitStates[key]) { + splitStates[key] = { + affectedEvents: affectedStores_1[key] || EMPTY_EVENT_STORE, + mutatedEvents: mutatedStores_1[key] || EMPTY_EVENT_STORE, + isEvent: interaction.isEvent, + }; + } + }; + for (var key in affectedStores_1) { + populate(key); + } + for (var key in mutatedStores_1) { + populate(key); + } + } + return splitStates; + }; + return Splitter; + }()); + function buildEventUiForKey(allUi, eventUiForKey, individualUi) { + var baseParts = []; + if (allUi) { + baseParts.push(allUi); + } + if (eventUiForKey) { + baseParts.push(eventUiForKey); + } + var stuff = { + '': combineEventUis(baseParts), + }; + if (individualUi) { + __assign(stuff, individualUi); + } + return stuff; + } + + function getDateMeta(date, todayRange, nowDate, dateProfile) { + return { + dow: date.getUTCDay(), + isDisabled: Boolean(dateProfile && !rangeContainsMarker(dateProfile.activeRange, date)), + isOther: Boolean(dateProfile && !rangeContainsMarker(dateProfile.currentRange, date)), + isToday: Boolean(todayRange && rangeContainsMarker(todayRange, date)), + isPast: Boolean(nowDate ? (date < nowDate) : todayRange ? (date < todayRange.start) : false), + isFuture: Boolean(nowDate ? (date > nowDate) : todayRange ? (date >= todayRange.end) : false), + }; + } + function getDayClassNames(meta, theme) { + var classNames = [ + 'fc-day', + "fc-day-" + DAY_IDS[meta.dow], + ]; + if (meta.isDisabled) { + classNames.push('fc-day-disabled'); + } + else { + if (meta.isToday) { + classNames.push('fc-day-today'); + classNames.push(theme.getClass('today')); + } + if (meta.isPast) { + classNames.push('fc-day-past'); + } + if (meta.isFuture) { + classNames.push('fc-day-future'); + } + if (meta.isOther) { + classNames.push('fc-day-other'); + } + } + return classNames; + } + function getSlotClassNames(meta, theme) { + var classNames = [ + 'fc-slot', + "fc-slot-" + DAY_IDS[meta.dow], + ]; + if (meta.isDisabled) { + classNames.push('fc-slot-disabled'); + } + else { + if (meta.isToday) { + classNames.push('fc-slot-today'); + classNames.push(theme.getClass('today')); + } + if (meta.isPast) { + classNames.push('fc-slot-past'); + } + if (meta.isFuture) { + classNames.push('fc-slot-future'); + } + } + return classNames; + } + + function buildNavLinkData(date, type) { + if (type === void 0) { type = 'day'; } + return JSON.stringify({ + date: formatDayString(date), + type: type, + }); + } + + var _isRtlScrollbarOnLeft = null; + function getIsRtlScrollbarOnLeft() { + if (_isRtlScrollbarOnLeft === null) { + _isRtlScrollbarOnLeft = computeIsRtlScrollbarOnLeft(); + } + return _isRtlScrollbarOnLeft; + } + function computeIsRtlScrollbarOnLeft() { + var outerEl = document.createElement('div'); + applyStyle(outerEl, { + position: 'absolute', + top: -1000, + left: 0, + border: 0, + padding: 0, + overflow: 'scroll', + direction: 'rtl', + }); + outerEl.innerHTML = '
'; + document.body.appendChild(outerEl); + var innerEl = outerEl.firstChild; + var res = innerEl.getBoundingClientRect().left > outerEl.getBoundingClientRect().left; + removeElement(outerEl); + return res; + } + + var _scrollbarWidths; + function getScrollbarWidths() { + if (!_scrollbarWidths) { + _scrollbarWidths = computeScrollbarWidths(); + } + return _scrollbarWidths; + } + function computeScrollbarWidths() { + var el = document.createElement('div'); + el.style.overflow = 'scroll'; + el.style.position = 'absolute'; + el.style.top = '-9999px'; + el.style.left = '-9999px'; + document.body.appendChild(el); + var res = computeScrollbarWidthsForEl(el); + document.body.removeChild(el); + return res; + } + // WARNING: will include border + function computeScrollbarWidthsForEl(el) { + return { + x: el.offsetHeight - el.clientHeight, + y: el.offsetWidth - el.clientWidth, + }; + } + + function computeEdges(el, getPadding) { + if (getPadding === void 0) { getPadding = false; } + var computedStyle = window.getComputedStyle(el); + var borderLeft = parseInt(computedStyle.borderLeftWidth, 10) || 0; + var borderRight = parseInt(computedStyle.borderRightWidth, 10) || 0; + var borderTop = parseInt(computedStyle.borderTopWidth, 10) || 0; + var borderBottom = parseInt(computedStyle.borderBottomWidth, 10) || 0; + var badScrollbarWidths = computeScrollbarWidthsForEl(el); // includes border! + var scrollbarLeftRight = badScrollbarWidths.y - borderLeft - borderRight; + var scrollbarBottom = badScrollbarWidths.x - borderTop - borderBottom; + var res = { + borderLeft: borderLeft, + borderRight: borderRight, + borderTop: borderTop, + borderBottom: borderBottom, + scrollbarBottom: scrollbarBottom, + scrollbarLeft: 0, + scrollbarRight: 0, + }; + if (getIsRtlScrollbarOnLeft() && computedStyle.direction === 'rtl') { // is the scrollbar on the left side? + res.scrollbarLeft = scrollbarLeftRight; + } + else { + res.scrollbarRight = scrollbarLeftRight; + } + if (getPadding) { + res.paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0; + res.paddingRight = parseInt(computedStyle.paddingRight, 10) || 0; + res.paddingTop = parseInt(computedStyle.paddingTop, 10) || 0; + res.paddingBottom = parseInt(computedStyle.paddingBottom, 10) || 0; + } + return res; + } + function computeInnerRect(el, goWithinPadding, doFromWindowViewport) { + if (goWithinPadding === void 0) { goWithinPadding = false; } + var outerRect = doFromWindowViewport ? el.getBoundingClientRect() : computeRect(el); + var edges = computeEdges(el, goWithinPadding); + var res = { + left: outerRect.left + edges.borderLeft + edges.scrollbarLeft, + right: outerRect.right - edges.borderRight - edges.scrollbarRight, + top: outerRect.top + edges.borderTop, + bottom: outerRect.bottom - edges.borderBottom - edges.scrollbarBottom, + }; + if (goWithinPadding) { + res.left += edges.paddingLeft; + res.right -= edges.paddingRight; + res.top += edges.paddingTop; + res.bottom -= edges.paddingBottom; + } + return res; + } + function computeRect(el) { + var rect = el.getBoundingClientRect(); + return { + left: rect.left + window.pageXOffset, + top: rect.top + window.pageYOffset, + right: rect.right + window.pageXOffset, + bottom: rect.bottom + window.pageYOffset, + }; + } + function computeClippedClientRect(el) { + var clippingParents = getClippingParents(el); + var rect = el.getBoundingClientRect(); + for (var _i = 0, clippingParents_1 = clippingParents; _i < clippingParents_1.length; _i++) { + var clippingParent = clippingParents_1[_i]; + var intersection = intersectRects(rect, clippingParent.getBoundingClientRect()); + if (intersection) { + rect = intersection; + } + else { + return null; + } + } + return rect; + } + function computeHeightAndMargins(el) { + return el.getBoundingClientRect().height + computeVMargins(el); + } + function computeVMargins(el) { + var computed = window.getComputedStyle(el); + return parseInt(computed.marginTop, 10) + + parseInt(computed.marginBottom, 10); + } + // does not return window + function getClippingParents(el) { + var parents = []; + while (el instanceof HTMLElement) { // will stop when gets to document or null + var computedStyle = window.getComputedStyle(el); + if (computedStyle.position === 'fixed') { + break; + } + if ((/(auto|scroll)/).test(computedStyle.overflow + computedStyle.overflowY + computedStyle.overflowX)) { + parents.push(el); + } + el = el.parentNode; + } + return parents; + } + + // given a function that resolves a result asynchronously. + // the function can either call passed-in success and failure callbacks, + // or it can return a promise. + // if you need to pass additional params to func, bind them first. + function unpromisify(func, success, failure) { + // guard against success/failure callbacks being called more than once + // and guard against a promise AND callback being used together. + var isResolved = false; + var wrappedSuccess = function () { + if (!isResolved) { + isResolved = true; + success.apply(this, arguments); // eslint-disable-line prefer-rest-params + } + }; + var wrappedFailure = function () { + if (!isResolved) { + isResolved = true; + if (failure) { + failure.apply(this, arguments); // eslint-disable-line prefer-rest-params + } + } + }; + var res = func(wrappedSuccess, wrappedFailure); + if (res && typeof res.then === 'function') { + res.then(wrappedSuccess, wrappedFailure); + } + } + + var Emitter = /** @class */ (function () { + function Emitter() { + this.handlers = {}; + this.thisContext = null; + } + Emitter.prototype.setThisContext = function (thisContext) { + this.thisContext = thisContext; + }; + Emitter.prototype.setOptions = function (options) { + this.options = options; + }; + Emitter.prototype.on = function (type, handler) { + addToHash(this.handlers, type, handler); + }; + Emitter.prototype.off = function (type, handler) { + removeFromHash(this.handlers, type, handler); + }; + Emitter.prototype.trigger = function (type) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + var attachedHandlers = this.handlers[type] || []; + var optionHandler = this.options && this.options[type]; + var handlers = [].concat(optionHandler || [], attachedHandlers); + for (var _a = 0, handlers_1 = handlers; _a < handlers_1.length; _a++) { + var handler = handlers_1[_a]; + handler.apply(this.thisContext, args); + } + }; + Emitter.prototype.hasHandlers = function (type) { + return (this.handlers[type] && this.handlers[type].length) || + (this.options && this.options[type]); + }; + return Emitter; + }()); + function addToHash(hash, type, handler) { + (hash[type] || (hash[type] = [])) + .push(handler); + } + function removeFromHash(hash, type, handler) { + if (handler) { + if (hash[type]) { + hash[type] = hash[type].filter(function (func) { return func !== handler; }); + } + } + else { + delete hash[type]; // remove all handler funcs for this type + } + } + + /* + Records offset information for a set of elements, relative to an origin element. + Can record the left/right OR the top/bottom OR both. + Provides methods for querying the cache by position. + */ + var PositionCache = /** @class */ (function () { + function PositionCache(originEl, els, isHorizontal, isVertical) { + this.els = els; + var originClientRect = this.originClientRect = originEl.getBoundingClientRect(); // relative to viewport top-left + if (isHorizontal) { + this.buildElHorizontals(originClientRect.left); + } + if (isVertical) { + this.buildElVerticals(originClientRect.top); + } + } + // Populates the left/right internal coordinate arrays + PositionCache.prototype.buildElHorizontals = function (originClientLeft) { + var lefts = []; + var rights = []; + for (var _i = 0, _a = this.els; _i < _a.length; _i++) { + var el = _a[_i]; + var rect = el.getBoundingClientRect(); + lefts.push(rect.left - originClientLeft); + rights.push(rect.right - originClientLeft); + } + this.lefts = lefts; + this.rights = rights; + }; + // Populates the top/bottom internal coordinate arrays + PositionCache.prototype.buildElVerticals = function (originClientTop) { + var tops = []; + var bottoms = []; + for (var _i = 0, _a = this.els; _i < _a.length; _i++) { + var el = _a[_i]; + var rect = el.getBoundingClientRect(); + tops.push(rect.top - originClientTop); + bottoms.push(rect.bottom - originClientTop); + } + this.tops = tops; + this.bottoms = bottoms; + }; + // Given a left offset (from document left), returns the index of the el that it horizontally intersects. + // If no intersection is made, returns undefined. + PositionCache.prototype.leftToIndex = function (leftPosition) { + var _a = this, lefts = _a.lefts, rights = _a.rights; + var len = lefts.length; + var i; + for (i = 0; i < len; i += 1) { + if (leftPosition >= lefts[i] && leftPosition < rights[i]) { + return i; + } + } + return undefined; // TODO: better + }; + // Given a top offset (from document top), returns the index of the el that it vertically intersects. + // If no intersection is made, returns undefined. + PositionCache.prototype.topToIndex = function (topPosition) { + var _a = this, tops = _a.tops, bottoms = _a.bottoms; + var len = tops.length; + var i; + for (i = 0; i < len; i += 1) { + if (topPosition >= tops[i] && topPosition < bottoms[i]) { + return i; + } + } + return undefined; // TODO: better + }; + // Gets the width of the element at the given index + PositionCache.prototype.getWidth = function (leftIndex) { + return this.rights[leftIndex] - this.lefts[leftIndex]; + }; + // Gets the height of the element at the given index + PositionCache.prototype.getHeight = function (topIndex) { + return this.bottoms[topIndex] - this.tops[topIndex]; + }; + return PositionCache; + }()); + + /* eslint max-classes-per-file: "off" */ + /* + An object for getting/setting scroll-related information for an element. + Internally, this is done very differently for window versus DOM element, + so this object serves as a common interface. + */ + var ScrollController = /** @class */ (function () { + function ScrollController() { + } + ScrollController.prototype.getMaxScrollTop = function () { + return this.getScrollHeight() - this.getClientHeight(); + }; + ScrollController.prototype.getMaxScrollLeft = function () { + return this.getScrollWidth() - this.getClientWidth(); + }; + ScrollController.prototype.canScrollVertically = function () { + return this.getMaxScrollTop() > 0; + }; + ScrollController.prototype.canScrollHorizontally = function () { + return this.getMaxScrollLeft() > 0; + }; + ScrollController.prototype.canScrollUp = function () { + return this.getScrollTop() > 0; + }; + ScrollController.prototype.canScrollDown = function () { + return this.getScrollTop() < this.getMaxScrollTop(); + }; + ScrollController.prototype.canScrollLeft = function () { + return this.getScrollLeft() > 0; + }; + ScrollController.prototype.canScrollRight = function () { + return this.getScrollLeft() < this.getMaxScrollLeft(); + }; + return ScrollController; + }()); + var ElementScrollController = /** @class */ (function (_super) { + __extends(ElementScrollController, _super); + function ElementScrollController(el) { + var _this = _super.call(this) || this; + _this.el = el; + return _this; + } + ElementScrollController.prototype.getScrollTop = function () { + return this.el.scrollTop; + }; + ElementScrollController.prototype.getScrollLeft = function () { + return this.el.scrollLeft; + }; + ElementScrollController.prototype.setScrollTop = function (top) { + this.el.scrollTop = top; + }; + ElementScrollController.prototype.setScrollLeft = function (left) { + this.el.scrollLeft = left; + }; + ElementScrollController.prototype.getScrollWidth = function () { + return this.el.scrollWidth; + }; + ElementScrollController.prototype.getScrollHeight = function () { + return this.el.scrollHeight; + }; + ElementScrollController.prototype.getClientHeight = function () { + return this.el.clientHeight; + }; + ElementScrollController.prototype.getClientWidth = function () { + return this.el.clientWidth; + }; + return ElementScrollController; + }(ScrollController)); + var WindowScrollController = /** @class */ (function (_super) { + __extends(WindowScrollController, _super); + function WindowScrollController() { + return _super !== null && _super.apply(this, arguments) || this; + } + WindowScrollController.prototype.getScrollTop = function () { + return window.pageYOffset; + }; + WindowScrollController.prototype.getScrollLeft = function () { + return window.pageXOffset; + }; + WindowScrollController.prototype.setScrollTop = function (n) { + window.scroll(window.pageXOffset, n); + }; + WindowScrollController.prototype.setScrollLeft = function (n) { + window.scroll(n, window.pageYOffset); + }; + WindowScrollController.prototype.getScrollWidth = function () { + return document.documentElement.scrollWidth; + }; + WindowScrollController.prototype.getScrollHeight = function () { + return document.documentElement.scrollHeight; + }; + WindowScrollController.prototype.getClientHeight = function () { + return document.documentElement.clientHeight; + }; + WindowScrollController.prototype.getClientWidth = function () { + return document.documentElement.clientWidth; + }; + return WindowScrollController; + }(ScrollController)); + + var Theme = /** @class */ (function () { + function Theme(calendarOptions) { + if (this.iconOverrideOption) { + this.setIconOverride(calendarOptions[this.iconOverrideOption]); + } + } + Theme.prototype.setIconOverride = function (iconOverrideHash) { + var iconClassesCopy; + var buttonName; + if (typeof iconOverrideHash === 'object' && iconOverrideHash) { // non-null object + iconClassesCopy = __assign({}, this.iconClasses); + for (buttonName in iconOverrideHash) { + iconClassesCopy[buttonName] = this.applyIconOverridePrefix(iconOverrideHash[buttonName]); + } + this.iconClasses = iconClassesCopy; + } + else if (iconOverrideHash === false) { + this.iconClasses = {}; + } + }; + Theme.prototype.applyIconOverridePrefix = function (className) { + var prefix = this.iconOverridePrefix; + if (prefix && className.indexOf(prefix) !== 0) { // if not already present + className = prefix + className; + } + return className; + }; + Theme.prototype.getClass = function (key) { + return this.classes[key] || ''; + }; + Theme.prototype.getIconClass = function (buttonName, isRtl) { + var className; + if (isRtl && this.rtlIconClasses) { + className = this.rtlIconClasses[buttonName] || this.iconClasses[buttonName]; + } + else { + className = this.iconClasses[buttonName]; + } + if (className) { + return this.baseIconClass + " " + className; + } + return ''; + }; + Theme.prototype.getCustomButtonIconClass = function (customButtonProps) { + var className; + if (this.iconOverrideCustomButtonOption) { + className = customButtonProps[this.iconOverrideCustomButtonOption]; + if (className) { + return this.baseIconClass + " " + this.applyIconOverridePrefix(className); + } + } + return ''; + }; + return Theme; + }()); + Theme.prototype.classes = {}; + Theme.prototype.iconClasses = {}; + Theme.prototype.baseIconClass = ''; + Theme.prototype.iconOverridePrefix = ''; + + /// + if (typeof FullCalendarVDom === 'undefined') { + throw new Error('Please import the top-level fullcalendar lib before attempting to import a plugin.'); + } + var Component = FullCalendarVDom.Component; + var createElement = FullCalendarVDom.createElement; + var render = FullCalendarVDom.render; + var createRef = FullCalendarVDom.createRef; + var Fragment = FullCalendarVDom.Fragment; + var createContext = FullCalendarVDom.createContext; + var createPortal = FullCalendarVDom.createPortal; + var flushToDom = FullCalendarVDom.flushToDom; + var unmountComponentAtNode = FullCalendarVDom.unmountComponentAtNode; + /* eslint-enable */ + + var ScrollResponder = /** @class */ (function () { + function ScrollResponder(execFunc, emitter, scrollTime, scrollTimeReset) { + var _this = this; + this.execFunc = execFunc; + this.emitter = emitter; + this.scrollTime = scrollTime; + this.scrollTimeReset = scrollTimeReset; + this.handleScrollRequest = function (request) { + _this.queuedRequest = __assign({}, _this.queuedRequest || {}, request); + _this.drain(); + }; + emitter.on('_scrollRequest', this.handleScrollRequest); + this.fireInitialScroll(); + } + ScrollResponder.prototype.detach = function () { + this.emitter.off('_scrollRequest', this.handleScrollRequest); + }; + ScrollResponder.prototype.update = function (isDatesNew) { + if (isDatesNew && this.scrollTimeReset) { + this.fireInitialScroll(); // will drain + } + else { + this.drain(); + } + }; + ScrollResponder.prototype.fireInitialScroll = function () { + this.handleScrollRequest({ + time: this.scrollTime, + }); + }; + ScrollResponder.prototype.drain = function () { + if (this.queuedRequest && this.execFunc(this.queuedRequest)) { + this.queuedRequest = null; + } + }; + return ScrollResponder; + }()); + + var ViewContextType = createContext({}); // for Components + function buildViewContext(viewSpec, viewApi, viewOptions, dateProfileGenerator, dateEnv, theme, pluginHooks, dispatch, getCurrentData, emitter, calendarApi, registerInteractiveComponent, unregisterInteractiveComponent) { + return { + dateEnv: dateEnv, + options: viewOptions, + pluginHooks: pluginHooks, + emitter: emitter, + dispatch: dispatch, + getCurrentData: getCurrentData, + calendarApi: calendarApi, + viewSpec: viewSpec, + viewApi: viewApi, + dateProfileGenerator: dateProfileGenerator, + theme: theme, + isRtl: viewOptions.direction === 'rtl', + addResizeHandler: function (handler) { + emitter.on('_resize', handler); + }, + removeResizeHandler: function (handler) { + emitter.off('_resize', handler); + }, + createScrollResponder: function (execFunc) { + return new ScrollResponder(execFunc, emitter, createDuration(viewOptions.scrollTime), viewOptions.scrollTimeReset); + }, + registerInteractiveComponent: registerInteractiveComponent, + unregisterInteractiveComponent: unregisterInteractiveComponent, + }; + } + + /* eslint max-classes-per-file: off */ + var PureComponent = /** @class */ (function (_super) { + __extends(PureComponent, _super); + function PureComponent() { + return _super !== null && _super.apply(this, arguments) || this; + } + PureComponent.prototype.shouldComponentUpdate = function (nextProps, nextState) { + if (this.debug) { + // eslint-disable-next-line no-console + console.log(getUnequalProps(nextProps, this.props), getUnequalProps(nextState, this.state)); + } + return !compareObjs(this.props, nextProps, this.propEquality) || + !compareObjs(this.state, nextState, this.stateEquality); + }; + PureComponent.addPropsEquality = addPropsEquality; + PureComponent.addStateEquality = addStateEquality; + PureComponent.contextType = ViewContextType; + return PureComponent; + }(Component)); + PureComponent.prototype.propEquality = {}; + PureComponent.prototype.stateEquality = {}; + var BaseComponent = /** @class */ (function (_super) { + __extends(BaseComponent, _super); + function BaseComponent() { + return _super !== null && _super.apply(this, arguments) || this; + } + BaseComponent.contextType = ViewContextType; + return BaseComponent; + }(PureComponent)); + function addPropsEquality(propEquality) { + var hash = Object.create(this.prototype.propEquality); + __assign(hash, propEquality); + this.prototype.propEquality = hash; + } + function addStateEquality(stateEquality) { + var hash = Object.create(this.prototype.stateEquality); + __assign(hash, stateEquality); + this.prototype.stateEquality = hash; + } + // use other one + function setRef(ref, current) { + if (typeof ref === 'function') { + ref(current); + } + else if (ref) { + // see https://github.com/facebook/react/issues/13029 + ref.current = current; + } + } + + /* + an INTERACTABLE date component + + PURPOSES: + - hook up to fg, fill, and mirror renderers + - interface for dragging and hits + */ + var DateComponent = /** @class */ (function (_super) { + __extends(DateComponent, _super); + function DateComponent() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.uid = guid(); + return _this; + } + // Hit System + // ----------------------------------------------------------------------------------------------------------------- + DateComponent.prototype.prepareHits = function () { + }; + DateComponent.prototype.queryHit = function (positionLeft, positionTop, elWidth, elHeight) { + return null; // this should be abstract + }; + // Pointer Interaction Utils + // ----------------------------------------------------------------------------------------------------------------- + DateComponent.prototype.isValidSegDownEl = function (el) { + return !this.props.eventDrag && // HACK + !this.props.eventResize && // HACK + !elementClosest(el, '.fc-event-mirror'); + }; + DateComponent.prototype.isValidDateDownEl = function (el) { + return !elementClosest(el, '.fc-event:not(.fc-bg-event)') && + !elementClosest(el, '.fc-more-link') && // a "more.." link + !elementClosest(el, 'a[data-navlink]') && // a clickable nav link + !elementClosest(el, '.fc-popover'); // hack + }; + return DateComponent; + }(BaseComponent)); + + // TODO: easier way to add new hooks? need to update a million things + function createPlugin(input) { + return { + id: guid(), + deps: input.deps || [], + reducers: input.reducers || [], + isLoadingFuncs: input.isLoadingFuncs || [], + contextInit: [].concat(input.contextInit || []), + eventRefiners: input.eventRefiners || {}, + eventDefMemberAdders: input.eventDefMemberAdders || [], + eventSourceRefiners: input.eventSourceRefiners || {}, + isDraggableTransformers: input.isDraggableTransformers || [], + eventDragMutationMassagers: input.eventDragMutationMassagers || [], + eventDefMutationAppliers: input.eventDefMutationAppliers || [], + dateSelectionTransformers: input.dateSelectionTransformers || [], + datePointTransforms: input.datePointTransforms || [], + dateSpanTransforms: input.dateSpanTransforms || [], + views: input.views || {}, + viewPropsTransformers: input.viewPropsTransformers || [], + isPropsValid: input.isPropsValid || null, + externalDefTransforms: input.externalDefTransforms || [], + viewContainerAppends: input.viewContainerAppends || [], + eventDropTransformers: input.eventDropTransformers || [], + componentInteractions: input.componentInteractions || [], + calendarInteractions: input.calendarInteractions || [], + themeClasses: input.themeClasses || {}, + eventSourceDefs: input.eventSourceDefs || [], + cmdFormatter: input.cmdFormatter, + recurringTypes: input.recurringTypes || [], + namedTimeZonedImpl: input.namedTimeZonedImpl, + initialView: input.initialView || '', + elementDraggingImpl: input.elementDraggingImpl, + optionChangeHandlers: input.optionChangeHandlers || {}, + scrollGridImpl: input.scrollGridImpl || null, + contentTypeHandlers: input.contentTypeHandlers || {}, + listenerRefiners: input.listenerRefiners || {}, + optionRefiners: input.optionRefiners || {}, + propSetHandlers: input.propSetHandlers || {}, + }; + } + function buildPluginHooks(pluginDefs, globalDefs) { + var isAdded = {}; + var hooks = { + reducers: [], + isLoadingFuncs: [], + contextInit: [], + eventRefiners: {}, + eventDefMemberAdders: [], + eventSourceRefiners: {}, + isDraggableTransformers: [], + eventDragMutationMassagers: [], + eventDefMutationAppliers: [], + dateSelectionTransformers: [], + datePointTransforms: [], + dateSpanTransforms: [], + views: {}, + viewPropsTransformers: [], + isPropsValid: null, + externalDefTransforms: [], + viewContainerAppends: [], + eventDropTransformers: [], + componentInteractions: [], + calendarInteractions: [], + themeClasses: {}, + eventSourceDefs: [], + cmdFormatter: null, + recurringTypes: [], + namedTimeZonedImpl: null, + initialView: '', + elementDraggingImpl: null, + optionChangeHandlers: {}, + scrollGridImpl: null, + contentTypeHandlers: {}, + listenerRefiners: {}, + optionRefiners: {}, + propSetHandlers: {}, + }; + function addDefs(defs) { + for (var _i = 0, defs_1 = defs; _i < defs_1.length; _i++) { + var def = defs_1[_i]; + if (!isAdded[def.id]) { + isAdded[def.id] = true; + addDefs(def.deps); + hooks = combineHooks(hooks, def); + } + } + } + if (pluginDefs) { + addDefs(pluginDefs); + } + addDefs(globalDefs); + return hooks; + } + function buildBuildPluginHooks() { + var currentOverrideDefs = []; + var currentGlobalDefs = []; + var currentHooks; + return function (overrideDefs, globalDefs) { + if (!currentHooks || !isArraysEqual(overrideDefs, currentOverrideDefs) || !isArraysEqual(globalDefs, currentGlobalDefs)) { + currentHooks = buildPluginHooks(overrideDefs, globalDefs); + } + currentOverrideDefs = overrideDefs; + currentGlobalDefs = globalDefs; + return currentHooks; + }; + } + function combineHooks(hooks0, hooks1) { + return { + reducers: hooks0.reducers.concat(hooks1.reducers), + isLoadingFuncs: hooks0.isLoadingFuncs.concat(hooks1.isLoadingFuncs), + contextInit: hooks0.contextInit.concat(hooks1.contextInit), + eventRefiners: __assign(__assign({}, hooks0.eventRefiners), hooks1.eventRefiners), + eventDefMemberAdders: hooks0.eventDefMemberAdders.concat(hooks1.eventDefMemberAdders), + eventSourceRefiners: __assign(__assign({}, hooks0.eventSourceRefiners), hooks1.eventSourceRefiners), + isDraggableTransformers: hooks0.isDraggableTransformers.concat(hooks1.isDraggableTransformers), + eventDragMutationMassagers: hooks0.eventDragMutationMassagers.concat(hooks1.eventDragMutationMassagers), + eventDefMutationAppliers: hooks0.eventDefMutationAppliers.concat(hooks1.eventDefMutationAppliers), + dateSelectionTransformers: hooks0.dateSelectionTransformers.concat(hooks1.dateSelectionTransformers), + datePointTransforms: hooks0.datePointTransforms.concat(hooks1.datePointTransforms), + dateSpanTransforms: hooks0.dateSpanTransforms.concat(hooks1.dateSpanTransforms), + views: __assign(__assign({}, hooks0.views), hooks1.views), + viewPropsTransformers: hooks0.viewPropsTransformers.concat(hooks1.viewPropsTransformers), + isPropsValid: hooks1.isPropsValid || hooks0.isPropsValid, + externalDefTransforms: hooks0.externalDefTransforms.concat(hooks1.externalDefTransforms), + viewContainerAppends: hooks0.viewContainerAppends.concat(hooks1.viewContainerAppends), + eventDropTransformers: hooks0.eventDropTransformers.concat(hooks1.eventDropTransformers), + calendarInteractions: hooks0.calendarInteractions.concat(hooks1.calendarInteractions), + componentInteractions: hooks0.componentInteractions.concat(hooks1.componentInteractions), + themeClasses: __assign(__assign({}, hooks0.themeClasses), hooks1.themeClasses), + eventSourceDefs: hooks0.eventSourceDefs.concat(hooks1.eventSourceDefs), + cmdFormatter: hooks1.cmdFormatter || hooks0.cmdFormatter, + recurringTypes: hooks0.recurringTypes.concat(hooks1.recurringTypes), + namedTimeZonedImpl: hooks1.namedTimeZonedImpl || hooks0.namedTimeZonedImpl, + initialView: hooks0.initialView || hooks1.initialView, + elementDraggingImpl: hooks0.elementDraggingImpl || hooks1.elementDraggingImpl, + optionChangeHandlers: __assign(__assign({}, hooks0.optionChangeHandlers), hooks1.optionChangeHandlers), + scrollGridImpl: hooks1.scrollGridImpl || hooks0.scrollGridImpl, + contentTypeHandlers: __assign(__assign({}, hooks0.contentTypeHandlers), hooks1.contentTypeHandlers), + listenerRefiners: __assign(__assign({}, hooks0.listenerRefiners), hooks1.listenerRefiners), + optionRefiners: __assign(__assign({}, hooks0.optionRefiners), hooks1.optionRefiners), + propSetHandlers: __assign(__assign({}, hooks0.propSetHandlers), hooks1.propSetHandlers), + }; + } + + var StandardTheme = /** @class */ (function (_super) { + __extends(StandardTheme, _super); + function StandardTheme() { + return _super !== null && _super.apply(this, arguments) || this; + } + return StandardTheme; + }(Theme)); + StandardTheme.prototype.classes = { + root: 'fc-theme-standard', + tableCellShaded: 'fc-cell-shaded', + buttonGroup: 'fc-button-group', + button: 'fc-button fc-button-primary', + buttonActive: 'fc-button-active', + }; + StandardTheme.prototype.baseIconClass = 'fc-icon'; + StandardTheme.prototype.iconClasses = { + close: 'fc-icon-x', + prev: 'fc-icon-chevron-left', + next: 'fc-icon-chevron-right', + prevYear: 'fc-icon-chevrons-left', + nextYear: 'fc-icon-chevrons-right', + }; + StandardTheme.prototype.rtlIconClasses = { + prev: 'fc-icon-chevron-right', + next: 'fc-icon-chevron-left', + prevYear: 'fc-icon-chevrons-right', + nextYear: 'fc-icon-chevrons-left', + }; + StandardTheme.prototype.iconOverrideOption = 'buttonIcons'; // TODO: make TS-friendly + StandardTheme.prototype.iconOverrideCustomButtonOption = 'icon'; + StandardTheme.prototype.iconOverridePrefix = 'fc-icon-'; + + function compileViewDefs(defaultConfigs, overrideConfigs) { + var hash = {}; + var viewType; + for (viewType in defaultConfigs) { + ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs); + } + for (viewType in overrideConfigs) { + ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs); + } + return hash; + } + function ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs) { + if (hash[viewType]) { + return hash[viewType]; + } + var viewDef = buildViewDef(viewType, hash, defaultConfigs, overrideConfigs); + if (viewDef) { + hash[viewType] = viewDef; + } + return viewDef; + } + function buildViewDef(viewType, hash, defaultConfigs, overrideConfigs) { + var defaultConfig = defaultConfigs[viewType]; + var overrideConfig = overrideConfigs[viewType]; + var queryProp = function (name) { return ((defaultConfig && defaultConfig[name] !== null) ? defaultConfig[name] : + ((overrideConfig && overrideConfig[name] !== null) ? overrideConfig[name] : null)); }; + var theComponent = queryProp('component'); + var superType = queryProp('superType'); + var superDef = null; + if (superType) { + if (superType === viewType) { + throw new Error('Can\'t have a custom view type that references itself'); + } + superDef = ensureViewDef(superType, hash, defaultConfigs, overrideConfigs); + } + if (!theComponent && superDef) { + theComponent = superDef.component; + } + if (!theComponent) { + return null; // don't throw a warning, might be settings for a single-unit view + } + return { + type: viewType, + component: theComponent, + defaults: __assign(__assign({}, (superDef ? superDef.defaults : {})), (defaultConfig ? defaultConfig.rawOptions : {})), + overrides: __assign(__assign({}, (superDef ? superDef.overrides : {})), (overrideConfig ? overrideConfig.rawOptions : {})), + }; + } + + /* eslint max-classes-per-file: off */ + // NOTE: in JSX, you should always use this class with arg. otherwise, will default to any??? + var RenderHook = /** @class */ (function (_super) { + __extends(RenderHook, _super); + function RenderHook() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.rootElRef = createRef(); + _this.handleRootEl = function (el) { + setRef(_this.rootElRef, el); + if (_this.props.elRef) { + setRef(_this.props.elRef, el); + } + }; + return _this; + } + RenderHook.prototype.render = function () { + var _this = this; + var props = this.props; + var hookProps = props.hookProps; + return (createElement(MountHook, { hookProps: hookProps, didMount: props.didMount, willUnmount: props.willUnmount, elRef: this.handleRootEl }, function (rootElRef) { return (createElement(ContentHook, { hookProps: hookProps, content: props.content, defaultContent: props.defaultContent, backupElRef: _this.rootElRef }, function (innerElRef, innerContent) { return props.children(rootElRef, normalizeClassNames(props.classNames, hookProps), innerElRef, innerContent); })); })); + }; + return RenderHook; + }(BaseComponent)); + // TODO: rename to be about function, not default. use in above type + // for forcing rerender of components that use the ContentHook + var CustomContentRenderContext = createContext(0); + function ContentHook(props) { + return (createElement(CustomContentRenderContext.Consumer, null, function (renderId) { return (createElement(ContentHookInner, __assign({ renderId: renderId }, props))); })); + } + var ContentHookInner = /** @class */ (function (_super) { + __extends(ContentHookInner, _super); + function ContentHookInner() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.innerElRef = createRef(); + return _this; + } + ContentHookInner.prototype.render = function () { + return this.props.children(this.innerElRef, this.renderInnerContent()); + }; + ContentHookInner.prototype.componentDidMount = function () { + this.updateCustomContent(); + }; + ContentHookInner.prototype.componentDidUpdate = function () { + this.updateCustomContent(); + }; + ContentHookInner.prototype.componentWillUnmount = function () { + if (this.customContentInfo && this.customContentInfo.destroy) { + this.customContentInfo.destroy(); + } + }; + ContentHookInner.prototype.renderInnerContent = function () { + var contentTypeHandlers = this.context.pluginHooks.contentTypeHandlers; + var _a = this, props = _a.props, customContentInfo = _a.customContentInfo; + var rawVal = props.content; + var innerContent = normalizeContent(rawVal, props.hookProps); + var innerContentVDom = null; + if (innerContent === undefined) { // use the default + innerContent = normalizeContent(props.defaultContent, props.hookProps); + } + if (innerContent !== undefined) { // we allow custom content handlers to return nothing + if (customContentInfo) { + customContentInfo.contentVal = innerContent[customContentInfo.contentKey]; + } + else if (typeof innerContent === 'object') { + // look for a prop that would indicate a custom content handler is needed + for (var contentKey in contentTypeHandlers) { + if (innerContent[contentKey] !== undefined) { + var stuff = contentTypeHandlers[contentKey](); + customContentInfo = this.customContentInfo = __assign({ contentKey: contentKey, contentVal: innerContent[contentKey] }, stuff); + break; + } + } + } + if (customContentInfo) { + innerContentVDom = []; // signal that something was specified + } + else { + innerContentVDom = innerContent; // assume a [p]react vdom node. use it + } + } + return innerContentVDom; + }; + ContentHookInner.prototype.updateCustomContent = function () { + if (this.customContentInfo) { + this.customContentInfo.render(this.innerElRef.current || this.props.backupElRef.current, // the element to render into + this.customContentInfo.contentVal); + } + }; + return ContentHookInner; + }(BaseComponent)); + var MountHook = /** @class */ (function (_super) { + __extends(MountHook, _super); + function MountHook() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.handleRootEl = function (rootEl) { + _this.rootEl = rootEl; + if (_this.props.elRef) { + setRef(_this.props.elRef, rootEl); + } + }; + return _this; + } + MountHook.prototype.render = function () { + return this.props.children(this.handleRootEl); + }; + MountHook.prototype.componentDidMount = function () { + var callback = this.props.didMount; + if (callback) { + callback(__assign(__assign({}, this.props.hookProps), { el: this.rootEl })); + } + }; + MountHook.prototype.componentWillUnmount = function () { + var callback = this.props.willUnmount; + if (callback) { + callback(__assign(__assign({}, this.props.hookProps), { el: this.rootEl })); + } + }; + return MountHook; + }(BaseComponent)); + function buildClassNameNormalizer() { + var currentGenerator; + var currentHookProps; + var currentClassNames = []; + return function (generator, hookProps) { + if (!currentHookProps || !isPropsEqual(currentHookProps, hookProps) || generator !== currentGenerator) { + currentGenerator = generator; + currentHookProps = hookProps; + currentClassNames = normalizeClassNames(generator, hookProps); + } + return currentClassNames; + }; + } + function normalizeClassNames(classNames, hookProps) { + if (typeof classNames === 'function') { + classNames = classNames(hookProps); + } + return parseClassNames(classNames); + } + function normalizeContent(input, hookProps) { + if (typeof input === 'function') { + return input(hookProps, createElement); // give the function the vdom-creation func + } + return input; + } + + var ViewRoot = /** @class */ (function (_super) { + __extends(ViewRoot, _super); + function ViewRoot() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.normalizeClassNames = buildClassNameNormalizer(); + return _this; + } + ViewRoot.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var options = context.options; + var hookProps = { view: context.viewApi }; + var customClassNames = this.normalizeClassNames(options.viewClassNames, hookProps); + return (createElement(MountHook, { hookProps: hookProps, didMount: options.viewDidMount, willUnmount: options.viewWillUnmount, elRef: props.elRef }, function (rootElRef) { return props.children(rootElRef, ["fc-" + props.viewSpec.type + "-view", 'fc-view'].concat(customClassNames)); })); + }; + return ViewRoot; + }(BaseComponent)); + + function parseViewConfigs(inputs) { + return mapHash(inputs, parseViewConfig); + } + function parseViewConfig(input) { + var rawOptions = typeof input === 'function' ? + { component: input } : + input; + var component = rawOptions.component; + if (rawOptions.content) { + component = createViewHookComponent(rawOptions); + // TODO: remove content/classNames/didMount/etc from options? + } + return { + superType: rawOptions.type, + component: component, + rawOptions: rawOptions, + }; + } + function createViewHookComponent(options) { + return function (viewProps) { return (createElement(ViewContextType.Consumer, null, function (context) { return (createElement(ViewRoot, { viewSpec: context.viewSpec }, function (viewElRef, viewClassNames) { + var hookProps = __assign(__assign({}, viewProps), { nextDayThreshold: context.options.nextDayThreshold }); + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.classNames, content: options.content, didMount: options.didMount, willUnmount: options.willUnmount, elRef: viewElRef }, function (rootElRef, customClassNames, innerElRef, innerContent) { return (createElement("div", { className: viewClassNames.concat(customClassNames).join(' '), ref: rootElRef }, innerContent)); })); + })); })); }; + } + + function buildViewSpecs(defaultInputs, optionOverrides, dynamicOptionOverrides, localeDefaults) { + var defaultConfigs = parseViewConfigs(defaultInputs); + var overrideConfigs = parseViewConfigs(optionOverrides.views); + var viewDefs = compileViewDefs(defaultConfigs, overrideConfigs); + return mapHash(viewDefs, function (viewDef) { return buildViewSpec(viewDef, overrideConfigs, optionOverrides, dynamicOptionOverrides, localeDefaults); }); + } + function buildViewSpec(viewDef, overrideConfigs, optionOverrides, dynamicOptionOverrides, localeDefaults) { + var durationInput = viewDef.overrides.duration || + viewDef.defaults.duration || + dynamicOptionOverrides.duration || + optionOverrides.duration; + var duration = null; + var durationUnit = ''; + var singleUnit = ''; + var singleUnitOverrides = {}; + if (durationInput) { + duration = createDurationCached(durationInput); + if (duration) { // valid? + var denom = greatestDurationDenominator(duration); + durationUnit = denom.unit; + if (denom.value === 1) { + singleUnit = durationUnit; + singleUnitOverrides = overrideConfigs[durationUnit] ? overrideConfigs[durationUnit].rawOptions : {}; + } + } + } + var queryButtonText = function (optionsSubset) { + var buttonTextMap = optionsSubset.buttonText || {}; + var buttonTextKey = viewDef.defaults.buttonTextKey; + if (buttonTextKey != null && buttonTextMap[buttonTextKey] != null) { + return buttonTextMap[buttonTextKey]; + } + if (buttonTextMap[viewDef.type] != null) { + return buttonTextMap[viewDef.type]; + } + if (buttonTextMap[singleUnit] != null) { + return buttonTextMap[singleUnit]; + } + return null; + }; + return { + type: viewDef.type, + component: viewDef.component, + duration: duration, + durationUnit: durationUnit, + singleUnit: singleUnit, + optionDefaults: viewDef.defaults, + optionOverrides: __assign(__assign({}, singleUnitOverrides), viewDef.overrides), + buttonTextOverride: queryButtonText(dynamicOptionOverrides) || + queryButtonText(optionOverrides) || // constructor-specified buttonText lookup hash takes precedence + viewDef.overrides.buttonText, + buttonTextDefault: queryButtonText(localeDefaults) || + viewDef.defaults.buttonText || + queryButtonText(BASE_OPTION_DEFAULTS) || + viewDef.type, // fall back to given view name + }; + } + // hack to get memoization working + var durationInputMap = {}; + function createDurationCached(durationInput) { + var json = JSON.stringify(durationInput); + var res = durationInputMap[json]; + if (res === undefined) { + res = createDuration(durationInput); + durationInputMap[json] = res; + } + return res; + } + + var DateProfileGenerator = /** @class */ (function () { + function DateProfileGenerator(props) { + this.props = props; + this.nowDate = getNow(props.nowInput, props.dateEnv); + this.initHiddenDays(); + } + /* Date Range Computation + ------------------------------------------------------------------------------------------------------------------*/ + // Builds a structure with info about what the dates/ranges will be for the "prev" view. + DateProfileGenerator.prototype.buildPrev = function (currentDateProfile, currentDate, forceToValid) { + var dateEnv = this.props.dateEnv; + var prevDate = dateEnv.subtract(dateEnv.startOf(currentDate, currentDateProfile.currentRangeUnit), // important for start-of-month + currentDateProfile.dateIncrement); + return this.build(prevDate, -1, forceToValid); + }; + // Builds a structure with info about what the dates/ranges will be for the "next" view. + DateProfileGenerator.prototype.buildNext = function (currentDateProfile, currentDate, forceToValid) { + var dateEnv = this.props.dateEnv; + var nextDate = dateEnv.add(dateEnv.startOf(currentDate, currentDateProfile.currentRangeUnit), // important for start-of-month + currentDateProfile.dateIncrement); + return this.build(nextDate, 1, forceToValid); + }; + // Builds a structure holding dates/ranges for rendering around the given date. + // Optional direction param indicates whether the date is being incremented/decremented + // from its previous value. decremented = -1, incremented = 1 (default). + DateProfileGenerator.prototype.build = function (currentDate, direction, forceToValid) { + if (forceToValid === void 0) { forceToValid = true; } + var props = this.props; + var validRange; + var currentInfo; + var isRangeAllDay; + var renderRange; + var activeRange; + var isValid; + validRange = this.buildValidRange(); + validRange = this.trimHiddenDays(validRange); + if (forceToValid) { + currentDate = constrainMarkerToRange(currentDate, validRange); + } + currentInfo = this.buildCurrentRangeInfo(currentDate, direction); + isRangeAllDay = /^(year|month|week|day)$/.test(currentInfo.unit); + renderRange = this.buildRenderRange(this.trimHiddenDays(currentInfo.range), currentInfo.unit, isRangeAllDay); + renderRange = this.trimHiddenDays(renderRange); + activeRange = renderRange; + if (!props.showNonCurrentDates) { + activeRange = intersectRanges(activeRange, currentInfo.range); + } + activeRange = this.adjustActiveRange(activeRange); + activeRange = intersectRanges(activeRange, validRange); // might return null + // it's invalid if the originally requested date is not contained, + // or if the range is completely outside of the valid range. + isValid = rangesIntersect(currentInfo.range, validRange); + return { + // constraint for where prev/next operations can go and where events can be dragged/resized to. + // an object with optional start and end properties. + validRange: validRange, + // range the view is formally responsible for. + // for example, a month view might have 1st-31st, excluding padded dates + currentRange: currentInfo.range, + // name of largest unit being displayed, like "month" or "week" + currentRangeUnit: currentInfo.unit, + isRangeAllDay: isRangeAllDay, + // dates that display events and accept drag-n-drop + // will be `null` if no dates accept events + activeRange: activeRange, + // date range with a rendered skeleton + // includes not-active days that need some sort of DOM + renderRange: renderRange, + // Duration object that denotes the first visible time of any given day + slotMinTime: props.slotMinTime, + // Duration object that denotes the exclusive visible end time of any given day + slotMaxTime: props.slotMaxTime, + isValid: isValid, + // how far the current date will move for a prev/next operation + dateIncrement: this.buildDateIncrement(currentInfo.duration), + // pass a fallback (might be null) ^ + }; + }; + // Builds an object with optional start/end properties. + // Indicates the minimum/maximum dates to display. + // not responsible for trimming hidden days. + DateProfileGenerator.prototype.buildValidRange = function () { + var input = this.props.validRangeInput; + var simpleInput = typeof input === 'function' + ? input.call(this.props.calendarApi, this.nowDate) + : input; + return this.refineRange(simpleInput) || + { start: null, end: null }; // completely open-ended + }; + // Builds a structure with info about the "current" range, the range that is + // highlighted as being the current month for example. + // See build() for a description of `direction`. + // Guaranteed to have `range` and `unit` properties. `duration` is optional. + DateProfileGenerator.prototype.buildCurrentRangeInfo = function (date, direction) { + var props = this.props; + var duration = null; + var unit = null; + var range = null; + var dayCount; + if (props.duration) { + duration = props.duration; + unit = props.durationUnit; + range = this.buildRangeFromDuration(date, direction, duration, unit); + } + else if ((dayCount = this.props.dayCount)) { + unit = 'day'; + range = this.buildRangeFromDayCount(date, direction, dayCount); + } + else if ((range = this.buildCustomVisibleRange(date))) { + unit = props.dateEnv.greatestWholeUnit(range.start, range.end).unit; + } + else { + duration = this.getFallbackDuration(); + unit = greatestDurationDenominator(duration).unit; + range = this.buildRangeFromDuration(date, direction, duration, unit); + } + return { duration: duration, unit: unit, range: range }; + }; + DateProfileGenerator.prototype.getFallbackDuration = function () { + return createDuration({ day: 1 }); + }; + // Returns a new activeRange to have time values (un-ambiguate) + // slotMinTime or slotMaxTime causes the range to expand. + DateProfileGenerator.prototype.adjustActiveRange = function (range) { + var _a = this.props, dateEnv = _a.dateEnv, usesMinMaxTime = _a.usesMinMaxTime, slotMinTime = _a.slotMinTime, slotMaxTime = _a.slotMaxTime; + var start = range.start, end = range.end; + if (usesMinMaxTime) { + // expand active range if slotMinTime is negative (why not when positive?) + if (asRoughDays(slotMinTime) < 0) { + start = startOfDay(start); // necessary? + start = dateEnv.add(start, slotMinTime); + } + // expand active range if slotMaxTime is beyond one day (why not when negative?) + if (asRoughDays(slotMaxTime) > 1) { + end = startOfDay(end); // necessary? + end = addDays(end, -1); + end = dateEnv.add(end, slotMaxTime); + } + } + return { start: start, end: end }; + }; + // Builds the "current" range when it is specified as an explicit duration. + // `unit` is the already-computed greatestDurationDenominator unit of duration. + DateProfileGenerator.prototype.buildRangeFromDuration = function (date, direction, duration, unit) { + var _a = this.props, dateEnv = _a.dateEnv, dateAlignment = _a.dateAlignment; + var start; + var end; + var res; + // compute what the alignment should be + if (!dateAlignment) { + var dateIncrement = this.props.dateIncrement; + if (dateIncrement) { + // use the smaller of the two units + if (asRoughMs(dateIncrement) < asRoughMs(duration)) { + dateAlignment = greatestDurationDenominator(dateIncrement).unit; + } + else { + dateAlignment = unit; + } + } + else { + dateAlignment = unit; + } + } + // if the view displays a single day or smaller + if (asRoughDays(duration) <= 1) { + if (this.isHiddenDay(start)) { + start = this.skipHiddenDays(start, direction); + start = startOfDay(start); + } + } + function computeRes() { + start = dateEnv.startOf(date, dateAlignment); + end = dateEnv.add(start, duration); + res = { start: start, end: end }; + } + computeRes(); + // if range is completely enveloped by hidden days, go past the hidden days + if (!this.trimHiddenDays(res)) { + date = this.skipHiddenDays(date, direction); + computeRes(); + } + return res; + }; + // Builds the "current" range when a dayCount is specified. + DateProfileGenerator.prototype.buildRangeFromDayCount = function (date, direction, dayCount) { + var _a = this.props, dateEnv = _a.dateEnv, dateAlignment = _a.dateAlignment; + var runningCount = 0; + var start = date; + var end; + if (dateAlignment) { + start = dateEnv.startOf(start, dateAlignment); + } + start = startOfDay(start); + start = this.skipHiddenDays(start, direction); + end = start; + do { + end = addDays(end, 1); + if (!this.isHiddenDay(end)) { + runningCount += 1; + } + } while (runningCount < dayCount); + return { start: start, end: end }; + }; + // Builds a normalized range object for the "visible" range, + // which is a way to define the currentRange and activeRange at the same time. + DateProfileGenerator.prototype.buildCustomVisibleRange = function (date) { + var props = this.props; + var input = props.visibleRangeInput; + var simpleInput = typeof input === 'function' + ? input.call(props.calendarApi, props.dateEnv.toDate(date)) + : input; + var range = this.refineRange(simpleInput); + if (range && (range.start == null || range.end == null)) { + return null; + } + return range; + }; + // Computes the range that will represent the element/cells for *rendering*, + // but which may have voided days/times. + // not responsible for trimming hidden days. + DateProfileGenerator.prototype.buildRenderRange = function (currentRange, currentRangeUnit, isRangeAllDay) { + return currentRange; + }; + // Compute the duration value that should be added/substracted to the current date + // when a prev/next operation happens. + DateProfileGenerator.prototype.buildDateIncrement = function (fallback) { + var dateIncrement = this.props.dateIncrement; + var customAlignment; + if (dateIncrement) { + return dateIncrement; + } + if ((customAlignment = this.props.dateAlignment)) { + return createDuration(1, customAlignment); + } + if (fallback) { + return fallback; + } + return createDuration({ days: 1 }); + }; + DateProfileGenerator.prototype.refineRange = function (rangeInput) { + if (rangeInput) { + var range = parseRange(rangeInput, this.props.dateEnv); + if (range) { + range = computeVisibleDayRange(range); + } + return range; + } + return null; + }; + /* Hidden Days + ------------------------------------------------------------------------------------------------------------------*/ + // Initializes internal variables related to calculating hidden days-of-week + DateProfileGenerator.prototype.initHiddenDays = function () { + var hiddenDays = this.props.hiddenDays || []; // array of day-of-week indices that are hidden + var isHiddenDayHash = []; // is the day-of-week hidden? (hash with day-of-week-index -> bool) + var dayCnt = 0; + var i; + if (this.props.weekends === false) { + hiddenDays.push(0, 6); // 0=sunday, 6=saturday + } + for (i = 0; i < 7; i += 1) { + if (!(isHiddenDayHash[i] = hiddenDays.indexOf(i) !== -1)) { + dayCnt += 1; + } + } + if (!dayCnt) { + throw new Error('invalid hiddenDays'); // all days were hidden? bad. + } + this.isHiddenDayHash = isHiddenDayHash; + }; + // Remove days from the beginning and end of the range that are computed as hidden. + // If the whole range is trimmed off, returns null + DateProfileGenerator.prototype.trimHiddenDays = function (range) { + var start = range.start, end = range.end; + if (start) { + start = this.skipHiddenDays(start); + } + if (end) { + end = this.skipHiddenDays(end, -1, true); + } + if (start == null || end == null || start < end) { + return { start: start, end: end }; + } + return null; + }; + // Is the current day hidden? + // `day` is a day-of-week index (0-6), or a Date (used for UTC) + DateProfileGenerator.prototype.isHiddenDay = function (day) { + if (day instanceof Date) { + day = day.getUTCDay(); + } + return this.isHiddenDayHash[day]; + }; + // Incrementing the current day until it is no longer a hidden day, returning a copy. + // DOES NOT CONSIDER validRange! + // If the initial value of `date` is not a hidden day, don't do anything. + // Pass `isExclusive` as `true` if you are dealing with an end date. + // `inc` defaults to `1` (increment one day forward each time) + DateProfileGenerator.prototype.skipHiddenDays = function (date, inc, isExclusive) { + if (inc === void 0) { inc = 1; } + if (isExclusive === void 0) { isExclusive = false; } + while (this.isHiddenDayHash[(date.getUTCDay() + (isExclusive ? inc : 0) + 7) % 7]) { + date = addDays(date, inc); + } + return date; + }; + return DateProfileGenerator; + }()); + + function reduceViewType(viewType, action) { + switch (action.type) { + case 'CHANGE_VIEW_TYPE': + viewType = action.viewType; + } + return viewType; + } + + function reduceDynamicOptionOverrides(dynamicOptionOverrides, action) { + var _a; + switch (action.type) { + case 'SET_OPTION': + return __assign(__assign({}, dynamicOptionOverrides), (_a = {}, _a[action.optionName] = action.rawOptionValue, _a)); + default: + return dynamicOptionOverrides; + } + } + + function reduceDateProfile(currentDateProfile, action, currentDate, dateProfileGenerator) { + var dp; + switch (action.type) { + case 'CHANGE_VIEW_TYPE': + return dateProfileGenerator.build(action.dateMarker || currentDate); + case 'CHANGE_DATE': + return dateProfileGenerator.build(action.dateMarker); + case 'PREV': + dp = dateProfileGenerator.buildPrev(currentDateProfile, currentDate); + if (dp.isValid) { + return dp; + } + break; + case 'NEXT': + dp = dateProfileGenerator.buildNext(currentDateProfile, currentDate); + if (dp.isValid) { + return dp; + } + break; + } + return currentDateProfile; + } + + function initEventSources(calendarOptions, dateProfile, context) { + var activeRange = dateProfile ? dateProfile.activeRange : null; + return addSources({}, parseInitialSources(calendarOptions, context), activeRange, context); + } + function reduceEventSources(eventSources, action, dateProfile, context) { + var activeRange = dateProfile ? dateProfile.activeRange : null; // need this check? + switch (action.type) { + case 'ADD_EVENT_SOURCES': // already parsed + return addSources(eventSources, action.sources, activeRange, context); + case 'REMOVE_EVENT_SOURCE': + return removeSource(eventSources, action.sourceId); + case 'PREV': // TODO: how do we track all actions that affect dateProfile :( + case 'NEXT': + case 'CHANGE_DATE': + case 'CHANGE_VIEW_TYPE': + if (dateProfile) { + return fetchDirtySources(eventSources, activeRange, context); + } + return eventSources; + case 'FETCH_EVENT_SOURCES': + return fetchSourcesByIds(eventSources, action.sourceIds ? // why no type? + arrayToHash(action.sourceIds) : + excludeStaticSources(eventSources, context), activeRange, action.isRefetch || false, context); + case 'RECEIVE_EVENTS': + case 'RECEIVE_EVENT_ERROR': + return receiveResponse$1(eventSources, action.sourceId, action.fetchId, action.fetchRange); + case 'REMOVE_ALL_EVENT_SOURCES': + return {}; + default: + return eventSources; + } + } + function reduceEventSourcesNewTimeZone(eventSources, dateProfile, context) { + var activeRange = dateProfile ? dateProfile.activeRange : null; // need this check? + return fetchSourcesByIds(eventSources, excludeStaticSources(eventSources, context), activeRange, true, context); + } + function computeEventSourcesLoading(eventSources) { + for (var sourceId in eventSources) { + if (eventSources[sourceId].isFetching) { + return true; + } + } + return false; + } + function addSources(eventSourceHash, sources, fetchRange, context) { + var hash = {}; + for (var _i = 0, sources_1 = sources; _i < sources_1.length; _i++) { + var source = sources_1[_i]; + hash[source.sourceId] = source; + } + if (fetchRange) { + hash = fetchDirtySources(hash, fetchRange, context); + } + return __assign(__assign({}, eventSourceHash), hash); + } + function removeSource(eventSourceHash, sourceId) { + return filterHash(eventSourceHash, function (eventSource) { return eventSource.sourceId !== sourceId; }); + } + function fetchDirtySources(sourceHash, fetchRange, context) { + return fetchSourcesByIds(sourceHash, filterHash(sourceHash, function (eventSource) { return isSourceDirty(eventSource, fetchRange, context); }), fetchRange, false, context); + } + function isSourceDirty(eventSource, fetchRange, context) { + if (!doesSourceNeedRange(eventSource, context)) { + return !eventSource.latestFetchId; + } + return !context.options.lazyFetching || + !eventSource.fetchRange || + eventSource.isFetching || // always cancel outdated in-progress fetches + fetchRange.start < eventSource.fetchRange.start || + fetchRange.end > eventSource.fetchRange.end; + } + function fetchSourcesByIds(prevSources, sourceIdHash, fetchRange, isRefetch, context) { + var nextSources = {}; + for (var sourceId in prevSources) { + var source = prevSources[sourceId]; + if (sourceIdHash[sourceId]) { + nextSources[sourceId] = fetchSource$1(source, fetchRange, isRefetch, context); + } + else { + nextSources[sourceId] = source; + } + } + return nextSources; + } + function fetchSource$1(eventSource, fetchRange, isRefetch, context) { + var options = context.options, calendarApi = context.calendarApi; + var sourceDef = context.pluginHooks.eventSourceDefs[eventSource.sourceDefId]; + var fetchId = guid(); + sourceDef.fetch({ + eventSource: eventSource, + range: fetchRange, + isRefetch: isRefetch, + context: context, + }, function (res) { + var rawEvents = res.rawEvents; + if (options.eventSourceSuccess) { + rawEvents = options.eventSourceSuccess.call(calendarApi, rawEvents, res.xhr) || rawEvents; + } + if (eventSource.success) { + rawEvents = eventSource.success.call(calendarApi, rawEvents, res.xhr) || rawEvents; + } + context.dispatch({ + type: 'RECEIVE_EVENTS', + sourceId: eventSource.sourceId, + fetchId: fetchId, + fetchRange: fetchRange, + rawEvents: rawEvents, + }); + }, function (error) { + console.warn(error.message, error); + if (options.eventSourceFailure) { + options.eventSourceFailure.call(calendarApi, error); + } + if (eventSource.failure) { + eventSource.failure(error); + } + context.dispatch({ + type: 'RECEIVE_EVENT_ERROR', + sourceId: eventSource.sourceId, + fetchId: fetchId, + fetchRange: fetchRange, + error: error, + }); + }); + return __assign(__assign({}, eventSource), { isFetching: true, latestFetchId: fetchId }); + } + function receiveResponse$1(sourceHash, sourceId, fetchId, fetchRange) { + var _a; + var eventSource = sourceHash[sourceId]; + if (eventSource && // not already removed + fetchId === eventSource.latestFetchId) { + return __assign(__assign({}, sourceHash), (_a = {}, _a[sourceId] = __assign(__assign({}, eventSource), { isFetching: false, fetchRange: fetchRange }), _a)); + } + return sourceHash; + } + function excludeStaticSources(eventSources, context) { + return filterHash(eventSources, function (eventSource) { return doesSourceNeedRange(eventSource, context); }); + } + function parseInitialSources(rawOptions, context) { + var refiners = buildEventSourceRefiners(context); + var rawSources = [].concat(rawOptions.eventSources || []); + var sources = []; // parsed + if (rawOptions.initialEvents) { + rawSources.unshift(rawOptions.initialEvents); + } + if (rawOptions.events) { + rawSources.unshift(rawOptions.events); + } + for (var _i = 0, rawSources_1 = rawSources; _i < rawSources_1.length; _i++) { + var rawSource = rawSources_1[_i]; + var source = parseEventSource(rawSource, context, refiners); + if (source) { + sources.push(source); + } + } + return sources; + } + function doesSourceNeedRange(eventSource, context) { + var defs = context.pluginHooks.eventSourceDefs; + return !defs[eventSource.sourceDefId].ignoreRange; + } + + function reduceEventStore(eventStore, action, eventSources, dateProfile, context) { + switch (action.type) { + case 'RECEIVE_EVENTS': // raw + return receiveRawEvents(eventStore, eventSources[action.sourceId], action.fetchId, action.fetchRange, action.rawEvents, context); + case 'ADD_EVENTS': // already parsed, but not expanded + return addEvent(eventStore, action.eventStore, // new ones + dateProfile ? dateProfile.activeRange : null, context); + case 'RESET_EVENTS': + return action.eventStore; + case 'MERGE_EVENTS': // already parsed and expanded + return mergeEventStores(eventStore, action.eventStore); + case 'PREV': // TODO: how do we track all actions that affect dateProfile :( + case 'NEXT': + case 'CHANGE_DATE': + case 'CHANGE_VIEW_TYPE': + if (dateProfile) { + return expandRecurring(eventStore, dateProfile.activeRange, context); + } + return eventStore; + case 'REMOVE_EVENTS': + return excludeSubEventStore(eventStore, action.eventStore); + case 'REMOVE_EVENT_SOURCE': + return excludeEventsBySourceId(eventStore, action.sourceId); + case 'REMOVE_ALL_EVENT_SOURCES': + return filterEventStoreDefs(eventStore, function (eventDef) { return (!eventDef.sourceId // only keep events with no source id + ); }); + case 'REMOVE_ALL_EVENTS': + return createEmptyEventStore(); + default: + return eventStore; + } + } + function receiveRawEvents(eventStore, eventSource, fetchId, fetchRange, rawEvents, context) { + if (eventSource && // not already removed + fetchId === eventSource.latestFetchId // TODO: wish this logic was always in event-sources + ) { + var subset = parseEvents(transformRawEvents(rawEvents, eventSource, context), eventSource, context); + if (fetchRange) { + subset = expandRecurring(subset, fetchRange, context); + } + return mergeEventStores(excludeEventsBySourceId(eventStore, eventSource.sourceId), subset); + } + return eventStore; + } + function transformRawEvents(rawEvents, eventSource, context) { + var calEachTransform = context.options.eventDataTransform; + var sourceEachTransform = eventSource ? eventSource.eventDataTransform : null; + if (sourceEachTransform) { + rawEvents = transformEachRawEvent(rawEvents, sourceEachTransform); + } + if (calEachTransform) { + rawEvents = transformEachRawEvent(rawEvents, calEachTransform); + } + return rawEvents; + } + function transformEachRawEvent(rawEvents, func) { + var refinedEvents; + if (!func) { + refinedEvents = rawEvents; + } + else { + refinedEvents = []; + for (var _i = 0, rawEvents_1 = rawEvents; _i < rawEvents_1.length; _i++) { + var rawEvent = rawEvents_1[_i]; + var refinedEvent = func(rawEvent); + if (refinedEvent) { + refinedEvents.push(refinedEvent); + } + else if (refinedEvent == null) { + refinedEvents.push(rawEvent); + } // if a different falsy value, do nothing + } + } + return refinedEvents; + } + function addEvent(eventStore, subset, expandRange, context) { + if (expandRange) { + subset = expandRecurring(subset, expandRange, context); + } + return mergeEventStores(eventStore, subset); + } + function rezoneEventStoreDates(eventStore, oldDateEnv, newDateEnv) { + var defs = eventStore.defs; + var instances = mapHash(eventStore.instances, function (instance) { + var def = defs[instance.defId]; + if (def.allDay || def.recurringDef) { + return instance; // isn't dependent on timezone + } + return __assign(__assign({}, instance), { range: { + start: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.start, instance.forcedStartTzo)), + end: newDateEnv.createMarker(oldDateEnv.toDate(instance.range.end, instance.forcedEndTzo)), + }, forcedStartTzo: newDateEnv.canComputeOffset ? null : instance.forcedStartTzo, forcedEndTzo: newDateEnv.canComputeOffset ? null : instance.forcedEndTzo }); + }); + return { defs: defs, instances: instances }; + } + function excludeEventsBySourceId(eventStore, sourceId) { + return filterEventStoreDefs(eventStore, function (eventDef) { return eventDef.sourceId !== sourceId; }); + } + // QUESTION: why not just return instances? do a general object-property-exclusion util + function excludeInstances(eventStore, removals) { + return { + defs: eventStore.defs, + instances: filterHash(eventStore.instances, function (instance) { return !removals[instance.instanceId]; }), + }; + } + + function reduceDateSelection(currentSelection, action) { + switch (action.type) { + case 'UNSELECT_DATES': + return null; + case 'SELECT_DATES': + return action.selection; + default: + return currentSelection; + } + } + + function reduceSelectedEvent(currentInstanceId, action) { + switch (action.type) { + case 'UNSELECT_EVENT': + return ''; + case 'SELECT_EVENT': + return action.eventInstanceId; + default: + return currentInstanceId; + } + } + + function reduceEventDrag(currentDrag, action) { + var newDrag; + switch (action.type) { + case 'UNSET_EVENT_DRAG': + return null; + case 'SET_EVENT_DRAG': + newDrag = action.state; + return { + affectedEvents: newDrag.affectedEvents, + mutatedEvents: newDrag.mutatedEvents, + isEvent: newDrag.isEvent, + }; + default: + return currentDrag; + } + } + + function reduceEventResize(currentResize, action) { + var newResize; + switch (action.type) { + case 'UNSET_EVENT_RESIZE': + return null; + case 'SET_EVENT_RESIZE': + newResize = action.state; + return { + affectedEvents: newResize.affectedEvents, + mutatedEvents: newResize.mutatedEvents, + isEvent: newResize.isEvent, + }; + default: + return currentResize; + } + } + + function parseToolbars(calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) { + var viewsWithButtons = []; + var headerToolbar = calendarOptions.headerToolbar ? parseToolbar(calendarOptions.headerToolbar, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi, viewsWithButtons) : null; + var footerToolbar = calendarOptions.footerToolbar ? parseToolbar(calendarOptions.footerToolbar, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi, viewsWithButtons) : null; + return { headerToolbar: headerToolbar, footerToolbar: footerToolbar, viewsWithButtons: viewsWithButtons }; + } + function parseToolbar(sectionStrHash, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi, viewsWithButtons) { + return mapHash(sectionStrHash, function (sectionStr) { return parseSection(sectionStr, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi, viewsWithButtons); }); + } + /* + BAD: querying icons and text here. should be done at render time + */ + function parseSection(sectionStr, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi, viewsWithButtons) { + var isRtl = calendarOptions.direction === 'rtl'; + var calendarCustomButtons = calendarOptions.customButtons || {}; + var calendarButtonTextOverrides = calendarOptionOverrides.buttonText || {}; + var calendarButtonText = calendarOptions.buttonText || {}; + var sectionSubstrs = sectionStr ? sectionStr.split(' ') : []; + return sectionSubstrs.map(function (buttonGroupStr) { return (buttonGroupStr.split(',').map(function (buttonName) { + if (buttonName === 'title') { + return { buttonName: buttonName }; + } + var customButtonProps; + var viewSpec; + var buttonClick; + var buttonIcon; // only one of these will be set + var buttonText; // " + if ((customButtonProps = calendarCustomButtons[buttonName])) { + buttonClick = function (ev) { + if (customButtonProps.click) { + customButtonProps.click.call(ev.target, ev, ev.target); // TODO: use Calendar this context? + } + }; + (buttonIcon = theme.getCustomButtonIconClass(customButtonProps)) || + (buttonIcon = theme.getIconClass(buttonName, isRtl)) || + (buttonText = customButtonProps.text); + } + else if ((viewSpec = viewSpecs[buttonName])) { + viewsWithButtons.push(buttonName); + buttonClick = function () { + calendarApi.changeView(buttonName); + }; + (buttonText = viewSpec.buttonTextOverride) || + (buttonIcon = theme.getIconClass(buttonName, isRtl)) || + (buttonText = viewSpec.buttonTextDefault); + } + else if (calendarApi[buttonName]) { // a calendarApi method + buttonClick = function () { + calendarApi[buttonName](); + }; + (buttonText = calendarButtonTextOverrides[buttonName]) || + (buttonIcon = theme.getIconClass(buttonName, isRtl)) || + (buttonText = calendarButtonText[buttonName]); + // ^ everything else is considered default + } + return { buttonName: buttonName, buttonClick: buttonClick, buttonIcon: buttonIcon, buttonText: buttonText }; + })); }); + } + + var eventSourceDef$3 = { + ignoreRange: true, + parseMeta: function (refined) { + if (Array.isArray(refined.events)) { + return refined.events; + } + return null; + }, + fetch: function (arg, success) { + success({ + rawEvents: arg.eventSource.meta, + }); + }, + }; + var arrayEventSourcePlugin = createPlugin({ + eventSourceDefs: [eventSourceDef$3], + }); + + var eventSourceDef$2 = { + parseMeta: function (refined) { + if (typeof refined.events === 'function') { + return refined.events; + } + return null; + }, + fetch: function (arg, success, failure) { + var dateEnv = arg.context.dateEnv; + var func = arg.eventSource.meta; + unpromisify(func.bind(null, buildRangeApiWithTimeZone(arg.range, dateEnv)), function (rawEvents) { + success({ rawEvents: rawEvents }); // needs an object response + }, failure); + }, + }; + var funcEventSourcePlugin = createPlugin({ + eventSourceDefs: [eventSourceDef$2], + }); + + function requestJson(method, url, params, successCallback, failureCallback) { + method = method.toUpperCase(); + var body = null; + if (method === 'GET') { + url = injectQueryStringParams(url, params); + } + else { + body = encodeParams(params); + } + var xhr = new XMLHttpRequest(); + xhr.open(method, url, true); + if (method !== 'GET') { + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + } + xhr.onload = function () { + if (xhr.status >= 200 && xhr.status < 400) { + var parsed = false; + var res = void 0; + try { + res = JSON.parse(xhr.responseText); + parsed = true; + } + catch (err) { + // will handle parsed=false + } + if (parsed) { + successCallback(res, xhr); + } + else { + failureCallback('Failure parsing JSON', xhr); + } + } + else { + failureCallback('Request failed', xhr); + } + }; + xhr.onerror = function () { + failureCallback('Request failed', xhr); + }; + xhr.send(body); + } + function injectQueryStringParams(url, params) { + return url + + (url.indexOf('?') === -1 ? '?' : '&') + + encodeParams(params); + } + function encodeParams(params) { + var parts = []; + for (var key in params) { + parts.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key])); + } + return parts.join('&'); + } + + var JSON_FEED_EVENT_SOURCE_REFINERS = { + method: String, + extraParams: identity, + startParam: String, + endParam: String, + timeZoneParam: String, + }; + + var eventSourceDef$1 = { + parseMeta: function (refined) { + if (refined.url && (refined.format === 'json' || !refined.format)) { + return { + url: refined.url, + format: 'json', + method: (refined.method || 'GET').toUpperCase(), + extraParams: refined.extraParams, + startParam: refined.startParam, + endParam: refined.endParam, + timeZoneParam: refined.timeZoneParam, + }; + } + return null; + }, + fetch: function (arg, success, failure) { + var meta = arg.eventSource.meta; + var requestParams = buildRequestParams$2(meta, arg.range, arg.context); + requestJson(meta.method, meta.url, requestParams, function (rawEvents, xhr) { + success({ rawEvents: rawEvents, xhr: xhr }); + }, function (errorMessage, xhr) { + failure({ message: errorMessage, xhr: xhr }); + }); + }, + }; + var jsonFeedEventSourcePlugin = createPlugin({ + eventSourceRefiners: JSON_FEED_EVENT_SOURCE_REFINERS, + eventSourceDefs: [eventSourceDef$1], + }); + function buildRequestParams$2(meta, range, context) { + var dateEnv = context.dateEnv, options = context.options; + var startParam; + var endParam; + var timeZoneParam; + var customRequestParams; + var params = {}; + startParam = meta.startParam; + if (startParam == null) { + startParam = options.startParam; + } + endParam = meta.endParam; + if (endParam == null) { + endParam = options.endParam; + } + timeZoneParam = meta.timeZoneParam; + if (timeZoneParam == null) { + timeZoneParam = options.timeZoneParam; + } + // retrieve any outbound GET/POST data from the options + if (typeof meta.extraParams === 'function') { + // supplied as a function that returns a key/value object + customRequestParams = meta.extraParams(); + } + else { + // probably supplied as a straight key/value object + customRequestParams = meta.extraParams || {}; + } + __assign(params, customRequestParams); + params[startParam] = dateEnv.formatIso(range.start); + params[endParam] = dateEnv.formatIso(range.end); + if (dateEnv.timeZone !== 'local') { + params[timeZoneParam] = dateEnv.timeZone; + } + return params; + } + + var SIMPLE_RECURRING_REFINERS = { + daysOfWeek: identity, + startTime: createDuration, + endTime: createDuration, + duration: createDuration, + startRecur: identity, + endRecur: identity, + }; + + var recurring = { + parse: function (refined, dateEnv) { + if (refined.daysOfWeek || refined.startTime || refined.endTime || refined.startRecur || refined.endRecur) { + var recurringData = { + daysOfWeek: refined.daysOfWeek || null, + startTime: refined.startTime || null, + endTime: refined.endTime || null, + startRecur: refined.startRecur ? dateEnv.createMarker(refined.startRecur) : null, + endRecur: refined.endRecur ? dateEnv.createMarker(refined.endRecur) : null, + }; + var duration = void 0; + if (refined.duration) { + duration = refined.duration; + } + if (!duration && refined.startTime && refined.endTime) { + duration = subtractDurations(refined.endTime, refined.startTime); + } + return { + allDayGuess: Boolean(!refined.startTime && !refined.endTime), + duration: duration, + typeData: recurringData, // doesn't need endTime anymore but oh well + }; + } + return null; + }, + expand: function (typeData, framingRange, dateEnv) { + var clippedFramingRange = intersectRanges(framingRange, { start: typeData.startRecur, end: typeData.endRecur }); + if (clippedFramingRange) { + return expandRanges(typeData.daysOfWeek, typeData.startTime, clippedFramingRange, dateEnv); + } + return []; + }, + }; + var simpleRecurringEventsPlugin = createPlugin({ + recurringTypes: [recurring], + eventRefiners: SIMPLE_RECURRING_REFINERS, + }); + function expandRanges(daysOfWeek, startTime, framingRange, dateEnv) { + var dowHash = daysOfWeek ? arrayToHash(daysOfWeek) : null; + var dayMarker = startOfDay(framingRange.start); + var endMarker = framingRange.end; + var instanceStarts = []; + while (dayMarker < endMarker) { + var instanceStart + // if everyday, or this particular day-of-week + = void 0; + // if everyday, or this particular day-of-week + if (!dowHash || dowHash[dayMarker.getUTCDay()]) { + if (startTime) { + instanceStart = dateEnv.add(dayMarker, startTime); + } + else { + instanceStart = dayMarker; + } + instanceStarts.push(instanceStart); + } + dayMarker = addDays(dayMarker, 1); + } + return instanceStarts; + } + + var changeHandlerPlugin = createPlugin({ + optionChangeHandlers: { + events: function (events, context) { + handleEventSources([events], context); + }, + eventSources: handleEventSources, + }, + }); + /* + BUG: if `event` was supplied, all previously-given `eventSources` will be wiped out + */ + function handleEventSources(inputs, context) { + var unfoundSources = hashValuesToArray(context.getCurrentData().eventSources); + var newInputs = []; + for (var _i = 0, inputs_1 = inputs; _i < inputs_1.length; _i++) { + var input = inputs_1[_i]; + var inputFound = false; + for (var i = 0; i < unfoundSources.length; i += 1) { + if (unfoundSources[i]._raw === input) { + unfoundSources.splice(i, 1); // delete + inputFound = true; + break; + } + } + if (!inputFound) { + newInputs.push(input); + } + } + for (var _a = 0, unfoundSources_1 = unfoundSources; _a < unfoundSources_1.length; _a++) { + var unfoundSource = unfoundSources_1[_a]; + context.dispatch({ + type: 'REMOVE_EVENT_SOURCE', + sourceId: unfoundSource.sourceId, + }); + } + for (var _b = 0, newInputs_1 = newInputs; _b < newInputs_1.length; _b++) { + var newInput = newInputs_1[_b]; + context.calendarApi.addEventSource(newInput); + } + } + + function handleDateProfile(dateProfile, context) { + context.emitter.trigger('datesSet', __assign(__assign({}, buildRangeApiWithTimeZone(dateProfile.activeRange, context.dateEnv)), { view: context.viewApi })); + } + + function handleEventStore(eventStore, context) { + var emitter = context.emitter; + if (emitter.hasHandlers('eventsSet')) { + emitter.trigger('eventsSet', buildEventApis(eventStore, context)); + } + } + + /* + this array is exposed on the root namespace so that UMD plugins can add to it. + see the rollup-bundles script. + */ + var globalPlugins = [ + arrayEventSourcePlugin, + funcEventSourcePlugin, + jsonFeedEventSourcePlugin, + simpleRecurringEventsPlugin, + changeHandlerPlugin, + createPlugin({ + isLoadingFuncs: [ + function (state) { return computeEventSourcesLoading(state.eventSources); }, + ], + contentTypeHandlers: { + html: function () { return ({ render: injectHtml }); }, + domNodes: function () { return ({ render: injectDomNodes }); }, + }, + propSetHandlers: { + dateProfile: handleDateProfile, + eventStore: handleEventStore, + }, + }), + ]; + function injectHtml(el, html) { + el.innerHTML = html; + } + function injectDomNodes(el, domNodes) { + var oldNodes = Array.prototype.slice.call(el.childNodes); // TODO: use array util + var newNodes = Array.prototype.slice.call(domNodes); // TODO: use array util + if (!isArraysEqual(oldNodes, newNodes)) { + for (var _i = 0, newNodes_1 = newNodes; _i < newNodes_1.length; _i++) { + var newNode = newNodes_1[_i]; + el.appendChild(newNode); + } + oldNodes.forEach(removeElement); + } + } + + var DelayedRunner = /** @class */ (function () { + function DelayedRunner(drainedOption) { + this.drainedOption = drainedOption; + this.isRunning = false; + this.isDirty = false; + this.pauseDepths = {}; + this.timeoutId = 0; + } + DelayedRunner.prototype.request = function (delay) { + this.isDirty = true; + if (!this.isPaused()) { + this.clearTimeout(); + if (delay == null) { + this.tryDrain(); + } + else { + this.timeoutId = setTimeout(// NOT OPTIMAL! TODO: look at debounce + this.tryDrain.bind(this), delay); + } + } + }; + DelayedRunner.prototype.pause = function (scope) { + if (scope === void 0) { scope = ''; } + var pauseDepths = this.pauseDepths; + pauseDepths[scope] = (pauseDepths[scope] || 0) + 1; + this.clearTimeout(); + }; + DelayedRunner.prototype.resume = function (scope, force) { + if (scope === void 0) { scope = ''; } + var pauseDepths = this.pauseDepths; + if (scope in pauseDepths) { + if (force) { + delete pauseDepths[scope]; + } + else { + pauseDepths[scope] -= 1; + var depth = pauseDepths[scope]; + if (depth <= 0) { + delete pauseDepths[scope]; + } + } + this.tryDrain(); + } + }; + DelayedRunner.prototype.isPaused = function () { + return Object.keys(this.pauseDepths).length; + }; + DelayedRunner.prototype.tryDrain = function () { + if (!this.isRunning && !this.isPaused()) { + this.isRunning = true; + while (this.isDirty) { + this.isDirty = false; + this.drained(); // might set isDirty to true again + } + this.isRunning = false; + } + }; + DelayedRunner.prototype.clear = function () { + this.clearTimeout(); + this.isDirty = false; + this.pauseDepths = {}; + }; + DelayedRunner.prototype.clearTimeout = function () { + if (this.timeoutId) { + clearTimeout(this.timeoutId); + this.timeoutId = 0; + } + }; + DelayedRunner.prototype.drained = function () { + if (this.drainedOption) { + this.drainedOption(); + } + }; + return DelayedRunner; + }()); + + var TaskRunner = /** @class */ (function () { + function TaskRunner(runTaskOption, drainedOption) { + this.runTaskOption = runTaskOption; + this.drainedOption = drainedOption; + this.queue = []; + this.delayedRunner = new DelayedRunner(this.drain.bind(this)); + } + TaskRunner.prototype.request = function (task, delay) { + this.queue.push(task); + this.delayedRunner.request(delay); + }; + TaskRunner.prototype.pause = function (scope) { + this.delayedRunner.pause(scope); + }; + TaskRunner.prototype.resume = function (scope, force) { + this.delayedRunner.resume(scope, force); + }; + TaskRunner.prototype.drain = function () { + var queue = this.queue; + while (queue.length) { + var completedTasks = []; + var task = void 0; + while ((task = queue.shift())) { + this.runTask(task); + completedTasks.push(task); + } + this.drained(completedTasks); + } // keep going, in case new tasks were added in the drained handler + }; + TaskRunner.prototype.runTask = function (task) { + if (this.runTaskOption) { + this.runTaskOption(task); + } + }; + TaskRunner.prototype.drained = function (completedTasks) { + if (this.drainedOption) { + this.drainedOption(completedTasks); + } + }; + return TaskRunner; + }()); + + // Computes what the title at the top of the calendarApi should be for this view + function buildTitle(dateProfile, viewOptions, dateEnv) { + var range; + // for views that span a large unit of time, show the proper interval, ignoring stray days before and after + if (/^(year|month)$/.test(dateProfile.currentRangeUnit)) { + range = dateProfile.currentRange; + } + else { // for day units or smaller, use the actual day range + range = dateProfile.activeRange; + } + return dateEnv.formatRange(range.start, range.end, createFormatter(viewOptions.titleFormat || buildTitleFormat(dateProfile)), { + isEndExclusive: dateProfile.isRangeAllDay, + defaultSeparator: viewOptions.titleRangeSeparator, + }); + } + // Generates the format string that should be used to generate the title for the current date range. + // Attempts to compute the most appropriate format if not explicitly specified with `titleFormat`. + function buildTitleFormat(dateProfile) { + var currentRangeUnit = dateProfile.currentRangeUnit; + if (currentRangeUnit === 'year') { + return { year: 'numeric' }; + } + if (currentRangeUnit === 'month') { + return { year: 'numeric', month: 'long' }; // like "September 2014" + } + var days = diffWholeDays(dateProfile.currentRange.start, dateProfile.currentRange.end); + if (days !== null && days > 1) { + // multi-day range. shorter, like "Sep 9 - 10 2014" + return { year: 'numeric', month: 'short', day: 'numeric' }; + } + // one day. longer, like "September 9 2014" + return { year: 'numeric', month: 'long', day: 'numeric' }; + } + + // in future refactor, do the redux-style function(state=initial) for initial-state + // also, whatever is happening in constructor, have it happen in action queue too + var CalendarDataManager = /** @class */ (function () { + function CalendarDataManager(props) { + var _this = this; + this.computeOptionsData = memoize(this._computeOptionsData); + this.computeCurrentViewData = memoize(this._computeCurrentViewData); + this.organizeRawLocales = memoize(organizeRawLocales); + this.buildLocale = memoize(buildLocale); + this.buildPluginHooks = buildBuildPluginHooks(); + this.buildDateEnv = memoize(buildDateEnv); + this.buildTheme = memoize(buildTheme); + this.parseToolbars = memoize(parseToolbars); + this.buildViewSpecs = memoize(buildViewSpecs); + this.buildDateProfileGenerator = memoizeObjArg(buildDateProfileGenerator); + this.buildViewApi = memoize(buildViewApi); + this.buildViewUiProps = memoizeObjArg(buildViewUiProps); + this.buildEventUiBySource = memoize(buildEventUiBySource, isPropsEqual); + this.buildEventUiBases = memoize(buildEventUiBases); + this.parseContextBusinessHours = memoizeObjArg(parseContextBusinessHours); + this.buildTitle = memoize(buildTitle); + this.emitter = new Emitter(); + this.actionRunner = new TaskRunner(this._handleAction.bind(this), this.updateData.bind(this)); + this.currentCalendarOptionsInput = {}; + this.currentCalendarOptionsRefined = {}; + this.currentViewOptionsInput = {}; + this.currentViewOptionsRefined = {}; + this.currentCalendarOptionsRefiners = {}; + this.getCurrentData = function () { return _this.data; }; + this.dispatch = function (action) { + _this.actionRunner.request(action); // protects against recursive calls to _handleAction + }; + this.props = props; + this.actionRunner.pause(); + var dynamicOptionOverrides = {}; + var optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi); + var currentViewType = optionsData.calendarOptions.initialView || optionsData.pluginHooks.initialView; + var currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides); + // wire things up + // TODO: not DRY + props.calendarApi.currentDataManager = this; + this.emitter.setThisContext(props.calendarApi); + this.emitter.setOptions(currentViewData.options); + var currentDate = getInitialDate(optionsData.calendarOptions, optionsData.dateEnv); + var dateProfile = currentViewData.dateProfileGenerator.build(currentDate); + if (!rangeContainsMarker(dateProfile.activeRange, currentDate)) { + currentDate = dateProfile.currentRange.start; + } + var calendarContext = { + dateEnv: optionsData.dateEnv, + options: optionsData.calendarOptions, + pluginHooks: optionsData.pluginHooks, + calendarApi: props.calendarApi, + dispatch: this.dispatch, + emitter: this.emitter, + getCurrentData: this.getCurrentData, + }; + // needs to be after setThisContext + for (var _i = 0, _a = optionsData.pluginHooks.contextInit; _i < _a.length; _i++) { + var callback = _a[_i]; + callback(calendarContext); + } + // NOT DRY + var eventSources = initEventSources(optionsData.calendarOptions, dateProfile, calendarContext); + var initialState = { + dynamicOptionOverrides: dynamicOptionOverrides, + currentViewType: currentViewType, + currentDate: currentDate, + dateProfile: dateProfile, + businessHours: this.parseContextBusinessHours(calendarContext), + eventSources: eventSources, + eventUiBases: {}, + eventStore: createEmptyEventStore(), + renderableEventStore: createEmptyEventStore(), + dateSelection: null, + eventSelection: '', + eventDrag: null, + eventResize: null, + selectionConfig: this.buildViewUiProps(calendarContext).selectionConfig, + }; + var contextAndState = __assign(__assign({}, calendarContext), initialState); + for (var _b = 0, _c = optionsData.pluginHooks.reducers; _b < _c.length; _b++) { + var reducer = _c[_b]; + __assign(initialState, reducer(null, null, contextAndState)); + } + if (computeIsLoading(initialState, calendarContext)) { + this.emitter.trigger('loading', true); // NOT DRY + } + this.state = initialState; + this.updateData(); + this.actionRunner.resume(); + } + CalendarDataManager.prototype.resetOptions = function (optionOverrides, append) { + var props = this.props; + props.optionOverrides = append + ? __assign(__assign({}, props.optionOverrides), optionOverrides) : optionOverrides; + this.actionRunner.request({ + type: 'NOTHING', + }); + }; + CalendarDataManager.prototype._handleAction = function (action) { + var _a = this, props = _a.props, state = _a.state, emitter = _a.emitter; + var dynamicOptionOverrides = reduceDynamicOptionOverrides(state.dynamicOptionOverrides, action); + var optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi); + var currentViewType = reduceViewType(state.currentViewType, action); + var currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides); + // wire things up + // TODO: not DRY + props.calendarApi.currentDataManager = this; + emitter.setThisContext(props.calendarApi); + emitter.setOptions(currentViewData.options); + var calendarContext = { + dateEnv: optionsData.dateEnv, + options: optionsData.calendarOptions, + pluginHooks: optionsData.pluginHooks, + calendarApi: props.calendarApi, + dispatch: this.dispatch, + emitter: emitter, + getCurrentData: this.getCurrentData, + }; + var currentDate = state.currentDate, dateProfile = state.dateProfile; + if (this.data && this.data.dateProfileGenerator !== currentViewData.dateProfileGenerator) { // hack + dateProfile = currentViewData.dateProfileGenerator.build(currentDate); + } + currentDate = reduceCurrentDate(currentDate, action); + dateProfile = reduceDateProfile(dateProfile, action, currentDate, currentViewData.dateProfileGenerator); + if (action.type === 'PREV' || // TODO: move this logic into DateProfileGenerator + action.type === 'NEXT' || // " + !rangeContainsMarker(dateProfile.currentRange, currentDate)) { + currentDate = dateProfile.currentRange.start; + } + var eventSources = reduceEventSources(state.eventSources, action, dateProfile, calendarContext); + var eventStore = reduceEventStore(state.eventStore, action, eventSources, dateProfile, calendarContext); + var isEventsLoading = computeEventSourcesLoading(eventSources); // BAD. also called in this func in computeIsLoading + var renderableEventStore = (isEventsLoading && !currentViewData.options.progressiveEventRendering) ? + (state.renderableEventStore || eventStore) : // try from previous state + eventStore; + var _b = this.buildViewUiProps(calendarContext), eventUiSingleBase = _b.eventUiSingleBase, selectionConfig = _b.selectionConfig; // will memoize obj + var eventUiBySource = this.buildEventUiBySource(eventSources); + var eventUiBases = this.buildEventUiBases(renderableEventStore.defs, eventUiSingleBase, eventUiBySource); + var newState = { + dynamicOptionOverrides: dynamicOptionOverrides, + currentViewType: currentViewType, + currentDate: currentDate, + dateProfile: dateProfile, + eventSources: eventSources, + eventStore: eventStore, + renderableEventStore: renderableEventStore, + selectionConfig: selectionConfig, + eventUiBases: eventUiBases, + businessHours: this.parseContextBusinessHours(calendarContext), + dateSelection: reduceDateSelection(state.dateSelection, action), + eventSelection: reduceSelectedEvent(state.eventSelection, action), + eventDrag: reduceEventDrag(state.eventDrag, action), + eventResize: reduceEventResize(state.eventResize, action), + }; + var contextAndState = __assign(__assign({}, calendarContext), newState); + for (var _i = 0, _c = optionsData.pluginHooks.reducers; _i < _c.length; _i++) { + var reducer = _c[_i]; + __assign(newState, reducer(state, action, contextAndState)); // give the OLD state, for old value + } + var wasLoading = computeIsLoading(state, calendarContext); + var isLoading = computeIsLoading(newState, calendarContext); + // TODO: use propSetHandlers in plugin system + if (!wasLoading && isLoading) { + emitter.trigger('loading', true); + } + else if (wasLoading && !isLoading) { + emitter.trigger('loading', false); + } + this.state = newState; + if (props.onAction) { + props.onAction(action); + } + }; + CalendarDataManager.prototype.updateData = function () { + var _a = this, props = _a.props, state = _a.state; + var oldData = this.data; + var optionsData = this.computeOptionsData(props.optionOverrides, state.dynamicOptionOverrides, props.calendarApi); + var currentViewData = this.computeCurrentViewData(state.currentViewType, optionsData, props.optionOverrides, state.dynamicOptionOverrides); + var data = this.data = __assign(__assign(__assign({ viewTitle: this.buildTitle(state.dateProfile, currentViewData.options, optionsData.dateEnv), calendarApi: props.calendarApi, dispatch: this.dispatch, emitter: this.emitter, getCurrentData: this.getCurrentData }, optionsData), currentViewData), state); + var changeHandlers = optionsData.pluginHooks.optionChangeHandlers; + var oldCalendarOptions = oldData && oldData.calendarOptions; + var newCalendarOptions = optionsData.calendarOptions; + if (oldCalendarOptions && oldCalendarOptions !== newCalendarOptions) { + if (oldCalendarOptions.timeZone !== newCalendarOptions.timeZone) { + // hack + state.eventSources = data.eventSources = reduceEventSourcesNewTimeZone(data.eventSources, state.dateProfile, data); + state.eventStore = data.eventStore = rezoneEventStoreDates(data.eventStore, oldData.dateEnv, data.dateEnv); + } + for (var optionName in changeHandlers) { + if (oldCalendarOptions[optionName] !== newCalendarOptions[optionName]) { + changeHandlers[optionName](newCalendarOptions[optionName], data); + } + } + } + if (props.onData) { + props.onData(data); + } + }; + CalendarDataManager.prototype._computeOptionsData = function (optionOverrides, dynamicOptionOverrides, calendarApi) { + // TODO: blacklist options that are handled by optionChangeHandlers + var _a = this.processRawCalendarOptions(optionOverrides, dynamicOptionOverrides), refinedOptions = _a.refinedOptions, pluginHooks = _a.pluginHooks, localeDefaults = _a.localeDefaults, availableLocaleData = _a.availableLocaleData, extra = _a.extra; + warnUnknownOptions(extra); + var dateEnv = this.buildDateEnv(refinedOptions.timeZone, refinedOptions.locale, refinedOptions.weekNumberCalculation, refinedOptions.firstDay, refinedOptions.weekText, pluginHooks, availableLocaleData, refinedOptions.defaultRangeSeparator); + var viewSpecs = this.buildViewSpecs(pluginHooks.views, optionOverrides, dynamicOptionOverrides, localeDefaults); + var theme = this.buildTheme(refinedOptions, pluginHooks); + var toolbarConfig = this.parseToolbars(refinedOptions, optionOverrides, theme, viewSpecs, calendarApi); + return { + calendarOptions: refinedOptions, + pluginHooks: pluginHooks, + dateEnv: dateEnv, + viewSpecs: viewSpecs, + theme: theme, + toolbarConfig: toolbarConfig, + localeDefaults: localeDefaults, + availableRawLocales: availableLocaleData.map, + }; + }; + // always called from behind a memoizer + CalendarDataManager.prototype.processRawCalendarOptions = function (optionOverrides, dynamicOptionOverrides) { + var _a = mergeRawOptions([ + BASE_OPTION_DEFAULTS, + optionOverrides, + dynamicOptionOverrides, + ]), locales = _a.locales, locale = _a.locale; + var availableLocaleData = this.organizeRawLocales(locales); + var availableRawLocales = availableLocaleData.map; + var localeDefaults = this.buildLocale(locale || availableLocaleData.defaultCode, availableRawLocales).options; + var pluginHooks = this.buildPluginHooks(optionOverrides.plugins || [], globalPlugins); + var refiners = this.currentCalendarOptionsRefiners = __assign(__assign(__assign(__assign(__assign({}, BASE_OPTION_REFINERS), CALENDAR_LISTENER_REFINERS), CALENDAR_OPTION_REFINERS), pluginHooks.listenerRefiners), pluginHooks.optionRefiners); + var extra = {}; + var raw = mergeRawOptions([ + BASE_OPTION_DEFAULTS, + localeDefaults, + optionOverrides, + dynamicOptionOverrides, + ]); + var refined = {}; + var currentRaw = this.currentCalendarOptionsInput; + var currentRefined = this.currentCalendarOptionsRefined; + var anyChanges = false; + for (var optionName in raw) { + if (optionName !== 'plugins') { // because plugins is special-cased + if (raw[optionName] === currentRaw[optionName] || + (COMPLEX_OPTION_COMPARATORS[optionName] && + (optionName in currentRaw) && + COMPLEX_OPTION_COMPARATORS[optionName](currentRaw[optionName], raw[optionName]))) { + refined[optionName] = currentRefined[optionName]; + } + else if (refiners[optionName]) { + refined[optionName] = refiners[optionName](raw[optionName]); + anyChanges = true; + } + else { + extra[optionName] = currentRaw[optionName]; + } + } + } + if (anyChanges) { + this.currentCalendarOptionsInput = raw; + this.currentCalendarOptionsRefined = refined; + } + return { + rawOptions: this.currentCalendarOptionsInput, + refinedOptions: this.currentCalendarOptionsRefined, + pluginHooks: pluginHooks, + availableLocaleData: availableLocaleData, + localeDefaults: localeDefaults, + extra: extra, + }; + }; + CalendarDataManager.prototype._computeCurrentViewData = function (viewType, optionsData, optionOverrides, dynamicOptionOverrides) { + var viewSpec = optionsData.viewSpecs[viewType]; + if (!viewSpec) { + throw new Error("viewType \"" + viewType + "\" is not available. Please make sure you've loaded all neccessary plugins"); + } + var _a = this.processRawViewOptions(viewSpec, optionsData.pluginHooks, optionsData.localeDefaults, optionOverrides, dynamicOptionOverrides), refinedOptions = _a.refinedOptions, extra = _a.extra; + warnUnknownOptions(extra); + var dateProfileGenerator = this.buildDateProfileGenerator({ + dateProfileGeneratorClass: viewSpec.optionDefaults.dateProfileGeneratorClass, + duration: viewSpec.duration, + durationUnit: viewSpec.durationUnit, + usesMinMaxTime: viewSpec.optionDefaults.usesMinMaxTime, + dateEnv: optionsData.dateEnv, + calendarApi: this.props.calendarApi, + slotMinTime: refinedOptions.slotMinTime, + slotMaxTime: refinedOptions.slotMaxTime, + showNonCurrentDates: refinedOptions.showNonCurrentDates, + dayCount: refinedOptions.dayCount, + dateAlignment: refinedOptions.dateAlignment, + dateIncrement: refinedOptions.dateIncrement, + hiddenDays: refinedOptions.hiddenDays, + weekends: refinedOptions.weekends, + nowInput: refinedOptions.now, + validRangeInput: refinedOptions.validRange, + visibleRangeInput: refinedOptions.visibleRange, + monthMode: refinedOptions.monthMode, + fixedWeekCount: refinedOptions.fixedWeekCount, + }); + var viewApi = this.buildViewApi(viewType, this.getCurrentData, optionsData.dateEnv); + return { viewSpec: viewSpec, options: refinedOptions, dateProfileGenerator: dateProfileGenerator, viewApi: viewApi }; + }; + CalendarDataManager.prototype.processRawViewOptions = function (viewSpec, pluginHooks, localeDefaults, optionOverrides, dynamicOptionOverrides) { + var raw = mergeRawOptions([ + BASE_OPTION_DEFAULTS, + viewSpec.optionDefaults, + localeDefaults, + optionOverrides, + viewSpec.optionOverrides, + dynamicOptionOverrides, + ]); + var refiners = __assign(__assign(__assign(__assign(__assign(__assign({}, BASE_OPTION_REFINERS), CALENDAR_LISTENER_REFINERS), CALENDAR_OPTION_REFINERS), VIEW_OPTION_REFINERS), pluginHooks.listenerRefiners), pluginHooks.optionRefiners); + var refined = {}; + var currentRaw = this.currentViewOptionsInput; + var currentRefined = this.currentViewOptionsRefined; + var anyChanges = false; + var extra = {}; + for (var optionName in raw) { + if (raw[optionName] === currentRaw[optionName]) { + refined[optionName] = currentRefined[optionName]; + } + else { + if (raw[optionName] === this.currentCalendarOptionsInput[optionName]) { + if (optionName in this.currentCalendarOptionsRefined) { // might be an "extra" prop + refined[optionName] = this.currentCalendarOptionsRefined[optionName]; + } + } + else if (refiners[optionName]) { + refined[optionName] = refiners[optionName](raw[optionName]); + } + else { + extra[optionName] = raw[optionName]; + } + anyChanges = true; + } + } + if (anyChanges) { + this.currentViewOptionsInput = raw; + this.currentViewOptionsRefined = refined; + } + return { + rawOptions: this.currentViewOptionsInput, + refinedOptions: this.currentViewOptionsRefined, + extra: extra, + }; + }; + return CalendarDataManager; + }()); + function buildDateEnv(timeZone, explicitLocale, weekNumberCalculation, firstDay, weekText, pluginHooks, availableLocaleData, defaultSeparator) { + var locale = buildLocale(explicitLocale || availableLocaleData.defaultCode, availableLocaleData.map); + return new DateEnv({ + calendarSystem: 'gregory', + timeZone: timeZone, + namedTimeZoneImpl: pluginHooks.namedTimeZonedImpl, + locale: locale, + weekNumberCalculation: weekNumberCalculation, + firstDay: firstDay, + weekText: weekText, + cmdFormatter: pluginHooks.cmdFormatter, + defaultSeparator: defaultSeparator, + }); + } + function buildTheme(options, pluginHooks) { + var ThemeClass = pluginHooks.themeClasses[options.themeSystem] || StandardTheme; + return new ThemeClass(options); + } + function buildDateProfileGenerator(props) { + var DateProfileGeneratorClass = props.dateProfileGeneratorClass || DateProfileGenerator; + return new DateProfileGeneratorClass(props); + } + function buildViewApi(type, getCurrentData, dateEnv) { + return new ViewApi(type, getCurrentData, dateEnv); + } + function buildEventUiBySource(eventSources) { + return mapHash(eventSources, function (eventSource) { return eventSource.ui; }); + } + function buildEventUiBases(eventDefs, eventUiSingleBase, eventUiBySource) { + var eventUiBases = { '': eventUiSingleBase }; + for (var defId in eventDefs) { + var def = eventDefs[defId]; + if (def.sourceId && eventUiBySource[def.sourceId]) { + eventUiBases[defId] = eventUiBySource[def.sourceId]; + } + } + return eventUiBases; + } + function buildViewUiProps(calendarContext) { + var options = calendarContext.options; + return { + eventUiSingleBase: createEventUi({ + display: options.eventDisplay, + editable: options.editable, + startEditable: options.eventStartEditable, + durationEditable: options.eventDurationEditable, + constraint: options.eventConstraint, + overlap: typeof options.eventOverlap === 'boolean' ? options.eventOverlap : undefined, + allow: options.eventAllow, + backgroundColor: options.eventBackgroundColor, + borderColor: options.eventBorderColor, + textColor: options.eventTextColor, + color: options.eventColor, + // classNames: options.eventClassNames // render hook will handle this + }, calendarContext), + selectionConfig: createEventUi({ + constraint: options.selectConstraint, + overlap: typeof options.selectOverlap === 'boolean' ? options.selectOverlap : undefined, + allow: options.selectAllow, + }, calendarContext), + }; + } + function computeIsLoading(state, context) { + for (var _i = 0, _a = context.pluginHooks.isLoadingFuncs; _i < _a.length; _i++) { + var isLoadingFunc = _a[_i]; + if (isLoadingFunc(state)) { + return true; + } + } + return false; + } + function parseContextBusinessHours(calendarContext) { + return parseBusinessHours(calendarContext.options.businessHours, calendarContext); + } + function warnUnknownOptions(options, viewName) { + for (var optionName in options) { + console.warn("Unknown option '" + optionName + "'" + + (viewName ? " for view '" + viewName + "'" : '')); + } + } + + // TODO: move this to react plugin? + var CalendarDataProvider = /** @class */ (function (_super) { + __extends(CalendarDataProvider, _super); + function CalendarDataProvider(props) { + var _this = _super.call(this, props) || this; + _this.handleData = function (data) { + if (!_this.dataManager) { // still within initial run, before assignment in constructor + // eslint-disable-next-line react/no-direct-mutation-state + _this.state = data; // can't use setState yet + } + else { + _this.setState(data); + } + }; + _this.dataManager = new CalendarDataManager({ + optionOverrides: props.optionOverrides, + calendarApi: props.calendarApi, + onData: _this.handleData, + }); + return _this; + } + CalendarDataProvider.prototype.render = function () { + return this.props.children(this.state); + }; + CalendarDataProvider.prototype.componentDidUpdate = function (prevProps) { + var newOptionOverrides = this.props.optionOverrides; + if (newOptionOverrides !== prevProps.optionOverrides) { // prevent recursive handleData + this.dataManager.resetOptions(newOptionOverrides); + } + }; + return CalendarDataProvider; + }(Component)); + + // HELPERS + /* + if nextDayThreshold is specified, slicing is done in an all-day fashion. + you can get nextDayThreshold from context.nextDayThreshold + */ + function sliceEvents(props, allDay) { + return sliceEventStore(props.eventStore, props.eventUiBases, props.dateProfile.activeRange, allDay ? props.nextDayThreshold : null).fg; + } + + var NamedTimeZoneImpl = /** @class */ (function () { + function NamedTimeZoneImpl(timeZoneName) { + this.timeZoneName = timeZoneName; + } + return NamedTimeZoneImpl; + }()); + + var SegHierarchy = /** @class */ (function () { + function SegHierarchy() { + // settings + this.strictOrder = false; + this.allowReslicing = false; + this.maxCoord = -1; // -1 means no max + this.maxStackCnt = -1; // -1 means no max + this.levelCoords = []; // ordered + this.entriesByLevel = []; // parallel with levelCoords + this.stackCnts = {}; // TODO: use better technique!? + } + SegHierarchy.prototype.addSegs = function (inputs) { + var hiddenEntries = []; + for (var _i = 0, inputs_1 = inputs; _i < inputs_1.length; _i++) { + var input = inputs_1[_i]; + this.insertEntry(input, hiddenEntries); + } + return hiddenEntries; + }; + SegHierarchy.prototype.insertEntry = function (entry, hiddenEntries) { + var insertion = this.findInsertion(entry); + if (this.isInsertionValid(insertion, entry)) { + this.insertEntryAt(entry, insertion); + return 1; + } + return this.handleInvalidInsertion(insertion, entry, hiddenEntries); + }; + SegHierarchy.prototype.isInsertionValid = function (insertion, entry) { + return (this.maxCoord === -1 || insertion.levelCoord + entry.thickness <= this.maxCoord) && + (this.maxStackCnt === -1 || insertion.stackCnt < this.maxStackCnt); + }; + // returns number of new entries inserted + SegHierarchy.prototype.handleInvalidInsertion = function (insertion, entry, hiddenEntries) { + if (this.allowReslicing && insertion.touchingEntry) { + return this.splitEntry(entry, insertion.touchingEntry, hiddenEntries); + } + hiddenEntries.push(entry); + return 0; + }; + SegHierarchy.prototype.splitEntry = function (entry, barrier, hiddenEntries) { + var partCnt = 0; + var splitHiddenEntries = []; + var entrySpan = entry.span; + var barrierSpan = barrier.span; + if (entrySpan.start < barrierSpan.start) { + partCnt += this.insertEntry({ + index: entry.index, + thickness: entry.thickness, + span: { start: entrySpan.start, end: barrierSpan.start }, + }, splitHiddenEntries); + } + if (entrySpan.end > barrierSpan.end) { + partCnt += this.insertEntry({ + index: entry.index, + thickness: entry.thickness, + span: { start: barrierSpan.end, end: entrySpan.end }, + }, splitHiddenEntries); + } + if (partCnt) { + hiddenEntries.push.apply(hiddenEntries, __spreadArray([{ + index: entry.index, + thickness: entry.thickness, + span: intersectSpans(barrierSpan, entrySpan), // guaranteed to intersect + }], splitHiddenEntries)); + return partCnt; + } + hiddenEntries.push(entry); + return 0; + }; + SegHierarchy.prototype.insertEntryAt = function (entry, insertion) { + var _a = this, entriesByLevel = _a.entriesByLevel, levelCoords = _a.levelCoords; + var destLevel = insertion.level; + if (destLevel >= levelCoords.length || // level doesn't exist yet + levelCoords[destLevel] > insertion.levelCoord // destLevel needs to be pushed forward to make way + ) { + // create a new level + insertAt(levelCoords, destLevel, insertion.levelCoord); + insertAt(entriesByLevel, destLevel, [entry]); + } + else { + // insert into existing level + insertAt(entriesByLevel[destLevel], insertion.lateralEnd, entry); + } + this.stackCnts[buildEntryKey(entry)] = insertion.stackCnt; + }; + SegHierarchy.prototype.findInsertion = function (newEntry) { + var _a = this, levelCoords = _a.levelCoords, entriesByLevel = _a.entriesByLevel, stackCnts = _a.stackCnts, strictOrder = _a.strictOrder; + var levelCnt = levelCoords.length; + var resLevelCoord = 0; + var resLevel = 0; + var lateralStart = 0; + var lateralEnd = 0; + var touchingLevel = -1; + var touchingEntry = null; // last touch entry + for (var level = 0; level < levelCnt; level += 1) { + var levelCoord = levelCoords[level]; + // if the current level is past the placed entry, we have found a good empty space and can stop. + // if strictOrder, keep finding more lateral intersections. + if (!strictOrder && levelCoord >= resLevelCoord + newEntry.thickness) { + break; + } + var entries = entriesByLevel[level]; + var entry = void 0; + var searchRes = binarySearch(entries, newEntry.span.start, getEntrySpanEnd); + lateralStart = searchRes[0] + searchRes[1]; // if exact match (which doesn't collide), go to next one + lateralEnd = lateralStart; // also functions as a moving index + while ( // loop through entries that horizontally intersect + (entry = entries[lateralEnd]) && // but not past the whole entry list + entry.span.start < newEntry.span.end // and not entirely past newEntry + ) { + if (strictOrder || // strict-mode doesn't care about vert intersection. record touch and keep pushing down + ( // vertically intersects? + resLevelCoord < levelCoord + entry.thickness && + resLevelCoord + newEntry.thickness > levelCoord)) { + // push down the potential destination + resLevelCoord = levelCoord + entry.thickness; // move to bottom of colliding entry + touchingLevel = level; + touchingEntry = entry; + } + lateralEnd += 1; + } + // regardless of whether there were collisions in the current level, + // keep updating the final-destination level until it goes past the final-destination coord. + if (levelCoord < resLevelCoord) { + resLevel = level + 1; + } + } + return { + level: resLevel, + levelCoord: resLevelCoord, + lateralStart: lateralStart, + lateralEnd: lateralEnd, + touchingLevel: touchingLevel, + touchingEntry: touchingEntry, + stackCnt: touchingEntry ? stackCnts[buildEntryKey(touchingEntry)] + 1 : 0, + }; + }; + // sorted by levelCoord (lowest to highest) + SegHierarchy.prototype.toRects = function () { + var _a = this, entriesByLevel = _a.entriesByLevel, levelCoords = _a.levelCoords; + var levelCnt = entriesByLevel.length; + var rects = []; + for (var level = 0; level < levelCnt; level += 1) { + var entries = entriesByLevel[level]; + var levelCoord = levelCoords[level]; + for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) { + var entry = entries_1[_i]; + rects.push(__assign(__assign({}, entry), { levelCoord: levelCoord })); + } + } + return rects; + }; + return SegHierarchy; + }()); + function getEntrySpanEnd(entry) { + return entry.span.end; + } + function buildEntryKey(entry) { + return entry.index + ':' + entry.span.start; + } + // returns groups with entries sorted by input order + function groupIntersectingEntries(entries) { + var merges = []; + for (var _i = 0, entries_2 = entries; _i < entries_2.length; _i++) { + var entry = entries_2[_i]; + var filteredMerges = []; + var hungryMerge = { + span: entry.span, + entries: [entry], + }; + for (var _a = 0, merges_1 = merges; _a < merges_1.length; _a++) { + var merge = merges_1[_a]; + if (intersectSpans(merge.span, hungryMerge.span)) { + hungryMerge = { + entries: merge.entries.concat(hungryMerge.entries), + span: joinSpans(merge.span, hungryMerge.span), + }; + } + else { + filteredMerges.push(merge); + } + } + filteredMerges.push(hungryMerge); + merges = filteredMerges; + } + return merges; + } + function joinSpans(span0, span1) { + return { + start: Math.min(span0.start, span1.start), + end: Math.max(span0.end, span1.end), + }; + } + function intersectSpans(span0, span1) { + var start = Math.max(span0.start, span1.start); + var end = Math.min(span0.end, span1.end); + if (start < end) { + return { start: start, end: end }; + } + return null; + } + // general util + // --------------------------------------------------------------------------------------------------------------------- + function insertAt(arr, index, item) { + arr.splice(index, 0, item); + } + function binarySearch(a, searchVal, getItemVal) { + var startIndex = 0; + var endIndex = a.length; // exclusive + if (!endIndex || searchVal < getItemVal(a[startIndex])) { // no items OR before first item + return [0, 0]; + } + if (searchVal > getItemVal(a[endIndex - 1])) { // after last item + return [endIndex, 0]; + } + while (startIndex < endIndex) { + var middleIndex = Math.floor(startIndex + (endIndex - startIndex) / 2); + var middleVal = getItemVal(a[middleIndex]); + if (searchVal < middleVal) { + endIndex = middleIndex; + } + else if (searchVal > middleVal) { + startIndex = middleIndex + 1; + } + else { // equal! + return [middleIndex, 1]; + } + } + return [startIndex, 0]; + } + + var Interaction = /** @class */ (function () { + function Interaction(settings) { + this.component = settings.component; + this.isHitComboAllowed = settings.isHitComboAllowed || null; + } + Interaction.prototype.destroy = function () { + }; + return Interaction; + }()); + function parseInteractionSettings(component, input) { + return { + component: component, + el: input.el, + useEventCenter: input.useEventCenter != null ? input.useEventCenter : true, + isHitComboAllowed: input.isHitComboAllowed || null, + }; + } + function interactionSettingsToStore(settings) { + var _a; + return _a = {}, + _a[settings.component.uid] = settings, + _a; + } + // global state + var interactionSettingsStore = {}; + + /* + An abstraction for a dragging interaction originating on an event. + Does higher-level things than PointerDragger, such as possibly: + - a "mirror" that moves with the pointer + - a minimum number of pixels or other criteria for a true drag to begin + + subclasses must emit: + - pointerdown + - dragstart + - dragmove + - pointerup + - dragend + */ + var ElementDragging = /** @class */ (function () { + function ElementDragging(el, selector) { + this.emitter = new Emitter(); + } + ElementDragging.prototype.destroy = function () { + }; + ElementDragging.prototype.setMirrorIsVisible = function (bool) { + // optional if subclass doesn't want to support a mirror + }; + ElementDragging.prototype.setMirrorNeedsRevert = function (bool) { + // optional if subclass doesn't want to support a mirror + }; + ElementDragging.prototype.setAutoScrollEnabled = function (bool) { + // optional + }; + return ElementDragging; + }()); + + // TODO: get rid of this in favor of options system, + // tho it's really easy to access this globally rather than pass thru options. + var config = {}; + + /* + Information about what will happen when an external element is dragged-and-dropped + onto a calendar. Contains information for creating an event. + */ + var DRAG_META_REFINERS = { + startTime: createDuration, + duration: createDuration, + create: Boolean, + sourceId: String, + }; + function parseDragMeta(raw) { + var _a = refineProps(raw, DRAG_META_REFINERS), refined = _a.refined, extra = _a.extra; + return { + startTime: refined.startTime || null, + duration: refined.duration || null, + create: refined.create != null ? refined.create : true, + sourceId: refined.sourceId, + leftoverProps: extra, + }; + } + + var ToolbarSection = /** @class */ (function (_super) { + __extends(ToolbarSection, _super); + function ToolbarSection() { + return _super !== null && _super.apply(this, arguments) || this; + } + ToolbarSection.prototype.render = function () { + var _this = this; + var children = this.props.widgetGroups.map(function (widgetGroup) { return _this.renderWidgetGroup(widgetGroup); }); + return createElement.apply(void 0, __spreadArray(['div', { className: 'fc-toolbar-chunk' }], children)); + }; + ToolbarSection.prototype.renderWidgetGroup = function (widgetGroup) { + var props = this.props; + var theme = this.context.theme; + var children = []; + var isOnlyButtons = true; + for (var _i = 0, widgetGroup_1 = widgetGroup; _i < widgetGroup_1.length; _i++) { + var widget = widgetGroup_1[_i]; + var buttonName = widget.buttonName, buttonClick = widget.buttonClick, buttonText = widget.buttonText, buttonIcon = widget.buttonIcon; + if (buttonName === 'title') { + isOnlyButtons = false; + children.push(createElement("h2", { className: "fc-toolbar-title" }, props.title)); + } + else { + var ariaAttrs = buttonIcon ? { 'aria-label': buttonName } : {}; + var buttonClasses = ["fc-" + buttonName + "-button", theme.getClass('button')]; + if (buttonName === props.activeButton) { + buttonClasses.push(theme.getClass('buttonActive')); + } + var isDisabled = (!props.isTodayEnabled && buttonName === 'today') || + (!props.isPrevEnabled && buttonName === 'prev') || + (!props.isNextEnabled && buttonName === 'next'); + children.push(createElement("button", __assign({ disabled: isDisabled, className: buttonClasses.join(' '), onClick: buttonClick, type: "button" }, ariaAttrs), buttonText || (buttonIcon ? createElement("span", { className: buttonIcon }) : ''))); + } + } + if (children.length > 1) { + var groupClassName = (isOnlyButtons && theme.getClass('buttonGroup')) || ''; + return createElement.apply(void 0, __spreadArray(['div', { className: groupClassName }], children)); + } + return children[0]; + }; + return ToolbarSection; + }(BaseComponent)); + + var Toolbar = /** @class */ (function (_super) { + __extends(Toolbar, _super); + function Toolbar() { + return _super !== null && _super.apply(this, arguments) || this; + } + Toolbar.prototype.render = function () { + var _a = this.props, model = _a.model, extraClassName = _a.extraClassName; + var forceLtr = false; + var startContent; + var endContent; + var centerContent = model.center; + if (model.left) { + forceLtr = true; + startContent = model.left; + } + else { + startContent = model.start; + } + if (model.right) { + forceLtr = true; + endContent = model.right; + } + else { + endContent = model.end; + } + var classNames = [ + extraClassName || '', + 'fc-toolbar', + forceLtr ? 'fc-toolbar-ltr' : '', + ]; + return (createElement("div", { className: classNames.join(' ') }, + this.renderSection('start', startContent || []), + this.renderSection('center', centerContent || []), + this.renderSection('end', endContent || []))); + }; + Toolbar.prototype.renderSection = function (key, widgetGroups) { + var props = this.props; + return (createElement(ToolbarSection, { key: key, widgetGroups: widgetGroups, title: props.title, activeButton: props.activeButton, isTodayEnabled: props.isTodayEnabled, isPrevEnabled: props.isPrevEnabled, isNextEnabled: props.isNextEnabled })); + }; + return Toolbar; + }(BaseComponent)); + + // TODO: do function component? + var ViewContainer = /** @class */ (function (_super) { + __extends(ViewContainer, _super); + function ViewContainer() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.state = { + availableWidth: null, + }; + _this.handleEl = function (el) { + _this.el = el; + setRef(_this.props.elRef, el); + _this.updateAvailableWidth(); + }; + _this.handleResize = function () { + _this.updateAvailableWidth(); + }; + return _this; + } + ViewContainer.prototype.render = function () { + var _a = this, props = _a.props, state = _a.state; + var aspectRatio = props.aspectRatio; + var classNames = [ + 'fc-view-harness', + (aspectRatio || props.liquid || props.height) + ? 'fc-view-harness-active' // harness controls the height + : 'fc-view-harness-passive', // let the view do the height + ]; + var height = ''; + var paddingBottom = ''; + if (aspectRatio) { + if (state.availableWidth !== null) { + height = state.availableWidth / aspectRatio; + } + else { + // while waiting to know availableWidth, we can't set height to *zero* + // because will cause lots of unnecessary scrollbars within scrollgrid. + // BETTER: don't start rendering ANYTHING yet until we know container width + // NOTE: why not always use paddingBottom? Causes height oscillation (issue 5606) + paddingBottom = (1 / aspectRatio) * 100 + "%"; + } + } + else { + height = props.height || ''; + } + return (createElement("div", { ref: this.handleEl, onClick: props.onClick, className: classNames.join(' '), style: { height: height, paddingBottom: paddingBottom } }, props.children)); + }; + ViewContainer.prototype.componentDidMount = function () { + this.context.addResizeHandler(this.handleResize); + }; + ViewContainer.prototype.componentWillUnmount = function () { + this.context.removeResizeHandler(this.handleResize); + }; + ViewContainer.prototype.updateAvailableWidth = function () { + if (this.el && // needed. but why? + this.props.aspectRatio // aspectRatio is the only height setting that needs availableWidth + ) { + this.setState({ availableWidth: this.el.offsetWidth }); + } + }; + return ViewContainer; + }(BaseComponent)); + + /* + Detects when the user clicks on an event within a DateComponent + */ + var EventClicking = /** @class */ (function (_super) { + __extends(EventClicking, _super); + function EventClicking(settings) { + var _this = _super.call(this, settings) || this; + _this.handleSegClick = function (ev, segEl) { + var component = _this.component; + var context = component.context; + var seg = getElSeg(segEl); + if (seg && // might be the
surrounding the more link + component.isValidSegDownEl(ev.target)) { + // our way to simulate a link click for elements that can't be tags + // grab before trigger fired in case trigger trashes DOM thru rerendering + var hasUrlContainer = elementClosest(ev.target, '.fc-event-forced-url'); + var url = hasUrlContainer ? hasUrlContainer.querySelector('a[href]').href : ''; + context.emitter.trigger('eventClick', { + el: segEl, + event: new EventApi(component.context, seg.eventRange.def, seg.eventRange.instance), + jsEvent: ev, + view: context.viewApi, + }); + if (url && !ev.defaultPrevented) { + window.location.href = url; + } + } + }; + _this.destroy = listenBySelector(settings.el, 'click', '.fc-event', // on both fg and bg events + _this.handleSegClick); + return _this; + } + return EventClicking; + }(Interaction)); + + /* + Triggers events and adds/removes core classNames when the user's pointer + enters/leaves event-elements of a component. + */ + var EventHovering = /** @class */ (function (_super) { + __extends(EventHovering, _super); + function EventHovering(settings) { + var _this = _super.call(this, settings) || this; + // for simulating an eventMouseLeave when the event el is destroyed while mouse is over it + _this.handleEventElRemove = function (el) { + if (el === _this.currentSegEl) { + _this.handleSegLeave(null, _this.currentSegEl); + } + }; + _this.handleSegEnter = function (ev, segEl) { + if (getElSeg(segEl)) { // TODO: better way to make sure not hovering over more+ link or its wrapper + _this.currentSegEl = segEl; + _this.triggerEvent('eventMouseEnter', ev, segEl); + } + }; + _this.handleSegLeave = function (ev, segEl) { + if (_this.currentSegEl) { + _this.currentSegEl = null; + _this.triggerEvent('eventMouseLeave', ev, segEl); + } + }; + _this.removeHoverListeners = listenToHoverBySelector(settings.el, '.fc-event', // on both fg and bg events + _this.handleSegEnter, _this.handleSegLeave); + return _this; + } + EventHovering.prototype.destroy = function () { + this.removeHoverListeners(); + }; + EventHovering.prototype.triggerEvent = function (publicEvName, ev, segEl) { + var component = this.component; + var context = component.context; + var seg = getElSeg(segEl); + if (!ev || component.isValidSegDownEl(ev.target)) { + context.emitter.trigger(publicEvName, { + el: segEl, + event: new EventApi(context, seg.eventRange.def, seg.eventRange.instance), + jsEvent: ev, + view: context.viewApi, + }); + } + }; + return EventHovering; + }(Interaction)); + + var CalendarContent = /** @class */ (function (_super) { + __extends(CalendarContent, _super); + function CalendarContent() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.buildViewContext = memoize(buildViewContext); + _this.buildViewPropTransformers = memoize(buildViewPropTransformers); + _this.buildToolbarProps = memoize(buildToolbarProps); + _this.handleNavLinkClick = buildDelegationHandler('a[data-navlink]', _this._handleNavLinkClick.bind(_this)); + _this.headerRef = createRef(); + _this.footerRef = createRef(); + _this.interactionsStore = {}; + // Component Registration + // ----------------------------------------------------------------------------------------------------------------- + _this.registerInteractiveComponent = function (component, settingsInput) { + var settings = parseInteractionSettings(component, settingsInput); + var DEFAULT_INTERACTIONS = [ + EventClicking, + EventHovering, + ]; + var interactionClasses = DEFAULT_INTERACTIONS.concat(_this.props.pluginHooks.componentInteractions); + var interactions = interactionClasses.map(function (TheInteractionClass) { return new TheInteractionClass(settings); }); + _this.interactionsStore[component.uid] = interactions; + interactionSettingsStore[component.uid] = settings; + }; + _this.unregisterInteractiveComponent = function (component) { + for (var _i = 0, _a = _this.interactionsStore[component.uid]; _i < _a.length; _i++) { + var listener = _a[_i]; + listener.destroy(); + } + delete _this.interactionsStore[component.uid]; + delete interactionSettingsStore[component.uid]; + }; + // Resizing + // ----------------------------------------------------------------------------------------------------------------- + _this.resizeRunner = new DelayedRunner(function () { + _this.props.emitter.trigger('_resize', true); // should window resizes be considered "forced" ? + _this.props.emitter.trigger('windowResize', { view: _this.props.viewApi }); + }); + _this.handleWindowResize = function (ev) { + var options = _this.props.options; + if (options.handleWindowResize && + ev.target === window // avoid jqui events + ) { + _this.resizeRunner.request(options.windowResizeDelay); + } + }; + return _this; + } + /* + renders INSIDE of an outer div + */ + CalendarContent.prototype.render = function () { + var props = this.props; + var toolbarConfig = props.toolbarConfig, options = props.options; + var toolbarProps = this.buildToolbarProps(props.viewSpec, props.dateProfile, props.dateProfileGenerator, props.currentDate, getNow(props.options.now, props.dateEnv), // TODO: use NowTimer???? + props.viewTitle); + var viewVGrow = false; + var viewHeight = ''; + var viewAspectRatio; + if (props.isHeightAuto || props.forPrint) { + viewHeight = ''; + } + else if (options.height != null) { + viewVGrow = true; + } + else if (options.contentHeight != null) { + viewHeight = options.contentHeight; + } + else { + viewAspectRatio = Math.max(options.aspectRatio, 0.5); // prevent from getting too tall + } + var viewContext = this.buildViewContext(props.viewSpec, props.viewApi, props.options, props.dateProfileGenerator, props.dateEnv, props.theme, props.pluginHooks, props.dispatch, props.getCurrentData, props.emitter, props.calendarApi, this.registerInteractiveComponent, this.unregisterInteractiveComponent); + return (createElement(ViewContextType.Provider, { value: viewContext }, + toolbarConfig.headerToolbar && (createElement(Toolbar, __assign({ ref: this.headerRef, extraClassName: "fc-header-toolbar", model: toolbarConfig.headerToolbar }, toolbarProps))), + createElement(ViewContainer, { liquid: viewVGrow, height: viewHeight, aspectRatio: viewAspectRatio, onClick: this.handleNavLinkClick }, + this.renderView(props), + this.buildAppendContent()), + toolbarConfig.footerToolbar && (createElement(Toolbar, __assign({ ref: this.footerRef, extraClassName: "fc-footer-toolbar", model: toolbarConfig.footerToolbar }, toolbarProps))))); + }; + CalendarContent.prototype.componentDidMount = function () { + var props = this.props; + this.calendarInteractions = props.pluginHooks.calendarInteractions + .map(function (CalendarInteractionClass) { return new CalendarInteractionClass(props); }); + window.addEventListener('resize', this.handleWindowResize); + var propSetHandlers = props.pluginHooks.propSetHandlers; + for (var propName in propSetHandlers) { + propSetHandlers[propName](props[propName], props); + } + }; + CalendarContent.prototype.componentDidUpdate = function (prevProps) { + var props = this.props; + var propSetHandlers = props.pluginHooks.propSetHandlers; + for (var propName in propSetHandlers) { + if (props[propName] !== prevProps[propName]) { + propSetHandlers[propName](props[propName], props); + } + } + }; + CalendarContent.prototype.componentWillUnmount = function () { + window.removeEventListener('resize', this.handleWindowResize); + this.resizeRunner.clear(); + for (var _i = 0, _a = this.calendarInteractions; _i < _a.length; _i++) { + var interaction = _a[_i]; + interaction.destroy(); + } + this.props.emitter.trigger('_unmount'); + }; + CalendarContent.prototype._handleNavLinkClick = function (ev, anchorEl) { + var _a = this.props, dateEnv = _a.dateEnv, options = _a.options, calendarApi = _a.calendarApi; + var navLinkOptions = anchorEl.getAttribute('data-navlink'); + navLinkOptions = navLinkOptions ? JSON.parse(navLinkOptions) : {}; + var dateMarker = dateEnv.createMarker(navLinkOptions.date); + var viewType = navLinkOptions.type; + var customAction = viewType === 'day' ? options.navLinkDayClick : + viewType === 'week' ? options.navLinkWeekClick : null; + if (typeof customAction === 'function') { + customAction.call(calendarApi, dateEnv.toDate(dateMarker), ev); + } + else { + if (typeof customAction === 'string') { + viewType = customAction; + } + calendarApi.zoomTo(dateMarker, viewType); + } + }; + CalendarContent.prototype.buildAppendContent = function () { + var props = this.props; + var children = props.pluginHooks.viewContainerAppends.map(function (buildAppendContent) { return buildAppendContent(props); }); + return createElement.apply(void 0, __spreadArray([Fragment, {}], children)); + }; + CalendarContent.prototype.renderView = function (props) { + var pluginHooks = props.pluginHooks; + var viewSpec = props.viewSpec; + var viewProps = { + dateProfile: props.dateProfile, + businessHours: props.businessHours, + eventStore: props.renderableEventStore, + eventUiBases: props.eventUiBases, + dateSelection: props.dateSelection, + eventSelection: props.eventSelection, + eventDrag: props.eventDrag, + eventResize: props.eventResize, + isHeightAuto: props.isHeightAuto, + forPrint: props.forPrint, + }; + var transformers = this.buildViewPropTransformers(pluginHooks.viewPropsTransformers); + for (var _i = 0, transformers_1 = transformers; _i < transformers_1.length; _i++) { + var transformer = transformers_1[_i]; + __assign(viewProps, transformer.transform(viewProps, props)); + } + var ViewComponent = viewSpec.component; + return (createElement(ViewComponent, __assign({}, viewProps))); + }; + return CalendarContent; + }(PureComponent)); + function buildToolbarProps(viewSpec, dateProfile, dateProfileGenerator, currentDate, now, title) { + // don't force any date-profiles to valid date profiles (the `false`) so that we can tell if it's invalid + var todayInfo = dateProfileGenerator.build(now, undefined, false); // TODO: need `undefined` or else INFINITE LOOP for some reason + var prevInfo = dateProfileGenerator.buildPrev(dateProfile, currentDate, false); + var nextInfo = dateProfileGenerator.buildNext(dateProfile, currentDate, false); + return { + title: title, + activeButton: viewSpec.type, + isTodayEnabled: todayInfo.isValid && !rangeContainsMarker(dateProfile.currentRange, now), + isPrevEnabled: prevInfo.isValid, + isNextEnabled: nextInfo.isValid, + }; + } + // Plugin + // ----------------------------------------------------------------------------------------------------------------- + function buildViewPropTransformers(theClasses) { + return theClasses.map(function (TheClass) { return new TheClass(); }); + } + + var CalendarRoot = /** @class */ (function (_super) { + __extends(CalendarRoot, _super); + function CalendarRoot() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.state = { + forPrint: false, + }; + _this.handleBeforePrint = function () { + _this.setState({ forPrint: true }); + }; + _this.handleAfterPrint = function () { + _this.setState({ forPrint: false }); + }; + return _this; + } + CalendarRoot.prototype.render = function () { + var props = this.props; + var options = props.options; + var forPrint = this.state.forPrint; + var isHeightAuto = forPrint || options.height === 'auto' || options.contentHeight === 'auto'; + var height = (!isHeightAuto && options.height != null) ? options.height : ''; + var classNames = [ + 'fc', + forPrint ? 'fc-media-print' : 'fc-media-screen', + "fc-direction-" + options.direction, + props.theme.getClass('root'), + ]; + if (!getCanVGrowWithinCell()) { + classNames.push('fc-liquid-hack'); + } + return props.children(classNames, height, isHeightAuto, forPrint); + }; + CalendarRoot.prototype.componentDidMount = function () { + var emitter = this.props.emitter; + emitter.on('_beforeprint', this.handleBeforePrint); + emitter.on('_afterprint', this.handleAfterPrint); + }; + CalendarRoot.prototype.componentWillUnmount = function () { + var emitter = this.props.emitter; + emitter.off('_beforeprint', this.handleBeforePrint); + emitter.off('_afterprint', this.handleAfterPrint); + }; + return CalendarRoot; + }(BaseComponent)); + + // Computes a default column header formatting string if `colFormat` is not explicitly defined + function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) { + // if more than one week row, or if there are a lot of columns with not much space, + // put just the day numbers will be in each cell + if (!datesRepDistinctDays || dayCnt > 10) { + return createFormatter({ weekday: 'short' }); // "Sat" + } + if (dayCnt > 1) { + return createFormatter({ weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }); // "Sat 11/12" + } + return createFormatter({ weekday: 'long' }); // "Saturday" + } + + var CLASS_NAME = 'fc-col-header-cell'; // do the cushion too? no + function renderInner$1(hookProps) { + return hookProps.text; + } + + var TableDateCell = /** @class */ (function (_super) { + __extends(TableDateCell, _super); + function TableDateCell() { + return _super !== null && _super.apply(this, arguments) || this; + } + TableDateCell.prototype.render = function () { + var _a = this.context, dateEnv = _a.dateEnv, options = _a.options, theme = _a.theme, viewApi = _a.viewApi; + var props = this.props; + var date = props.date, dateProfile = props.dateProfile; + var dayMeta = getDateMeta(date, props.todayRange, null, dateProfile); + var classNames = [CLASS_NAME].concat(getDayClassNames(dayMeta, theme)); + var text = dateEnv.format(date, props.dayHeaderFormat); + // if colCnt is 1, we are already in a day-view and don't need a navlink + var navLinkAttrs = (options.navLinks && !dayMeta.isDisabled && props.colCnt > 1) + ? { 'data-navlink': buildNavLinkData(date), tabIndex: 0 } + : {}; + var hookProps = __assign(__assign(__assign({ date: dateEnv.toDate(date), view: viewApi }, props.extraHookProps), { text: text }), dayMeta); + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.dayHeaderClassNames, content: options.dayHeaderContent, defaultContent: renderInner$1, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, function (rootElRef, customClassNames, innerElRef, innerContent) { return (createElement("th", __assign({ ref: rootElRef, className: classNames.concat(customClassNames).join(' '), "data-date": !dayMeta.isDisabled ? formatDayString(date) : undefined, colSpan: props.colSpan }, props.extraDataAttrs), + createElement("div", { className: "fc-scrollgrid-sync-inner" }, !dayMeta.isDisabled && (createElement("a", __assign({ ref: innerElRef, className: [ + 'fc-col-header-cell-cushion', + props.isSticky ? 'fc-sticky' : '', + ].join(' ') }, navLinkAttrs), innerContent))))); })); + }; + return TableDateCell; + }(BaseComponent)); + + var TableDowCell = /** @class */ (function (_super) { + __extends(TableDowCell, _super); + function TableDowCell() { + return _super !== null && _super.apply(this, arguments) || this; + } + TableDowCell.prototype.render = function () { + var props = this.props; + var _a = this.context, dateEnv = _a.dateEnv, theme = _a.theme, viewApi = _a.viewApi, options = _a.options; + var date = addDays(new Date(259200000), props.dow); // start with Sun, 04 Jan 1970 00:00:00 GMT + var dateMeta = { + dow: props.dow, + isDisabled: false, + isFuture: false, + isPast: false, + isToday: false, + isOther: false, + }; + var classNames = [CLASS_NAME].concat(getDayClassNames(dateMeta, theme), props.extraClassNames || []); + var text = dateEnv.format(date, props.dayHeaderFormat); + var hookProps = __assign(__assign(__assign(__assign({ // TODO: make this public? + date: date }, dateMeta), { view: viewApi }), props.extraHookProps), { text: text }); + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.dayHeaderClassNames, content: options.dayHeaderContent, defaultContent: renderInner$1, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, function (rootElRef, customClassNames, innerElRef, innerContent) { return (createElement("th", __assign({ ref: rootElRef, className: classNames.concat(customClassNames).join(' '), colSpan: props.colSpan }, props.extraDataAttrs), + createElement("div", { className: "fc-scrollgrid-sync-inner" }, + createElement("a", { className: [ + 'fc-col-header-cell-cushion', + props.isSticky ? 'fc-sticky' : '', + ].join(' '), ref: innerElRef }, innerContent)))); })); + }; + return TableDowCell; + }(BaseComponent)); + + var NowTimer = /** @class */ (function (_super) { + __extends(NowTimer, _super); + function NowTimer(props, context) { + var _this = _super.call(this, props, context) || this; + _this.initialNowDate = getNow(context.options.now, context.dateEnv); + _this.initialNowQueriedMs = new Date().valueOf(); + _this.state = _this.computeTiming().currentState; + return _this; + } + NowTimer.prototype.render = function () { + var _a = this, props = _a.props, state = _a.state; + return props.children(state.nowDate, state.todayRange); + }; + NowTimer.prototype.componentDidMount = function () { + this.setTimeout(); + }; + NowTimer.prototype.componentDidUpdate = function (prevProps) { + if (prevProps.unit !== this.props.unit) { + this.clearTimeout(); + this.setTimeout(); + } + }; + NowTimer.prototype.componentWillUnmount = function () { + this.clearTimeout(); + }; + NowTimer.prototype.computeTiming = function () { + var _a = this, props = _a.props, context = _a.context; + var unroundedNow = addMs(this.initialNowDate, new Date().valueOf() - this.initialNowQueriedMs); + var currentUnitStart = context.dateEnv.startOf(unroundedNow, props.unit); + var nextUnitStart = context.dateEnv.add(currentUnitStart, createDuration(1, props.unit)); + var waitMs = nextUnitStart.valueOf() - unroundedNow.valueOf(); + // there is a max setTimeout ms value (https://stackoverflow.com/a/3468650/96342) + // ensure no longer than a day + waitMs = Math.min(1000 * 60 * 60 * 24, waitMs); + return { + currentState: { nowDate: currentUnitStart, todayRange: buildDayRange(currentUnitStart) }, + nextState: { nowDate: nextUnitStart, todayRange: buildDayRange(nextUnitStart) }, + waitMs: waitMs, + }; + }; + NowTimer.prototype.setTimeout = function () { + var _this = this; + var _a = this.computeTiming(), nextState = _a.nextState, waitMs = _a.waitMs; + this.timeoutId = setTimeout(function () { + _this.setState(nextState, function () { + _this.setTimeout(); + }); + }, waitMs); + }; + NowTimer.prototype.clearTimeout = function () { + if (this.timeoutId) { + clearTimeout(this.timeoutId); + } + }; + NowTimer.contextType = ViewContextType; + return NowTimer; + }(Component)); + function buildDayRange(date) { + var start = startOfDay(date); + var end = addDays(start, 1); + return { start: start, end: end }; + } + + var DayHeader = /** @class */ (function (_super) { + __extends(DayHeader, _super); + function DayHeader() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.createDayHeaderFormatter = memoize(createDayHeaderFormatter); + return _this; + } + DayHeader.prototype.render = function () { + var context = this.context; + var _a = this.props, dates = _a.dates, dateProfile = _a.dateProfile, datesRepDistinctDays = _a.datesRepDistinctDays, renderIntro = _a.renderIntro; + var dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, datesRepDistinctDays, dates.length); + return (createElement(NowTimer, { unit: "day" }, function (nowDate, todayRange) { return (createElement("tr", null, + renderIntro && renderIntro('day'), + dates.map(function (date) { return (datesRepDistinctDays ? (createElement(TableDateCell, { key: date.toISOString(), date: date, dateProfile: dateProfile, todayRange: todayRange, colCnt: dates.length, dayHeaderFormat: dayHeaderFormat })) : (createElement(TableDowCell, { key: date.getUTCDay(), dow: date.getUTCDay(), dayHeaderFormat: dayHeaderFormat }))); }))); })); + }; + return DayHeader; + }(BaseComponent)); + function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt) { + return explicitFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dateCnt); + } + + var DaySeriesModel = /** @class */ (function () { + function DaySeriesModel(range, dateProfileGenerator) { + var date = range.start; + var end = range.end; + var indices = []; + var dates = []; + var dayIndex = -1; + while (date < end) { // loop each day from start to end + if (dateProfileGenerator.isHiddenDay(date)) { + indices.push(dayIndex + 0.5); // mark that it's between indices + } + else { + dayIndex += 1; + indices.push(dayIndex); + dates.push(date); + } + date = addDays(date, 1); + } + this.dates = dates; + this.indices = indices; + this.cnt = dates.length; + } + DaySeriesModel.prototype.sliceRange = function (range) { + var firstIndex = this.getDateDayIndex(range.start); // inclusive first index + var lastIndex = this.getDateDayIndex(addDays(range.end, -1)); // inclusive last index + var clippedFirstIndex = Math.max(0, firstIndex); + var clippedLastIndex = Math.min(this.cnt - 1, lastIndex); + // deal with in-between indices + clippedFirstIndex = Math.ceil(clippedFirstIndex); // in-between starts round to next cell + clippedLastIndex = Math.floor(clippedLastIndex); // in-between ends round to prev cell + if (clippedFirstIndex <= clippedLastIndex) { + return { + firstIndex: clippedFirstIndex, + lastIndex: clippedLastIndex, + isStart: firstIndex === clippedFirstIndex, + isEnd: lastIndex === clippedLastIndex, + }; + } + return null; + }; + // Given a date, returns its chronolocial cell-index from the first cell of the grid. + // If the date lies between cells (because of hiddenDays), returns a floating-point value between offsets. + // If before the first offset, returns a negative number. + // If after the last offset, returns an offset past the last cell offset. + // Only works for *start* dates of cells. Will not work for exclusive end dates for cells. + DaySeriesModel.prototype.getDateDayIndex = function (date) { + var indices = this.indices; + var dayOffset = Math.floor(diffDays(this.dates[0], date)); + if (dayOffset < 0) { + return indices[0] - 1; + } + if (dayOffset >= indices.length) { + return indices[indices.length - 1] + 1; + } + return indices[dayOffset]; + }; + return DaySeriesModel; + }()); + + var DayTableModel = /** @class */ (function () { + function DayTableModel(daySeries, breakOnWeeks) { + var dates = daySeries.dates; + var daysPerRow; + var firstDay; + var rowCnt; + if (breakOnWeeks) { + // count columns until the day-of-week repeats + firstDay = dates[0].getUTCDay(); + for (daysPerRow = 1; daysPerRow < dates.length; daysPerRow += 1) { + if (dates[daysPerRow].getUTCDay() === firstDay) { + break; + } + } + rowCnt = Math.ceil(dates.length / daysPerRow); + } + else { + rowCnt = 1; + daysPerRow = dates.length; + } + this.rowCnt = rowCnt; + this.colCnt = daysPerRow; + this.daySeries = daySeries; + this.cells = this.buildCells(); + this.headerDates = this.buildHeaderDates(); + } + DayTableModel.prototype.buildCells = function () { + var rows = []; + for (var row = 0; row < this.rowCnt; row += 1) { + var cells = []; + for (var col = 0; col < this.colCnt; col += 1) { + cells.push(this.buildCell(row, col)); + } + rows.push(cells); + } + return rows; + }; + DayTableModel.prototype.buildCell = function (row, col) { + var date = this.daySeries.dates[row * this.colCnt + col]; + return { + key: date.toISOString(), + date: date, + }; + }; + DayTableModel.prototype.buildHeaderDates = function () { + var dates = []; + for (var col = 0; col < this.colCnt; col += 1) { + dates.push(this.cells[0][col].date); + } + return dates; + }; + DayTableModel.prototype.sliceRange = function (range) { + var colCnt = this.colCnt; + var seriesSeg = this.daySeries.sliceRange(range); + var segs = []; + if (seriesSeg) { + var firstIndex = seriesSeg.firstIndex, lastIndex = seriesSeg.lastIndex; + var index = firstIndex; + while (index <= lastIndex) { + var row = Math.floor(index / colCnt); + var nextIndex = Math.min((row + 1) * colCnt, lastIndex + 1); + segs.push({ + row: row, + firstCol: index % colCnt, + lastCol: (nextIndex - 1) % colCnt, + isStart: seriesSeg.isStart && index === firstIndex, + isEnd: seriesSeg.isEnd && (nextIndex - 1) === lastIndex, + }); + index = nextIndex; + } + } + return segs; + }; + return DayTableModel; + }()); + + var Slicer = /** @class */ (function () { + function Slicer() { + this.sliceBusinessHours = memoize(this._sliceBusinessHours); + this.sliceDateSelection = memoize(this._sliceDateSpan); + this.sliceEventStore = memoize(this._sliceEventStore); + this.sliceEventDrag = memoize(this._sliceInteraction); + this.sliceEventResize = memoize(this._sliceInteraction); + this.forceDayIfListItem = false; // hack + } + Slicer.prototype.sliceProps = function (props, dateProfile, nextDayThreshold, context) { + var extraArgs = []; + for (var _i = 4; _i < arguments.length; _i++) { + extraArgs[_i - 4] = arguments[_i]; + } + var eventUiBases = props.eventUiBases; + var eventSegs = this.sliceEventStore.apply(this, __spreadArray([props.eventStore, eventUiBases, dateProfile, nextDayThreshold], extraArgs)); + return { + dateSelectionSegs: this.sliceDateSelection.apply(this, __spreadArray([props.dateSelection, eventUiBases, context], extraArgs)), + businessHourSegs: this.sliceBusinessHours.apply(this, __spreadArray([props.businessHours, dateProfile, nextDayThreshold, context], extraArgs)), + fgEventSegs: eventSegs.fg, + bgEventSegs: eventSegs.bg, + eventDrag: this.sliceEventDrag.apply(this, __spreadArray([props.eventDrag, eventUiBases, dateProfile, nextDayThreshold], extraArgs)), + eventResize: this.sliceEventResize.apply(this, __spreadArray([props.eventResize, eventUiBases, dateProfile, nextDayThreshold], extraArgs)), + eventSelection: props.eventSelection, + }; // TODO: give interactionSegs? + }; + Slicer.prototype.sliceNowDate = function (// does not memoize + date, context) { + var extraArgs = []; + for (var _i = 2; _i < arguments.length; _i++) { + extraArgs[_i - 2] = arguments[_i]; + } + return this._sliceDateSpan.apply(this, __spreadArray([{ range: { start: date, end: addMs(date, 1) }, allDay: false }, + {}, + context], extraArgs)); + }; + Slicer.prototype._sliceBusinessHours = function (businessHours, dateProfile, nextDayThreshold, context) { + var extraArgs = []; + for (var _i = 4; _i < arguments.length; _i++) { + extraArgs[_i - 4] = arguments[_i]; + } + if (!businessHours) { + return []; + } + return this._sliceEventStore.apply(this, __spreadArray([expandRecurring(businessHours, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), context), + {}, + dateProfile, + nextDayThreshold], extraArgs)).bg; + }; + Slicer.prototype._sliceEventStore = function (eventStore, eventUiBases, dateProfile, nextDayThreshold) { + var extraArgs = []; + for (var _i = 4; _i < arguments.length; _i++) { + extraArgs[_i - 4] = arguments[_i]; + } + if (eventStore) { + var rangeRes = sliceEventStore(eventStore, eventUiBases, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), nextDayThreshold); + return { + bg: this.sliceEventRanges(rangeRes.bg, extraArgs), + fg: this.sliceEventRanges(rangeRes.fg, extraArgs), + }; + } + return { bg: [], fg: [] }; + }; + Slicer.prototype._sliceInteraction = function (interaction, eventUiBases, dateProfile, nextDayThreshold) { + var extraArgs = []; + for (var _i = 4; _i < arguments.length; _i++) { + extraArgs[_i - 4] = arguments[_i]; + } + if (!interaction) { + return null; + } + var rangeRes = sliceEventStore(interaction.mutatedEvents, eventUiBases, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), nextDayThreshold); + return { + segs: this.sliceEventRanges(rangeRes.fg, extraArgs), + affectedInstances: interaction.affectedEvents.instances, + isEvent: interaction.isEvent, + }; + }; + Slicer.prototype._sliceDateSpan = function (dateSpan, eventUiBases, context) { + var extraArgs = []; + for (var _i = 3; _i < arguments.length; _i++) { + extraArgs[_i - 3] = arguments[_i]; + } + if (!dateSpan) { + return []; + } + var eventRange = fabricateEventRange(dateSpan, eventUiBases, context); + var segs = this.sliceRange.apply(this, __spreadArray([dateSpan.range], extraArgs)); + for (var _a = 0, segs_1 = segs; _a < segs_1.length; _a++) { + var seg = segs_1[_a]; + seg.eventRange = eventRange; + } + return segs; + }; + /* + "complete" seg means it has component and eventRange + */ + Slicer.prototype.sliceEventRanges = function (eventRanges, extraArgs) { + var segs = []; + for (var _i = 0, eventRanges_1 = eventRanges; _i < eventRanges_1.length; _i++) { + var eventRange = eventRanges_1[_i]; + segs.push.apply(segs, this.sliceEventRange(eventRange, extraArgs)); + } + return segs; + }; + /* + "complete" seg means it has component and eventRange + */ + Slicer.prototype.sliceEventRange = function (eventRange, extraArgs) { + var dateRange = eventRange.range; + // hack to make multi-day events that are being force-displayed as list-items to take up only one day + if (this.forceDayIfListItem && eventRange.ui.display === 'list-item') { + dateRange = { + start: dateRange.start, + end: addDays(dateRange.start, 1), + }; + } + var segs = this.sliceRange.apply(this, __spreadArray([dateRange], extraArgs)); + for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) { + var seg = segs_2[_i]; + seg.eventRange = eventRange; + seg.isStart = eventRange.isStart && seg.isStart; + seg.isEnd = eventRange.isEnd && seg.isEnd; + } + return segs; + }; + return Slicer; + }()); + /* + for incorporating slotMinTime/slotMaxTime if appropriate + TODO: should be part of DateProfile! + TimelineDateProfile already does this btw + */ + function computeActiveRange(dateProfile, isComponentAllDay) { + var range = dateProfile.activeRange; + if (isComponentAllDay) { + return range; + } + return { + start: addMs(range.start, dateProfile.slotMinTime.milliseconds), + end: addMs(range.end, dateProfile.slotMaxTime.milliseconds - 864e5), // 864e5 = ms in a day + }; + } + + // high-level segmenting-aware tester functions + // ------------------------------------------------------------------------------------------------------------------------ + function isInteractionValid(interaction, dateProfile, context) { + var instances = interaction.mutatedEvents.instances; + for (var instanceId in instances) { + if (!rangeContainsRange(dateProfile.validRange, instances[instanceId].range)) { + return false; + } + } + return isNewPropsValid({ eventDrag: interaction }, context); // HACK: the eventDrag props is used for ALL interactions + } + function isDateSelectionValid(dateSelection, dateProfile, context) { + if (!rangeContainsRange(dateProfile.validRange, dateSelection.range)) { + return false; + } + return isNewPropsValid({ dateSelection: dateSelection }, context); + } + function isNewPropsValid(newProps, context) { + var calendarState = context.getCurrentData(); + var props = __assign({ businessHours: calendarState.businessHours, dateSelection: '', eventStore: calendarState.eventStore, eventUiBases: calendarState.eventUiBases, eventSelection: '', eventDrag: null, eventResize: null }, newProps); + return (context.pluginHooks.isPropsValid || isPropsValid)(props, context); + } + function isPropsValid(state, context, dateSpanMeta, filterConfig) { + if (dateSpanMeta === void 0) { dateSpanMeta = {}; } + if (state.eventDrag && !isInteractionPropsValid(state, context, dateSpanMeta, filterConfig)) { + return false; + } + if (state.dateSelection && !isDateSelectionPropsValid(state, context, dateSpanMeta, filterConfig)) { + return false; + } + return true; + } + // Moving Event Validation + // ------------------------------------------------------------------------------------------------------------------------ + function isInteractionPropsValid(state, context, dateSpanMeta, filterConfig) { + var currentState = context.getCurrentData(); + var interaction = state.eventDrag; // HACK: the eventDrag props is used for ALL interactions + var subjectEventStore = interaction.mutatedEvents; + var subjectDefs = subjectEventStore.defs; + var subjectInstances = subjectEventStore.instances; + var subjectConfigs = compileEventUis(subjectDefs, interaction.isEvent ? + state.eventUiBases : + { '': currentState.selectionConfig }); + if (filterConfig) { + subjectConfigs = mapHash(subjectConfigs, filterConfig); + } + // exclude the subject events. TODO: exclude defs too? + var otherEventStore = excludeInstances(state.eventStore, interaction.affectedEvents.instances); + var otherDefs = otherEventStore.defs; + var otherInstances = otherEventStore.instances; + var otherConfigs = compileEventUis(otherDefs, state.eventUiBases); + for (var subjectInstanceId in subjectInstances) { + var subjectInstance = subjectInstances[subjectInstanceId]; + var subjectRange = subjectInstance.range; + var subjectConfig = subjectConfigs[subjectInstance.defId]; + var subjectDef = subjectDefs[subjectInstance.defId]; + // constraint + if (!allConstraintsPass(subjectConfig.constraints, subjectRange, otherEventStore, state.businessHours, context)) { + return false; + } + // overlap + var eventOverlap = context.options.eventOverlap; + var eventOverlapFunc = typeof eventOverlap === 'function' ? eventOverlap : null; + for (var otherInstanceId in otherInstances) { + var otherInstance = otherInstances[otherInstanceId]; + // intersect! evaluate + if (rangesIntersect(subjectRange, otherInstance.range)) { + var otherOverlap = otherConfigs[otherInstance.defId].overlap; + // consider the other event's overlap. only do this if the subject event is a "real" event + if (otherOverlap === false && interaction.isEvent) { + return false; + } + if (subjectConfig.overlap === false) { + return false; + } + if (eventOverlapFunc && !eventOverlapFunc(new EventApi(context, otherDefs[otherInstance.defId], otherInstance), // still event + new EventApi(context, subjectDef, subjectInstance))) { + return false; + } + } + } + // allow (a function) + var calendarEventStore = currentState.eventStore; // need global-to-calendar, not local to component (splittable)state + for (var _i = 0, _a = subjectConfig.allows; _i < _a.length; _i++) { + var subjectAllow = _a[_i]; + var subjectDateSpan = __assign(__assign({}, dateSpanMeta), { range: subjectInstance.range, allDay: subjectDef.allDay }); + var origDef = calendarEventStore.defs[subjectDef.defId]; + var origInstance = calendarEventStore.instances[subjectInstanceId]; + var eventApi = void 0; + if (origDef) { // was previously in the calendar + eventApi = new EventApi(context, origDef, origInstance); + } + else { // was an external event + eventApi = new EventApi(context, subjectDef); // no instance, because had no dates + } + if (!subjectAllow(buildDateSpanApiWithContext(subjectDateSpan, context), eventApi)) { + return false; + } + } + } + return true; + } + // Date Selection Validation + // ------------------------------------------------------------------------------------------------------------------------ + function isDateSelectionPropsValid(state, context, dateSpanMeta, filterConfig) { + var relevantEventStore = state.eventStore; + var relevantDefs = relevantEventStore.defs; + var relevantInstances = relevantEventStore.instances; + var selection = state.dateSelection; + var selectionRange = selection.range; + var selectionConfig = context.getCurrentData().selectionConfig; + if (filterConfig) { + selectionConfig = filterConfig(selectionConfig); + } + // constraint + if (!allConstraintsPass(selectionConfig.constraints, selectionRange, relevantEventStore, state.businessHours, context)) { + return false; + } + // overlap + var selectOverlap = context.options.selectOverlap; + var selectOverlapFunc = typeof selectOverlap === 'function' ? selectOverlap : null; + for (var relevantInstanceId in relevantInstances) { + var relevantInstance = relevantInstances[relevantInstanceId]; + // intersect! evaluate + if (rangesIntersect(selectionRange, relevantInstance.range)) { + if (selectionConfig.overlap === false) { + return false; + } + if (selectOverlapFunc && !selectOverlapFunc(new EventApi(context, relevantDefs[relevantInstance.defId], relevantInstance), null)) { + return false; + } + } + } + // allow (a function) + for (var _i = 0, _a = selectionConfig.allows; _i < _a.length; _i++) { + var selectionAllow = _a[_i]; + var fullDateSpan = __assign(__assign({}, dateSpanMeta), selection); + if (!selectionAllow(buildDateSpanApiWithContext(fullDateSpan, context), null)) { + return false; + } + } + return true; + } + // Constraint Utils + // ------------------------------------------------------------------------------------------------------------------------ + function allConstraintsPass(constraints, subjectRange, otherEventStore, businessHoursUnexpanded, context) { + for (var _i = 0, constraints_1 = constraints; _i < constraints_1.length; _i++) { + var constraint = constraints_1[_i]; + if (!anyRangesContainRange(constraintToRanges(constraint, subjectRange, otherEventStore, businessHoursUnexpanded, context), subjectRange)) { + return false; + } + } + return true; + } + function constraintToRanges(constraint, subjectRange, // for expanding a recurring constraint, or expanding business hours + otherEventStore, // for if constraint is an even group ID + businessHoursUnexpanded, // for if constraint is 'businessHours' + context) { + if (constraint === 'businessHours') { + return eventStoreToRanges(expandRecurring(businessHoursUnexpanded, subjectRange, context)); + } + if (typeof constraint === 'string') { // an group ID + return eventStoreToRanges(filterEventStoreDefs(otherEventStore, function (eventDef) { return eventDef.groupId === constraint; })); + } + if (typeof constraint === 'object' && constraint) { // non-null object + return eventStoreToRanges(expandRecurring(constraint, subjectRange, context)); + } + return []; // if it's false + } + // TODO: move to event-store file? + function eventStoreToRanges(eventStore) { + var instances = eventStore.instances; + var ranges = []; + for (var instanceId in instances) { + ranges.push(instances[instanceId].range); + } + return ranges; + } + // TODO: move to geom file? + function anyRangesContainRange(outerRanges, innerRange) { + for (var _i = 0, outerRanges_1 = outerRanges; _i < outerRanges_1.length; _i++) { + var outerRange = outerRanges_1[_i]; + if (rangeContainsRange(outerRange, innerRange)) { + return true; + } + } + return false; + } + + var VISIBLE_HIDDEN_RE = /^(visible|hidden)$/; + var Scroller = /** @class */ (function (_super) { + __extends(Scroller, _super); + function Scroller() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.handleEl = function (el) { + _this.el = el; + setRef(_this.props.elRef, el); + }; + return _this; + } + Scroller.prototype.render = function () { + var props = this.props; + var liquid = props.liquid, liquidIsAbsolute = props.liquidIsAbsolute; + var isAbsolute = liquid && liquidIsAbsolute; + var className = ['fc-scroller']; + if (liquid) { + if (liquidIsAbsolute) { + className.push('fc-scroller-liquid-absolute'); + } + else { + className.push('fc-scroller-liquid'); + } + } + return (createElement("div", { ref: this.handleEl, className: className.join(' '), style: { + overflowX: props.overflowX, + overflowY: props.overflowY, + left: (isAbsolute && -(props.overcomeLeft || 0)) || '', + right: (isAbsolute && -(props.overcomeRight || 0)) || '', + bottom: (isAbsolute && -(props.overcomeBottom || 0)) || '', + marginLeft: (!isAbsolute && -(props.overcomeLeft || 0)) || '', + marginRight: (!isAbsolute && -(props.overcomeRight || 0)) || '', + marginBottom: (!isAbsolute && -(props.overcomeBottom || 0)) || '', + maxHeight: props.maxHeight || '', + } }, props.children)); + }; + Scroller.prototype.needsXScrolling = function () { + if (VISIBLE_HIDDEN_RE.test(this.props.overflowX)) { + return false; + } + // testing scrollWidth>clientWidth is unreliable cross-browser when pixel heights aren't integers. + // much more reliable to see if children are taller than the scroller, even tho doesn't account for + // inner-child margins and absolute positioning + var el = this.el; + var realClientWidth = this.el.getBoundingClientRect().width - this.getYScrollbarWidth(); + var children = el.children; + for (var i = 0; i < children.length; i += 1) { + var childEl = children[i]; + if (childEl.getBoundingClientRect().width > realClientWidth) { + return true; + } + } + return false; + }; + Scroller.prototype.needsYScrolling = function () { + if (VISIBLE_HIDDEN_RE.test(this.props.overflowY)) { + return false; + } + // testing scrollHeight>clientHeight is unreliable cross-browser when pixel heights aren't integers. + // much more reliable to see if children are taller than the scroller, even tho doesn't account for + // inner-child margins and absolute positioning + var el = this.el; + var realClientHeight = this.el.getBoundingClientRect().height - this.getXScrollbarWidth(); + var children = el.children; + for (var i = 0; i < children.length; i += 1) { + var childEl = children[i]; + if (childEl.getBoundingClientRect().height > realClientHeight) { + return true; + } + } + return false; + }; + Scroller.prototype.getXScrollbarWidth = function () { + if (VISIBLE_HIDDEN_RE.test(this.props.overflowX)) { + return 0; + } + return this.el.offsetHeight - this.el.clientHeight; // only works because we guarantee no borders. TODO: add to CSS with important? + }; + Scroller.prototype.getYScrollbarWidth = function () { + if (VISIBLE_HIDDEN_RE.test(this.props.overflowY)) { + return 0; + } + return this.el.offsetWidth - this.el.clientWidth; // only works because we guarantee no borders. TODO: add to CSS with important? + }; + return Scroller; + }(BaseComponent)); + + /* + TODO: somehow infer OtherArgs from masterCallback? + TODO: infer RefType from masterCallback if provided + */ + var RefMap = /** @class */ (function () { + function RefMap(masterCallback) { + var _this = this; + this.masterCallback = masterCallback; + this.currentMap = {}; + this.depths = {}; + this.callbackMap = {}; + this.handleValue = function (val, key) { + var _a = _this, depths = _a.depths, currentMap = _a.currentMap; + var removed = false; + var added = false; + if (val !== null) { + // for bug... ACTUALLY: can probably do away with this now that callers don't share numeric indices anymore + removed = (key in currentMap); + currentMap[key] = val; + depths[key] = (depths[key] || 0) + 1; + added = true; + } + else { + depths[key] -= 1; + if (!depths[key]) { + delete currentMap[key]; + delete _this.callbackMap[key]; + removed = true; + } + } + if (_this.masterCallback) { + if (removed) { + _this.masterCallback(null, String(key)); + } + if (added) { + _this.masterCallback(val, String(key)); + } + } + }; + } + RefMap.prototype.createRef = function (key) { + var _this = this; + var refCallback = this.callbackMap[key]; + if (!refCallback) { + refCallback = this.callbackMap[key] = function (val) { + _this.handleValue(val, String(key)); + }; + } + return refCallback; + }; + // TODO: check callers that don't care about order. should use getAll instead + // NOTE: this method has become less valuable now that we are encouraged to map order by some other index + // TODO: provide ONE array-export function, buildArray, which fails on non-numeric indexes. caller can manipulate and "collect" + RefMap.prototype.collect = function (startIndex, endIndex, step) { + return collectFromHash(this.currentMap, startIndex, endIndex, step); + }; + RefMap.prototype.getAll = function () { + return hashValuesToArray(this.currentMap); + }; + return RefMap; + }()); + + function computeShrinkWidth(chunkEls) { + var shrinkCells = findElements(chunkEls, '.fc-scrollgrid-shrink'); + var largestWidth = 0; + for (var _i = 0, shrinkCells_1 = shrinkCells; _i < shrinkCells_1.length; _i++) { + var shrinkCell = shrinkCells_1[_i]; + largestWidth = Math.max(largestWidth, computeSmallestCellWidth(shrinkCell)); + } + return Math.ceil(largestWidth); // elements work best with integers. round up to ensure contents fits + } + function getSectionHasLiquidHeight(props, sectionConfig) { + return props.liquid && sectionConfig.liquid; // does the section do liquid-height? (need to have whole scrollgrid liquid-height as well) + } + function getAllowYScrolling(props, sectionConfig) { + return sectionConfig.maxHeight != null || // if its possible for the height to max out, we might need scrollbars + getSectionHasLiquidHeight(props, sectionConfig); // if the section is liquid height, it might condense enough to require scrollbars + } + // TODO: ONLY use `arg`. force out internal function to use same API + function renderChunkContent(sectionConfig, chunkConfig, arg) { + var expandRows = arg.expandRows; + var content = typeof chunkConfig.content === 'function' ? + chunkConfig.content(arg) : + createElement('table', { + className: [ + chunkConfig.tableClassName, + sectionConfig.syncRowHeights ? 'fc-scrollgrid-sync-table' : '', + ].join(' '), + style: { + minWidth: arg.tableMinWidth, + width: arg.clientWidth, + height: expandRows ? arg.clientHeight : '', // css `height` on a
serves as a min-height + }, + }, arg.tableColGroupNode, createElement('tbody', {}, typeof chunkConfig.rowContent === 'function' ? chunkConfig.rowContent(arg) : chunkConfig.rowContent)); + return content; + } + function isColPropsEqual(cols0, cols1) { + return isArraysEqual(cols0, cols1, isPropsEqual); + } + function renderMicroColGroup(cols, shrinkWidth) { + var colNodes = []; + /* + for ColProps with spans, it would have been great to make a single + HOWEVER, Chrome was getting messing up distributing the width to elements makes Chrome behave. + */ + for (var _i = 0, cols_1 = cols; _i < cols_1.length; _i++) { + var colProps = cols_1[_i]; + var span = colProps.span || 1; + for (var i = 0; i < span; i += 1) { + colNodes.push(createElement("col", { style: { + width: colProps.width === 'shrink' ? sanitizeShrinkWidth(shrinkWidth) : (colProps.width || ''), + minWidth: colProps.minWidth || '', + } })); + } + } + return createElement.apply(void 0, __spreadArray(['colgroup', {}], colNodes)); + } + function sanitizeShrinkWidth(shrinkWidth) { + /* why 4? if we do 0, it will kill any border, which are needed for computeSmallestCellWidth + 4 accounts for 2 2-pixel borders. TODO: better solution? */ + return shrinkWidth == null ? 4 : shrinkWidth; + } + function hasShrinkWidth(cols) { + for (var _i = 0, cols_2 = cols; _i < cols_2.length; _i++) { + var col = cols_2[_i]; + if (col.width === 'shrink') { + return true; + } + } + return false; + } + function getScrollGridClassNames(liquid, context) { + var classNames = [ + 'fc-scrollgrid', + context.theme.getClass('table'), + ]; + if (liquid) { + classNames.push('fc-scrollgrid-liquid'); + } + return classNames; + } + function getSectionClassNames(sectionConfig, wholeTableVGrow) { + var classNames = [ + 'fc-scrollgrid-section', + "fc-scrollgrid-section-" + sectionConfig.type, + sectionConfig.className, // used? + ]; + if (wholeTableVGrow && sectionConfig.liquid && sectionConfig.maxHeight == null) { + classNames.push('fc-scrollgrid-section-liquid'); + } + if (sectionConfig.isSticky) { + classNames.push('fc-scrollgrid-section-sticky'); + } + return classNames; + } + function renderScrollShim(arg) { + return (createElement("div", { className: "fc-scrollgrid-sticky-shim", style: { + width: arg.clientWidth, + minWidth: arg.tableMinWidth, + } })); + } + function getStickyHeaderDates(options) { + var stickyHeaderDates = options.stickyHeaderDates; + if (stickyHeaderDates == null || stickyHeaderDates === 'auto') { + stickyHeaderDates = options.height === 'auto' || options.viewHeight === 'auto'; + } + return stickyHeaderDates; + } + function getStickyFooterScrollbar(options) { + var stickyFooterScrollbar = options.stickyFooterScrollbar; + if (stickyFooterScrollbar == null || stickyFooterScrollbar === 'auto') { + stickyFooterScrollbar = options.height === 'auto' || options.viewHeight === 'auto'; + } + return stickyFooterScrollbar; + } + + var SimpleScrollGrid = /** @class */ (function (_super) { + __extends(SimpleScrollGrid, _super); + function SimpleScrollGrid() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.processCols = memoize(function (a) { return a; }, isColPropsEqual); // so we get same `cols` props every time + // yucky to memoize VNodes, but much more efficient for consumers + _this.renderMicroColGroup = memoize(renderMicroColGroup); + _this.scrollerRefs = new RefMap(); + _this.scrollerElRefs = new RefMap(_this._handleScrollerEl.bind(_this)); + _this.state = { + shrinkWidth: null, + forceYScrollbars: false, + scrollerClientWidths: {}, + scrollerClientHeights: {}, + }; + // TODO: can do a really simple print-view. dont need to join rows + _this.handleSizing = function () { + _this.setState(__assign({ shrinkWidth: _this.computeShrinkWidth() }, _this.computeScrollerDims())); + }; + return _this; + } + SimpleScrollGrid.prototype.render = function () { + var _a = this, props = _a.props, state = _a.state, context = _a.context; + var sectionConfigs = props.sections || []; + var cols = this.processCols(props.cols); + var microColGroupNode = this.renderMicroColGroup(cols, state.shrinkWidth); + var classNames = getScrollGridClassNames(props.liquid, context); + if (props.collapsibleWidth) { + classNames.push('fc-scrollgrid-collapsible'); + } + // TODO: make DRY + var configCnt = sectionConfigs.length; + var configI = 0; + var currentConfig; + var headSectionNodes = []; + var bodySectionNodes = []; + var footSectionNodes = []; + while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'header') { + headSectionNodes.push(this.renderSection(currentConfig, microColGroupNode)); + configI += 1; + } + while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'body') { + bodySectionNodes.push(this.renderSection(currentConfig, microColGroupNode)); + configI += 1; + } + while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'footer') { + footSectionNodes.push(this.renderSection(currentConfig, microColGroupNode)); + configI += 1; + } + // firefox bug: when setting height on table and there is a thead or tfoot, + // the necessary height:100% on the liquid-height body section forces the *whole* table to be taller. (bug #5524) + // use getCanVGrowWithinCell as a way to detect table-stupid firefox. + // if so, use a simpler dom structure, jam everything into a lone tbody. + var isBuggy = !getCanVGrowWithinCell(); + return createElement('table', { + className: classNames.join(' '), + style: { height: props.height }, + }, Boolean(!isBuggy && headSectionNodes.length) && createElement.apply(void 0, __spreadArray(['thead', {}], headSectionNodes)), Boolean(!isBuggy && bodySectionNodes.length) && createElement.apply(void 0, __spreadArray(['tbody', {}], bodySectionNodes)), Boolean(!isBuggy && footSectionNodes.length) && createElement.apply(void 0, __spreadArray(['tfoot', {}], footSectionNodes)), isBuggy && createElement.apply(void 0, __spreadArray(__spreadArray(__spreadArray(['tbody', {}], headSectionNodes), bodySectionNodes), footSectionNodes))); + }; + SimpleScrollGrid.prototype.renderSection = function (sectionConfig, microColGroupNode) { + if ('outerContent' in sectionConfig) { + return (createElement(Fragment, { key: sectionConfig.key }, sectionConfig.outerContent)); + } + return (createElement("tr", { key: sectionConfig.key, className: getSectionClassNames(sectionConfig, this.props.liquid).join(' ') }, this.renderChunkTd(sectionConfig, microColGroupNode, sectionConfig.chunk))); + }; + SimpleScrollGrid.prototype.renderChunkTd = function (sectionConfig, microColGroupNode, chunkConfig) { + if ('outerContent' in chunkConfig) { + return chunkConfig.outerContent; + } + var props = this.props; + var _a = this.state, forceYScrollbars = _a.forceYScrollbars, scrollerClientWidths = _a.scrollerClientWidths, scrollerClientHeights = _a.scrollerClientHeights; + var needsYScrolling = getAllowYScrolling(props, sectionConfig); // TODO: do lazily. do in section config? + var isLiquid = getSectionHasLiquidHeight(props, sectionConfig); + // for `!props.liquid` - is WHOLE scrollgrid natural height? + // TODO: do same thing in advanced scrollgrid? prolly not b/c always has horizontal scrollbars + var overflowY = !props.liquid ? 'visible' : + forceYScrollbars ? 'auto' : + !needsYScrolling ? 'hidden' : + 'auto'; + var sectionKey = sectionConfig.key; + var content = renderChunkContent(sectionConfig, chunkConfig, { + tableColGroupNode: microColGroupNode, + tableMinWidth: '', + clientWidth: (!props.collapsibleWidth && scrollerClientWidths[sectionKey] !== undefined) ? scrollerClientWidths[sectionKey] : null, + clientHeight: scrollerClientHeights[sectionKey] !== undefined ? scrollerClientHeights[sectionKey] : null, + expandRows: sectionConfig.expandRows, + syncRowHeights: false, + rowSyncHeights: [], + reportRowHeightChange: function () { }, + }); + return (createElement("td", { ref: chunkConfig.elRef }, + createElement("div", { className: "fc-scroller-harness" + (isLiquid ? ' fc-scroller-harness-liquid' : '') }, + createElement(Scroller, { ref: this.scrollerRefs.createRef(sectionKey), elRef: this.scrollerElRefs.createRef(sectionKey), overflowY: overflowY, overflowX: !props.liquid ? 'visible' : 'hidden' /* natural height? */, maxHeight: sectionConfig.maxHeight, liquid: isLiquid, liquidIsAbsolute // because its within a harness + : true }, content)))); + }; + SimpleScrollGrid.prototype._handleScrollerEl = function (scrollerEl, key) { + var section = getSectionByKey(this.props.sections, key); + if (section) { + setRef(section.chunk.scrollerElRef, scrollerEl); + } + }; + SimpleScrollGrid.prototype.componentDidMount = function () { + this.handleSizing(); + this.context.addResizeHandler(this.handleSizing); + }; + SimpleScrollGrid.prototype.componentDidUpdate = function () { + // TODO: need better solution when state contains non-sizing things + this.handleSizing(); + }; + SimpleScrollGrid.prototype.componentWillUnmount = function () { + this.context.removeResizeHandler(this.handleSizing); + }; + SimpleScrollGrid.prototype.computeShrinkWidth = function () { + return hasShrinkWidth(this.props.cols) + ? computeShrinkWidth(this.scrollerElRefs.getAll()) + : 0; + }; + SimpleScrollGrid.prototype.computeScrollerDims = function () { + var scrollbarWidth = getScrollbarWidths(); + var _a = this, scrollerRefs = _a.scrollerRefs, scrollerElRefs = _a.scrollerElRefs; + var forceYScrollbars = false; + var scrollerClientWidths = {}; + var scrollerClientHeights = {}; + for (var sectionKey in scrollerRefs.currentMap) { + var scroller = scrollerRefs.currentMap[sectionKey]; + if (scroller && scroller.needsYScrolling()) { + forceYScrollbars = true; + break; + } + } + for (var _i = 0, _b = this.props.sections; _i < _b.length; _i++) { + var section = _b[_i]; + var sectionKey = section.key; + var scrollerEl = scrollerElRefs.currentMap[sectionKey]; + if (scrollerEl) { + var harnessEl = scrollerEl.parentNode; // TODO: weird way to get this. need harness b/c doesn't include table borders + scrollerClientWidths[sectionKey] = Math.floor(harnessEl.getBoundingClientRect().width - (forceYScrollbars + ? scrollbarWidth.y // use global because scroller might not have scrollbars yet but will need them in future + : 0)); + scrollerClientHeights[sectionKey] = Math.floor(harnessEl.getBoundingClientRect().height); + } + } + return { forceYScrollbars: forceYScrollbars, scrollerClientWidths: scrollerClientWidths, scrollerClientHeights: scrollerClientHeights }; + }; + return SimpleScrollGrid; + }(BaseComponent)); + SimpleScrollGrid.addStateEquality({ + scrollerClientWidths: isPropsEqual, + scrollerClientHeights: isPropsEqual, + }); + function getSectionByKey(sections, key) { + for (var _i = 0, sections_1 = sections; _i < sections_1.length; _i++) { + var section = sections_1[_i]; + if (section.key === key) { + return section; + } + } + return null; + } + + var EventRoot = /** @class */ (function (_super) { + __extends(EventRoot, _super); + function EventRoot() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.elRef = createRef(); + return _this; + } + EventRoot.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var options = context.options; + var seg = props.seg; + var eventRange = seg.eventRange; + var ui = eventRange.ui; + var hookProps = { + event: new EventApi(context, eventRange.def, eventRange.instance), + view: context.viewApi, + timeText: props.timeText, + textColor: ui.textColor, + backgroundColor: ui.backgroundColor, + borderColor: ui.borderColor, + isDraggable: !props.disableDragging && computeSegDraggable(seg, context), + isStartResizable: !props.disableResizing && computeSegStartResizable(seg, context), + isEndResizable: !props.disableResizing && computeSegEndResizable(seg), + isMirror: Boolean(props.isDragging || props.isResizing || props.isDateSelecting), + isStart: Boolean(seg.isStart), + isEnd: Boolean(seg.isEnd), + isPast: Boolean(props.isPast), + isFuture: Boolean(props.isFuture), + isToday: Boolean(props.isToday), + isSelected: Boolean(props.isSelected), + isDragging: Boolean(props.isDragging), + isResizing: Boolean(props.isResizing), + }; + var standardClassNames = getEventClassNames(hookProps).concat(ui.classNames); + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.eventClassNames, content: options.eventContent, defaultContent: props.defaultContent, didMount: options.eventDidMount, willUnmount: options.eventWillUnmount, elRef: this.elRef }, function (rootElRef, customClassNames, innerElRef, innerContent) { return props.children(rootElRef, standardClassNames.concat(customClassNames), innerElRef, innerContent, hookProps); })); + }; + EventRoot.prototype.componentDidMount = function () { + setElSeg(this.elRef.current, this.props.seg); + }; + /* + need to re-assign seg to the element if seg changes, even if the element is the same + */ + EventRoot.prototype.componentDidUpdate = function (prevProps) { + var seg = this.props.seg; + if (seg !== prevProps.seg) { + setElSeg(this.elRef.current, seg); + } + }; + return EventRoot; + }(BaseComponent)); + + // should not be a purecomponent + var StandardEvent = /** @class */ (function (_super) { + __extends(StandardEvent, _super); + function StandardEvent() { + return _super !== null && _super.apply(this, arguments) || this; + } + StandardEvent.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var seg = props.seg; + var timeFormat = context.options.eventTimeFormat || props.defaultTimeFormat; + var timeText = buildSegTimeText(seg, timeFormat, context, props.defaultDisplayEventTime, props.defaultDisplayEventEnd); + return (createElement(EventRoot, { seg: seg, timeText: timeText, disableDragging: props.disableDragging, disableResizing: props.disableResizing, defaultContent: props.defaultContent || renderInnerContent$6, isDragging: props.isDragging, isResizing: props.isResizing, isDateSelecting: props.isDateSelecting, isSelected: props.isSelected, isPast: props.isPast, isFuture: props.isFuture, isToday: props.isToday }, function (rootElRef, classNames, innerElRef, innerContent, hookProps) { return (createElement("a", __assign({ className: props.extraClassNames.concat(classNames).join(' '), style: { + borderColor: hookProps.borderColor, + backgroundColor: hookProps.backgroundColor, + }, ref: rootElRef }, getSegAnchorAttrs$1(seg)), + createElement("div", { className: "fc-event-main", ref: innerElRef, style: { color: hookProps.textColor } }, innerContent), + hookProps.isStartResizable && + createElement("div", { className: "fc-event-resizer fc-event-resizer-start" }), + hookProps.isEndResizable && + createElement("div", { className: "fc-event-resizer fc-event-resizer-end" }))); })); + }; + return StandardEvent; + }(BaseComponent)); + function renderInnerContent$6(innerProps) { + return (createElement("div", { className: "fc-event-main-frame" }, + innerProps.timeText && (createElement("div", { className: "fc-event-time" }, innerProps.timeText)), + createElement("div", { className: "fc-event-title-container" }, + createElement("div", { className: "fc-event-title fc-sticky" }, innerProps.event.title || createElement(Fragment, null, "\u00A0"))))); + } + function getSegAnchorAttrs$1(seg) { + var url = seg.eventRange.def.url; + return url ? { href: url } : {}; + } + + var NowIndicatorRoot = function (props) { return (createElement(ViewContextType.Consumer, null, function (context) { + var options = context.options; + var hookProps = { + isAxis: props.isAxis, + date: context.dateEnv.toDate(props.date), + view: context.viewApi, + }; + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.nowIndicatorClassNames, content: options.nowIndicatorContent, didMount: options.nowIndicatorDidMount, willUnmount: options.nowIndicatorWillUnmount }, props.children)); + })); }; + + var DAY_NUM_FORMAT = createFormatter({ day: 'numeric' }); + var DayCellContent = /** @class */ (function (_super) { + __extends(DayCellContent, _super); + function DayCellContent() { + return _super !== null && _super.apply(this, arguments) || this; + } + DayCellContent.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var options = context.options; + var hookProps = refineDayCellHookProps({ + date: props.date, + dateProfile: props.dateProfile, + todayRange: props.todayRange, + showDayNumber: props.showDayNumber, + extraProps: props.extraHookProps, + viewApi: context.viewApi, + dateEnv: context.dateEnv, + }); + return (createElement(ContentHook, { hookProps: hookProps, content: options.dayCellContent, defaultContent: props.defaultContent }, props.children)); + }; + return DayCellContent; + }(BaseComponent)); + function refineDayCellHookProps(raw) { + var date = raw.date, dateEnv = raw.dateEnv; + var dayMeta = getDateMeta(date, raw.todayRange, null, raw.dateProfile); + return __assign(__assign(__assign({ date: dateEnv.toDate(date), view: raw.viewApi }, dayMeta), { dayNumberText: raw.showDayNumber ? dateEnv.format(date, DAY_NUM_FORMAT) : '' }), raw.extraProps); + } + + var DayCellRoot = /** @class */ (function (_super) { + __extends(DayCellRoot, _super); + function DayCellRoot() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.refineHookProps = memoizeObjArg(refineDayCellHookProps); + _this.normalizeClassNames = buildClassNameNormalizer(); + return _this; + } + DayCellRoot.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var options = context.options; + var hookProps = this.refineHookProps({ + date: props.date, + dateProfile: props.dateProfile, + todayRange: props.todayRange, + showDayNumber: props.showDayNumber, + extraProps: props.extraHookProps, + viewApi: context.viewApi, + dateEnv: context.dateEnv, + }); + var classNames = getDayClassNames(hookProps, context.theme).concat(hookProps.isDisabled + ? [] // don't use custom classNames if disabled + : this.normalizeClassNames(options.dayCellClassNames, hookProps)); + var dataAttrs = hookProps.isDisabled ? {} : { + 'data-date': formatDayString(props.date), + }; + return (createElement(MountHook, { hookProps: hookProps, didMount: options.dayCellDidMount, willUnmount: options.dayCellWillUnmount, elRef: props.elRef }, function (rootElRef) { return props.children(rootElRef, classNames, dataAttrs, hookProps.isDisabled); })); + }; + return DayCellRoot; + }(BaseComponent)); + + function renderFill(fillType) { + return (createElement("div", { className: "fc-" + fillType })); + } + var BgEvent = function (props) { return (createElement(EventRoot, { defaultContent: renderInnerContent$5, seg: props.seg /* uselesss i think */, timeText: "", disableDragging: true, disableResizing: true, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: false, isPast: props.isPast, isFuture: props.isFuture, isToday: props.isToday }, function (rootElRef, classNames, innerElRef, innerContent, hookProps) { return (createElement("div", { ref: rootElRef, className: ['fc-bg-event'].concat(classNames).join(' '), style: { + backgroundColor: hookProps.backgroundColor, + } }, innerContent)); })); }; + function renderInnerContent$5(props) { + var title = props.event.title; + return title && (createElement("div", { className: "fc-event-title" }, props.event.title)); + } + + var WeekNumberRoot = function (props) { return (createElement(ViewContextType.Consumer, null, function (context) { + var dateEnv = context.dateEnv, options = context.options; + var date = props.date; + var format = options.weekNumberFormat || props.defaultFormat; + var num = dateEnv.computeWeekNumber(date); // TODO: somehow use for formatting as well? + var text = dateEnv.format(date, format); + var hookProps = { num: num, text: text, date: date }; + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.weekNumberClassNames, content: options.weekNumberContent, defaultContent: renderInner, didMount: options.weekNumberDidMount, willUnmount: options.weekNumberWillUnmount }, props.children)); + })); }; + function renderInner(innerProps) { + return innerProps.text; + } + + var PADDING_FROM_VIEWPORT = 10; + var Popover = /** @class */ (function (_super) { + __extends(Popover, _super); + function Popover() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.handleRootEl = function (el) { + _this.rootEl = el; + if (_this.props.elRef) { + setRef(_this.props.elRef, el); + } + }; + // Triggered when the user clicks *anywhere* in the document, for the autoHide feature + _this.handleDocumentMousedown = function (ev) { + // only hide the popover if the click happened outside the popover + var target = getEventTargetViaRoot(ev); + if (!_this.rootEl.contains(target) && window.auto_close_popup !== false) { + _this.handleCloseClick(); + } + }; + _this.handleCloseClick = function () { + var onClose = _this.props.onClose; + if (onClose) { + onClose(); + } + }; + return _this; + } + Popover.prototype.render = function () { + var theme = this.context.theme; + var props = this.props; + var classNames = [ + 'fc-popover', + theme.getClass('popover'), + ].concat(props.extraClassNames || []); + return createPortal(createElement("div", __assign({ className: classNames.join(' ') }, props.extraAttrs, { ref: this.handleRootEl }), + createElement("div", { className: 'fc-popover-header ' + theme.getClass('popoverHeader') }, + createElement("span", { className: "fc-popover-title" }, props.title), + createElement("span", { className: 'fc-popover-close ' + theme.getIconClass('close'), onClick: this.handleCloseClick })), + createElement("div", { className: 'fc-popover-body ' + theme.getClass('popoverContent') }, props.children)), props.parentEl); + }; + Popover.prototype.componentDidMount = function () { + document.addEventListener('mousedown', this.handleDocumentMousedown); + this.updateSize(); + }; + Popover.prototype.componentWillUnmount = function () { + document.removeEventListener('mousedown', this.handleDocumentMousedown); + }; + Popover.prototype.updateSize = function () { + var isRtl = this.context.isRtl; + var _a = this.props, alignmentEl = _a.alignmentEl, alignGridTop = _a.alignGridTop; + var rootEl = this.rootEl; + var alignmentRect = computeClippedClientRect(alignmentEl); + if (alignmentRect) { + var popoverDims = rootEl.getBoundingClientRect(); + // position relative to viewport + var popoverTop = alignGridTop + ? elementClosest(alignmentEl, '.fc-scrollgrid').getBoundingClientRect().top + : alignmentRect.top; + var popoverLeft = isRtl ? alignmentRect.right - popoverDims.width : alignmentRect.left; + // constrain + rootEl.style.display = "block"; + var popup_width = rootEl.clientWidth, + popup_height = rootEl.clientHeigh; + popoverTop = Math.max(popoverTop, PADDING_FROM_VIEWPORT); + popoverLeft = Math.min(popoverLeft - popup_width, document.documentElement.clientWidth - PADDING_FROM_VIEWPORT - popup_width); + popoverLeft = Math.max(popoverLeft, PADDING_FROM_VIEWPORT); + + var origin_1 = rootEl.offsetParent.getBoundingClientRect(); + var offset = { + top: popoverTop - origin_1.top, + left: popoverLeft - origin_1.left, + } + applyStyle(rootEl, offset); + } + }; + return Popover; + }(BaseComponent)); + + var MorePopover = /** @class */ (function (_super) { + __extends(MorePopover, _super); + function MorePopover() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.handleRootEl = function (rootEl) { + _this.rootEl = rootEl; + if (rootEl) { + _this.context.registerInteractiveComponent(_this, { + el: rootEl, + useEventCenter: false, + }); + } + else { + _this.context.unregisterInteractiveComponent(_this); + } + }; + return _this; + } + MorePopover.prototype.render = function () { + var _a = this.context, options = _a.options, dateEnv = _a.dateEnv; + var props = this.props; + var startDate = props.startDate, todayRange = props.todayRange, dateProfile = props.dateProfile; + var title = dateEnv.format(startDate, options.dayPopoverFormat); + return (createElement(DayCellRoot, { date: startDate, dateProfile: dateProfile, todayRange: todayRange, elRef: this.handleRootEl }, function (rootElRef, dayClassNames, dataAttrs) { return (createElement(Popover, { elRef: rootElRef, title: title, extraClassNames: ['fc-more-popover'].concat(dayClassNames), extraAttrs: dataAttrs /* TODO: make these time-based when not whole-day? */, parentEl: props.parentEl, alignmentEl: props.alignmentEl, alignGridTop: props.alignGridTop, onClose: props.onClose }, + createElement(DayCellContent, { date: startDate, dateProfile: dateProfile, todayRange: todayRange }, function (innerElRef, innerContent) { return (innerContent && + createElement("div", { className: "fc-more-popover-misc", ref: innerElRef }, innerContent)); }), + props.children)); })); + }; + MorePopover.prototype.queryHit = function (positionLeft, positionTop, elWidth, elHeight) { + var _a = this, rootEl = _a.rootEl, props = _a.props; + if (positionLeft >= 0 && positionLeft < elWidth && + positionTop >= 0 && positionTop < elHeight) { + return { + dateProfile: props.dateProfile, + dateSpan: __assign({ allDay: true, range: { + start: props.startDate, + end: props.endDate, + } }, props.extraDateSpan), + dayEl: rootEl, + rect: { + left: 0, + top: 0, + right: elWidth, + bottom: elHeight, + }, + layer: 1, // important when comparing with hits from other components + }; + } + return null; + }; + return MorePopover; + }(DateComponent)); + + var MoreLinkRoot = /** @class */ (function (_super) { + __extends(MoreLinkRoot, _super); + function MoreLinkRoot() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.linkElRef = createRef(); + _this.state = { + isPopoverOpen: false, + }; + _this.handleClick = function (ev) { + var _a = _this, props = _a.props, context = _a.context; + var moreLinkClick = context.options.moreLinkClick; + var date = computeRange(props).start; + function buildPublicSeg(seg) { + var _a = seg.eventRange, def = _a.def, instance = _a.instance, range = _a.range; + return { + event: new EventApi(context, def, instance), + start: context.dateEnv.toDate(range.start), + end: context.dateEnv.toDate(range.end), + isStart: seg.isStart, + isEnd: seg.isEnd, + }; + } + if (typeof moreLinkClick === 'function') { + moreLinkClick = moreLinkClick({ + date: date, + allDay: Boolean(props.allDayDate), + allSegs: props.allSegs.map(buildPublicSeg), + hiddenSegs: props.hiddenSegs.map(buildPublicSeg), + jsEvent: ev, + view: context.viewApi, + }); + } + if (!moreLinkClick || moreLinkClick === 'popover') { + _this.setState({ isPopoverOpen: true }); + } + else if (typeof moreLinkClick === 'string') { // a view name + context.calendarApi.zoomTo(date, moreLinkClick); + } + }; + _this.handlePopoverClose = function () { + _this.setState({ isPopoverOpen: false }); + }; + return _this; + } + MoreLinkRoot.prototype.render = function () { + var _this = this; + var props = this.props; + return (createElement(ViewContextType.Consumer, null, function (context) { + var viewApi = context.viewApi, options = context.options, calendarApi = context.calendarApi; + var moreLinkText = options.moreLinkText; + var moreCnt = props.moreCnt; + var range = computeRange(props); + var hookProps = { + num: moreCnt, + shortText: "+" + moreCnt, + text: typeof moreLinkText === 'function' + ? moreLinkText.call(calendarApi, moreCnt) + : "+" + moreCnt + " " + moreLinkText, + view: viewApi, + }; + return (createElement(Fragment, null, + Boolean(props.moreCnt) && (createElement(RenderHook, { elRef: _this.linkElRef, hookProps: hookProps, classNames: options.moreLinkClassNames, content: options.moreLinkContent, defaultContent: props.defaultContent || renderMoreLinkInner$1, didMount: options.moreLinkDidMount, willUnmount: options.moreLinkWillUnmount }, function (rootElRef, customClassNames, innerElRef, innerContent) { return props.children(rootElRef, ['fc-more-link'].concat(customClassNames), innerElRef, innerContent, _this.handleClick); })), + _this.state.isPopoverOpen && (createElement(MorePopover, { startDate: range.start, endDate: range.end, dateProfile: props.dateProfile, todayRange: props.todayRange, extraDateSpan: props.extraDateSpan, parentEl: _this.parentEl, alignmentEl: props.alignmentElRef.current, alignGridTop: props.alignGridTop, onClose: _this.handlePopoverClose }, props.popoverContent())))); + })); + }; + MoreLinkRoot.prototype.componentDidMount = function () { + this.updateParentEl(); + }; + MoreLinkRoot.prototype.componentDidUpdate = function () { + this.updateParentEl(); + }; + MoreLinkRoot.prototype.updateParentEl = function () { + if (this.linkElRef.current) { + this.parentEl = elementClosest(this.linkElRef.current, '.fc-view-harness'); + } + }; + return MoreLinkRoot; + }(BaseComponent)); + function renderMoreLinkInner$1(props) { + return props.text; + } + function computeRange(props) { + if (props.allDayDate) { + return { + start: props.allDayDate, + end: addDays(props.allDayDate, 1), + }; + } + var hiddenSegs = props.hiddenSegs; + return { + start: computeEarliestSegStart(hiddenSegs), + end: computeLatestSegEnd(hiddenSegs), + }; + } + function computeEarliestSegStart(segs) { + return segs.reduce(pickEarliestStart).eventRange.range.start; + } + function pickEarliestStart(seg0, seg1) { + return seg0.eventRange.range.start < seg1.eventRange.range.start ? seg0 : seg1; + } + function computeLatestSegEnd(segs) { + return segs.reduce(pickLatestEnd).eventRange.range.end; + } + function pickLatestEnd(seg0, seg1) { + return seg0.eventRange.range.end > seg1.eventRange.range.end ? seg0 : seg1; + } + + // exports + // -------------------------------------------------------------------------------------------------- + var version = '5.8.0'; // important to type it, so .d.ts has generic string + + var Calendar = /** @class */ (function (_super) { + __extends(Calendar, _super); + function Calendar(el, optionOverrides) { + if (optionOverrides === void 0) { optionOverrides = {}; } + var _this = _super.call(this) || this; + _this.isRendering = false; + _this.isRendered = false; + _this.currentClassNames = []; + _this.customContentRenderId = 0; // will affect custom generated classNames? + _this.handleAction = function (action) { + // actions we know we want to render immediately + switch (action.type) { + case 'SET_EVENT_DRAG': + case 'SET_EVENT_RESIZE': + _this.renderRunner.tryDrain(); + } + }; + _this.handleData = function (data) { + _this.currentData = data; + _this.renderRunner.request(data.calendarOptions.rerenderDelay); + }; + _this.handleRenderRequest = function () { + if (_this.isRendering) { + _this.isRendered = true; + var currentData_1 = _this.currentData; + render(createElement(CalendarRoot, { options: currentData_1.calendarOptions, theme: currentData_1.theme, emitter: currentData_1.emitter }, function (classNames, height, isHeightAuto, forPrint) { + _this.setClassNames(classNames); + _this.setHeight(height); + return (createElement(CustomContentRenderContext.Provider, { value: _this.customContentRenderId }, + createElement(CalendarContent, __assign({ isHeightAuto: isHeightAuto, forPrint: forPrint }, currentData_1)))); + }), _this.el); + } + else if (_this.isRendered) { + _this.isRendered = false; + unmountComponentAtNode(_this.el); + _this.setClassNames([]); + _this.setHeight(''); + } + flushToDom(); + }; + _this.el = el; + _this.renderRunner = new DelayedRunner(_this.handleRenderRequest); + new CalendarDataManager({ + optionOverrides: optionOverrides, + calendarApi: _this, + onAction: _this.handleAction, + onData: _this.handleData, + }); + return _this; + } + Object.defineProperty(Calendar.prototype, "view", { + get: function () { return this.currentData.viewApi; } // for public API + , + enumerable: false, + configurable: true + }); + Calendar.prototype.render = function () { + var wasRendering = this.isRendering; + if (!wasRendering) { + this.isRendering = true; + } + else { + this.customContentRenderId += 1; + } + this.renderRunner.request(); + if (wasRendering) { + this.updateSize(); + } + }; + Calendar.prototype.destroy = function () { + if (this.isRendering) { + this.isRendering = false; + this.renderRunner.request(); + } + }; + Calendar.prototype.updateSize = function () { + _super.prototype.updateSize.call(this); + flushToDom(); + }; + Calendar.prototype.batchRendering = function (func) { + this.renderRunner.pause('batchRendering'); + func(); + this.renderRunner.resume('batchRendering'); + }; + Calendar.prototype.pauseRendering = function () { + this.renderRunner.pause('pauseRendering'); + }; + Calendar.prototype.resumeRendering = function () { + this.renderRunner.resume('pauseRendering', true); + }; + Calendar.prototype.resetOptions = function (optionOverrides, append) { + this.currentDataManager.resetOptions(optionOverrides, append); + }; + Calendar.prototype.setClassNames = function (classNames) { + if (!isArraysEqual(classNames, this.currentClassNames)) { + var classList = this.el.classList; + for (var _i = 0, _a = this.currentClassNames; _i < _a.length; _i++) { + var className = _a[_i]; + classList.remove(className); + } + for (var _b = 0, classNames_1 = classNames; _b < classNames_1.length; _b++) { + var className = classNames_1[_b]; + classList.add(className); + } + this.currentClassNames = classNames; + } + }; + Calendar.prototype.setHeight = function (height) { + applyStyleProp(this.el, 'height', height); + }; + return Calendar; + }(CalendarApi)); + + config.touchMouseIgnoreWait = 500; + var ignoreMouseDepth = 0; + var listenerCnt = 0; + var isWindowTouchMoveCancelled = false; + /* + Uses a "pointer" abstraction, which monitors UI events for both mouse and touch. + Tracks when the pointer "drags" on a certain element, meaning down+move+up. + + Also, tracks if there was touch-scrolling. + Also, can prevent touch-scrolling from happening. + Also, can fire pointermove events when scrolling happens underneath, even when no real pointer movement. + + emits: + - pointerdown + - pointermove + - pointerup + */ + var PointerDragging = /** @class */ (function () { + function PointerDragging(containerEl) { + var _this = this; + this.subjectEl = null; + // options that can be directly assigned by caller + this.selector = ''; // will cause subjectEl in all emitted events to be this element + this.handleSelector = ''; + this.shouldIgnoreMove = false; + this.shouldWatchScroll = true; // for simulating pointermove on scroll + // internal states + this.isDragging = false; + this.isTouchDragging = false; + this.wasTouchScroll = false; + // Mouse + // ---------------------------------------------------------------------------------------------------- + this.handleMouseDown = function (ev) { + if (!_this.shouldIgnoreMouse() && + isPrimaryMouseButton(ev) && + _this.tryStart(ev)) { + var pev = _this.createEventFromMouse(ev, true); + _this.emitter.trigger('pointerdown', pev); + _this.initScrollWatch(pev); + if (!_this.shouldIgnoreMove) { + document.addEventListener('mousemove', _this.handleMouseMove); + } + document.addEventListener('mouseup', _this.handleMouseUp); + } + }; + this.handleMouseMove = function (ev) { + var pev = _this.createEventFromMouse(ev); + _this.recordCoords(pev); + _this.emitter.trigger('pointermove', pev); + }; + this.handleMouseUp = function (ev) { + document.removeEventListener('mousemove', _this.handleMouseMove); + document.removeEventListener('mouseup', _this.handleMouseUp); + _this.emitter.trigger('pointerup', _this.createEventFromMouse(ev)); + _this.cleanup(); // call last so that pointerup has access to props + }; + // Touch + // ---------------------------------------------------------------------------------------------------- + this.handleTouchStart = function (ev) { + if (_this.tryStart(ev)) { + _this.isTouchDragging = true; + var pev = _this.createEventFromTouch(ev, true); + _this.emitter.trigger('pointerdown', pev); + _this.initScrollWatch(pev); + // unlike mouse, need to attach to target, not document + // https://stackoverflow.com/a/45760014 + var targetEl = ev.target; + if (!_this.shouldIgnoreMove) { + targetEl.addEventListener('touchmove', _this.handleTouchMove); + } + targetEl.addEventListener('touchend', _this.handleTouchEnd); + targetEl.addEventListener('touchcancel', _this.handleTouchEnd); // treat it as a touch end + // attach a handler to get called when ANY scroll action happens on the page. + // this was impossible to do with normal on/off because 'scroll' doesn't bubble. + // http://stackoverflow.com/a/32954565/96342 + window.addEventListener('scroll', _this.handleTouchScroll, true); + } + }; + this.handleTouchMove = function (ev) { + var pev = _this.createEventFromTouch(ev); + _this.recordCoords(pev); + _this.emitter.trigger('pointermove', pev); + }; + this.handleTouchEnd = function (ev) { + if (_this.isDragging) { // done to guard against touchend followed by touchcancel + var targetEl = ev.target; + targetEl.removeEventListener('touchmove', _this.handleTouchMove); + targetEl.removeEventListener('touchend', _this.handleTouchEnd); + targetEl.removeEventListener('touchcancel', _this.handleTouchEnd); + window.removeEventListener('scroll', _this.handleTouchScroll, true); // useCaptured=true + _this.emitter.trigger('pointerup', _this.createEventFromTouch(ev)); + _this.cleanup(); // call last so that pointerup has access to props + _this.isTouchDragging = false; + startIgnoringMouse(); + } + }; + this.handleTouchScroll = function () { + _this.wasTouchScroll = true; + }; + this.handleScroll = function (ev) { + if (!_this.shouldIgnoreMove) { + var pageX = (window.pageXOffset - _this.prevScrollX) + _this.prevPageX; + var pageY = (window.pageYOffset - _this.prevScrollY) + _this.prevPageY; + _this.emitter.trigger('pointermove', { + origEvent: ev, + isTouch: _this.isTouchDragging, + subjectEl: _this.subjectEl, + pageX: pageX, + pageY: pageY, + deltaX: pageX - _this.origPageX, + deltaY: pageY - _this.origPageY, + }); + } + }; + this.containerEl = containerEl; + this.emitter = new Emitter(); + containerEl.addEventListener('mousedown', this.handleMouseDown); + containerEl.addEventListener('touchstart', this.handleTouchStart, { passive: true }); + listenerCreated(); + } + PointerDragging.prototype.destroy = function () { + this.containerEl.removeEventListener('mousedown', this.handleMouseDown); + this.containerEl.removeEventListener('touchstart', this.handleTouchStart, { passive: true }); + listenerDestroyed(); + }; + PointerDragging.prototype.tryStart = function (ev) { + var subjectEl = this.querySubjectEl(ev); + var downEl = ev.target; + if (subjectEl && + (!this.handleSelector || elementClosest(downEl, this.handleSelector))) { + this.subjectEl = subjectEl; + this.isDragging = true; // do this first so cancelTouchScroll will work + this.wasTouchScroll = false; + return true; + } + return false; + }; + PointerDragging.prototype.cleanup = function () { + isWindowTouchMoveCancelled = false; + this.isDragging = false; + this.subjectEl = null; + // keep wasTouchScroll around for later access + this.destroyScrollWatch(); + }; + PointerDragging.prototype.querySubjectEl = function (ev) { + if (this.selector) { + return elementClosest(ev.target, this.selector); + } + return this.containerEl; + }; + PointerDragging.prototype.shouldIgnoreMouse = function () { + return ignoreMouseDepth || this.isTouchDragging; + }; + // can be called by user of this class, to cancel touch-based scrolling for the current drag + PointerDragging.prototype.cancelTouchScroll = function () { + if (this.isDragging) { + isWindowTouchMoveCancelled = true; + } + }; + // Scrolling that simulates pointermoves + // ---------------------------------------------------------------------------------------------------- + PointerDragging.prototype.initScrollWatch = function (ev) { + if (this.shouldWatchScroll) { + this.recordCoords(ev); + window.addEventListener('scroll', this.handleScroll, true); // useCapture=true + } + }; + PointerDragging.prototype.recordCoords = function (ev) { + if (this.shouldWatchScroll) { + this.prevPageX = ev.pageX; + this.prevPageY = ev.pageY; + this.prevScrollX = window.pageXOffset; + this.prevScrollY = window.pageYOffset; + } + }; + PointerDragging.prototype.destroyScrollWatch = function () { + if (this.shouldWatchScroll) { + window.removeEventListener('scroll', this.handleScroll, true); // useCaptured=true + } + }; + // Event Normalization + // ---------------------------------------------------------------------------------------------------- + PointerDragging.prototype.createEventFromMouse = function (ev, isFirst) { + var deltaX = 0; + var deltaY = 0; + // TODO: repeat code + if (isFirst) { + this.origPageX = ev.pageX; + this.origPageY = ev.pageY; + } + else { + deltaX = ev.pageX - this.origPageX; + deltaY = ev.pageY - this.origPageY; + } + return { + origEvent: ev, + isTouch: false, + subjectEl: this.subjectEl, + pageX: ev.pageX, + pageY: ev.pageY, + deltaX: deltaX, + deltaY: deltaY, + }; + }; + PointerDragging.prototype.createEventFromTouch = function (ev, isFirst) { + var touches = ev.touches; + var pageX; + var pageY; + var deltaX = 0; + var deltaY = 0; + // if touch coords available, prefer, + // because FF would give bad ev.pageX ev.pageY + if (touches && touches.length) { + pageX = touches[0].pageX; + pageY = touches[0].pageY; + } + else { + pageX = ev.pageX; + pageY = ev.pageY; + } + // TODO: repeat code + if (isFirst) { + this.origPageX = pageX; + this.origPageY = pageY; + } + else { + deltaX = pageX - this.origPageX; + deltaY = pageY - this.origPageY; + } + return { + origEvent: ev, + isTouch: true, + subjectEl: this.subjectEl, + pageX: pageX, + pageY: pageY, + deltaX: deltaX, + deltaY: deltaY, + }; + }; + return PointerDragging; + }()); + // Returns a boolean whether this was a left mouse click and no ctrl key (which means right click on Mac) + function isPrimaryMouseButton(ev) { + return ev.button === 0 && !ev.ctrlKey; + } + // Ignoring fake mouse events generated by touch + // ---------------------------------------------------------------------------------------------------- + function startIgnoringMouse() { + ignoreMouseDepth += 1; + setTimeout(function () { + ignoreMouseDepth -= 1; + }, config.touchMouseIgnoreWait); + } + // We want to attach touchmove as early as possible for Safari + // ---------------------------------------------------------------------------------------------------- + function listenerCreated() { + listenerCnt += 1; + if (listenerCnt === 1) { + window.addEventListener('touchmove', onWindowTouchMove, { passive: false }); + } + } + function listenerDestroyed() { + listenerCnt -= 1; + if (!listenerCnt) { + window.removeEventListener('touchmove', onWindowTouchMove, { passive: false }); + } + } + function onWindowTouchMove(ev) { + if (isWindowTouchMoveCancelled) { + ev.preventDefault(); + } + } + + /* + An effect in which an element follows the movement of a pointer across the screen. + The moving element is a clone of some other element. + Must call start + handleMove + stop. + */ + var ElementMirror = /** @class */ (function () { + function ElementMirror() { + this.isVisible = false; // must be explicitly enabled + this.sourceEl = null; + this.mirrorEl = null; + this.sourceElRect = null; // screen coords relative to viewport + // options that can be set directly by caller + this.parentNode = document.body; + this.zIndex = 9999; + this.revertDuration = 0; + } + ElementMirror.prototype.start = function (sourceEl, pageX, pageY) { + this.sourceEl = sourceEl; + this.sourceElRect = this.sourceEl.getBoundingClientRect(); + this.origScreenX = pageX - window.pageXOffset; + this.origScreenY = pageY - window.pageYOffset; + this.deltaX = 0; + this.deltaY = 0; + this.updateElPosition(); + }; + ElementMirror.prototype.handleMove = function (pageX, pageY) { + this.deltaX = (pageX - window.pageXOffset) - this.origScreenX; + this.deltaY = (pageY - window.pageYOffset) - this.origScreenY; + this.updateElPosition(); + }; + // can be called before start + ElementMirror.prototype.setIsVisible = function (bool) { + if (bool) { + if (!this.isVisible) { + if (this.mirrorEl) { + this.mirrorEl.style.display = ''; + } + this.isVisible = bool; // needs to happen before updateElPosition + this.updateElPosition(); // because was not updating the position while invisible + } + } + else if (this.isVisible) { + if (this.mirrorEl) { + this.mirrorEl.style.display = 'none'; + } + this.isVisible = bool; + } + }; + // always async + ElementMirror.prototype.stop = function (needsRevertAnimation, callback) { + var _this = this; + var done = function () { + _this.cleanup(); + callback(); + }; + if (needsRevertAnimation && + this.mirrorEl && + this.isVisible && + this.revertDuration && // if 0, transition won't work + (this.deltaX || this.deltaY) // if same coords, transition won't work + ) { + this.doRevertAnimation(done, this.revertDuration); + } + else { + setTimeout(done, 0); + } + }; + ElementMirror.prototype.doRevertAnimation = function (callback, revertDuration) { + var mirrorEl = this.mirrorEl; + var finalSourceElRect = this.sourceEl.getBoundingClientRect(); // because autoscrolling might have happened + mirrorEl.style.transition = + 'top ' + revertDuration + 'ms,' + + 'left ' + revertDuration + 'ms'; + applyStyle(mirrorEl, { + left: finalSourceElRect.left, + top: finalSourceElRect.top, + }); + whenTransitionDone(mirrorEl, function () { + mirrorEl.style.transition = ''; + callback(); + }); + }; + ElementMirror.prototype.cleanup = function () { + if (this.mirrorEl) { + removeElement(this.mirrorEl); + this.mirrorEl = null; + } + this.sourceEl = null; + }; + ElementMirror.prototype.updateElPosition = function () { + if (this.sourceEl && this.isVisible) { + applyStyle(this.getMirrorEl(), { + left: this.sourceElRect.left + this.deltaX, + top: this.sourceElRect.top + this.deltaY, + }); + } + }; + ElementMirror.prototype.getMirrorEl = function () { + var sourceElRect = this.sourceElRect; + var mirrorEl = this.mirrorEl; + if (!mirrorEl) { + mirrorEl = this.mirrorEl = this.sourceEl.cloneNode(true); // cloneChildren=true + // we don't want long taps or any mouse interaction causing selection/menus. + // would use preventSelection(), but that prevents selectstart, causing problems. + mirrorEl.classList.add('fc-unselectable'); + mirrorEl.classList.add('fc-event-dragging'); + applyStyle(mirrorEl, { + position: 'fixed', + zIndex: this.zIndex, + visibility: '', + boxSizing: 'border-box', + width: sourceElRect.right - sourceElRect.left, + height: sourceElRect.bottom - sourceElRect.top, + right: 'auto', + bottom: 'auto', + margin: 0, + }); + this.parentNode.appendChild(mirrorEl); + } + return mirrorEl; + }; + return ElementMirror; + }()); + + /* + Is a cache for a given element's scroll information (all the info that ScrollController stores) + in addition the "client rectangle" of the element.. the area within the scrollbars. + + The cache can be in one of two modes: + - doesListening:false - ignores when the container is scrolled by someone else + - doesListening:true - watch for scrolling and update the cache + */ + var ScrollGeomCache = /** @class */ (function (_super) { + __extends(ScrollGeomCache, _super); + function ScrollGeomCache(scrollController, doesListening) { + var _this = _super.call(this) || this; + _this.handleScroll = function () { + _this.scrollTop = _this.scrollController.getScrollTop(); + _this.scrollLeft = _this.scrollController.getScrollLeft(); + _this.handleScrollChange(); + }; + _this.scrollController = scrollController; + _this.doesListening = doesListening; + _this.scrollTop = _this.origScrollTop = scrollController.getScrollTop(); + _this.scrollLeft = _this.origScrollLeft = scrollController.getScrollLeft(); + _this.scrollWidth = scrollController.getScrollWidth(); + _this.scrollHeight = scrollController.getScrollHeight(); + _this.clientWidth = scrollController.getClientWidth(); + _this.clientHeight = scrollController.getClientHeight(); + _this.clientRect = _this.computeClientRect(); // do last in case it needs cached values + if (_this.doesListening) { + _this.getEventTarget().addEventListener('scroll', _this.handleScroll); + } + return _this; + } + ScrollGeomCache.prototype.destroy = function () { + if (this.doesListening) { + this.getEventTarget().removeEventListener('scroll', this.handleScroll); + } + }; + ScrollGeomCache.prototype.getScrollTop = function () { + return this.scrollTop; + }; + ScrollGeomCache.prototype.getScrollLeft = function () { + return this.scrollLeft; + }; + ScrollGeomCache.prototype.setScrollTop = function (top) { + this.scrollController.setScrollTop(top); + if (!this.doesListening) { + // we are not relying on the element to normalize out-of-bounds scroll values + // so we need to sanitize ourselves + this.scrollTop = Math.max(Math.min(top, this.getMaxScrollTop()), 0); + this.handleScrollChange(); + } + }; + ScrollGeomCache.prototype.setScrollLeft = function (top) { + this.scrollController.setScrollLeft(top); + if (!this.doesListening) { + // we are not relying on the element to normalize out-of-bounds scroll values + // so we need to sanitize ourselves + this.scrollLeft = Math.max(Math.min(top, this.getMaxScrollLeft()), 0); + this.handleScrollChange(); + } + }; + ScrollGeomCache.prototype.getClientWidth = function () { + return this.clientWidth; + }; + ScrollGeomCache.prototype.getClientHeight = function () { + return this.clientHeight; + }; + ScrollGeomCache.prototype.getScrollWidth = function () { + return this.scrollWidth; + }; + ScrollGeomCache.prototype.getScrollHeight = function () { + return this.scrollHeight; + }; + ScrollGeomCache.prototype.handleScrollChange = function () { + }; + return ScrollGeomCache; + }(ScrollController)); + + var ElementScrollGeomCache = /** @class */ (function (_super) { + __extends(ElementScrollGeomCache, _super); + function ElementScrollGeomCache(el, doesListening) { + return _super.call(this, new ElementScrollController(el), doesListening) || this; + } + ElementScrollGeomCache.prototype.getEventTarget = function () { + return this.scrollController.el; + }; + ElementScrollGeomCache.prototype.computeClientRect = function () { + return computeInnerRect(this.scrollController.el); + }; + return ElementScrollGeomCache; + }(ScrollGeomCache)); + + var WindowScrollGeomCache = /** @class */ (function (_super) { + __extends(WindowScrollGeomCache, _super); + function WindowScrollGeomCache(doesListening) { + return _super.call(this, new WindowScrollController(), doesListening) || this; + } + WindowScrollGeomCache.prototype.getEventTarget = function () { + return window; + }; + WindowScrollGeomCache.prototype.computeClientRect = function () { + return { + left: this.scrollLeft, + right: this.scrollLeft + this.clientWidth, + top: this.scrollTop, + bottom: this.scrollTop + this.clientHeight, + }; + }; + // the window is the only scroll object that changes it's rectangle relative + // to the document's topleft as it scrolls + WindowScrollGeomCache.prototype.handleScrollChange = function () { + this.clientRect = this.computeClientRect(); + }; + return WindowScrollGeomCache; + }(ScrollGeomCache)); + + // If available we are using native "performance" API instead of "Date" + // Read more about it on MDN: + // https://developer.mozilla.org/en-US/docs/Web/API/Performance + var getTime = typeof performance === 'function' ? performance.now : Date.now; + /* + For a pointer interaction, automatically scrolls certain scroll containers when the pointer + approaches the edge. + + The caller must call start + handleMove + stop. + */ + var AutoScroller = /** @class */ (function () { + function AutoScroller() { + var _this = this; + // options that can be set by caller + this.isEnabled = true; + this.scrollQuery = [window, '.fc-scroller']; + this.edgeThreshold = 50; // pixels + this.maxVelocity = 300; // pixels per second + // internal state + this.pointerScreenX = null; + this.pointerScreenY = null; + this.isAnimating = false; + this.scrollCaches = null; + // protect against the initial pointerdown being too close to an edge and starting the scroll + this.everMovedUp = false; + this.everMovedDown = false; + this.everMovedLeft = false; + this.everMovedRight = false; + this.animate = function () { + if (_this.isAnimating) { // wasn't cancelled between animation calls + var edge = _this.computeBestEdge(_this.pointerScreenX + window.pageXOffset, _this.pointerScreenY + window.pageYOffset); + if (edge) { + var now = getTime(); + _this.handleSide(edge, (now - _this.msSinceRequest) / 1000); + _this.requestAnimation(now); + } + else { + _this.isAnimating = false; // will stop animation + } + } + }; + } + AutoScroller.prototype.start = function (pageX, pageY) { + if (this.isEnabled) { + this.scrollCaches = this.buildCaches(); + this.pointerScreenX = null; + this.pointerScreenY = null; + this.everMovedUp = false; + this.everMovedDown = false; + this.everMovedLeft = false; + this.everMovedRight = false; + this.handleMove(pageX, pageY); + } + }; + AutoScroller.prototype.handleMove = function (pageX, pageY) { + if (this.isEnabled) { + var pointerScreenX = pageX - window.pageXOffset; + var pointerScreenY = pageY - window.pageYOffset; + var yDelta = this.pointerScreenY === null ? 0 : pointerScreenY - this.pointerScreenY; + var xDelta = this.pointerScreenX === null ? 0 : pointerScreenX - this.pointerScreenX; + if (yDelta < 0) { + this.everMovedUp = true; + } + else if (yDelta > 0) { + this.everMovedDown = true; + } + if (xDelta < 0) { + this.everMovedLeft = true; + } + else if (xDelta > 0) { + this.everMovedRight = true; + } + this.pointerScreenX = pointerScreenX; + this.pointerScreenY = pointerScreenY; + if (!this.isAnimating) { + this.isAnimating = true; + this.requestAnimation(getTime()); + } + } + }; + AutoScroller.prototype.stop = function () { + if (this.isEnabled) { + this.isAnimating = false; // will stop animation + for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { + var scrollCache = _a[_i]; + scrollCache.destroy(); + } + this.scrollCaches = null; + } + }; + AutoScroller.prototype.requestAnimation = function (now) { + this.msSinceRequest = now; + requestAnimationFrame(this.animate); + }; + AutoScroller.prototype.handleSide = function (edge, seconds) { + var scrollCache = edge.scrollCache; + var edgeThreshold = this.edgeThreshold; + var invDistance = edgeThreshold - edge.distance; + var velocity = // the closer to the edge, the faster we scroll + ((invDistance * invDistance) / (edgeThreshold * edgeThreshold)) * // quadratic + this.maxVelocity * seconds; + var sign = 1; + switch (edge.name) { + case 'left': + sign = -1; + // falls through + case 'right': + scrollCache.setScrollLeft(scrollCache.getScrollLeft() + velocity * sign); + break; + case 'top': + sign = -1; + // falls through + case 'bottom': + scrollCache.setScrollTop(scrollCache.getScrollTop() + velocity * sign); + break; + } + }; + // left/top are relative to document topleft + AutoScroller.prototype.computeBestEdge = function (left, top) { + var edgeThreshold = this.edgeThreshold; + var bestSide = null; + for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { + var scrollCache = _a[_i]; + var rect = scrollCache.clientRect; + var leftDist = left - rect.left; + var rightDist = rect.right - left; + var topDist = top - rect.top; + var bottomDist = rect.bottom - top; + // completely within the rect? + if (leftDist >= 0 && rightDist >= 0 && topDist >= 0 && bottomDist >= 0) { + if (topDist <= edgeThreshold && this.everMovedUp && scrollCache.canScrollUp() && + (!bestSide || bestSide.distance > topDist)) { + bestSide = { scrollCache: scrollCache, name: 'top', distance: topDist }; + } + if (bottomDist <= edgeThreshold && this.everMovedDown && scrollCache.canScrollDown() && + (!bestSide || bestSide.distance > bottomDist)) { + bestSide = { scrollCache: scrollCache, name: 'bottom', distance: bottomDist }; + } + if (leftDist <= edgeThreshold && this.everMovedLeft && scrollCache.canScrollLeft() && + (!bestSide || bestSide.distance > leftDist)) { + bestSide = { scrollCache: scrollCache, name: 'left', distance: leftDist }; + } + if (rightDist <= edgeThreshold && this.everMovedRight && scrollCache.canScrollRight() && + (!bestSide || bestSide.distance > rightDist)) { + bestSide = { scrollCache: scrollCache, name: 'right', distance: rightDist }; + } + } + } + return bestSide; + }; + AutoScroller.prototype.buildCaches = function () { + return this.queryScrollEls().map(function (el) { + if (el === window) { + return new WindowScrollGeomCache(false); // false = don't listen to user-generated scrolls + } + return new ElementScrollGeomCache(el, false); // false = don't listen to user-generated scrolls + }); + }; + AutoScroller.prototype.queryScrollEls = function () { + var els = []; + for (var _i = 0, _a = this.scrollQuery; _i < _a.length; _i++) { + var query = _a[_i]; + if (typeof query === 'object') { + els.push(query); + } + else { + els.push.apply(els, Array.prototype.slice.call(document.querySelectorAll(query))); + } + } + return els; + }; + return AutoScroller; + }()); + + /* + Monitors dragging on an element. Has a number of high-level features: + - minimum distance required before dragging + - minimum wait time ("delay") before dragging + - a mirror element that follows the pointer + */ + var FeaturefulElementDragging = /** @class */ (function (_super) { + __extends(FeaturefulElementDragging, _super); + function FeaturefulElementDragging(containerEl, selector) { + var _this = _super.call(this, containerEl) || this; + // options that can be directly set by caller + // the caller can also set the PointerDragging's options as well + _this.delay = null; + _this.minDistance = 0; + _this.touchScrollAllowed = true; // prevents drag from starting and blocks scrolling during drag + _this.mirrorNeedsRevert = false; + _this.isInteracting = false; // is the user validly moving the pointer? lasts until pointerup + _this.isDragging = false; // is it INTENTFULLY dragging? lasts until after revert animation + _this.isDelayEnded = false; + _this.isDistanceSurpassed = false; + _this.delayTimeoutId = null; + _this.onPointerDown = function (ev) { + if (!_this.isDragging) { // so new drag doesn't happen while revert animation is going + _this.isInteracting = true; + _this.isDelayEnded = false; + _this.isDistanceSurpassed = false; + preventSelection(document.body); + preventContextMenu(document.body); + // prevent links from being visited if there's an eventual drag. + // also prevents selection in older browsers (maybe?). + // not necessary for touch, besides, browser would complain about passiveness. + if (!ev.isTouch) { + ev.origEvent.preventDefault(); + } + _this.emitter.trigger('pointerdown', ev); + if (_this.isInteracting && // not destroyed via pointerdown handler + !_this.pointer.shouldIgnoreMove) { + // actions related to initiating dragstart+dragmove+dragend... + _this.mirror.setIsVisible(false); // reset. caller must set-visible + _this.mirror.start(ev.subjectEl, ev.pageX, ev.pageY); // must happen on first pointer down + _this.startDelay(ev); + if (!_this.minDistance) { + _this.handleDistanceSurpassed(ev); + } + } + } + }; + _this.onPointerMove = function (ev) { + if (_this.isInteracting) { + _this.emitter.trigger('pointermove', ev); + if (!_this.isDistanceSurpassed) { + var minDistance = _this.minDistance; + var distanceSq = void 0; // current distance from the origin, squared + var deltaX = ev.deltaX, deltaY = ev.deltaY; + distanceSq = deltaX * deltaX + deltaY * deltaY; + if (distanceSq >= minDistance * minDistance) { // use pythagorean theorem + _this.handleDistanceSurpassed(ev); + } + } + if (_this.isDragging) { + // a real pointer move? (not one simulated by scrolling) + if (ev.origEvent.type !== 'scroll') { + _this.mirror.handleMove(ev.pageX, ev.pageY); + _this.autoScroller.handleMove(ev.pageX, ev.pageY); + } + _this.emitter.trigger('dragmove', ev); + } + } + }; + _this.onPointerUp = function (ev) { + if (_this.isInteracting) { + _this.isInteracting = false; + allowSelection(document.body); + allowContextMenu(document.body); + _this.emitter.trigger('pointerup', ev); // can potentially set mirrorNeedsRevert + if (_this.isDragging) { + _this.autoScroller.stop(); + _this.tryStopDrag(ev); // which will stop the mirror + } + if (_this.delayTimeoutId) { + clearTimeout(_this.delayTimeoutId); + _this.delayTimeoutId = null; + } + } + }; + var pointer = _this.pointer = new PointerDragging(containerEl); + pointer.emitter.on('pointerdown', _this.onPointerDown); + pointer.emitter.on('pointermove', _this.onPointerMove); + pointer.emitter.on('pointerup', _this.onPointerUp); + if (selector) { + pointer.selector = selector; + } + _this.mirror = new ElementMirror(); + _this.autoScroller = new AutoScroller(); + return _this; + } + FeaturefulElementDragging.prototype.destroy = function () { + this.pointer.destroy(); + // HACK: simulate a pointer-up to end the current drag + // TODO: fire 'dragend' directly and stop interaction. discourage use of pointerup event (b/c might not fire) + this.onPointerUp({}); + }; + FeaturefulElementDragging.prototype.startDelay = function (ev) { + var _this = this; + if (typeof this.delay === 'number') { + this.delayTimeoutId = setTimeout(function () { + _this.delayTimeoutId = null; + _this.handleDelayEnd(ev); + }, this.delay); // not assignable to number! + } + else { + this.handleDelayEnd(ev); + } + }; + FeaturefulElementDragging.prototype.handleDelayEnd = function (ev) { + this.isDelayEnded = true; + this.tryStartDrag(ev); + }; + FeaturefulElementDragging.prototype.handleDistanceSurpassed = function (ev) { + this.isDistanceSurpassed = true; + this.tryStartDrag(ev); + }; + FeaturefulElementDragging.prototype.tryStartDrag = function (ev) { + if (this.isDelayEnded && this.isDistanceSurpassed) { + if (!this.pointer.wasTouchScroll || this.touchScrollAllowed) { + this.isDragging = true; + this.mirrorNeedsRevert = false; + this.autoScroller.start(ev.pageX, ev.pageY); + this.emitter.trigger('dragstart', ev); + if (this.touchScrollAllowed === false) { + this.pointer.cancelTouchScroll(); + } + } + } + }; + FeaturefulElementDragging.prototype.tryStopDrag = function (ev) { + // .stop() is ALWAYS asynchronous, which we NEED because we want all pointerup events + // that come from the document to fire beforehand. much more convenient this way. + this.mirror.stop(this.mirrorNeedsRevert, this.stopDrag.bind(this, ev)); + }; + FeaturefulElementDragging.prototype.stopDrag = function (ev) { + this.isDragging = false; + this.emitter.trigger('dragend', ev); + }; + // fill in the implementations... + FeaturefulElementDragging.prototype.setIgnoreMove = function (bool) { + this.pointer.shouldIgnoreMove = bool; + }; + FeaturefulElementDragging.prototype.setMirrorIsVisible = function (bool) { + this.mirror.setIsVisible(bool); + }; + FeaturefulElementDragging.prototype.setMirrorNeedsRevert = function (bool) { + this.mirrorNeedsRevert = bool; + }; + FeaturefulElementDragging.prototype.setAutoScrollEnabled = function (bool) { + this.autoScroller.isEnabled = bool; + }; + return FeaturefulElementDragging; + }(ElementDragging)); + + /* + When this class is instantiated, it records the offset of an element (relative to the document topleft), + and continues to monitor scrolling, updating the cached coordinates if it needs to. + Does not access the DOM after instantiation, so highly performant. + + Also keeps track of all scrolling/overflow:hidden containers that are parents of the given element + and an determine if a given point is inside the combined clipping rectangle. + */ + var OffsetTracker = /** @class */ (function () { + function OffsetTracker(el) { + this.origRect = computeRect(el); + // will work fine for divs that have overflow:hidden + this.scrollCaches = getClippingParents(el).map(function (scrollEl) { return new ElementScrollGeomCache(scrollEl, true); }); + } + OffsetTracker.prototype.destroy = function () { + for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { + var scrollCache = _a[_i]; + scrollCache.destroy(); + } + }; + OffsetTracker.prototype.computeLeft = function () { + var left = this.origRect.left; + for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { + var scrollCache = _a[_i]; + left += scrollCache.origScrollLeft - scrollCache.getScrollLeft(); + } + return left; + }; + OffsetTracker.prototype.computeTop = function () { + var top = this.origRect.top; + for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { + var scrollCache = _a[_i]; + top += scrollCache.origScrollTop - scrollCache.getScrollTop(); + } + return top; + }; + OffsetTracker.prototype.isWithinClipping = function (pageX, pageY) { + var point = { left: pageX, top: pageY }; + for (var _i = 0, _a = this.scrollCaches; _i < _a.length; _i++) { + var scrollCache = _a[_i]; + if (!isIgnoredClipping(scrollCache.getEventTarget()) && + !pointInsideRect(point, scrollCache.clientRect)) { + return false; + } + } + return true; + }; + return OffsetTracker; + }()); + // certain clipping containers should never constrain interactions, like and + // https://github.com/fullcalendar/fullcalendar/issues/3615 + function isIgnoredClipping(node) { + var tagName = node.tagName; + return tagName === 'HTML' || tagName === 'BODY'; + } + + /* + Tracks movement over multiple droppable areas (aka "hits") + that exist in one or more DateComponents. + Relies on an existing draggable. + + emits: + - pointerdown + - dragstart + - hitchange - fires initially, even if not over a hit + - pointerup + - (hitchange - again, to null, if ended over a hit) + - dragend + */ + var HitDragging = /** @class */ (function () { + function HitDragging(dragging, droppableStore) { + var _this = this; + // options that can be set by caller + this.useSubjectCenter = false; + this.requireInitial = true; // if doesn't start out on a hit, won't emit any events + this.initialHit = null; + this.movingHit = null; + this.finalHit = null; // won't ever be populated if shouldIgnoreMove + this.handlePointerDown = function (ev) { + var dragging = _this.dragging; + _this.initialHit = null; + _this.movingHit = null; + _this.finalHit = null; + _this.prepareHits(); + _this.processFirstCoord(ev); + if (_this.initialHit || !_this.requireInitial) { + dragging.setIgnoreMove(false); + // TODO: fire this before computing processFirstCoord, so listeners can cancel. this gets fired by almost every handler :( + _this.emitter.trigger('pointerdown', ev); + } + else { + dragging.setIgnoreMove(true); + } + }; + this.handleDragStart = function (ev) { + _this.emitter.trigger('dragstart', ev); + _this.handleMove(ev, true); // force = fire even if initially null + }; + this.handleDragMove = function (ev) { + _this.emitter.trigger('dragmove', ev); + _this.handleMove(ev); + }; + this.handlePointerUp = function (ev) { + _this.releaseHits(); + _this.emitter.trigger('pointerup', ev); + }; + this.handleDragEnd = function (ev) { + if (_this.movingHit) { + _this.emitter.trigger('hitupdate', null, true, ev); + } + _this.finalHit = _this.movingHit; + _this.movingHit = null; + _this.emitter.trigger('dragend', ev); + }; + this.droppableStore = droppableStore; + dragging.emitter.on('pointerdown', this.handlePointerDown); + dragging.emitter.on('dragstart', this.handleDragStart); + dragging.emitter.on('dragmove', this.handleDragMove); + dragging.emitter.on('pointerup', this.handlePointerUp); + dragging.emitter.on('dragend', this.handleDragEnd); + this.dragging = dragging; + this.emitter = new Emitter(); + } + // sets initialHit + // sets coordAdjust + HitDragging.prototype.processFirstCoord = function (ev) { + var origPoint = { left: ev.pageX, top: ev.pageY }; + var adjustedPoint = origPoint; + var subjectEl = ev.subjectEl; + var subjectRect; + if (subjectEl !== document) { + subjectRect = computeRect(subjectEl); + adjustedPoint = constrainPoint(adjustedPoint, subjectRect); + } + var initialHit = this.initialHit = this.queryHitForOffset(adjustedPoint.left, adjustedPoint.top); + if (initialHit) { + if (this.useSubjectCenter && subjectRect) { + var slicedSubjectRect = intersectRects(subjectRect, initialHit.rect); + if (slicedSubjectRect) { + adjustedPoint = getRectCenter(slicedSubjectRect); + } + } + this.coordAdjust = diffPoints(adjustedPoint, origPoint); + } + else { + this.coordAdjust = { left: 0, top: 0 }; + } + }; + HitDragging.prototype.handleMove = function (ev, forceHandle) { + var hit = this.queryHitForOffset(ev.pageX + this.coordAdjust.left, ev.pageY + this.coordAdjust.top); + if (forceHandle || !isHitsEqual(this.movingHit, hit)) { + this.movingHit = hit; + this.emitter.trigger('hitupdate', hit, false, ev); + } + }; + HitDragging.prototype.prepareHits = function () { + this.offsetTrackers = mapHash(this.droppableStore, function (interactionSettings) { + interactionSettings.component.prepareHits(); + return new OffsetTracker(interactionSettings.el); + }); + }; + HitDragging.prototype.releaseHits = function () { + var offsetTrackers = this.offsetTrackers; + for (var id in offsetTrackers) { + offsetTrackers[id].destroy(); + } + this.offsetTrackers = {}; + }; + HitDragging.prototype.queryHitForOffset = function (offsetLeft, offsetTop) { + var _a = this, droppableStore = _a.droppableStore, offsetTrackers = _a.offsetTrackers; + var bestHit = null; + for (var id in droppableStore) { + var component = droppableStore[id].component; + var offsetTracker = offsetTrackers[id]; + if (offsetTracker && // wasn't destroyed mid-drag + offsetTracker.isWithinClipping(offsetLeft, offsetTop)) { + var originLeft = offsetTracker.computeLeft(); + var originTop = offsetTracker.computeTop(); + var positionLeft = offsetLeft - originLeft; + var positionTop = offsetTop - originTop; + var origRect = offsetTracker.origRect; + var width = origRect.right - origRect.left; + var height = origRect.bottom - origRect.top; + if ( + // must be within the element's bounds + positionLeft >= 0 && positionLeft < width && + positionTop >= 0 && positionTop < height) { + var hit = component.queryHit(positionLeft, positionTop, width, height); + if (hit && ( + // make sure the hit is within activeRange, meaning it's not a dead cell + rangeContainsRange(hit.dateProfile.activeRange, hit.dateSpan.range)) && + (!bestHit || hit.layer > bestHit.layer)) { + hit.componentId = id; + hit.context = component.context; + // TODO: better way to re-orient rectangle + hit.rect.left += originLeft; + hit.rect.right += originLeft; + hit.rect.top += originTop; + hit.rect.bottom += originTop; + bestHit = hit; + } + } + } + } + return bestHit; + }; + return HitDragging; + }()); + function isHitsEqual(hit0, hit1) { + if (!hit0 && !hit1) { + return true; + } + if (Boolean(hit0) !== Boolean(hit1)) { + return false; + } + return isDateSpansEqual(hit0.dateSpan, hit1.dateSpan); + } + + function buildDatePointApiWithContext(dateSpan, context) { + var props = {}; + for (var _i = 0, _a = context.pluginHooks.datePointTransforms; _i < _a.length; _i++) { + var transform = _a[_i]; + __assign(props, transform(dateSpan, context)); + } + __assign(props, buildDatePointApi(dateSpan, context.dateEnv)); + return props; + } + function buildDatePointApi(span, dateEnv) { + return { + date: dateEnv.toDate(span.range.start), + dateStr: dateEnv.formatIso(span.range.start, { omitTime: span.allDay }), + allDay: span.allDay, + }; + } + + /* + Monitors when the user clicks on a specific date/time of a component. + A pointerdown+pointerup on the same "hit" constitutes a click. + */ + var DateClicking = /** @class */ (function (_super) { + __extends(DateClicking, _super); + function DateClicking(settings) { + var _this = _super.call(this, settings) || this; + _this.handlePointerDown = function (pev) { + var dragging = _this.dragging; + var downEl = pev.origEvent.target; + // do this in pointerdown (not dragend) because DOM might be mutated by the time dragend is fired + dragging.setIgnoreMove(!_this.component.isValidDateDownEl(downEl)); + }; + // won't even fire if moving was ignored + _this.handleDragEnd = function (ev) { + var component = _this.component; + var pointer = _this.dragging.pointer; + if (!pointer.wasTouchScroll) { + var _a = _this.hitDragging, initialHit = _a.initialHit, finalHit = _a.finalHit; + if (initialHit && finalHit && isHitsEqual(initialHit, finalHit)) { + var context = component.context; + var arg = __assign(__assign({}, buildDatePointApiWithContext(initialHit.dateSpan, context)), { dayEl: initialHit.dayEl, jsEvent: ev.origEvent, view: context.viewApi || context.calendarApi.view }); + context.emitter.trigger('dateClick', arg); + } + } + }; + // we DO want to watch pointer moves because otherwise finalHit won't get populated + _this.dragging = new FeaturefulElementDragging(settings.el); + _this.dragging.autoScroller.isEnabled = false; + var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, interactionSettingsToStore(settings)); + hitDragging.emitter.on('pointerdown', _this.handlePointerDown); + hitDragging.emitter.on('dragend', _this.handleDragEnd); + return _this; + } + DateClicking.prototype.destroy = function () { + this.dragging.destroy(); + }; + return DateClicking; + }(Interaction)); + + /* + Tracks when the user selects a portion of time of a component, + constituted by a drag over date cells, with a possible delay at the beginning of the drag. + */ + var DateSelecting = /** @class */ (function (_super) { + __extends(DateSelecting, _super); + function DateSelecting(settings) { + var _this = _super.call(this, settings) || this; + _this.dragSelection = null; + _this.handlePointerDown = function (ev) { + var _a = _this, component = _a.component, dragging = _a.dragging; + var options = component.context.options; + var canSelect = options.selectable && + component.isValidDateDownEl(ev.origEvent.target); + // don't bother to watch expensive moves if component won't do selection + dragging.setIgnoreMove(!canSelect); + // if touch, require user to hold down + dragging.delay = ev.isTouch ? getComponentTouchDelay$1(component) : null; + }; + _this.handleDragStart = function (ev) { + _this.component.context.calendarApi.unselect(ev); // unselect previous selections + }; + _this.handleHitUpdate = function (hit, isFinal) { + var context = _this.component.context; + var dragSelection = null; + var isInvalid = false; + if (hit) { + var initialHit = _this.hitDragging.initialHit; + var disallowed = hit.componentId === initialHit.componentId + && _this.isHitComboAllowed + && !_this.isHitComboAllowed(initialHit, hit); + if (!disallowed) { + dragSelection = joinHitsIntoSelection(initialHit, hit, context.pluginHooks.dateSelectionTransformers); + } + if (!dragSelection || !isDateSelectionValid(dragSelection, hit.dateProfile, context)) { + isInvalid = true; + dragSelection = null; + } + } + if (dragSelection) { + context.dispatch({ type: 'SELECT_DATES', selection: dragSelection }); + } + else if (!isFinal) { // only unselect if moved away while dragging + context.dispatch({ type: 'UNSELECT_DATES' }); + } + if (!isInvalid) { + enableCursor(); + } + else { + disableCursor(); + } + if (!isFinal) { + _this.dragSelection = dragSelection; // only clear if moved away from all hits while dragging + } + }; + _this.handlePointerUp = function (pev) { + if (_this.dragSelection) { + // selection is already rendered, so just need to report selection + triggerDateSelect(_this.dragSelection, pev, _this.component.context); + _this.dragSelection = null; + } + }; + var component = settings.component; + var options = component.context.options; + var dragging = _this.dragging = new FeaturefulElementDragging(settings.el); + dragging.touchScrollAllowed = false; + dragging.minDistance = options.selectMinDistance || 0; + dragging.autoScroller.isEnabled = options.dragScroll; + var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, interactionSettingsToStore(settings)); + hitDragging.emitter.on('pointerdown', _this.handlePointerDown); + hitDragging.emitter.on('dragstart', _this.handleDragStart); + hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); + hitDragging.emitter.on('pointerup', _this.handlePointerUp); + return _this; + } + DateSelecting.prototype.destroy = function () { + this.dragging.destroy(); + }; + return DateSelecting; + }(Interaction)); + function getComponentTouchDelay$1(component) { + var options = component.context.options; + var delay = options.selectLongPressDelay; + if (delay == null) { + delay = options.longPressDelay; + } + return delay; + } + function joinHitsIntoSelection(hit0, hit1, dateSelectionTransformers) { + var dateSpan0 = hit0.dateSpan; + var dateSpan1 = hit1.dateSpan; + var ms = [ + dateSpan0.range.start, + dateSpan0.range.end, + dateSpan1.range.start, + dateSpan1.range.end, + ]; + ms.sort(compareNumbers); + var props = {}; + for (var _i = 0, dateSelectionTransformers_1 = dateSelectionTransformers; _i < dateSelectionTransformers_1.length; _i++) { + var transformer = dateSelectionTransformers_1[_i]; + var res = transformer(hit0, hit1); + if (res === false) { + return null; + } + if (res) { + __assign(props, res); + } + } + props.range = { start: ms[0], end: ms[3] }; + props.allDay = dateSpan0.allDay; + return props; + } + + var EventDragging = /** @class */ (function (_super) { + __extends(EventDragging, _super); + function EventDragging(settings) { + var _this = _super.call(this, settings) || this; + // internal state + _this.subjectEl = null; + _this.subjectSeg = null; // the seg being selected/dragged + _this.isDragging = false; + _this.eventRange = null; + _this.relevantEvents = null; // the events being dragged + _this.receivingContext = null; + _this.validMutation = null; + _this.mutatedRelevantEvents = null; + _this.handlePointerDown = function (ev) { + var origTarget = ev.origEvent.target; + var _a = _this, component = _a.component, dragging = _a.dragging; + var mirror = dragging.mirror; + var options = component.context.options; + var initialContext = component.context; + _this.subjectEl = ev.subjectEl; + var subjectSeg = _this.subjectSeg = getElSeg(ev.subjectEl); + var eventRange = _this.eventRange = subjectSeg.eventRange; + var eventInstanceId = eventRange.instance.instanceId; + _this.relevantEvents = getRelevantEvents(initialContext.getCurrentData().eventStore, eventInstanceId); + dragging.minDistance = ev.isTouch ? 0 : options.eventDragMinDistance; + dragging.delay = + // only do a touch delay if touch and this event hasn't been selected yet + (ev.isTouch && eventInstanceId !== component.props.eventSelection) ? + getComponentTouchDelay(component) : + null; + if (options.fixedMirrorParent) { + mirror.parentNode = options.fixedMirrorParent; + } + else { + mirror.parentNode = elementClosest(origTarget, '.fc'); + } + mirror.revertDuration = options.dragRevertDuration; + var isValid = component.isValidSegDownEl(origTarget) && + !elementClosest(origTarget, '.fc-event-resizer'); // NOT on a resizer + dragging.setIgnoreMove(!isValid); + // disable dragging for elements that are resizable (ie, selectable) + // but are not draggable + _this.isDragging = isValid && + ev.subjectEl.classList.contains('fc-event-draggable'); + }; + _this.handleDragStart = function (ev) { + var initialContext = _this.component.context; + var eventRange = _this.eventRange; + var eventInstanceId = eventRange.instance.instanceId; + if (ev.isTouch) { + // need to select a different event? + if (eventInstanceId !== _this.component.props.eventSelection) { + initialContext.dispatch({ type: 'SELECT_EVENT', eventInstanceId: eventInstanceId }); + } + } + else { + // if now using mouse, but was previous touch interaction, clear selected event + initialContext.dispatch({ type: 'UNSELECT_EVENT' }); + } + if (_this.isDragging) { + initialContext.calendarApi.unselect(ev); // unselect *date* selection + initialContext.emitter.trigger('eventDragStart', { + el: _this.subjectEl, + event: new EventApi(initialContext, eventRange.def, eventRange.instance), + jsEvent: ev.origEvent, + view: initialContext.viewApi, + }); + } + }; + _this.handleHitUpdate = function (hit, isFinal) { + if (!_this.isDragging) { + return; + } + var relevantEvents = _this.relevantEvents; + var initialHit = _this.hitDragging.initialHit; + var initialContext = _this.component.context; + // states based on new hit + var receivingContext = null; + var mutation = null; + var mutatedRelevantEvents = null; + var isInvalid = false; + var interaction = { + affectedEvents: relevantEvents, + mutatedEvents: createEmptyEventStore(), + isEvent: true, + }; + if (hit) { + receivingContext = hit.context; + var receivingOptions = receivingContext.options; + if (initialContext === receivingContext || + (receivingOptions.editable && receivingOptions.droppable)) { + mutation = computeEventMutation(initialHit, hit, receivingContext.getCurrentData().pluginHooks.eventDragMutationMassagers); + if (mutation) { + mutatedRelevantEvents = applyMutationToEventStore(relevantEvents, receivingContext.getCurrentData().eventUiBases, mutation, receivingContext); + interaction.mutatedEvents = mutatedRelevantEvents; + if (!isInteractionValid(interaction, hit.dateProfile, receivingContext)) { + isInvalid = true; + mutation = null; + mutatedRelevantEvents = null; + interaction.mutatedEvents = createEmptyEventStore(); + } + } + } + else { + receivingContext = null; + } + } + _this.displayDrag(receivingContext, interaction); + if (!isInvalid) { + enableCursor(); + } + else { + disableCursor(); + } + if (!isFinal) { + if (initialContext === receivingContext && // TODO: write test for this + isHitsEqual(initialHit, hit)) { + mutation = null; + } + _this.dragging.setMirrorNeedsRevert(!mutation); + // render the mirror if no already-rendered mirror + // TODO: wish we could somehow wait for dispatch to guarantee render + _this.dragging.setMirrorIsVisible(!hit || !document.querySelector('.fc-event-mirror')); + // assign states based on new hit + _this.receivingContext = receivingContext; + _this.validMutation = mutation; + _this.mutatedRelevantEvents = mutatedRelevantEvents; + } + }; + _this.handlePointerUp = function () { + if (!_this.isDragging) { + _this.cleanup(); // because handleDragEnd won't fire + } + }; + _this.handleDragEnd = function (ev) { + if (_this.isDragging) { + var initialContext_1 = _this.component.context; + var initialView = initialContext_1.viewApi; + var _a = _this, receivingContext_1 = _a.receivingContext, validMutation = _a.validMutation; + var eventDef = _this.eventRange.def; + var eventInstance = _this.eventRange.instance; + var eventApi = new EventApi(initialContext_1, eventDef, eventInstance); + var relevantEvents_1 = _this.relevantEvents; + var mutatedRelevantEvents_1 = _this.mutatedRelevantEvents; + var finalHit = _this.hitDragging.finalHit; + _this.clearDrag(); // must happen after revert animation + initialContext_1.emitter.trigger('eventDragStop', { + el: _this.subjectEl, + event: eventApi, + jsEvent: ev.origEvent, + view: initialView, + }); + if (validMutation) { + // dropped within same calendar + if (receivingContext_1 === initialContext_1) { + var updatedEventApi = new EventApi(initialContext_1, mutatedRelevantEvents_1.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents_1.instances[eventInstance.instanceId] : null); + initialContext_1.dispatch({ + type: 'MERGE_EVENTS', + eventStore: mutatedRelevantEvents_1, + }); + var eventChangeArg = { + oldEvent: eventApi, + event: updatedEventApi, + relatedEvents: buildEventApis(mutatedRelevantEvents_1, initialContext_1, eventInstance), + revert: function () { + initialContext_1.dispatch({ + type: 'MERGE_EVENTS', + eventStore: relevantEvents_1, // the pre-change data + }); + }, + }; + var transformed = {}; + for (var _i = 0, _b = initialContext_1.getCurrentData().pluginHooks.eventDropTransformers; _i < _b.length; _i++) { + var transformer = _b[_i]; + __assign(transformed, transformer(validMutation, initialContext_1)); + } + initialContext_1.emitter.trigger('eventDrop', __assign(__assign(__assign({}, eventChangeArg), transformed), { el: ev.subjectEl, delta: validMutation.datesDelta, jsEvent: ev.origEvent, view: initialView })); + initialContext_1.emitter.trigger('eventChange', eventChangeArg); + // dropped in different calendar + } + else if (receivingContext_1) { + var eventRemoveArg = { + event: eventApi, + relatedEvents: buildEventApis(relevantEvents_1, initialContext_1, eventInstance), + revert: function () { + initialContext_1.dispatch({ + type: 'MERGE_EVENTS', + eventStore: relevantEvents_1, + }); + }, + }; + initialContext_1.emitter.trigger('eventLeave', __assign(__assign({}, eventRemoveArg), { draggedEl: ev.subjectEl, view: initialView })); + initialContext_1.dispatch({ + type: 'REMOVE_EVENTS', + eventStore: relevantEvents_1, + }); + initialContext_1.emitter.trigger('eventRemove', eventRemoveArg); + var addedEventDef = mutatedRelevantEvents_1.defs[eventDef.defId]; + var addedEventInstance = mutatedRelevantEvents_1.instances[eventInstance.instanceId]; + var addedEventApi = new EventApi(receivingContext_1, addedEventDef, addedEventInstance); + receivingContext_1.dispatch({ + type: 'MERGE_EVENTS', + eventStore: mutatedRelevantEvents_1, + }); + var eventAddArg = { + event: addedEventApi, + relatedEvents: buildEventApis(mutatedRelevantEvents_1, receivingContext_1, addedEventInstance), + revert: function () { + receivingContext_1.dispatch({ + type: 'REMOVE_EVENTS', + eventStore: mutatedRelevantEvents_1, + }); + }, + }; + receivingContext_1.emitter.trigger('eventAdd', eventAddArg); + if (ev.isTouch) { + receivingContext_1.dispatch({ + type: 'SELECT_EVENT', + eventInstanceId: eventInstance.instanceId, + }); + } + receivingContext_1.emitter.trigger('drop', __assign(__assign({}, buildDatePointApiWithContext(finalHit.dateSpan, receivingContext_1)), { draggedEl: ev.subjectEl, jsEvent: ev.origEvent, view: finalHit.context.viewApi })); + receivingContext_1.emitter.trigger('eventReceive', __assign(__assign({}, eventAddArg), { draggedEl: ev.subjectEl, view: finalHit.context.viewApi })); + } + } + else { + initialContext_1.emitter.trigger('_noEventDrop'); + } + } + _this.cleanup(); + }; + var component = _this.component; + var options = component.context.options; + var dragging = _this.dragging = new FeaturefulElementDragging(settings.el); + dragging.pointer.selector = EventDragging.SELECTOR; + dragging.touchScrollAllowed = false; + dragging.autoScroller.isEnabled = options.dragScroll; + var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, interactionSettingsStore); + hitDragging.useSubjectCenter = settings.useEventCenter; + hitDragging.emitter.on('pointerdown', _this.handlePointerDown); + hitDragging.emitter.on('dragstart', _this.handleDragStart); + hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); + hitDragging.emitter.on('pointerup', _this.handlePointerUp); + hitDragging.emitter.on('dragend', _this.handleDragEnd); + return _this; + } + EventDragging.prototype.destroy = function () { + this.dragging.destroy(); + }; + // render a drag state on the next receivingCalendar + EventDragging.prototype.displayDrag = function (nextContext, state) { + var initialContext = this.component.context; + var prevContext = this.receivingContext; + // does the previous calendar need to be cleared? + if (prevContext && prevContext !== nextContext) { + // does the initial calendar need to be cleared? + // if so, don't clear all the way. we still need to to hide the affectedEvents + if (prevContext === initialContext) { + prevContext.dispatch({ + type: 'SET_EVENT_DRAG', + state: { + affectedEvents: state.affectedEvents, + mutatedEvents: createEmptyEventStore(), + isEvent: true, + }, + }); + // completely clear the old calendar if it wasn't the initial + } + else { + prevContext.dispatch({ type: 'UNSET_EVENT_DRAG' }); + } + } + if (nextContext) { + nextContext.dispatch({ type: 'SET_EVENT_DRAG', state: state }); + } + }; + EventDragging.prototype.clearDrag = function () { + var initialCalendar = this.component.context; + var receivingContext = this.receivingContext; + if (receivingContext) { + receivingContext.dispatch({ type: 'UNSET_EVENT_DRAG' }); + } + // the initial calendar might have an dummy drag state from displayDrag + if (initialCalendar !== receivingContext) { + initialCalendar.dispatch({ type: 'UNSET_EVENT_DRAG' }); + } + }; + EventDragging.prototype.cleanup = function () { + this.subjectSeg = null; + this.isDragging = false; + this.eventRange = null; + this.relevantEvents = null; + this.receivingContext = null; + this.validMutation = null; + this.mutatedRelevantEvents = null; + }; + // TODO: test this in IE11 + // QUESTION: why do we need it on the resizable??? + EventDragging.SELECTOR = '.fc-event-draggable, .fc-event-resizable'; + return EventDragging; + }(Interaction)); + function computeEventMutation(hit0, hit1, massagers) { + var dateSpan0 = hit0.dateSpan; + var dateSpan1 = hit1.dateSpan; + var date0 = dateSpan0.range.start; + var date1 = dateSpan1.range.start; + var standardProps = {}; + if (dateSpan0.allDay !== dateSpan1.allDay) { + standardProps.allDay = dateSpan1.allDay; + standardProps.hasEnd = hit1.context.options.allDayMaintainDuration; + if (dateSpan1.allDay) { + // means date1 is already start-of-day, + // but date0 needs to be converted + date0 = startOfDay(date0); + } + } + var delta = diffDates(date0, date1, hit0.context.dateEnv, hit0.componentId === hit1.componentId ? + hit0.largeUnit : + null); + if (delta.milliseconds) { // has hours/minutes/seconds + standardProps.allDay = false; + } + var mutation = { + datesDelta: delta, + standardProps: standardProps, + }; + for (var _i = 0, massagers_1 = massagers; _i < massagers_1.length; _i++) { + var massager = massagers_1[_i]; + massager(mutation, hit0, hit1); + } + return mutation; + } + function getComponentTouchDelay(component) { + var options = component.context.options; + var delay = options.eventLongPressDelay; + if (delay == null) { + delay = options.longPressDelay; + } + return delay; + } + + var EventResizing = /** @class */ (function (_super) { + __extends(EventResizing, _super); + function EventResizing(settings) { + var _this = _super.call(this, settings) || this; + // internal state + _this.draggingSegEl = null; + _this.draggingSeg = null; // TODO: rename to resizingSeg? subjectSeg? + _this.eventRange = null; + _this.relevantEvents = null; + _this.validMutation = null; + _this.mutatedRelevantEvents = null; + _this.handlePointerDown = function (ev) { + var component = _this.component; + var segEl = _this.querySegEl(ev); + var seg = getElSeg(segEl); + var eventRange = _this.eventRange = seg.eventRange; + _this.dragging.minDistance = component.context.options.eventDragMinDistance; + // if touch, need to be working with a selected event + _this.dragging.setIgnoreMove(!_this.component.isValidSegDownEl(ev.origEvent.target) || + (ev.isTouch && _this.component.props.eventSelection !== eventRange.instance.instanceId)); + }; + _this.handleDragStart = function (ev) { + var context = _this.component.context; + var eventRange = _this.eventRange; + _this.relevantEvents = getRelevantEvents(context.getCurrentData().eventStore, _this.eventRange.instance.instanceId); + var segEl = _this.querySegEl(ev); + _this.draggingSegEl = segEl; + _this.draggingSeg = getElSeg(segEl); + context.calendarApi.unselect(); + context.emitter.trigger('eventResizeStart', { + el: segEl, + event: new EventApi(context, eventRange.def, eventRange.instance), + jsEvent: ev.origEvent, + view: context.viewApi, + }); + }; + _this.handleHitUpdate = function (hit, isFinal, ev) { + var context = _this.component.context; + var relevantEvents = _this.relevantEvents; + var initialHit = _this.hitDragging.initialHit; + var eventInstance = _this.eventRange.instance; + var mutation = null; + var mutatedRelevantEvents = null; + var isInvalid = false; + var interaction = { + affectedEvents: relevantEvents, + mutatedEvents: createEmptyEventStore(), + isEvent: true, + }; + if (hit) { + var disallowed = hit.componentId === initialHit.componentId + && _this.isHitComboAllowed + && !_this.isHitComboAllowed(initialHit, hit); + if (!disallowed) { + mutation = computeMutation(initialHit, hit, ev.subjectEl.classList.contains('fc-event-resizer-start'), eventInstance.range); + } + } + if (mutation) { + mutatedRelevantEvents = applyMutationToEventStore(relevantEvents, context.getCurrentData().eventUiBases, mutation, context); + interaction.mutatedEvents = mutatedRelevantEvents; + if (!isInteractionValid(interaction, hit.dateProfile, context)) { + isInvalid = true; + mutation = null; + mutatedRelevantEvents = null; + interaction.mutatedEvents = null; + } + } + if (mutatedRelevantEvents) { + context.dispatch({ + type: 'SET_EVENT_RESIZE', + state: interaction, + }); + } + else { + context.dispatch({ type: 'UNSET_EVENT_RESIZE' }); + } + if (!isInvalid) { + enableCursor(); + } + else { + disableCursor(); + } + if (!isFinal) { + if (mutation && isHitsEqual(initialHit, hit)) { + mutation = null; + } + _this.validMutation = mutation; + _this.mutatedRelevantEvents = mutatedRelevantEvents; + } + }; + _this.handleDragEnd = function (ev) { + var context = _this.component.context; + var eventDef = _this.eventRange.def; + var eventInstance = _this.eventRange.instance; + var eventApi = new EventApi(context, eventDef, eventInstance); + var relevantEvents = _this.relevantEvents; + var mutatedRelevantEvents = _this.mutatedRelevantEvents; + context.emitter.trigger('eventResizeStop', { + el: _this.draggingSegEl, + event: eventApi, + jsEvent: ev.origEvent, + view: context.viewApi, + }); + if (_this.validMutation) { + var updatedEventApi = new EventApi(context, mutatedRelevantEvents.defs[eventDef.defId], eventInstance ? mutatedRelevantEvents.instances[eventInstance.instanceId] : null); + context.dispatch({ + type: 'MERGE_EVENTS', + eventStore: mutatedRelevantEvents, + }); + var eventChangeArg = { + oldEvent: eventApi, + event: updatedEventApi, + relatedEvents: buildEventApis(mutatedRelevantEvents, context, eventInstance), + revert: function () { + context.dispatch({ + type: 'MERGE_EVENTS', + eventStore: relevantEvents, // the pre-change events + }); + }, + }; + context.emitter.trigger('eventResize', __assign(__assign({}, eventChangeArg), { el: _this.draggingSegEl, startDelta: _this.validMutation.startDelta || createDuration(0), endDelta: _this.validMutation.endDelta || createDuration(0), jsEvent: ev.origEvent, view: context.viewApi })); + context.emitter.trigger('eventChange', eventChangeArg); + } + else { + context.emitter.trigger('_noEventResize'); + } + // reset all internal state + _this.draggingSeg = null; + _this.relevantEvents = null; + _this.validMutation = null; + // okay to keep eventInstance around. useful to set it in handlePointerDown + }; + var component = settings.component; + var dragging = _this.dragging = new FeaturefulElementDragging(settings.el); + dragging.pointer.selector = '.fc-event-resizer'; + dragging.touchScrollAllowed = false; + dragging.autoScroller.isEnabled = component.context.options.dragScroll; + var hitDragging = _this.hitDragging = new HitDragging(_this.dragging, interactionSettingsToStore(settings)); + hitDragging.emitter.on('pointerdown', _this.handlePointerDown); + hitDragging.emitter.on('dragstart', _this.handleDragStart); + hitDragging.emitter.on('hitupdate', _this.handleHitUpdate); + hitDragging.emitter.on('dragend', _this.handleDragEnd); + return _this; + } + EventResizing.prototype.destroy = function () { + this.dragging.destroy(); + }; + EventResizing.prototype.querySegEl = function (ev) { + return elementClosest(ev.subjectEl, '.fc-event'); + }; + return EventResizing; + }(Interaction)); + function computeMutation(hit0, hit1, isFromStart, instanceRange) { + var dateEnv = hit0.context.dateEnv; + var date0 = hit0.dateSpan.range.start; + var date1 = hit1.dateSpan.range.start; + var delta = diffDates(date0, date1, dateEnv, hit0.largeUnit); + if (isFromStart) { + if (dateEnv.add(instanceRange.start, delta) < instanceRange.end) { + return { startDelta: delta }; + } + } + else if (dateEnv.add(instanceRange.end, delta) > instanceRange.start) { + return { endDelta: delta }; + } + return null; + } + + var UnselectAuto = /** @class */ (function () { + function UnselectAuto(context) { + var _this = this; + this.context = context; + this.isRecentPointerDateSelect = false; // wish we could use a selector to detect date selection, but uses hit system + this.matchesCancel = false; + this.matchesEvent = false; + this.onSelect = function (selectInfo) { + if (selectInfo.jsEvent) { + _this.isRecentPointerDateSelect = true; + } + }; + this.onDocumentPointerDown = function (pev) { + var unselectCancel = _this.context.options.unselectCancel; + var downEl = pev.origEvent.target; + _this.matchesCancel = !!elementClosest(downEl, unselectCancel); + _this.matchesEvent = !!elementClosest(downEl, EventDragging.SELECTOR); // interaction started on an event? + }; + this.onDocumentPointerUp = function (pev) { + var context = _this.context; + var documentPointer = _this.documentPointer; + var calendarState = context.getCurrentData(); + // touch-scrolling should never unfocus any type of selection + if (!documentPointer.wasTouchScroll) { + if (calendarState.dateSelection && // an existing date selection? + !_this.isRecentPointerDateSelect // a new pointer-initiated date selection since last onDocumentPointerUp? + ) { + var unselectAuto = context.options.unselectAuto; + if (unselectAuto && (!unselectAuto || !_this.matchesCancel)) { + context.calendarApi.unselect(pev); + } + } + if (calendarState.eventSelection && // an existing event selected? + !_this.matchesEvent // interaction DIDN'T start on an event + ) { + context.dispatch({ type: 'UNSELECT_EVENT' }); + } + } + _this.isRecentPointerDateSelect = false; + }; + var documentPointer = this.documentPointer = new PointerDragging(document); + documentPointer.shouldIgnoreMove = true; + documentPointer.shouldWatchScroll = false; + documentPointer.emitter.on('pointerdown', this.onDocumentPointerDown); + documentPointer.emitter.on('pointerup', this.onDocumentPointerUp); + /* + TODO: better way to know about whether there was a selection with the pointer + */ + context.emitter.on('select', this.onSelect); + } + UnselectAuto.prototype.destroy = function () { + this.context.emitter.off('select', this.onSelect); + this.documentPointer.destroy(); + }; + return UnselectAuto; + }()); + + var OPTION_REFINERS$5 = { + fixedMirrorParent: identity, + }; + var LISTENER_REFINERS$1 = { + dateClick: identity, + eventDragStart: identity, + eventDragStop: identity, + eventDrop: identity, + eventResizeStart: identity, + eventResizeStop: identity, + eventResize: identity, + drop: identity, + eventReceive: identity, + eventLeave: identity, + }; + + /* + Given an already instantiated draggable object for one-or-more elements, + Interprets any dragging as an attempt to drag an events that lives outside + of a calendar onto a calendar. + */ + var ExternalElementDragging = /** @class */ (function () { + function ExternalElementDragging(dragging, suppliedDragMeta) { + var _this = this; + this.receivingContext = null; + this.droppableEvent = null; // will exist for all drags, even if create:false + this.suppliedDragMeta = null; + this.dragMeta = null; + this.handleDragStart = function (ev) { + _this.dragMeta = _this.buildDragMeta(ev.subjectEl); + }; + this.handleHitUpdate = function (hit, isFinal, ev) { + var dragging = _this.hitDragging.dragging; + var receivingContext = null; + var droppableEvent = null; + var isInvalid = false; + var interaction = { + affectedEvents: createEmptyEventStore(), + mutatedEvents: createEmptyEventStore(), + isEvent: _this.dragMeta.create, + }; + if (hit) { + receivingContext = hit.context; + if (_this.canDropElOnCalendar(ev.subjectEl, receivingContext)) { + droppableEvent = computeEventForDateSpan(hit.dateSpan, _this.dragMeta, receivingContext); + interaction.mutatedEvents = eventTupleToStore(droppableEvent); + isInvalid = !isInteractionValid(interaction, hit.dateProfile, receivingContext); + if (isInvalid) { + interaction.mutatedEvents = createEmptyEventStore(); + droppableEvent = null; + } + } + } + _this.displayDrag(receivingContext, interaction); + // show mirror if no already-rendered mirror element OR if we are shutting down the mirror (?) + // TODO: wish we could somehow wait for dispatch to guarantee render + dragging.setMirrorIsVisible(isFinal || !droppableEvent || !document.querySelector('.fc-event-mirror')); + if (!isInvalid) { + enableCursor(); + } + else { + disableCursor(); + } + if (!isFinal) { + dragging.setMirrorNeedsRevert(!droppableEvent); + _this.receivingContext = receivingContext; + _this.droppableEvent = droppableEvent; + } + }; + this.handleDragEnd = function (pev) { + var _a = _this, receivingContext = _a.receivingContext, droppableEvent = _a.droppableEvent; + _this.clearDrag(); + if (receivingContext && droppableEvent) { + var finalHit = _this.hitDragging.finalHit; + var finalView = finalHit.context.viewApi; + var dragMeta = _this.dragMeta; + receivingContext.emitter.trigger('drop', __assign(__assign({}, buildDatePointApiWithContext(finalHit.dateSpan, receivingContext)), { draggedEl: pev.subjectEl, jsEvent: pev.origEvent, view: finalView })); + if (dragMeta.create) { + var addingEvents_1 = eventTupleToStore(droppableEvent); + receivingContext.dispatch({ + type: 'MERGE_EVENTS', + eventStore: addingEvents_1, + }); + if (pev.isTouch) { + receivingContext.dispatch({ + type: 'SELECT_EVENT', + eventInstanceId: droppableEvent.instance.instanceId, + }); + } + // signal that an external event landed + receivingContext.emitter.trigger('eventReceive', { + event: new EventApi(receivingContext, droppableEvent.def, droppableEvent.instance), + relatedEvents: [], + revert: function () { + receivingContext.dispatch({ + type: 'REMOVE_EVENTS', + eventStore: addingEvents_1, + }); + }, + draggedEl: pev.subjectEl, + view: finalView, + }); + } + } + _this.receivingContext = null; + _this.droppableEvent = null; + }; + var hitDragging = this.hitDragging = new HitDragging(dragging, interactionSettingsStore); + hitDragging.requireInitial = false; // will start outside of a component + hitDragging.emitter.on('dragstart', this.handleDragStart); + hitDragging.emitter.on('hitupdate', this.handleHitUpdate); + hitDragging.emitter.on('dragend', this.handleDragEnd); + this.suppliedDragMeta = suppliedDragMeta; + } + ExternalElementDragging.prototype.buildDragMeta = function (subjectEl) { + if (typeof this.suppliedDragMeta === 'object') { + return parseDragMeta(this.suppliedDragMeta); + } + if (typeof this.suppliedDragMeta === 'function') { + return parseDragMeta(this.suppliedDragMeta(subjectEl)); + } + return getDragMetaFromEl(subjectEl); + }; + ExternalElementDragging.prototype.displayDrag = function (nextContext, state) { + var prevContext = this.receivingContext; + if (prevContext && prevContext !== nextContext) { + prevContext.dispatch({ type: 'UNSET_EVENT_DRAG' }); + } + if (nextContext) { + nextContext.dispatch({ type: 'SET_EVENT_DRAG', state: state }); + } + }; + ExternalElementDragging.prototype.clearDrag = function () { + if (this.receivingContext) { + this.receivingContext.dispatch({ type: 'UNSET_EVENT_DRAG' }); + } + }; + ExternalElementDragging.prototype.canDropElOnCalendar = function (el, receivingContext) { + var dropAccept = receivingContext.options.dropAccept; + if (typeof dropAccept === 'function') { + return dropAccept.call(receivingContext.calendarApi, el); + } + if (typeof dropAccept === 'string' && dropAccept) { + return Boolean(elementMatches(el, dropAccept)); + } + return true; + }; + return ExternalElementDragging; + }()); + // Utils for computing event store from the DragMeta + // ---------------------------------------------------------------------------------------------------- + function computeEventForDateSpan(dateSpan, dragMeta, context) { + var defProps = __assign({}, dragMeta.leftoverProps); + for (var _i = 0, _a = context.pluginHooks.externalDefTransforms; _i < _a.length; _i++) { + var transform = _a[_i]; + __assign(defProps, transform(dateSpan, dragMeta)); + } + var _b = refineEventDef(defProps, context), refined = _b.refined, extra = _b.extra; + var def = parseEventDef(refined, extra, dragMeta.sourceId, dateSpan.allDay, context.options.forceEventDuration || Boolean(dragMeta.duration), // hasEnd + context); + var start = dateSpan.range.start; + // only rely on time info if drop zone is all-day, + // otherwise, we already know the time + if (dateSpan.allDay && dragMeta.startTime) { + start = context.dateEnv.add(start, dragMeta.startTime); + } + var end = dragMeta.duration ? + context.dateEnv.add(start, dragMeta.duration) : + getDefaultEventEnd(dateSpan.allDay, start, context); + var instance = createEventInstance(def.defId, { start: start, end: end }); + return { def: def, instance: instance }; + } + // Utils for extracting data from element + // ---------------------------------------------------------------------------------------------------- + function getDragMetaFromEl(el) { + var str = getEmbeddedElData(el, 'event'); + var obj = str ? + JSON.parse(str) : + { create: false }; // if no embedded data, assume no event creation + return parseDragMeta(obj); + } + config.dataAttrPrefix = ''; + function getEmbeddedElData(el, name) { + var prefix = config.dataAttrPrefix; + var prefixedName = (prefix ? prefix + '-' : '') + name; + return el.getAttribute('data-' + prefixedName) || ''; + } + + /* + Makes an element (that is *external* to any calendar) draggable. + Can pass in data that determines how an event will be created when dropped onto a calendar. + Leverages FullCalendar's internal drag-n-drop functionality WITHOUT a third-party drag system. + */ + var ExternalDraggable = /** @class */ (function () { + function ExternalDraggable(el, settings) { + var _this = this; + if (settings === void 0) { settings = {}; } + this.handlePointerDown = function (ev) { + var dragging = _this.dragging; + var _a = _this.settings, minDistance = _a.minDistance, longPressDelay = _a.longPressDelay; + dragging.minDistance = + minDistance != null ? + minDistance : + (ev.isTouch ? 0 : BASE_OPTION_DEFAULTS.eventDragMinDistance); + dragging.delay = + ev.isTouch ? // TODO: eventually read eventLongPressDelay instead vvv + (longPressDelay != null ? longPressDelay : BASE_OPTION_DEFAULTS.longPressDelay) : + 0; + }; + this.handleDragStart = function (ev) { + if (ev.isTouch && + _this.dragging.delay && + ev.subjectEl.classList.contains('fc-event')) { + _this.dragging.mirror.getMirrorEl().classList.add('fc-event-selected'); + } + }; + this.settings = settings; + var dragging = this.dragging = new FeaturefulElementDragging(el); + dragging.touchScrollAllowed = false; + if (settings.itemSelector != null) { + dragging.pointer.selector = settings.itemSelector; + } + if (settings.appendTo != null) { + dragging.mirror.parentNode = settings.appendTo; // TODO: write tests + } + dragging.emitter.on('pointerdown', this.handlePointerDown); + dragging.emitter.on('dragstart', this.handleDragStart); + new ExternalElementDragging(dragging, settings.eventData); // eslint-disable-line no-new + } + ExternalDraggable.prototype.destroy = function () { + this.dragging.destroy(); + }; + return ExternalDraggable; + }()); + + /* + Detects when a *THIRD-PARTY* drag-n-drop system interacts with elements. + The third-party system is responsible for drawing the visuals effects of the drag. + This class simply monitors for pointer movements and fires events. + It also has the ability to hide the moving element (the "mirror") during the drag. + */ + var InferredElementDragging = /** @class */ (function (_super) { + __extends(InferredElementDragging, _super); + function InferredElementDragging(containerEl) { + var _this = _super.call(this, containerEl) || this; + _this.shouldIgnoreMove = false; + _this.mirrorSelector = ''; + _this.currentMirrorEl = null; + _this.handlePointerDown = function (ev) { + _this.emitter.trigger('pointerdown', ev); + if (!_this.shouldIgnoreMove) { + // fire dragstart right away. does not support delay or min-distance + _this.emitter.trigger('dragstart', ev); + } + }; + _this.handlePointerMove = function (ev) { + if (!_this.shouldIgnoreMove) { + _this.emitter.trigger('dragmove', ev); + } + }; + _this.handlePointerUp = function (ev) { + _this.emitter.trigger('pointerup', ev); + if (!_this.shouldIgnoreMove) { + // fire dragend right away. does not support a revert animation + _this.emitter.trigger('dragend', ev); + } + }; + var pointer = _this.pointer = new PointerDragging(containerEl); + pointer.emitter.on('pointerdown', _this.handlePointerDown); + pointer.emitter.on('pointermove', _this.handlePointerMove); + pointer.emitter.on('pointerup', _this.handlePointerUp); + return _this; + } + InferredElementDragging.prototype.destroy = function () { + this.pointer.destroy(); + }; + InferredElementDragging.prototype.setIgnoreMove = function (bool) { + this.shouldIgnoreMove = bool; + }; + InferredElementDragging.prototype.setMirrorIsVisible = function (bool) { + if (bool) { + // restore a previously hidden element. + // use the reference in case the selector class has already been removed. + if (this.currentMirrorEl) { + this.currentMirrorEl.style.visibility = ''; + this.currentMirrorEl = null; + } + } + else { + var mirrorEl = this.mirrorSelector ? + document.querySelector(this.mirrorSelector) : + null; + if (mirrorEl) { + this.currentMirrorEl = mirrorEl; + mirrorEl.style.visibility = 'hidden'; + } + } + }; + return InferredElementDragging; + }(ElementDragging)); + + /* + Bridges third-party drag-n-drop systems with FullCalendar. + Must be instantiated and destroyed by caller. + */ + var ThirdPartyDraggable = /** @class */ (function () { + function ThirdPartyDraggable(containerOrSettings, settings) { + var containerEl = document; + if ( + // wish we could just test instanceof EventTarget, but doesn't work in IE11 + containerOrSettings === document || + containerOrSettings instanceof Element) { + containerEl = containerOrSettings; + settings = settings || {}; + } + else { + settings = (containerOrSettings || {}); + } + var dragging = this.dragging = new InferredElementDragging(containerEl); + if (typeof settings.itemSelector === 'string') { + dragging.pointer.selector = settings.itemSelector; + } + else if (containerEl === document) { + dragging.pointer.selector = '[data-event]'; + } + if (typeof settings.mirrorSelector === 'string') { + dragging.mirrorSelector = settings.mirrorSelector; + } + new ExternalElementDragging(dragging, settings.eventData); // eslint-disable-line no-new + } + ThirdPartyDraggable.prototype.destroy = function () { + this.dragging.destroy(); + }; + return ThirdPartyDraggable; + }()); + + var interactionPlugin = createPlugin({ + componentInteractions: [DateClicking, DateSelecting, EventDragging, EventResizing], + calendarInteractions: [UnselectAuto], + elementDraggingImpl: FeaturefulElementDragging, + optionRefiners: OPTION_REFINERS$5, + listenerRefiners: LISTENER_REFINERS$1, + }); + + /* An abstract class for the daygrid views, as well as month view. Renders one or more rows of day cells. + ----------------------------------------------------------------------------------------------------------------------*/ + // It is a manager for a Table subcomponent, which does most of the heavy lifting. + // It is responsible for managing width/height. + var TableView = /** @class */ (function (_super) { + __extends(TableView, _super); + function TableView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.headerElRef = createRef(); + return _this; + } + TableView.prototype.renderSimpleLayout = function (headerRowContent, bodyContent) { + var _a = this, props = _a.props, context = _a.context; + var sections = []; + var stickyHeaderDates = getStickyHeaderDates(context.options); + if (headerRowContent) { + sections.push({ + type: 'header', + key: 'header', + isSticky: stickyHeaderDates, + chunk: { + elRef: this.headerElRef, + tableClassName: 'fc-col-header', + rowContent: headerRowContent, + }, + }); + } + sections.push({ + type: 'body', + key: 'body', + liquid: true, + chunk: { content: bodyContent }, + }); + return (createElement(ViewRoot, { viewSpec: context.viewSpec }, function (rootElRef, classNames) { return (createElement("div", { ref: rootElRef, className: ['fc-daygrid'].concat(classNames).join(' ') }, + createElement(SimpleScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [] /* TODO: make optional? */, sections: sections }))); })); + }; + TableView.prototype.renderHScrollLayout = function (headerRowContent, bodyContent, colCnt, dayMinWidth) { + var ScrollGrid = this.context.pluginHooks.scrollGridImpl; + if (!ScrollGrid) { + throw new Error('No ScrollGrid implementation'); + } + var _a = this, props = _a.props, context = _a.context; + var stickyHeaderDates = !props.forPrint && getStickyHeaderDates(context.options); + var stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(context.options); + var sections = []; + if (headerRowContent) { + sections.push({ + type: 'header', + key: 'header', + isSticky: stickyHeaderDates, + chunks: [{ + key: 'main', + elRef: this.headerElRef, + tableClassName: 'fc-col-header', + rowContent: headerRowContent, + }], + }); + } + sections.push({ + type: 'body', + key: 'body', + liquid: true, + chunks: [{ + key: 'main', + content: bodyContent, + }], + }); + if (stickyFooterScrollbar) { + sections.push({ + type: 'footer', + key: 'footer', + isSticky: true, + chunks: [{ + key: 'main', + content: renderScrollShim, + }], + }); + } + return (createElement(ViewRoot, { viewSpec: context.viewSpec }, function (rootElRef, classNames) { return (createElement("div", { ref: rootElRef, className: ['fc-daygrid'].concat(classNames).join(' ') }, + createElement(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, colGroups: [{ cols: [{ span: colCnt, minWidth: dayMinWidth }] }], sections: sections }))); })); + }; + return TableView; + }(DateComponent)); + + function splitSegsByRow(segs, rowCnt) { + var byRow = []; + for (var i = 0; i < rowCnt; i += 1) { + byRow[i] = []; + } + for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { + var seg = segs_1[_i]; + byRow[seg.row].push(seg); + } + return byRow; + } + function splitSegsByFirstCol(segs, colCnt) { + var byCol = []; + for (var i = 0; i < colCnt; i += 1) { + byCol[i] = []; + } + for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) { + var seg = segs_2[_i]; + byCol[seg.firstCol].push(seg); + } + return byCol; + } + function splitInteractionByRow(ui, rowCnt) { + var byRow = []; + if (!ui) { + for (var i = 0; i < rowCnt; i += 1) { + byRow[i] = null; + } + } + else { + for (var i = 0; i < rowCnt; i += 1) { + byRow[i] = { + affectedInstances: ui.affectedInstances, + isEvent: ui.isEvent, + segs: [], + }; + } + for (var _i = 0, _a = ui.segs; _i < _a.length; _i++) { + var seg = _a[_i]; + byRow[seg.row].segs.push(seg); + } + } + return byRow; + } + + var TableCellTop = /** @class */ (function (_super) { + __extends(TableCellTop, _super); + function TableCellTop() { + return _super !== null && _super.apply(this, arguments) || this; + } + TableCellTop.prototype.render = function () { + var props = this.props; + var navLinkAttrs = this.context.options.navLinks + ? { 'data-navlink': buildNavLinkData(props.date), tabIndex: 0 } + : {}; + return (createElement(DayCellContent, { date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, showDayNumber: props.showDayNumber, extraHookProps: props.extraHookProps, defaultContent: renderTopInner }, function (innerElRef, innerContent) { return ((innerContent || props.forceDayTop) && (createElement("div", { className: "fc-daygrid-day-top", ref: innerElRef }, + createElement("a", __assign({ className: "fc-daygrid-day-number" }, navLinkAttrs), innerContent || createElement(Fragment, null, "\u00A0"))))); })); + }; + return TableCellTop; + }(BaseComponent)); + function renderTopInner(props) { + return props.dayNumberText; + } + + var DEFAULT_TABLE_EVENT_TIME_FORMAT = createFormatter({ + hour: 'numeric', + minute: '2-digit', + omitZeroMinute: true, + meridiem: 'narrow', + }); + function hasListItemDisplay(seg) { + var display = seg.eventRange.ui.display; + return display === 'list-item' || (display === 'auto' && + !seg.eventRange.def.allDay && + seg.firstCol === seg.lastCol && // can't be multi-day + seg.isStart && // " + seg.isEnd // " + ); + } + + var TableBlockEvent = /** @class */ (function (_super) { + __extends(TableBlockEvent, _super); + function TableBlockEvent() { + return _super !== null && _super.apply(this, arguments) || this; + } + TableBlockEvent.prototype.render = function () { + var props = this.props; + return (createElement(StandardEvent, __assign({}, props, { extraClassNames: ['fc-daygrid-event', 'fc-daygrid-block-event', 'fc-h-event'], defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: props.defaultDisplayEventEnd, disableResizing: !props.seg.eventRange.def.allDay }))); + }; + return TableBlockEvent; + }(BaseComponent)); + + var TableListItemEvent = /** @class */ (function (_super) { + __extends(TableListItemEvent, _super); + function TableListItemEvent() { + return _super !== null && _super.apply(this, arguments) || this; + } + TableListItemEvent.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var timeFormat = context.options.eventTimeFormat || DEFAULT_TABLE_EVENT_TIME_FORMAT; + var timeText = buildSegTimeText(props.seg, timeFormat, context, true, props.defaultDisplayEventEnd); + return (createElement(EventRoot, { seg: props.seg, timeText: timeText, defaultContent: renderInnerContent$4, isDragging: props.isDragging, isResizing: false, isDateSelecting: false, isSelected: props.isSelected, isPast: props.isPast, isFuture: props.isFuture, isToday: props.isToday }, function (rootElRef, classNames, innerElRef, innerContent) { return ( // we don't use styles! + createElement("a", __assign({ className: ['fc-daygrid-event', 'fc-daygrid-dot-event'].concat(classNames).join(' '), ref: rootElRef }, getSegAnchorAttrs(props.seg)), innerContent)); })); + }; + return TableListItemEvent; + }(BaseComponent)); + function renderInnerContent$4(innerProps) { + return (createElement(Fragment, null, + createElement("div", { className: "fc-daygrid-event-dot", style: { borderColor: innerProps.borderColor || innerProps.backgroundColor } }), + innerProps.timeText && (createElement("div", { className: "fc-event-time" }, innerProps.timeText)), + createElement("div", { className: "fc-event-title" }, innerProps.event.title || createElement(Fragment, null, "\u00A0")))); + } + function getSegAnchorAttrs(seg) { + var url = seg.eventRange.def.url; + return url ? { href: url } : {}; + } + + var TableCellMoreLink = /** @class */ (function (_super) { + __extends(TableCellMoreLink, _super); + function TableCellMoreLink() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.compileSegs = memoize(compileSegs); + return _this; + } + TableCellMoreLink.prototype.render = function () { + var props = this.props; + var _a = this.compileSegs(props.singlePlacements), allSegs = _a.allSegs, invisibleSegs = _a.invisibleSegs; + return (createElement(MoreLinkRoot, { dateProfile: props.dateProfile, todayRange: props.todayRange, allDayDate: props.allDayDate, moreCnt: props.moreCnt, allSegs: allSegs, hiddenSegs: invisibleSegs, alignmentElRef: props.alignmentElRef, alignGridTop: props.alignGridTop, extraDateSpan: props.extraDateSpan, popoverContent: function () { + var isForcedInvisible = (props.eventDrag ? props.eventDrag.affectedInstances : null) || + (props.eventResize ? props.eventResize.affectedInstances : null) || + {}; + return (createElement(Fragment, null, allSegs.map(function (seg) { + var instanceId = seg.eventRange.instance.instanceId; + return (createElement("div", { className: "fc-daygrid-event-harness", key: instanceId, style: { + visibility: isForcedInvisible[instanceId] ? 'hidden' : '', + } }, hasListItemDisplay(seg) ? (createElement(TableListItemEvent, __assign({ seg: seg, isDragging: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, getSegMeta(seg, props.todayRange)))) : (createElement(TableBlockEvent, __assign({ seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, getSegMeta(seg, props.todayRange)))))); + }))); + } }, function (rootElRef, classNames, innerElRef, innerContent, handleClick) { return (createElement("a", { ref: rootElRef, className: ['fc-daygrid-more-link'].concat(classNames).join(' '), onClick: handleClick }, innerContent)); })); + }; + return TableCellMoreLink; + }(BaseComponent)); + function compileSegs(singlePlacements) { + var allSegs = []; + var invisibleSegs = []; + for (var _i = 0, singlePlacements_1 = singlePlacements; _i < singlePlacements_1.length; _i++) { + var placement = singlePlacements_1[_i]; + allSegs.push(placement.seg); + if (!placement.isVisible) { + invisibleSegs.push(placement.seg); + } + } + return { allSegs: allSegs, invisibleSegs: invisibleSegs }; + } + + var DEFAULT_WEEK_NUM_FORMAT$1 = createFormatter({ week: 'narrow' }); + var TableCell = /** @class */ (function (_super) { + __extends(TableCell, _super); + function TableCell() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.rootElRef = createRef(); + _this.handleRootEl = function (el) { + setRef(_this.rootElRef, el); + setRef(_this.props.elRef, el); + }; + return _this; + } + TableCell.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context, rootElRef = _a.rootElRef; + var options = context.options; + var date = props.date, dateProfile = props.dateProfile; + var navLinkAttrs = options.navLinks + ? { 'data-navlink': buildNavLinkData(date, 'week'), tabIndex: 0 } + : {}; + return (createElement(DayCellRoot, { date: date, dateProfile: dateProfile, todayRange: props.todayRange, showDayNumber: props.showDayNumber, extraHookProps: props.extraHookProps, elRef: this.handleRootEl }, function (dayElRef, dayClassNames, rootDataAttrs, isDisabled) { return (createElement("td", __assign({ ref: dayElRef, className: ['fc-daygrid-day'].concat(dayClassNames, props.extraClassNames || []).join(' ') }, rootDataAttrs, props.extraDataAttrs), + createElement("div", { className: "fc-daygrid-day-frame fc-scrollgrid-sync-inner", ref: props.innerElRef /* different from hook system! RENAME */ }, + props.showWeekNumber && (createElement(WeekNumberRoot, { date: date, defaultFormat: DEFAULT_WEEK_NUM_FORMAT$1 }, function (weekElRef, weekClassNames, innerElRef, innerContent) { return (createElement("a", __assign({ ref: weekElRef, className: ['fc-daygrid-week-number'].concat(weekClassNames).join(' ') }, navLinkAttrs), innerContent)); })), + !isDisabled && (createElement(TableCellTop, { date: date, dateProfile: dateProfile, showDayNumber: props.showDayNumber, forceDayTop: props.forceDayTop, todayRange: props.todayRange, extraHookProps: props.extraHookProps })), + createElement("div", { className: "fc-daygrid-day-events", ref: props.fgContentElRef }, + props.fgContent, + createElement("div", { className: "fc-daygrid-day-bottom", style: { marginTop: props.moreMarginTop } }, + createElement(TableCellMoreLink, { allDayDate: date, singlePlacements: props.singlePlacements, moreCnt: props.moreCnt, alignmentElRef: rootElRef, alignGridTop: !props.showDayNumber, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange }))), + createElement("div", { className: "fc-daygrid-day-bg" }, props.bgContent)))); })); + }; + return TableCell; + }(DateComponent)); + + function computeFgSegPlacement(segs, // assumed already sorted + dayMaxEvents, dayMaxEventRows, strictOrder, eventInstanceHeights, maxContentHeight, cells) { + var hierarchy = new DayGridSegHierarchy(); + hierarchy.allowReslicing = true; + hierarchy.strictOrder = strictOrder; + if (dayMaxEvents === true || dayMaxEventRows === true) { + hierarchy.maxCoord = maxContentHeight; + hierarchy.hiddenConsumes = true; + } + else if (typeof dayMaxEvents === 'number') { + hierarchy.maxStackCnt = dayMaxEvents; + } + else if (typeof dayMaxEventRows === 'number') { + hierarchy.maxStackCnt = dayMaxEventRows; + hierarchy.hiddenConsumes = true; + } + // create segInputs only for segs with known heights + var segInputs = []; + var unknownHeightSegs = []; + for (var i = 0; i < segs.length; i += 1) { + var seg = segs[i]; + var instanceId = seg.eventRange.instance.instanceId; + var eventHeight = eventInstanceHeights[instanceId]; + if (eventHeight != null) { + segInputs.push({ + index: i, + thickness: eventHeight, + span: { + start: seg.firstCol, + end: seg.lastCol + 1, + }, + }); + } + else { + unknownHeightSegs.push(seg); + } + } + var hiddenEntries = hierarchy.addSegs(segInputs); + var segRects = hierarchy.toRects(); + var _a = placeRects(segRects, segs, cells), singleColPlacements = _a.singleColPlacements, multiColPlacements = _a.multiColPlacements, leftoverMargins = _a.leftoverMargins; + var moreCnts = []; + var moreMarginTops = []; + // add segs with unknown heights + for (var _i = 0, unknownHeightSegs_1 = unknownHeightSegs; _i < unknownHeightSegs_1.length; _i++) { + var seg = unknownHeightSegs_1[_i]; + multiColPlacements[seg.firstCol].push({ + seg: seg, + isVisible: false, + isAbsolute: true, + absoluteTop: 0, + marginTop: 0, + }); + for (var col = seg.firstCol; col <= seg.lastCol; col += 1) { + singleColPlacements[col].push({ + seg: resliceSeg(seg, col, col + 1, cells), + isVisible: false, + isAbsolute: false, + absoluteTop: 0, + marginTop: 0, + }); + } + } + // add the hidden entries + for (var col = 0; col < cells.length; col += 1) { + moreCnts.push(0); + } + for (var _b = 0, hiddenEntries_1 = hiddenEntries; _b < hiddenEntries_1.length; _b++) { + var hiddenEntry = hiddenEntries_1[_b]; + var seg = segs[hiddenEntry.index]; + var hiddenSpan = hiddenEntry.span; + multiColPlacements[hiddenSpan.start].push({ + seg: resliceSeg(seg, hiddenSpan.start, hiddenSpan.end, cells), + isVisible: false, + isAbsolute: true, + absoluteTop: 0, + marginTop: 0, + }); + for (var col = hiddenSpan.start; col < hiddenSpan.end; col += 1) { + moreCnts[col] += 1; + singleColPlacements[col].push({ + seg: resliceSeg(seg, col, col + 1, cells), + isVisible: false, + isAbsolute: false, + absoluteTop: 0, + marginTop: 0, + }); + } + } + // deal with leftover margins + for (var col = 0; col < cells.length; col += 1) { + moreMarginTops.push(leftoverMargins[col]); + } + return { singleColPlacements: singleColPlacements, multiColPlacements: multiColPlacements, moreCnts: moreCnts, moreMarginTops: moreMarginTops }; + } + // rects ordered by top coord, then left + function placeRects(allRects, segs, cells) { + var rectsByEachCol = groupRectsByEachCol(allRects, cells.length); + var singleColPlacements = []; + var multiColPlacements = []; + var leftoverMargins = []; + for (var col = 0; col < cells.length; col += 1) { + var rects = rectsByEachCol[col]; + // compute all static segs in singlePlacements + var singlePlacements = []; + var currentHeight = 0; + var currentMarginTop = 0; + for (var _i = 0, rects_1 = rects; _i < rects_1.length; _i++) { + var rect = rects_1[_i]; + var seg = segs[rect.index]; + singlePlacements.push({ + seg: resliceSeg(seg, col, col + 1, cells), + isVisible: true, + isAbsolute: false, + absoluteTop: 0, + marginTop: rect.levelCoord - currentHeight, + }); + currentHeight = rect.levelCoord + rect.thickness; + } + // compute mixed static/absolute segs in multiPlacements + var multiPlacements = []; + currentHeight = 0; + currentMarginTop = 0; + for (var _a = 0, rects_2 = rects; _a < rects_2.length; _a++) { + var rect = rects_2[_a]; + var seg = segs[rect.index]; + var isAbsolute = rect.span.end - rect.span.start > 1; // multi-column? + var isFirstCol = rect.span.start === col; + currentMarginTop += rect.levelCoord - currentHeight; // amount of space since bottom of previous seg + currentHeight = rect.levelCoord + rect.thickness; // height will now be bottom of current seg + if (isAbsolute) { + currentMarginTop += rect.thickness; + if (isFirstCol) { + multiPlacements.push({ + seg: resliceSeg(seg, rect.span.start, rect.span.end, cells), + isVisible: true, + isAbsolute: true, + absoluteTop: rect.levelCoord, + marginTop: 0, + }); + } + } + else if (isFirstCol) { + multiPlacements.push({ + seg: resliceSeg(seg, rect.span.start, rect.span.end, cells), + isVisible: true, + isAbsolute: false, + absoluteTop: 0, + marginTop: currentMarginTop, // claim the margin + }); + currentMarginTop = 0; + } + } + singleColPlacements.push(singlePlacements); + multiColPlacements.push(multiPlacements); + leftoverMargins.push(currentMarginTop); + } + return { singleColPlacements: singleColPlacements, multiColPlacements: multiColPlacements, leftoverMargins: leftoverMargins }; + } + function groupRectsByEachCol(rects, colCnt) { + var rectsByEachCol = []; + for (var col = 0; col < colCnt; col += 1) { + rectsByEachCol.push([]); + } + for (var _i = 0, rects_3 = rects; _i < rects_3.length; _i++) { + var rect = rects_3[_i]; + for (var col = rect.span.start; col < rect.span.end; col += 1) { + rectsByEachCol[col].push(rect); + } + } + return rectsByEachCol; + } + function resliceSeg(seg, spanStart, spanEnd, cells) { + if (seg.firstCol === spanStart && seg.lastCol === spanEnd - 1) { + return seg; + } + var eventRange = seg.eventRange; + var origRange = eventRange.range; + var slicedRange = intersectRanges(origRange, { + start: cells[spanStart].date, + end: addDays(cells[spanEnd - 1].date, 1), + }); + return __assign(__assign({}, seg), { firstCol: spanStart, lastCol: spanEnd - 1, eventRange: { + def: eventRange.def, + ui: __assign(__assign({}, eventRange.ui), { durationEditable: false }), + instance: eventRange.instance, + range: slicedRange, + }, isStart: seg.isStart && slicedRange.start.valueOf() === origRange.start.valueOf(), isEnd: seg.isEnd && slicedRange.end.valueOf() === origRange.end.valueOf() }); + } + var DayGridSegHierarchy = /** @class */ (function (_super) { + __extends(DayGridSegHierarchy, _super); + function DayGridSegHierarchy() { + var _this = _super !== null && _super.apply(this, arguments) || this; + // config + _this.hiddenConsumes = false; + // allows us to keep hidden entries in the hierarchy so they take up space + _this.forceHidden = {}; + return _this; + } + DayGridSegHierarchy.prototype.addSegs = function (segInputs) { + var _this = this; + var hiddenSegs = _super.prototype.addSegs.call(this, segInputs); + var entriesByLevel = this.entriesByLevel; + var excludeHidden = function (entry) { return !_this.forceHidden[buildEntryKey(entry)]; }; + // remove the forced-hidden segs + for (var level = 0; level < entriesByLevel.length; level += 1) { + entriesByLevel[level] = entriesByLevel[level].filter(excludeHidden); + } + return hiddenSegs; + }; + DayGridSegHierarchy.prototype.handleInvalidInsertion = function (insertion, entry, hiddenEntries) { + var _a = this, entriesByLevel = _a.entriesByLevel, forceHidden = _a.forceHidden; + var touchingLevel = insertion.touchingLevel; + if (this.hiddenConsumes && touchingLevel >= 0) { + for (var lateral = insertion.lateralStart; lateral < insertion.lateralEnd; lateral += 1) { + var leadingEntry = entriesByLevel[touchingLevel][lateral]; + if (this.allowReslicing) { + var placeholderEntry = __assign(__assign({}, leadingEntry), { span: intersectSpans(leadingEntry.span, entry.span) }); + var placeholderEntryId = buildEntryKey(placeholderEntry); + if (!forceHidden[placeholderEntryId]) { // if not already hidden + forceHidden[placeholderEntryId] = true; + entriesByLevel[touchingLevel][lateral] = placeholderEntry; // replace leadingEntry with our placeholder + this.splitEntry(leadingEntry, entry, hiddenEntries); // split up the leadingEntry, reinsert it + } + } + else { + var placeholderEntryId = buildEntryKey(leadingEntry); + if (!forceHidden[placeholderEntryId]) { + forceHidden[placeholderEntryId] = true; + hiddenEntries.push(leadingEntry); + } + } + } + } + return _super.prototype.handleInvalidInsertion.call(this, insertion, entry, hiddenEntries); + }; + return DayGridSegHierarchy; + }(SegHierarchy)); + + var TableRow = /** @class */ (function (_super) { + __extends(TableRow, _super); + function TableRow() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.cellElRefs = new RefMap(); // the ? + createElement("tr", { className: "fc-scrollgrid-section" }, + createElement("td", { className: 'fc-timegrid-divider ' + context.theme.getClass('tableCellShaded') }))), + }); + } + sections.push({ + type: 'body', + key: 'body', + liquid: true, + expandRows: Boolean(context.options.expandRows), + chunk: { + scrollerElRef: this.scrollerElRef, + content: timeContent, + }, + }); + return (createElement(ViewRoot, { viewSpec: context.viewSpec, elRef: this.rootElRef }, function (rootElRef, classNames) { return (createElement("div", { className: ['fc-timegrid'].concat(classNames).join(' '), ref: rootElRef }, + createElement(SimpleScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [{ width: 'shrink' }], sections: sections }))); })); + }; + TimeColsView.prototype.renderHScrollLayout = function (headerRowContent, allDayContent, timeContent, colCnt, dayMinWidth, slatMetas, slatCoords) { + var _this = this; + var ScrollGrid = this.context.pluginHooks.scrollGridImpl; + if (!ScrollGrid) { + throw new Error('No ScrollGrid implementation'); + } + var _a = this, context = _a.context, props = _a.props; + var stickyHeaderDates = !props.forPrint && getStickyHeaderDates(context.options); + var stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(context.options); + var sections = []; + if (headerRowContent) { + sections.push({ + type: 'header', + key: 'header', + isSticky: stickyHeaderDates, + syncRowHeights: true, + chunks: [ + { + key: 'axis', + rowContent: function (arg) { return (createElement("tr", null, _this.renderHeadAxis('day', arg.rowSyncHeights[0]))); }, + }, + { + key: 'cols', + elRef: this.headerElRef, + tableClassName: 'fc-col-header', + rowContent: headerRowContent, + }, + ], + }); + } + if (allDayContent) { + sections.push({ + type: 'body', + key: 'all-day', + syncRowHeights: true, + chunks: [ + { + key: 'axis', + rowContent: function (contentArg) { return (createElement("tr", null, _this.renderTableRowAxis(contentArg.rowSyncHeights[0]))); }, + }, + { + key: 'cols', + content: allDayContent, + }, + ], + }); + sections.push({ + key: 'all-day-divider', + type: 'body', + outerContent: ( // TODO: rename to cellContent so don't need to define ? + createElement("tr", { className: "fc-scrollgrid-section" }, + createElement("td", { colSpan: 2, className: 'fc-timegrid-divider ' + context.theme.getClass('tableCellShaded') }))), + }); + } + var isNowIndicator = context.options.nowIndicator; + sections.push({ + type: 'body', + key: 'body', + liquid: true, + expandRows: Boolean(context.options.expandRows), + chunks: [ + { + key: 'axis', + content: function (arg) { return ( + // TODO: make this now-indicator arrow more DRY with TimeColsContent + createElement("div", { className: "fc-timegrid-axis-chunk" }, + createElement("table", { style: { height: arg.expandRows ? arg.clientHeight : '' } }, + arg.tableColGroupNode, + createElement("tbody", null, + createElement(TimeBodyAxis, { slatMetas: slatMetas }))), + createElement("div", { className: "fc-timegrid-now-indicator-container" }, + createElement(NowTimer, { unit: isNowIndicator ? 'minute' : 'day' /* hacky */ }, function (nowDate) { + var nowIndicatorTop = isNowIndicator && + slatCoords && + slatCoords.safeComputeTop(nowDate); // might return void + if (typeof nowIndicatorTop === 'number') { + return (createElement(NowIndicatorRoot, { isAxis: true, date: nowDate }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("div", { ref: rootElRef, className: ['fc-timegrid-now-indicator-arrow'].concat(classNames).join(' '), style: { top: nowIndicatorTop } }, innerContent)); })); + } + return null; + })))); }, + }, + { + key: 'cols', + scrollerElRef: this.scrollerElRef, + content: timeContent, + }, + ], + }); + if (stickyFooterScrollbar) { + sections.push({ + key: 'footer', + type: 'footer', + isSticky: true, + chunks: [ + { + key: 'axis', + content: renderScrollShim, + }, + { + key: 'cols', + content: renderScrollShim, + }, + ], + }); + } + return (createElement(ViewRoot, { viewSpec: context.viewSpec, elRef: this.rootElRef }, function (rootElRef, classNames) { return (createElement("div", { className: ['fc-timegrid'].concat(classNames).join(' '), ref: rootElRef }, + createElement(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: false, colGroups: [ + { width: 'shrink', cols: [{ width: 'shrink' }] }, + { cols: [{ span: colCnt, minWidth: dayMinWidth }] }, + ], sections: sections }))); })); + }; + /* Dimensions + ------------------------------------------------------------------------------------------------------------------*/ + TimeColsView.prototype.getAllDayMaxEventProps = function () { + var _a = this.context.options, dayMaxEvents = _a.dayMaxEvents, dayMaxEventRows = _a.dayMaxEventRows; + if (dayMaxEvents === true || dayMaxEventRows === true) { // is auto? + dayMaxEvents = undefined; + dayMaxEventRows = AUTO_ALL_DAY_MAX_EVENT_ROWS; // make sure "auto" goes to a real number + } + return { dayMaxEvents: dayMaxEvents, dayMaxEventRows: dayMaxEventRows }; + }; + return TimeColsView; + }(DateComponent)); + function renderAllDayInner$1(hookProps) { + return hookProps.text; + } + + var TimeColsSlatsCoords = /** @class */ (function () { + function TimeColsSlatsCoords(positions, dateProfile, slotDuration) { + this.positions = positions; + this.dateProfile = dateProfile; + this.slotDuration = slotDuration; + } + TimeColsSlatsCoords.prototype.safeComputeTop = function (date) { + var dateProfile = this.dateProfile; + if (rangeContainsMarker(dateProfile.currentRange, date)) { + var startOfDayDate = startOfDay(date); + var timeMs = date.valueOf() - startOfDayDate.valueOf(); + if (timeMs >= asRoughMs(dateProfile.slotMinTime) && + timeMs < asRoughMs(dateProfile.slotMaxTime)) { + return this.computeTimeTop(createDuration(timeMs)); + } + } + return null; + }; + // Computes the top coordinate, relative to the bounds of the grid, of the given date. + // A `startOfDayDate` must be given for avoiding ambiguity over how to treat midnight. + TimeColsSlatsCoords.prototype.computeDateTop = function (when, startOfDayDate) { + if (!startOfDayDate) { + startOfDayDate = startOfDay(when); + } + return this.computeTimeTop(createDuration(when.valueOf() - startOfDayDate.valueOf())); + }; + // Computes the top coordinate, relative to the bounds of the grid, of the given time (a Duration). + // This is a makeshify way to compute the time-top. Assumes all slatMetas dates are uniform. + // Eventually allow computation with arbirary slat dates. + TimeColsSlatsCoords.prototype.computeTimeTop = function (duration) { + var _a = this, positions = _a.positions, dateProfile = _a.dateProfile; + var len = positions.els.length; + // floating-point value of # of slots covered + var slatCoverage = (duration.milliseconds - asRoughMs(dateProfile.slotMinTime)) / asRoughMs(this.slotDuration); + var slatIndex; + var slatRemainder; + // compute a floating-point number for how many slats should be progressed through. + // from 0 to number of slats (inclusive) + // constrained because slotMinTime/slotMaxTime might be customized. + slatCoverage = Math.max(0, slatCoverage); + slatCoverage = Math.min(len, slatCoverage); + // an integer index of the furthest whole slat + // from 0 to number slats (*exclusive*, so len-1) + slatIndex = Math.floor(slatCoverage); + slatIndex = Math.min(slatIndex, len - 1); + // how much further through the slatIndex slat (from 0.0-1.0) must be covered in addition. + // could be 1.0 if slatCoverage is covering *all* the slots + slatRemainder = slatCoverage - slatIndex; + return positions.tops[slatIndex] + + positions.getHeight(slatIndex) * slatRemainder; + }; + return TimeColsSlatsCoords; + }()); + + var TimeColsSlatsBody = /** @class */ (function (_super) { + __extends(TimeColsSlatsBody, _super); + function TimeColsSlatsBody() { + return _super !== null && _super.apply(this, arguments) || this; + } + TimeColsSlatsBody.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var options = context.options; + var slatElRefs = props.slatElRefs; + return (createElement("tbody", null, props.slatMetas.map(function (slatMeta, i) { + var hookProps = { + time: slatMeta.time, + date: context.dateEnv.toDate(slatMeta.date), + view: context.viewApi, + }; + var classNames = [ + 'fc-timegrid-slot', + 'fc-timegrid-slot-lane', + slatMeta.isLabeled ? '' : 'fc-timegrid-slot-minor', + ]; + return (createElement("tr", { key: slatMeta.key, ref: slatElRefs.createRef(slatMeta.key) }, + props.axis && (createElement(TimeColsAxisCell, __assign({}, slatMeta))), + createElement(RenderHook, { hookProps: hookProps, classNames: options.slotLaneClassNames, content: options.slotLaneContent, didMount: options.slotLaneDidMount, willUnmount: options.slotLaneWillUnmount }, function (rootElRef, customClassNames, innerElRef, innerContent) { return (createElement("td", { ref: rootElRef, className: classNames.concat(customClassNames).join(' '), "data-time": slatMeta.isoTimeStr }, innerContent)); }))); + }))); + }; + return TimeColsSlatsBody; + }(BaseComponent)); + + /* + for the horizontal "slats" that run width-wise. Has a time axis on a side. Depends on RTL. + */ + var TimeColsSlats = /** @class */ (function (_super) { + __extends(TimeColsSlats, _super); + function TimeColsSlats() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.rootElRef = createRef(); + _this.slatElRefs = new RefMap(); + return _this; + } + TimeColsSlats.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + return (createElement("div", { className: "fc-timegrid-slots", ref: this.rootElRef }, + createElement("table", { className: context.theme.getClass('table'), style: { + minWidth: props.tableMinWidth, + width: props.clientWidth, + height: props.minHeight, + } }, + props.tableColGroupNode /* relies on there only being a single for the axis */, + createElement(TimeColsSlatsBody, { slatElRefs: this.slatElRefs, axis: props.axis, slatMetas: props.slatMetas })))); + }; + TimeColsSlats.prototype.componentDidMount = function () { + this.updateSizing(); + }; + TimeColsSlats.prototype.componentDidUpdate = function () { + this.updateSizing(); + }; + TimeColsSlats.prototype.componentWillUnmount = function () { + if (this.props.onCoords) { + this.props.onCoords(null); + } + }; + TimeColsSlats.prototype.updateSizing = function () { + var _a = this, context = _a.context, props = _a.props; + if (props.onCoords && + props.clientWidth !== null // means sizing has stabilized + ) { + var rootEl = this.rootElRef.current; + if (rootEl.offsetHeight) { // not hidden by css + props.onCoords(new TimeColsSlatsCoords(new PositionCache(this.rootElRef.current, collectSlatEls(this.slatElRefs.currentMap, props.slatMetas), false, true), this.props.dateProfile, context.options.slotDuration)); + } + } + }; + return TimeColsSlats; + }(BaseComponent)); + function collectSlatEls(elMap, slatMetas) { + return slatMetas.map(function (slatMeta) { return elMap[slatMeta.key]; }); + } + + function splitSegsByCol(segs, colCnt) { + var segsByCol = []; + var i; + for (i = 0; i < colCnt; i += 1) { + segsByCol.push([]); + } + if (segs) { + for (i = 0; i < segs.length; i += 1) { + segsByCol[segs[i].col].push(segs[i]); + } + } + return segsByCol; + } + function splitInteractionByCol(ui, colCnt) { + var byRow = []; + if (!ui) { + for (var i = 0; i < colCnt; i += 1) { + byRow[i] = null; + } + } + else { + for (var i = 0; i < colCnt; i += 1) { + byRow[i] = { + affectedInstances: ui.affectedInstances, + isEvent: ui.isEvent, + segs: [], + }; + } + for (var _i = 0, _a = ui.segs; _i < _a.length; _i++) { + var seg = _a[_i]; + byRow[seg.col].segs.push(seg); + } + } + return byRow; + } + + var TimeColMoreLink = /** @class */ (function (_super) { + __extends(TimeColMoreLink, _super); + function TimeColMoreLink() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.rootElRef = createRef(); + return _this; + } + TimeColMoreLink.prototype.render = function () { + var _this = this; + var props = this.props; + return (createElement(MoreLinkRoot, { allDayDate: null, moreCnt: props.hiddenSegs.length, allSegs: props.hiddenSegs, hiddenSegs: props.hiddenSegs, alignmentElRef: this.rootElRef, defaultContent: renderMoreLinkInner, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, todayRange: props.todayRange, popoverContent: function () { return renderPlainFgSegs(props.hiddenSegs, props); } }, function (rootElRef, classNames, innerElRef, innerContent, handleClick) { return (createElement("a", { ref: function (el) { + setRef(rootElRef, el); + setRef(_this.rootElRef, el); + }, className: ['fc-timegrid-more-link'].concat(classNames).join(' '), style: { top: props.top, bottom: props.bottom }, onClick: handleClick }, + createElement("div", { ref: innerElRef, className: "fc-timegrid-more-link-inner fc-sticky" }, innerContent))); })); + }; + return TimeColMoreLink; + }(BaseComponent)); + function renderMoreLinkInner(props) { + return props.shortText; + } + + // segInputs assumed sorted + function buildPositioning(segInputs, strictOrder, maxStackCnt) { + var hierarchy = new SegHierarchy(); + if (strictOrder != null) { + hierarchy.strictOrder = strictOrder; + } + if (maxStackCnt != null) { + hierarchy.maxStackCnt = maxStackCnt; + } + var hiddenEntries = hierarchy.addSegs(segInputs); + var hiddenGroups = groupIntersectingEntries(hiddenEntries); + var web = buildWeb(hierarchy); + web = stretchWeb(web, 1); // all levelCoords/thickness will have 0.0-1.0 + var segRects = webToRects(web); + return { segRects: segRects, hiddenGroups: hiddenGroups }; + } + function buildWeb(hierarchy) { + var entriesByLevel = hierarchy.entriesByLevel; + var buildNode = cacheable(function (level, lateral) { return level + ':' + lateral; }, function (level, lateral) { + var siblingRange = findNextLevelSegs(hierarchy, level, lateral); + var nextLevelRes = buildNodes(siblingRange, buildNode); + var entry = entriesByLevel[level][lateral]; + return [ + __assign(__assign({}, entry), { nextLevelNodes: nextLevelRes[0] }), + entry.thickness + nextLevelRes[1], // the pressure builds + ]; + }); + return buildNodes(entriesByLevel.length + ? { level: 0, lateralStart: 0, lateralEnd: entriesByLevel[0].length } + : null, buildNode)[0]; + } + function buildNodes(siblingRange, buildNode) { + if (!siblingRange) { + return [[], 0]; + } + var level = siblingRange.level, lateralStart = siblingRange.lateralStart, lateralEnd = siblingRange.lateralEnd; + var lateral = lateralStart; + var pairs = []; + while (lateral < lateralEnd) { + pairs.push(buildNode(level, lateral)); + lateral += 1; + } + pairs.sort(cmpDescPressures); + return [ + pairs.map(extractNode), + pairs[0][1], // first item's pressure + ]; + } + function cmpDescPressures(a, b) { + return b[1] - a[1]; + } + function extractNode(a) { + return a[0]; + } + function findNextLevelSegs(hierarchy, subjectLevel, subjectLateral) { + var levelCoords = hierarchy.levelCoords, entriesByLevel = hierarchy.entriesByLevel; + var subjectEntry = entriesByLevel[subjectLevel][subjectLateral]; + var afterSubject = levelCoords[subjectLevel] + subjectEntry.thickness; + var levelCnt = levelCoords.length; + var level = subjectLevel; + // skip past levels that are too high up + for (; level < levelCnt && levelCoords[level] < afterSubject; level += 1) + ; // do nothing + for (; level < levelCnt; level += 1) { + var entries = entriesByLevel[level]; + var entry = void 0; + var searchIndex = binarySearch(entries, subjectEntry.span.start, getEntrySpanEnd); + var lateralStart = searchIndex[0] + searchIndex[1]; // if exact match (which doesn't collide), go to next one + var lateralEnd = lateralStart; + while ( // loop through entries that horizontally intersect + (entry = entries[lateralEnd]) && // but not past the whole seg list + entry.span.start < subjectEntry.span.end) { + lateralEnd += 1; + } + if (lateralStart < lateralEnd) { + return { level: level, lateralStart: lateralStart, lateralEnd: lateralEnd }; + } + } + return null; + } + function stretchWeb(topLevelNodes, totalThickness) { + var stretchNode = cacheable(function (node, startCoord, prevThickness) { return buildEntryKey(node); }, function (node, startCoord, prevThickness) { + var nextLevelNodes = node.nextLevelNodes, thickness = node.thickness; + var allThickness = thickness + prevThickness; + var thicknessFraction = thickness / allThickness; + var endCoord; + var newChildren = []; + if (!nextLevelNodes.length) { + endCoord = totalThickness; + } + else { + for (var _i = 0, nextLevelNodes_1 = nextLevelNodes; _i < nextLevelNodes_1.length; _i++) { + var childNode = nextLevelNodes_1[_i]; + if (endCoord === undefined) { + var res = stretchNode(childNode, startCoord, allThickness); + endCoord = res[0]; + newChildren.push(res[1]); + } + else { + var res = stretchNode(childNode, endCoord, 0); + newChildren.push(res[1]); + } + } + } + var newThickness = (endCoord - startCoord) * thicknessFraction; + return [endCoord - newThickness, __assign(__assign({}, node), { thickness: newThickness, nextLevelNodes: newChildren })]; + }); + return topLevelNodes.map(function (node) { return stretchNode(node, 0, 0)[1]; }); + } + // not sorted in any particular order + function webToRects(topLevelNodes) { + var rects = []; + var processNode = cacheable(function (node, levelCoord, stackDepth) { return buildEntryKey(node); }, function (node, levelCoord, stackDepth) { + var rect = __assign(__assign({}, node), { levelCoord: levelCoord, + stackDepth: stackDepth, stackForward: 0 }); + rects.push(rect); + return (rect.stackForward = processNodes(node.nextLevelNodes, levelCoord + node.thickness, stackDepth + 1) + 1); + }); + function processNodes(nodes, levelCoord, stackDepth) { + var stackForward = 0; + for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) { + var node = nodes_1[_i]; + stackForward = Math.max(processNode(node, levelCoord, stackDepth), stackForward); + } + return stackForward; + } + processNodes(topLevelNodes, 0, 0); + return rects; // TODO: sort rects by levelCoord to be consistent with toRects? + } + // TODO: move to general util + function cacheable(keyFunc, workFunc) { + var cache = {}; + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var key = keyFunc.apply(void 0, args); + return (key in cache) + ? cache[key] + : (cache[key] = workFunc.apply(void 0, args)); + }; + } + + function computeSegVCoords(segs, colDate, slatCoords, eventMinHeight) { + if (slatCoords === void 0) { slatCoords = null; } + if (eventMinHeight === void 0) { eventMinHeight = 0; } + var vcoords = []; + if (slatCoords) { + for (var i = 0; i < segs.length; i += 1) { + var seg = segs[i]; + var spanStart = slatCoords.computeDateTop(seg.start, colDate); + var spanEnd = Math.max(spanStart + (eventMinHeight || 0), // :( + slatCoords.computeDateTop(seg.end, colDate)); + vcoords.push({ + start: Math.round(spanStart), + end: Math.round(spanEnd), // + }); + } + } + return vcoords; + } + function computeFgSegPlacements$1(segs, segVCoords, // might not have for every seg + eventOrderStrict, eventMaxStack) { + var segInputs = []; + var dumbSegs = []; // segs without coords + for (var i = 0; i < segs.length; i += 1) { + var vcoords = segVCoords[i]; + if (vcoords) { + segInputs.push({ + index: i, + thickness: 1, + span: vcoords, + }); + } + else { + dumbSegs.push(segs[i]); + } + } + var _a = buildPositioning(segInputs, eventOrderStrict, eventMaxStack), segRects = _a.segRects, hiddenGroups = _a.hiddenGroups; + var segPlacements = []; + for (var _i = 0, segRects_1 = segRects; _i < segRects_1.length; _i++) { + var segRect = segRects_1[_i]; + segPlacements.push({ + seg: segs[segRect.index], + rect: segRect, + }); + } + for (var _b = 0, dumbSegs_1 = dumbSegs; _b < dumbSegs_1.length; _b++) { + var dumbSeg = dumbSegs_1[_b]; + segPlacements.push({ seg: dumbSeg, rect: null }); + } + return { segPlacements: segPlacements, hiddenGroups: hiddenGroups }; + } + + var DEFAULT_TIME_FORMAT$2 = createFormatter({ + hour: 'numeric', + minute: '2-digit', + meridiem: false, + }); + var TimeColEvent = /** @class */ (function (_super) { + __extends(TimeColEvent, _super); + function TimeColEvent() { + return _super !== null && _super.apply(this, arguments) || this; + } + TimeColEvent.prototype.render = function () { + var classNames = [ + 'fc-timegrid-event', + 'fc-v-event', + ]; + if (this.props.isShort) { + classNames.push('fc-timegrid-event-short'); + } + return (createElement(StandardEvent, __assign({}, this.props, { defaultTimeFormat: DEFAULT_TIME_FORMAT$2, extraClassNames: classNames }))); + }; + return TimeColEvent; + }(BaseComponent)); + + var TimeColMisc = /** @class */ (function (_super) { + __extends(TimeColMisc, _super); + function TimeColMisc() { + return _super !== null && _super.apply(this, arguments) || this; + } + TimeColMisc.prototype.render = function () { + var props = this.props; + return (createElement(DayCellContent, { date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, extraHookProps: props.extraHookProps }, function (innerElRef, innerContent) { return (innerContent && + createElement("div", { className: "fc-timegrid-col-misc", ref: innerElRef }, innerContent)); })); + }; + return TimeColMisc; + }(BaseComponent)); + + var TimeCol = /** @class */ (function (_super) { + __extends(TimeCol, _super); + function TimeCol() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.sortEventSegs = memoize(sortEventSegs); + return _this; + } + // TODO: memoize event-placement? + TimeCol.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var isSelectMirror = context.options.selectMirror; + var mirrorSegs = (props.eventDrag && props.eventDrag.segs) || + (props.eventResize && props.eventResize.segs) || + (isSelectMirror && props.dateSelectionSegs) || + []; + var interactionAffectedInstances = // TODO: messy way to compute this + (props.eventDrag && props.eventDrag.affectedInstances) || + (props.eventResize && props.eventResize.affectedInstances) || + {}; + var sortedFgSegs = this.sortEventSegs(props.fgEventSegs, context.options.eventOrder); + return (createElement(DayCellRoot, { elRef: props.elRef, date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, extraHookProps: props.extraHookProps }, function (rootElRef, classNames, dataAttrs) { return (createElement("td", __assign({ ref: rootElRef, className: ['fc-timegrid-col'].concat(classNames, props.extraClassNames || []).join(' ') }, dataAttrs, props.extraDataAttrs), + createElement("div", { className: "fc-timegrid-col-frame" }, + createElement("div", { className: "fc-timegrid-col-bg" }, + _this.renderFillSegs(props.businessHourSegs, 'non-business'), + _this.renderFillSegs(props.bgEventSegs, 'bg-event'), + _this.renderFillSegs(props.dateSelectionSegs, 'highlight')), + createElement("div", { className: "fc-timegrid-col-events" }, _this.renderFgSegs(sortedFgSegs, interactionAffectedInstances, false, false, false)), + createElement("div", { className: "fc-timegrid-col-events" }, _this.renderFgSegs(mirrorSegs, {}, Boolean(props.eventDrag), Boolean(props.eventResize), Boolean(isSelectMirror))), + createElement("div", { className: "fc-timegrid-now-indicator-container" }, _this.renderNowIndicator(props.nowIndicatorSegs)), + createElement(TimeColMisc, { date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, extraHookProps: props.extraHookProps })))); })); + }; + TimeCol.prototype.renderFgSegs = function (sortedFgSegs, segIsInvisible, isDragging, isResizing, isDateSelecting) { + var props = this.props; + if (props.forPrint) { + return renderPlainFgSegs(sortedFgSegs, props); + } + return this.renderPositionedFgSegs(sortedFgSegs, segIsInvisible, isDragging, isResizing, isDateSelecting); + }; + TimeCol.prototype.renderPositionedFgSegs = function (segs, // if not mirror, needs to be sorted + segIsInvisible, isDragging, isResizing, isDateSelecting) { + var _this = this; + var _a = this.context.options, eventMaxStack = _a.eventMaxStack, eventShortHeight = _a.eventShortHeight, eventOrderStrict = _a.eventOrderStrict, eventMinHeight = _a.eventMinHeight; + var _b = this.props, date = _b.date, slatCoords = _b.slatCoords, eventSelection = _b.eventSelection, todayRange = _b.todayRange, nowDate = _b.nowDate; + var isMirror = isDragging || isResizing || isDateSelecting; + var segVCoords = computeSegVCoords(segs, date, slatCoords, eventMinHeight); + var _c = computeFgSegPlacements$1(segs, segVCoords, eventOrderStrict, eventMaxStack), segPlacements = _c.segPlacements, hiddenGroups = _c.hiddenGroups; + return (createElement(Fragment, null, + this.renderHiddenGroups(hiddenGroups, segs), + segPlacements.map(function (segPlacement) { + var seg = segPlacement.seg, rect = segPlacement.rect; + var instanceId = seg.eventRange.instance.instanceId; + var isVisible = isMirror || Boolean(!segIsInvisible[instanceId] && rect); + var vStyle = computeSegVStyle(rect && rect.span); + var hStyle = (!isMirror && rect) ? _this.computeSegHStyle(rect) : { left: 0, right: 0 }; + var isInset = Boolean(rect) && rect.stackForward > 0; + var isShort = Boolean(rect) && (rect.span.end - rect.span.start) < eventShortHeight; // look at other places for this problem + return (createElement("div", { className: 'fc-timegrid-event-harness' + + (isInset ? ' fc-timegrid-event-harness-inset' : ''), key: instanceId, style: __assign(__assign({ visibility: isVisible ? '' : 'hidden' }, vStyle), hStyle) }, + createElement(TimeColEvent, __assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, isShort: isShort }, getSegMeta(seg, todayRange, nowDate))))); + }))); + }; + // will already have eventMinHeight applied because segInputs already had it + TimeCol.prototype.renderHiddenGroups = function (hiddenGroups, segs) { + var _a = this.props, extraDateSpan = _a.extraDateSpan, dateProfile = _a.dateProfile, todayRange = _a.todayRange, nowDate = _a.nowDate, eventSelection = _a.eventSelection, eventDrag = _a.eventDrag, eventResize = _a.eventResize; + return (createElement(Fragment, null, hiddenGroups.map(function (hiddenGroup) { + var positionCss = computeSegVStyle(hiddenGroup.span); + var hiddenSegs = compileSegsFromEntries(hiddenGroup.entries, segs); + return (createElement(TimeColMoreLink, { key: buildIsoString(computeEarliestSegStart(hiddenSegs)), hiddenSegs: hiddenSegs, top: positionCss.top, bottom: positionCss.bottom, extraDateSpan: extraDateSpan, dateProfile: dateProfile, todayRange: todayRange, nowDate: nowDate, eventSelection: eventSelection, eventDrag: eventDrag, eventResize: eventResize })); + }))); + }; + TimeCol.prototype.renderFillSegs = function (segs, fillType) { + var _a = this, props = _a.props, context = _a.context; + var segVCoords = computeSegVCoords(segs, props.date, props.slatCoords, context.options.eventMinHeight); // don't assume all populated + var children = segVCoords.map(function (vcoords, i) { + var seg = segs[i]; + return (createElement("div", { key: buildEventRangeKey(seg.eventRange), className: "fc-timegrid-bg-harness", style: computeSegVStyle(vcoords) }, fillType === 'bg-event' ? + createElement(BgEvent, __assign({ seg: seg }, getSegMeta(seg, props.todayRange, props.nowDate))) : + renderFill(fillType))); + }); + return createElement(Fragment, null, children); + }; + TimeCol.prototype.renderNowIndicator = function (segs) { + var _a = this.props, slatCoords = _a.slatCoords, date = _a.date; + if (!slatCoords) { + return null; + } + return segs.map(function (seg, i) { return (createElement(NowIndicatorRoot, { isAxis: false, date: date, + // key doesn't matter. will only ever be one + key: i }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("div", { ref: rootElRef, className: ['fc-timegrid-now-indicator-line'].concat(classNames).join(' '), style: { top: slatCoords.computeDateTop(seg.start, date) } }, innerContent)); })); }); + }; + TimeCol.prototype.computeSegHStyle = function (segHCoords) { + var _a = this.context, isRtl = _a.isRtl, options = _a.options; + var shouldOverlap = options.slotEventOverlap; + var nearCoord = segHCoords.levelCoord; // the left side if LTR. the right side if RTL. floating-point + var farCoord = segHCoords.levelCoord + segHCoords.thickness; // the right side if LTR. the left side if RTL. floating-point + var left; // amount of space from left edge, a fraction of the total width + var right; // amount of space from right edge, a fraction of the total width + if (shouldOverlap) { + // double the width, but don't go beyond the maximum forward coordinate (1.0) + farCoord = Math.min(1, nearCoord + (farCoord - nearCoord) * 2); + } + if (isRtl) { + left = 1 - farCoord; + right = nearCoord; + } + else { + left = nearCoord; + right = 1 - farCoord; + } + var props = { + zIndex: segHCoords.stackDepth + 1, + left: left * 100 + '%', + right: right * 100 + '%', + }; + if (shouldOverlap && !segHCoords.stackForward) { + // add padding to the edge so that forward stacked events don't cover the resizer's icon + props[isRtl ? 'marginLeft' : 'marginRight'] = 10 * 2; // 10 is a guesstimate of the icon's width + } + return props; + }; + return TimeCol; + }(BaseComponent)); + function renderPlainFgSegs(sortedFgSegs, _a) { + var todayRange = _a.todayRange, nowDate = _a.nowDate, eventSelection = _a.eventSelection, eventDrag = _a.eventDrag, eventResize = _a.eventResize; + var hiddenInstances = (eventDrag ? eventDrag.affectedInstances : null) || + (eventResize ? eventResize.affectedInstances : null) || + {}; + return (createElement(Fragment, null, sortedFgSegs.map(function (seg) { + var instanceId = seg.eventRange.instance.instanceId; + return (createElement("div", { key: instanceId, style: { visibility: hiddenInstances[instanceId] ? 'hidden' : '' } }, + createElement(TimeColEvent, __assign({ seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === eventSelection, isShort: false }, getSegMeta(seg, todayRange, nowDate))))); + }))); + } + function computeSegVStyle(segVCoords) { + if (!segVCoords) { + return { top: '', bottom: '' }; + } + return { + top: segVCoords.start, + bottom: -segVCoords.end, + }; + } + function compileSegsFromEntries(segEntries, allSegs) { + return segEntries.map(function (segEntry) { return allSegs[segEntry.index]; }); + } + + var TimeColsContent = /** @class */ (function (_super) { + __extends(TimeColsContent, _super); + function TimeColsContent() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.splitFgEventSegs = memoize(splitSegsByCol); + _this.splitBgEventSegs = memoize(splitSegsByCol); + _this.splitBusinessHourSegs = memoize(splitSegsByCol); + _this.splitNowIndicatorSegs = memoize(splitSegsByCol); + _this.splitDateSelectionSegs = memoize(splitSegsByCol); + _this.splitEventDrag = memoize(splitInteractionByCol); + _this.splitEventResize = memoize(splitInteractionByCol); + _this.rootElRef = createRef(); + _this.cellElRefs = new RefMap(); + return _this; + } + TimeColsContent.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var nowIndicatorTop = context.options.nowIndicator && + props.slatCoords && + props.slatCoords.safeComputeTop(props.nowDate); // might return void + var colCnt = props.cells.length; + var fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, colCnt); + var bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, colCnt); + var businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, colCnt); + var nowIndicatorSegsByRow = this.splitNowIndicatorSegs(props.nowIndicatorSegs, colCnt); + var dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, colCnt); + var eventDragByRow = this.splitEventDrag(props.eventDrag, colCnt); + var eventResizeByRow = this.splitEventResize(props.eventResize, colCnt); + return (createElement("div", { className: "fc-timegrid-cols", ref: this.rootElRef }, + createElement("table", { style: { + minWidth: props.tableMinWidth, + width: props.clientWidth, + } }, + props.tableColGroupNode, + createElement("tbody", null, + createElement("tr", null, + props.axis && (createElement("td", { className: "fc-timegrid-col fc-timegrid-axis" }, + createElement("div", { className: "fc-timegrid-col-frame" }, + createElement("div", { className: "fc-timegrid-now-indicator-container" }, typeof nowIndicatorTop === 'number' && (createElement(NowIndicatorRoot, { isAxis: true, date: props.nowDate }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("div", { ref: rootElRef, className: ['fc-timegrid-now-indicator-arrow'].concat(classNames).join(' '), style: { top: nowIndicatorTop } }, innerContent)); })))))), + props.cells.map(function (cell, i) { return (createElement(TimeCol, { key: cell.key, elRef: _this.cellElRefs.createRef(cell.key), dateProfile: props.dateProfile, date: cell.date, nowDate: props.nowDate, todayRange: props.todayRange, extraHookProps: cell.extraHookProps, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames, extraDateSpan: cell.extraDateSpan, fgEventSegs: fgEventSegsByRow[i], bgEventSegs: bgEventSegsByRow[i], businessHourSegs: businessHourSegsByRow[i], nowIndicatorSegs: nowIndicatorSegsByRow[i], dateSelectionSegs: dateSelectionSegsByRow[i], eventDrag: eventDragByRow[i], eventResize: eventResizeByRow[i], slatCoords: props.slatCoords, eventSelection: props.eventSelection, forPrint: props.forPrint })); })))))); + }; + TimeColsContent.prototype.componentDidMount = function () { + this.updateCoords(); + }; + TimeColsContent.prototype.componentDidUpdate = function () { + this.updateCoords(); + }; + TimeColsContent.prototype.updateCoords = function () { + var props = this.props; + if (props.onColCoords && + props.clientWidth !== null // means sizing has stabilized + ) { + props.onColCoords(new PositionCache(this.rootElRef.current, collectCellEls$1(this.cellElRefs.currentMap, props.cells), true, // horizontal + false)); + } + }; + return TimeColsContent; + }(BaseComponent)); + function collectCellEls$1(elMap, cells) { + return cells.map(function (cell) { return elMap[cell.key]; }); + } + + /* A component that renders one or more columns of vertical time slots + ----------------------------------------------------------------------------------------------------------------------*/ + var TimeCols = /** @class */ (function (_super) { + __extends(TimeCols, _super); + function TimeCols() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.processSlotOptions = memoize(processSlotOptions); + _this.state = { + slatCoords: null, + }; + _this.handleRootEl = function (el) { + if (el) { + _this.context.registerInteractiveComponent(_this, { + el: el, + isHitComboAllowed: _this.props.isHitComboAllowed, + }); + } + else { + _this.context.unregisterInteractiveComponent(_this); + } + }; + _this.handleScrollRequest = function (request) { + var onScrollTopRequest = _this.props.onScrollTopRequest; + var slatCoords = _this.state.slatCoords; + if (onScrollTopRequest && slatCoords) { + if (request.time) { + var top_1 = slatCoords.computeTimeTop(request.time); + top_1 = Math.ceil(top_1); // zoom can give weird floating-point values. rather scroll a little bit further + if (top_1) { + top_1 += 1; // to overcome top border that slots beyond the first have. looks better + } + onScrollTopRequest(top_1); + } + return true; + } + return false; + }; + _this.handleColCoords = function (colCoords) { + _this.colCoords = colCoords; + }; + _this.handleSlatCoords = function (slatCoords) { + _this.setState({ slatCoords: slatCoords }); + if (_this.props.onSlatCoords) { + _this.props.onSlatCoords(slatCoords); + } + }; + return _this; + } + TimeCols.prototype.render = function () { + var _a = this, props = _a.props, state = _a.state; + return (createElement("div", { className: "fc-timegrid-body", ref: this.handleRootEl, style: { + // these props are important to give this wrapper correct dimensions for interactions + // TODO: if we set it here, can we avoid giving to inner tables? + width: props.clientWidth, + minWidth: props.tableMinWidth, + } }, + createElement(TimeColsSlats, { axis: props.axis, dateProfile: props.dateProfile, slatMetas: props.slatMetas, clientWidth: props.clientWidth, minHeight: props.expandRows ? props.clientHeight : '', tableMinWidth: props.tableMinWidth, tableColGroupNode: props.axis ? props.tableColGroupNode : null /* axis depends on the colgroup's shrinking */, onCoords: this.handleSlatCoords }), + createElement(TimeColsContent, { cells: props.cells, axis: props.axis, dateProfile: props.dateProfile, businessHourSegs: props.businessHourSegs, bgEventSegs: props.bgEventSegs, fgEventSegs: props.fgEventSegs, dateSelectionSegs: props.dateSelectionSegs, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange, nowDate: props.nowDate, nowIndicatorSegs: props.nowIndicatorSegs, clientWidth: props.clientWidth, tableMinWidth: props.tableMinWidth, tableColGroupNode: props.tableColGroupNode, slatCoords: state.slatCoords, onColCoords: this.handleColCoords, forPrint: props.forPrint }))); + }; + TimeCols.prototype.componentDidMount = function () { + this.scrollResponder = this.context.createScrollResponder(this.handleScrollRequest); + }; + TimeCols.prototype.componentDidUpdate = function (prevProps) { + this.scrollResponder.update(prevProps.dateProfile !== this.props.dateProfile); + }; + TimeCols.prototype.componentWillUnmount = function () { + this.scrollResponder.detach(); + }; + TimeCols.prototype.queryHit = function (positionLeft, positionTop) { + var _a = this.context, dateEnv = _a.dateEnv, options = _a.options; + var colCoords = this.colCoords; + var dateProfile = this.props.dateProfile; + var slatCoords = this.state.slatCoords; + var _b = this.processSlotOptions(this.props.slotDuration, options.snapDuration), snapDuration = _b.snapDuration, snapsPerSlot = _b.snapsPerSlot; + var colIndex = colCoords.leftToIndex(positionLeft); + var slatIndex = slatCoords.positions.topToIndex(positionTop); + if (colIndex != null && slatIndex != null) { + var cell = this.props.cells[colIndex]; + var slatTop = slatCoords.positions.tops[slatIndex]; + var slatHeight = slatCoords.positions.getHeight(slatIndex); + var partial = (positionTop - slatTop) / slatHeight; // floating point number between 0 and 1 + var localSnapIndex = Math.floor(partial * snapsPerSlot); // the snap # relative to start of slat + var snapIndex = slatIndex * snapsPerSlot + localSnapIndex; + var dayDate = this.props.cells[colIndex].date; + var time = addDurations(dateProfile.slotMinTime, multiplyDuration(snapDuration, snapIndex)); + var start = dateEnv.add(dayDate, time); + var end = dateEnv.add(start, snapDuration); + return { + dateProfile: dateProfile, + dateSpan: __assign({ range: { start: start, end: end }, allDay: false }, cell.extraDateSpan), + dayEl: colCoords.els[colIndex], + rect: { + left: colCoords.lefts[colIndex], + right: colCoords.rights[colIndex], + top: slatTop, + bottom: slatTop + slatHeight, + }, + layer: 0, + }; + } + return null; + }; + return TimeCols; + }(DateComponent)); + function processSlotOptions(slotDuration, snapDurationOverride) { + var snapDuration = snapDurationOverride || slotDuration; + var snapsPerSlot = wholeDivideDurations(slotDuration, snapDuration); + if (snapsPerSlot === null) { + snapDuration = slotDuration; + snapsPerSlot = 1; + // TODO: say warning? + } + return { snapDuration: snapDuration, snapsPerSlot: snapsPerSlot }; + } + + var DayTimeColsSlicer = /** @class */ (function (_super) { + __extends(DayTimeColsSlicer, _super); + function DayTimeColsSlicer() { + return _super !== null && _super.apply(this, arguments) || this; + } + DayTimeColsSlicer.prototype.sliceRange = function (range, dayRanges) { + var segs = []; + for (var col = 0; col < dayRanges.length; col += 1) { + var segRange = intersectRanges(range, dayRanges[col]); + if (segRange) { + segs.push({ + start: segRange.start, + end: segRange.end, + isStart: segRange.start.valueOf() === range.start.valueOf(), + isEnd: segRange.end.valueOf() === range.end.valueOf(), + col: col, + }); + } + } + return segs; + }; + return DayTimeColsSlicer; + }(Slicer)); + + var DayTimeCols = /** @class */ (function (_super) { + __extends(DayTimeCols, _super); + function DayTimeCols() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.buildDayRanges = memoize(buildDayRanges); + _this.slicer = new DayTimeColsSlicer(); + _this.timeColsRef = createRef(); + return _this; + } + DayTimeCols.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var dateProfile = props.dateProfile, dayTableModel = props.dayTableModel; + var isNowIndicator = context.options.nowIndicator; + var dayRanges = this.buildDayRanges(dayTableModel, dateProfile, context.dateEnv); + // give it the first row of cells + // TODO: would move this further down hierarchy, but sliceNowDate needs it + return (createElement(NowTimer, { unit: isNowIndicator ? 'minute' : 'day' }, function (nowDate, todayRange) { return (createElement(TimeCols, __assign({ ref: _this.timeColsRef }, _this.slicer.sliceProps(props, dateProfile, null, context, dayRanges), { forPrint: props.forPrint, axis: props.axis, dateProfile: dateProfile, slatMetas: props.slatMetas, slotDuration: props.slotDuration, cells: dayTableModel.cells[0], tableColGroupNode: props.tableColGroupNode, tableMinWidth: props.tableMinWidth, clientWidth: props.clientWidth, clientHeight: props.clientHeight, expandRows: props.expandRows, nowDate: nowDate, nowIndicatorSegs: isNowIndicator && _this.slicer.sliceNowDate(nowDate, context, dayRanges), todayRange: todayRange, onScrollTopRequest: props.onScrollTopRequest, onSlatCoords: props.onSlatCoords }))); })); + }; + return DayTimeCols; + }(DateComponent)); + function buildDayRanges(dayTableModel, dateProfile, dateEnv) { + var ranges = []; + for (var _i = 0, _a = dayTableModel.headerDates; _i < _a.length; _i++) { + var date = _a[_i]; + ranges.push({ + start: dateEnv.add(date, dateProfile.slotMinTime), + end: dateEnv.add(date, dateProfile.slotMaxTime), + }); + } + return ranges; + } + + // potential nice values for the slot-duration and interval-duration + // from largest to smallest + var STOCK_SUB_DURATIONS$1 = [ + { hours: 1 }, + { minutes: 30 }, + { minutes: 15 }, + { seconds: 30 }, + { seconds: 15 }, + ]; + function buildSlatMetas(slotMinTime, slotMaxTime, explicitLabelInterval, slotDuration, dateEnv) { + var dayStart = new Date(0); + var slatTime = slotMinTime; + var slatIterator = createDuration(0); + var labelInterval = explicitLabelInterval || computeLabelInterval(slotDuration); + var metas = []; + while (asRoughMs(slatTime) < asRoughMs(slotMaxTime)) { + var date = dateEnv.add(dayStart, slatTime); + var isLabeled = wholeDivideDurations(slatIterator, labelInterval) !== null; + metas.push({ + date: date, + time: slatTime, + key: date.toISOString(), + isoTimeStr: formatIsoTimeString(date), + isLabeled: isLabeled, + }); + slatTime = addDurations(slatTime, slotDuration); + slatIterator = addDurations(slatIterator, slotDuration); + } + return metas; + } + // Computes an automatic value for slotLabelInterval + function computeLabelInterval(slotDuration) { + var i; + var labelInterval; + var slotsPerLabel; + // find the smallest stock label interval that results in more than one slots-per-label + for (i = STOCK_SUB_DURATIONS$1.length - 1; i >= 0; i -= 1) { + labelInterval = createDuration(STOCK_SUB_DURATIONS$1[i]); + slotsPerLabel = wholeDivideDurations(labelInterval, slotDuration); + if (slotsPerLabel !== null && slotsPerLabel > 1) { + return labelInterval; + } + } + return slotDuration; // fall back + } + + var DayTimeColsView = /** @class */ (function (_super) { + __extends(DayTimeColsView, _super); + function DayTimeColsView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.buildTimeColsModel = memoize(buildTimeColsModel); + _this.buildSlatMetas = memoize(buildSlatMetas); + return _this; + } + DayTimeColsView.prototype.render = function () { + var _this = this; + var _a = this.context, options = _a.options, dateEnv = _a.dateEnv, dateProfileGenerator = _a.dateProfileGenerator; + var props = this.props; + var dateProfile = props.dateProfile; + var dayTableModel = this.buildTimeColsModel(dateProfile, dateProfileGenerator); + var splitProps = this.allDaySplitter.splitProps(props); + var slatMetas = this.buildSlatMetas(dateProfile.slotMinTime, dateProfile.slotMaxTime, options.slotLabelInterval, options.slotDuration, dateEnv); + var dayMinWidth = options.dayMinWidth; + var hasAttachedAxis = !dayMinWidth; + var hasDetachedAxis = dayMinWidth; + var headerContent = options.dayHeaders && (createElement(DayHeader, { dates: dayTableModel.headerDates, dateProfile: dateProfile, datesRepDistinctDays: true, renderIntro: hasAttachedAxis ? this.renderHeadAxis : null })); + var allDayContent = (options.allDaySlot !== false) && (function (contentArg) { return (createElement(DayTable, __assign({}, splitProps.allDay, { dateProfile: dateProfile, dayTableModel: dayTableModel, nextDayThreshold: options.nextDayThreshold, tableMinWidth: contentArg.tableMinWidth, colGroupNode: contentArg.tableColGroupNode, renderRowIntro: hasAttachedAxis ? _this.renderTableRowAxis : null, showWeekNumbers: false, expandRows: false, headerAlignElRef: _this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint }, _this.getAllDayMaxEventProps()))); }); + var timeGridContent = function (contentArg) { return (createElement(DayTimeCols, __assign({}, splitProps.timed, { dayTableModel: dayTableModel, dateProfile: dateProfile, axis: hasAttachedAxis, slotDuration: options.slotDuration, slatMetas: slatMetas, forPrint: props.forPrint, tableColGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, onSlatCoords: _this.handleSlatCoords, expandRows: contentArg.expandRows, onScrollTopRequest: _this.handleScrollTopRequest }))); }; + return hasDetachedAxis + ? this.renderHScrollLayout(headerContent, allDayContent, timeGridContent, dayTableModel.colCnt, dayMinWidth, slatMetas, this.state.slatCoords) + : this.renderSimpleLayout(headerContent, allDayContent, timeGridContent); + }; + return DayTimeColsView; + }(TimeColsView)); + function buildTimeColsModel(dateProfile, dateProfileGenerator) { + var daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator); + return new DayTableModel(daySeries, false); + } + + var OPTION_REFINERS$4 = { + allDaySlot: Boolean, + }; + + var timeGridPlugin = createPlugin({ + initialView: 'timeGridWeek', + optionRefiners: OPTION_REFINERS$4, + views: { + timeGrid: { + component: DayTimeColsView, + usesMinMaxTime: true, + allDaySlot: true, + slotDuration: '00:30:00', + slotEventOverlap: true, // a bad name. confused with overlap/constraint system + }, + timeGridDay: { + type: 'timeGrid', + duration: { days: 1 }, + }, + timeGridWeek: { + type: 'timeGrid', + duration: { weeks: 1 }, + }, + }, + }); + + var ListViewHeaderRow = /** @class */ (function (_super) { + __extends(ListViewHeaderRow, _super); + function ListViewHeaderRow() { + return _super !== null && _super.apply(this, arguments) || this; + } + ListViewHeaderRow.prototype.render = function () { + var _a = this.props, dayDate = _a.dayDate, todayRange = _a.todayRange; + var _b = this.context, theme = _b.theme, dateEnv = _b.dateEnv, options = _b.options, viewApi = _b.viewApi; + var dayMeta = getDateMeta(dayDate, todayRange); + // will ever be falsy? + var text = options.listDayFormat ? dateEnv.format(dayDate, options.listDayFormat) : ''; + // will ever be falsy? also, BAD NAME "alt" + var sideText = options.listDaySideFormat ? dateEnv.format(dayDate, options.listDaySideFormat) : ''; + var navLinkData = options.navLinks + ? buildNavLinkData(dayDate) + : null; + var hookProps = __assign({ date: dateEnv.toDate(dayDate), view: viewApi, text: text, + sideText: sideText, + navLinkData: navLinkData }, dayMeta); + var classNames = ['fc-list-day'].concat(getDayClassNames(dayMeta, theme)); + // TODO: make a reusable HOC for dayHeader (used in daygrid/timegrid too) + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.dayHeaderClassNames, content: options.dayHeaderContent, defaultContent: renderInnerContent$2, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, function (rootElRef, customClassNames, innerElRef, innerContent) { return (createElement("tr", { ref: rootElRef, className: classNames.concat(customClassNames).join(' '), "data-date": formatDayString(dayDate) }, + createElement("th", { colSpan: 3 }, + createElement("div", { className: 'fc-list-day-cushion ' + theme.getClass('tableCellShaded'), ref: innerElRef }, innerContent)))); })); + }; + return ListViewHeaderRow; + }(BaseComponent)); + function renderInnerContent$2(props) { + var navLinkAttrs = props.navLinkData // is there a type for this? + ? { 'data-navlink': props.navLinkData, tabIndex: 0 } + : {}; + return (createElement(Fragment, null, + props.text && (createElement("a", __assign({ className: "fc-list-day-text" }, navLinkAttrs), props.text)), + props.sideText && (createElement("a", __assign({ className: "fc-list-day-side-text" }, navLinkAttrs), props.sideText)))); + } + + var DEFAULT_TIME_FORMAT$1 = createFormatter({ + hour: 'numeric', + minute: '2-digit', + meridiem: 'short', + }); + var ListViewEventRow = /** @class */ (function (_super) { + __extends(ListViewEventRow, _super); + function ListViewEventRow() { + return _super !== null && _super.apply(this, arguments) || this; + } + ListViewEventRow.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var seg = props.seg; + var timeFormat = context.options.eventTimeFormat || DEFAULT_TIME_FORMAT$1; + return (createElement(EventRoot, { seg: seg, timeText: "" // BAD. because of all-day content + , disableDragging: true, disableResizing: true, defaultContent: renderEventInnerContent, isPast: props.isPast, isFuture: props.isFuture, isToday: props.isToday, isSelected: props.isSelected, isDragging: props.isDragging, isResizing: props.isResizing, isDateSelecting: props.isDateSelecting }, function (rootElRef, classNames, innerElRef, innerContent, hookProps) { return (createElement("tr", { className: ['fc-list-event', hookProps.event.url ? 'fc-event-forced-url' : ''].concat(classNames).join(' '), ref: rootElRef }, + buildTimeContent(seg, timeFormat, context), + createElement("td", { className: "fc-list-event-graphic" }, + createElement("span", { className: "fc-list-event-dot", style: { borderColor: hookProps.borderColor || hookProps.backgroundColor } })), + createElement("td", { className: "fc-list-event-title", ref: innerElRef }, innerContent))); })); + }; + return ListViewEventRow; + }(BaseComponent)); + function renderEventInnerContent(props) { + var event = props.event; + var url = event.url; + var anchorAttrs = url ? { href: url } : {}; + return (createElement("a", __assign({}, anchorAttrs), event.title)); + } + function buildTimeContent(seg, timeFormat, context) { + var options = context.options; + if (options.displayEventTime !== false) { + var eventDef = seg.eventRange.def; + var eventInstance = seg.eventRange.instance; + var doAllDay = false; + var timeText = void 0; + if (eventDef.allDay) { + doAllDay = true; + } + else if (isMultiDayRange(seg.eventRange.range)) { // TODO: use (!isStart || !isEnd) instead? + if (seg.isStart) { + timeText = buildSegTimeText(seg, timeFormat, context, null, null, eventInstance.range.start, seg.end); + } + else if (seg.isEnd) { + timeText = buildSegTimeText(seg, timeFormat, context, null, null, seg.start, eventInstance.range.end); + } + else { + doAllDay = true; + } + } + else { + timeText = buildSegTimeText(seg, timeFormat, context); + } + if (doAllDay) { + var hookProps = { + text: context.options.allDayText, + view: context.viewApi, + }; + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.allDayClassNames, content: options.allDayContent, defaultContent: renderAllDayInner, didMount: options.allDayDidMount, willUnmount: options.allDayWillUnmount }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("td", { className: ['fc-list-event-time'].concat(classNames).join(' '), ref: rootElRef }, innerContent)); })); + } + return (createElement("td", { className: "fc-list-event-time" }, timeText)); + } + return null; + } + function renderAllDayInner(hookProps) { + return hookProps.text; + } + + /* + Responsible for the scroller, and forwarding event-related actions into the "grid". + */ + var ListView = /** @class */ (function (_super) { + __extends(ListView, _super); + function ListView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.computeDateVars = memoize(computeDateVars); + _this.eventStoreToSegs = memoize(_this._eventStoreToSegs); + _this.setRootEl = function (rootEl) { + if (rootEl) { + _this.context.registerInteractiveComponent(_this, { + el: rootEl, + }); + } + else { + _this.context.unregisterInteractiveComponent(_this); + } + }; + return _this; + } + ListView.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var extraClassNames = [ + 'fc-list', + context.theme.getClass('table'), + context.options.stickyHeaderDates !== false ? 'fc-list-sticky' : '', + ]; + var _b = this.computeDateVars(props.dateProfile), dayDates = _b.dayDates, dayRanges = _b.dayRanges; + var eventSegs = this.eventStoreToSegs(props.eventStore, props.eventUiBases, dayRanges); + return (createElement(ViewRoot, { viewSpec: context.viewSpec, elRef: this.setRootEl }, function (rootElRef, classNames) { return (createElement("div", { ref: rootElRef, className: extraClassNames.concat(classNames).join(' ') }, + createElement(Scroller, { liquid: !props.isHeightAuto, overflowX: props.isHeightAuto ? 'visible' : 'hidden', overflowY: props.isHeightAuto ? 'visible' : 'auto' }, eventSegs.length > 0 ? + _this.renderSegList(eventSegs, dayDates) : + _this.renderEmptyMessage()))); })); + }; + ListView.prototype.renderEmptyMessage = function () { + var _a = this.context, options = _a.options, viewApi = _a.viewApi; + var hookProps = { + text: options.noEventsText, + view: viewApi, + }; + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.noEventsClassNames, content: options.noEventsContent, defaultContent: renderNoEventsInner, didMount: options.noEventsDidMount, willUnmount: options.noEventsWillUnmount }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("div", { className: ['fc-list-empty'].concat(classNames).join(' '), ref: rootElRef }, + createElement("div", { className: "fc-list-empty-cushion", ref: innerElRef }, innerContent))); })); + }; + ListView.prototype.renderSegList = function (allSegs, dayDates) { + var _a = this.context, theme = _a.theme, options = _a.options; + var segsByDay = groupSegsByDay(allSegs); // sparse array + return (createElement(NowTimer, { unit: "day" }, function (nowDate, todayRange) { + var innerNodes = []; + for (var dayIndex = 0; dayIndex < segsByDay.length; dayIndex += 1) { + var daySegs = segsByDay[dayIndex]; + if (daySegs) { // sparse array, so might be undefined + var dayStr = dayDates[dayIndex].toISOString(); + // append a day header + innerNodes.push(createElement(ListViewHeaderRow, { key: dayStr, dayDate: dayDates[dayIndex], todayRange: todayRange })); + daySegs = sortEventSegs(daySegs, options.eventOrder); + for (var _i = 0, daySegs_1 = daySegs; _i < daySegs_1.length; _i++) { + var seg = daySegs_1[_i]; + innerNodes.push(createElement(ListViewEventRow, __assign({ key: dayStr + ':' + seg.eventRange.instance.instanceId /* are multiple segs for an instanceId */, seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: false }, getSegMeta(seg, todayRange, nowDate)))); + } + } + } + return (createElement("table", { className: 'fc-list-table ' + theme.getClass('table') }, + createElement("tbody", null, innerNodes))); + })); + }; + ListView.prototype._eventStoreToSegs = function (eventStore, eventUiBases, dayRanges) { + return this.eventRangesToSegs(sliceEventStore(eventStore, eventUiBases, this.props.dateProfile.activeRange, this.context.options.nextDayThreshold).fg, dayRanges); + }; + ListView.prototype.eventRangesToSegs = function (eventRanges, dayRanges) { + var segs = []; + for (var _i = 0, eventRanges_1 = eventRanges; _i < eventRanges_1.length; _i++) { + var eventRange = eventRanges_1[_i]; + segs.push.apply(segs, this.eventRangeToSegs(eventRange, dayRanges)); + } + return segs; + }; + ListView.prototype.eventRangeToSegs = function (eventRange, dayRanges) { + var dateEnv = this.context.dateEnv; + var nextDayThreshold = this.context.options.nextDayThreshold; + var range = eventRange.range; + var allDay = eventRange.def.allDay; + var dayIndex; + var segRange; + var seg; + var segs = []; + for (dayIndex = 0; dayIndex < dayRanges.length; dayIndex += 1) { + segRange = intersectRanges(range, dayRanges[dayIndex]); + if (segRange) { + seg = { + component: this, + eventRange: eventRange, + start: segRange.start, + end: segRange.end, + isStart: eventRange.isStart && segRange.start.valueOf() === range.start.valueOf(), + isEnd: eventRange.isEnd && segRange.end.valueOf() === range.end.valueOf(), + dayIndex: dayIndex, + }; + segs.push(seg); + // detect when range won't go fully into the next day, + // and mutate the latest seg to the be the end. + if (!seg.isEnd && !allDay && + dayIndex + 1 < dayRanges.length && + range.end < + dateEnv.add(dayRanges[dayIndex + 1].start, nextDayThreshold)) { + seg.end = range.end; + seg.isEnd = true; + break; + } + } + } + return segs; + }; + return ListView; + }(DateComponent)); + function renderNoEventsInner(hookProps) { + return hookProps.text; + } + function computeDateVars(dateProfile) { + var dayStart = startOfDay(dateProfile.renderRange.start); + var viewEnd = dateProfile.renderRange.end; + var dayDates = []; + var dayRanges = []; + while (dayStart < viewEnd) { + dayDates.push(dayStart); + dayRanges.push({ + start: dayStart, + end: addDays(dayStart, 1), + }); + dayStart = addDays(dayStart, 1); + } + return { dayDates: dayDates, dayRanges: dayRanges }; + } + // Returns a sparse array of arrays, segs grouped by their dayIndex + function groupSegsByDay(segs) { + var segsByDay = []; // sparse array + var i; + var seg; + for (i = 0; i < segs.length; i += 1) { + seg = segs[i]; + (segsByDay[seg.dayIndex] || (segsByDay[seg.dayIndex] = [])) + .push(seg); + } + return segsByDay; + } + + var OPTION_REFINERS$3 = { + listDayFormat: createFalsableFormatter, + listDaySideFormat: createFalsableFormatter, + noEventsClassNames: identity, + noEventsContent: identity, + noEventsDidMount: identity, + noEventsWillUnmount: identity, + // noEventsText is defined in base options + }; + function createFalsableFormatter(input) { + return input === false ? null : createFormatter(input); + } + + var listPlugin = createPlugin({ + optionRefiners: OPTION_REFINERS$3, + views: { + list: { + component: ListView, + buttonTextKey: 'list', + listDayFormat: { month: 'long', day: 'numeric', year: 'numeric' }, // like "January 1, 2016" + }, + listDay: { + type: 'list', + duration: { days: 1 }, + listDayFormat: { weekday: 'long' }, // day-of-week is all we need. full date is probably in headerToolbar + }, + listWeek: { + type: 'list', + duration: { weeks: 1 }, + listDayFormat: { weekday: 'long' }, + listDaySideFormat: { month: 'long', day: 'numeric', year: 'numeric' }, + }, + listMonth: { + type: 'list', + duration: { month: 1 }, + listDaySideFormat: { weekday: 'long' }, // day-of-week is nice-to-have + }, + listYear: { + type: 'list', + duration: { year: 1 }, + listDaySideFormat: { weekday: 'long' }, // day-of-week is nice-to-have + }, + }, + }); + + var BootstrapTheme = /** @class */ (function (_super) { + __extends(BootstrapTheme, _super); + function BootstrapTheme() { + return _super !== null && _super.apply(this, arguments) || this; + } + return BootstrapTheme; + }(Theme)); + BootstrapTheme.prototype.classes = { + root: 'fc-theme-bootstrap', + table: 'table-bordered', + tableCellShaded: 'table-active', + buttonGroup: 'btn-group', + button: 'btn btn-primary', + buttonActive: 'active', + popover: 'popover', + popoverHeader: 'popover-header', + popoverContent: 'popover-body', + }; + BootstrapTheme.prototype.baseIconClass = 'fa'; + BootstrapTheme.prototype.iconClasses = { + close: 'fa-times', + prev: 'fa-chevron-left', + next: 'fa-chevron-right', + prevYear: 'fa-angle-double-left', + nextYear: 'fa-angle-double-right', + }; + BootstrapTheme.prototype.rtlIconClasses = { + prev: 'fa-chevron-right', + next: 'fa-chevron-left', + prevYear: 'fa-angle-double-right', + nextYear: 'fa-angle-double-left', + }; + BootstrapTheme.prototype.iconOverrideOption = 'bootstrapFontAwesome'; // TODO: make TS-friendly. move the option-processing into this plugin + BootstrapTheme.prototype.iconOverrideCustomButtonOption = 'bootstrapFontAwesome'; + BootstrapTheme.prototype.iconOverridePrefix = 'fa-'; + var plugin = createPlugin({ + themeClasses: { + bootstrap: BootstrapTheme, + }, + }); + + // rename this file to options.ts like other packages? + var OPTION_REFINERS$2 = { + googleCalendarApiKey: String, + }; + + var EVENT_SOURCE_REFINERS = { + googleCalendarApiKey: String, + googleCalendarId: String, + googleCalendarApiBase: String, + extraParams: identity, + }; + + // TODO: expose somehow + var API_BASE = 'https://www.googleapis.com/calendar/v3/calendars'; + var eventSourceDef = { + parseMeta: function (refined) { + var googleCalendarId = refined.googleCalendarId; + if (!googleCalendarId && refined.url) { + googleCalendarId = parseGoogleCalendarId(refined.url); + } + if (googleCalendarId) { + return { + googleCalendarId: googleCalendarId, + googleCalendarApiKey: refined.googleCalendarApiKey, + googleCalendarApiBase: refined.googleCalendarApiBase, + extraParams: refined.extraParams, + }; + } + return null; + }, + fetch: function (arg, onSuccess, onFailure) { + var _a = arg.context, dateEnv = _a.dateEnv, options = _a.options; + var meta = arg.eventSource.meta; + var apiKey = meta.googleCalendarApiKey || options.googleCalendarApiKey; + if (!apiKey) { + onFailure({ + message: 'Specify a googleCalendarApiKey. See http://fullcalendar.io/docs/google_calendar/', + }); + } + else { + var url = buildUrl(meta); + // TODO: make DRY with json-feed-event-source + var extraParams = meta.extraParams; + var extraParamsObj = typeof extraParams === 'function' ? extraParams() : extraParams; + var requestParams_1 = buildRequestParams$1(arg.range, apiKey, extraParamsObj, dateEnv); + requestJson('GET', url, requestParams_1, function (body, xhr) { + if (body.error) { + onFailure({ + message: 'Google Calendar API: ' + body.error.message, + errors: body.error.errors, + xhr: xhr, + }); + } + else { + onSuccess({ + rawEvents: gcalItemsToRawEventDefs(body.items, requestParams_1.timeZone), + xhr: xhr, + }); + } + }, function (message, xhr) { + onFailure({ message: message, xhr: xhr }); + }); + } + }, + }; + function parseGoogleCalendarId(url) { + var match; + // detect if the ID was specified as a single string. + // will match calendars like "asdf1234@calendar.google.com" in addition to person email calendars. + if (/^[^/]+@([^/.]+\.)*(google|googlemail|gmail)\.com$/.test(url)) { + return url; + } + if ((match = /^https:\/\/www.googleapis.com\/calendar\/v3\/calendars\/([^/]*)/.exec(url)) || + (match = /^https?:\/\/www.google.com\/calendar\/feeds\/([^/]*)/.exec(url))) { + return decodeURIComponent(match[1]); + } + return null; + } + function buildUrl(meta) { + var apiBase = meta.googleCalendarApiBase; + if (!apiBase) { + apiBase = API_BASE; + } + return apiBase + '/' + encodeURIComponent(meta.googleCalendarId) + '/events'; + } + function buildRequestParams$1(range, apiKey, extraParams, dateEnv) { + var params; + var startStr; + var endStr; + if (dateEnv.canComputeOffset) { + // strings will naturally have offsets, which GCal needs + startStr = dateEnv.formatIso(range.start); + endStr = dateEnv.formatIso(range.end); + } + else { + // when timezone isn't known, we don't know what the UTC offset should be, so ask for +/- 1 day + // from the UTC day-start to guarantee we're getting all the events + // (start/end will be UTC-coerced dates, so toISOString is okay) + startStr = addDays(range.start, -1).toISOString(); + endStr = addDays(range.end, 1).toISOString(); + } + params = __assign(__assign({}, (extraParams || {})), { key: apiKey, timeMin: startStr, timeMax: endStr, singleEvents: true, maxResults: 9999 }); + if (dateEnv.timeZone !== 'local') { + params.timeZone = dateEnv.timeZone; + } + return params; + } + function gcalItemsToRawEventDefs(items, gcalTimezone) { + return items.map(function (item) { return gcalItemToRawEventDef(item, gcalTimezone); }); + } + function gcalItemToRawEventDef(item, gcalTimezone) { + var url = item.htmlLink || null; + // make the URLs for each event show times in the correct timezone + if (url && gcalTimezone) { + url = injectQsComponent(url, 'ctz=' + gcalTimezone); + } + return { + id: item.id, + title: item.summary, + start: item.start.dateTime || item.start.date, + end: item.end.dateTime || item.end.date, + url: url, + location: item.location, + description: item.description, + attachments: item.attachments || [], + extendedProps: (item.extendedProperties || {}).shared || {}, + }; + } + // Injects a string like "arg=value" into the querystring of a URL + // TODO: move to a general util file? + function injectQsComponent(url, component) { + // inject it after the querystring but before the fragment + return url.replace(/(\?.*?)?(#|$)/, function (whole, qs, hash) { return (qs ? qs + '&' : '?') + component + hash; }); + } + var googleCalendarPlugin = createPlugin({ + eventSourceDefs: [eventSourceDef], + optionRefiners: OPTION_REFINERS$2, + eventSourceRefiners: EVENT_SOURCE_REFINERS, + }); + + var RELEASE_DATE = '2021-06-16'; // for Scheduler + var UPGRADE_WINDOW = 365 + 7; // days. 1 week leeway, for tz shift reasons too + var INVALID_LICENSE_URL = 'http://fullcalendar.io/docs/schedulerLicenseKey#invalid'; + var OUTDATED_LICENSE_URL = 'http://fullcalendar.io/docs/schedulerLicenseKey#outdated'; + var PRESET_LICENSE_KEYS = [ + 'GPL-My-Project-Is-Open-Source', + 'CC-Attribution-NonCommercial-NoDerivatives', + ]; + var CSS = { + position: 'absolute', + zIndex: 99999, + bottom: '1px', + left: '1px', + background: '#eee', + borderColor: '#ddd', + borderStyle: 'solid', + borderWidth: '1px 1px 0 0', + padding: '2px 4px', + fontSize: '12px', + borderTopRightRadius: '3px', + }; + /* + This decryption is not meant to be bulletproof. Just a way to remind about an upgrade. + */ + function processLicenseKey(key) { + if (PRESET_LICENSE_KEYS.indexOf(key) !== -1) { + return 'valid'; + } + var parts = (key || '').match(/^(\d+)-fcs-(\d+)$/); + if (parts && (parts[1].length === 10)) { + var purchaseDate = new Date(parseInt(parts[2], 10) * 1000); + var releaseDate = new Date(config.mockSchedulerReleaseDate || RELEASE_DATE); + if (isValidDate$1(releaseDate)) { // token won't be replaced in dev mode + var minPurchaseDate = addDays(releaseDate, -UPGRADE_WINDOW); + if (minPurchaseDate < purchaseDate) { + return 'valid'; + } + return 'outdated'; + } + } + return 'invalid'; + } + function isImmuneUrl(url) { + return /\w+:\/\/fullcalendar\.io\/|\/examples\/[\w-]+\.html$/.test(url); + } + + var OPTION_REFINERS$1 = { + schedulerLicenseKey: String, + }; + + var premiumCommonPlugin = createPlugin({ + optionRefiners: OPTION_REFINERS$1, + viewContainerAppends: [], + }); + + var WHEEL_EVENT_NAMES = 'wheel mousewheel DomMouseScroll MozMousePixelScroll'.split(' '); + /* + ALSO, with the ability to disable touch + */ + var ScrollListener = /** @class */ (function () { + function ScrollListener(el) { + var _this = this; + this.el = el; + this.emitter = new Emitter(); + this.isScrolling = false; + this.isTouching = false; // user currently has finger down? + this.isRecentlyWheeled = false; + this.isRecentlyScrolled = false; + this.wheelWaiter = new DelayedRunner(this._handleWheelWaited.bind(this)); + this.scrollWaiter = new DelayedRunner(this._handleScrollWaited.bind(this)); + // Handlers + // ---------------------------------------------------------------------------------------------- + this.handleScroll = function () { + _this.startScroll(); + _this.emitter.trigger('scroll', _this.isRecentlyWheeled, _this.isTouching); + _this.isRecentlyScrolled = true; + _this.scrollWaiter.request(500); + }; + // will fire *before* the scroll event is fired (might not cause a scroll) + this.handleWheel = function () { + _this.isRecentlyWheeled = true; + _this.wheelWaiter.request(500); + }; + // will fire *before* the scroll event is fired (might not cause a scroll) + this.handleTouchStart = function () { + _this.isTouching = true; + }; + this.handleTouchEnd = function () { + _this.isTouching = false; + // if the user ended their touch, and the scroll area wasn't moving, + // we consider this to be the end of the scroll. + if (!_this.isRecentlyScrolled) { + _this.endScroll(); // won't fire if already ended + } + }; + el.addEventListener('scroll', this.handleScroll); + el.addEventListener('touchstart', this.handleTouchStart, { passive: true }); + el.addEventListener('touchend', this.handleTouchEnd); + for (var _i = 0, WHEEL_EVENT_NAMES_1 = WHEEL_EVENT_NAMES; _i < WHEEL_EVENT_NAMES_1.length; _i++) { + var eventName = WHEEL_EVENT_NAMES_1[_i]; + el.addEventListener(eventName, this.handleWheel); + } + } + ScrollListener.prototype.destroy = function () { + var el = this.el; + el.removeEventListener('scroll', this.handleScroll); + el.removeEventListener('touchstart', this.handleTouchStart, { passive: true }); + el.removeEventListener('touchend', this.handleTouchEnd); + for (var _i = 0, WHEEL_EVENT_NAMES_2 = WHEEL_EVENT_NAMES; _i < WHEEL_EVENT_NAMES_2.length; _i++) { + var eventName = WHEEL_EVENT_NAMES_2[_i]; + el.removeEventListener(eventName, this.handleWheel); + } + }; + // Start / Stop + // ---------------------------------------------------------------------------------------------- + ScrollListener.prototype.startScroll = function () { + if (!this.isScrolling) { + this.isScrolling = true; + this.emitter.trigger('scrollStart', this.isRecentlyWheeled, this.isTouching); + } + }; + ScrollListener.prototype.endScroll = function () { + if (this.isScrolling) { + this.emitter.trigger('scrollEnd'); + this.isScrolling = false; + this.isRecentlyScrolled = true; + this.isRecentlyWheeled = false; + this.scrollWaiter.clear(); + this.wheelWaiter.clear(); + } + }; + ScrollListener.prototype._handleScrollWaited = function () { + this.isRecentlyScrolled = false; + // only end the scroll if not currently touching. + // if touching, the scrolling will end later, on touchend. + if (!this.isTouching) { + this.endScroll(); // won't fire if already ended + } + }; + ScrollListener.prototype._handleWheelWaited = function () { + this.isRecentlyWheeled = false; + }; + return ScrollListener; + }()); + + // TODO: assume the el has no borders? + function getScrollCanvasOrigin(scrollEl) { + var rect = scrollEl.getBoundingClientRect(); + var edges = computeEdges(scrollEl); // TODO: pass in isRtl? + return { + left: rect.left + edges.borderLeft + edges.scrollbarLeft - getScrollFromLeftEdge(scrollEl), + top: rect.top + edges.borderTop - scrollEl.scrollTop, + }; + } + function getScrollFromLeftEdge(el) { + var scrollLeft = el.scrollLeft; + var computedStyles = window.getComputedStyle(el); // TODO: pass in isRtl instead? + if (computedStyles.direction === 'rtl') { + switch (getRtlScrollSystem()) { + case 'negative': + scrollLeft *= -1; // convert to 'reverse'. fall through... + case 'reverse': // scrollLeft is distance between scrollframe's right edge scrollcanvas's right edge + scrollLeft = el.scrollWidth - scrollLeft - el.clientWidth; + } + } + return scrollLeft; + } + function setScrollFromLeftEdge(el, scrollLeft) { + var computedStyles = window.getComputedStyle(el); // TODO: pass in isRtl instead? + if (computedStyles.direction === 'rtl') { + switch (getRtlScrollSystem()) { + case 'reverse': + scrollLeft = el.scrollWidth - scrollLeft; + break; + case 'negative': + scrollLeft = -(el.scrollWidth - scrollLeft); + break; + } + } + el.scrollLeft = scrollLeft; + } + // Horizontal Scroll System Detection + // ---------------------------------------------------------------------------------------------- + var _rtlScrollSystem; + function getRtlScrollSystem() { + return _rtlScrollSystem || (_rtlScrollSystem = detectRtlScrollSystem()); + } + function detectRtlScrollSystem() { + var el = document.createElement('div'); + el.style.position = 'absolute'; + el.style.top = '-1000px'; + el.style.width = '1px'; + el.style.height = '1px'; + el.style.overflow = 'scroll'; + el.style.direction = 'rtl'; + el.style.fontSize = '100px'; + el.innerHTML = 'A'; + document.body.appendChild(el); + var system; + if (el.scrollLeft > 0) { + system = 'positive'; // scroll is a positive number from the left edge + } + else { + el.scrollLeft = 1; + if (el.scrollLeft > 0) { + system = 'reverse'; // scroll is a positive number from the right edge + } + else { + system = 'negative'; // scroll is a negative number from the right edge + } + } + removeElement(el); + return system; + } + + var IS_MS_EDGE = typeof navigator !== 'undefined' && /Edge/.test(navigator.userAgent); // TODO: what about Chromeum-based Edge? + var STICKY_SELECTOR = '.fc-sticky'; + /* + useful beyond the native position:sticky for these reasons: + - support in IE11 + - nice centering support + + REQUIREMENT: fc-sticky elements, if the fc-sticky className is taken away, should NOT have relative or absolute positioning. + This is because we attach the coords with JS, and the VDOM might take away the fc-sticky class but doesn't know kill the positioning. + + TODO: don't query text-align:center. isn't compatible with flexbox centering. instead, check natural X coord within parent container + */ + var StickyScrolling = /** @class */ (function () { + function StickyScrolling(scrollEl, isRtl) { + var _this = this; + this.scrollEl = scrollEl; + this.isRtl = isRtl; + this.usingRelative = null; + this.updateSize = function () { + var scrollEl = _this.scrollEl; + var els = findElements(scrollEl, STICKY_SELECTOR); + var elGeoms = _this.queryElGeoms(els); + var viewportWidth = scrollEl.clientWidth; + var viewportHeight = scrollEl.clientHeight; + if (_this.usingRelative) { + var elDestinations = _this.computeElDestinations(elGeoms, viewportWidth); // read before prepPositioning + assignRelativePositions(els, elGeoms, elDestinations, viewportWidth, viewportHeight); + } + else { + assignStickyPositions(els, elGeoms, viewportWidth); + } + }; + this.usingRelative = + !computeStickyPropVal() || // IE11 + // https://stackoverflow.com/questions/56835658/in-microsoft-edge-sticky-positioning-doesnt-work-when-combined-with-dir-rtl + (IS_MS_EDGE && isRtl); + if (this.usingRelative) { + this.listener = new ScrollListener(scrollEl); + this.listener.emitter.on('scrollEnd', this.updateSize); + } + } + StickyScrolling.prototype.destroy = function () { + if (this.listener) { + this.listener.destroy(); + } + }; + StickyScrolling.prototype.queryElGeoms = function (els) { + var _a = this, scrollEl = _a.scrollEl, isRtl = _a.isRtl; + var canvasOrigin = getScrollCanvasOrigin(scrollEl); + var elGeoms = []; + for (var _i = 0, els_1 = els; _i < els_1.length; _i++) { + var el = els_1[_i]; + var parentBound = translateRect(computeInnerRect(el.parentNode, true, true), // weird way to call this!!! + -canvasOrigin.left, -canvasOrigin.top); + var elRect = el.getBoundingClientRect(); + var computedStyles = window.getComputedStyle(el); + var textAlign = window.getComputedStyle(el.parentNode).textAlign; // ask the parent + var naturalBound = null; + if (textAlign === 'start') { + textAlign = isRtl ? 'right' : 'left'; + } + else if (textAlign === 'end') { + textAlign = isRtl ? 'left' : 'right'; + } + if (computedStyles.position !== 'sticky') { + naturalBound = translateRect(elRect, -canvasOrigin.left - (parseFloat(computedStyles.left) || 0), // could be 'auto' + -canvasOrigin.top - (parseFloat(computedStyles.top) || 0)); + } + elGeoms.push({ + parentBound: parentBound, + naturalBound: naturalBound, + elWidth: elRect.width, + elHeight: elRect.height, + textAlign: textAlign, + }); + } + return elGeoms; + }; + // only for IE + StickyScrolling.prototype.computeElDestinations = function (elGeoms, viewportWidth) { + var scrollEl = this.scrollEl; + var viewportTop = scrollEl.scrollTop; + var viewportLeft = getScrollFromLeftEdge(scrollEl); + var viewportRight = viewportLeft + viewportWidth; + return elGeoms.map(function (elGeom) { + var elWidth = elGeom.elWidth, elHeight = elGeom.elHeight, parentBound = elGeom.parentBound, naturalBound = elGeom.naturalBound; + var destLeft; // relative to canvas topleft + var destTop; // " + switch (elGeom.textAlign) { + case 'left': + destLeft = viewportLeft; + break; + case 'right': + destLeft = viewportRight - elWidth; + break; + case 'center': + destLeft = (viewportLeft + viewportRight) / 2 - elWidth / 2; /// noooo, use half-width insteadddddddd + break; + } + destLeft = Math.min(destLeft, parentBound.right - elWidth); + destLeft = Math.max(destLeft, parentBound.left); + destTop = viewportTop; + destTop = Math.min(destTop, parentBound.bottom - elHeight); + destTop = Math.max(destTop, naturalBound.top); // better to use natural top for upper bound + return { left: destLeft, top: destTop }; + }); + }; + return StickyScrolling; + }()); + function assignRelativePositions(els, elGeoms, elDestinations, viewportWidth, viewportHeight) { + els.forEach(function (el, i) { + var _a = elGeoms[i], naturalBound = _a.naturalBound, parentBound = _a.parentBound; + var parentWidth = parentBound.right - parentBound.left; + var parentHeight = parentBound.bottom - parentBound.bottom; + var left; + var top; + if (parentWidth > viewportWidth || + parentHeight > viewportHeight) { + left = elDestinations[i].left - naturalBound.left; + top = elDestinations[i].top - naturalBound.top; + } + else { // if parent container can be completely in view, we don't need stickiness + left = ''; + top = ''; + } + applyStyle(el, { + position: 'relative', + left: left, + right: -left, + top: top, + }); + }); + } + function assignStickyPositions(els, elGeoms, viewportWidth) { + els.forEach(function (el, i) { + var _a = elGeoms[i], textAlign = _a.textAlign, elWidth = _a.elWidth, parentBound = _a.parentBound; + var parentWidth = parentBound.right - parentBound.left; + var left; + if (textAlign === 'center' && + parentWidth > viewportWidth) { + left = (viewportWidth - elWidth) / 2; + } + else { // if parent container can be completely in view, we don't need stickiness + left = ''; + } + applyStyle(el, { + left: left, + right: left, + top: 0, + }); + }); + } + // overkill now that we use the stylesheet to set it! + // just test that the 'position' value of a div with the fc-sticky classname has the word 'sticky' in it + function computeStickyPropVal() { + var el = document.createElement('div'); + el.className = 'fc-sticky'; + document.body.appendChild(el); + var val = window.getComputedStyle(el).position; + removeElement(el); + if (val.indexOf('sticky') !== -1) { + return val; + } + return null; + } + + var ClippedScroller = /** @class */ (function (_super) { + __extends(ClippedScroller, _super); + function ClippedScroller() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.elRef = createRef(); + _this.state = { + xScrollbarWidth: 0, + yScrollbarWidth: 0, + }; + _this.handleScroller = function (scroller) { + _this.scroller = scroller; + setRef(_this.props.scrollerRef, scroller); + }; + _this.handleSizing = function () { + var props = _this.props; + if (props.overflowY === 'scroll-hidden') { + _this.setState({ yScrollbarWidth: _this.scroller.getYScrollbarWidth() }); + } + if (props.overflowX === 'scroll-hidden') { + _this.setState({ xScrollbarWidth: _this.scroller.getXScrollbarWidth() }); + } + }; + return _this; + } + ClippedScroller.prototype.render = function () { + var _a = this, props = _a.props, state = _a.state, context = _a.context; + var isScrollbarOnLeft = context.isRtl && getIsRtlScrollbarOnLeft(); + var overcomeLeft = 0; + var overcomeRight = 0; + var overcomeBottom = 0; + if (props.overflowX === 'scroll-hidden') { + overcomeBottom = state.xScrollbarWidth; + } + if (props.overflowY === 'scroll-hidden') { + if (state.yScrollbarWidth != null) { + if (isScrollbarOnLeft) { + overcomeLeft = state.yScrollbarWidth; + } + else { + overcomeRight = state.yScrollbarWidth; + } + } + } + return (createElement("div", { ref: this.elRef, className: 'fc-scroller-harness' + (props.liquid ? ' fc-scroller-harness-liquid' : '') }, + createElement(Scroller, { ref: this.handleScroller, elRef: this.props.scrollerElRef, overflowX: props.overflowX === 'scroll-hidden' ? 'scroll' : props.overflowX, overflowY: props.overflowY === 'scroll-hidden' ? 'scroll' : props.overflowY, overcomeLeft: overcomeLeft, overcomeRight: overcomeRight, overcomeBottom: overcomeBottom, maxHeight: typeof props.maxHeight === 'number' + ? (props.maxHeight + (props.overflowX === 'scroll-hidden' ? state.xScrollbarWidth : 0)) + : '', liquid: props.liquid, liquidIsAbsolute: true }, props.children))); + }; + ClippedScroller.prototype.componentDidMount = function () { + this.handleSizing(); + this.context.addResizeHandler(this.handleSizing); + }; + ClippedScroller.prototype.componentDidUpdate = function (prevProps) { + if (!isPropsEqual(prevProps, this.props)) { // an external change? + this.handleSizing(); + } + }; + ClippedScroller.prototype.componentWillUnmount = function () { + this.context.removeResizeHandler(this.handleSizing); + }; + ClippedScroller.prototype.needsXScrolling = function () { + return this.scroller.needsXScrolling(); + }; + ClippedScroller.prototype.needsYScrolling = function () { + return this.scroller.needsYScrolling(); + }; + return ClippedScroller; + }(BaseComponent)); + + var ScrollSyncer = /** @class */ (function () { + function ScrollSyncer(isVertical, scrollEls) { + var _this = this; + this.isVertical = isVertical; + this.scrollEls = scrollEls; + this.isPaused = false; + this.scrollListeners = scrollEls.map(function (el) { return _this.bindScroller(el); }); + } + ScrollSyncer.prototype.destroy = function () { + for (var _i = 0, _a = this.scrollListeners; _i < _a.length; _i++) { + var scrollListener = _a[_i]; + scrollListener.destroy(); + } + }; + ScrollSyncer.prototype.bindScroller = function (el) { + var _this = this; + var _a = this, scrollEls = _a.scrollEls, isVertical = _a.isVertical; + var scrollListener = new ScrollListener(el); + var onScroll = function (isWheel, isTouch) { + if (!_this.isPaused) { + if (!_this.masterEl || (_this.masterEl !== el && (isWheel || isTouch))) { + _this.assignMaster(el); + } + if (_this.masterEl === el) { // dealing with current + for (var _i = 0, scrollEls_1 = scrollEls; _i < scrollEls_1.length; _i++) { + var otherEl = scrollEls_1[_i]; + if (otherEl !== el) { + if (isVertical) { + otherEl.scrollTop = el.scrollTop; + } + else { + otherEl.scrollLeft = el.scrollLeft; + } + } + } + } + } + }; + var onScrollEnd = function () { + if (_this.masterEl === el) { + _this.masterEl = null; + } + }; + scrollListener.emitter.on('scroll', onScroll); + scrollListener.emitter.on('scrollEnd', onScrollEnd); + return scrollListener; + }; + ScrollSyncer.prototype.assignMaster = function (el) { + this.masterEl = el; + for (var _i = 0, _a = this.scrollListeners; _i < _a.length; _i++) { + var scrollListener = _a[_i]; + if (scrollListener.el !== el) { + scrollListener.endScroll(); // to prevent residual scrolls from reclaiming master + } + } + }; + /* + will normalize the scrollLeft value + */ + ScrollSyncer.prototype.forceScrollLeft = function (scrollLeft) { + this.isPaused = true; + for (var _i = 0, _a = this.scrollListeners; _i < _a.length; _i++) { + var listener = _a[_i]; + setScrollFromLeftEdge(listener.el, scrollLeft); + } + this.isPaused = false; + }; + ScrollSyncer.prototype.forceScrollTop = function (top) { + this.isPaused = true; + for (var _i = 0, _a = this.scrollListeners; _i < _a.length; _i++) { + var listener = _a[_i]; + listener.el.scrollTop = top; + } + this.isPaused = false; + }; + return ScrollSyncer; + }()); + + /* + TODO: make subcomponent + NOTE: doesn't support collapsibleWidth (which is sortof a hack anyway) + */ + var ScrollGrid = /** @class */ (function (_super) { + __extends(ScrollGrid, _super); + function ScrollGrid() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.compileColGroupStats = memoizeArraylike(compileColGroupStat, isColGroupStatsEqual); + _this.renderMicroColGroups = memoizeArraylike(renderMicroColGroup); // yucky to memoize VNodes, but much more efficient for consumers + _this.clippedScrollerRefs = new RefMap(); + // doesn't hold non-scrolling els used just for padding + _this.scrollerElRefs = new RefMap(_this._handleScrollerEl.bind(_this)); + _this.chunkElRefs = new RefMap(_this._handleChunkEl.bind(_this)); + _this.getStickyScrolling = memoizeArraylike(initStickyScrolling, null, destroyStickyScrolling); + _this.getScrollSyncersBySection = memoizeHashlike(initScrollSyncer.bind(_this, true), null, destroyScrollSyncer); + _this.getScrollSyncersByColumn = memoizeHashlike(initScrollSyncer.bind(_this, false), null, destroyScrollSyncer); + _this.stickyScrollings = []; + _this.scrollSyncersBySection = {}; + _this.scrollSyncersByColumn = {}; + // for row-height-syncing + _this.rowUnstableMap = new Map(); // no need to groom. always self-cancels + _this.rowInnerMaxHeightMap = new Map(); + _this.anyRowHeightsChanged = false; + _this.recentSizingCnt = 0; + _this.state = { + shrinkWidths: [], + forceYScrollbars: false, + forceXScrollbars: false, + scrollerClientWidths: {}, + scrollerClientHeights: {}, + sectionRowMaxHeights: [], + }; + _this.handleSizing = function (isForcedResize, sectionRowMaxHeightsChanged) { + if (!_this.allowSizing()) { + return; + } + if (!sectionRowMaxHeightsChanged) { // something else changed, probably external + _this.anyRowHeightsChanged = true; + } + var otherState = {}; + // if reacting to self-change of sectionRowMaxHeightsChanged, or not stable, don't do anything + if (isForcedResize || (!sectionRowMaxHeightsChanged && !_this.rowUnstableMap.size)) { + otherState.sectionRowMaxHeights = _this.computeSectionRowMaxHeights(); + } + _this.setState(__assign(__assign({ shrinkWidths: _this.computeShrinkWidths() }, _this.computeScrollerDims()), otherState), function () { + if (!_this.rowUnstableMap.size) { + _this.updateStickyScrolling(); // needs to happen AFTER final positioning committed to DOM + } + }); + }; + _this.handleRowHeightChange = function (rowEl, isStable) { + var _a = _this, rowUnstableMap = _a.rowUnstableMap, rowInnerMaxHeightMap = _a.rowInnerMaxHeightMap; + if (!isStable) { + rowUnstableMap.set(rowEl, true); + } + else { + rowUnstableMap.delete(rowEl); + var innerMaxHeight = getRowInnerMaxHeight(rowEl); + if (!rowInnerMaxHeightMap.has(rowEl) || rowInnerMaxHeightMap.get(rowEl) !== innerMaxHeight) { + rowInnerMaxHeightMap.set(rowEl, innerMaxHeight); + _this.anyRowHeightsChanged = true; + } + if (!rowUnstableMap.size && _this.anyRowHeightsChanged) { + _this.anyRowHeightsChanged = false; + _this.setState({ + sectionRowMaxHeights: _this.computeSectionRowMaxHeights(), + }); + } + } + }; + return _this; + } + ScrollGrid.prototype.render = function () { + var _a = this, props = _a.props, state = _a.state, context = _a.context; + var shrinkWidths = state.shrinkWidths; + var colGroupStats = this.compileColGroupStats(props.colGroups.map(function (colGroup) { return [colGroup]; })); + var microColGroupNodes = this.renderMicroColGroups(colGroupStats.map(function (stat, i) { return [stat.cols, shrinkWidths[i]]; })); + var classNames = getScrollGridClassNames(props.liquid, context); + var _b = this.getDims(); _b[0]; _b[1]; + // TODO: make DRY + var sectionConfigs = props.sections; + var configCnt = sectionConfigs.length; + var configI = 0; + var currentConfig; + var headSectionNodes = []; + var bodySectionNodes = []; + var footSectionNodes = []; + while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'header') { + headSectionNodes.push(this.renderSection(currentConfig, configI, colGroupStats, microColGroupNodes, state.sectionRowMaxHeights)); + configI += 1; + } + while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'body') { + bodySectionNodes.push(this.renderSection(currentConfig, configI, colGroupStats, microColGroupNodes, state.sectionRowMaxHeights)); + configI += 1; + } + while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'footer') { + footSectionNodes.push(this.renderSection(currentConfig, configI, colGroupStats, microColGroupNodes, state.sectionRowMaxHeights)); + configI += 1; + } + var isBuggy = !getCanVGrowWithinCell(); // see NOTE in SimpleScrollGrid + return createElement('table', { + ref: props.elRef, + className: classNames.join(' '), + }, renderMacroColGroup(colGroupStats, shrinkWidths), Boolean(!isBuggy && headSectionNodes.length) && createElement.apply(void 0, __spreadArray(['thead', {}], headSectionNodes)), Boolean(!isBuggy && bodySectionNodes.length) && createElement.apply(void 0, __spreadArray(['tbody', {}], bodySectionNodes)), Boolean(!isBuggy && footSectionNodes.length) && createElement.apply(void 0, __spreadArray(['tfoot', {}], footSectionNodes)), isBuggy && createElement.apply(void 0, __spreadArray(__spreadArray(__spreadArray(['tbody', {}], headSectionNodes), bodySectionNodes), footSectionNodes))); + }; + ScrollGrid.prototype.renderSection = function (sectionConfig, sectionIndex, colGroupStats, microColGroupNodes, sectionRowMaxHeights) { + var _this = this; + if ('outerContent' in sectionConfig) { + return (createElement(Fragment, { key: sectionConfig.key }, sectionConfig.outerContent)); + } + return (createElement("tr", { key: sectionConfig.key, className: getSectionClassNames(sectionConfig, this.props.liquid).join(' ') }, sectionConfig.chunks.map(function (chunkConfig, i) { return _this.renderChunk(sectionConfig, sectionIndex, colGroupStats[i], microColGroupNodes[i], chunkConfig, i, (sectionRowMaxHeights[sectionIndex] || [])[i] || []); }))); + }; + ScrollGrid.prototype.renderChunk = function (sectionConfig, sectionIndex, colGroupStat, microColGroupNode, chunkConfig, chunkIndex, rowHeights) { + if ('outerContent' in chunkConfig) { + return (createElement(Fragment, { key: chunkConfig.key }, chunkConfig.outerContent)); + } + var state = this.state; + var scrollerClientWidths = state.scrollerClientWidths, scrollerClientHeights = state.scrollerClientHeights; + var _a = this.getDims(), sectionCnt = _a[0], chunksPerSection = _a[1]; + var index = sectionIndex * chunksPerSection + chunkIndex; + var sideScrollIndex = (!this.context.isRtl || getIsRtlScrollbarOnLeft()) ? chunksPerSection - 1 : 0; + var isVScrollSide = chunkIndex === sideScrollIndex; + var isLastSection = sectionIndex === sectionCnt - 1; + var forceXScrollbars = isLastSection && state.forceXScrollbars; // NOOOO can result in `null` + var forceYScrollbars = isVScrollSide && state.forceYScrollbars; // NOOOO can result in `null` + var allowXScrolling = colGroupStat && colGroupStat.allowXScrolling; // rename? + var allowYScrolling = getAllowYScrolling(this.props, sectionConfig); // rename? do in section func? + var chunkVGrow = getSectionHasLiquidHeight(this.props, sectionConfig); // do in section func? + var expandRows = sectionConfig.expandRows && chunkVGrow; + var tableMinWidth = (colGroupStat && colGroupStat.totalColMinWidth) || ''; + var content = renderChunkContent(sectionConfig, chunkConfig, { + tableColGroupNode: microColGroupNode, + tableMinWidth: tableMinWidth, + clientWidth: scrollerClientWidths[index] !== undefined ? scrollerClientWidths[index] : null, + clientHeight: scrollerClientHeights[index] !== undefined ? scrollerClientHeights[index] : null, + expandRows: expandRows, + syncRowHeights: Boolean(sectionConfig.syncRowHeights), + rowSyncHeights: rowHeights, + reportRowHeightChange: this.handleRowHeightChange, + }); + var overflowX = forceXScrollbars ? (isLastSection ? 'auto' : 'scroll-hidden') : + !allowXScrolling ? 'hidden' : + (isLastSection ? 'auto' : 'scroll-hidden'); + var overflowY = forceYScrollbars ? (isVScrollSide ? 'auto' : 'scroll-hidden') : + !allowYScrolling ? 'hidden' : + (isVScrollSide ? 'auto' : 'scroll-hidden'); + // it *could* be possible to reduce DOM wrappers by only doing a ClippedScroller when allowXScrolling or allowYScrolling, + // but if these values were to change, the inner components would be unmounted/remounted because of the parent change. + content = (createElement(ClippedScroller, { ref: this.clippedScrollerRefs.createRef(index), scrollerElRef: this.scrollerElRefs.createRef(index), overflowX: overflowX, overflowY: overflowY, liquid: chunkVGrow, maxHeight: sectionConfig.maxHeight }, content)); + return (createElement("td", { key: chunkConfig.key, ref: this.chunkElRefs.createRef(index) }, content)); + }; + ScrollGrid.prototype.componentDidMount = function () { + this.updateScrollSyncers(); + this.handleSizing(false); + this.context.addResizeHandler(this.handleSizing); + }; + ScrollGrid.prototype.componentDidUpdate = function (prevProps, prevState) { + this.updateScrollSyncers(); + // TODO: need better solution when state contains non-sizing things + this.handleSizing(false, prevState.sectionRowMaxHeights !== this.state.sectionRowMaxHeights); + }; + ScrollGrid.prototype.componentWillUnmount = function () { + this.context.removeResizeHandler(this.handleSizing); + this.destroyStickyScrolling(); + this.destroyScrollSyncers(); + }; + ScrollGrid.prototype.allowSizing = function () { + var now = new Date(); + if (!this.lastSizingDate || + now.valueOf() > this.lastSizingDate.valueOf() + config.SCROLLGRID_RESIZE_INTERVAL) { + this.lastSizingDate = now; + this.recentSizingCnt = 0; + return true; + } + return (this.recentSizingCnt += 1) <= 10; + }; + ScrollGrid.prototype.computeShrinkWidths = function () { + var _this = this; + var colGroupStats = this.compileColGroupStats(this.props.colGroups.map(function (colGroup) { return [colGroup]; })); + var _a = this.getDims(), sectionCnt = _a[0], chunksPerSection = _a[1]; + var cnt = sectionCnt * chunksPerSection; + var shrinkWidths = []; + colGroupStats.forEach(function (colGroupStat, i) { + if (colGroupStat.hasShrinkCol) { + var chunkEls = _this.chunkElRefs.collect(i, cnt, chunksPerSection); // in one col + shrinkWidths[i] = computeShrinkWidth(chunkEls); + } + }); + return shrinkWidths; + }; + // has the side effect of grooming rowInnerMaxHeightMap + // TODO: somehow short-circuit if there are no new height changes + ScrollGrid.prototype.computeSectionRowMaxHeights = function () { + var newHeightMap = new Map(); + var _a = this.getDims(), sectionCnt = _a[0], chunksPerSection = _a[1]; + var sectionRowMaxHeights = []; + for (var sectionI = 0; sectionI < sectionCnt; sectionI += 1) { + var sectionConfig = this.props.sections[sectionI]; + var assignableHeights = []; // chunk, row + if (sectionConfig && sectionConfig.syncRowHeights) { + var rowHeightsByChunk = []; + for (var chunkI = 0; chunkI < chunksPerSection; chunkI += 1) { + var index = sectionI * chunksPerSection + chunkI; + var rowHeights = []; + var chunkEl = this.chunkElRefs.currentMap[index]; + if (chunkEl) { + rowHeights = findElements(chunkEl, '.fc-scrollgrid-sync-table tr').map(function (rowEl) { + var max = getRowInnerMaxHeight(rowEl); + newHeightMap.set(rowEl, max); + return max; + }); + } + else { + rowHeights = []; + } + rowHeightsByChunk.push(rowHeights); + } + var rowCnt = rowHeightsByChunk[0].length; + var isEqualRowCnt = true; + for (var chunkI = 1; chunkI < chunksPerSection; chunkI += 1) { + var isOuterContent = sectionConfig.chunks[chunkI] && sectionConfig.chunks[chunkI].outerContent !== undefined; // can be null + if (!isOuterContent && rowHeightsByChunk[chunkI].length !== rowCnt) { // skip outer content + isEqualRowCnt = false; + break; + } + } + if (!isEqualRowCnt) { + var chunkHeightSums = []; + for (var chunkI = 0; chunkI < chunksPerSection; chunkI += 1) { + chunkHeightSums.push(sumNumbers(rowHeightsByChunk[chunkI]) + rowHeightsByChunk[chunkI].length); + } + var maxTotalSum = Math.max.apply(Math, chunkHeightSums); + for (var chunkI = 0; chunkI < chunksPerSection; chunkI += 1) { + var rowInChunkCnt = rowHeightsByChunk[chunkI].length; + var rowInChunkTotalHeight = maxTotalSum - rowInChunkCnt; // subtract border + // height of non-first row. we do this to avoid rounding, because it's unreliable within a table + var rowInChunkHeightOthers = Math.floor(rowInChunkTotalHeight / rowInChunkCnt); + // whatever is leftover goes to the first row + var rowInChunkHeightFirst = rowInChunkTotalHeight - rowInChunkHeightOthers * (rowInChunkCnt - 1); + var rowInChunkHeights = []; + var row = 0; + if (row < rowInChunkCnt) { + rowInChunkHeights.push(rowInChunkHeightFirst); + row += 1; + } + while (row < rowInChunkCnt) { + rowInChunkHeights.push(rowInChunkHeightOthers); + row += 1; + } + assignableHeights.push(rowInChunkHeights); + } + } + else { + for (var chunkI = 0; chunkI < chunksPerSection; chunkI += 1) { + assignableHeights.push([]); + } + for (var row = 0; row < rowCnt; row += 1) { + var rowHeightsAcrossChunks = []; + for (var chunkI = 0; chunkI < chunksPerSection; chunkI += 1) { + var h = rowHeightsByChunk[chunkI][row]; + if (h != null) { // protect against outerContent + rowHeightsAcrossChunks.push(h); + } + } + var maxHeight = Math.max.apply(Math, rowHeightsAcrossChunks); + for (var chunkI = 0; chunkI < chunksPerSection; chunkI += 1) { + assignableHeights[chunkI].push(maxHeight); + } + } + } + } + sectionRowMaxHeights.push(assignableHeights); + } + this.rowInnerMaxHeightMap = newHeightMap; + return sectionRowMaxHeights; + }; + ScrollGrid.prototype.computeScrollerDims = function () { + var scrollbarWidth = getScrollbarWidths(); + var _a = this.getDims(), sectionCnt = _a[0], chunksPerSection = _a[1]; + var sideScrollI = (!this.context.isRtl || getIsRtlScrollbarOnLeft()) ? chunksPerSection - 1 : 0; + var lastSectionI = sectionCnt - 1; + var currentScrollers = this.clippedScrollerRefs.currentMap; + var scrollerEls = this.scrollerElRefs.currentMap; + var forceYScrollbars = false; + var forceXScrollbars = false; + var scrollerClientWidths = {}; + var scrollerClientHeights = {}; + for (var sectionI = 0; sectionI < sectionCnt; sectionI += 1) { // along edge + var index = sectionI * chunksPerSection + sideScrollI; + var scroller = currentScrollers[index]; + if (scroller && scroller.needsYScrolling()) { + forceYScrollbars = true; + break; + } + } + for (var chunkI = 0; chunkI < chunksPerSection; chunkI += 1) { // along last row + var index = lastSectionI * chunksPerSection + chunkI; + var scroller = currentScrollers[index]; + if (scroller && scroller.needsXScrolling()) { + forceXScrollbars = true; + break; + } + } + for (var sectionI = 0; sectionI < sectionCnt; sectionI += 1) { + for (var chunkI = 0; chunkI < chunksPerSection; chunkI += 1) { + var index = sectionI * chunksPerSection + chunkI; + var scrollerEl = scrollerEls[index]; + if (scrollerEl) { + // TODO: weird way to get this. need harness b/c doesn't include table borders + var harnessEl = scrollerEl.parentNode; + scrollerClientWidths[index] = Math.floor(harnessEl.getBoundingClientRect().width - ((chunkI === sideScrollI && forceYScrollbars) + ? scrollbarWidth.y // use global because scroller might not have scrollbars yet but will need them in future + : 0)); + scrollerClientHeights[index] = Math.floor(harnessEl.getBoundingClientRect().height - ((sectionI === lastSectionI && forceXScrollbars) + ? scrollbarWidth.x // use global because scroller might not have scrollbars yet but will need them in future + : 0)); + } + } + } + return { forceYScrollbars: forceYScrollbars, forceXScrollbars: forceXScrollbars, scrollerClientWidths: scrollerClientWidths, scrollerClientHeights: scrollerClientHeights }; + }; + ScrollGrid.prototype.updateStickyScrolling = function () { + var isRtl = this.context.isRtl; + var argsByKey = this.scrollerElRefs.getAll().map(function (scrollEl) { return [scrollEl, isRtl]; }); + var stickyScrollings = this.getStickyScrolling(argsByKey); + stickyScrollings.forEach(function (stickyScrolling) { return stickyScrolling.updateSize(); }); + this.stickyScrollings = stickyScrollings; + }; + ScrollGrid.prototype.destroyStickyScrolling = function () { + this.stickyScrollings.forEach(destroyStickyScrolling); + }; + ScrollGrid.prototype.updateScrollSyncers = function () { + var _a = this.getDims(), sectionCnt = _a[0], chunksPerSection = _a[1]; + var cnt = sectionCnt * chunksPerSection; + var scrollElsBySection = {}; + var scrollElsByColumn = {}; + var scrollElMap = this.scrollerElRefs.currentMap; + for (var sectionI = 0; sectionI < sectionCnt; sectionI += 1) { + var startIndex = sectionI * chunksPerSection; + var endIndex = startIndex + chunksPerSection; + scrollElsBySection[sectionI] = collectFromHash(scrollElMap, startIndex, endIndex, 1); // use the filtered + } + for (var col = 0; col < chunksPerSection; col += 1) { + scrollElsByColumn[col] = this.scrollerElRefs.collect(col, cnt, chunksPerSection); // DON'T use the filtered + } + this.scrollSyncersBySection = this.getScrollSyncersBySection(scrollElsBySection); + this.scrollSyncersByColumn = this.getScrollSyncersByColumn(scrollElsByColumn); + }; + ScrollGrid.prototype.destroyScrollSyncers = function () { + mapHash(this.scrollSyncersBySection, destroyScrollSyncer); + mapHash(this.scrollSyncersByColumn, destroyScrollSyncer); + }; + ScrollGrid.prototype.getChunkConfigByIndex = function (index) { + var chunksPerSection = this.getDims()[1]; + var sectionI = Math.floor(index / chunksPerSection); + var chunkI = index % chunksPerSection; + var sectionConfig = this.props.sections[sectionI]; + return sectionConfig && sectionConfig.chunks[chunkI]; + }; + ScrollGrid.prototype.forceScrollLeft = function (col, scrollLeft) { + var scrollSyncer = this.scrollSyncersByColumn[col]; + if (scrollSyncer) { + scrollSyncer.forceScrollLeft(scrollLeft); + } + }; + ScrollGrid.prototype.forceScrollTop = function (sectionI, scrollTop) { + var scrollSyncer = this.scrollSyncersBySection[sectionI]; + if (scrollSyncer) { + scrollSyncer.forceScrollTop(scrollTop); + } + }; + ScrollGrid.prototype._handleChunkEl = function (chunkEl, key) { + var chunkConfig = this.getChunkConfigByIndex(parseInt(key, 10)); + if (chunkConfig) { // null if section disappeared. bad, b/c won't null-set the elRef + setRef(chunkConfig.elRef, chunkEl); + } + }; + ScrollGrid.prototype._handleScrollerEl = function (scrollerEl, key) { + var chunkConfig = this.getChunkConfigByIndex(parseInt(key, 10)); + if (chunkConfig) { // null if section disappeared. bad, b/c won't null-set the elRef + setRef(chunkConfig.scrollerElRef, scrollerEl); + } + }; + ScrollGrid.prototype.getDims = function () { + var sectionCnt = this.props.sections.length; + var chunksPerSection = sectionCnt ? this.props.sections[0].chunks.length : 0; + return [sectionCnt, chunksPerSection]; + }; + return ScrollGrid; + }(BaseComponent)); + ScrollGrid.addStateEquality({ + shrinkWidths: isArraysEqual, + scrollerClientWidths: isPropsEqual, + scrollerClientHeights: isPropsEqual, + }); + function sumNumbers(numbers) { + var sum = 0; + for (var _i = 0, numbers_1 = numbers; _i < numbers_1.length; _i++) { + var n = numbers_1[_i]; + sum += n; + } + return sum; + } + function getRowInnerMaxHeight(rowEl) { + var innerHeights = findElements(rowEl, '.fc-scrollgrid-sync-inner').map(getElHeight); + if (innerHeights.length) { + return Math.max.apply(Math, innerHeights); + } + return 0; + } + function getElHeight(el) { + return el.offsetHeight; // better to deal with integers, for rounding, for PureComponent + } + function renderMacroColGroup(colGroupStats, shrinkWidths) { + var children = colGroupStats.map(function (colGroupStat, i) { + var width = colGroupStat.width; + if (width === 'shrink') { + width = colGroupStat.totalColWidth + sanitizeShrinkWidth(shrinkWidths[i]) + 1; // +1 for border :( + } + return ( // eslint-disable-next-line react/jsx-key + createElement("col", { style: { width: width } })); + }); + return createElement.apply(void 0, __spreadArray(['colgroup', {}], children)); + } + function compileColGroupStat(colGroupConfig) { + var totalColWidth = sumColProp(colGroupConfig.cols, 'width'); // excludes "shrink" + var totalColMinWidth = sumColProp(colGroupConfig.cols, 'minWidth'); + var hasShrinkCol = hasShrinkWidth(colGroupConfig.cols); + var allowXScrolling = colGroupConfig.width !== 'shrink' && Boolean(totalColWidth || totalColMinWidth || hasShrinkCol); + return { + hasShrinkCol: hasShrinkCol, + totalColWidth: totalColWidth, + totalColMinWidth: totalColMinWidth, + allowXScrolling: allowXScrolling, + cols: colGroupConfig.cols, + width: colGroupConfig.width, + }; + } + function sumColProp(cols, propName) { + var total = 0; + for (var _i = 0, cols_1 = cols; _i < cols_1.length; _i++) { + var col = cols_1[_i]; + var val = col[propName]; + if (typeof val === 'number') { + total += val * (col.span || 1); + } + } + return total; + } + var COL_GROUP_STAT_EQUALITY = { + cols: isColPropsEqual, + }; + function isColGroupStatsEqual(stat0, stat1) { + return compareObjs(stat0, stat1, COL_GROUP_STAT_EQUALITY); + } + // for memoizers... + function initScrollSyncer(isVertical) { + var scrollEls = []; + for (var _i = 1; _i < arguments.length; _i++) { + scrollEls[_i - 1] = arguments[_i]; + } + return new ScrollSyncer(isVertical, scrollEls); + } + function destroyScrollSyncer(scrollSyncer) { + scrollSyncer.destroy(); + } + function initStickyScrolling(scrollEl, isRtl) { + return new StickyScrolling(scrollEl, isRtl); + } + function destroyStickyScrolling(stickyScrolling) { + stickyScrolling.destroy(); + } + + var scrollGridPlugin = createPlugin({ + deps: [ + premiumCommonPlugin, + ], + scrollGridImpl: ScrollGrid, + }); + config.SCROLLGRID_RESIZE_INTERVAL = 500; + + config.COLLAPSIBLE_WIDTH_THRESHOLD = 1200; + var contexts = []; + var undoFuncs = []; + var adaptivePlugin = createPlugin({ + deps: [ + premiumCommonPlugin, + ], + contextInit: function (context) { + if (!contexts.length) { + attachGlobalHandlers(); + } + contexts.push(context); + context.calendarApi.on('_unmount', function () { + removeExact(contexts, context); + if (!contexts.length) { + removeGlobalHandlers(); + } + }); + }, + }); + function attachGlobalHandlers() { + window.addEventListener('beforeprint', handleBeforePrint); + window.addEventListener('afterprint', handleAfterPrint); + // // for testing + // let forPrint = false + // document.addEventListener('keypress', (ev) => { + // if (ev.key === 'p') { + // forPrint = !forPrint + // if (forPrint) { + // handleBeforePrint() + // } else { + // handleAfterPrint() + // } + // } + // }) + } + function removeGlobalHandlers() { + window.removeEventListener('beforeprint', handleBeforePrint); + window.removeEventListener('afterprint', handleAfterPrint); + } + function handleBeforePrint() { + var scrollEls = queryScrollerEls(); + var scrollCoords = queryScrollerCoords(scrollEls); + for (var _i = 0, contexts_1 = contexts; _i < contexts_1.length; _i++) { + var context = contexts_1[_i]; + context.emitter.trigger('_beforeprint'); + } + flushToDom(); // because printing grabs DOM immediately after + killHorizontalScrolling(scrollEls, scrollCoords); + undoFuncs.push(function () { return restoreScrollerCoords(scrollEls, scrollCoords); }); + undoFuncs.push(freezeScrollgridWidths()); + } + function handleAfterPrint() { + for (var _i = 0, contexts_2 = contexts; _i < contexts_2.length; _i++) { + var context = contexts_2[_i]; + context.emitter.trigger('_afterprint'); + } + flushToDom(); // guarantee that there are real scrollers + while (undoFuncs.length) { + undoFuncs.shift()(); + } + } + // scrollgrid widths + function freezeScrollgridWidths() { + var els = findElements(document.body, '.fc-scrollgrid'); + els.forEach(freezeScrollGridWidth); + return function () { return els.forEach(unfreezeScrollGridWidth); }; + } + function freezeScrollGridWidth(el) { + var elWidth = el.getBoundingClientRect().width; + // along with collapsibleWidth, this is a hack for #5707 + if (!el.classList.contains('fc-scrollgrid-collapsible') || elWidth < config.COLLAPSIBLE_WIDTH_THRESHOLD) { + el.style.width = elWidth + 'px'; + } + } + function unfreezeScrollGridWidth(el) { + el.style.width = ''; + } + // scrollers + // TODO: use scroll normalization!? yes + function queryScrollerEls() { + return findElements(document.body, '.fc-scroller-harness > .fc-scroller'); + } + function queryScrollerCoords(els) { + return els.map(function (el) { + var computedStyle = window.getComputedStyle(el); + return { + scrollLeft: el.scrollLeft, + scrollTop: el.scrollTop, + overflowX: computedStyle.overflowX, + overflowY: computedStyle.overflowY, + marginBottom: computedStyle.marginBottom, + }; + }); + } + function killHorizontalScrolling(els, coords) { + els.forEach(function (el, i) { + el.style.overflowX = 'visible'; // need to clear X/Y to get true overflow + el.style.overflowY = 'visible'; // " + el.style.marginBottom = ''; // for clipping away scrollbar. disable + el.style.left = -coords[i].scrollLeft + 'px'; // simulate scrollLeft! will be position:relative + }); + } + function restoreScrollerCoords(els, coords) { + els.forEach(function (el, i) { + var c = coords[i]; + el.style.overflowX = c.overflowX; + el.style.overflowY = c.overflowY; + el.style.marginBottom = c.marginBottom; + el.style.left = ''; + el.scrollLeft = c.scrollLeft; + el.scrollTop = c.scrollTop; + }); + } + + var MIN_AUTO_LABELS = 18; // more than `12` months but less that `24` hours + var MAX_AUTO_SLOTS_PER_LABEL = 6; // allows 6 10-min slots in an hour + var MAX_AUTO_CELLS = 200; // allows 4-days to have a :30 slot duration + config.MAX_TIMELINE_SLOTS = 1000; + // potential nice values for slot-duration and interval-duration + var STOCK_SUB_DURATIONS = [ + { years: 1 }, + { months: 1 }, + { days: 1 }, + { hours: 1 }, + { minutes: 30 }, + { minutes: 15 }, + { minutes: 10 }, + { minutes: 5 }, + { minutes: 1 }, + { seconds: 30 }, + { seconds: 15 }, + { seconds: 10 }, + { seconds: 5 }, + { seconds: 1 }, + { milliseconds: 500 }, + { milliseconds: 100 }, + { milliseconds: 10 }, + { milliseconds: 1 }, + ]; + function buildTimelineDateProfile(dateProfile, dateEnv, allOptions, dateProfileGenerator) { + var tDateProfile = { + labelInterval: allOptions.slotLabelInterval, + slotDuration: allOptions.slotDuration, + }; + validateLabelAndSlot(tDateProfile, dateProfile, dateEnv); // validate after computed grid duration + ensureLabelInterval(tDateProfile, dateProfile, dateEnv); + ensureSlotDuration(tDateProfile, dateProfile, dateEnv); + var input = allOptions.slotLabelFormat; + var rawFormats = Array.isArray(input) ? input : + (input != null) ? [input] : + computeHeaderFormats(tDateProfile, dateProfile, dateEnv, allOptions); + tDateProfile.headerFormats = rawFormats.map(function (rawFormat) { return createFormatter(rawFormat); }); + tDateProfile.isTimeScale = Boolean(tDateProfile.slotDuration.milliseconds); + var largeUnit = null; + if (!tDateProfile.isTimeScale) { + var slotUnit = greatestDurationDenominator(tDateProfile.slotDuration).unit; + if (/year|month|week/.test(slotUnit)) { + largeUnit = slotUnit; + } + } + tDateProfile.largeUnit = largeUnit; + tDateProfile.emphasizeWeeks = + asCleanDays(tDateProfile.slotDuration) === 1 && + currentRangeAs('weeks', dateProfile, dateEnv) >= 2 && + !allOptions.businessHours; + /* + console.log('label interval =', timelineView.labelInterval.humanize()) + console.log('slot duration =', timelineView.slotDuration.humanize()) + console.log('header formats =', timelineView.headerFormats) + console.log('isTimeScale', timelineView.isTimeScale) + console.log('largeUnit', timelineView.largeUnit) + */ + var rawSnapDuration = allOptions.snapDuration; + var snapDuration; + var snapsPerSlot; + if (rawSnapDuration) { + snapDuration = createDuration(rawSnapDuration); + snapsPerSlot = wholeDivideDurations(tDateProfile.slotDuration, snapDuration); + // ^ TODO: warning if not whole? + } + if (snapsPerSlot == null) { + snapDuration = tDateProfile.slotDuration; + snapsPerSlot = 1; + } + tDateProfile.snapDuration = snapDuration; + tDateProfile.snapsPerSlot = snapsPerSlot; + // more... + var timeWindowMs = asRoughMs(dateProfile.slotMaxTime) - asRoughMs(dateProfile.slotMinTime); + // TODO: why not use normalizeRange!? + var normalizedStart = normalizeDate(dateProfile.renderRange.start, tDateProfile, dateEnv); + var normalizedEnd = normalizeDate(dateProfile.renderRange.end, tDateProfile, dateEnv); + // apply slotMinTime/slotMaxTime + // TODO: View should be responsible. + if (tDateProfile.isTimeScale) { + normalizedStart = dateEnv.add(normalizedStart, dateProfile.slotMinTime); + normalizedEnd = dateEnv.add(addDays(normalizedEnd, -1), dateProfile.slotMaxTime); + } + tDateProfile.timeWindowMs = timeWindowMs; + tDateProfile.normalizedRange = { start: normalizedStart, end: normalizedEnd }; + var slotDates = []; + var date = normalizedStart; + while (date < normalizedEnd) { + if (isValidDate(date, tDateProfile, dateProfile, dateProfileGenerator)) { + slotDates.push(date); + } + date = dateEnv.add(date, tDateProfile.slotDuration); + } + tDateProfile.slotDates = slotDates; + // more... + var snapIndex = -1; + var snapDiff = 0; // index of the diff :( + var snapDiffToIndex = []; + var snapIndexToDiff = []; + date = normalizedStart; + while (date < normalizedEnd) { + if (isValidDate(date, tDateProfile, dateProfile, dateProfileGenerator)) { + snapIndex += 1; + snapDiffToIndex.push(snapIndex); + snapIndexToDiff.push(snapDiff); + } + else { + snapDiffToIndex.push(snapIndex + 0.5); + } + date = dateEnv.add(date, tDateProfile.snapDuration); + snapDiff += 1; + } + tDateProfile.snapDiffToIndex = snapDiffToIndex; + tDateProfile.snapIndexToDiff = snapIndexToDiff; + tDateProfile.snapCnt = snapIndex + 1; // is always one behind + tDateProfile.slotCnt = tDateProfile.snapCnt / tDateProfile.snapsPerSlot; + // more... + tDateProfile.isWeekStarts = buildIsWeekStarts(tDateProfile, dateEnv); + tDateProfile.cellRows = buildCellRows(tDateProfile, dateEnv); + tDateProfile.slotsPerLabel = wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration); + return tDateProfile; + } + /* + snaps to appropriate unit + */ + function normalizeDate(date, tDateProfile, dateEnv) { + var normalDate = date; + if (!tDateProfile.isTimeScale) { + normalDate = startOfDay(normalDate); + if (tDateProfile.largeUnit) { + normalDate = dateEnv.startOf(normalDate, tDateProfile.largeUnit); + } + } + return normalDate; + } + /* + snaps to appropriate unit + */ + function normalizeRange(range, tDateProfile, dateEnv) { + if (!tDateProfile.isTimeScale) { + range = computeVisibleDayRange(range); + if (tDateProfile.largeUnit) { + var dayRange = range; // preserve original result + range = { + start: dateEnv.startOf(range.start, tDateProfile.largeUnit), + end: dateEnv.startOf(range.end, tDateProfile.largeUnit), + }; + // if date is partially through the interval, or is in the same interval as the start, + // make the exclusive end be the *next* interval + if (range.end.valueOf() !== dayRange.end.valueOf() || range.end <= range.start) { + range = { + start: range.start, + end: dateEnv.add(range.end, tDateProfile.slotDuration), + }; + } + } + } + return range; + } + function isValidDate(date, tDateProfile, dateProfile, dateProfileGenerator) { + if (dateProfileGenerator.isHiddenDay(date)) { + return false; + } + if (tDateProfile.isTimeScale) { + // determine if the time is within slotMinTime/slotMaxTime, which may have wacky values + var day = startOfDay(date); + var timeMs = date.valueOf() - day.valueOf(); + var ms = timeMs - asRoughMs(dateProfile.slotMinTime); // milliseconds since slotMinTime + ms = ((ms % 86400000) + 86400000) % 86400000; // make negative values wrap to 24hr clock + return ms < tDateProfile.timeWindowMs; // before the slotMaxTime? + } + return true; + } + function validateLabelAndSlot(tDateProfile, dateProfile, dateEnv) { + var currentRange = dateProfile.currentRange; + // make sure labelInterval doesn't exceed the max number of cells + if (tDateProfile.labelInterval) { + var labelCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, tDateProfile.labelInterval); + if (labelCnt > config.MAX_TIMELINE_SLOTS) { + console.warn('slotLabelInterval results in too many cells'); + tDateProfile.labelInterval = null; + } + } + // make sure slotDuration doesn't exceed the maximum number of cells + if (tDateProfile.slotDuration) { + var slotCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, tDateProfile.slotDuration); + if (slotCnt > config.MAX_TIMELINE_SLOTS) { + console.warn('slotDuration results in too many cells'); + tDateProfile.slotDuration = null; + } + } + // make sure labelInterval is a multiple of slotDuration + if (tDateProfile.labelInterval && tDateProfile.slotDuration) { + var slotsPerLabel = wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration); + if (slotsPerLabel === null || slotsPerLabel < 1) { + console.warn('slotLabelInterval must be a multiple of slotDuration'); + tDateProfile.slotDuration = null; + } + } + } + function ensureLabelInterval(tDateProfile, dateProfile, dateEnv) { + var currentRange = dateProfile.currentRange; + var labelInterval = tDateProfile.labelInterval; + if (!labelInterval) { + // compute based off the slot duration + // find the largest label interval with an acceptable slots-per-label + var input = void 0; + if (tDateProfile.slotDuration) { + for (var _i = 0, STOCK_SUB_DURATIONS_1 = STOCK_SUB_DURATIONS; _i < STOCK_SUB_DURATIONS_1.length; _i++) { + input = STOCK_SUB_DURATIONS_1[_i]; + var tryLabelInterval = createDuration(input); + var slotsPerLabel = wholeDivideDurations(tryLabelInterval, tDateProfile.slotDuration); + if (slotsPerLabel !== null && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) { + labelInterval = tryLabelInterval; + break; + } + } + // use the slot duration as a last resort + if (!labelInterval) { + labelInterval = tDateProfile.slotDuration; + } + // compute based off the view's duration + // find the largest label interval that yields the minimum number of labels + } + else { + for (var _a = 0, STOCK_SUB_DURATIONS_2 = STOCK_SUB_DURATIONS; _a < STOCK_SUB_DURATIONS_2.length; _a++) { + input = STOCK_SUB_DURATIONS_2[_a]; + labelInterval = createDuration(input); + var labelCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, labelInterval); + if (labelCnt >= MIN_AUTO_LABELS) { + break; + } + } + } + tDateProfile.labelInterval = labelInterval; + } + return labelInterval; + } + function ensureSlotDuration(tDateProfile, dateProfile, dateEnv) { + var currentRange = dateProfile.currentRange; + var slotDuration = tDateProfile.slotDuration; + if (!slotDuration) { + var labelInterval = ensureLabelInterval(tDateProfile, dateProfile, dateEnv); // will compute if necessary + // compute based off the label interval + // find the largest slot duration that is different from labelInterval, but still acceptable + for (var _i = 0, STOCK_SUB_DURATIONS_3 = STOCK_SUB_DURATIONS; _i < STOCK_SUB_DURATIONS_3.length; _i++) { + var input = STOCK_SUB_DURATIONS_3[_i]; + var trySlotDuration = createDuration(input); + var slotsPerLabel = wholeDivideDurations(labelInterval, trySlotDuration); + if (slotsPerLabel !== null && slotsPerLabel > 1 && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) { + slotDuration = trySlotDuration; + break; + } + } + // only allow the value if it won't exceed the view's # of slots limit + if (slotDuration) { + var slotCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, slotDuration); + if (slotCnt > MAX_AUTO_CELLS) { + slotDuration = null; + } + } + // use the label interval as a last resort + if (!slotDuration) { + slotDuration = labelInterval; + } + tDateProfile.slotDuration = slotDuration; + } + return slotDuration; + } + function computeHeaderFormats(tDateProfile, dateProfile, dateEnv, allOptions) { + var format1; + var format2; + var labelInterval = tDateProfile.labelInterval; + var unit = greatestDurationDenominator(labelInterval).unit; + var weekNumbersVisible = allOptions.weekNumbers; + var format0 = (format1 = (format2 = null)); + // NOTE: weekNumber computation function wont work + if ((unit === 'week') && !weekNumbersVisible) { + unit = 'day'; + } + switch (unit) { + case 'year': + format0 = { year: 'numeric' }; // '2015' + break; + case 'month': + if (currentRangeAs('years', dateProfile, dateEnv) > 1) { + format0 = { year: 'numeric' }; // '2015' + } + format1 = { month: 'short' }; // 'Jan' + break; + case 'week': + if (currentRangeAs('years', dateProfile, dateEnv) > 1) { + format0 = { year: 'numeric' }; // '2015' + } + format1 = { week: 'narrow' }; // 'Wk4' + break; + case 'day': + if (currentRangeAs('years', dateProfile, dateEnv) > 1) { + format0 = { year: 'numeric', month: 'long' }; // 'January 2014' + } + else if (currentRangeAs('months', dateProfile, dateEnv) > 1) { + format0 = { month: 'long' }; // 'January' + } + if (weekNumbersVisible) { + format1 = { week: 'short' }; // 'Wk 4' + } + format2 = { weekday: 'narrow', day: 'numeric' }; // 'Su 9' + break; + case 'hour': + if (weekNumbersVisible) { + format0 = { week: 'short' }; // 'Wk 4' + } + if (currentRangeAs('days', dateProfile, dateEnv) > 1) { + format1 = { weekday: 'short', day: 'numeric', month: 'numeric', omitCommas: true }; // Sat 4/7 + } + format2 = { + hour: 'numeric', + minute: '2-digit', + omitZeroMinute: true, + meridiem: 'short', + }; + break; + case 'minute': + // sufficiently large number of different minute cells? + if ((asRoughMinutes(labelInterval) / 60) >= MAX_AUTO_SLOTS_PER_LABEL) { + format0 = { + hour: 'numeric', + meridiem: 'short', + }; + format1 = function (params) { return (':' + padStart(params.date.minute, 2) // ':30' + ); }; + } + else { + format0 = { + hour: 'numeric', + minute: 'numeric', + meridiem: 'short', + }; + } + break; + case 'second': + // sufficiently large number of different second cells? + if ((asRoughSeconds(labelInterval) / 60) >= MAX_AUTO_SLOTS_PER_LABEL) { + format0 = { hour: 'numeric', minute: '2-digit', meridiem: 'lowercase' }; // '8:30 PM' + format1 = function (params) { return (':' + padStart(params.date.second, 2) // ':30' + ); }; + } + else { + format0 = { hour: 'numeric', minute: '2-digit', second: '2-digit', meridiem: 'lowercase' }; // '8:30:45 PM' + } + break; + case 'millisecond': + format0 = { hour: 'numeric', minute: '2-digit', second: '2-digit', meridiem: 'lowercase' }; // '8:30:45 PM' + format1 = function (params) { return ('.' + padStart(params.millisecond, 3)); }; + break; + } + return [].concat(format0 || [], format1 || [], format2 || []); + } + // Compute the number of the give units in the "current" range. + // Won't go more precise than days. + // Will return `0` if there's not a clean whole interval. + function currentRangeAs(unit, dateProfile, dateEnv) { + var range = dateProfile.currentRange; + var res = null; + if (unit === 'years') { + res = dateEnv.diffWholeYears(range.start, range.end); + } + else if (unit === 'months') { + res = dateEnv.diffWholeMonths(range.start, range.end); + } + else if (unit === 'weeks') { + res = dateEnv.diffWholeMonths(range.start, range.end); + } + else if (unit === 'days') { + res = diffWholeDays(range.start, range.end); + } + return res || 0; + } + function buildIsWeekStarts(tDateProfile, dateEnv) { + var slotDates = tDateProfile.slotDates, emphasizeWeeks = tDateProfile.emphasizeWeeks; + var prevWeekNumber = null; + var isWeekStarts = []; + for (var _i = 0, slotDates_1 = slotDates; _i < slotDates_1.length; _i++) { + var slotDate = slotDates_1[_i]; + var weekNumber = dateEnv.computeWeekNumber(slotDate); + var isWeekStart = emphasizeWeeks && (prevWeekNumber !== null) && (prevWeekNumber !== weekNumber); + prevWeekNumber = weekNumber; + isWeekStarts.push(isWeekStart); + } + return isWeekStarts; + } + function buildCellRows(tDateProfile, dateEnv) { + var slotDates = tDateProfile.slotDates; + var formats = tDateProfile.headerFormats; + var cellRows = formats.map(function () { return []; }); // indexed by row,col + var slotAsDays = asCleanDays(tDateProfile.slotDuration); + var guessedSlotUnit = slotAsDays === 7 ? 'week' : + slotAsDays === 1 ? 'day' : + null; + // specifically for navclicks + var rowUnitsFromFormats = formats.map(function (format) { return (format.getLargestUnit ? format.getLargestUnit() : null); }); + // builds cellRows and slotCells + for (var i = 0; i < slotDates.length; i += 1) { + var date = slotDates[i]; + var isWeekStart = tDateProfile.isWeekStarts[i]; + for (var row = 0; row < formats.length; row += 1) { + var format = formats[row]; + var rowCells = cellRows[row]; + var leadingCell = rowCells[rowCells.length - 1]; + var isLastRow = row === formats.length - 1; + var isSuperRow = formats.length > 1 && !isLastRow; // more than one row and not the last + var newCell = null; + var rowUnit = rowUnitsFromFormats[row] || (isLastRow ? guessedSlotUnit : null); + if (isSuperRow) { + var text = dateEnv.format(date, format); + if (!leadingCell || (leadingCell.text !== text)) { + newCell = buildCellObject(date, text, rowUnit); + } + else { + leadingCell.colspan += 1; + } + } + else if (!leadingCell || + isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.labelInterval))) { + var text = dateEnv.format(date, format); + newCell = buildCellObject(date, text, rowUnit); + } + else { + leadingCell.colspan += 1; + } + if (newCell) { + newCell.weekStart = isWeekStart; + rowCells.push(newCell); + } + } + } + return cellRows; + } + function buildCellObject(date, text, rowUnit) { + return { date: date, text: text, rowUnit: rowUnit, colspan: 1, isWeekStart: false }; + } + + var TimelineHeaderThInner = /** @class */ (function (_super) { + __extends(TimelineHeaderThInner, _super); + function TimelineHeaderThInner() { + return _super !== null && _super.apply(this, arguments) || this; + } + TimelineHeaderThInner.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var navLinkAttrs = props.navLinkData + ? { 'data-navlink': props.navLinkData, tabIndex: 0 } + : {}; + return (createElement(ContentHook, { hookProps: props.hookProps, content: context.options.slotLabelContent, defaultContent: renderInnerContent$1 }, function (innerElRef, innerContent) { return (createElement("a", __assign({ ref: innerElRef, className: 'fc-timeline-slot-cushion fc-scrollgrid-sync-inner' + (props.isSticky ? ' fc-sticky' : '') }, navLinkAttrs), innerContent)); })); + }; + return TimelineHeaderThInner; + }(BaseComponent)); + function renderInnerContent$1(props) { + return props.text; + } + function refineHookProps$2(input) { + return { + level: input.level, + date: input.dateEnv.toDate(input.dateMarker), + view: input.viewApi, + text: input.text, + }; + } + + var TimelineHeaderTh = /** @class */ (function (_super) { + __extends(TimelineHeaderTh, _super); + function TimelineHeaderTh() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.refineHookProps = memoizeObjArg(refineHookProps$2); + _this.normalizeClassNames = buildClassNameNormalizer(); + return _this; + } + TimelineHeaderTh.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var dateEnv = context.dateEnv, options = context.options; + var cell = props.cell, dateProfile = props.dateProfile, tDateProfile = props.tDateProfile; + // the cell.rowUnit is f'd + // giving 'month' for a 3-day view + // workaround: to infer day, do NOT time + var dateMeta = getDateMeta(cell.date, props.todayRange, props.nowDate, dateProfile); + var classNames = ['fc-timeline-slot', 'fc-timeline-slot-label'].concat(cell.rowUnit === 'time' // TODO: so slot classnames for week/month/bigger. see note above about rowUnit + ? getSlotClassNames(dateMeta, context.theme) + : getDayClassNames(dateMeta, context.theme)); + if (cell.isWeekStart) { + classNames.push('fc-timeline-slot-em'); + } + var navLinkData = (options.navLinks && cell.rowUnit && cell.rowUnit !== 'time') + ? buildNavLinkData(cell.date, cell.rowUnit) + : null; + var hookProps = this.refineHookProps({ + level: props.rowLevel, + dateMarker: cell.date, + text: cell.text, + dateEnv: context.dateEnv, + viewApi: context.viewApi, + }); + var customClassNames = this.normalizeClassNames(options.slotLabelClassNames, hookProps); + return (createElement(MountHook, { hookProps: hookProps, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, function (rootElRef) { return (createElement("th", { ref: rootElRef, className: classNames.concat(customClassNames).join(' '), "data-date": dateEnv.formatIso(cell.date, { omitTime: !tDateProfile.isTimeScale, omitTimeZoneOffset: true }), colSpan: cell.colspan }, + createElement("div", { className: "fc-timeline-slot-frame", style: { height: props.rowInnerHeight } }, + createElement(TimelineHeaderThInner, { hookProps: hookProps, isSticky: props.isSticky, navLinkData: navLinkData })))); })); + }; + return TimelineHeaderTh; + }(BaseComponent)); + + var TimelineHeaderRows = /** @class */ (function (_super) { + __extends(TimelineHeaderRows, _super); + function TimelineHeaderRows() { + return _super !== null && _super.apply(this, arguments) || this; + } + TimelineHeaderRows.prototype.render = function () { + var _a = this.props, dateProfile = _a.dateProfile, tDateProfile = _a.tDateProfile, rowInnerHeights = _a.rowInnerHeights, todayRange = _a.todayRange, nowDate = _a.nowDate; + var cellRows = tDateProfile.cellRows; + return (createElement(Fragment, null, cellRows.map(function (rowCells, rowLevel) { + var isLast = rowLevel === cellRows.length - 1; + var isChrono = tDateProfile.isTimeScale && isLast; // the final row, with times? + var classNames = [ + 'fc-timeline-header-row', + isChrono ? 'fc-timeline-header-row-chrono' : '', + ]; + return ( // eslint-disable-next-line react/no-array-index-key + createElement("tr", { key: rowLevel, className: classNames.join(' ') }, rowCells.map(function (cell) { return (createElement(TimelineHeaderTh, { key: cell.date.toISOString(), cell: cell, rowLevel: rowLevel, dateProfile: dateProfile, tDateProfile: tDateProfile, todayRange: todayRange, nowDate: nowDate, rowInnerHeight: rowInnerHeights && rowInnerHeights[rowLevel], isSticky: !isLast })); }))); + }))); + }; + return TimelineHeaderRows; + }(BaseComponent)); + + var TimelineCoords = /** @class */ (function () { + function TimelineCoords(slatRootEl, // okay to expose? + slatEls, dateProfile, tDateProfile, dateEnv, isRtl) { + this.slatRootEl = slatRootEl; + this.dateProfile = dateProfile; + this.tDateProfile = tDateProfile; + this.dateEnv = dateEnv; + this.isRtl = isRtl; + this.outerCoordCache = new PositionCache(slatRootEl, slatEls, true, // isHorizontal + false); + // for the inner divs within the slats + // used for event rendering and scrollTime, to disregard slat border + this.innerCoordCache = new PositionCache(slatRootEl, findDirectChildren(slatEls, 'div'), true, // isHorizontal + false); + } + TimelineCoords.prototype.isDateInRange = function (date) { + return rangeContainsMarker(this.dateProfile.currentRange, date); + }; + // results range from negative width of area to 0 + TimelineCoords.prototype.dateToCoord = function (date) { + var tDateProfile = this.tDateProfile; + var snapCoverage = this.computeDateSnapCoverage(date); + var slotCoverage = snapCoverage / tDateProfile.snapsPerSlot; + var slotIndex = Math.floor(slotCoverage); + slotIndex = Math.min(slotIndex, tDateProfile.slotCnt - 1); + var partial = slotCoverage - slotIndex; + var _a = this, innerCoordCache = _a.innerCoordCache, outerCoordCache = _a.outerCoordCache; + if (this.isRtl) { + return outerCoordCache.originClientRect.width - (outerCoordCache.rights[slotIndex] - + (innerCoordCache.getWidth(slotIndex) * partial)); + } + return (outerCoordCache.lefts[slotIndex] + + (innerCoordCache.getWidth(slotIndex) * partial)); + }; + TimelineCoords.prototype.rangeToCoords = function (range) { + return { + start: this.dateToCoord(range.start), + end: this.dateToCoord(range.end), + }; + }; + TimelineCoords.prototype.durationToCoord = function (duration) { + var _a = this, dateProfile = _a.dateProfile, tDateProfile = _a.tDateProfile, dateEnv = _a.dateEnv, isRtl = _a.isRtl; + var coord = 0; + if (dateProfile) { + var date = dateEnv.add(dateProfile.activeRange.start, duration); + if (!tDateProfile.isTimeScale) { + date = startOfDay(date); + } + coord = this.dateToCoord(date); + // hack to overcome the left borders of non-first slat + if (!isRtl && coord) { + coord += 1; + } + } + return coord; + }; + TimelineCoords.prototype.coordFromLeft = function (coord) { + if (this.isRtl) { + return this.outerCoordCache.originClientRect.width - coord; + } + return coord; + }; + // returned value is between 0 and the number of snaps + TimelineCoords.prototype.computeDateSnapCoverage = function (date) { + return computeDateSnapCoverage(date, this.tDateProfile, this.dateEnv); + }; + return TimelineCoords; + }()); + // returned value is between 0 and the number of snaps + function computeDateSnapCoverage(date, tDateProfile, dateEnv) { + var snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration); + if (snapDiff < 0) { + return 0; + } + if (snapDiff >= tDateProfile.snapDiffToIndex.length) { + return tDateProfile.snapCnt; + } + var snapDiffInt = Math.floor(snapDiff); + var snapCoverage = tDateProfile.snapDiffToIndex[snapDiffInt]; + if (isInt(snapCoverage)) { // not an in-between value + snapCoverage += snapDiff - snapDiffInt; // add the remainder + } + else { + // a fractional value, meaning the date is not visible + // always round up in this case. works for start AND end dates in a range. + snapCoverage = Math.ceil(snapCoverage); + } + return snapCoverage; + } + function coordToCss(hcoord, isRtl) { + if (hcoord === null) { + return { left: '', right: '' }; + } + if (isRtl) { + return { right: hcoord, left: '' }; + } + return { left: hcoord, right: '' }; + } + function coordsToCss(hcoords, isRtl) { + if (!hcoords) { + return { left: '', right: '' }; + } + if (isRtl) { + return { right: hcoords.start, left: -hcoords.end }; + } + return { left: hcoords.start, right: -hcoords.end }; + } + + var TimelineHeader = /** @class */ (function (_super) { + __extends(TimelineHeader, _super); + function TimelineHeader() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.rootElRef = createRef(); + return _this; + } + TimelineHeader.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + // TODO: very repetitive + // TODO: make part of tDateProfile? + var timerUnit = greatestDurationDenominator(props.tDateProfile.slotDuration).unit; + // WORKAROUND: make ignore slatCoords when out of sync with dateProfile + var slatCoords = props.slatCoords && props.slatCoords.dateProfile === props.dateProfile ? props.slatCoords : null; + return (createElement(NowTimer, { unit: timerUnit }, function (nowDate, todayRange) { return (createElement("div", { className: "fc-timeline-header", ref: _this.rootElRef }, + createElement("table", { className: "fc-scrollgrid-sync-table", style: { minWidth: props.tableMinWidth, width: props.clientWidth } }, + props.tableColGroupNode, + createElement("tbody", null, + createElement(TimelineHeaderRows, { dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, nowDate: nowDate, todayRange: todayRange, rowInnerHeights: props.rowInnerHeights }))), + context.options.nowIndicator && ( + // need to have a container regardless of whether the current view has a visible now indicator + // because apparently removal of the element resets the scroll for some reasons (issue #5351). + // this issue doesn't happen for the timeline body however ( + createElement("div", { className: "fc-timeline-now-indicator-container" }, (slatCoords && slatCoords.isDateInRange(nowDate)) && (createElement(NowIndicatorRoot, { isAxis: true, date: nowDate }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("div", { ref: rootElRef, className: ['fc-timeline-now-indicator-arrow'].concat(classNames).join(' '), style: coordToCss(slatCoords.dateToCoord(nowDate), context.isRtl) }, innerContent)); })))))); })); + }; + TimelineHeader.prototype.componentDidMount = function () { + this.updateSize(); + }; + TimelineHeader.prototype.componentDidUpdate = function () { + this.updateSize(); + }; + TimelineHeader.prototype.updateSize = function () { + if (this.props.onMaxCushionWidth) { + this.props.onMaxCushionWidth(this.computeMaxCushionWidth()); + } + }; + TimelineHeader.prototype.computeMaxCushionWidth = function () { + return Math.max.apply(Math, findElements(this.rootElRef.current, '.fc-timeline-header-row:last-child .fc-timeline-slot-cushion').map(function (el) { return el.getBoundingClientRect().width; })); + }; + return TimelineHeader; + }(BaseComponent)); + + var TimelineSlatCell = /** @class */ (function (_super) { + __extends(TimelineSlatCell, _super); + function TimelineSlatCell() { + return _super !== null && _super.apply(this, arguments) || this; + } + TimelineSlatCell.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var dateEnv = context.dateEnv, options = context.options, theme = context.theme; + var date = props.date, tDateProfile = props.tDateProfile, isEm = props.isEm; + var dateMeta = getDateMeta(props.date, props.todayRange, props.nowDate, props.dateProfile); + var classNames = ['fc-timeline-slot', 'fc-timeline-slot-lane']; + var dataAttrs = { 'data-date': dateEnv.formatIso(date, { omitTimeZoneOffset: true, omitTime: !tDateProfile.isTimeScale }) }; + var hookProps = __assign(__assign({ date: dateEnv.toDate(props.date) }, dateMeta), { view: context.viewApi }); + if (isEm) { + classNames.push('fc-timeline-slot-em'); + } + if (tDateProfile.isTimeScale) { + classNames.push(isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, props.date, tDateProfile.labelInterval)) ? + 'fc-timeline-slot-major' : + 'fc-timeline-slot-minor'); + } + classNames.push.apply(classNames, (props.isDay + ? getDayClassNames(dateMeta, theme) + : getSlotClassNames(dateMeta, theme))); + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.slotLaneClassNames, content: options.slotLaneContent, didMount: options.slotLaneDidMount, willUnmount: options.slotLaneWillUnmount, elRef: props.elRef }, function (rootElRef, customClassNames, innerElRef, innerContent) { return (createElement("td", __assign({ ref: rootElRef, className: classNames.concat(customClassNames).join(' ') }, dataAttrs), + createElement("div", { ref: innerElRef }, innerContent))); })); + }; + return TimelineSlatCell; + }(BaseComponent)); + + var TimelineSlatsBody = /** @class */ (function (_super) { + __extends(TimelineSlatsBody, _super); + function TimelineSlatsBody() { + return _super !== null && _super.apply(this, arguments) || this; + } + TimelineSlatsBody.prototype.render = function () { + var props = this.props; + var tDateProfile = props.tDateProfile, cellElRefs = props.cellElRefs; + var slotDates = tDateProfile.slotDates, isWeekStarts = tDateProfile.isWeekStarts; + var isDay = !tDateProfile.isTimeScale && !tDateProfile.largeUnit; + return (createElement("tbody", null, + createElement("tr", null, slotDates.map(function (slotDate, i) { + var key = slotDate.toISOString(); + return (createElement(TimelineSlatCell, { key: key, elRef: cellElRefs.createRef(key), date: slotDate, dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: props.nowDate, todayRange: props.todayRange, isEm: isWeekStarts[i], isDay: isDay })); + })))); + }; + return TimelineSlatsBody; + }(BaseComponent)); + + var TimelineSlats = /** @class */ (function (_super) { + __extends(TimelineSlats, _super); + function TimelineSlats() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.rootElRef = createRef(); + _this.cellElRefs = new RefMap(); + _this.handleScrollRequest = function (request) { + var onScrollLeftRequest = _this.props.onScrollLeftRequest; + var coords = _this.coords; + if (onScrollLeftRequest && coords) { + if (request.time) { + var scrollLeft = coords.coordFromLeft(coords.durationToCoord(request.time)); + onScrollLeftRequest(scrollLeft); + } + return true; + } + return null; // best? + }; + return _this; + } + TimelineSlats.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + return (createElement("div", { className: "fc-timeline-slots", ref: this.rootElRef }, + createElement("table", { className: context.theme.getClass('table'), style: { + minWidth: props.tableMinWidth, + width: props.clientWidth, + } }, + props.tableColGroupNode, + createElement(TimelineSlatsBody, { cellElRefs: this.cellElRefs, dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, nowDate: props.nowDate, todayRange: props.todayRange })))); + }; + TimelineSlats.prototype.componentDidMount = function () { + this.updateSizing(); + this.scrollResponder = this.context.createScrollResponder(this.handleScrollRequest); + }; + TimelineSlats.prototype.componentDidUpdate = function (prevProps) { + this.updateSizing(); + this.scrollResponder.update(prevProps.dateProfile !== this.props.dateProfile); + }; + TimelineSlats.prototype.componentWillUnmount = function () { + this.scrollResponder.detach(); + if (this.props.onCoords) { + this.props.onCoords(null); + } + }; + TimelineSlats.prototype.updateSizing = function () { + var _a = this, props = _a.props, context = _a.context; + if (props.clientWidth !== null && // is sizing stable? + this.scrollResponder + // ^it's possible to have clientWidth immediately after mount (when returning from print view), but w/o scrollResponder + ) { + var rootEl = this.rootElRef.current; + if (rootEl.offsetWidth) { // not hidden by css + this.coords = new TimelineCoords(this.rootElRef.current, collectCellEls(this.cellElRefs.currentMap, props.tDateProfile.slotDates), props.dateProfile, props.tDateProfile, context.dateEnv, context.isRtl); + if (props.onCoords) { + props.onCoords(this.coords); + } + this.scrollResponder.update(false); // TODO: wouldn't have to do this if coords were in state + } + } + }; + TimelineSlats.prototype.positionToHit = function (leftPosition) { + var outerCoordCache = this.coords.outerCoordCache; + var _a = this.context, dateEnv = _a.dateEnv, isRtl = _a.isRtl; + var tDateProfile = this.props.tDateProfile; + var slatIndex = outerCoordCache.leftToIndex(leftPosition); + if (slatIndex != null) { + // somewhat similar to what TimeGrid does. consolidate? + var slatWidth = outerCoordCache.getWidth(slatIndex); + var partial = isRtl ? + (outerCoordCache.rights[slatIndex] - leftPosition) / slatWidth : + (leftPosition - outerCoordCache.lefts[slatIndex]) / slatWidth; + var localSnapIndex = Math.floor(partial * tDateProfile.snapsPerSlot); + var start = dateEnv.add(tDateProfile.slotDates[slatIndex], multiplyDuration(tDateProfile.snapDuration, localSnapIndex)); + var end = dateEnv.add(start, tDateProfile.snapDuration); + return { + dateSpan: { + range: { start: start, end: end }, + allDay: !this.props.tDateProfile.isTimeScale, + }, + dayEl: this.cellElRefs.currentMap[slatIndex], + left: outerCoordCache.lefts[slatIndex], + right: outerCoordCache.rights[slatIndex], + }; + } + return null; + }; + return TimelineSlats; + }(BaseComponent)); + function collectCellEls(elMap, slotDates) { + return slotDates.map(function (slotDate) { + var key = slotDate.toISOString(); + return elMap[key]; + }); + } + + function computeSegHCoords(segs, minWidth, timelineCoords) { + var hcoords = []; + if (timelineCoords) { + for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { + var seg = segs_1[_i]; + var res = timelineCoords.rangeToCoords(seg); + var start = Math.round(res.start); // for barely-overlapping collisions + var end = Math.round(res.end); // + if (end - start < minWidth) { + end = start + minWidth; + } + hcoords.push({ start: start, end: end }); + } + } + return hcoords; + } + function computeFgSegPlacements(segs, segHCoords, // might not have for every seg + eventInstanceHeights, // might not have for every seg + moreLinkHeights, // might not have for every more-link + strictOrder, maxStackCnt) { + var segInputs = []; + var crudePlacements = []; // when we don't know dims + for (var i = 0; i < segs.length; i += 1) { + var seg = segs[i]; + var instanceId = seg.eventRange.instance.instanceId; + var height = eventInstanceHeights[instanceId]; + var hcoords = segHCoords[i]; + if (height && hcoords) { + segInputs.push({ + index: i, + span: hcoords, + thickness: height, + }); + } + else { + crudePlacements.push({ + seg: seg, + hcoords: hcoords, + top: null, + }); + } + } + var hierarchy = new SegHierarchy(); + if (strictOrder != null) { + hierarchy.strictOrder = strictOrder; + } + if (maxStackCnt != null) { + hierarchy.maxStackCnt = maxStackCnt; + } + var hiddenEntries = hierarchy.addSegs(segInputs); + var hiddenPlacements = hiddenEntries.map(function (entry) { return ({ + seg: segs[entry.index], + hcoords: entry.span, + top: 0, + }); }); + var hiddenGroups = groupIntersectingEntries(hiddenEntries); + var moreLinkInputs = []; + var moreLinkCrudePlacements = []; + var extractSeg = function (entry) { return segs[entry.index]; }; + for (var i = 0; i < hiddenGroups.length; i += 1) { + var hiddenGroup = hiddenGroups[i]; + var sortedSegs = hiddenGroup.entries.map(extractSeg); + var height = moreLinkHeights[buildIsoString(computeEarliestSegStart(sortedSegs))]; // not optimal :( + if (height != null) { + // NOTE: the hiddenGroup's spanStart/spanEnd are already computed by rangeToCoords. computed during input. + moreLinkInputs.push({ + index: segs.length + i, + thickness: height, + span: hiddenGroup.span, + }); + } + else { + moreLinkCrudePlacements.push({ + seg: sortedSegs, + hcoords: hiddenGroup.span, + top: null, + }); + } + } + // add more-links into the hierarchy, but don't limit + hierarchy.maxStackCnt = -1; + hierarchy.addSegs(moreLinkInputs); + var visibleRects = hierarchy.toRects(); + var visiblePlacements = []; + var maxHeight = 0; + for (var _i = 0, visibleRects_1 = visibleRects; _i < visibleRects_1.length; _i++) { + var rect = visibleRects_1[_i]; + var segIndex = rect.index; + visiblePlacements.push({ + seg: segIndex < segs.length + ? segs[segIndex] // a real seg + : hiddenGroups[segIndex - segs.length].entries.map(extractSeg), + hcoords: rect.span, + top: rect.levelCoord, + }); + maxHeight = Math.max(maxHeight, rect.levelCoord + rect.thickness); + } + return [ + visiblePlacements.concat(crudePlacements, hiddenPlacements, moreLinkCrudePlacements), + maxHeight, + ]; + } + + var TimelineLaneBg = /** @class */ (function (_super) { + __extends(TimelineLaneBg, _super); + function TimelineLaneBg() { + return _super !== null && _super.apply(this, arguments) || this; + } + TimelineLaneBg.prototype.render = function () { + var props = this.props; + var highlightSeg = [].concat(props.eventResizeSegs, props.dateSelectionSegs); + return props.timelineCoords && (createElement("div", { className: "fc-timeline-bg" }, + this.renderSegs(props.businessHourSegs || [], props.timelineCoords, 'non-business'), + this.renderSegs(props.bgEventSegs || [], props.timelineCoords, 'bg-event'), + this.renderSegs(highlightSeg, props.timelineCoords, 'highlight'))); + }; + TimelineLaneBg.prototype.renderSegs = function (segs, timelineCoords, fillType) { + var _a = this.props, todayRange = _a.todayRange, nowDate = _a.nowDate; + var isRtl = this.context.isRtl; + var segHCoords = computeSegHCoords(segs, 0, timelineCoords); + var children = segs.map(function (seg, i) { + var hcoords = segHCoords[i]; + var hStyle = coordsToCss(hcoords, isRtl); + return (createElement("div", { key: buildEventRangeKey(seg.eventRange), className: "fc-timeline-bg-harness", style: hStyle }, fillType === 'bg-event' ? + createElement(BgEvent, __assign({ seg: seg }, getSegMeta(seg, todayRange, nowDate))) : + renderFill(fillType))); + }); + return createElement(Fragment, null, children); + }; + return TimelineLaneBg; + }(BaseComponent)); + + var TimelineLaneSlicer = /** @class */ (function (_super) { + __extends(TimelineLaneSlicer, _super); + function TimelineLaneSlicer() { + return _super !== null && _super.apply(this, arguments) || this; + } + TimelineLaneSlicer.prototype.sliceRange = function (origRange, dateProfile, dateProfileGenerator, tDateProfile, dateEnv) { + var normalRange = normalizeRange(origRange, tDateProfile, dateEnv); + var segs = []; + // protect against when the span is entirely in an invalid date region + if (computeDateSnapCoverage(normalRange.start, tDateProfile, dateEnv) + < computeDateSnapCoverage(normalRange.end, tDateProfile, dateEnv)) { + // intersect the footprint's range with the grid's range + var slicedRange = intersectRanges(normalRange, tDateProfile.normalizedRange); + if (slicedRange) { + segs.push({ + start: slicedRange.start, + end: slicedRange.end, + isStart: slicedRange.start.valueOf() === normalRange.start.valueOf() + && isValidDate(slicedRange.start, tDateProfile, dateProfile, dateProfileGenerator), + isEnd: slicedRange.end.valueOf() === normalRange.end.valueOf() + && isValidDate(addMs(slicedRange.end, -1), tDateProfile, dateProfile, dateProfileGenerator), + }); + } + } + return segs; + }; + return TimelineLaneSlicer; + }(Slicer)); + + var DEFAULT_TIME_FORMAT = createFormatter({ + hour: 'numeric', + minute: '2-digit', + omitZeroMinute: true, + meridiem: 'narrow', + }); + var TimelineEvent = /** @class */ (function (_super) { + __extends(TimelineEvent, _super); + function TimelineEvent() { + return _super !== null && _super.apply(this, arguments) || this; + } + TimelineEvent.prototype.render = function () { + var props = this.props; + return (createElement(StandardEvent, __assign({}, props, { extraClassNames: ['fc-timeline-event', 'fc-h-event'], defaultTimeFormat: DEFAULT_TIME_FORMAT, defaultDisplayEventTime: !props.isTimeScale }))); + }; + return TimelineEvent; + }(BaseComponent)); + + var TimelineLaneMoreLink = /** @class */ (function (_super) { + __extends(TimelineLaneMoreLink, _super); + function TimelineLaneMoreLink() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.rootElRef = createRef(); + return _this; + } + TimelineLaneMoreLink.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var hiddenSegs = props.hiddenSegs, elRef = props.elRef, placement = props.placement, resourceId = props.resourceId; + var top = placement.top, hcoords = placement.hcoords; + var isVisible = hcoords && top !== null; + var hStyle = coordsToCss(hcoords, context.isRtl); + var extraDateSpan = resourceId ? { resourceId: resourceId } : {}; + return (createElement(MoreLinkRoot, { allDayDate: null, moreCnt: hiddenSegs.length, allSegs: hiddenSegs, hiddenSegs: hiddenSegs, alignmentElRef: this.rootElRef, dateProfile: props.dateProfile, todayRange: props.todayRange, extraDateSpan: extraDateSpan, popoverContent: function () { return (createElement(Fragment, null, hiddenSegs.map(function (seg) { + var instanceId = seg.eventRange.instance.instanceId; + return (createElement("div", { key: instanceId, style: { visibility: props.isForcedInvisible[instanceId] ? 'hidden' : '' } }, + createElement(TimelineEvent, __assign({ isTimeScale: props.isTimeScale, seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection }, getSegMeta(seg, props.todayRange, props.nowDate))))); + }))); } }, function (rootElRef, classNames, innerElRef, innerContent, handleClick) { return (createElement("a", { ref: function (el) { + setRef(rootElRef, el); // for MoreLinkRoot + setRef(elRef, el); // for props props + setRef(_this.rootElRef, el); // for this component + }, className: ['fc-timeline-more-link'].concat(classNames).join(' '), style: __assign({ visibility: isVisible ? '' : 'hidden', top: top || 0 }, hStyle), onClick: handleClick }, + createElement("div", { ref: innerElRef, className: "fc-timeline-more-link-inner fc-sticky" }, innerContent))); })); + }; + return TimelineLaneMoreLink; + }(BaseComponent)); + + var TimelineLane = /** @class */ (function (_super) { + __extends(TimelineLane, _super); + function TimelineLane() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.slicer = new TimelineLaneSlicer(); + _this.sortEventSegs = memoize(sortEventSegs); + _this.harnessElRefs = new RefMap(); + _this.moreElRefs = new RefMap(); + _this.innerElRef = createRef(); + // TODO: memoize event positioning + _this.state = { + eventInstanceHeights: {}, + moreLinkHeights: {}, + }; + return _this; + } + TimelineLane.prototype.render = function () { + var _a = this, props = _a.props, state = _a.state, context = _a.context; + var options = context.options; + var dateProfile = props.dateProfile, tDateProfile = props.tDateProfile; + var slicedProps = this.slicer.sliceProps(props, dateProfile, tDateProfile.isTimeScale ? null : props.nextDayThreshold, context, // wish we didn't have to pass in the rest of the args... + dateProfile, context.dateProfileGenerator, tDateProfile, context.dateEnv); + var mirrorSegs = (slicedProps.eventDrag ? slicedProps.eventDrag.segs : null) || + (slicedProps.eventResize ? slicedProps.eventResize.segs : null) || + []; + var fgSegs = this.sortEventSegs(slicedProps.fgEventSegs, options.eventOrder); + var fgSegHCoords = computeSegHCoords(fgSegs, options.eventMinWidth, props.timelineCoords); + var _b = computeFgSegPlacements(fgSegs, fgSegHCoords, state.eventInstanceHeights, state.moreLinkHeights, options.eventOrderStrict, options.eventMaxStack), fgPlacements = _b[0], fgHeight = _b[1]; + var isForcedInvisible = // TODO: more convenient + (slicedProps.eventDrag ? slicedProps.eventDrag.affectedInstances : null) || + (slicedProps.eventResize ? slicedProps.eventResize.affectedInstances : null) || + {}; + return (createElement(Fragment, null, + createElement(TimelineLaneBg, { businessHourSegs: slicedProps.businessHourSegs, bgEventSegs: slicedProps.bgEventSegs, timelineCoords: props.timelineCoords, eventResizeSegs: slicedProps.eventResize ? slicedProps.eventResize.segs : [] /* bad new empty array? */, dateSelectionSegs: slicedProps.dateSelectionSegs, nowDate: props.nowDate, todayRange: props.todayRange }), + createElement("div", { className: "fc-timeline-events fc-scrollgrid-sync-inner", ref: this.innerElRef, style: { height: fgHeight } }, + this.renderFgSegs(fgPlacements, isForcedInvisible, false, false, false), + this.renderFgSegs(buildMirrorPlacements(mirrorSegs, props.timelineCoords, fgPlacements), {}, Boolean(slicedProps.eventDrag), Boolean(slicedProps.eventResize), false)))); + }; + TimelineLane.prototype.componentDidMount = function () { + this.updateSize(); + }; + TimelineLane.prototype.componentDidUpdate = function (prevProps, prevState) { + if (prevProps.eventStore !== this.props.eventStore || // external thing changed? + prevProps.timelineCoords !== this.props.timelineCoords || // external thing changed? + prevState.moreLinkHeights !== this.state.moreLinkHeights // HACK. see addStateEquality + ) { + this.updateSize(); + } + }; + TimelineLane.prototype.updateSize = function () { + var _this = this; + var props = this.props; + var timelineCoords = props.timelineCoords; + if (props.onHeightChange) { + props.onHeightChange(this.innerElRef.current, false); + } + if (timelineCoords) { + this.setState({ + eventInstanceHeights: mapHash(this.harnessElRefs.currentMap, function (harnessEl) { return (Math.round(harnessEl.getBoundingClientRect().height)); }), + moreLinkHeights: mapHash(this.moreElRefs.currentMap, function (moreEl) { return (Math.round(moreEl.getBoundingClientRect().height)); }), + }, function () { + if (props.onHeightChange) { + props.onHeightChange(_this.innerElRef.current, true); + } + }); + } + }; + TimelineLane.prototype.renderFgSegs = function (segPlacements, isForcedInvisible, isDragging, isResizing, isDateSelecting) { + var _a = this, harnessElRefs = _a.harnessElRefs, moreElRefs = _a.moreElRefs, props = _a.props, context = _a.context; + var isMirror = isDragging || isResizing || isDateSelecting; + return (createElement(Fragment, null, segPlacements.map(function (segPlacement) { + var seg = segPlacement.seg, hcoords = segPlacement.hcoords, top = segPlacement.top; + if (Array.isArray(seg)) { // a more-link + var isoStr = buildIsoString(computeEarliestSegStart(seg)); + return (createElement(TimelineLaneMoreLink, { key: 'm:' + isoStr /* "m" for "more" */, elRef: moreElRefs.createRef(isoStr), hiddenSegs: seg, placement: segPlacement, dateProfile: props.dateProfile, nowDate: props.nowDate, todayRange: props.todayRange, isTimeScale: props.tDateProfile.isTimeScale, eventSelection: props.eventSelection, resourceId: props.resourceId, isForcedInvisible: isForcedInvisible })); + } + var instanceId = seg.eventRange.instance.instanceId; + var isVisible = isMirror || Boolean(!isForcedInvisible[instanceId] && hcoords && top !== null); + var hStyle = coordsToCss(hcoords, context.isRtl); + return (createElement("div", { key: 'e:' + instanceId /* "e" for "event" */, ref: isMirror ? null : harnessElRefs.createRef(instanceId), className: "fc-timeline-event-harness", style: __assign({ visibility: isVisible ? '' : 'hidden', top: top || 0 }, hStyle) }, + createElement(TimelineEvent, __assign({ isTimeScale: props.tDateProfile.isTimeScale, seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === props.eventSelection /* TODO: bad for mirror? */ }, getSegMeta(seg, props.todayRange, props.nowDate))))); + }))); + }; + return TimelineLane; + }(BaseComponent)); + TimelineLane.addStateEquality({ + eventInstanceHeights: isPropsEqual, + moreLinkHeights: isPropsEqual, + }); + function buildMirrorPlacements(mirrorSegs, timelineCoords, fgPlacements) { + if (!mirrorSegs.length || !timelineCoords) { + return []; + } + var topsByInstanceId = buildAbsoluteTopHash(fgPlacements); // TODO: cache this at first render? + return mirrorSegs.map(function (seg) { return ({ + seg: seg, + hcoords: timelineCoords.rangeToCoords(seg), + top: topsByInstanceId[seg.eventRange.instance.instanceId], + }); }); + } + function buildAbsoluteTopHash(placements) { + var topsByInstanceId = {}; + for (var _i = 0, placements_1 = placements; _i < placements_1.length; _i++) { + var placement = placements_1[_i]; + var seg = placement.seg; + if (!Array.isArray(seg)) { // doesn't represent a more-link + topsByInstanceId[seg.eventRange.instance.instanceId] = placement.top; + } + } + return topsByInstanceId; + } + + var TimelineGrid = /** @class */ (function (_super) { + __extends(TimelineGrid, _super); + function TimelineGrid() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.slatsRef = createRef(); + _this.state = { + coords: null, + }; + _this.handeEl = function (el) { + if (el) { + _this.context.registerInteractiveComponent(_this, { el: el }); + } + else { + _this.context.unregisterInteractiveComponent(_this); + } + }; + _this.handleCoords = function (coords) { + _this.setState({ coords: coords }); + if (_this.props.onSlatCoords) { + _this.props.onSlatCoords(coords); + } + }; + return _this; + } + TimelineGrid.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, state = _a.state, context = _a.context; + var options = context.options; + var dateProfile = props.dateProfile, tDateProfile = props.tDateProfile; + var timerUnit = greatestDurationDenominator(tDateProfile.slotDuration).unit; + return (createElement("div", { className: "fc-timeline-body", ref: this.handeEl, style: { + minWidth: props.tableMinWidth, + height: props.clientHeight, + width: props.clientWidth, + } }, + createElement(NowTimer, { unit: timerUnit }, function (nowDate, todayRange) { return (createElement(Fragment, null, + createElement(TimelineSlats, { ref: _this.slatsRef, dateProfile: dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange, clientWidth: props.clientWidth, tableColGroupNode: props.tableColGroupNode, tableMinWidth: props.tableMinWidth, onCoords: _this.handleCoords, onScrollLeftRequest: props.onScrollLeftRequest }), + createElement(TimelineLane, { dateProfile: dateProfile, tDateProfile: props.tDateProfile, nowDate: nowDate, todayRange: todayRange, nextDayThreshold: options.nextDayThreshold, businessHours: props.businessHours, eventStore: props.eventStore, eventUiBases: props.eventUiBases, dateSelection: props.dateSelection, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, timelineCoords: state.coords }), + (options.nowIndicator && state.coords && state.coords.isDateInRange(nowDate)) && (createElement("div", { className: "fc-timeline-now-indicator-container" }, + createElement(NowIndicatorRoot, { isAxis: false, date: nowDate }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("div", { ref: rootElRef, className: ['fc-timeline-now-indicator-line'].concat(classNames).join(' '), style: coordToCss(state.coords.dateToCoord(nowDate), context.isRtl) }, innerContent)); }))))); }))); + }; + // Hit System + // ------------------------------------------------------------------------------------------ + TimelineGrid.prototype.queryHit = function (positionLeft, positionTop, elWidth, elHeight) { + var slats = this.slatsRef.current; + var slatHit = slats.positionToHit(positionLeft); + if (slatHit) { + return { + dateProfile: this.props.dateProfile, + dateSpan: slatHit.dateSpan, + rect: { + left: slatHit.left, + right: slatHit.right, + top: 0, + bottom: elHeight, + }, + dayEl: slatHit.dayEl, + layer: 0, + }; + } + return null; + }; + return TimelineGrid; + }(DateComponent)); + + var TimelineView = /** @class */ (function (_super) { + __extends(TimelineView, _super); + function TimelineView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.buildTimelineDateProfile = memoize(buildTimelineDateProfile); + _this.scrollGridRef = createRef(); + _this.state = { + slatCoords: null, + slotCushionMaxWidth: null, + }; + _this.handleSlatCoords = function (slatCoords) { + _this.setState({ slatCoords: slatCoords }); + }; + _this.handleScrollLeftRequest = function (scrollLeft) { + var scrollGrid = _this.scrollGridRef.current; + scrollGrid.forceScrollLeft(0, scrollLeft); + }; + _this.handleMaxCushionWidth = function (slotCushionMaxWidth) { + _this.setState({ + slotCushionMaxWidth: Math.ceil(slotCushionMaxWidth), // for less rerendering TODO: DRY + }); + }; + return _this; + } + TimelineView.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, state = _a.state, context = _a.context; + var options = context.options; + var stickyHeaderDates = !props.forPrint && getStickyHeaderDates(options); + var stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(options); + var tDateProfile = this.buildTimelineDateProfile(props.dateProfile, context.dateEnv, options, context.dateProfileGenerator); + var extraClassNames = [ + 'fc-timeline', + options.eventOverlap === false ? 'fc-timeline-overlap-disabled' : '', + ]; + var slotMinWidth = options.slotMinWidth; + var slatCols = buildSlatCols(tDateProfile, slotMinWidth || this.computeFallbackSlotMinWidth(tDateProfile)); + var sections = [ + { + type: 'header', + key: 'header', + isSticky: stickyHeaderDates, + chunks: [{ + key: 'timeline', + content: function (contentArg) { return (createElement(TimelineHeader, { dateProfile: props.dateProfile, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, tableMinWidth: contentArg.tableMinWidth, tableColGroupNode: contentArg.tableColGroupNode, tDateProfile: tDateProfile, slatCoords: state.slatCoords, onMaxCushionWidth: slotMinWidth ? null : _this.handleMaxCushionWidth })); }, + }], + }, + { + type: 'body', + key: 'body', + liquid: true, + chunks: [{ + key: 'timeline', + content: function (contentArg) { return (createElement(TimelineGrid, __assign({}, props, { clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, tableMinWidth: contentArg.tableMinWidth, tableColGroupNode: contentArg.tableColGroupNode, tDateProfile: tDateProfile, onSlatCoords: _this.handleSlatCoords, onScrollLeftRequest: _this.handleScrollLeftRequest }))); }, + }], + }, + ]; + if (stickyFooterScrollbar) { + sections.push({ + type: 'footer', + key: 'footer', + isSticky: true, + chunks: [{ + key: 'timeline', + content: renderScrollShim, + }], + }); + } + return (createElement(ViewRoot, { viewSpec: context.viewSpec }, function (rootElRef, classNames) { return (createElement("div", { ref: rootElRef, className: extraClassNames.concat(classNames).join(' ') }, + createElement(ScrollGrid, { ref: _this.scrollGridRef, liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: false, colGroups: [ + { cols: slatCols }, + ], sections: sections }))); })); + }; + TimelineView.prototype.computeFallbackSlotMinWidth = function (tDateProfile) { + return Math.max(30, ((this.state.slotCushionMaxWidth || 0) / tDateProfile.slotsPerLabel)); + }; + return TimelineView; + }(DateComponent)); + function buildSlatCols(tDateProfile, slotMinWidth) { + return [{ + span: tDateProfile.slotCnt, + minWidth: slotMinWidth || 1, // needs to be a non-zero number to trigger horizontal scrollbars!?????? + }]; + } + + var timelinePlugin = createPlugin({ + deps: [ + premiumCommonPlugin, + ], + initialView: 'timelineDay', + views: { + timeline: { + component: TimelineView, + usesMinMaxTime: true, + eventResizableFromStart: true, // how is this consumed for TimelineView tho? + }, + timelineDay: { + type: 'timeline', + duration: { days: 1 }, + }, + timelineWeek: { + type: 'timeline', + duration: { weeks: 1 }, + }, + timelineMonth: { + type: 'timeline', + duration: { months: 1 }, + }, + timelineYear: { + type: 'timeline', + duration: { years: 1 }, + }, + }, + }); + + function massageEventDragMutation(eventMutation, hit0, hit1) { + var resource0 = hit0.dateSpan.resourceId; + var resource1 = hit1.dateSpan.resourceId; + if (resource0 && resource1 && + resource0 !== resource1) { + eventMutation.resourceMutation = { + matchResourceId: resource0, + setResourceId: resource1, + }; + } + } + /* + TODO: all this would be much easier if we were using a hash! + */ + function applyEventDefMutation(eventDef, mutation, context) { + var resourceMutation = mutation.resourceMutation; + if (resourceMutation && computeResourceEditable(eventDef, context)) { + var index = eventDef.resourceIds.indexOf(resourceMutation.matchResourceId); + if (index !== -1) { + var resourceIds = eventDef.resourceIds.slice(); // copy + resourceIds.splice(index, 1); // remove + if (resourceIds.indexOf(resourceMutation.setResourceId) === -1) { // not already in there + resourceIds.push(resourceMutation.setResourceId); // add + } + eventDef.resourceIds = resourceIds; + } + } + } + /* + HACK + TODO: use EventUi system instead of this + */ + function computeResourceEditable(eventDef, context) { + var resourceEditable = eventDef.resourceEditable; + if (resourceEditable == null) { + var source = eventDef.sourceId && context.getCurrentData().eventSources[eventDef.sourceId]; + if (source) { + resourceEditable = source.extendedProps.resourceEditable; // used the Source::extendedProps hack + } + if (resourceEditable == null) { + resourceEditable = context.options.eventResourceEditable; + if (resourceEditable == null) { + resourceEditable = context.options.editable; // TODO: use defaults system instead + } + } + } + return resourceEditable; + } + function transformEventDrop(mutation, context) { + var resourceMutation = mutation.resourceMutation; + if (resourceMutation) { + var calendarApi = context.calendarApi; + return { + oldResource: calendarApi.getResourceById(resourceMutation.matchResourceId), + newResource: calendarApi.getResourceById(resourceMutation.setResourceId), + }; + } + return { + oldResource: null, + newResource: null, + }; + } + + var ResourceDataAdder = /** @class */ (function () { + function ResourceDataAdder() { + this.filterResources = memoize(filterResources); + } + ResourceDataAdder.prototype.transform = function (viewProps, calendarProps) { + if (calendarProps.viewSpec.optionDefaults.needsResourceData) { + return { + resourceStore: this.filterResources(calendarProps.resourceStore, calendarProps.options.filterResourcesWithEvents, calendarProps.eventStore, calendarProps.dateProfile.activeRange), + resourceEntityExpansions: calendarProps.resourceEntityExpansions, + }; + } + return null; + }; + return ResourceDataAdder; + }()); + function filterResources(resourceStore, doFilterResourcesWithEvents, eventStore, activeRange) { + if (doFilterResourcesWithEvents) { + var instancesInRange = filterEventInstancesInRange(eventStore.instances, activeRange); + var hasEvents_1 = computeHasEvents(instancesInRange, eventStore.defs); + __assign(hasEvents_1, computeAncestorHasEvents(hasEvents_1, resourceStore)); + return filterHash(resourceStore, function (resource, resourceId) { return hasEvents_1[resourceId]; }); + } + return resourceStore; + } + function filterEventInstancesInRange(eventInstances, activeRange) { + return filterHash(eventInstances, function (eventInstance) { return rangesIntersect(eventInstance.range, activeRange); }); + } + function computeHasEvents(eventInstances, eventDefs) { + var hasEvents = {}; + for (var instanceId in eventInstances) { + var instance = eventInstances[instanceId]; + for (var _i = 0, _a = eventDefs[instance.defId].resourceIds; _i < _a.length; _i++) { + var resourceId = _a[_i]; + hasEvents[resourceId] = true; + } + } + return hasEvents; + } + /* + mark resources as having events if any of their ancestors have them + NOTE: resourceStore might not have all the resources that hasEvents{} has keyed + */ + function computeAncestorHasEvents(hasEvents, resourceStore) { + var res = {}; + for (var resourceId in hasEvents) { + var resource = void 0; + while ((resource = resourceStore[resourceId])) { + resourceId = resource.parentId; // now functioning as the parentId + if (resourceId) { + res[resourceId] = true; + } + else { + break; + } + } + } + return res; + } + /* + for making sure events that have editable resources are always draggable in resource views + */ + function transformIsDraggable(val, eventDef, eventUi, context) { + if (!val) { + var state = context.getCurrentData(); + var viewSpec = state.viewSpecs[state.currentViewType]; + if (viewSpec.optionDefaults.needsResourceData) { + if (computeResourceEditable(eventDef, context)) { + return true; + } + } + } + return val; + } + + // for when non-resource view should be given EventUi info (for event coloring/constraints based off of resource data) + var ResourceEventConfigAdder = /** @class */ (function () { + function ResourceEventConfigAdder() { + this.buildResourceEventUis = memoize(buildResourceEventUis, isPropsEqual); + this.injectResourceEventUis = memoize(injectResourceEventUis); + } + ResourceEventConfigAdder.prototype.transform = function (viewProps, calendarProps) { + if (!calendarProps.viewSpec.optionDefaults.needsResourceData) { + return { + eventUiBases: this.injectResourceEventUis(viewProps.eventUiBases, viewProps.eventStore.defs, this.buildResourceEventUis(calendarProps.resourceStore)), + }; + } + return null; + }; + return ResourceEventConfigAdder; + }()); + function buildResourceEventUis(resourceStore) { + return mapHash(resourceStore, function (resource) { return resource.ui; }); + } + function injectResourceEventUis(eventUiBases, eventDefs, resourceEventUis) { + return mapHash(eventUiBases, function (eventUi, defId) { + if (defId) { // not the '' key + return injectResourceEventUi(eventUi, eventDefs[defId], resourceEventUis); + } + return eventUi; + }); + } + function injectResourceEventUi(origEventUi, eventDef, resourceEventUis) { + var parts = []; + // first resource takes precedence, which fights with the ordering of combineEventUis, thus the unshifts + for (var _i = 0, _a = eventDef.resourceIds; _i < _a.length; _i++) { + var resourceId = _a[_i]; + if (resourceEventUis[resourceId]) { + parts.unshift(resourceEventUis[resourceId]); + } + } + parts.unshift(origEventUi); + return combineEventUis(parts); + } + + var defs = []; // TODO: use plugin system + function registerResourceSourceDef(def) { + defs.push(def); + } + function getResourceSourceDef(id) { + return defs[id]; + } + function getResourceSourceDefs() { + return defs; + } + + // TODO: make this a plugin-able parser + // TODO: success/failure + var RESOURCE_SOURCE_REFINERS = { + id: String, + // for array. TODO: move to resource-array + resources: identity, + // for json feed. TODO: move to resource-json-feed + url: String, + method: String, + startParam: String, + endParam: String, + timeZoneParam: String, + extraParams: identity, + }; + function parseResourceSource(input) { + var inputObj; + if (typeof input === 'string') { + inputObj = { url: input }; + } + else if (typeof input === 'function' || Array.isArray(input)) { + inputObj = { resources: input }; + } + else if (typeof input === 'object' && input) { // non-null object + inputObj = input; + } + if (inputObj) { + var _a = refineProps(inputObj, RESOURCE_SOURCE_REFINERS), refined = _a.refined, extra = _a.extra; + warnUnknownProps(extra); + var metaRes = buildResourceSourceMeta(refined); + if (metaRes) { + return { + _raw: input, + sourceId: guid(), + sourceDefId: metaRes.sourceDefId, + meta: metaRes.meta, + publicId: refined.id || '', + isFetching: false, + latestFetchId: '', + fetchRange: null, + }; + } + } + return null; + } + function buildResourceSourceMeta(refined) { + var defs = getResourceSourceDefs(); + for (var i = defs.length - 1; i >= 0; i -= 1) { // later-added plugins take precedence + var def = defs[i]; + var meta = def.parseMeta(refined); + if (meta) { + return { meta: meta, sourceDefId: i }; + } + } + return null; + } + function warnUnknownProps(props) { + for (var propName in props) { + console.warn("Unknown resource prop '" + propName + "'"); + } + } + + function reduceResourceSource(source, action, context) { + var options = context.options, dateProfile = context.dateProfile; + if (!source || !action) { + return createSource(options.initialResources || options.resources, dateProfile.activeRange, options.refetchResourcesOnNavigate, context); + } + switch (action.type) { + case 'RESET_RESOURCE_SOURCE': + return createSource(action.resourceSourceInput, dateProfile.activeRange, options.refetchResourcesOnNavigate, context); + case 'PREV': // TODO: how do we track all actions that affect dateProfile :( + case 'NEXT': + case 'CHANGE_DATE': + case 'CHANGE_VIEW_TYPE': + return handleRangeChange(source, dateProfile.activeRange, options.refetchResourcesOnNavigate, context); + case 'RECEIVE_RESOURCES': + case 'RECEIVE_RESOURCE_ERROR': + return receiveResponse(source, action.fetchId, action.fetchRange); + case 'REFETCH_RESOURCES': + return fetchSource(source, dateProfile.activeRange, context); + default: + return source; + } + } + function createSource(input, activeRange, refetchResourcesOnNavigate, context) { + if (input) { + var source = parseResourceSource(input); + source = fetchSource(source, refetchResourcesOnNavigate ? activeRange : null, context); + return source; + } + return null; + } + function handleRangeChange(source, activeRange, refetchResourcesOnNavigate, context) { + if (refetchResourcesOnNavigate && + !doesSourceIgnoreRange(source) && + (!source.fetchRange || !rangesEqual(source.fetchRange, activeRange))) { + return fetchSource(source, activeRange, context); + } + return source; + } + function doesSourceIgnoreRange(source) { + return Boolean(getResourceSourceDef(source.sourceDefId).ignoreRange); + } + function fetchSource(source, fetchRange, context) { + var sourceDef = getResourceSourceDef(source.sourceDefId); + var fetchId = guid(); + sourceDef.fetch({ + resourceSource: source, + range: fetchRange, + context: context, + }, function (res) { + context.dispatch({ + type: 'RECEIVE_RESOURCES', + fetchId: fetchId, + fetchRange: fetchRange, + rawResources: res.rawResources, + }); + }, function (error) { + context.dispatch({ + type: 'RECEIVE_RESOURCE_ERROR', + fetchId: fetchId, + fetchRange: fetchRange, + error: error, + }); + }); + return __assign(__assign({}, source), { isFetching: true, latestFetchId: fetchId }); + } + function receiveResponse(source, fetchId, fetchRange) { + if (fetchId === source.latestFetchId) { + return __assign(__assign({}, source), { isFetching: false, fetchRange: fetchRange }); + } + return source; + } + + var PRIVATE_ID_PREFIX = '_fc:'; + var RESOURCE_REFINERS = { + id: String, + parentId: String, + children: identity, + title: String, + businessHours: identity, + extendedProps: identity, + // event-ui + eventEditable: Boolean, + eventStartEditable: Boolean, + eventDurationEditable: Boolean, + eventConstraint: identity, + eventOverlap: Boolean, + eventAllow: identity, + eventClassNames: parseClassNames, + eventBackgroundColor: String, + eventBorderColor: String, + eventTextColor: String, + eventColor: String, + }; + /* + needs a full store so that it can populate children too + */ + function parseResource(raw, parentId, store, context) { + if (parentId === void 0) { parentId = ''; } + var _a = refineProps(raw, RESOURCE_REFINERS), refined = _a.refined, extra = _a.extra; + var resource = { + id: refined.id || (PRIVATE_ID_PREFIX + guid()), + parentId: refined.parentId || parentId, + title: refined.title || '', + businessHours: refined.businessHours ? parseBusinessHours(refined.businessHours, context) : null, + ui: createEventUi({ + editable: refined.eventEditable, + startEditable: refined.eventStartEditable, + durationEditable: refined.eventDurationEditable, + constraint: refined.eventConstraint, + overlap: refined.eventOverlap, + allow: refined.eventAllow, + classNames: refined.eventClassNames, + backgroundColor: refined.eventBackgroundColor, + borderColor: refined.eventBorderColor, + textColor: refined.eventTextColor, + color: refined.eventColor, + }, context), + extendedProps: __assign(__assign({}, extra), refined.extendedProps), + }; + // help out ResourceApi from having user modify props + Object.freeze(resource.ui.classNames); + Object.freeze(resource.extendedProps); + if (store[resource.id]) ; + else { + store[resource.id] = resource; + if (refined.children) { + for (var _i = 0, _b = refined.children; _i < _b.length; _i++) { + var childInput = _b[_i]; + parseResource(childInput, resource.id, store, context); + } + } + } + return resource; + } + /* + TODO: use this in more places + */ + function getPublicId(id) { + if (id.indexOf(PRIVATE_ID_PREFIX) === 0) { + return ''; + } + return id; + } + + function reduceResourceStore(store, action, source, context) { + if (!store || !action) { + return {}; + } + switch (action.type) { + case 'RECEIVE_RESOURCES': + return receiveRawResources(store, action.rawResources, action.fetchId, source, context); + case 'ADD_RESOURCE': + return addResource(store, action.resourceHash); + case 'REMOVE_RESOURCE': + return removeResource(store, action.resourceId); + case 'SET_RESOURCE_PROP': + return setResourceProp(store, action.resourceId, action.propName, action.propValue); + case 'SET_RESOURCE_EXTENDED_PROP': + return setResourceExtendedProp(store, action.resourceId, action.propName, action.propValue); + default: + return store; + } + } + function receiveRawResources(existingStore, inputs, fetchId, source, context) { + if (source.latestFetchId === fetchId) { + var nextStore = {}; + for (var _i = 0, inputs_1 = inputs; _i < inputs_1.length; _i++) { + var input = inputs_1[_i]; + parseResource(input, '', nextStore, context); + } + return nextStore; + } + return existingStore; + } + function addResource(existingStore, additions) { + // TODO: warn about duplicate IDs + return __assign(__assign({}, existingStore), additions); + } + function removeResource(existingStore, resourceId) { + var newStore = __assign({}, existingStore); + delete newStore[resourceId]; + // promote children + for (var childResourceId in newStore) { // a child, *maybe* but probably not + if (newStore[childResourceId].parentId === resourceId) { + newStore[childResourceId] = __assign(__assign({}, newStore[childResourceId]), { parentId: '' }); + } + } + return newStore; + } + function setResourceProp(existingStore, resourceId, name, value) { + var _a, _b; + var existingResource = existingStore[resourceId]; + // TODO: sanitization + if (existingResource) { + return __assign(__assign({}, existingStore), (_a = {}, _a[resourceId] = __assign(__assign({}, existingResource), (_b = {}, _b[name] = value, _b)), _a)); + } + return existingStore; + } + function setResourceExtendedProp(existingStore, resourceId, name, value) { + var _a, _b; + var existingResource = existingStore[resourceId]; + if (existingResource) { + return __assign(__assign({}, existingStore), (_a = {}, _a[resourceId] = __assign(__assign({}, existingResource), { extendedProps: __assign(__assign({}, existingResource.extendedProps), (_b = {}, _b[name] = value, _b)) }), _a)); + } + return existingStore; + } + + function reduceResourceEntityExpansions(expansions, action) { + var _a; + if (!expansions || !action) { + return {}; + } + switch (action.type) { + case 'SET_RESOURCE_ENTITY_EXPANDED': + return __assign(__assign({}, expansions), (_a = {}, _a[action.id] = action.isExpanded, _a)); + default: + return expansions; + } + } + + function reduceResources(state, action, context) { + var resourceSource = reduceResourceSource(state && state.resourceSource, action, context); + var resourceStore = reduceResourceStore(state && state.resourceStore, action, resourceSource, context); + var resourceEntityExpansions = reduceResourceEntityExpansions(state && state.resourceEntityExpansions, action); + return { + resourceSource: resourceSource, + resourceStore: resourceStore, + resourceEntityExpansions: resourceEntityExpansions, + }; + } + + var EVENT_REFINERS = { + resourceId: String, + resourceIds: identity, + resourceEditable: Boolean, + }; + function generateEventDefResourceMembers(refined) { + return { + resourceIds: ensureStringArray(refined.resourceIds) + .concat(refined.resourceId ? [refined.resourceId] : []), + resourceEditable: refined.resourceEditable, + }; + } + function ensureStringArray(items) { + return (items || []).map(function (item) { return String(item); }); + } + + function transformDateSelectionJoin(hit0, hit1) { + var resourceId0 = hit0.dateSpan.resourceId; + var resourceId1 = hit1.dateSpan.resourceId; + if (resourceId0 && resourceId1) { + return { resourceId: resourceId0 }; + } + return null; + } + + var ResourceApi = /** @class */ (function () { + function ResourceApi(_context, _resource) { + this._context = _context; + this._resource = _resource; + } + ResourceApi.prototype.setProp = function (name, value) { + var oldResource = this._resource; + this._context.dispatch({ + type: 'SET_RESOURCE_PROP', + resourceId: oldResource.id, + propName: name, + propValue: value, + }); + this.sync(oldResource); + }; + ResourceApi.prototype.setExtendedProp = function (name, value) { + var oldResource = this._resource; + this._context.dispatch({ + type: 'SET_RESOURCE_EXTENDED_PROP', + resourceId: oldResource.id, + propName: name, + propValue: value, + }); + this.sync(oldResource); + }; + ResourceApi.prototype.sync = function (oldResource) { + var context = this._context; + var resourceId = oldResource.id; + // TODO: what if dispatch didn't complete synchronously? + this._resource = context.getCurrentData().resourceStore[resourceId]; + context.emitter.trigger('resourceChange', { + oldResource: new ResourceApi(context, oldResource), + resource: this, + revert: function () { + var _a; + context.dispatch({ + type: 'ADD_RESOURCE', + resourceHash: (_a = {}, + _a[resourceId] = oldResource, + _a), + }); + }, + }); + }; + ResourceApi.prototype.remove = function () { + var context = this._context; + var internalResource = this._resource; + var resourceId = internalResource.id; + context.dispatch({ + type: 'REMOVE_RESOURCE', + resourceId: resourceId, + }); + context.emitter.trigger('resourceRemove', { + resource: this, + revert: function () { + var _a; + context.dispatch({ + type: 'ADD_RESOURCE', + resourceHash: (_a = {}, + _a[resourceId] = internalResource, + _a), + }); + }, + }); + }; + ResourceApi.prototype.getParent = function () { + var context = this._context; + var parentId = this._resource.parentId; + if (parentId) { + return new ResourceApi(context, context.getCurrentData().resourceSource[parentId]); + } + return null; + }; + ResourceApi.prototype.getChildren = function () { + var thisResourceId = this._resource.id; + var context = this._context; + var resourceStore = context.getCurrentData().resourceStore; + var childApis = []; + for (var resourceId in resourceStore) { + if (resourceStore[resourceId].parentId === thisResourceId) { + childApis.push(new ResourceApi(context, resourceStore[resourceId])); + } + } + return childApis; + }; + /* + this is really inefficient! + TODO: make EventApi::resourceIds a hash or keep an index in the Calendar's state + */ + ResourceApi.prototype.getEvents = function () { + var thisResourceId = this._resource.id; + var context = this._context; + var _a = context.getCurrentData().eventStore, defs = _a.defs, instances = _a.instances; + var eventApis = []; + for (var instanceId in instances) { + var instance = instances[instanceId]; + var def = defs[instance.defId]; + if (def.resourceIds.indexOf(thisResourceId) !== -1) { // inefficient!!! + eventApis.push(new EventApi(context, def, instance)); + } + } + return eventApis; + }; + Object.defineProperty(ResourceApi.prototype, "id", { + get: function () { return getPublicId(this._resource.id); }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ResourceApi.prototype, "title", { + get: function () { return this._resource.title; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ResourceApi.prototype, "eventConstraint", { + get: function () { return this._resource.ui.constraints[0] || null; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ResourceApi.prototype, "eventOverlap", { + get: function () { return this._resource.ui.overlap; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ResourceApi.prototype, "eventAllow", { + get: function () { return this._resource.ui.allows[0] || null; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ResourceApi.prototype, "eventBackgroundColor", { + get: function () { return this._resource.ui.backgroundColor; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ResourceApi.prototype, "eventBorderColor", { + get: function () { return this._resource.ui.borderColor; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ResourceApi.prototype, "eventTextColor", { + get: function () { return this._resource.ui.textColor; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ResourceApi.prototype, "eventClassNames", { + // NOTE: user can't modify these because Object.freeze was called in event-def parsing + get: function () { return this._resource.ui.classNames; }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ResourceApi.prototype, "extendedProps", { + get: function () { return this._resource.extendedProps; }, + enumerable: false, + configurable: true + }); + ResourceApi.prototype.toPlainObject = function (settings) { + if (settings === void 0) { settings = {}; } + var internal = this._resource; + var ui = internal.ui; + var publicId = this.id; + var res = {}; + if (publicId) { + res.id = publicId; + } + if (internal.title) { + res.title = internal.title; + } + if (settings.collapseEventColor && ui.backgroundColor && ui.backgroundColor === ui.borderColor) { + res.eventColor = ui.backgroundColor; + } + else { + if (ui.backgroundColor) { + res.eventBackgroundColor = ui.backgroundColor; + } + if (ui.borderColor) { + res.eventBorderColor = ui.borderColor; + } + } + if (ui.textColor) { + res.eventTextColor = ui.textColor; + } + if (ui.classNames.length) { + res.eventClassNames = ui.classNames; + } + if (Object.keys(internal.extendedProps).length) { + if (settings.collapseExtendedProps) { + __assign(res, internal.extendedProps); + } + else { + res.extendedProps = internal.extendedProps; + } + } + return res; + }; + ResourceApi.prototype.toJSON = function () { + return this.toPlainObject(); + }; + return ResourceApi; + }()); + function buildResourceApis(resourceStore, context) { + var resourceApis = []; + for (var resourceId in resourceStore) { + resourceApis.push(new ResourceApi(context, resourceStore[resourceId])); + } + return resourceApis; + } + + CalendarApi.prototype.addResource = function (input, scrollTo) { + var _a; + var _this = this; + if (scrollTo === void 0) { scrollTo = true; } + var currentState = this.getCurrentData(); + var resourceHash; + var resource; + if (input instanceof ResourceApi) { + resource = input._resource; + resourceHash = (_a = {}, _a[resource.id] = resource, _a); + } + else { + resourceHash = {}; + resource = parseResource(input, '', resourceHash, currentState); + } + this.dispatch({ + type: 'ADD_RESOURCE', + resourceHash: resourceHash, + }); + if (scrollTo) { + // TODO: wait til dispatch completes somehow + this.trigger('_scrollRequest', { resourceId: resource.id }); + } + var resourceApi = new ResourceApi(currentState, resource); + currentState.emitter.trigger('resourceAdd', { + resource: resourceApi, + revert: function () { + _this.dispatch({ + type: 'REMOVE_RESOURCE', + resourceId: resource.id, + }); + }, + }); + return resourceApi; + }; + CalendarApi.prototype.getResourceById = function (id) { + id = String(id); + var currentState = this.getCurrentData(); // eslint-disable-line react/no-this-in-sfc + if (currentState.resourceStore) { // guard against calendar with no resource functionality + var rawResource = currentState.resourceStore[id]; + if (rawResource) { + return new ResourceApi(currentState, rawResource); + } + } + return null; + }; + CalendarApi.prototype.getResources = function () { + var currentState = this.getCurrentData(); + var resourceStore = currentState.resourceStore; + var resourceApis = []; + if (resourceStore) { // guard against calendar with no resource functionality + for (var resourceId in resourceStore) { + resourceApis.push(new ResourceApi(currentState, resourceStore[resourceId])); + } + } + return resourceApis; + }; + CalendarApi.prototype.getTopLevelResources = function () { + var currentState = this.getCurrentData(); + var resourceStore = currentState.resourceStore; + var resourceApis = []; + if (resourceStore) { // guard against calendar with no resource functionality + for (var resourceId in resourceStore) { + if (!resourceStore[resourceId].parentId) { + resourceApis.push(new ResourceApi(currentState, resourceStore[resourceId])); + } + } + } + return resourceApis; + }; + CalendarApi.prototype.refetchResources = function () { + this.dispatch({ + type: 'REFETCH_RESOURCES', + }); + }; + function transformDatePoint(dateSpan, context) { + return dateSpan.resourceId ? + { resource: context.calendarApi.getResourceById(dateSpan.resourceId) } : + {}; + } + function transformDateSpan(dateSpan, context) { + return dateSpan.resourceId ? + { resource: context.calendarApi.getResourceById(dateSpan.resourceId) } : + {}; + } + + /* + splits things BASED OFF OF which resources they are associated with. + creates a '' entry which is when something has NO resource. + */ + var ResourceSplitter = /** @class */ (function (_super) { + __extends(ResourceSplitter, _super); + function ResourceSplitter() { + return _super !== null && _super.apply(this, arguments) || this; + } + ResourceSplitter.prototype.getKeyInfo = function (props) { + return __assign({ '': {} }, props.resourceStore); + }; + ResourceSplitter.prototype.getKeysForDateSpan = function (dateSpan) { + return [dateSpan.resourceId || '']; + }; + ResourceSplitter.prototype.getKeysForEventDef = function (eventDef) { + var resourceIds = eventDef.resourceIds; + if (!resourceIds.length) { + return ['']; + } + return resourceIds; + }; + return ResourceSplitter; + }(Splitter)); + + function isPropsValidWithResources(combinedProps, context) { + var splitter = new ResourceSplitter(); + var sets = splitter.splitProps(__assign(__assign({}, combinedProps), { resourceStore: context.getCurrentData().resourceStore })); + for (var resourceId in sets) { + var props = sets[resourceId]; + // merge in event data from the non-resource segment + if (resourceId && sets['']) { // current segment is not the non-resource one, and there IS a non-resource one + props = __assign(__assign({}, props), { eventStore: mergeEventStores(sets[''].eventStore, props.eventStore), eventUiBases: __assign(__assign({}, sets[''].eventUiBases), props.eventUiBases) }); + } + if (!isPropsValid(props, context, { resourceId: resourceId }, filterConfig.bind(null, resourceId))) { + return false; + } + } + return true; + } + function filterConfig(resourceId, config) { + return __assign(__assign({}, config), { constraints: filterConstraints(resourceId, config.constraints) }); + } + function filterConstraints(resourceId, constraints) { + return constraints.map(function (constraint) { + var defs = constraint.defs; + if (defs) { // we are dealing with an EventStore + // if any of the events define constraints to resources that are NOT this resource, + // then this resource is unconditionally prohibited, which is what a `false` value does. + for (var defId in defs) { + var resourceIds = defs[defId].resourceIds; + if (resourceIds.length && resourceIds.indexOf(resourceId) === -1) { // TODO: use a hash?!!! (for other reasons too) + return false; + } + } + } + return constraint; + }); + } + + function transformExternalDef(dateSpan) { + return dateSpan.resourceId ? + { resourceId: dateSpan.resourceId } : + {}; + } + + EventApi.prototype.getResources = function () { + var calendarApi = this._context.calendarApi; + return this._def.resourceIds.map(function (resourceId) { return calendarApi.getResourceById(resourceId); }); + }; + EventApi.prototype.setResources = function (resources) { + var resourceIds = []; + // massage resources -> resourceIds + for (var _i = 0, resources_1 = resources; _i < resources_1.length; _i++) { + var resource = resources_1[_i]; + var resourceId = null; + if (typeof resource === 'string') { + resourceId = resource; + } + else if (typeof resource === 'number') { + resourceId = String(resource); + } + else if (resource instanceof ResourceApi) { + resourceId = resource.id; // guaranteed to always have an ID. hmmm + } + else { + console.warn('unknown resource type: ' + resource); + } + if (resourceId) { + resourceIds.push(resourceId); + } + } + this.mutate({ + standardProps: { + resourceIds: resourceIds, + }, + }); + }; + + var optionChangeHandlers = { + resources: handleResources, + }; + function handleResources(newSourceInput, context) { + var oldSourceInput = context.getCurrentData().resourceSource._raw; + if (oldSourceInput !== newSourceInput) { + context.dispatch({ + type: 'RESET_RESOURCE_SOURCE', + resourceSourceInput: newSourceInput, + }); + } + } + + var DEFAULT_RESOURCE_ORDER = parseFieldSpecs('id,title'); + function handleResourceStore(resourceStore, calendarData) { + var emitter = calendarData.emitter; + if (emitter.hasHandlers('resourcesSet')) { + emitter.trigger('resourcesSet', buildResourceApis(resourceStore, calendarData)); + } + } + + var OPTION_REFINERS = { + initialResources: identity, + resources: identity, + eventResourceEditable: Boolean, + refetchResourcesOnNavigate: Boolean, + resourceOrder: parseFieldSpecs, + filterResourcesWithEvents: Boolean, + resourceGroupField: String, + resourceAreaWidth: identity, + resourceAreaColumns: identity, + resourcesInitiallyExpanded: Boolean, + datesAboveResources: Boolean, + needsResourceData: Boolean, + resourceAreaHeaderClassNames: identity, + resourceAreaHeaderContent: identity, + resourceAreaHeaderDidMount: identity, + resourceAreaHeaderWillUnmount: identity, + resourceGroupLabelClassNames: identity, + resourceGroupLabelContent: identity, + resourceGroupLabelDidMount: identity, + resourceGroupLabelWillUnmount: identity, + resourceLabelClassNames: identity, + resourceLabelContent: identity, + resourceLabelDidMount: identity, + resourceLabelWillUnmount: identity, + resourceLaneClassNames: identity, + resourceLaneContent: identity, + resourceLaneDidMount: identity, + resourceLaneWillUnmount: identity, + resourceGroupLaneClassNames: identity, + resourceGroupLaneContent: identity, + resourceGroupLaneDidMount: identity, + resourceGroupLaneWillUnmount: identity, + }; + var LISTENER_REFINERS = { + resourcesSet: identity, + resourceAdd: identity, + resourceChange: identity, + resourceRemove: identity, + }; + + registerResourceSourceDef({ + ignoreRange: true, + parseMeta: function (refined) { + if (Array.isArray(refined.resources)) { + return refined.resources; + } + return null; + }, + fetch: function (arg, successCallback) { + successCallback({ + rawResources: arg.resourceSource.meta, + }); + }, + }); + + registerResourceSourceDef({ + parseMeta: function (refined) { + if (typeof refined.resources === 'function') { + return refined.resources; + } + return null; + }, + fetch: function (arg, success, failure) { + var dateEnv = arg.context.dateEnv; + var func = arg.resourceSource.meta; + var publicArg = arg.range ? { + start: dateEnv.toDate(arg.range.start), + end: dateEnv.toDate(arg.range.end), + startStr: dateEnv.formatIso(arg.range.start), + endStr: dateEnv.formatIso(arg.range.end), + timeZone: dateEnv.timeZone, + } : {}; + // TODO: make more dry with EventSourceFunc + // TODO: accept a response? + unpromisify(func.bind(null, publicArg), function (rawResources) { + success({ rawResources: rawResources }); // needs an object response + }, failure); + }, + }); + + registerResourceSourceDef({ + parseMeta: function (refined) { + if (refined.url) { + return { + url: refined.url, + method: (refined.method || 'GET').toUpperCase(), + extraParams: refined.extraParams, + }; + } + return null; + }, + fetch: function (arg, successCallback, failureCallback) { + var meta = arg.resourceSource.meta; + var requestParams = buildRequestParams(meta, arg.range, arg.context); + requestJson(meta.method, meta.url, requestParams, function (rawResources, xhr) { + successCallback({ rawResources: rawResources, xhr: xhr }); + }, function (message, xhr) { + failureCallback({ message: message, xhr: xhr }); + }); + }, + }); + // TODO: somehow consolidate with event json feed + function buildRequestParams(meta, range, context) { + var dateEnv = context.dateEnv, options = context.options; + var startParam; + var endParam; + var timeZoneParam; + var customRequestParams; + var params = {}; + if (range) { + startParam = meta.startParam; + if (startParam == null) { + startParam = options.startParam; + } + endParam = meta.endParam; + if (endParam == null) { + endParam = options.endParam; + } + timeZoneParam = meta.timeZoneParam; + if (timeZoneParam == null) { + timeZoneParam = options.timeZoneParam; + } + params[startParam] = dateEnv.formatIso(range.start); + params[endParam] = dateEnv.formatIso(range.end); + if (dateEnv.timeZone !== 'local') { + params[timeZoneParam] = dateEnv.timeZone; + } + } + // retrieve any outbound GET/POST data from the options + if (typeof meta.extraParams === 'function') { + // supplied as a function that returns a key/value object + customRequestParams = meta.extraParams(); + } + else { + // probably supplied as a straight key/value object + customRequestParams = meta.extraParams || {}; + } + __assign(params, customRequestParams); + return params; + } + + // TODO: not used for Spreadsheet. START USING. difficult because of col-specific rendering props + function ResourceLabelRoot(props) { + return (createElement(ViewContextType.Consumer, null, function (context) { + var options = context.options; + var hookProps = { + resource: new ResourceApi(context, props.resource), + date: props.date ? context.dateEnv.toDate(props.date) : null, + view: context.viewApi, + }; + var dataAttrs = { + 'data-resource-id': props.resource.id, + 'data-date': props.date ? formatDayString(props.date) : undefined, + }; + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.resourceLabelClassNames, content: options.resourceLabelContent, defaultContent: renderInnerContent, didMount: options.resourceLabelDidMount, willUnmount: options.resourceLabelWillUnmount }, function (rootElRef, classNames, innerElRef, innerContent) { return props.children(rootElRef, classNames, // TODO: pass in 'fc-resource' ? + dataAttrs, innerElRef, innerContent); })); + })); + } + function renderInnerContent(props) { + return props.resource.title || props.resource.id; + } + + var ResourceCell = /** @class */ (function (_super) { + __extends(ResourceCell, _super); + function ResourceCell() { + return _super !== null && _super.apply(this, arguments) || this; + } + ResourceCell.prototype.render = function () { + var props = this.props; + return (createElement(ResourceLabelRoot, { resource: props.resource, date: props.date }, function (elRef, customClassNames, dataAttrs, innerElRef, innerContent) { return (createElement("th", __assign({ ref: elRef, className: ['fc-col-header-cell', 'fc-resource'].concat(customClassNames).join(' '), colSpan: props.colSpan }, dataAttrs), + createElement("div", { className: "fc-scrollgrid-sync-inner" }, + createElement("span", { className: [ + 'fc-col-header-cell-cushion', + props.isSticky ? 'fc-sticky' : '', + ].join(' '), ref: innerElRef }, innerContent)))); })); + }; + return ResourceCell; + }(BaseComponent)); + + var ResourceDayHeader = /** @class */ (function (_super) { + __extends(ResourceDayHeader, _super); + function ResourceDayHeader() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.buildDateFormat = memoize(buildDateFormat); + return _this; + } + ResourceDayHeader.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var dateFormat = this.buildDateFormat(context.options.dayHeaderFormat, props.datesRepDistinctDays, props.dates.length); + return (createElement(NowTimer, { unit: "day" }, function (nowDate, todayRange) { + if (props.dates.length === 1) { + return _this.renderResourceRow(props.resources, props.dates[0]); + } + if (context.options.datesAboveResources) { + return _this.renderDayAndResourceRows(props.dates, dateFormat, todayRange, props.resources); + } + return _this.renderResourceAndDayRows(props.resources, props.dates, dateFormat, todayRange); + })); + }; + ResourceDayHeader.prototype.renderResourceRow = function (resources, date) { + var resourceCells = resources.map(function (resource) { return (createElement(ResourceCell, { key: resource.id, resource: resource, colSpan: 1, date: date })); }); + return this.buildTr(resourceCells, 'resources'); + }; + ResourceDayHeader.prototype.renderDayAndResourceRows = function (dates, dateFormat, todayRange, resources) { + var dateCells = []; + var resourceCells = []; + for (var _i = 0, dates_1 = dates; _i < dates_1.length; _i++) { + var date = dates_1[_i]; + dateCells.push(this.renderDateCell(date, dateFormat, todayRange, resources.length, null, true)); + for (var _a = 0, resources_1 = resources; _a < resources_1.length; _a++) { + var resource = resources_1[_a]; + resourceCells.push(createElement(ResourceCell, { key: resource.id + ':' + date.toISOString(), resource: resource, colSpan: 1, date: date })); + } + } + return (createElement(Fragment, null, + this.buildTr(dateCells, 'day'), + this.buildTr(resourceCells, 'resources'))); + }; + ResourceDayHeader.prototype.renderResourceAndDayRows = function (resources, dates, dateFormat, todayRange) { + var resourceCells = []; + var dateCells = []; + for (var _i = 0, resources_2 = resources; _i < resources_2.length; _i++) { + var resource = resources_2[_i]; + resourceCells.push(createElement(ResourceCell, { key: resource.id, resource: resource, colSpan: dates.length, isSticky: true })); + for (var _a = 0, dates_2 = dates; _a < dates_2.length; _a++) { + var date = dates_2[_a]; + dateCells.push(this.renderDateCell(date, dateFormat, todayRange, 1, resource)); + } + } + return (createElement(Fragment, null, + this.buildTr(resourceCells, 'resources'), + this.buildTr(dateCells, 'day'))); + }; + // a cell with date text. might have a resource associated with it + ResourceDayHeader.prototype.renderDateCell = function (date, dateFormat, todayRange, colSpan, resource, isSticky) { + var props = this.props; + var keyPostfix = resource ? ":" + resource.id : ''; + var extraHookProps = resource ? { resource: new ResourceApi(this.context, resource) } : {}; + var extraDataAttrs = resource ? { 'data-resource-id': resource.id } : {}; + return props.datesRepDistinctDays ? (createElement(TableDateCell, { key: date.toISOString() + keyPostfix, date: date, dateProfile: props.dateProfile, todayRange: todayRange, colCnt: props.dates.length * props.resources.length, dayHeaderFormat: dateFormat, colSpan: colSpan, isSticky: isSticky, extraHookProps: extraHookProps, extraDataAttrs: extraDataAttrs })) : (createElement(TableDowCell // we can't leverage the pure-componentness becausae the extra* props are new every time :( + , { key: date.getUTCDay() + keyPostfix, dow: date.getUTCDay(), dayHeaderFormat: dateFormat, colSpan: colSpan, isSticky: isSticky, extraHookProps: extraHookProps, extraDataAttrs: extraDataAttrs })); + }; + ResourceDayHeader.prototype.buildTr = function (cells, key) { + var renderIntro = this.props.renderIntro; + if (!cells.length) { + cells = [createElement("td", { key: 0 }, "\u00A0")]; + } + return (createElement("tr", { key: key }, + renderIntro && renderIntro(key), + cells)); + }; + return ResourceDayHeader; + }(BaseComponent)); + function buildDateFormat(dayHeaderFormat, datesRepDistinctDays, dayCnt) { + return dayHeaderFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt); + } + + var ResourceIndex = /** @class */ (function () { + function ResourceIndex(resources) { + var indicesById = {}; + var ids = []; + for (var i = 0; i < resources.length; i += 1) { + var id = resources[i].id; + ids.push(id); + indicesById[id] = i; + } + this.ids = ids; + this.indicesById = indicesById; + this.length = resources.length; + } + return ResourceIndex; + }()); + + var AbstractResourceDayTableModel = /** @class */ (function () { + function AbstractResourceDayTableModel(dayTableModel, resources, context) { + this.dayTableModel = dayTableModel; + this.resources = resources; + this.context = context; + this.resourceIndex = new ResourceIndex(resources); + this.rowCnt = dayTableModel.rowCnt; + this.colCnt = dayTableModel.colCnt * resources.length; + this.cells = this.buildCells(); + } + AbstractResourceDayTableModel.prototype.buildCells = function () { + var _a = this, rowCnt = _a.rowCnt, dayTableModel = _a.dayTableModel, resources = _a.resources; + var rows = []; + for (var row = 0; row < rowCnt; row += 1) { + var rowCells = []; + for (var dateCol = 0; dateCol < dayTableModel.colCnt; dateCol += 1) { + for (var resourceCol = 0; resourceCol < resources.length; resourceCol += 1) { + var resource = resources[resourceCol]; + var extraHookProps = { resource: new ResourceApi(this.context, resource) }; + var extraDataAttrs = { 'data-resource-id': resource.id }; + var extraClassNames = ['fc-resource']; + var extraDateSpan = { resourceId: resource.id }; + var date = dayTableModel.cells[row][dateCol].date; + rowCells[this.computeCol(dateCol, resourceCol)] = { + key: resource.id + ':' + date.toISOString(), + date: date, + extraHookProps: extraHookProps, + extraDataAttrs: extraDataAttrs, + extraClassNames: extraClassNames, + extraDateSpan: extraDateSpan, + }; + } + } + rows.push(rowCells); + } + return rows; + }; + return AbstractResourceDayTableModel; + }()); + + /* + resources over dates + */ + var ResourceDayTableModel = /** @class */ (function (_super) { + __extends(ResourceDayTableModel, _super); + function ResourceDayTableModel() { + return _super !== null && _super.apply(this, arguments) || this; + } + ResourceDayTableModel.prototype.computeCol = function (dateI, resourceI) { + return resourceI * this.dayTableModel.colCnt + dateI; + }; + /* + all date ranges are intact + */ + ResourceDayTableModel.prototype.computeColRanges = function (dateStartI, dateEndI, resourceI) { + return [ + { + firstCol: this.computeCol(dateStartI, resourceI), + lastCol: this.computeCol(dateEndI, resourceI), + isStart: true, + isEnd: true, + }, + ]; + }; + return ResourceDayTableModel; + }(AbstractResourceDayTableModel)); + + /* + dates over resources + */ + var DayResourceTableModel = /** @class */ (function (_super) { + __extends(DayResourceTableModel, _super); + function DayResourceTableModel() { + return _super !== null && _super.apply(this, arguments) || this; + } + DayResourceTableModel.prototype.computeCol = function (dateI, resourceI) { + return dateI * this.resources.length + resourceI; + }; + /* + every single day is broken up + */ + DayResourceTableModel.prototype.computeColRanges = function (dateStartI, dateEndI, resourceI) { + var segs = []; + for (var i = dateStartI; i <= dateEndI; i += 1) { + var col = this.computeCol(i, resourceI); + segs.push({ + firstCol: col, + lastCol: col, + isStart: i === dateStartI, + isEnd: i === dateEndI, + }); + } + return segs; + }; + return DayResourceTableModel; + }(AbstractResourceDayTableModel)); + + var NO_SEGS = []; // for memoizing + var VResourceJoiner = /** @class */ (function () { + function VResourceJoiner() { + this.joinDateSelection = memoize(this.joinSegs); + this.joinBusinessHours = memoize(this.joinSegs); + this.joinFgEvents = memoize(this.joinSegs); + this.joinBgEvents = memoize(this.joinSegs); + this.joinEventDrags = memoize(this.joinInteractions); + this.joinEventResizes = memoize(this.joinInteractions); + } + /* + propSets also has a '' key for things with no resource + */ + VResourceJoiner.prototype.joinProps = function (propSets, resourceDayTable) { + var dateSelectionSets = []; + var businessHoursSets = []; + var fgEventSets = []; + var bgEventSets = []; + var eventDrags = []; + var eventResizes = []; + var eventSelection = ''; + var keys = resourceDayTable.resourceIndex.ids.concat(['']); // add in the all-resource key + for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) { + var key = keys_1[_i]; + var props = propSets[key]; + dateSelectionSets.push(props.dateSelectionSegs); + businessHoursSets.push(key ? props.businessHourSegs : NO_SEGS); // don't include redundant all-resource businesshours + fgEventSets.push(key ? props.fgEventSegs : NO_SEGS); // don't include fg all-resource segs + bgEventSets.push(props.bgEventSegs); + eventDrags.push(props.eventDrag); + eventResizes.push(props.eventResize); + eventSelection = eventSelection || props.eventSelection; + } + return { + dateSelectionSegs: this.joinDateSelection.apply(this, __spreadArray([resourceDayTable], dateSelectionSets)), + businessHourSegs: this.joinBusinessHours.apply(this, __spreadArray([resourceDayTable], businessHoursSets)), + fgEventSegs: this.joinFgEvents.apply(this, __spreadArray([resourceDayTable], fgEventSets)), + bgEventSegs: this.joinBgEvents.apply(this, __spreadArray([resourceDayTable], bgEventSets)), + eventDrag: this.joinEventDrags.apply(this, __spreadArray([resourceDayTable], eventDrags)), + eventResize: this.joinEventResizes.apply(this, __spreadArray([resourceDayTable], eventResizes)), + eventSelection: eventSelection, + }; + }; + VResourceJoiner.prototype.joinSegs = function (resourceDayTable) { + var segGroups = []; + for (var _i = 1; _i < arguments.length; _i++) { + segGroups[_i - 1] = arguments[_i]; + } + var resourceCnt = resourceDayTable.resources.length; + var transformedSegs = []; + for (var i = 0; i < resourceCnt; i += 1) { + for (var _a = 0, _b = segGroups[i]; _a < _b.length; _a++) { + var seg = _b[_a]; + transformedSegs.push.apply(transformedSegs, this.transformSeg(seg, resourceDayTable, i)); + } + for (var _c = 0, _d = segGroups[resourceCnt]; _c < _d.length; _c++) { // one beyond. the all-resource + var seg = _d[_c]; + transformedSegs.push.apply(// one beyond. the all-resource + transformedSegs, this.transformSeg(seg, resourceDayTable, i)); + } + } + return transformedSegs; + }; + /* + for expanding non-resource segs to all resources. + only for public use. + no memoizing. + */ + VResourceJoiner.prototype.expandSegs = function (resourceDayTable, segs) { + var resourceCnt = resourceDayTable.resources.length; + var transformedSegs = []; + for (var i = 0; i < resourceCnt; i += 1) { + for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { + var seg = segs_1[_i]; + transformedSegs.push.apply(transformedSegs, this.transformSeg(seg, resourceDayTable, i)); + } + } + return transformedSegs; + }; + VResourceJoiner.prototype.joinInteractions = function (resourceDayTable) { + var interactions = []; + for (var _i = 1; _i < arguments.length; _i++) { + interactions[_i - 1] = arguments[_i]; + } + var resourceCnt = resourceDayTable.resources.length; + var affectedInstances = {}; + var transformedSegs = []; + var anyInteractions = false; + var isEvent = false; + for (var i = 0; i < resourceCnt; i += 1) { + var interaction = interactions[i]; + if (interaction) { + anyInteractions = true; + for (var _a = 0, _b = interaction.segs; _a < _b.length; _a++) { + var seg = _b[_a]; + transformedSegs.push.apply(transformedSegs, this.transformSeg(seg, resourceDayTable, i)); + } + __assign(affectedInstances, interaction.affectedInstances); + isEvent = isEvent || interaction.isEvent; + } + if (interactions[resourceCnt]) { // one beyond. the all-resource + for (var _c = 0, _d = interactions[resourceCnt].segs; _c < _d.length; _c++) { + var seg = _d[_c]; + transformedSegs.push.apply(transformedSegs, this.transformSeg(seg, resourceDayTable, i)); + } + } + } + if (anyInteractions) { + return { + affectedInstances: affectedInstances, + segs: transformedSegs, + isEvent: isEvent, + }; + } + return null; + }; + return VResourceJoiner; + }()); + + /* + TODO: just use ResourceHash somehow? could then use the generic ResourceSplitter + */ + var VResourceSplitter = /** @class */ (function (_super) { + __extends(VResourceSplitter, _super); + function VResourceSplitter() { + return _super !== null && _super.apply(this, arguments) || this; + } + VResourceSplitter.prototype.getKeyInfo = function (props) { + var resourceDayTableModel = props.resourceDayTableModel; + var hash = mapHash(resourceDayTableModel.resourceIndex.indicesById, function (i) { return resourceDayTableModel.resources[i]; }); // :( + hash[''] = {}; + return hash; + }; + VResourceSplitter.prototype.getKeysForDateSpan = function (dateSpan) { + return [dateSpan.resourceId || '']; + }; + VResourceSplitter.prototype.getKeysForEventDef = function (eventDef) { + var resourceIds = eventDef.resourceIds; + if (!resourceIds.length) { + return ['']; + } + return resourceIds; + }; + return VResourceSplitter; + }(Splitter)); + + /* + doesn't accept grouping + */ + function flattenResources(resourceStore, orderSpecs) { + return buildRowNodes(resourceStore, [], orderSpecs, false, {}, true) + .map(function (node) { return node.resource; }); + } + function buildRowNodes(resourceStore, groupSpecs, orderSpecs, isVGrouping, expansions, expansionDefault) { + var complexNodes = buildHierarchy(resourceStore, isVGrouping ? -1 : 1, groupSpecs, orderSpecs); + var flatNodes = []; + flattenNodes(complexNodes, flatNodes, isVGrouping, [], 0, expansions, expansionDefault); + return flatNodes; + } + function flattenNodes(complexNodes, res, isVGrouping, rowSpans, depth, expansions, expansionDefault) { + for (var i = 0; i < complexNodes.length; i += 1) { + var complexNode = complexNodes[i]; + var group = complexNode.group; + if (group) { + if (isVGrouping) { + var firstRowIndex = res.length; + var rowSpanIndex = rowSpans.length; + flattenNodes(complexNode.children, res, isVGrouping, rowSpans.concat(0), depth, expansions, expansionDefault); + if (firstRowIndex < res.length) { + var firstRow = res[firstRowIndex]; + var firstRowSpans = firstRow.rowSpans = firstRow.rowSpans.slice(); + firstRowSpans[rowSpanIndex] = res.length - firstRowIndex; + } + } + else { + var id = group.spec.field + ':' + group.value; + var isExpanded = expansions[id] != null ? expansions[id] : expansionDefault; + res.push({ id: id, group: group, isExpanded: isExpanded }); + if (isExpanded) { + flattenNodes(complexNode.children, res, isVGrouping, rowSpans, depth + 1, expansions, expansionDefault); + } + } + } + else if (complexNode.resource) { + var id = complexNode.resource.id; + var isExpanded = expansions[id] != null ? expansions[id] : expansionDefault; + res.push({ + id: id, + rowSpans: rowSpans, + depth: depth, + isExpanded: isExpanded, + hasChildren: Boolean(complexNode.children.length), + resource: complexNode.resource, + resourceFields: complexNode.resourceFields, + }); + if (isExpanded) { + flattenNodes(complexNode.children, res, isVGrouping, rowSpans, depth + 1, expansions, expansionDefault); + } + } + } + } + function buildHierarchy(resourceStore, maxDepth, groupSpecs, orderSpecs) { + var resourceNodes = buildResourceNodes(resourceStore, orderSpecs); + var builtNodes = []; + for (var resourceId in resourceNodes) { + var resourceNode = resourceNodes[resourceId]; + if (!resourceNode.resource.parentId) { + insertResourceNode(resourceNode, builtNodes, groupSpecs, 0, maxDepth, orderSpecs); + } + } + return builtNodes; + } + function buildResourceNodes(resourceStore, orderSpecs) { + var nodeHash = {}; + for (var resourceId in resourceStore) { + var resource = resourceStore[resourceId]; + nodeHash[resourceId] = { + resource: resource, + resourceFields: buildResourceFields(resource), + children: [], + }; + } + for (var resourceId in resourceStore) { + var resource = resourceStore[resourceId]; + if (resource.parentId) { + var parentNode = nodeHash[resource.parentId]; + if (parentNode) { + insertResourceNodeInSiblings(nodeHash[resourceId], parentNode.children, orderSpecs); + } + } + } + return nodeHash; + } + function insertResourceNode(resourceNode, nodes, groupSpecs, depth, maxDepth, orderSpecs) { + if (groupSpecs.length && (maxDepth === -1 || depth <= maxDepth)) { + var groupNode = ensureGroupNodes(resourceNode, nodes, groupSpecs[0]); + insertResourceNode(resourceNode, groupNode.children, groupSpecs.slice(1), depth + 1, maxDepth, orderSpecs); + } + else { + insertResourceNodeInSiblings(resourceNode, nodes, orderSpecs); + } + } + function ensureGroupNodes(resourceNode, nodes, groupSpec) { + var groupValue = resourceNode.resourceFields[groupSpec.field]; + var groupNode; + var newGroupIndex; + // find an existing group that matches, or determine the position for a new group + if (groupSpec.order) { + for (newGroupIndex = 0; newGroupIndex < nodes.length; newGroupIndex += 1) { + var node = nodes[newGroupIndex]; + if (node.group) { + var cmp = flexibleCompare(groupValue, node.group.value) * groupSpec.order; + if (cmp === 0) { + groupNode = node; + break; + } + else if (cmp < 0) { + break; + } + } + } + } + else { // the groups are unordered + for (newGroupIndex = 0; newGroupIndex < nodes.length; newGroupIndex += 1) { + var node = nodes[newGroupIndex]; + if (node.group && groupValue === node.group.value) { + groupNode = node; + break; + } + } + } + if (!groupNode) { + groupNode = { + group: { + value: groupValue, + spec: groupSpec, + }, + children: [], + }; + nodes.splice(newGroupIndex, 0, groupNode); + } + return groupNode; + } + function insertResourceNodeInSiblings(resourceNode, siblings, orderSpecs) { + var i; + for (i = 0; i < siblings.length; i += 1) { + var cmp = compareByFieldSpecs(siblings[i].resourceFields, resourceNode.resourceFields, orderSpecs); // TODO: pass in ResourceApi? + if (cmp > 0) { // went 1 past. insert at i + break; + } + } + siblings.splice(i, 0, resourceNode); + } + function buildResourceFields(resource) { + var obj = __assign(__assign(__assign({}, resource.extendedProps), resource.ui), resource); + delete obj.ui; + delete obj.extendedProps; + return obj; + } + function isGroupsEqual(group0, group1) { + return group0.spec === group1.spec && group0.value === group1.value; + } + + var resourceCommonPlugin = createPlugin({ + deps: [ + premiumCommonPlugin, + ], + reducers: [ + reduceResources, + ], + isLoadingFuncs: [ + function (state) { return state.resourceSource && state.resourceSource.isFetching; }, + ], + eventRefiners: EVENT_REFINERS, + eventDefMemberAdders: [generateEventDefResourceMembers], + isDraggableTransformers: [transformIsDraggable], + eventDragMutationMassagers: [massageEventDragMutation], + eventDefMutationAppliers: [applyEventDefMutation], + dateSelectionTransformers: [transformDateSelectionJoin], + datePointTransforms: [transformDatePoint], + dateSpanTransforms: [transformDateSpan], + viewPropsTransformers: [ResourceDataAdder, ResourceEventConfigAdder], + isPropsValid: isPropsValidWithResources, + externalDefTransforms: [transformExternalDef], + eventDropTransformers: [transformEventDrop], + optionChangeHandlers: optionChangeHandlers, + optionRefiners: OPTION_REFINERS, + listenerRefiners: LISTENER_REFINERS, + propSetHandlers: { resourceStore: handleResourceStore }, + }); + + var ResourceDayTableJoiner = /** @class */ (function (_super) { + __extends(ResourceDayTableJoiner, _super); + function ResourceDayTableJoiner() { + return _super !== null && _super.apply(this, arguments) || this; + } + ResourceDayTableJoiner.prototype.transformSeg = function (seg, resourceDayTableModel, resourceI) { + var colRanges = resourceDayTableModel.computeColRanges(seg.firstCol, seg.lastCol, resourceI); + return colRanges.map(function (colRange) { return (__assign(__assign(__assign({}, seg), colRange), { isStart: seg.isStart && colRange.isStart, isEnd: seg.isEnd && colRange.isEnd })); }); + }; + return ResourceDayTableJoiner; + }(VResourceJoiner)); + + var ResourceDayTable = /** @class */ (function (_super) { + __extends(ResourceDayTable, _super); + function ResourceDayTable() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.splitter = new VResourceSplitter(); + _this.slicers = {}; + _this.joiner = new ResourceDayTableJoiner(); + _this.tableRef = createRef(); + _this.isHitComboAllowed = function (hit0, hit1) { + var allowAcrossResources = _this.props.resourceDayTableModel.dayTableModel.colCnt === 1; + return allowAcrossResources || hit0.dateSpan.resourceId === hit1.dateSpan.resourceId; + }; + return _this; + } + ResourceDayTable.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var resourceDayTableModel = props.resourceDayTableModel, nextDayThreshold = props.nextDayThreshold, dateProfile = props.dateProfile; + var splitProps = this.splitter.splitProps(props); + this.slicers = mapHash(splitProps, function (split, resourceId) { return _this.slicers[resourceId] || new DayTableSlicer(); }); + var slicedProps = mapHash(this.slicers, function (slicer, resourceId) { return slicer.sliceProps(splitProps[resourceId], dateProfile, nextDayThreshold, context, resourceDayTableModel.dayTableModel); }); + return (createElement(Table, __assign({ forPrint: props.forPrint, ref: this.tableRef }, this.joiner.joinProps(slicedProps, resourceDayTableModel), { cells: resourceDayTableModel.cells, dateProfile: dateProfile, colGroupNode: props.colGroupNode, tableMinWidth: props.tableMinWidth, renderRowIntro: props.renderRowIntro, dayMaxEvents: props.dayMaxEvents, dayMaxEventRows: props.dayMaxEventRows, showWeekNumbers: props.showWeekNumbers, expandRows: props.expandRows, headerAlignElRef: props.headerAlignElRef, clientWidth: props.clientWidth, clientHeight: props.clientHeight, isHitComboAllowed: this.isHitComboAllowed }))); + }; + return ResourceDayTable; + }(DateComponent)); + + var ResourceDayTableView = /** @class */ (function (_super) { + __extends(ResourceDayTableView, _super); + function ResourceDayTableView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.flattenResources = memoize(flattenResources); + _this.buildResourceDayTableModel = memoize(buildResourceDayTableModel); + _this.headerRef = createRef(); + _this.tableRef = createRef(); + return _this; + } + ResourceDayTableView.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var options = context.options; + var resourceOrderSpecs = options.resourceOrder || DEFAULT_RESOURCE_ORDER; + var resources = this.flattenResources(props.resourceStore, resourceOrderSpecs); + var resourceDayTableModel = this.buildResourceDayTableModel(props.dateProfile, context.dateProfileGenerator, resources, options.datesAboveResources, context); + var headerContent = options.dayHeaders && (createElement(ResourceDayHeader, { ref: this.headerRef, resources: resources, dateProfile: props.dateProfile, dates: resourceDayTableModel.dayTableModel.headerDates, datesRepDistinctDays: true })); + var bodyContent = function (contentArg) { return (createElement(ResourceDayTable, { ref: _this.tableRef, dateProfile: props.dateProfile, resourceDayTableModel: resourceDayTableModel, businessHours: props.businessHours, eventStore: props.eventStore, eventUiBases: props.eventUiBases, dateSelection: props.dateSelection, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, nextDayThreshold: options.nextDayThreshold, tableMinWidth: contentArg.tableMinWidth, colGroupNode: contentArg.tableColGroupNode, dayMaxEvents: options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows, showWeekNumbers: options.weekNumbers, expandRows: !props.isHeightAuto, headerAlignElRef: _this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint })); }; + return options.dayMinWidth + ? this.renderHScrollLayout(headerContent, bodyContent, resourceDayTableModel.colCnt, options.dayMinWidth) + : this.renderSimpleLayout(headerContent, bodyContent); + }; + return ResourceDayTableView; + }(TableView)); + function buildResourceDayTableModel(dateProfile, dateProfileGenerator, resources, datesAboveResources, context) { + var dayTable = buildDayTableModel(dateProfile, dateProfileGenerator); + return datesAboveResources ? + new DayResourceTableModel(dayTable, resources, context) : + new ResourceDayTableModel(dayTable, resources, context); + } + + var resourceDayGridPlugin = createPlugin({ + deps: [ + premiumCommonPlugin, + resourceCommonPlugin, + dayGridPlugin, + ], + initialView: 'resourceDayGridDay', + views: { + resourceDayGrid: { + type: 'dayGrid', + component: ResourceDayTableView, + needsResourceData: true, + }, + resourceDayGridDay: { + type: 'resourceDayGrid', + duration: { days: 1 }, + }, + resourceDayGridWeek: { + type: 'resourceDayGrid', + duration: { weeks: 1 }, + }, + resourceDayGridMonth: { + type: 'resourceDayGrid', + duration: { months: 1 }, + // TODO: wish we didn't have to C&P from dayGrid's file + monthMode: true, + fixedWeekCount: true, + }, + }, + }); + + var ResourceDayTimeColsJoiner = /** @class */ (function (_super) { + __extends(ResourceDayTimeColsJoiner, _super); + function ResourceDayTimeColsJoiner() { + return _super !== null && _super.apply(this, arguments) || this; + } + ResourceDayTimeColsJoiner.prototype.transformSeg = function (seg, resourceDayTable, resourceI) { + return [ + __assign(__assign({}, seg), { col: resourceDayTable.computeCol(seg.col, resourceI) }), + ]; + }; + return ResourceDayTimeColsJoiner; + }(VResourceJoiner)); + + var ResourceDayTimeCols = /** @class */ (function (_super) { + __extends(ResourceDayTimeCols, _super); + function ResourceDayTimeCols() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.buildDayRanges = memoize(buildDayRanges); + _this.splitter = new VResourceSplitter(); + _this.slicers = {}; + _this.joiner = new ResourceDayTimeColsJoiner(); + _this.timeColsRef = createRef(); + _this.isHitComboAllowed = function (hit0, hit1) { + var allowAcrossResources = _this.dayRanges.length === 1; + return allowAcrossResources || hit0.dateSpan.resourceId === hit1.dateSpan.resourceId; + }; + return _this; + } + ResourceDayTimeCols.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var dateEnv = context.dateEnv, options = context.options; + var dateProfile = props.dateProfile, resourceDayTableModel = props.resourceDayTableModel; + var dayRanges = this.dayRanges = this.buildDayRanges(resourceDayTableModel.dayTableModel, dateProfile, dateEnv); + var splitProps = this.splitter.splitProps(props); + this.slicers = mapHash(splitProps, function (split, resourceId) { return _this.slicers[resourceId] || new DayTimeColsSlicer(); }); + var slicedProps = mapHash(this.slicers, function (slicer, resourceId) { return slicer.sliceProps(splitProps[resourceId], dateProfile, null, context, dayRanges); }); + return ( // TODO: would move this further down hierarchy, but sliceNowDate needs it + createElement(NowTimer, { unit: options.nowIndicator ? 'minute' : 'day' }, function (nowDate, todayRange) { return (createElement(TimeCols, __assign({ ref: _this.timeColsRef }, _this.joiner.joinProps(slicedProps, resourceDayTableModel), { dateProfile: dateProfile, axis: props.axis, slotDuration: props.slotDuration, slatMetas: props.slatMetas, cells: resourceDayTableModel.cells[0], tableColGroupNode: props.tableColGroupNode, tableMinWidth: props.tableMinWidth, clientWidth: props.clientWidth, clientHeight: props.clientHeight, expandRows: props.expandRows, nowDate: nowDate, nowIndicatorSegs: options.nowIndicator && _this.buildNowIndicatorSegs(nowDate), todayRange: todayRange, onScrollTopRequest: props.onScrollTopRequest, forPrint: props.forPrint, onSlatCoords: props.onSlatCoords, isHitComboAllowed: _this.isHitComboAllowed }))); })); + }; + ResourceDayTimeCols.prototype.buildNowIndicatorSegs = function (date) { + var nonResourceSegs = this.slicers[''].sliceNowDate(date, this.context, this.dayRanges); + return this.joiner.expandSegs(this.props.resourceDayTableModel, nonResourceSegs); + }; + return ResourceDayTimeCols; + }(DateComponent)); + + var ResourceDayTimeColsView = /** @class */ (function (_super) { + __extends(ResourceDayTimeColsView, _super); + function ResourceDayTimeColsView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.flattenResources = memoize(flattenResources); + _this.buildResourceTimeColsModel = memoize(buildResourceTimeColsModel); + _this.buildSlatMetas = memoize(buildSlatMetas); + return _this; + } + ResourceDayTimeColsView.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var options = context.options, dateEnv = context.dateEnv; + var dateProfile = props.dateProfile; + var splitProps = this.allDaySplitter.splitProps(props); + var resourceOrderSpecs = options.resourceOrder || DEFAULT_RESOURCE_ORDER; + var resources = this.flattenResources(props.resourceStore, resourceOrderSpecs); + var resourceDayTableModel = this.buildResourceTimeColsModel(dateProfile, context.dateProfileGenerator, resources, options.datesAboveResources, context); + var slatMetas = this.buildSlatMetas(dateProfile.slotMinTime, dateProfile.slotMaxTime, options.slotLabelInterval, options.slotDuration, dateEnv); + var dayMinWidth = options.dayMinWidth; + var hasAttachedAxis = !dayMinWidth; + var hasDetachedAxis = dayMinWidth; + var headerContent = options.dayHeaders && (createElement(ResourceDayHeader, { resources: resources, dates: resourceDayTableModel.dayTableModel.headerDates, dateProfile: dateProfile, datesRepDistinctDays: true, renderIntro: hasAttachedAxis ? this.renderHeadAxis : null })); + var allDayContent = (options.allDaySlot !== false) && (function (contentArg) { return (createElement(ResourceDayTable, __assign({}, splitProps.allDay, { dateProfile: dateProfile, resourceDayTableModel: resourceDayTableModel, nextDayThreshold: options.nextDayThreshold, tableMinWidth: contentArg.tableMinWidth, colGroupNode: contentArg.tableColGroupNode, renderRowIntro: hasAttachedAxis ? _this.renderTableRowAxis : null, showWeekNumbers: false, expandRows: false, headerAlignElRef: _this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint }, _this.getAllDayMaxEventProps()))); }); + var timeGridContent = function (contentArg) { return (createElement(ResourceDayTimeCols, __assign({}, splitProps.timed, { dateProfile: dateProfile, axis: hasAttachedAxis, slotDuration: options.slotDuration, slatMetas: slatMetas, resourceDayTableModel: resourceDayTableModel, tableColGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, onSlatCoords: _this.handleSlatCoords, expandRows: contentArg.expandRows, forPrint: props.forPrint, onScrollTopRequest: _this.handleScrollTopRequest }))); }; + return hasDetachedAxis + ? this.renderHScrollLayout(headerContent, allDayContent, timeGridContent, resourceDayTableModel.colCnt, dayMinWidth, slatMetas, this.state.slatCoords) + : this.renderSimpleLayout(headerContent, allDayContent, timeGridContent); + }; + return ResourceDayTimeColsView; + }(TimeColsView)); + function buildResourceTimeColsModel(dateProfile, dateProfileGenerator, resources, datesAboveResources, context) { + var dayTable = buildTimeColsModel(dateProfile, dateProfileGenerator); + return datesAboveResources ? + new DayResourceTableModel(dayTable, resources, context) : + new ResourceDayTableModel(dayTable, resources, context); + } + + var resourceTimeGridPlugin = createPlugin({ + deps: [ + premiumCommonPlugin, + resourceCommonPlugin, + timeGridPlugin, + ], + initialView: 'resourceTimeGridDay', + views: { + resourceTimeGrid: { + type: 'timeGrid', + component: ResourceDayTimeColsView, + needsResourceData: true, + }, + resourceTimeGridDay: { + type: 'resourceTimeGrid', + duration: { days: 1 }, + }, + resourceTimeGridWeek: { + type: 'resourceTimeGrid', + duration: { weeks: 1 }, + }, + }, + }); + + /* + Renders the DOM responsible for the subrow expander area, + as well as the space before it (used to align expanders of similar depths) + */ + function ExpanderIcon(_a) { + var depth = _a.depth, hasChildren = _a.hasChildren, isExpanded = _a.isExpanded, onExpanderClick = _a.onExpanderClick; + var nodes = []; + for (var i = 0; i < depth; i += 1) { + nodes.push(createElement("span", { className: "fc-icon" })); + } + var iconClassNames = ['fc-icon']; + if (hasChildren) { + if (isExpanded) { + iconClassNames.push('fc-icon-minus-square'); + } + else { + iconClassNames.push('fc-icon-plus-square'); + } + } + nodes.push(createElement("span", { className: 'fc-datagrid-expander' + (hasChildren ? '' : ' fc-datagrid-expander-placeholder'), onClick: onExpanderClick }, + createElement("span", { className: iconClassNames.join(' ') }))); + return createElement.apply(void 0, __spreadArray([Fragment, {}], nodes)); + } + + function refineHookProps$1(raw) { + return { + resource: new ResourceApi(raw.context, raw.resource), + fieldValue: raw.fieldValue, + view: raw.context.viewApi, + }; + } + + var SpreadsheetIndividualCellInner = /** @class */ (function (_super) { + __extends(SpreadsheetIndividualCellInner, _super); + function SpreadsheetIndividualCellInner() { + return _super !== null && _super.apply(this, arguments) || this; + } + SpreadsheetIndividualCellInner.prototype.render = function () { + var props = this.props; + return (createElement(ContentHook, { hookProps: props.hookProps, content: props.colSpec.cellContent, defaultContent: renderResourceInner }, function (innerElRef, innerContent) { return (createElement("span", { className: "fc-datagrid-cell-main", ref: innerElRef }, innerContent)); })); + }; + return SpreadsheetIndividualCellInner; + }(BaseComponent)); + function renderResourceInner(hookProps) { + return hookProps.fieldValue || createElement(Fragment, null, "\u00A0"); + } + + // worth making a PureComponent? (because of innerHeight) + var SpreadsheetIndividualCell = /** @class */ (function (_super) { + __extends(SpreadsheetIndividualCell, _super); + function SpreadsheetIndividualCell() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.refineHookProps = memoizeObjArg(refineHookProps$1); + _this.normalizeClassNames = buildClassNameNormalizer(); + _this.onExpanderClick = function (ev) { + var props = _this.props; + if (props.hasChildren) { + _this.context.dispatch({ + type: 'SET_RESOURCE_ENTITY_EXPANDED', + id: props.resource.id, + isExpanded: !props.isExpanded, + }); + } + }; + return _this; + } + SpreadsheetIndividualCell.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var colSpec = props.colSpec; + var hookProps = this.refineHookProps({ + resource: props.resource, + fieldValue: props.fieldValue, + context: context, + }); + var customClassNames = this.normalizeClassNames(colSpec.cellClassNames, hookProps); + return (createElement(MountHook, { hookProps: hookProps, didMount: colSpec.cellDidMount, willUnmount: colSpec.cellWillUnmount }, function (rootElRef) { return (createElement("td", { ref: rootElRef, "data-resource-id": props.resource.id, className: [ + 'fc-datagrid-cell', + 'fc-resource', + ].concat(customClassNames).join(' ') }, + createElement("div", { className: "fc-datagrid-cell-frame", style: { height: props.innerHeight } }, + createElement("div", { className: "fc-datagrid-cell-cushion fc-scrollgrid-sync-inner" }, + colSpec.isMain && (createElement(ExpanderIcon, { depth: props.depth, hasChildren: props.hasChildren, isExpanded: props.isExpanded, onExpanderClick: _this.onExpanderClick })), + createElement(SpreadsheetIndividualCellInner, { hookProps: hookProps, colSpec: colSpec }))))); })); + }; + return SpreadsheetIndividualCell; + }(BaseComponent)); + + // for VERTICAL cell grouping, in spreadsheet area + var SpreadsheetGroupCell = /** @class */ (function (_super) { + __extends(SpreadsheetGroupCell, _super); + function SpreadsheetGroupCell() { + return _super !== null && _super.apply(this, arguments) || this; + } + SpreadsheetGroupCell.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var colSpec = props.colSpec; + var hookProps = { + groupValue: props.fieldValue, + view: context.viewApi, + }; + // a grouped cell. no data that is specific to this specific resource + // `colSpec` is for the group. a GroupSpec :( + return (createElement(RenderHook, { hookProps: hookProps, classNames: colSpec.cellClassNames, content: colSpec.cellContent, defaultContent: renderGroupInner, didMount: colSpec.cellDidMount, willUnmount: colSpec.cellWillUnmount }, function (rootElRef, classNames, innerElRef, innerContent) { return ( + // TODO: make data-attr with group value? + createElement("td", { className: ['fc-datagrid-cell', 'fc-resource-group'].concat(classNames).join(' '), rowSpan: props.rowSpan, ref: rootElRef }, + createElement("div", { className: "fc-datagrid-cell-frame fc-datagrid-cell-frame-liquid" }, + createElement("div", { className: "fc-datagrid-cell-cushion fc-sticky", ref: innerElRef }, innerContent)))); })); + }; + return SpreadsheetGroupCell; + }(BaseComponent)); + function renderGroupInner(hookProps) { + return hookProps.groupValue || createElement(Fragment, null, "\u00A0"); + } + + var SpreadsheetRow = /** @class */ (function (_super) { + __extends(SpreadsheetRow, _super); + function SpreadsheetRow() { + return _super !== null && _super.apply(this, arguments) || this; + } + SpreadsheetRow.prototype.render = function () { + var props = this.props; + var resource = props.resource, rowSpans = props.rowSpans, depth = props.depth; + var resourceFields = buildResourceFields(resource); // slightly inefficient. already done up the call stack + return (createElement("tr", null, props.colSpecs.map(function (colSpec, i) { + var rowSpan = rowSpans[i]; + if (rowSpan === 0) { // not responsible for group-based rows. VRowGroup is + return null; + } + if (rowSpan == null) { + rowSpan = 1; + } + var fieldValue = colSpec.field ? resourceFields[colSpec.field] : + (resource.title || getPublicId(resource.id)); + if (rowSpan > 1) { + return (createElement(SpreadsheetGroupCell, { key: i, colSpec: colSpec, fieldValue: fieldValue, rowSpan: rowSpan })); + } + return (createElement(SpreadsheetIndividualCell, { key: i, colSpec: colSpec, resource: resource, fieldValue: fieldValue, depth: depth, hasChildren: props.hasChildren, isExpanded: props.isExpanded, innerHeight: props.innerHeight })); + }))); + }; + return SpreadsheetRow; + }(BaseComponent)); + SpreadsheetRow.addPropsEquality({ + rowSpans: isArraysEqual, + }); + + // for HORIZONTAL cell grouping, in spreadsheet area + var SpreadsheetGroupRow = /** @class */ (function (_super) { + __extends(SpreadsheetGroupRow, _super); + function SpreadsheetGroupRow() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.innerInnerRef = createRef(); + _this.onExpanderClick = function () { + var props = _this.props; + _this.context.dispatch({ + type: 'SET_RESOURCE_ENTITY_EXPANDED', + id: props.id, + isExpanded: !props.isExpanded, + }); + }; + return _this; + } + SpreadsheetGroupRow.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var hookProps = { groupValue: props.group.value, view: context.viewApi }; + var spec = props.group.spec; + return (createElement("tr", null, + createElement(RenderHook, { hookProps: hookProps, classNames: spec.labelClassNames, content: spec.labelContent, defaultContent: renderCellInner, didMount: spec.labelDidMount, willUnmount: spec.labelWillUnmount }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("td", { ref: rootElRef, colSpan: props.spreadsheetColCnt, className: [ + 'fc-datagrid-cell', + 'fc-resource-group', + context.theme.getClass('tableCellShaded'), + ].concat(classNames).join(' ') }, + createElement("div", { className: "fc-datagrid-cell-frame", style: { height: props.innerHeight } }, + createElement("div", { className: "fc-datagrid-cell-cushion fc-scrollgrid-sync-inner", ref: _this.innerInnerRef }, + createElement(ExpanderIcon, { depth: 0, hasChildren: true, isExpanded: props.isExpanded, onExpanderClick: _this.onExpanderClick }), + createElement("span", { className: "fc-datagrid-cell-main", ref: innerElRef }, innerContent))))); }))); + }; + return SpreadsheetGroupRow; + }(BaseComponent)); + SpreadsheetGroupRow.addPropsEquality({ + group: isGroupsEqual, + }); + function renderCellInner(hookProps) { + return hookProps.groupValue || createElement(Fragment, null, "\u00A0"); + } + + var SPREADSHEET_COL_MIN_WIDTH = 20; + var SpreadsheetHeader = /** @class */ (function (_super) { + __extends(SpreadsheetHeader, _super); + function SpreadsheetHeader() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.resizerElRefs = new RefMap(_this._handleColResizerEl.bind(_this)); + _this.colDraggings = {}; + return _this; + } + SpreadsheetHeader.prototype.render = function () { + var _this = this; + var _a = this.props, colSpecs = _a.colSpecs, superHeaderRendering = _a.superHeaderRendering, rowInnerHeights = _a.rowInnerHeights; + var hookProps = { view: this.context.viewApi }; + var rowNodes = []; + rowInnerHeights = rowInnerHeights.slice(); // copy, because we're gonna pop + if (superHeaderRendering) { + var rowInnerHeight_1 = rowInnerHeights.shift(); + rowNodes.push(createElement("tr", { key: "row-super" }, + createElement(RenderHook, { hookProps: hookProps, classNames: superHeaderRendering.headerClassNames, content: superHeaderRendering.headerContent, didMount: superHeaderRendering.headerDidMount, willUnmount: superHeaderRendering.headerWillUnmount }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("th", { colSpan: colSpecs.length, ref: rootElRef, className: [ + 'fc-datagrid-cell', + 'fc-datagrid-cell-super', + ].concat(classNames).join(' ') }, + createElement("div", { className: "fc-datagrid-cell-frame", style: { height: rowInnerHeight_1 } }, + createElement("div", { className: "fc-datagrid-cell-cushion fc-scrollgrid-sync-inner", ref: innerElRef }, innerContent)))); }))); + } + var rowInnerHeight = rowInnerHeights.shift(); + rowNodes.push(createElement("tr", { key: "row" }, colSpecs.map(function (colSpec, i) { + var isLastCol = i === (colSpecs.length - 1); + // need empty inner div for abs positioning for resizer + return (createElement(RenderHook, { key: i, hookProps: hookProps, classNames: colSpec.headerClassNames, content: colSpec.headerContent, didMount: colSpec.headerDidMount, willUnmount: colSpec.headerWillUnmount }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("th", { ref: rootElRef, className: ['fc-datagrid-cell'].concat(classNames).join(' ') }, + createElement("div", { className: "fc-datagrid-cell-frame", style: { height: rowInnerHeight } }, + createElement("div", { className: "fc-datagrid-cell-cushion fc-scrollgrid-sync-inner" }, + colSpec.isMain && (createElement("span", { className: "fc-datagrid-expander fc-datagrid-expander-placeholder" }, + createElement("span", { className: "fc-icon" }))), + createElement("span", { className: "fc-datagrid-cell-main", ref: innerElRef }, innerContent)), + !isLastCol && + createElement("div", { className: "fc-datagrid-cell-resizer", ref: _this.resizerElRefs.createRef(i) })))); })); + }))); + return (createElement(Fragment, null, rowNodes)); + }; + SpreadsheetHeader.prototype._handleColResizerEl = function (resizerEl, index) { + var colDraggings = this.colDraggings; + if (!resizerEl) { + var dragging = colDraggings[index]; + if (dragging) { + dragging.destroy(); + delete colDraggings[index]; + } + } + else { + var dragging = this.initColResizing(resizerEl, parseInt(index, 10)); + if (dragging) { + colDraggings[index] = dragging; + } + } + }; + SpreadsheetHeader.prototype.initColResizing = function (resizerEl, index) { + var _a = this.context, pluginHooks = _a.pluginHooks, isRtl = _a.isRtl; + var onColWidthChange = this.props.onColWidthChange; + var ElementDraggingImpl = pluginHooks.elementDraggingImpl; + if (ElementDraggingImpl) { + var dragging = new ElementDraggingImpl(resizerEl); + var startWidth_1; // of just the single column + var currentWidths_1; // of all columns + dragging.emitter.on('dragstart', function () { + var allCells = findElements(elementClosest(resizerEl, 'tr'), 'th'); + currentWidths_1 = allCells.map(function (cellEl) { return (cellEl.getBoundingClientRect().width); }); + startWidth_1 = currentWidths_1[index]; + }); + dragging.emitter.on('dragmove', function (pev) { + currentWidths_1[index] = Math.max(startWidth_1 + pev.deltaX * (isRtl ? -1 : 1), SPREADSHEET_COL_MIN_WIDTH); + if (onColWidthChange) { + onColWidthChange(currentWidths_1.slice()); // send a copy since currentWidths continues to be mutated + } + }); + dragging.setAutoScrollEnabled(false); // because gets weird with auto-scrolling time area + return dragging; + } + return null; + }; + return SpreadsheetHeader; + }(BaseComponent)); + + var ResourceTimelineLaneMisc = /** @class */ (function (_super) { + __extends(ResourceTimelineLaneMisc, _super); + function ResourceTimelineLaneMisc() { + return _super !== null && _super.apply(this, arguments) || this; + } + ResourceTimelineLaneMisc.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var hookProps = { resource: new ResourceApi(context, props.resource) }; // just easier to make directly + return (createElement(ContentHook, { hookProps: hookProps, content: context.options.resourceLaneContent }, function (innerElRef, innerContent) { return (innerContent && // TODO: test how this would interfere with height + createElement("div", { className: "fc-timeline-lane-misc", ref: innerElRef }, innerContent)); })); + }; + return ResourceTimelineLaneMisc; + }(BaseComponent)); + + var ResourceTimelineLane = /** @class */ (function (_super) { + __extends(ResourceTimelineLane, _super); + function ResourceTimelineLane() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.refineHookProps = memoizeObjArg(refineHookProps); + _this.normalizeClassNames = buildClassNameNormalizer(); + _this.handleHeightChange = function (innerEl, isStable) { + if (_this.props.onHeightChange) { + _this.props.onHeightChange( + // would want to use own ref, but not guaranteed to be ready when this fires + elementClosest(innerEl, 'tr'), isStable); + } + }; + return _this; + } + ResourceTimelineLane.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, context = _a.context; + var options = context.options; + var hookProps = this.refineHookProps({ resource: props.resource, context: context }); + var customClassNames = this.normalizeClassNames(options.resourceLaneClassNames, hookProps); + return (createElement("tr", { ref: props.elRef }, + createElement(MountHook, { hookProps: hookProps, didMount: options.resourceLaneDidMount, willUnmount: options.resourceLaneWillUnmount }, function (rootElRef) { return (createElement("td", { ref: rootElRef, className: ['fc-timeline-lane', 'fc-resource'].concat(customClassNames).join(' '), "data-resource-id": props.resource.id }, + createElement("div", { className: "fc-timeline-lane-frame", style: { height: props.innerHeight } }, + createElement(ResourceTimelineLaneMisc, { resource: props.resource }), + createElement(TimelineLane, { dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, nowDate: props.nowDate, todayRange: props.todayRange, nextDayThreshold: props.nextDayThreshold, businessHours: props.businessHours, eventStore: props.eventStore, eventUiBases: props.eventUiBases, dateSelection: props.dateSelection, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, timelineCoords: props.timelineCoords, onHeightChange: _this.handleHeightChange, resourceId: props.resource.id })))); }))); // important NOT to do liquid-height. dont want to shrink height smaller than content + }; + return ResourceTimelineLane; + }(BaseComponent)); + function refineHookProps(raw) { + return { + resource: new ResourceApi(raw.context, raw.resource), + }; + } + + /* + parallels the SpreadsheetGroupRow + */ + var DividerRow = /** @class */ (function (_super) { + __extends(DividerRow, _super); + function DividerRow() { + return _super !== null && _super.apply(this, arguments) || this; + } + DividerRow.prototype.render = function () { + var _this = this; + var props = this.props; + var renderingHooks = this.props.renderingHooks; + var hookProps = { groupValue: props.groupValue, view: this.context.viewApi }; + return (createElement("tr", { ref: props.elRef }, + createElement(RenderHook, { hookProps: hookProps, classNames: renderingHooks.laneClassNames, content: renderingHooks.laneContent, didMount: renderingHooks.laneDidMount, willUnmount: renderingHooks.laneWillUnmount }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("td", { ref: rootElRef, className: [ + 'fc-timeline-lane', + 'fc-resource-group', + _this.context.theme.getClass('tableCellShaded'), + ].concat(classNames).join(' ') }, + createElement("div", { style: { height: props.innerHeight }, ref: innerElRef }, innerContent))); }))); + }; + return DividerRow; + }(BaseComponent)); + + var ResourceTimelineLanesBody = /** @class */ (function (_super) { + __extends(ResourceTimelineLanesBody, _super); + function ResourceTimelineLanesBody() { + return _super !== null && _super.apply(this, arguments) || this; + } + ResourceTimelineLanesBody.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + var rowElRefs = props.rowElRefs, innerHeights = props.innerHeights; + return (createElement("tbody", null, props.rowNodes.map(function (node, index) { + if (node.group) { + return (createElement(DividerRow, { key: node.id, elRef: rowElRefs.createRef(node.id), groupValue: node.group.value, renderingHooks: node.group.spec, innerHeight: innerHeights[index] || '' })); + } + if (node.resource) { + var resource = node.resource; + return (createElement(ResourceTimelineLane, __assign({ key: node.id, elRef: rowElRefs.createRef(node.id) }, props.splitProps[resource.id], { resource: resource, dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, nowDate: props.nowDate, todayRange: props.todayRange, nextDayThreshold: context.options.nextDayThreshold, businessHours: resource.businessHours || props.fallbackBusinessHours, innerHeight: innerHeights[index] || '', timelineCoords: props.slatCoords, onHeightChange: props.onRowHeightChange }))); + } + return null; + }))); + }; + return ResourceTimelineLanesBody; + }(BaseComponent)); + + var ResourceTimelineLanes = /** @class */ (function (_super) { + __extends(ResourceTimelineLanes, _super); + function ResourceTimelineLanes() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.rootElRef = createRef(); + _this.rowElRefs = new RefMap(); + return _this; + } + ResourceTimelineLanes.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + return (createElement("table", { ref: this.rootElRef, className: 'fc-scrollgrid-sync-table ' + context.theme.getClass('table'), style: { + minWidth: props.tableMinWidth, + width: props.clientWidth, + height: props.minHeight, + } }, + createElement(ResourceTimelineLanesBody, { rowElRefs: this.rowElRefs, rowNodes: props.rowNodes, dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, nowDate: props.nowDate, todayRange: props.todayRange, splitProps: props.splitProps, fallbackBusinessHours: props.fallbackBusinessHours, slatCoords: props.slatCoords, innerHeights: props.innerHeights, onRowHeightChange: props.onRowHeightChange }))); + }; + ResourceTimelineLanes.prototype.componentDidMount = function () { + this.updateCoords(); + }; + ResourceTimelineLanes.prototype.componentDidUpdate = function () { + this.updateCoords(); + }; + ResourceTimelineLanes.prototype.componentWillUnmount = function () { + if (this.props.onRowCoords) { + this.props.onRowCoords(null); + } + }; + ResourceTimelineLanes.prototype.updateCoords = function () { + var props = this.props; + if (props.onRowCoords && props.clientWidth !== null) { // a populated clientWidth means sizing has stabilized + this.props.onRowCoords(new PositionCache(this.rootElRef.current, collectRowEls(this.rowElRefs.currentMap, props.rowNodes), false, true)); + } + }; + return ResourceTimelineLanes; + }(BaseComponent)); + function collectRowEls(elMap, rowNodes) { + return rowNodes.map(function (rowNode) { return elMap[rowNode.id]; }); + } + + var ResourceTimelineGrid = /** @class */ (function (_super) { + __extends(ResourceTimelineGrid, _super); + function ResourceTimelineGrid() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.computeHasResourceBusinessHours = memoize(computeHasResourceBusinessHours); + _this.resourceSplitter = new ResourceSplitter(); // doesn't let it do businessHours tho + _this.bgSlicer = new TimelineLaneSlicer(); + _this.slatsRef = createRef(); // needed for Hit creation :( + _this.state = { + slatCoords: null, + }; + _this.handleEl = function (el) { + if (el) { + _this.context.registerInteractiveComponent(_this, { el: el }); + } + else { + _this.context.unregisterInteractiveComponent(_this); + } + }; + _this.handleSlatCoords = function (slatCoords) { + _this.setState({ slatCoords: slatCoords }); + if (_this.props.onSlatCoords) { + _this.props.onSlatCoords(slatCoords); + } + }; + _this.handleRowCoords = function (rowCoords) { + _this.rowCoords = rowCoords; + if (_this.props.onRowCoords) { + _this.props.onRowCoords(rowCoords); + } + }; + return _this; + } + ResourceTimelineGrid.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, state = _a.state, context = _a.context; + var dateProfile = props.dateProfile, tDateProfile = props.tDateProfile; + var timerUnit = greatestDurationDenominator(tDateProfile.slotDuration).unit; + var hasResourceBusinessHours = this.computeHasResourceBusinessHours(props.rowNodes); + var splitProps = this.resourceSplitter.splitProps(props); + var bgLaneProps = splitProps['']; + var bgSlicedProps = this.bgSlicer.sliceProps(bgLaneProps, dateProfile, tDateProfile.isTimeScale ? null : props.nextDayThreshold, context, // wish we didn't need to pass in the rest of these args... + dateProfile, context.dateProfileGenerator, tDateProfile, context.dateEnv); + // WORKAROUND: make ignore slatCoords when out of sync with dateProfile + var slatCoords = state.slatCoords && state.slatCoords.dateProfile === props.dateProfile ? state.slatCoords : null; + return (createElement("div", { ref: this.handleEl, className: [ + 'fc-timeline-body', + props.expandRows ? 'fc-timeline-body-expandrows' : '', + ].join(' '), style: { minWidth: props.tableMinWidth } }, + createElement(NowTimer, { unit: timerUnit }, function (nowDate, todayRange) { return (createElement(Fragment, null, + createElement(TimelineSlats, { ref: _this.slatsRef, dateProfile: dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange, clientWidth: props.clientWidth, tableColGroupNode: props.tableColGroupNode, tableMinWidth: props.tableMinWidth, onCoords: _this.handleSlatCoords, onScrollLeftRequest: props.onScrollLeftRequest }), + createElement(TimelineLaneBg, { businessHourSegs: hasResourceBusinessHours ? null : bgSlicedProps.businessHourSegs, bgEventSegs: bgSlicedProps.bgEventSegs, timelineCoords: slatCoords, + // empty array will result in unnecessary rerenders? + eventResizeSegs: (bgSlicedProps.eventResize ? bgSlicedProps.eventResize.segs : []), dateSelectionSegs: bgSlicedProps.dateSelectionSegs, nowDate: nowDate, todayRange: todayRange }), + createElement(ResourceTimelineLanes, { rowNodes: props.rowNodes, dateProfile: dateProfile, tDateProfile: props.tDateProfile, nowDate: nowDate, todayRange: todayRange, splitProps: splitProps, fallbackBusinessHours: hasResourceBusinessHours ? props.businessHours : null, clientWidth: props.clientWidth, minHeight: props.expandRows ? props.clientHeight : '', tableMinWidth: props.tableMinWidth, innerHeights: props.rowInnerHeights, slatCoords: slatCoords, onRowCoords: _this.handleRowCoords, onRowHeightChange: props.onRowHeightChange }), + (context.options.nowIndicator && slatCoords && slatCoords.isDateInRange(nowDate)) && (createElement("div", { className: "fc-timeline-now-indicator-container" }, + createElement(NowIndicatorRoot, { isAxis: false, date: nowDate }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("div", { ref: rootElRef, className: ['fc-timeline-now-indicator-line'].concat(classNames).join(' '), style: coordToCss(slatCoords.dateToCoord(nowDate), context.isRtl) }, innerContent)); }))))); }))); + }; + // Hit System + // ------------------------------------------------------------------------------------------ + ResourceTimelineGrid.prototype.queryHit = function (positionLeft, positionTop) { + var rowCoords = this.rowCoords; + var rowIndex = rowCoords.topToIndex(positionTop); + if (rowIndex != null) { + var resource = this.props.rowNodes[rowIndex].resource; + if (resource) { // not a group + var slatHit = this.slatsRef.current.positionToHit(positionLeft); + if (slatHit) { + return { + dateProfile: this.props.dateProfile, + dateSpan: { + range: slatHit.dateSpan.range, + allDay: slatHit.dateSpan.allDay, + resourceId: resource.id, + }, + rect: { + left: slatHit.left, + right: slatHit.right, + top: rowCoords.tops[rowIndex], + bottom: rowCoords.bottoms[rowIndex], + }, + dayEl: slatHit.dayEl, + layer: 0, + }; + } + } + } + return null; + }; + return ResourceTimelineGrid; + }(DateComponent)); + function computeHasResourceBusinessHours(rowNodes) { + for (var _i = 0, rowNodes_1 = rowNodes; _i < rowNodes_1.length; _i++) { + var node = rowNodes_1[_i]; + var resource = node.resource; + if (resource && resource.businessHours) { + return true; + } + } + return false; + } + + var MIN_RESOURCE_AREA_WIDTH = 30; // definitely bigger than scrollbars + // RENAME? + var ResourceTimelineViewLayout = /** @class */ (function (_super) { + __extends(ResourceTimelineViewLayout, _super); + function ResourceTimelineViewLayout() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.scrollGridRef = createRef(); + _this.timeBodyScrollerElRef = createRef(); + _this.spreadsheetHeaderChunkElRef = createRef(); + _this.rootElRef = createRef(); + _this.ensureScrollGridResizeId = 0; + _this.state = { + resourceAreaWidthOverride: null, + }; + /* + ghetto debounce. don't race with ScrollGrid's resizing delay. solves #6140 + */ + _this.ensureScrollGridResize = function () { + if (_this.ensureScrollGridResizeId) { + clearTimeout(_this.ensureScrollGridResizeId); + } + _this.ensureScrollGridResizeId = setTimeout(function () { + _this.scrollGridRef.current.handleSizing(false); + }, config.SCROLLGRID_RESIZE_INTERVAL + 1); + }; + return _this; + } + ResourceTimelineViewLayout.prototype.render = function () { + var _a = this, props = _a.props, state = _a.state, context = _a.context; + var options = context.options; + var stickyHeaderDates = !props.forPrint && getStickyHeaderDates(options); + var stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(options); + var sections = [ + { + type: 'header', + key: 'header', + syncRowHeights: true, + isSticky: stickyHeaderDates, + chunks: [ + { + key: 'datagrid', + elRef: this.spreadsheetHeaderChunkElRef, + // TODO: allow the content to specify this. have general-purpose 'content' with obj with keys + tableClassName: 'fc-datagrid-header', + rowContent: props.spreadsheetHeaderRows, + }, + { + key: 'divider', + outerContent: (createElement("td", { className: 'fc-resource-timeline-divider ' + context.theme.getClass('tableCellShaded') })), + }, + { + key: 'timeline', + content: props.timeHeaderContent, + }, + ], + }, + { + type: 'body', + key: 'body', + syncRowHeights: true, + liquid: true, + expandRows: Boolean(options.expandRows), + chunks: [ + { + key: 'datagrid', + tableClassName: 'fc-datagrid-body', + rowContent: props.spreadsheetBodyRows, + }, + { + key: 'divider', + outerContent: (createElement("td", { className: 'fc-resource-timeline-divider ' + context.theme.getClass('tableCellShaded') })), + }, + { + key: 'timeline', + scrollerElRef: this.timeBodyScrollerElRef, + content: props.timeBodyContent, + }, + ], + }, + ]; + if (stickyFooterScrollbar) { + sections.push({ + type: 'footer', + key: 'footer', + isSticky: true, + chunks: [ + { + key: 'datagrid', + content: renderScrollShim, + }, + { + key: 'divider', + outerContent: (createElement("td", { className: 'fc-resource-timeline-divider ' + context.theme.getClass('tableCellShaded') })), + }, + { + key: 'timeline', + content: renderScrollShim, + }, + ], + }); + } + var resourceAreaWidth = state.resourceAreaWidthOverride != null + ? state.resourceAreaWidthOverride + : options.resourceAreaWidth; + return (createElement(ScrollGrid, { ref: this.scrollGridRef, elRef: this.rootElRef, liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: false, colGroups: [ + { cols: props.spreadsheetCols, width: resourceAreaWidth }, + { cols: [] }, + { cols: props.timeCols }, + ], sections: sections })); + }; + ResourceTimelineViewLayout.prototype.forceTimeScroll = function (left) { + var scrollGrid = this.scrollGridRef.current; + scrollGrid.forceScrollLeft(2, left); // 2 = the time area + }; + ResourceTimelineViewLayout.prototype.forceResourceScroll = function (top) { + var scrollGrid = this.scrollGridRef.current; + scrollGrid.forceScrollTop(1, top); // 1 = the body + }; + ResourceTimelineViewLayout.prototype.getResourceScroll = function () { + var timeBodyScrollerEl = this.timeBodyScrollerElRef.current; + return timeBodyScrollerEl.scrollTop; + }; + // Resource Area Resizing + // ------------------------------------------------------------------------------------------ + // NOTE: a callback Ref for the resizer was firing multiple times with same elements (Preact) + // that's why we use spreadsheetResizerElRef instead + ResourceTimelineViewLayout.prototype.componentDidMount = function () { + this.initSpreadsheetResizing(); + }; + ResourceTimelineViewLayout.prototype.componentWillUnmount = function () { + this.destroySpreadsheetResizing(); + }; + ResourceTimelineViewLayout.prototype.initSpreadsheetResizing = function () { + var _this = this; + var _a = this.context, isRtl = _a.isRtl, pluginHooks = _a.pluginHooks; + var ElementDraggingImpl = pluginHooks.elementDraggingImpl; + var spreadsheetHeadEl = this.spreadsheetHeaderChunkElRef.current; + if (ElementDraggingImpl) { + var rootEl_1 = this.rootElRef.current; + var dragging = this.spreadsheetResizerDragging = new ElementDraggingImpl(rootEl_1, '.fc-resource-timeline-divider'); + var dragStartWidth_1; + var viewWidth_1; + dragging.emitter.on('dragstart', function () { + dragStartWidth_1 = spreadsheetHeadEl.getBoundingClientRect().width; + viewWidth_1 = rootEl_1.getBoundingClientRect().width; + }); + dragging.emitter.on('dragmove', function (pev) { + var newWidth = dragStartWidth_1 + pev.deltaX * (isRtl ? -1 : 1); + newWidth = Math.max(newWidth, MIN_RESOURCE_AREA_WIDTH); + newWidth = Math.min(newWidth, viewWidth_1 - MIN_RESOURCE_AREA_WIDTH); + // scrollgrid will ignore resize requests if there are too many :| + _this.setState({ + resourceAreaWidthOverride: newWidth, + }, _this.ensureScrollGridResize); + }); + dragging.setAutoScrollEnabled(false); // because gets weird with auto-scrolling time area + } + }; + ResourceTimelineViewLayout.prototype.destroySpreadsheetResizing = function () { + if (this.spreadsheetResizerDragging) { + this.spreadsheetResizerDragging.destroy(); + } + }; + return ResourceTimelineViewLayout; + }(BaseComponent)); + + var ResourceTimelineView = /** @class */ (function (_super) { + __extends(ResourceTimelineView, _super); + function ResourceTimelineView(props, context) { + var _this = _super.call(this, props, context) || this; + _this.processColOptions = memoize(processColOptions); + _this.buildTimelineDateProfile = memoize(buildTimelineDateProfile); + _this.hasNesting = memoize(hasNesting); + _this.buildRowNodes = memoize(buildRowNodes); + _this.layoutRef = createRef(); + _this.rowNodes = []; + _this.renderedRowNodes = []; + _this.buildRowIndex = memoize(buildRowIndex); + _this.handleSlatCoords = function (slatCoords) { + _this.setState({ slatCoords: slatCoords }); + }; + _this.handleRowCoords = function (rowCoords) { + _this.rowCoords = rowCoords; + _this.scrollResponder.update(false); // TODO: could eliminate this if rowCoords lived in state + }; + _this.handleMaxCushionWidth = function (slotCushionMaxWidth) { + _this.setState({ + slotCushionMaxWidth: Math.ceil(slotCushionMaxWidth), // for less rerendering TODO: DRY + }); + }; + // Scrolling + // ------------------------------------------------------------------------------------------------------------------ + // this is useful for scrolling prev/next dates while resource is scrolled down + _this.handleScrollLeftRequest = function (scrollLeft) { + var layout = _this.layoutRef.current; + layout.forceTimeScroll(scrollLeft); + }; + _this.handleScrollRequest = function (request) { + var rowCoords = _this.rowCoords; + var layout = _this.layoutRef.current; + var rowId = request.rowId || request.resourceId; + if (rowCoords) { + if (rowId) { + var rowIdToIndex = _this.buildRowIndex(_this.renderedRowNodes); + var index = rowIdToIndex[rowId]; + if (index != null) { + var scrollTop = (request.fromBottom != null ? + rowCoords.bottoms[index] - request.fromBottom : // pixels from bottom edge + rowCoords.tops[index] // just use top edge + ); + layout.forceResourceScroll(scrollTop); + } + } + return true; + } + return null; + }; + // Resource INDIVIDUAL-Column Area Resizing + // ------------------------------------------------------------------------------------------ + _this.handleColWidthChange = function (colWidths) { + _this.setState({ + spreadsheetColWidths: colWidths, + }); + }; + _this.state = { + resourceAreaWidth: context.options.resourceAreaWidth, + spreadsheetColWidths: [], + }; + return _this; + } + ResourceTimelineView.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, state = _a.state, context = _a.context; + var options = context.options, viewSpec = context.viewSpec; + var _b = this.processColOptions(context.options), superHeaderRendering = _b.superHeaderRendering, groupSpecs = _b.groupSpecs, orderSpecs = _b.orderSpecs, isVGrouping = _b.isVGrouping, colSpecs = _b.colSpecs; + var tDateProfile = this.buildTimelineDateProfile(props.dateProfile, context.dateEnv, options, context.dateProfileGenerator); + var rowNodes = this.rowNodes = this.buildRowNodes(props.resourceStore, groupSpecs, orderSpecs, isVGrouping, props.resourceEntityExpansions, options.resourcesInitiallyExpanded); + var extraClassNames = [ + 'fc-resource-timeline', + this.hasNesting(rowNodes) ? '' : 'fc-resource-timeline-flat', + 'fc-timeline', + options.eventOverlap === false ? 'fc-timeline-overlap-disabled' : 'fc-timeline-overlap-enabled', + ]; + var slotMinWidth = options.slotMinWidth; + var slatCols = buildSlatCols(tDateProfile, slotMinWidth || this.computeFallbackSlotMinWidth(tDateProfile)); + return (createElement(ViewRoot, { viewSpec: viewSpec }, function (rootElRef, classNames) { return (createElement("div", { ref: rootElRef, className: extraClassNames.concat(classNames).join(' ') }, + createElement(ResourceTimelineViewLayout, { ref: _this.layoutRef, forPrint: props.forPrint, isHeightAuto: props.isHeightAuto, spreadsheetCols: buildSpreadsheetCols(colSpecs, state.spreadsheetColWidths, ''), spreadsheetHeaderRows: function (contentArg) { return (createElement(SpreadsheetHeader // TODO: rename to SpreadsheetHeaderRows + , { superHeaderRendering: superHeaderRendering, colSpecs: colSpecs, onColWidthChange: _this.handleColWidthChange, rowInnerHeights: contentArg.rowSyncHeights })); }, spreadsheetBodyRows: function (contentArg) { return (createElement(Fragment, null, _this.renderSpreadsheetRows(rowNodes, colSpecs, contentArg.rowSyncHeights))); }, timeCols: slatCols, timeHeaderContent: function (contentArg) { return (createElement(TimelineHeader, { clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, tableMinWidth: contentArg.tableMinWidth, tableColGroupNode: contentArg.tableColGroupNode, dateProfile: props.dateProfile, tDateProfile: tDateProfile, slatCoords: state.slatCoords, rowInnerHeights: contentArg.rowSyncHeights, onMaxCushionWidth: slotMinWidth ? null : _this.handleMaxCushionWidth })); }, timeBodyContent: function (contentArg) { return (createElement(ResourceTimelineGrid, { dateProfile: props.dateProfile, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, tableMinWidth: contentArg.tableMinWidth, tableColGroupNode: contentArg.tableColGroupNode, expandRows: contentArg.expandRows, tDateProfile: tDateProfile, rowNodes: rowNodes, businessHours: props.businessHours, dateSelection: props.dateSelection, eventStore: props.eventStore, eventUiBases: props.eventUiBases, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, resourceStore: props.resourceStore, nextDayThreshold: context.options.nextDayThreshold, rowInnerHeights: contentArg.rowSyncHeights, onSlatCoords: _this.handleSlatCoords, onRowCoords: _this.handleRowCoords, onScrollLeftRequest: _this.handleScrollLeftRequest, onRowHeightChange: contentArg.reportRowHeightChange })); } }))); })); + }; + ResourceTimelineView.prototype.renderSpreadsheetRows = function (nodes, colSpecs, rowSyncHeights) { + return nodes.map(function (node, index) { + if (node.group) { + return (createElement(SpreadsheetGroupRow, { key: node.id, id: node.id, spreadsheetColCnt: colSpecs.length, isExpanded: node.isExpanded, group: node.group, innerHeight: rowSyncHeights[index] || '' })); + } + if (node.resource) { + return (createElement(SpreadsheetRow, { key: node.id, colSpecs: colSpecs, rowSpans: node.rowSpans, depth: node.depth, isExpanded: node.isExpanded, hasChildren: node.hasChildren, resource: node.resource, innerHeight: rowSyncHeights[index] || '' })); + } + return null; + }); + }; + ResourceTimelineView.prototype.componentDidMount = function () { + this.renderedRowNodes = this.rowNodes; + this.scrollResponder = this.context.createScrollResponder(this.handleScrollRequest); + }; + ResourceTimelineView.prototype.getSnapshotBeforeUpdate = function () { + if (!this.props.forPrint) { // because print-view is always zero? + return { resourceScroll: this.queryResourceScroll() }; + } + return {}; + }; + ResourceTimelineView.prototype.componentDidUpdate = function (prevProps, prevState, snapshot) { + this.renderedRowNodes = this.rowNodes; + this.scrollResponder.update(prevProps.dateProfile !== this.props.dateProfile); + if (snapshot.resourceScroll) { + this.handleScrollRequest(snapshot.resourceScroll); // TODO: this gets triggered too often + } + }; + ResourceTimelineView.prototype.componentWillUnmount = function () { + this.scrollResponder.detach(); + }; + ResourceTimelineView.prototype.computeFallbackSlotMinWidth = function (tDateProfile) { + return Math.max(30, ((this.state.slotCushionMaxWidth || 0) / tDateProfile.slotsPerLabel)); + }; + ResourceTimelineView.prototype.queryResourceScroll = function () { + var _a = this, rowCoords = _a.rowCoords, renderedRowNodes = _a.renderedRowNodes; + if (rowCoords) { + var layout = this.layoutRef.current; + var trBottoms = rowCoords.bottoms; + var scrollTop = layout.getResourceScroll(); + var scroll_1 = {}; + for (var i = 0; i < trBottoms.length; i += 1) { + var rowNode = renderedRowNodes[i]; + var elBottom = trBottoms[i] - scrollTop; // from the top of the scroller + if (elBottom > 0) { + scroll_1.rowId = rowNode.id; + scroll_1.fromBottom = elBottom; + break; + } + } + return scroll_1; + } + return null; + }; + return ResourceTimelineView; + }(BaseComponent)); + ResourceTimelineView.addStateEquality({ + spreadsheetColWidths: isArraysEqual, + }); + function buildRowIndex(rowNodes) { + var rowIdToIndex = {}; + for (var i = 0; i < rowNodes.length; i += 1) { + rowIdToIndex[rowNodes[i].id] = i; + } + return rowIdToIndex; + } + function buildSpreadsheetCols(colSpecs, forcedWidths, fallbackWidth) { + if (fallbackWidth === void 0) { fallbackWidth = ''; } + return colSpecs.map(function (colSpec, i) { return ({ + className: colSpec.isMain ? 'fc-main-col' : '', + width: forcedWidths[i] || colSpec.width || fallbackWidth, + }); }); + } + function hasNesting(nodes) { + for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) { + var node = nodes_1[_i]; + if (node.group) { + return true; + } + if (node.resource) { + if (node.hasChildren) { + return true; + } + } + } + return false; + } + function processColOptions(options) { + var allColSpecs = options.resourceAreaColumns || []; + var superHeaderRendering = null; + if (!allColSpecs.length) { + allColSpecs.push({ + headerClassNames: options.resourceAreaHeaderClassNames, + headerContent: options.resourceAreaHeaderContent || 'Resources', + headerDidMount: options.resourceAreaHeaderDidMount, + headerWillUnmount: options.resourceAreaHeaderWillUnmount, + }); + } + else if (options.resourceAreaHeaderContent) { // weird way to determine if content + superHeaderRendering = { + headerClassNames: options.resourceAreaHeaderClassNames, + headerContent: options.resourceAreaHeaderContent, + headerDidMount: options.resourceAreaHeaderDidMount, + headerWillUnmount: options.resourceAreaHeaderWillUnmount, + }; + } + var plainColSpecs = []; + var groupColSpecs = []; // part of the colSpecs, but filtered out in order to put first + var groupSpecs = []; + var isVGrouping = false; + for (var _i = 0, allColSpecs_1 = allColSpecs; _i < allColSpecs_1.length; _i++) { + var colSpec = allColSpecs_1[_i]; + if (colSpec.group) { + groupColSpecs.push(__assign(__assign({}, colSpec), { cellClassNames: colSpec.cellClassNames || options.resourceGroupLabelClassNames, cellContent: colSpec.cellContent || options.resourceGroupLabelContent, cellDidMount: colSpec.cellDidMount || options.resourceGroupLabelDidMount, cellWillUnmount: colSpec.cellWillUnmount || options.resourceGroupLaneWillUnmount })); + } + else { + plainColSpecs.push(colSpec); + } + } + // BAD: mutates a user-supplied option + var mainColSpec = plainColSpecs[0]; + mainColSpec.isMain = true; + mainColSpec.cellClassNames = mainColSpec.cellClassNames || options.resourceLabelClassNames; + mainColSpec.cellContent = mainColSpec.cellContent || options.resourceLabelContent; + mainColSpec.cellDidMount = mainColSpec.cellDidMount || options.resourceLabelDidMount; + mainColSpec.cellWillUnmount = mainColSpec.cellWillUnmount || options.resourceLabelWillUnmount; + if (groupColSpecs.length) { + groupSpecs = groupColSpecs; + isVGrouping = true; + } + else { + var hGroupField = options.resourceGroupField; + if (hGroupField) { + groupSpecs.push({ + field: hGroupField, + labelClassNames: options.resourceGroupLabelClassNames, + labelContent: options.resourceGroupLabelContent, + labelDidMount: options.resourceGroupLabelDidMount, + labelWillUnmount: options.resourceGroupLabelWillUnmount, + laneClassNames: options.resourceGroupLaneClassNames, + laneContent: options.resourceGroupLaneContent, + laneDidMount: options.resourceGroupLaneDidMount, + laneWillUnmount: options.resourceGroupLaneWillUnmount, + }); + } + } + var allOrderSpecs = options.resourceOrder || DEFAULT_RESOURCE_ORDER; + var plainOrderSpecs = []; + for (var _a = 0, allOrderSpecs_1 = allOrderSpecs; _a < allOrderSpecs_1.length; _a++) { + var orderSpec = allOrderSpecs_1[_a]; + var isGroup = false; + for (var _b = 0, groupSpecs_1 = groupSpecs; _b < groupSpecs_1.length; _b++) { + var groupSpec = groupSpecs_1[_b]; + if (groupSpec.field === orderSpec.field) { + groupSpec.order = orderSpec.order; // -1, 0, 1 + isGroup = true; + break; + } + } + if (!isGroup) { + plainOrderSpecs.push(orderSpec); + } + } + return { + superHeaderRendering: superHeaderRendering, + isVGrouping: isVGrouping, + groupSpecs: groupSpecs, + colSpecs: groupColSpecs.concat(plainColSpecs), + orderSpecs: plainOrderSpecs, + }; + } + + var resourceTimelinePlugin = createPlugin({ + deps: [ + premiumCommonPlugin, + resourceCommonPlugin, + timelinePlugin, + ], + initialView: 'resourceTimelineDay', + views: { + resourceTimeline: { + type: 'timeline', + component: ResourceTimelineView, + needsResourceData: true, + resourceAreaWidth: '30%', + resourcesInitiallyExpanded: true, + eventResizableFromStart: true, // TODO: not DRY with this same setting in the main timeline config + }, + resourceTimelineDay: { + type: 'resourceTimeline', + duration: { days: 1 }, + }, + resourceTimelineWeek: { + type: 'resourceTimeline', + duration: { weeks: 1 }, + }, + resourceTimelineMonth: { + type: 'resourceTimeline', + duration: { months: 1 }, + }, + resourceTimelineYear: { + type: 'resourceTimeline', + duration: { years: 1 }, + }, + }, + }); + + globalPlugins.push(interactionPlugin, dayGridPlugin, timeGridPlugin, listPlugin, plugin, googleCalendarPlugin, scrollGridPlugin, adaptivePlugin, timelinePlugin, resourceCommonPlugin, resourceDayGridPlugin, resourceTimeGridPlugin, resourceTimelinePlugin); + + exports.AbstractResourceDayTableModel = AbstractResourceDayTableModel; + exports.BASE_OPTION_DEFAULTS = BASE_OPTION_DEFAULTS; + exports.BASE_OPTION_REFINERS = BASE_OPTION_REFINERS; + exports.BaseComponent = BaseComponent; + exports.BgEvent = BgEvent; + exports.BootstrapTheme = BootstrapTheme; + exports.Calendar = Calendar; + exports.CalendarApi = CalendarApi; + exports.CalendarContent = CalendarContent; + exports.CalendarDataManager = CalendarDataManager; + exports.CalendarDataProvider = CalendarDataProvider; + exports.CalendarRoot = CalendarRoot; + exports.Component = Component; + exports.ContentHook = ContentHook; + exports.CustomContentRenderContext = CustomContentRenderContext; + exports.DEFAULT_RESOURCE_ORDER = DEFAULT_RESOURCE_ORDER; + exports.DateComponent = DateComponent; + exports.DateEnv = DateEnv; + exports.DateProfileGenerator = DateProfileGenerator; + exports.DayCellContent = DayCellContent; + exports.DayCellRoot = DayCellRoot; + exports.DayGridView = DayTableView; + exports.DayHeader = DayHeader; + exports.DayResourceTableModel = DayResourceTableModel; + exports.DaySeriesModel = DaySeriesModel; + exports.DayTable = DayTable; + exports.DayTableModel = DayTableModel; + exports.DayTableSlicer = DayTableSlicer; + exports.DayTimeCols = DayTimeCols; + exports.DayTimeColsSlicer = DayTimeColsSlicer; + exports.DayTimeColsView = DayTimeColsView; + exports.DelayedRunner = DelayedRunner; + exports.Draggable = ExternalDraggable; + exports.ElementDragging = ElementDragging; + exports.ElementScrollController = ElementScrollController; + exports.Emitter = Emitter; + exports.EventApi = EventApi; + exports.EventRoot = EventRoot; + exports.EventSourceApi = EventSourceApi; + exports.FeaturefulElementDragging = FeaturefulElementDragging; + exports.Fragment = Fragment; + exports.Interaction = Interaction; + exports.ListView = ListView; + exports.MoreLinkRoot = MoreLinkRoot; + exports.MountHook = MountHook; + exports.NamedTimeZoneImpl = NamedTimeZoneImpl; + exports.NowIndicatorRoot = NowIndicatorRoot; + exports.NowTimer = NowTimer; + exports.PointerDragging = PointerDragging; + exports.PositionCache = PositionCache; + exports.RefMap = RefMap; + exports.RenderHook = RenderHook; + exports.ResourceApi = ResourceApi; + exports.ResourceDayHeader = ResourceDayHeader; + exports.ResourceDayTable = ResourceDayTable; + exports.ResourceDayTableModel = ResourceDayTableModel; + exports.ResourceDayTableView = ResourceDayTableView; + exports.ResourceDayTimeCols = ResourceDayTimeCols; + exports.ResourceDayTimeColsView = ResourceDayTimeColsView; + exports.ResourceLabelRoot = ResourceLabelRoot; + exports.ResourceSplitter = ResourceSplitter; + exports.ResourceTimelineLane = ResourceTimelineLane; + exports.ResourceTimelineView = ResourceTimelineView; + exports.ScrollController = ScrollController; + exports.ScrollGrid = ScrollGrid; + exports.ScrollResponder = ScrollResponder; + exports.Scroller = Scroller; + exports.SegHierarchy = SegHierarchy; + exports.SimpleScrollGrid = SimpleScrollGrid; + exports.Slicer = Slicer; + exports.Splitter = Splitter; + exports.SpreadsheetRow = SpreadsheetRow; + exports.StandardEvent = StandardEvent; + exports.Table = Table; + exports.TableDateCell = TableDateCell; + exports.TableDowCell = TableDowCell; + exports.TableView = TableView; + exports.Theme = Theme; + exports.ThirdPartyDraggable = ThirdPartyDraggable; + exports.TimeCols = TimeCols; + exports.TimeColsSlatsCoords = TimeColsSlatsCoords; + exports.TimeColsView = TimeColsView; + exports.TimelineCoords = TimelineCoords; + exports.TimelineHeader = TimelineHeader; + exports.TimelineHeaderRows = TimelineHeaderRows; + exports.TimelineLane = TimelineLane; + exports.TimelineLaneBg = TimelineLaneBg; + exports.TimelineLaneSlicer = TimelineLaneSlicer; + exports.TimelineSlats = TimelineSlats; + exports.TimelineView = TimelineView; + exports.VResourceJoiner = VResourceJoiner; + exports.VResourceSplitter = VResourceSplitter; + exports.ViewApi = ViewApi; + exports.ViewContextType = ViewContextType; + exports.ViewRoot = ViewRoot; + exports.WeekNumberRoot = WeekNumberRoot; + exports.WindowScrollController = WindowScrollController; + exports.addDays = addDays; + exports.addDurations = addDurations; + exports.addMs = addMs; + exports.addWeeks = addWeeks; + exports.allowContextMenu = allowContextMenu; + exports.allowSelection = allowSelection; + exports.applyMutationToEventStore = applyMutationToEventStore; + exports.applyStyle = applyStyle; + exports.applyStyleProp = applyStyleProp; + exports.asCleanDays = asCleanDays; + exports.asRoughMinutes = asRoughMinutes; + exports.asRoughMs = asRoughMs; + exports.asRoughSeconds = asRoughSeconds; + exports.binarySearch = binarySearch; + exports.buildClassNameNormalizer = buildClassNameNormalizer; + exports.buildDayRanges = buildDayRanges; + exports.buildDayTableModel = buildDayTableModel; + exports.buildEntryKey = buildEntryKey; + exports.buildEventApis = buildEventApis; + exports.buildEventRangeKey = buildEventRangeKey; + exports.buildHashFromArray = buildHashFromArray; + exports.buildIsoString = buildIsoString; + exports.buildNavLinkData = buildNavLinkData; + exports.buildResourceFields = buildResourceFields; + exports.buildRowNodes = buildRowNodes; + exports.buildSegCompareObj = buildSegCompareObj; + exports.buildSegTimeText = buildSegTimeText; + exports.buildSlatCols = buildSlatCols; + exports.buildSlatMetas = buildSlatMetas; + exports.buildTimeColsModel = buildTimeColsModel; + exports.buildTimelineDateProfile = buildTimelineDateProfile; + exports.collectFromHash = collectFromHash; + exports.combineEventUis = combineEventUis; + exports.compareByFieldSpec = compareByFieldSpec; + exports.compareByFieldSpecs = compareByFieldSpecs; + exports.compareNumbers = compareNumbers; + exports.compareObjs = compareObjs; + exports.computeEarliestSegStart = computeEarliestSegStart; + exports.computeEdges = computeEdges; + exports.computeFallbackHeaderFormat = computeFallbackHeaderFormat; + exports.computeHeightAndMargins = computeHeightAndMargins; + exports.computeInnerRect = computeInnerRect; + exports.computeRect = computeRect; + exports.computeSegDraggable = computeSegDraggable; + exports.computeSegEndResizable = computeSegEndResizable; + exports.computeSegStartResizable = computeSegStartResizable; + exports.computeShrinkWidth = computeShrinkWidth; + exports.computeSmallestCellWidth = computeSmallestCellWidth; + exports.computeVisibleDayRange = computeVisibleDayRange; + exports.config = config; + exports.constrainPoint = constrainPoint; + exports.coordToCss = coordToCss; + exports.coordsToCss = coordsToCss; + exports.createContext = createContext; + exports.createDuration = createDuration; + exports.createElement = createElement; + exports.createEmptyEventStore = createEmptyEventStore; + exports.createEventInstance = createEventInstance; + exports.createEventUi = createEventUi; + exports.createFormatter = createFormatter; + exports.createPlugin = createPlugin; + exports.createPortal = createPortal; + exports.createRef = createRef; + exports.diffDates = diffDates; + exports.diffDayAndTime = diffDayAndTime; + exports.diffDays = diffDays; + exports.diffPoints = diffPoints; + exports.diffWeeks = diffWeeks; + exports.diffWholeDays = diffWholeDays; + exports.diffWholeWeeks = diffWholeWeeks; + exports.disableCursor = disableCursor; + exports.elementClosest = elementClosest; + exports.elementMatches = elementMatches; + exports.enableCursor = enableCursor; + exports.eventTupleToStore = eventTupleToStore; + exports.filterEventStoreDefs = filterEventStoreDefs; + exports.filterHash = filterHash; + exports.findDirectChildren = findDirectChildren; + exports.findElements = findElements; + exports.flattenResources = flattenResources; + exports.flexibleCompare = flexibleCompare; + exports.flushToDom = flushToDom; + exports.formatDate = formatDate; + exports.formatDayString = formatDayString; + exports.formatIsoTimeString = formatIsoTimeString; + exports.formatRange = formatRange; + exports.getAllowYScrolling = getAllowYScrolling; + exports.getCanVGrowWithinCell = getCanVGrowWithinCell; + exports.getClippingParents = getClippingParents; + exports.getDateMeta = getDateMeta; + exports.getDayClassNames = getDayClassNames; + exports.getDefaultEventEnd = getDefaultEventEnd; + exports.getElSeg = getElSeg; + exports.getEntrySpanEnd = getEntrySpanEnd; + exports.getEventClassNames = getEventClassNames; + exports.getIsRtlScrollbarOnLeft = getIsRtlScrollbarOnLeft; + exports.getPublicId = getPublicId; + exports.getRectCenter = getRectCenter; + exports.getRelevantEvents = getRelevantEvents; + exports.getScrollGridClassNames = getScrollGridClassNames; + exports.getScrollbarWidths = getScrollbarWidths; + exports.getSectionClassNames = getSectionClassNames; + exports.getSectionHasLiquidHeight = getSectionHasLiquidHeight; + exports.getSegMeta = getSegMeta; + exports.getSlotClassNames = getSlotClassNames; + exports.getStickyFooterScrollbar = getStickyFooterScrollbar; + exports.getStickyHeaderDates = getStickyHeaderDates; + exports.getUnequalProps = getUnequalProps; + exports.globalLocales = globalLocales; + exports.globalPlugins = globalPlugins; + exports.greatestDurationDenominator = greatestDurationDenominator; + exports.groupIntersectingEntries = groupIntersectingEntries; + exports.guid = guid; + exports.hasBgRendering = hasBgRendering; + exports.hasShrinkWidth = hasShrinkWidth; + exports.identity = identity; + exports.interactionSettingsStore = interactionSettingsStore; + exports.interactionSettingsToStore = interactionSettingsToStore; + exports.intersectRanges = intersectRanges; + exports.intersectRects = intersectRects; + exports.intersectSpans = intersectSpans; + exports.isArraysEqual = isArraysEqual; + exports.isColPropsEqual = isColPropsEqual; + exports.isDateSelectionValid = isDateSelectionValid; + exports.isDateSpansEqual = isDateSpansEqual; + exports.isGroupsEqual = isGroupsEqual; + exports.isInt = isInt; + exports.isInteractionValid = isInteractionValid; + exports.isMultiDayRange = isMultiDayRange; + exports.isPropsEqual = isPropsEqual; + exports.isPropsValid = isPropsValid; + exports.isValidDate = isValidDate$1; + exports.joinSpans = joinSpans; + exports.listenBySelector = listenBySelector; + exports.mapHash = mapHash; + exports.memoize = memoize; + exports.memoizeArraylike = memoizeArraylike; + exports.memoizeHashlike = memoizeHashlike; + exports.memoizeObjArg = memoizeObjArg; + exports.mergeEventStores = mergeEventStores; + exports.multiplyDuration = multiplyDuration; + exports.padStart = padStart; + exports.parseBusinessHours = parseBusinessHours; + exports.parseClassNames = parseClassNames; + exports.parseDragMeta = parseDragMeta; + exports.parseEventDef = parseEventDef; + exports.parseFieldSpecs = parseFieldSpecs; + exports.parseMarker = parse; + exports.pointInsideRect = pointInsideRect; + exports.preventContextMenu = preventContextMenu; + exports.preventDefault = preventDefault; + exports.preventSelection = preventSelection; + exports.rangeContainsMarker = rangeContainsMarker; + exports.rangeContainsRange = rangeContainsRange; + exports.rangesEqual = rangesEqual; + exports.rangesIntersect = rangesIntersect; + exports.refineEventDef = refineEventDef; + exports.refineProps = refineProps; + exports.removeElement = removeElement; + exports.removeExact = removeExact; + exports.render = render; + exports.renderChunkContent = renderChunkContent; + exports.renderFill = renderFill; + exports.renderMicroColGroup = renderMicroColGroup; + exports.renderScrollShim = renderScrollShim; + exports.requestJson = requestJson; + exports.sanitizeShrinkWidth = sanitizeShrinkWidth; + exports.setElSeg = setElSeg; + exports.setRef = setRef; + exports.setScrollFromLeftEdge = setScrollFromLeftEdge; + exports.sliceEventStore = sliceEventStore; + exports.sliceEvents = sliceEvents; + exports.sortEventSegs = sortEventSegs; + exports.startOfDay = startOfDay; + exports.translateRect = translateRect; + exports.triggerDateSelect = triggerDateSelect; + exports.unmountComponentAtNode = unmountComponentAtNode; + exports.unpromisify = unpromisify; + exports.version = version; + exports.whenTransitionDone = whenTransitionDone; + exports.wholeDivideDurations = wholeDivideDurations; + + Object.defineProperty(exports, '__esModule', { value: true }); + + return exports; + +}({})); diff --git a/app/assets/javascripts/property_hire_fullcalendar.min.js b/app/assets/javascripts/property_hire_fullcalendar.min.js index c3e0834..a85e2e0 100644 --- a/app/assets/javascripts/property_hire_fullcalendar.min.js +++ b/app/assets/javascripts/property_hire_fullcalendar.min.js @@ -1,7 +1,19 @@ /*! - * FullCalendar v1.6.1 - * Docs & License: http://arshaw.com/fullcalendar/ - * (c) 2013 Adam Shaw - */ -(function(t,e){function n(e){t.extend(!0,ye,e)}function r(n,r,l){function u(t){G?(S(),C(),R(),b(t)):f()}function f(){K=r.theme?"ui":"fc",n.addClass("fc"),r.isRTL?n.addClass("fc-rtl"):n.addClass("fc-ltr"),r.theme&&n.addClass("ui-widget"),G=t("
").prependTo(n),$=new a(Z,r),Q=$.render(),Q&&n.prepend(Q),y(r.defaultView),t(window).resize(x),m()||v()}function v(){setTimeout(function(){!te.start&&m()&&b()},0)}function h(){t(window).unbind("resize",x),$.destroy(),G.remove(),n.removeClass("fc fc-rtl ui-widget")}function g(){return 0!==se.offsetWidth}function m(){return 0!==t("body")[0].offsetWidth}function y(e){if(!te||e!=te.name){ue++,W();var n,r=te;r?((r.beforeHide||I)(),q(G,G.height()),r.element.hide()):q(G,1),G.css("overflow","hidden"),te=ce[e],te?te.element.show():te=ce[e]=new De[e](n=re=t("
").appendTo(G),Z),r&&$.deactivateButton(r.name),$.activateButton(e),b(),G.css("overflow",""),r&&q(G,1),n||(te.afterShow||I)(),ue--}}function b(t){if(g()){ue++,W(),ne===e&&S();var r=!1;!te.start||t||te.start>fe||fe>=te.end?(te.render(fe,t||0),E(!0),r=!0):te.sizeDirty?(te.clearEvents(),E(),r=!0):te.eventsDirty&&(te.clearEvents(),r=!0),te.sizeDirty=!1,te.eventsDirty=!1,T(r),ee=n.outerWidth(),$.updateTitle(te.title);var a=new Date;a>=te.start&&te.end>a?$.disableButton("today"):$.enableButton("today"),ue--,te.trigger("viewDisplay",se)}}function M(){C(),g()&&(S(),E(),W(),te.clearEvents(),te.renderEvents(de),te.sizeDirty=!1)}function C(){t.each(ce,function(t,e){e.sizeDirty=!0})}function S(){ne=r.contentHeight?r.contentHeight:r.height?r.height-(Q?Q.height():0)-L(G):Math.round(G.width()/Math.max(r.aspectRatio,.5))}function E(t){ue++,te.setHeight(ne,t),re&&(re.css("position","relative"),re=null),te.setWidth(G.width(),t),ue--}function x(){if(!ue)if(te.start){var t=++le;setTimeout(function(){t==le&&!ue&&g()&&ee!=(ee=n.outerWidth())&&(ue++,M(),te.trigger("windowResize",se),ue--)},200)}else v()}function T(t){!r.lazyFetching||oe(te.visStart,te.visEnd)?k():t&&F()}function k(){ie(te.visStart,te.visEnd)}function H(t){de=t,F()}function z(t){F(t)}function F(t){R(),g()&&(te.clearEvents(),te.renderEvents(de,t),te.eventsDirty=!1)}function R(){t.each(ce,function(t,e){e.eventsDirty=!0})}function N(t,n,r){te.select(t,n,r===e?!0:r)}function W(){te&&te.unselect()}function A(){b(-1)}function _(){b(1)}function O(){i(fe,-1),b()}function B(){i(fe,1),b()}function Y(){fe=new Date,b()}function j(t,e,n){t instanceof Date?fe=d(t):p(fe,t,e,n),b()}function P(t,n,r){t!==e&&i(fe,t),n!==e&&s(fe,n),r!==e&&c(fe,r),b()}function J(){return d(fe)}function V(){return te}function X(t,n){return n===e?r[t]:(("height"==t||"contentHeight"==t||"aspectRatio"==t)&&(r[t]=n,M()),e)}function U(t,n){return r[t]?r[t].apply(n||se,Array.prototype.slice.call(arguments,2)):e}var Z=this;Z.options=r,Z.render=u,Z.destroy=h,Z.refetchEvents=k,Z.reportEvents=H,Z.reportEventChange=z,Z.rerenderEvents=F,Z.changeView=y,Z.select=N,Z.unselect=W,Z.prev=A,Z.next=_,Z.prevYear=O,Z.nextYear=B,Z.today=Y,Z.gotoDate=j,Z.incrementDate=P,Z.formatDate=function(t,e){return w(t,e,r)},Z.formatDates=function(t,e,n){return D(t,e,n,r)},Z.getDate=J,Z.getView=V,Z.option=X,Z.trigger=U,o.call(Z,r,l);var $,Q,G,K,te,ee,ne,re,ae,oe=Z.isFetchNeeded,ie=Z.fetchEvents,se=n[0],ce={},le=0,ue=0,fe=new Date,de=[];p(fe,r.year,r.month,r.date),r.droppable&&t(document).bind("dragstart",function(e,n){var a=e.target,o=t(a);if(!o.parents(".fc").length){var i=r.dropAccept;(t.isFunction(i)?i.call(a,o):o.is(i))&&(ae=a,te.dragStart(ae,e,n))}}).bind("dragstop",function(t,e){ae&&(te.dragStop(ae,t,e),ae=null)})}function a(n,r){function a(){v=r.theme?"ui":"fc";var n=r.header;return n?h=t("
/ elements with colspans. + SOLUTION: making individual
+ _this.frameElRefs = new RefMap(); // the fc-daygrid-day-frame + _this.fgElRefs = new RefMap(); // the fc-daygrid-day-events + _this.segHarnessRefs = new RefMap(); // indexed by "instanceId:firstCol" + _this.rootElRef = createRef(); + _this.state = { + framePositions: null, + maxContentHeight: null, + eventInstanceHeights: {}, + }; + return _this; + } + TableRow.prototype.render = function () { + var _this = this; + var _a = this, props = _a.props, state = _a.state, context = _a.context; + var options = context.options; + var colCnt = props.cells.length; + var businessHoursByCol = splitSegsByFirstCol(props.businessHourSegs, colCnt); + var bgEventSegsByCol = splitSegsByFirstCol(props.bgEventSegs, colCnt); + var highlightSegsByCol = splitSegsByFirstCol(this.getHighlightSegs(), colCnt); + var mirrorSegsByCol = splitSegsByFirstCol(this.getMirrorSegs(), colCnt); + var _b = computeFgSegPlacement(sortEventSegs(props.fgEventSegs, options.eventOrder), props.dayMaxEvents, props.dayMaxEventRows, options.eventOrderStrict, state.eventInstanceHeights, state.maxContentHeight, props.cells), singleColPlacements = _b.singleColPlacements, multiColPlacements = _b.multiColPlacements, moreCnts = _b.moreCnts, moreMarginTops = _b.moreMarginTops; + var isForcedInvisible = // TODO: messy way to compute this + (props.eventDrag && props.eventDrag.affectedInstances) || + (props.eventResize && props.eventResize.affectedInstances) || + {}; + return (createElement("tr", { ref: this.rootElRef }, + props.renderIntro && props.renderIntro(), + props.cells.map(function (cell, col) { + var normalFgNodes = _this.renderFgSegs(col, props.forPrint ? singleColPlacements[col] : multiColPlacements[col], props.todayRange, isForcedInvisible); + var mirrorFgNodes = _this.renderFgSegs(col, buildMirrorPlacements$1(mirrorSegsByCol[col], multiColPlacements), props.todayRange, {}, Boolean(props.eventDrag), Boolean(props.eventResize), false); + return (createElement(TableCell, { key: cell.key, elRef: _this.cellElRefs.createRef(cell.key), innerElRef: _this.frameElRefs.createRef(cell.key) /* FF problem, but okay to use for left/right. TODO: rename prop */, dateProfile: props.dateProfile, date: cell.date, showDayNumber: props.showDayNumbers, showWeekNumber: props.showWeekNumbers && col === 0, forceDayTop: props.showWeekNumbers /* even displaying weeknum for row, not necessarily day */, todayRange: props.todayRange, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, extraHookProps: cell.extraHookProps, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames, extraDateSpan: cell.extraDateSpan, moreCnt: moreCnts[col], moreMarginTop: moreMarginTops[col], singlePlacements: singleColPlacements[col], fgContentElRef: _this.fgElRefs.createRef(cell.key), fgContent: ( // Fragment scopes the keys + createElement(Fragment, null, + createElement(Fragment, null, normalFgNodes), + createElement(Fragment, null, mirrorFgNodes))), bgContent: ( // Fragment scopes the keys + createElement(Fragment, null, + _this.renderFillSegs(highlightSegsByCol[col], 'highlight'), + _this.renderFillSegs(businessHoursByCol[col], 'non-business'), + _this.renderFillSegs(bgEventSegsByCol[col], 'bg-event'))) })); + }))); + }; + TableRow.prototype.componentDidMount = function () { + this.updateSizing(true); + }; + TableRow.prototype.componentDidUpdate = function (prevProps, prevState) { + var currentProps = this.props; + this.updateSizing(!isPropsEqual(prevProps, currentProps)); + }; + TableRow.prototype.getHighlightSegs = function () { + var props = this.props; + if (props.eventDrag && props.eventDrag.segs.length) { // messy check + return props.eventDrag.segs; + } + if (props.eventResize && props.eventResize.segs.length) { // messy check + return props.eventResize.segs; + } + return props.dateSelectionSegs; + }; + TableRow.prototype.getMirrorSegs = function () { + var props = this.props; + if (props.eventResize && props.eventResize.segs.length) { // messy check + return props.eventResize.segs; + } + return []; + }; + TableRow.prototype.renderFgSegs = function (col, segPlacements, todayRange, isForcedInvisible, isDragging, isResizing, isDateSelecting) { + var context = this.context; + var eventSelection = this.props.eventSelection; + var framePositions = this.state.framePositions; + var defaultDisplayEventEnd = this.props.cells.length === 1; // colCnt === 1 + var isMirror = isDragging || isResizing || isDateSelecting; + var nodes = []; + if (framePositions) { + for (var _i = 0, segPlacements_1 = segPlacements; _i < segPlacements_1.length; _i++) { + var placement = segPlacements_1[_i]; + var seg = placement.seg; + var instanceId = seg.eventRange.instance.instanceId; + var key = instanceId + ':' + col; + var isVisible = placement.isVisible && !isForcedInvisible[instanceId]; + var isAbsolute = placement.isAbsolute; + var left = ''; + var right = ''; + if (isAbsolute) { + if (context.isRtl) { + right = 0; + left = framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol]; + } + else { + left = 0; + right = framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol]; + } + } + /* + known bug: events that are force to be list-item but span multiple days still take up space in later columns + todo: in print view, for multi-day events, don't display title within non-start/end segs + */ + nodes.push(createElement("div", { className: 'fc-daygrid-event-harness' + (isAbsolute ? ' fc-daygrid-event-harness-abs' : ''), key: key, ref: isMirror ? null : this.segHarnessRefs.createRef(key), style: { + visibility: isVisible ? '' : 'hidden', + marginTop: isAbsolute ? '' : placement.marginTop, + top: isAbsolute ? placement.absoluteTop : '', + left: left, + right: right, + } }, hasListItemDisplay(seg) ? (createElement(TableListItemEvent, __assign({ seg: seg, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, getSegMeta(seg, todayRange)))) : (createElement(TableBlockEvent, __assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, getSegMeta(seg, todayRange)))))); + } + } + return nodes; + }; + TableRow.prototype.renderFillSegs = function (segs, fillType) { + var isRtl = this.context.isRtl; + var todayRange = this.props.todayRange; + var framePositions = this.state.framePositions; + var nodes = []; + if (framePositions) { + for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) { + var seg = segs_1[_i]; + var leftRightCss = isRtl ? { + right: 0, + left: framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol], + } : { + left: 0, + right: framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol], + }; + nodes.push(createElement("div", { key: buildEventRangeKey(seg.eventRange), className: "fc-daygrid-bg-harness", style: leftRightCss }, fillType === 'bg-event' ? + createElement(BgEvent, __assign({ seg: seg }, getSegMeta(seg, todayRange))) : + renderFill(fillType))); + } + } + return createElement.apply(void 0, __spreadArray([Fragment, {}], nodes)); + }; + TableRow.prototype.updateSizing = function (isExternalSizingChange) { + var _a = this, props = _a.props, frameElRefs = _a.frameElRefs; + if (!props.forPrint && + props.clientWidth !== null // positioning ready? + ) { + if (isExternalSizingChange) { + var frameEls = props.cells.map(function (cell) { return frameElRefs.currentMap[cell.key]; }); + if (frameEls.length) { + var originEl = this.rootElRef.current; + this.setState({ + framePositions: new PositionCache(originEl, frameEls, true, // isHorizontal + false), + }); + } + } + var limitByContentHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true; + this.setState({ + eventInstanceHeights: this.queryEventInstanceHeights(), + maxContentHeight: limitByContentHeight ? this.computeMaxContentHeight() : null, + }); + } + }; + TableRow.prototype.queryEventInstanceHeights = function () { + var segElMap = this.segHarnessRefs.currentMap; + var eventInstanceHeights = {}; + // get the max height amongst instance segs + for (var key in segElMap) { + var height = Math.round(segElMap[key].getBoundingClientRect().height); + var instanceId = key.split(':')[0]; // deconstruct how renderFgSegs makes the key + eventInstanceHeights[instanceId] = Math.max(eventInstanceHeights[instanceId] || 0, height); + } + return eventInstanceHeights; + }; + TableRow.prototype.computeMaxContentHeight = function () { + var firstKey = this.props.cells[0].key; + var cellEl = this.cellElRefs.currentMap[firstKey]; + var fcContainerEl = this.fgElRefs.currentMap[firstKey]; + return cellEl.getBoundingClientRect().bottom - fcContainerEl.getBoundingClientRect().top; + }; + TableRow.prototype.getCellEls = function () { + var elMap = this.cellElRefs.currentMap; + return this.props.cells.map(function (cell) { return elMap[cell.key]; }); + }; + return TableRow; + }(DateComponent)); + TableRow.addStateEquality({ + eventInstanceHeights: isPropsEqual, + }); + function buildMirrorPlacements$1(mirrorSegs, colPlacements) { + if (!mirrorSegs.length) { + return []; + } + var topsByInstanceId = buildAbsoluteTopHash$1(colPlacements); // TODO: cache this at first render? + return mirrorSegs.map(function (seg) { return ({ + seg: seg, + isVisible: true, + isAbsolute: true, + absoluteTop: topsByInstanceId[seg.eventRange.instance.instanceId], + marginTop: 0, + }); }); + } + function buildAbsoluteTopHash$1(colPlacements) { + var topsByInstanceId = {}; + for (var _i = 0, colPlacements_1 = colPlacements; _i < colPlacements_1.length; _i++) { + var placements = colPlacements_1[_i]; + for (var _a = 0, placements_1 = placements; _a < placements_1.length; _a++) { + var placement = placements_1[_a]; + topsByInstanceId[placement.seg.eventRange.instance.instanceId] = placement.absoluteTop; + } + } + return colPlacements; + } + + var Table = /** @class */ (function (_super) { + __extends(Table, _super); + function Table() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.splitBusinessHourSegs = memoize(splitSegsByRow); + _this.splitBgEventSegs = memoize(splitSegsByRow); + _this.splitFgEventSegs = memoize(splitSegsByRow); + _this.splitDateSelectionSegs = memoize(splitSegsByRow); + _this.splitEventDrag = memoize(splitInteractionByRow); + _this.splitEventResize = memoize(splitInteractionByRow); + _this.rowRefs = new RefMap(); + _this.handleRootEl = function (rootEl) { + _this.rootEl = rootEl; + if (rootEl) { + _this.context.registerInteractiveComponent(_this, { + el: rootEl, + isHitComboAllowed: _this.props.isHitComboAllowed, + }); + } + else { + _this.context.unregisterInteractiveComponent(_this); + } + }; + return _this; + } + Table.prototype.render = function () { + var _this = this; + var props = this.props; + var dateProfile = props.dateProfile, dayMaxEventRows = props.dayMaxEventRows, dayMaxEvents = props.dayMaxEvents, expandRows = props.expandRows; + var rowCnt = props.cells.length; + var businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCnt); + var bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCnt); + var fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCnt); + var dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCnt); + var eventDragByRow = this.splitEventDrag(props.eventDrag, rowCnt); + var eventResizeByRow = this.splitEventResize(props.eventResize, rowCnt); + var limitViaBalanced = dayMaxEvents === true || dayMaxEventRows === true; + // if rows can't expand to fill fixed height, can't do balanced-height event limit + // TODO: best place to normalize these options? + if (limitViaBalanced && !expandRows) { + limitViaBalanced = false; + dayMaxEventRows = null; + dayMaxEvents = null; + } + var classNames = [ + 'fc-daygrid-body', + limitViaBalanced ? 'fc-daygrid-body-balanced' : 'fc-daygrid-body-unbalanced', + expandRows ? '' : 'fc-daygrid-body-natural', // will height of one row depend on the others? + ]; + return (createElement("div", { className: classNames.join(' '), ref: this.handleRootEl, style: { + // these props are important to give this wrapper correct dimensions for interactions + // TODO: if we set it here, can we avoid giving to inner tables? + width: props.clientWidth, + minWidth: props.tableMinWidth, + } }, + createElement(NowTimer, { unit: "day" }, function (nowDate, todayRange) { return (createElement(Fragment, null, + createElement("table", { className: "fc-scrollgrid-sync-table", style: { + width: props.clientWidth, + minWidth: props.tableMinWidth, + height: expandRows ? props.clientHeight : '', + } }, + props.colGroupNode, + createElement("tbody", null, props.cells.map(function (cells, row) { return (createElement(TableRow, { ref: _this.rowRefs.createRef(row), key: cells.length + ? cells[0].date.toISOString() /* best? or put key on cell? or use diff formatter? */ + : row // in case there are no cells (like when resource view is loading) + , showDayNumbers: rowCnt > 1, showWeekNumbers: props.showWeekNumbers, todayRange: todayRange, dateProfile: dateProfile, cells: cells, renderIntro: props.renderRowIntro, businessHourSegs: businessHourSegsByRow[row], eventSelection: props.eventSelection, bgEventSegs: bgEventSegsByRow[row].filter(isSegAllDay) /* hack */, fgEventSegs: fgEventSegsByRow[row], dateSelectionSegs: dateSelectionSegsByRow[row], eventDrag: eventDragByRow[row], eventResize: eventResizeByRow[row], dayMaxEvents: dayMaxEvents, dayMaxEventRows: dayMaxEventRows, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: props.forPrint })); }))))); }))); + }; + // Hit System + // ---------------------------------------------------------------------------------------------------- + Table.prototype.prepareHits = function () { + this.rowPositions = new PositionCache(this.rootEl, this.rowRefs.collect().map(function (rowObj) { return rowObj.getCellEls()[0]; }), // first cell el in each row. TODO: not optimal + false, true); + this.colPositions = new PositionCache(this.rootEl, this.rowRefs.currentMap[0].getCellEls(), // cell els in first row + true, // horizontal + false); + }; + Table.prototype.queryHit = function (positionLeft, positionTop) { + var _a = this, colPositions = _a.colPositions, rowPositions = _a.rowPositions; + var col = colPositions.leftToIndex(positionLeft); + var row = rowPositions.topToIndex(positionTop); + if (row != null && col != null) { + var cell = this.props.cells[row][col]; + return { + dateProfile: this.props.dateProfile, + dateSpan: __assign({ range: this.getCellRange(row, col), allDay: true }, cell.extraDateSpan), + dayEl: this.getCellEl(row, col), + rect: { + left: colPositions.lefts[col], + right: colPositions.rights[col], + top: rowPositions.tops[row], + bottom: rowPositions.bottoms[row], + }, + layer: 0, + }; + } + return null; + }; + Table.prototype.getCellEl = function (row, col) { + return this.rowRefs.currentMap[row].getCellEls()[col]; // TODO: not optimal + }; + Table.prototype.getCellRange = function (row, col) { + var start = this.props.cells[row][col].date; + var end = addDays(start, 1); + return { start: start, end: end }; + }; + return Table; + }(DateComponent)); + function isSegAllDay(seg) { + return seg.eventRange.def.allDay; + } + + var DayTableSlicer = /** @class */ (function (_super) { + __extends(DayTableSlicer, _super); + function DayTableSlicer() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.forceDayIfListItem = true; + return _this; + } + DayTableSlicer.prototype.sliceRange = function (dateRange, dayTableModel) { + return dayTableModel.sliceRange(dateRange); + }; + return DayTableSlicer; + }(Slicer)); + + var DayTable = /** @class */ (function (_super) { + __extends(DayTable, _super); + function DayTable() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.slicer = new DayTableSlicer(); + _this.tableRef = createRef(); + return _this; + } + DayTable.prototype.render = function () { + var _a = this, props = _a.props, context = _a.context; + return (createElement(Table, __assign({ ref: this.tableRef }, this.slicer.sliceProps(props, props.dateProfile, props.nextDayThreshold, context, props.dayTableModel), { dateProfile: props.dateProfile, cells: props.dayTableModel.cells, colGroupNode: props.colGroupNode, tableMinWidth: props.tableMinWidth, renderRowIntro: props.renderRowIntro, dayMaxEvents: props.dayMaxEvents, dayMaxEventRows: props.dayMaxEventRows, showWeekNumbers: props.showWeekNumbers, expandRows: props.expandRows, headerAlignElRef: props.headerAlignElRef, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: props.forPrint }))); + }; + return DayTable; + }(DateComponent)); + + var DayTableView = /** @class */ (function (_super) { + __extends(DayTableView, _super); + function DayTableView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.buildDayTableModel = memoize(buildDayTableModel); + _this.headerRef = createRef(); + _this.tableRef = createRef(); + return _this; + } + DayTableView.prototype.render = function () { + var _this = this; + var _a = this.context, options = _a.options, dateProfileGenerator = _a.dateProfileGenerator; + var props = this.props; + var dayTableModel = this.buildDayTableModel(props.dateProfile, dateProfileGenerator); + var headerContent = options.dayHeaders && (createElement(DayHeader, { ref: this.headerRef, dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: dayTableModel.rowCnt === 1 })); + var bodyContent = function (contentArg) { return (createElement(DayTable, { ref: _this.tableRef, dateProfile: props.dateProfile, dayTableModel: dayTableModel, businessHours: props.businessHours, dateSelection: props.dateSelection, eventStore: props.eventStore, eventUiBases: props.eventUiBases, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, nextDayThreshold: options.nextDayThreshold, colGroupNode: contentArg.tableColGroupNode, tableMinWidth: contentArg.tableMinWidth, dayMaxEvents: options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows, showWeekNumbers: options.weekNumbers, expandRows: !props.isHeightAuto, headerAlignElRef: _this.headerElRef, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, forPrint: props.forPrint })); }; + return options.dayMinWidth + ? this.renderHScrollLayout(headerContent, bodyContent, dayTableModel.colCnt, options.dayMinWidth) + : this.renderSimpleLayout(headerContent, bodyContent); + }; + return DayTableView; + }(TableView)); + function buildDayTableModel(dateProfile, dateProfileGenerator) { + var daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator); + return new DayTableModel(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit)); + } + + var TableDateProfileGenerator = /** @class */ (function (_super) { + __extends(TableDateProfileGenerator, _super); + function TableDateProfileGenerator() { + return _super !== null && _super.apply(this, arguments) || this; + } + // Computes the date range that will be rendered. + TableDateProfileGenerator.prototype.buildRenderRange = function (currentRange, currentRangeUnit, isRangeAllDay) { + var dateEnv = this.props.dateEnv; + var renderRange = _super.prototype.buildRenderRange.call(this, currentRange, currentRangeUnit, isRangeAllDay); + var start = renderRange.start; + var end = renderRange.end; + var endOfWeek; + // year and month views should be aligned with weeks. this is already done for week + if (/^(year|month)$/.test(currentRangeUnit)) { + start = dateEnv.startOfWeek(start); + // make end-of-week if not already + endOfWeek = dateEnv.startOfWeek(end); + if (endOfWeek.valueOf() !== end.valueOf()) { + end = addWeeks(endOfWeek, 1); + } + } + // ensure 6 weeks + if (this.props.monthMode && + this.props.fixedWeekCount) { + var rowCnt = Math.ceil(// could be partial weeks due to hiddenDays + diffWeeks(start, end)); + end = addWeeks(end, 6 - rowCnt); + } + return { start: start, end: end }; + }; + return TableDateProfileGenerator; + }(DateProfileGenerator)); + + var dayGridPlugin = createPlugin({ + initialView: 'dayGridMonth', + views: { + dayGrid: { + component: DayTableView, + dateProfileGeneratorClass: TableDateProfileGenerator, + }, + dayGridDay: { + type: 'dayGrid', + duration: { days: 1 }, + }, + dayGridWeek: { + type: 'dayGrid', + duration: { weeks: 1 }, + }, + dayGridMonth: { + type: 'dayGrid', + duration: { months: 1 }, + monthMode: true, + fixedWeekCount: true, + }, + }, + }); + + var AllDaySplitter = /** @class */ (function (_super) { + __extends(AllDaySplitter, _super); + function AllDaySplitter() { + return _super !== null && _super.apply(this, arguments) || this; + } + AllDaySplitter.prototype.getKeyInfo = function () { + return { + allDay: {}, + timed: {}, + }; + }; + AllDaySplitter.prototype.getKeysForDateSpan = function (dateSpan) { + if (dateSpan.allDay) { + return ['allDay']; + } + return ['timed']; + }; + AllDaySplitter.prototype.getKeysForEventDef = function (eventDef) { + if (!eventDef.allDay) { + return ['timed']; + } + if (hasBgRendering(eventDef)) { + return ['timed', 'allDay']; + } + return ['allDay']; + }; + return AllDaySplitter; + }(Splitter)); + + var DEFAULT_SLAT_LABEL_FORMAT = createFormatter({ + hour: 'numeric', + minute: '2-digit', + omitZeroMinute: true, + meridiem: 'short', + }); + function TimeColsAxisCell(props) { + var classNames = [ + 'fc-timegrid-slot', + 'fc-timegrid-slot-label', + props.isLabeled ? 'fc-scrollgrid-shrink' : 'fc-timegrid-slot-minor', + ]; + return (createElement(ViewContextType.Consumer, null, function (context) { + if (!props.isLabeled) { + return (createElement("td", { className: classNames.join(' '), "data-time": props.isoTimeStr })); + } + var dateEnv = context.dateEnv, options = context.options, viewApi = context.viewApi; + var labelFormat = // TODO: fully pre-parse + options.slotLabelFormat == null ? DEFAULT_SLAT_LABEL_FORMAT : + Array.isArray(options.slotLabelFormat) ? createFormatter(options.slotLabelFormat[0]) : + createFormatter(options.slotLabelFormat); + var hookProps = { + level: 0, + time: props.time, + date: dateEnv.toDate(props.date), + view: viewApi, + text: dateEnv.format(props.date, labelFormat), + }; + return (createElement(RenderHook, { hookProps: hookProps, classNames: options.slotLabelClassNames, content: options.slotLabelContent, defaultContent: renderInnerContent$3, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, function (rootElRef, customClassNames, innerElRef, innerContent) { return (createElement("td", { ref: rootElRef, className: classNames.concat(customClassNames).join(' '), "data-time": props.isoTimeStr }, + createElement("div", { className: "fc-timegrid-slot-label-frame fc-scrollgrid-shrink-frame" }, + createElement("div", { className: "fc-timegrid-slot-label-cushion fc-scrollgrid-shrink-cushion", ref: innerElRef }, innerContent)))); })); + })); + } + function renderInnerContent$3(props) { + return props.text; + } + + var TimeBodyAxis = /** @class */ (function (_super) { + __extends(TimeBodyAxis, _super); + function TimeBodyAxis() { + return _super !== null && _super.apply(this, arguments) || this; + } + TimeBodyAxis.prototype.render = function () { + return this.props.slatMetas.map(function (slatMeta) { return (createElement("tr", { key: slatMeta.key }, + createElement(TimeColsAxisCell, __assign({}, slatMeta)))); }); + }; + return TimeBodyAxis; + }(BaseComponent)); + + var DEFAULT_WEEK_NUM_FORMAT = createFormatter({ week: 'short' }); + var AUTO_ALL_DAY_MAX_EVENT_ROWS = 5; + var TimeColsView = /** @class */ (function (_super) { + __extends(TimeColsView, _super); + function TimeColsView() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.allDaySplitter = new AllDaySplitter(); // for use by subclasses + _this.headerElRef = createRef(); + _this.rootElRef = createRef(); + _this.scrollerElRef = createRef(); + _this.state = { + slatCoords: null, + }; + _this.handleScrollTopRequest = function (scrollTop) { + var scrollerEl = _this.scrollerElRef.current; + if (scrollerEl) { // TODO: not sure how this could ever be null. weirdness with the reducer + scrollerEl.scrollTop = scrollTop; + } + }; + /* Header Render Methods + ------------------------------------------------------------------------------------------------------------------*/ + _this.renderHeadAxis = function (rowKey, frameHeight) { + if (frameHeight === void 0) { frameHeight = ''; } + var options = _this.context.options; + var dateProfile = _this.props.dateProfile; + var range = dateProfile.renderRange; + var dayCnt = diffDays(range.start, range.end); + var navLinkAttrs = (options.navLinks && dayCnt === 1) // only do in day views (to avoid doing in week views that dont need it) + ? { 'data-navlink': buildNavLinkData(range.start, 'week'), tabIndex: 0 } + : {}; + if (options.weekNumbers && rowKey === 'day') { + return (createElement(WeekNumberRoot, { date: range.start, defaultFormat: DEFAULT_WEEK_NUM_FORMAT }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("th", { ref: rootElRef, className: [ + 'fc-timegrid-axis', + 'fc-scrollgrid-shrink', + ].concat(classNames).join(' ') }, + createElement("div", { className: "fc-timegrid-axis-frame fc-scrollgrid-shrink-frame fc-timegrid-axis-frame-liquid", style: { height: frameHeight } }, + createElement("a", __assign({ ref: innerElRef, className: "fc-timegrid-axis-cushion fc-scrollgrid-shrink-cushion fc-scrollgrid-sync-inner" }, navLinkAttrs), innerContent)))); })); + } + return (createElement("th", { className: "fc-timegrid-axis" }, + createElement("div", { className: "fc-timegrid-axis-frame", style: { height: frameHeight } }))); + }; + /* Table Component Render Methods + ------------------------------------------------------------------------------------------------------------------*/ + // only a one-way height sync. we don't send the axis inner-content height to the DayGrid, + // but DayGrid still needs to have classNames on inner elements in order to measure. + _this.renderTableRowAxis = function (rowHeight) { + var _a = _this.context, options = _a.options, viewApi = _a.viewApi; + var hookProps = { + text: options.allDayText, + view: viewApi, + }; + return ( + // TODO: make reusable hook. used in list view too + createElement(RenderHook, { hookProps: hookProps, classNames: options.allDayClassNames, content: options.allDayContent, defaultContent: renderAllDayInner$1, didMount: options.allDayDidMount, willUnmount: options.allDayWillUnmount }, function (rootElRef, classNames, innerElRef, innerContent) { return (createElement("td", { ref: rootElRef, className: [ + 'fc-timegrid-axis', + 'fc-scrollgrid-shrink', + ].concat(classNames).join(' ') }, + createElement("div", { className: 'fc-timegrid-axis-frame fc-scrollgrid-shrink-frame' + (rowHeight == null ? ' fc-timegrid-axis-frame-liquid' : ''), style: { height: rowHeight } }, + createElement("span", { className: "fc-timegrid-axis-cushion fc-scrollgrid-shrink-cushion fc-scrollgrid-sync-inner", ref: innerElRef }, innerContent)))); })); + }; + _this.handleSlatCoords = function (slatCoords) { + _this.setState({ slatCoords: slatCoords }); + }; + return _this; + } + // rendering + // ---------------------------------------------------------------------------------------------------- + TimeColsView.prototype.renderSimpleLayout = function (headerRowContent, allDayContent, timeContent) { + var _a = this, context = _a.context, props = _a.props; + var sections = []; + var stickyHeaderDates = getStickyHeaderDates(context.options); + if (headerRowContent) { + sections.push({ + type: 'header', + key: 'header', + isSticky: stickyHeaderDates, + chunk: { + elRef: this.headerElRef, + tableClassName: 'fc-col-header', + rowContent: headerRowContent, + }, + }); + } + if (allDayContent) { + sections.push({ + type: 'body', + key: 'all-day', + chunk: { content: allDayContent }, + }); + sections.push({ + type: 'body', + key: 'all-day-divider', + outerContent: ( // TODO: rename to cellContent so don't need to define
").append(t("").append(i("left")).append(i("center")).append(i("right"))):e}function o(){h.remove()}function i(e){var a=t(" */ + height: 1px /* better than 0, for firefox */ + + } +.fc .fc-scrollgrid-section > td { + height: 1px; /* needs a height so inner div within grow. better than 0, for firefox */ + } +.fc .fc-scrollgrid-section table { + height: 1px; + /* for most browsers, if a height isn't set on the table, can't do liquid-height within cells */ + /* serves as a min-height. harmless */ + } +.fc .fc-scrollgrid-section-liquid > td { + height: 100%; /* better than `auto`, for firefox */ + } +.fc .fc-scrollgrid-section > * { + border-top-width: 0; + border-left-width: 0; + } +.fc .fc-scrollgrid-section-header > *, + .fc .fc-scrollgrid-section-footer > * { + border-bottom-width: 0; + } +.fc .fc-scrollgrid-section-body table, + .fc .fc-scrollgrid-section-footer table { + border-bottom-style: hidden; /* head keeps its bottom border tho */ + } +.fc { + + /* stickiness */ + +} +.fc .fc-scrollgrid-section-sticky > * { + background: #fff; + background: var(--fc-page-bg-color, #fff); + position: sticky; + z-index: 3; /* TODO: var */ + /* TODO: box-shadow when sticking */ + } +.fc .fc-scrollgrid-section-header.fc-scrollgrid-section-sticky > * { + top: 0; /* because border-sharing causes a gap at the top */ + /* TODO: give safari -1. has bug */ + } +.fc .fc-scrollgrid-section-footer.fc-scrollgrid-section-sticky > * { + bottom: 0; /* known bug: bottom-stickiness doesn't work in safari */ + } +.fc .fc-scrollgrid-sticky-shim { /* for horizontal scrollbar */ + height: 1px; /* needs height to create scrollbars */ + margin-bottom: -1px; + } +.fc-sticky { /* no .fc wrap because used as child of body */ + position: sticky; +} +.fc .fc-view-harness { + flex-grow: 1; /* because this harness is WITHIN the .fc's flexbox */ + position: relative; + } +.fc { + + /* when the harness controls the height, make the view liquid */ + +} +.fc .fc-view-harness-active > .fc-view { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + } +.fc .fc-col-header-cell-cushion { + display: inline-block; /* x-browser for when sticky (when multi-tier header) */ + padding: 2px 4px; + } +.fc .fc-bg-event, + .fc .fc-non-business, + .fc .fc-highlight { + /* will always have a harness with position:relative/absolute, so absolutely expand */ + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + } +.fc .fc-non-business { + background: rgba(215, 215, 215, 0.3); + background: var(--fc-non-business-color, rgba(215, 215, 215, 0.3)); + } +.fc .fc-bg-event { + background: rgb(143, 223, 130); + background: var(--fc-bg-event-color, rgb(143, 223, 130)); + opacity: 0.3; + opacity: var(--fc-bg-event-opacity, 0.3) + } +.fc .fc-bg-event .fc-event-title { + margin: .5em; + font-size: .85em; + font-size: var(--fc-small-font-size, .85em); + font-style: italic; + } +.fc .fc-highlight { + background: rgba(188, 232, 241, 0.3); + background: var(--fc-highlight-color, rgba(188, 232, 241, 0.3)); + } +.fc .fc-cell-shaded, + .fc .fc-day-disabled { + background: rgba(208, 208, 208, 0.3); + background: var(--fc-neutral-bg-color, rgba(208, 208, 208, 0.3)); + } +/* link resets */ +/* ---------------------------------------------------------------------------------------------------- */ +a.fc-event, +a.fc-event:hover { + text-decoration: none; +} +/* cursor */ +.fc-event[href], +.fc-event.fc-event-draggable { + cursor: pointer; +} +/* event text content */ +/* ---------------------------------------------------------------------------------------------------- */ +.fc-event .fc-event-main { + position: relative; + z-index: 2; + } +/* dragging */ +/* ---------------------------------------------------------------------------------------------------- */ +.fc-event-dragging:not(.fc-event-selected) { /* MOUSE */ + opacity: 0.75; + } +.fc-event-dragging.fc-event-selected { /* TOUCH */ + box-shadow: 0 2px 7px rgba(0, 0, 0, 0.3); + } +/* resizing */ +/* ---------------------------------------------------------------------------------------------------- */ +/* (subclasses should hone positioning for touch and non-touch) */ +.fc-event .fc-event-resizer { + display: none; + position: absolute; + z-index: 4; + } +.fc-event:hover, /* MOUSE */ +.fc-event-selected { /* TOUCH */ + +} +.fc-event:hover .fc-event-resizer, .fc-event-selected .fc-event-resizer { + display: block; + } +.fc-event-selected .fc-event-resizer { + border-radius: 4px; + border-radius: calc(var(--fc-event-resizer-dot-total-width, 8px) / 2); + border-width: 1px; + border-width: var(--fc-event-resizer-dot-border-width, 1px); + width: 8px; + width: var(--fc-event-resizer-dot-total-width, 8px); + height: 8px; + height: var(--fc-event-resizer-dot-total-width, 8px); + border-style: solid; + border-color: inherit; + background: #fff; + background: var(--fc-page-bg-color, #fff) + + /* expand hit area */ + + } +.fc-event-selected .fc-event-resizer:before { + content: ''; + position: absolute; + top: -20px; + left: -20px; + right: -20px; + bottom: -20px; + } +/* selecting (always TOUCH) */ +/* ---------------------------------------------------------------------------------------------------- */ +.fc-event-selected { + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2) + + /* expand hit area (subclasses should expand) */ + +} +.fc-event-selected:before { + content: ""; + position: absolute; + z-index: 3; + top: 0; + left: 0; + right: 0; + bottom: 0; + } +.fc-event-selected { + + /* dimmer effect */ + +} +.fc-event-selected:after { + content: ""; + background: rgba(0, 0, 0, 0.25); + background: var(--fc-event-selected-overlay-color, rgba(0, 0, 0, 0.25)); + position: absolute; + z-index: 1; + + /* assume there's a border on all sides. overcome it. */ + /* sometimes there's NOT a border, in which case the dimmer will go over */ + /* an adjacent border, which looks fine. */ + top: -1px; + left: -1px; + right: -1px; + bottom: -1px; + } +/* +A HORIZONTAL event +*/ +.fc-h-event { /* allowed to be top-level */ + display: block; + border: 1px solid #3788d8; + border: 1px solid var(--fc-event-border-color, #3788d8); + background-color: #3788d8; + background-color: var(--fc-event-bg-color, #3788d8) + +} +.fc-h-event .fc-event-main { + color: #fff; + color: var(--fc-event-text-color, #fff); + } +.fc-h-event .fc-event-main-frame { + display: flex; /* for make fc-event-title-container expand */ + } +.fc-h-event .fc-event-time { + max-width: 100%; /* clip overflow on this element */ + overflow: hidden; + } +.fc-h-event .fc-event-title-container { /* serves as a container for the sticky cushion */ + flex-grow: 1; + flex-shrink: 1; + min-width: 0; /* important for allowing to shrink all the way */ + } +.fc-h-event .fc-event-title { + display: inline-block; /* need this to be sticky cross-browser */ + vertical-align: top; /* for not messing up line-height */ + left: 0; /* for sticky */ + right: 0; /* for sticky */ + max-width: 100%; /* clip overflow on this element */ + overflow: hidden; + } +.fc-h-event.fc-event-selected:before { + /* expand hit area */ + top: -10px; + bottom: -10px; + } +/* adjust border and border-radius (if there is any) for non-start/end */ +.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-start), +.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-end) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-left-width: 0; +} +.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-end), +.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-start) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right-width: 0; +} +/* resizers */ +.fc-h-event:not(.fc-event-selected) .fc-event-resizer { + top: 0; + bottom: 0; + width: 8px; + width: var(--fc-event-resizer-thickness, 8px); +} +.fc-direction-ltr .fc-h-event:not(.fc-event-selected) .fc-event-resizer-start, +.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end { + cursor: w-resize; + left: -4px; + left: calc(var(--fc-event-resizer-thickness, 8px) / -2); +} +.fc-direction-ltr .fc-h-event:not(.fc-event-selected) .fc-event-resizer-end, +.fc-direction-rtl .fc-h-event:not(.fc-event-selected) .fc-event-resizer-start { + cursor: e-resize; + right: -4px; + right: calc(var(--fc-event-resizer-thickness, 8px) / -2); +} +/* resizers for TOUCH */ +.fc-h-event.fc-event-selected .fc-event-resizer { + top: 50%; + margin-top: -4px; + margin-top: calc(var(--fc-event-resizer-dot-total-width, 8px) / -2); +} +.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-start, +.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-end { + left: -4px; + left: calc(var(--fc-event-resizer-dot-total-width, 8px) / -2); +} +.fc-direction-ltr .fc-h-event.fc-event-selected .fc-event-resizer-end, +.fc-direction-rtl .fc-h-event.fc-event-selected .fc-event-resizer-start { + right: -4px; + right: calc(var(--fc-event-resizer-dot-total-width, 8px) / -2); +} +.fc .fc-popover { + position: absolute; + z-index: 9999; + box-shadow: 0 2px 6px rgba(0,0,0,.15); + } +.fc .fc-popover-header { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 3px 4px; + } +.fc .fc-popover-title { + margin: 0 2px; + } +.fc .fc-popover-close { + cursor: pointer; + opacity: 0.65; + font-size: 1.1em; + } +.fc-theme-standard .fc-popover { + border: 1px solid #ddd; + border: 1px solid var(--fc-border-color, #ddd); + background: #fff; + background: var(--fc-page-bg-color, #fff); + } +.fc-theme-standard .fc-popover-header { + background: rgba(208, 208, 208, 0.3); + background: var(--fc-neutral-bg-color, rgba(208, 208, 208, 0.3)); + } + + +:root { + --fc-daygrid-event-dot-width: 8px; +} +/* help things clear margins of inner content */ +.fc-daygrid-day-frame, +.fc-daygrid-day-events, +.fc-daygrid-event-harness { /* for event top/bottom margins */ +} +.fc-daygrid-day-frame:before, .fc-daygrid-day-events:before, .fc-daygrid-event-harness:before { + content: ""; + clear: both; + display: table; } +.fc-daygrid-day-frame:after, .fc-daygrid-day-events:after, .fc-daygrid-event-harness:after { + content: ""; + clear: both; + display: table; } +.fc .fc-daygrid-body { /* a
that wraps the table */ + position: relative; + z-index: 1; /* container inner z-index's because
s can't do it */ + } +.fc .fc-daygrid-day.fc-day-today { + background-color: rgba(255, 220, 40, 0.15); + background-color: var(--fc-today-bg-color, rgba(255, 220, 40, 0.15)); + } +.fc .fc-daygrid-day-frame { + position: relative; + min-height: 100%; /* seems to work better than `height` because sets height after rows/cells naturally do it */ + } +.fc { + + /* cell top */ + +} +.fc .fc-daygrid-day-top { + display: flex; + flex-direction: row-reverse; + } +.fc .fc-day-other .fc-daygrid-day-top { + opacity: 0.3; + } +.fc { + + /* day number (within cell top) */ + +} +.fc .fc-daygrid-day-number { + position: relative; + z-index: 4; + padding: 4px; + } +.fc { + + /* event container */ + +} +.fc .fc-daygrid-day-events { + margin-top: 1px; /* needs to be margin, not padding, so that available cell height can be computed */ + } +.fc { + + /* positioning for balanced vs natural */ + +} +.fc .fc-daygrid-body-balanced .fc-daygrid-day-events { + position: absolute; + left: 0; + right: 0; + } +.fc .fc-daygrid-body-unbalanced .fc-daygrid-day-events { + position: relative; /* for containing abs positioned event harnesses */ + min-height: 2em; /* in addition to being a min-height during natural height, equalizes the heights a little bit */ + } +.fc .fc-daygrid-body-natural { /* can coexist with -unbalanced */ + } +.fc .fc-daygrid-body-natural .fc-daygrid-day-events { + margin-bottom: 1em; + } +.fc { + + /* event harness */ + +} +.fc .fc-daygrid-event-harness { + position: relative; + } +.fc .fc-daygrid-event-harness-abs { + position: absolute; + top: 0; /* fallback coords for when cannot yet be computed */ + left: 0; /* */ + right: 0; /* */ + } +.fc .fc-daygrid-bg-harness { + position: absolute; + top: 0; + bottom: 0; + } +.fc { + + /* bg content */ + +} +.fc .fc-daygrid-day-bg .fc-non-business { z-index: 1 } +.fc .fc-daygrid-day-bg .fc-bg-event { z-index: 2 } +.fc .fc-daygrid-day-bg .fc-highlight { z-index: 3 } +.fc { + + /* events */ + +} +.fc .fc-daygrid-event { + z-index: 6; + margin-top: 1px; + } +.fc .fc-daygrid-event.fc-event-mirror { + z-index: 7; + } +.fc { + + /* cell bottom (within day-events) */ + +} +.fc .fc-daygrid-day-bottom { + font-size: .85em; + padding: 2px 3px 0 + } +.fc .fc-daygrid-day-bottom:before { + content: ""; + clear: both; + display: table; } +.fc .fc-daygrid-more-link { + position: relative; + z-index: 4; + cursor: pointer; + } +.fc { + + /* week number (within frame) */ + +} +.fc .fc-daygrid-week-number { + position: absolute; + z-index: 5; + top: 0; + padding: 2px; + min-width: 1.5em; + text-align: center; + background-color: rgba(208, 208, 208, 0.3); + background-color: var(--fc-neutral-bg-color, rgba(208, 208, 208, 0.3)); + color: #808080; + color: var(--fc-neutral-text-color, #808080); + } +.fc { + + /* popover */ + +} +.fc .fc-more-popover .fc-popover-body { + min-width: 220px; + padding: 10px; + } +.fc-direction-ltr .fc-daygrid-event.fc-event-start, +.fc-direction-rtl .fc-daygrid-event.fc-event-end { + margin-left: 2px; +} +.fc-direction-ltr .fc-daygrid-event.fc-event-end, +.fc-direction-rtl .fc-daygrid-event.fc-event-start { + margin-right: 2px; +} +.fc-direction-ltr .fc-daygrid-week-number { + left: 0; + border-radius: 0 0 3px 0; + } +.fc-direction-rtl .fc-daygrid-week-number { + right: 0; + border-radius: 0 0 0 3px; + } +.fc-liquid-hack .fc-daygrid-day-frame { + position: static; /* will cause inner absolute stuff to expand to
"),o=r.header[e];return o&&t.each(o.split(" "),function(e){e>0&&a.append("");var o;t.each(this.split(","),function(e,i){if("title"==i)a.append("

 

"),o&&o.addClass(v+"-corner-right"),o=null;else{var s;if(n[i]?s=n[i]:De[i]&&(s=function(){u.removeClass(v+"-state-hover"),n.changeView(i)}),s){var c=r.theme?J(r.buttonIcons,i):null,l=J(r.buttonText,i),u=t(""+(c?""+"":l)+"").click(function(){u.hasClass(v+"-state-disabled")||s()}).mousedown(function(){u.not("."+v+"-state-active").not("."+v+"-state-disabled").addClass(v+"-state-down")}).mouseup(function(){u.removeClass(v+"-state-down")}).hover(function(){u.not("."+v+"-state-active").not("."+v+"-state-disabled").addClass(v+"-state-hover")},function(){u.removeClass(v+"-state-hover").removeClass(v+"-state-down")}).appendTo(a);U(u),o||u.addClass(v+"-corner-left"),o=u}}}),o&&o.addClass(v+"-corner-right")}),a}function s(t){h.find("h2").html(t)}function c(t){h.find("span.fc-button-"+t).addClass(v+"-state-active")}function l(t){h.find("span.fc-button-"+t).removeClass(v+"-state-active")}function u(t){h.find("span.fc-button-"+t).addClass(v+"-state-disabled")}function f(t){h.find("span.fc-button-"+t).removeClass(v+"-state-disabled")}var d=this;d.render=a,d.destroy=o,d.updateTitle=s,d.activateButton=c,d.deactivateButton=l,d.disableButton=u,d.enableButton=f;var v,h=t([])}function o(n,r){function a(t,e){return!S||S>t||e>E}function o(t,e){S=t,E=e,W=[];var n=++F,r=z.length;R=r;for(var a=0;r>a;a++)i(z[a],n)}function i(e,r){s(e,function(a){if(r==F){if(a){n.eventDataTransform&&(a=t.map(a,n.eventDataTransform)),e.eventDataTransform&&(a=t.map(a,e.eventDataTransform));for(var o=0;a.length>o;o++)a[o].source=e,b(a[o]);W=W.concat(a)}R--,R||k(W)}})}function s(r,a){var o,i,c=we.sourceFetchers;for(o=0;c.length>o;o++){if(i=c[o](r,S,E,a),i===!0)return;if("object"==typeof i)return s(i,a),e}var l=r.events;if(l)t.isFunction(l)?(p(),l(d(S),d(E),function(t){a(t),y()})):t.isArray(l)?a(l):a();else{var u=r.url;if(u){var f=r.success,v=r.error,h=r.complete,g=t.extend({},r.data||{}),m=K(r.startParam,n.startParam),b=K(r.endParam,n.endParam);m&&(g[m]=Math.round(+S/1e3)),b&&(g[b]=Math.round(+E/1e3)),p(),t.ajax(t.extend({},Me,r,{data:g,success:function(e){e=e||[];var n=G(f,this,arguments);t.isArray(n)&&(e=n),a(e)},error:function(){G(v,this,arguments),a()},complete:function(){G(h,this,arguments),y()}}))}else a()}}function c(t){t=l(t),t&&(R++,i(t,F))}function l(n){return t.isFunction(n)||t.isArray(n)?n={events:n}:"string"==typeof n&&(n={url:n}),"object"==typeof n?(w(n),z.push(n),n):e}function u(e){z=t.grep(z,function(t){return!D(t,e)}),W=t.grep(W,function(t){return!D(t.source,e)}),k(W)}function f(t){var e,n,r=W.length,a=T().defaultEventEnd,o=t.start-t._start,i=t.end?t.end-(t._end||a(t)):0;for(e=0;r>e;e++)n=W[e],n._id==t._id&&n!=t&&(n.start=new Date(+n.start+o),n.end=t.end?n.end?new Date(+n.end+i):new Date(+a(n)+i):null,n.title=t.title,n.url=t.url,n.allDay=t.allDay,n.className=t.className,n.editable=t.editable,n.color=t.color,n.backgroudColor=t.backgroudColor,n.borderColor=t.borderColor,n.textColor=t.textColor,b(n));b(t),k(W)}function v(t,e){b(t),t.source||(e&&(H.events.push(t),t.source=H),W.push(t)),k(W)}function h(e){if(e){if(!t.isFunction(e)){var n=e+"";e=function(t){return t._id==n}}W=t.grep(W,e,!0);for(var r=0;z.length>r;r++)t.isArray(z[r].events)&&(z[r].events=t.grep(z[r].events,e,!0))}else{W=[];for(var r=0;z.length>r;r++)t.isArray(z[r].events)&&(z[r].events=[])}k(W)}function g(e){return t.isFunction(e)?t.grep(W,e):e?(e+="",t.grep(W,function(t){return t._id==e})):W}function p(){N++||x("loading",null,!0)}function y(){--N||x("loading",null,!1)}function b(t){var r=t.source||{},a=K(r.ignoreTimezone,n.ignoreTimezone);t._id=t._id||(t.id===e?"_fc"+Ce++:t.id+""),t.date&&(t.start||(t.start=t.date),delete t.date),t._start=d(t.start=m(t.start,a)),t.end=m(t.end,a),t.end&&t.end<=t.start&&(t.end=null),t._end=t.end?d(t.end):null,t.allDay===e&&(t.allDay=K(r.allDayDefault,n.allDayDefault)),t.className?"string"==typeof t.className&&(t.className=t.className.split(/\s+/)):t.className=[]}function w(t){t.className?"string"==typeof t.className&&(t.className=t.className.split(/\s+/)):t.className=[];for(var e=we.sourceNormalizers,n=0;e.length>n;n++)e[n](t)}function D(t,e){return t&&e&&M(t)==M(e)}function M(t){return("object"==typeof t?t.events||t.url:"")||t}var C=this;C.isFetchNeeded=a,C.fetchEvents=o,C.addEventSource=c,C.removeEventSource=u,C.updateEvent=f,C.renderEvent=v,C.removeEvents=h,C.clientEvents=g,C.normalizeEvent=b;for(var S,E,x=C.trigger,T=C.getView,k=C.reportEvents,H={events:[]},z=[H],F=0,R=0,N=0,W=[],A=0;r.length>A;A++)l(r[A])}function i(t,e,n){return t.setFullYear(t.getFullYear()+e),n||f(t),t}function s(t,e,n){if(+t){var r=t.getMonth()+e,a=d(t);for(a.setDate(1),a.setMonth(r),t.setMonth(r),n||f(t);t.getMonth()!=a.getMonth();)t.setDate(t.getDate()+(a>t?1:-1))}return t}function c(t,e,n){if(+t){var r=t.getDate()+e,a=d(t);a.setHours(9),a.setDate(r),t.setDate(r),n||f(t),l(t,a)}return t}function l(t,e){if(+t)for(;t.getDate()!=e.getDate();)t.setTime(+t+(e>t?1:-1)*xe)}function u(t,e){return t.setMinutes(t.getMinutes()+e),t}function f(t){return t.setHours(0),t.setMinutes(0),t.setSeconds(0),t.setMilliseconds(0),t}function d(t,e){return e?f(new Date(+t)):new Date(+t)}function v(){var t,e=0;do t=new Date(1970,e++,1);while(t.getHours());return t}function h(t,e,n){for(e=e||1;!t.getDay()||n&&1==t.getDay()||!n&&6==t.getDay();)c(t,e);return t}function g(t,e){return Math.round((d(t,!0)-d(e,!0))/Ee)}function p(t,n,r,a){n!==e&&n!=t.getFullYear()&&(t.setDate(1),t.setMonth(0),t.setFullYear(n)),r!==e&&r!=t.getMonth()&&(t.setDate(1),t.setMonth(r)),a!==e&&t.setDate(a)}function m(t,n){return"object"==typeof t?t:"number"==typeof t?new Date(1e3*t):"string"==typeof t?t.match(/^\d+(\.\d+)?$/)?new Date(1e3*parseFloat(t)):(n===e&&(n=!0),y(t,n)||(t?new Date(t):null)):null}function y(t,e){var n=t.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/);if(!n)return null;var r=new Date(n[1],0,1);if(e||!n[13]){var a=new Date(n[1],0,1,9,0);n[3]&&(r.setMonth(n[3]-1),a.setMonth(n[3]-1)),n[5]&&(r.setDate(n[5]),a.setDate(n[5])),l(r,a),n[7]&&r.setHours(n[7]),n[8]&&r.setMinutes(n[8]),n[10]&&r.setSeconds(n[10]),n[12]&&r.setMilliseconds(1e3*Number("0."+n[12])),l(r,a)}else if(r.setUTCFullYear(n[1],n[3]?n[3]-1:0,n[5]||1),r.setUTCHours(n[7]||0,n[8]||0,n[10]||0,n[12]?1e3*Number("0."+n[12]):0),n[14]){var o=60*Number(n[16])+(n[18]?Number(n[18]):0);o*="-"==n[15]?1:-1,r=new Date(+r+1e3*60*o)}return r}function b(t){if("number"==typeof t)return 60*t;if("object"==typeof t)return 60*t.getHours()+t.getMinutes();var e=t.match(/(\d+)(?::(\d+))?\s*(\w+)?/);if(e){var n=parseInt(e[1],10);return e[3]&&(n%=12,"p"==e[3].toLowerCase().charAt(0)&&(n+=12)),60*n+(e[2]?parseInt(e[2],10):0)}}function w(t,e,n){return D(t,null,e,n)}function D(t,e,n,r){r=r||ye;var a,o,i,s,c=t,l=e,u=n.length,f="";for(a=0;u>a;a++)if(o=n.charAt(a),"'"==o){for(i=a+1;u>i;i++)if("'"==n.charAt(i)){c&&(f+=i==a+1?"'":n.substring(a+1,i),a=i);break}}else if("("==o){for(i=a+1;u>i;i++)if(")"==n.charAt(i)){var d=w(c,n.substring(a+1,i),r);parseInt(d.replace(/\D/,""),10)&&(f+=d),a=i;break}}else if("["==o){for(i=a+1;u>i;i++)if("]"==n.charAt(i)){var v=n.substring(a+1,i),d=w(c,v,r);d!=w(l,v,r)&&(f+=d),a=i;break}}else if("{"==o)c=e,l=t;else if("}"==o)c=t,l=e;else{for(i=u;i>a;i--)if(s=ke[n.substring(a,i)]){c&&(f+=s(c,r)),a=i-1;break}i==a&&c&&(f+=o)}return f}function M(t){var e,n=new Date(t.getTime());return n.setDate(n.getDate()+4-(n.getDay()||7)),e=n.getTime(),n.setMonth(0),n.setDate(1),Math.floor(Math.round((e-n)/864e5)/7)+1}function C(t){return t.end?S(t.end,t.allDay):c(d(t.start),1)}function S(t,e){return t=d(t),e||t.getHours()||t.getMinutes()?c(t,1):f(t)}function E(t,e){return 100*(e.msLength-t.msLength)+(t.event.start-e.event.start)}function x(t,e){return t.end>e.start&&t.starta;a++)o=t[a],i=o.start,s=e[a],s>n&&r>i&&(n>i?(c=d(n),u=!1):(c=i,u=!0),s>r?(l=d(r),f=!1):(l=s,f=!0),v.push({event:o,start:c,end:l,isStart:u,isEnd:f,msLength:l-c}));return v.sort(E)}function k(t){var e,n,r,a,o,i=[],s=t.length;for(e=0;s>e;e++){for(n=t[e],r=0;;){if(a=!1,i[r])for(o=0;i[r].length>o;o++)if(x(i[r][o],n)){a=!0;break}if(!a)break;r++}i[r]?i[r].push(n):i[r]=[n]}return i}function H(n,r,a){n.unbind("mouseover").mouseover(function(n){for(var o,i,s,c=n.target;c!=this;)o=c,c=c.parentNode;(i=o._fci)!==e&&(o._fci=e,s=r[i],a(s.event,s.element,s),t(n.target).trigger(n)),n.stopPropagation()})}function z(e,n,r){for(var a,o=0;e.length>o;o++)a=t(e[o]),a.width(Math.max(0,n-R(a,r)))}function F(e,n,r){for(var a,o=0;e.length>o;o++)a=t(e[o]),a.height(Math.max(0,n-L(a,r)))}function R(t,e){return N(t)+A(t)+(e?W(t):0)}function N(e){return(parseFloat(t.css(e[0],"paddingLeft",!0))||0)+(parseFloat(t.css(e[0],"paddingRight",!0))||0)}function W(e){return(parseFloat(t.css(e[0],"marginLeft",!0))||0)+(parseFloat(t.css(e[0],"marginRight",!0))||0)}function A(e){return(parseFloat(t.css(e[0],"borderLeftWidth",!0))||0)+(parseFloat(t.css(e[0],"borderRightWidth",!0))||0)}function L(t,e){return _(t)+B(t)+(e?O(t):0)}function _(e){return(parseFloat(t.css(e[0],"paddingTop",!0))||0)+(parseFloat(t.css(e[0],"paddingBottom",!0))||0)}function O(e){return(parseFloat(t.css(e[0],"marginTop",!0))||0)+(parseFloat(t.css(e[0],"marginBottom",!0))||0)}function B(e){return(parseFloat(t.css(e[0],"borderTopWidth",!0))||0)+(parseFloat(t.css(e[0],"borderBottomWidth",!0))||0)}function q(t,e){e="number"==typeof e?e+"px":e,t.each(function(t,n){n.style.cssText+=";min-height:"+e+";_height:"+e})}function I(){}function Y(t,e){return t-e}function j(t){return Math.max.apply(Math,t)}function P(t){return(10>t?"0":"")+t}function J(t,n){if(t[n]!==e)return t[n];for(var r,a=n.split(/(?=[A-Z])/),o=a.length-1;o>=0;o--)if(r=t[a[o].toLowerCase()],r!==e)return r;return t[""]}function V(t){return t.replace(/&/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""").replace(/\n/g,"
")}function X(t){return t.id+"/"+t.className+"/"+t.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/gi,"")}function U(t){t.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return!1})}function Z(t){t.children().removeClass("fc-first fc-last").filter(":first-child").addClass("fc-first").end().filter(":last-child").addClass("fc-last")}function $(t,e){t.each(function(t,n){n.className=n.className.replace(/^fc-\w*/,"fc-"+Se[e.getDay()])})}function Q(t,e){var n=t.source||{},r=t.color,a=n.color,o=e("eventColor"),i=t.backgroundColor||r||n.backgroundColor||a||e("eventBackgroundColor")||o,s=t.borderColor||r||n.borderColor||a||e("eventBorderColor")||o,c=t.textColor||n.textColor||e("eventTextColor"),l=[];return i&&l.push("background-color:"+i),s&&l.push("border-color:"+s),c&&l.push("color:"+c),l.join(";")}function G(e,n,r){if(t.isFunction(e)&&(e=[e]),e){var a,o;for(a=0;e.length>a;a++)o=e[a].apply(n,r)||o;return o}}function K(){for(var t=0;arguments.length>t;t++)if(arguments[t]!==e)return arguments[t]}function te(t,e){function n(t,e){e&&(s(t,e),t.setDate(1));var n=d(t,!0);n.setDate(1);var l=s(d(n),1),u=d(n),f=d(l),v=a("firstDay"),g=a("weekends")?0:1;g&&(h(u),h(f,-1,!0)),c(u,-((u.getDay()-Math.max(v,g)+7)%7)),c(f,(7-f.getDay()+Math.max(v,g))%7);var p=Math.round((f-u)/(7*Ee));"fixed"==a("weekMode")&&(c(f,7*(6-p)),p=6),r.title=i(n,a("titleFormat")),r.start=n,r.end=l,r.visStart=u,r.visEnd=f,o(p,g?5:7,!0)}var r=this;r.render=n,re.call(r,t,e,"month");var a=r.opt,o=r.renderBasic,i=e.formatDate}function ee(t,e){function n(t,e){e&&c(t,7*e);var n=c(d(t),-((t.getDay()-a("firstDay")+7)%7)),s=c(d(n),7),l=d(n),u=d(s),f=a("weekends");f||(h(l),h(u,-1,!0)),r.title=i(l,c(d(u),-1),a("titleFormat")),r.start=n,r.end=s,r.visStart=l,r.visEnd=u,o(1,f?7:5,!1)}var r=this;r.render=n,re.call(r,t,e,"basicWeek");var a=r.opt,o=r.renderBasic,i=e.formatDates}function ne(t,e){function n(t,e){e&&(c(t,e),a("weekends")||h(t,0>e?-1:1)),r.title=i(t,a("titleFormat")),r.start=r.visStart=d(t,!0),r.end=r.visEnd=c(d(r.start),1),o(1,1,!1)}var r=this;r.render=n,re.call(r,t,e,"basicDay");var a=r.opt,o=r.renderBasic,i=e.formatDate}function re(e,n,r){function a(t,e,n){ne=t,re=e,o();var r=!P;r?i():Te(),s(n)}function o(){ce=Ee("isRTL"),ce?(le=-1,fe=re-1):(le=1,fe=0),pe=Ee("firstDay"),ye=Ee("weekends")?0:1,be=Ee("theme")?"ui":"fc",we=Ee("columnFormat"),De=Ee("weekNumbers"),Me=Ee("weekNumberTitle"),Ce="iso"!=Ee("weekNumberCalculation")?"w":"W"}function i(){Q=t("
").appendTo(e)}function s(n){var r,a,o,i,s="",c=be+"-widget-header",l=be+"-widget-content",u=B.start.getMonth(),d=f(new Date);for(s+="",De&&(s+="",r=0;ne>r;r++){for(s+="",De&&(s+=""),a=0;re>a;a++)o=F(r,a),i=["fc-day","fc-"+Se[o.getDay()],l],o.getMonth()!=u&&i.push("fc-other-month"),+o==+d&&(i.push("fc-today"),i.push(be+"-state-highlight")),s+="";s+=""}s+="
"),r=0;re>r;r++)o=F(0,r),s+="";for(s+="
"+"
"+"
"+"
",n&&(s+="
"+o.getDate()+"
"),s+="
 
",_(),I&&I.remove(),I=t(s).appendTo(e),Y=I.find("thead"),j=Y.find(".fc-day-header"),P=I.find("tbody"),J=P.find("tr"),V=P.find(".fc-day"),X=J.find("td:first-child"),$=J.eq(0).find(".fc-day-content > div"),Z(Y.add(Y.find("tr"))),Z(J),J.eq(0).addClass("fc-first"),J.filter(":last").addClass("fc-last"),De&&Y.find(".fc-week-number").text(Me),j.each(function(e,n){var r=R(e);t(n).text(Fe(r,we))}),De&&P.find(".fc-week-number > div").each(function(e,n){var r=F(e,0);t(n).text(Fe(r,Ce))}),V.each(function(e,n){var r=R(e);xe("dayRender",B,r,t(n))}),v(V)}function l(e){K=e;var n,r,a,o=K-Y.height();"variable"==Ee("weekMode")?n=r=Math.floor(o/(1==ne?2:6)):(n=Math.floor(o/ne),r=o-n*(ne-1)),X.each(function(e,o){ne>e&&(a=t(o),q(a.find("> div"),(e==ne-1?r:n)-L(a)))}),O()}function u(t){G=t,se.clear(),ee=0,De&&(ee=Y.find("th.fc-week-number").outerWidth()),te=Math.floor((G-ee)/re),z(j.slice(0,-1),te)}function v(t){t.click(h).mousedown(ze)}function h(e){if(!Ee("selectable")){var n=y(t(this).data("date"));xe("dayClick",this,n,!0,e)}}function p(t,e,n){n&&oe.build();for(var r=d(B.visStart),a=c(d(r),re),o=0;ne>o;o++){var i=new Date(Math.max(r,t)),s=new Date(Math.min(a,e));if(s>i){var l,u;ce?(l=g(s,r)*le+fe+1,u=g(i,r)*le+fe+1):(l=g(i,r),u=g(s,r)),v(m(o,l,o,u-1))}c(r,7),c(a,7)}}function m(t,n,r,a){var o=oe.rect(t,n,r,a,e);return ke(o,e)}function b(t){return d(t)}function w(t,e){p(t,c(d(e),1),!0)}function D(){He()}function M(t,e,n){var r=k(t),a=V[r.row*re+r.col];xe("dayClick",a,t,e,n)}function C(t,e){ie.start(function(t){He(),t&&m(t.row,t.col,t.row,t.col)},e)}function S(t,e,n){var r=ie.stop();if(He(),r){var a=H(r);xe("drop",t,a,!0,e,n)}}function E(t){return d(t.start)}function x(t){return se.left(t)}function T(t){return se.right(t)}function k(t){return{row:Math.floor(g(t,B.visStart)/7),col:N(t.getDay())}}function H(t){return F(t.row,t.col)}function F(t,e){return c(d(B.visStart),7*t+e*le+fe)}function R(t){return F(Math.floor(t/re),t%re)}function N(t){return(t-Math.max(pe,ye)+re)%re*le+fe}function W(t){return J.eq(t)}function A(){var t=0;return De&&(t+=ee),{left:t,right:G}}function _(){q(e,e.height())}function O(){q(e,1)}var B=this;B.renderBasic=a,B.setHeight=l,B.setWidth=u,B.renderDayOverlay=p,B.defaultSelectionEnd=b,B.renderSelection=w,B.clearSelection=D,B.reportDayClick=M,B.dragStart=C,B.dragStop=S,B.defaultEventEnd=E,B.getHoverListener=function(){return ie},B.colContentLeft=x,B.colContentRight=T,B.dayOfWeekCol=N,B.dateCell=k,B.cellDate=H,B.cellIsAllDay=function(){return!0},B.allDayRow=W,B.allDayBounds=A,B.getRowCnt=function(){return ne},B.getColCnt=function(){return re},B.getColWidth=function(){return te},B.getDaySegmentContainer=function(){return Q},ue.call(B,e,n,r),ve.call(B),de.call(B),ae.call(B);var I,Y,j,P,J,V,X,$,Q,G,K,te,ee,ne,re,oe,ie,se,ce,le,fe,pe,ye,be,we,De,Me,Ce,Ee=B.opt,xe=B.trigger,Te=B.clearEvents,ke=B.renderOverlay,He=B.clearOverlays,ze=B.daySelectionMousedown,Fe=n.formatDate;U(e.addClass("fc-grid")),oe=new he(function(e,n){var r,a,o;j.each(function(e,i){r=t(i),a=r.offset().left,e&&(o[1]=a),o=[a],n[e]=o}),o[1]=a+r.outerWidth(),J.each(function(n,i){ne>n&&(r=t(i),a=r.offset().top,n&&(o[1]=a),o=[a],e[n]=o)}),o[1]=a+r.outerHeight()}),ie=new ge(oe),se=new me(function(t){return $.eq(t)})}function ae(){function e(t,e){v(t),x(r(t),e),l("eventAfterAllRender")}function n(){h(),b().empty()}function r(e){var n,r,a,o,s,l,u=S(),f=E(),v=d(i.visStart),h=c(d(v),f),g=t.map(e,C),p=[];for(n=0;u>n;n++){for(r=k(T(e,g,v,h)),a=0;r.length>a;a++)for(o=r[a],s=0;o.length>s;s++)l=o[s],l.row=n,l.level=a,p.push(l);c(v,7),c(h,7)}return p}function a(t,e,n){u(t)&&o(t,e),n.isEnd&&f(t)&&H(t,e,n),g(t,e)}function o(t,e){var n,r=w();e.draggable({zIndex:9,delay:50,opacity:s("dragOpacity"),revertDuration:s("dragRevertDuration"),start:function(a,o){l("eventDragStart",e,t,a,o),m(t,e),r.start(function(r,a,o,i){e.draggable("option","revert",!r||!o&&!i),M(),r?(n=7*o+i*(s("isRTL")?-1:1),D(c(d(t.start),n),c(C(t),n))):n=0},a,"drag")},stop:function(a,o){r.stop(),M(),l("eventDragStop",e,t,a,o),n?y(this,t,n,0,t.allDay,a,o):(e.css("filter",""),p(t,e))}})}var i=this;i.renderEvents=e,i.compileDaySegs=r,i.clearEvents=n,i.bindDaySeg=a,fe.call(i);var s=i.opt,l=i.trigger,u=i.isEventDraggable,f=i.isEventResizable,v=i.reportEvents,h=i.reportEventClear,g=i.eventElementHandlers,p=i.showEvents,m=i.hideEvents,y=i.eventDrop,b=i.getDaySegmentContainer,w=i.getHoverListener,D=i.renderDayOverlay,M=i.clearOverlays,S=i.getRowCnt,E=i.getColCnt,x=i.renderDaySegs,H=i.resizableDayEvent}function oe(t,e){function n(t,e){e&&c(t,7*e);var n=c(d(t),-((t.getDay()-a("firstDay")+7)%7)),s=c(d(n),7),l=d(n),u=d(s),f=a("weekends");f||(h(l),h(u,-1,!0)),r.title=i(l,c(d(u),-1),a("titleFormat")),r.start=n,r.end=s,r.visStart=l,r.visEnd=u,o(f?7:5)}var r=this;r.render=n,se.call(r,t,e,"agendaWeek");var a=r.opt,o=r.renderAgenda,i=e.formatDates}function ie(t,e){function n(t,e){e&&(c(t,e),a("weekends")||h(t,0>e?-1:1));var n=d(t,!0),s=c(d(n),1);r.title=i(t,a("titleFormat")),r.start=r.visStart=n,r.end=r.visEnd=s,o(1)}var r=this;r.render=n,se.call(r,t,e,"agendaDay");var a=r.opt,o=r.renderAgenda,i=e.formatDate}function se(n,r,a){function o(t){Le=t,i(),te?nn():s(),l()}function i(){Ye=tn("theme")?"ui":"fc",Pe=tn("weekends")?0:1,je=tn("firstDay"),(Je=tn("isRTL"))?(Ve=-1,Xe=Le-1):(Ve=1,Xe=0),Ue=b(tn("minTime")),Ze=b(tn("maxTime")),$e=tn("columnFormat"),Qe=tn("weekNumbers"),Ge=tn("weekNumberTitle"),Ke="iso"!=tn("weekNumberCalculation")?"w":"W",Ne=tn("snapMinutes")||tn("slotMinutes")}function s(){var e,r,a,o,i,s=Ye+"-widget-header",c=Ye+"-widget-content",l=0==tn("slotMinutes")%15;for(e="",e+=Qe?"",r=0;Le>r;r++)e+=""+""+""+""+""+"",r=0;Le>r;r++)e+="";for(e+=""+""+""+"
":" ";for(e+=" 
 "+"
"+"
"+"
 
"+"
"+"
"+"
 
",te=t(e).appendTo(n),ee=te.find("thead"),ne=ee.find("th").slice(1,-1),re=te.find("tbody"),ae=re.find("td").slice(0,-1),oe=ae.find("div.fc-day-content div"),ie=ae.eq(0),se=ie.find("> div"),Z(ee.add(ee.find("tr"))),Z(re.add(re.find("tr"))),Se=ee.find("th:first"),Ee=te.find(".fc-agenda-gutter"),le=t("
").appendTo(n),tn("allDaySlot")?(fe=t("
").appendTo(le),e=""+""+""+""+"
"+tn("allDayText")+""+"
"+"
 
",pe=t(e).appendTo(le),ye=pe.find("tr"),D(ye.find("td")),Se=Se.add(pe.find("th:first")),Ee=Ee.add(pe.find("th.fc-agenda-gutter")),le.append("
"+"
"+"
")):fe=t([]),be=t("
").appendTo(le),we=t("
").appendTo(be),De=t("
").appendTo(we),e="",a=v(),o=u(d(a),Ze),u(a,Ue),_e=0,r=0;o>a;r++)i=a.getMinutes(),e+=""+""+""+"",u(a,tn("slotMinutes")),_e++;e+="
"+(l&&i?" ":un(a,tn("axisFormat")))+""+"
 
"+"
",Me=t(e).appendTo(we),Ce=Me.find("div:first"),M(Me.find("td")),Se=Se.add(Me.find("th:first"))}function l(){var t,e,n,r,a=f(new Date);if(Qe){var o=un(N(0),Ke);Je?o+=Ge:o=Ge+o,ee.find(".fc-week-number").text(o)}for(t=0;Le>t;t++)r=N(t),e=ne.eq(t),e.html(un(r,$e)),n=ae.eq(t),+r==+a?n.addClass(Ye+"-state-highlight fc-today"):n.removeClass(Ye+"-state-highlight fc-today"),$(e.add(n),r)}function h(t,n){t===e&&(t=ke),ke=t,fn={};var r=re.position().top,a=be.position().top,o=Math.min(t-r,Me.height()+a+1);se.height(o-L(ie)),le.css("top",r),be.height(o-a-1),Re=Ce.height()+1,We=tn("slotMinutes")/Ne,Ae=Re/We,n&&m()}function p(e){Te=e,qe.clear(),He=0,z(Se.width("").each(function(e,n){He=Math.max(He,t(n).outerWidth())}),He);var n=be[0].clientWidth;Fe=be.width()-n,Fe?(z(Ee,Fe),Ee.show().prev().removeClass("fc-last")):Ee.hide().prev().addClass("fc-last"),ze=Math.floor((n-He)/Le),z(ne.slice(0,-1),ze)}function m(){function t(){be.scrollTop(r)}var e=v(),n=d(e);n.setHours(tn("firstHour"));var r=_(e,n)+1;t(),setTimeout(t,0)}function y(){Ie=be.scrollTop()}function w(){be.scrollTop(Ie)}function D(t){t.click(C).mousedown(cn)}function M(t){t.click(C).mousedown(V)}function C(t){if(!tn("selectable")){var e=Math.min(Le-1,Math.floor((t.pageX-te.offset().left-He)/ze)),n=N(e),r=this.parentNode.className.match(/fc-slot(\d+)/);if(r){var a=parseInt(r[1])*tn("slotMinutes"),o=Math.floor(a/60);n.setHours(o),n.setMinutes(a%60+Ue),en("dayClick",ae[e],n,!1,t)}else en("dayClick",ae[e],n,!0,t)}}function S(t,e,n){n&&Oe.build();var r,a,o=d(K.visStart);Je?(r=g(e,o)*Ve+Xe+1,a=g(t,o)*Ve+Xe+1):(r=g(t,o),a=g(e,o)),r=Math.max(0,r),a=Math.min(Le,a),a>r&&D(E(0,r,0,a-1))}function E(t,e,n,r){var a=Oe.rect(t,e,n,r,le);return rn(a,le)}function x(t,e){for(var n=d(K.visStart),r=c(d(n),1),a=0;Le>a;a++){var o=new Date(Math.max(n,t)),i=new Date(Math.min(r,e));if(i>o){var s=a*Ve+Xe,l=Oe.rect(0,s,0,s,we),u=_(n,o),f=_(n,i);l.top=u,l.height=f-u,M(rn(l,we))}c(n,1),c(r,1)}}function T(t){return qe.left(t)}function k(t){return qe.right(t)}function H(t){return{row:Math.floor(g(t,K.visStart)/7),col:A(t.getDay())}}function R(t){var e=N(t.col),n=t.row;return tn("allDaySlot")&&n--,n>=0&&u(e,Ue+n*Ne),e}function N(t){return c(d(K.visStart),t*Ve+Xe)}function W(t){return tn("allDaySlot")&&!t.row}function A(t){return(t-Math.max(je,Pe)+Le)%Le*Ve+Xe}function _(t,n){if(t=d(t,!0),u(d(t),Ue)>n)return 0;if(n>=u(d(t),Ze))return Me.height();var r=tn("slotMinutes"),a=60*n.getHours()+n.getMinutes()-Ue,o=Math.floor(a/r),i=fn[o];return i===e&&(i=fn[o]=Me.find("tr:eq("+o+") td div")[0].offsetTop),Math.max(0,Math.round(i-1+Re*(a%r/r)))}function O(){return{left:He,right:Te-Fe}}function B(){return ye}function q(t){var e=d(t.start);return t.allDay?e:u(e,tn("defaultEventMinutes"))}function I(t,e){return e?d(t):u(d(t),tn("slotMinutes"))}function j(t,e,n){n?tn("allDaySlot")&&S(t,c(d(e),1),!0):P(t,e)}function P(e,n){var r=tn("selectHelper");if(Oe.build(),r){var a=g(e,K.visStart)*Ve+Xe;if(a>=0&&Le>a){var o=Oe.rect(0,a,0,a,we),i=_(e,e),s=_(e,n);if(s>i){if(o.top=i,o.height=s-i,o.left+=2,o.width-=5,t.isFunction(r)){var c=r(e,n);c&&(o.position="absolute",o.zIndex=8,xe=t(c).css(o).appendTo(we))}else o.isStart=!0,o.isEnd=!0,xe=t(ln({title:"",start:e,end:n,className:["fc-select-helper"],editable:!1},o)),xe.css("opacity",tn("dragOpacity"));xe&&(M(xe),we.append(xe),z(xe,o.width,!0),F(xe,o.height,!0))}}}else x(e,n)}function J(){an(),xe&&(xe.remove(),xe=null)}function V(e){if(1==e.which&&tn("selectable")){sn(e);var n;Be.start(function(t,e){if(J(),t&&t.col==e.col&&!W(t)){var r=R(e),a=R(t);n=[r,u(d(r),Ne),a,u(d(a),Ne)].sort(Y),P(n[0],n[3])}else n=null},e),t(document).one("mouseup",function(t){Be.stop(),n&&(+n[0]==+n[1]&&X(n[0],!1,t),on(n[0],n[3],!1,t))})}}function X(t,e,n){en("dayClick",ae[A(t.getDay())],t,e,n)}function Q(t,e){Be.start(function(t){if(an(),t)if(W(t))E(t.row,t.col,t.row,t.col);else{var e=R(t),n=u(d(e),tn("defaultEventMinutes"));x(e,n)}},e)}function G(t,e,n){var r=Be.stop();an(),r&&en("drop",t,R(r),W(r),e,n)}var K=this;K.renderAgenda=o,K.setWidth=p,K.setHeight=h,K.beforeHide=y,K.afterShow=w,K.defaultEventEnd=q,K.timePosition=_,K.dayOfWeekCol=A,K.dateCell=H,K.cellDate=R,K.cellIsAllDay=W,K.allDayRow=B,K.allDayBounds=O,K.getHoverListener=function(){return Be},K.colContentLeft=T,K.colContentRight=k,K.getDaySegmentContainer=function(){return fe},K.getSlotSegmentContainer=function(){return De},K.getMinMinute=function(){return Ue},K.getMaxMinute=function(){return Ze},K.getBodyContent=function(){return we},K.getRowCnt=function(){return 1},K.getColCnt=function(){return Le},K.getColWidth=function(){return ze},K.getSnapHeight=function(){return Ae},K.getSnapMinutes=function(){return Ne},K.defaultSelectionEnd=I,K.renderDayOverlay=S,K.renderSelection=j,K.clearSelection=J,K.reportDayClick=X,K.dragStart=Q,K.dragStop=G,ue.call(K,n,r,a),ve.call(K),de.call(K),ce.call(K);var te,ee,ne,re,ae,oe,ie,se,le,fe,pe,ye,be,we,De,Me,Ce,Se,Ee,xe,Te,ke,He,ze,Fe,Re,Ne,We,Ae,Le,_e,Oe,Be,qe,Ie,Ye,je,Pe,Je,Ve,Xe,Ue,Ze,$e,Qe,Ge,Ke,tn=K.opt,en=K.trigger,nn=K.clearEvents,rn=K.renderOverlay,an=K.clearOverlays,on=K.reportSelection,sn=K.unselect,cn=K.daySelectionMousedown,ln=K.slotSegHtml,un=r.formatDate,fn={};U(n.addClass("fc-agenda")),Oe=new he(function(e,n){function r(t){return Math.max(c,Math.min(l,t))}var a,o,i;ne.each(function(e,r){a=t(r),o=a.offset().left,e&&(i[1]=o),i=[o],n[e]=i}),i[1]=o+a.outerWidth(),tn("allDaySlot")&&(a=ye,o=a.offset().top,e[0]=[o,o+a.outerHeight()]);for(var s=we.offset().top,c=be.offset().top,l=c+be.outerHeight(),u=0;_e*We>u;u++)e.push([r(s+Ae*u),r(s+Ae*(u+1))])}),Be=new ge(Oe),qe=new me(function(t){return oe.eq(t)})}function ce(){function n(t,e){S(t);var n,r=t.length,i=[],c=[];for(n=0;r>n;n++)t[n].allDay?i.push(t[n]):c.push(t[n]);y("allDaySlot")&&(Y(a(i),e),z()),s(o(c),e),b("eventAfterAllRender")}function r(){E(),N().empty(),W().empty()}function a(e){var n,r,a,o,i=k(T(e,t.map(e,C),m.visStart,m.visEnd)),s=i.length,c=[];for(n=0;s>n;n++)for(r=i[n],a=0;r.length>a;a++)o=r[a],o.row=0,o.level=n,c.push(o);return c}function o(e){var n,r,a,o,s,l,f=P(),v=O(),h=_(),g=u(d(m.visStart),v),p=t.map(e,i),y=[];for(n=0;f>n;n++){for(r=k(T(e,p,g,u(d(g),h-v))),le(r),a=0;r.length>a;a++)for(o=r[a],s=0;o.length>s;s++)l=o[s],l.col=n,l.level=a,y.push(l);c(g,1,!0)}return y}function i(t){return t.end?d(t.end):u(d(t.start),y("defaultEventMinutes"))}function s(n,r){var a,o,i,s,c,u,f,d,h,g,p,m,w,D,M,C,S,E,x,T,k,z,F=n.length,N="",A={},_={},O=W(),Y=P();for((T=y("isRTL"))?(k=-1,z=Y-1):(k=1,z=0),a=0;F>a;a++)o=n[a],i=o.event,s=B(o.start,o.start),c=B(o.start,o.end),u=o.col,f=o.level,d=o.forward||0,h=q(u*k+z),g=I(u*k+z)-h,g=Math.min(g-6,.95*g),p=f?g/(f+d+1):d?2*(g/(d+1)-6):g,m=h+g/(f+d+1)*f*k+(T?g-p:0),o.top=s,o.left=m,o.outerWidth=p,o.outerHeight=c-s,N+=l(i,o); -for(O[0].innerHTML=N,w=O.children(),a=0;F>a;a++)o=n[a],i=o.event,D=t(w[a]),M=b("eventRender",i,i,D),M===!1?D.remove():(M&&M!==!0&&(D.remove(),D=t(M).css({position:"absolute",top:o.top,left:o.left}).appendTo(O)),o.element=D,i._id===r?v(i,D,o):D[0]._fci=a,G(i,D));for(H(O,n,v),a=0;F>a;a++)o=n[a],(D=o.element)&&(S=A[C=o.key=X(D[0])],o.vsides=S===e?A[C]=L(D,!0):S,S=_[C],o.hsides=S===e?_[C]=R(D,!0):S,E=D.find(".fc-event-title"),E.length&&(o.contentTop=E[0].offsetTop));for(a=0;F>a;a++)o=n[a],(D=o.element)&&(D[0].style.width=Math.max(0,o.outerWidth-o.hsides)+"px",x=Math.max(0,o.outerHeight-o.vsides),D[0].style.height=x+"px",i=o.event,o.contentTop!==e&&10>x-o.contentTop&&(D.find("div.fc-event-time").text(ie(i.start,y("timeFormat"))+" - "+i.title),D.find("div.fc-event-title").remove()),b("eventAfterRender",i,i,D))}function l(t,e){var n="<",r=t.url,a=Q(t,y),o=["fc-event","fc-event-vert"];return w(t)&&o.push("fc-event-draggable"),e.isStart&&o.push("fc-event-start"),e.isEnd&&o.push("fc-event-end"),o=o.concat(t.className),t.source&&(o=o.concat(t.source.className||[])),n+=r?"a href='"+V(t.url)+"'":"div",n+=" class='"+o.join(" ")+"'"+" style='position:absolute;z-index:8;top:"+e.top+"px;left:"+e.left+"px;"+a+"'"+">"+"
"+"
"+V(se(t.start,t.end,y("timeFormat")))+"
"+"
"+V(t.title)+"
"+"
"+"
",e.isEnd&&D(t)&&(n+="
=
"),n+=""}function f(t,e,n){w(t)&&h(t,e,n.isStart),n.isEnd&&D(t)&&j(t,e,n),x(t,e)}function v(t,e,n){var r=e.find("div.fc-event-time");w(t)&&g(t,e,r),n.isEnd&&D(t)&&p(t,e,r),x(t,e)}function h(t,e,n){function r(){s||(e.width(a).height("").draggable("option","grid",null),s=!0)}var a,o,i,s=!0,l=y("isRTL")?-1:1,u=A(),f=J(),v=U(),h=Z(),g=O();e.draggable({zIndex:9,opacity:y("dragOpacity","month"),revertDuration:y("dragRevertDuration"),start:function(g,p){b("eventDragStart",e,t,g,p),te(t,e),a=e.width(),u.start(function(a,u,g,p){ae(),a?(o=!1,i=p*l,a.row?n?s&&(e.width(f-10),F(e,v*Math.round((t.end?(t.end-t.start)/Te:y("defaultEventMinutes"))/h)),e.draggable("option","grid",[f,1]),s=!1):o=!0:(re(c(d(t.start),i),c(C(t),i)),r()),o=o||s&&!i):(r(),o=!0),e.draggable("option","revert",o)},g,"drag")},stop:function(n,a){if(u.stop(),ae(),b("eventDragStop",e,t,n,a),o)r(),e.css("filter",""),K(t,e);else{var c=0;s||(c=Math.round((e.offset().top-$().offset().top)/v)*h+g-(60*t.start.getHours()+t.start.getMinutes())),ee(this,t,i,c,s,n,a)}}})}function g(t,e,n){function r(e){var r,a=u(d(t.start),e);t.end&&(r=u(d(t.end),e)),n.text(se(a,r,y("timeFormat")))}function a(){f&&(n.css("display",""),e.draggable("option","grid",[p,m]),f=!1)}var o,i,s,l,f=!1,v=y("isRTL")?-1:1,h=A(),g=P(),p=J(),m=U(),w=Z();e.draggable({zIndex:9,scroll:!1,grid:[p,m],axis:1==g?"y":!1,opacity:y("dragOpacity"),revertDuration:y("dragRevertDuration"),start:function(r,u){b("eventDragStart",e,t,r,u),te(t,e),o=e.position(),s=l=0,h.start(function(r,o,s,l){e.draggable("option","revert",!r),ae(),r&&(i=l*v,y("allDaySlot")&&!r.row?(f||(f=!0,n.hide(),e.draggable("option","grid",null)),re(c(d(t.start),i),c(C(t),i))):a())},r,"drag")},drag:function(t,e){s=Math.round((e.position.top-o.top)/m)*w,s!=l&&(f||r(s),l=s)},stop:function(n,c){var l=h.stop();ae(),b("eventDragStop",e,t,n,c),l&&(i||s||f)?ee(this,t,i,f?0:s,f,n,c):(a(),e.css("filter",""),e.css(o),r(0),K(t,e))}})}function p(t,e,n){var r,a,o=U(),i=Z();e.resizable({handles:{s:".ui-resizable-handle"},grid:o,start:function(n,o){r=a=0,te(t,e),e.css("z-index",9),b("eventResizeStart",this,t,n,o)},resize:function(s,c){r=Math.round((Math.max(o,e.height())-c.originalSize.height)/o),r!=a&&(n.text(se(t.start,r||t.end?u(M(t),i*r):null,y("timeFormat"))),a=r)},stop:function(n,a){b("eventResizeStop",this,t,n,a),r?ne(this,t,0,i*r,n,a):(e.css("z-index",8),K(t,e))}})}var m=this;m.renderEvents=n,m.compileDaySegs=a,m.clearEvents=r,m.slotSegHtml=l,m.bindDaySeg=f,fe.call(m);var y=m.opt,b=m.trigger,w=m.isEventDraggable,D=m.isEventResizable,M=m.eventEnd,S=m.reportEvents,E=m.reportEventClear,x=m.eventElementHandlers,z=m.setHeight,N=m.getDaySegmentContainer,W=m.getSlotSegmentContainer,A=m.getHoverListener,_=m.getMaxMinute,O=m.getMinMinute,B=m.timePosition,q=m.colContentLeft,I=m.colContentRight,Y=m.renderDaySegs,j=m.resizableDayEvent,P=m.getColCnt,J=m.getColWidth,U=m.getSnapHeight,Z=m.getSnapMinutes,$=m.getBodyContent,G=m.reportEventElement,K=m.showEvents,te=m.hideEvents,ee=m.eventDrop,ne=m.eventResize,re=m.renderDayOverlay,ae=m.clearOverlays,oe=m.calendar,ie=oe.formatDate,se=oe.formatDates}function le(t){var e,n,r,a,o,i;for(e=t.length-1;e>0;e--)for(a=t[e],n=0;a.length>n;n++)for(o=a[n],r=0;t[e-1].length>r;r++)i=t[e-1][r],x(o,i)&&(i.forward=Math.max(i.forward||0,(o.forward||0)+1))}function ue(t,n,r){function a(t,e){var n=F[t];return"object"==typeof n?J(n,e||r):n}function o(t,e){return n.trigger.apply(n,[t,e||S].concat(Array.prototype.slice.call(arguments,2),[S]))}function i(t){return l(t)&&!a("disableDragging")}function s(t){return l(t)&&!a("disableResizing")}function l(t){return K(t.editable,(t.source||{}).editable,a("editable"))}function f(t){k={};var e,n,r=t.length;for(e=0;r>e;e++)n=t[e],k[n._id]?k[n._id].push(n):k[n._id]=[n]}function v(t){return t.end?d(t.end):E(t)}function h(t,e){H.push(e),z[t._id]?z[t._id].push(e):z[t._id]=[e]}function g(){H=[],z={}}function p(t,n){n.click(function(r){return n.hasClass("ui-draggable-dragging")||n.hasClass("ui-resizable-resizing")?e:o("eventClick",this,t,r)}).hover(function(e){o("eventMouseover",this,t,e)},function(e){o("eventMouseout",this,t,e)})}function m(t,e){b(t,e,"show")}function y(t,e){b(t,e,"hide")}function b(t,e,n){var r,a=z[t._id],o=a.length;for(r=0;o>r;r++)e&&a[r][0]==e[0]||a[r][n]()}function w(t,e,n,r,a,i,s){var c=e.allDay,l=e._id;M(k[l],n,r,a),o("eventDrop",t,e,n,r,a,function(){M(k[l],-n,-r,c),T(l)},i,s),T(l)}function D(t,e,n,r,a,i){var s=e._id;C(k[s],n,r),o("eventResize",t,e,n,r,function(){C(k[s],-n,-r),T(s)},a,i),T(s)}function M(t,n,r,a){r=r||0;for(var o,i=t.length,s=0;i>s;s++)o=t[s],a!==e&&(o.allDay=a),u(c(o.start,n,!0),r),o.end&&(o.end=u(c(o.end,n,!0),r)),x(o,F)}function C(t,e,n){n=n||0;for(var r,a=t.length,o=0;a>o;o++)r=t[o],r.end=u(c(v(r),e,!0),n),x(r,F)}var S=this;S.element=t,S.calendar=n,S.name=r,S.opt=a,S.trigger=o,S.isEventDraggable=i,S.isEventResizable=s,S.reportEvents=f,S.eventEnd=v,S.reportEventElement=h,S.reportEventClear=g,S.eventElementHandlers=p,S.showEvents=m,S.hideEvents=y,S.eventDrop=w,S.eventResize=D;var E=S.defaultEventEnd,x=n.normalizeEvent,T=n.reportEventChange,k={},H=[],z={},F=n.options}function fe(){function n(t,e){var n,r,c,d,p,m,y,b,w=B(),D=T(),M=k(),C=0,S=t.length;for(w[0].innerHTML=a(t),o(t,w.children()),i(t),s(t,w,e),l(t),u(t),f(t),n=v(),r=0;D>r;r++){for(c=0,d=[],p=0;M>p;p++)d[p]=0;for(;S>C&&(m=t[C]).row==r;){for(y=j(d.slice(m.startCol,m.endCol)),m.top=y,y+=m.outerHeight,b=m.startCol;m.endCol>b;b++)d[b]=y;C++}n[r].height(j(d))}g(t,h(n))}function r(e,n,r){var i,s,c,d=t("
"),p=B(),m=e.length;for(d[0].innerHTML=a(e),i=d.children(),p.append(i),o(e,i),l(e),u(e),f(e),g(e,h(v())),i=[],s=0;m>s;s++)c=e[s].element,c&&(e[s].row===n&&c.css("top",r),i.push(c[0]));return t(i)}function a(t){var e,n,r,a,o,i,s,c,l,u,f=y("isRTL"),d=t.length,v=F(),h=v.left,g=v.right,p="";for(e=0;d>e;e++)n=t[e],r=n.event,o=["fc-event","fc-event-hori"],w(r)&&o.push("fc-event-draggable"),n.isStart&&o.push("fc-event-start"),n.isEnd&&o.push("fc-event-end"),f?(i=A(n.end.getDay()-1),s=A(n.start.getDay()),c=n.isEnd?N(i):h,l=n.isStart?W(s):g):(i=A(n.start.getDay()),s=A(n.end.getDay()-1),c=n.isStart?N(i):h,l=n.isEnd?W(s):g),o=o.concat(r.className),r.source&&(o=o.concat(r.source.className||[])),a=r.url,u=Q(r,y),p+=a?""+"
",!r.allDay&&n.isStart&&(p+=""+V(I(r.start,r.end,y("timeFormat")))+""),p+=""+V(r.title)+""+"
",n.isEnd&&D(r)&&(p+="
"+"   "+"
"),p+="",n.left=c,n.outerWidth=l-c,n.startCol=i,n.endCol=s+1;return p}function o(e,n){var r,a,o,i,s,c=e.length;for(r=0;c>r;r++)a=e[r],o=a.event,i=t(n[r]),s=b("eventRender",o,o,i),s===!1?i.remove():(s&&s!==!0&&(s=t(s).css({position:"absolute",left:a.left}),i.replaceWith(s),i=s),a.element=i)}function i(t){var e,n,r,a=t.length;for(e=0;a>e;e++)n=t[e],r=n.element,r&&C(n.event,r)}function s(t,e,n){var r,a,o,i,s=t.length;for(r=0;s>r;r++)a=t[r],o=a.element,o&&(i=a.event,i._id===n?q(i,o,a):o[0]._fci=r);H(e,t,q)}function l(t){var n,r,a,o,i,s=t.length,c={};for(n=0;s>n;n++)r=t[n],a=r.element,a&&(o=r.key=X(a[0]),i=c[o],i===e&&(i=c[o]=R(a,!0)),r.hsides=i)}function u(t){var e,n,r,a=t.length;for(e=0;a>e;e++)n=t[e],r=n.element,r&&(r[0].style.width=Math.max(0,n.outerWidth-n.hsides)+"px")}function f(t){var n,r,a,o,i,s=t.length,c={};for(n=0;s>n;n++)r=t[n],a=r.element,a&&(o=r.key,i=c[o],i===e&&(i=c[o]=O(a)),r.outerHeight=a[0].offsetHeight+i)}function v(){var t,e=T(),n=[];for(t=0;e>t;t++)n[t]=z(t).find("div.fc-day-content > div");return n}function h(t){var e,n=t.length,r=[];for(e=0;n>e;e++)r[e]=t[e][0].offsetTop;return r}function g(t,e){var n,r,a,o,i=t.length;for(n=0;i>n;n++)r=t[n],a=r.element,a&&(a[0].style.top=e[r.row]+(r.top||0)+"px",o=r.event,b("eventAfterRender",o,o,a))}function p(e,n,a){var o=y("isRTL"),i=o?"w":"e",s=n.find(".ui-resizable-"+i),l=!1;U(n),n.mousedown(function(t){t.preventDefault()}).click(function(t){l&&(t.preventDefault(),t.stopImmediatePropagation())}),s.mousedown(function(s){function u(n){b("eventResizeStop",this,e,n),t("body").css("cursor",""),h.stop(),P(),f&&x(this,e,f,0,n),setTimeout(function(){l=!1},0)}if(1==s.which){l=!0;var f,v,h=m.getHoverListener(),g=T(),p=k(),y=o?-1:1,w=o?p-1:0,D=n.css("top"),C=t.extend({},e),H=L(e.start);J(),t("body").css("cursor",i+"-resize").one("mouseup",u),b("eventResizeStart",this,e,s),h.start(function(t,n){if(t){var s=Math.max(H.row,t.row),l=t.col;1==g&&(s=0),s==H.row&&(l=o?Math.min(H.col,l):Math.max(H.col,l)),f=7*s+l*y+w-(7*n.row+n.col*y+w);var u=c(M(e),f,!0);if(f){C.end=u;var h=v;v=r(_([C]),a.row,D),v.find("*").css("cursor",i+"-resize"),h&&h.remove(),E(e)}else v&&(S(e),v.remove(),v=null);P(),Y(e.start,c(d(u),1))}},s)}})}var m=this;m.renderDaySegs=n,m.resizableDayEvent=p;var y=m.opt,b=m.trigger,w=m.isEventDraggable,D=m.isEventResizable,M=m.eventEnd,C=m.reportEventElement,S=m.showEvents,E=m.hideEvents,x=m.eventResize,T=m.getRowCnt,k=m.getColCnt;m.getColWidth;var z=m.allDayRow,F=m.allDayBounds,N=m.colContentLeft,W=m.colContentRight,A=m.dayOfWeekCol,L=m.dateCell,_=m.compileDaySegs,B=m.getDaySegmentContainer,q=m.bindDaySeg,I=m.calendar.formatDates,Y=m.renderDayOverlay,P=m.clearOverlays,J=m.clearSelection}function de(){function e(t,e,a){n(),e||(e=c(t,a)),l(t,e,a),r(t,e,a)}function n(t){f&&(f=!1,u(),s("unselect",null,t))}function r(t,e,n,r){f=!0,s("select",null,t,e,n,r)}function a(e){var a=o.cellDate,s=o.cellIsAllDay,c=o.getHoverListener(),f=o.reportDayClick;if(1==e.which&&i("selectable")){n(e);var d;c.start(function(t,e){u(),t&&s(t)?(d=[a(e),a(t)].sort(Y),l(d[0],d[1],!0)):d=null},e),t(document).one("mouseup",function(t){c.stop(),d&&(+d[0]==+d[1]&&f(d[0],!0,t),r(d[0],d[1],!0,t))})}}var o=this;o.select=e,o.unselect=n,o.reportSelection=r,o.daySelectionMousedown=a;var i=o.opt,s=o.trigger,c=o.defaultSelectionEnd,l=o.renderSelection,u=o.clearSelection,f=!1;i("selectable")&&i("unselectAuto")&&t(document).mousedown(function(e){var r=i("unselectCancel");r&&t(e.target).parents(r).length||n(e)})}function ve(){function e(e,n){var r=o.shift();return r||(r=t("
")),r[0].parentNode!=n[0]&&r.appendTo(n),a.push(r.css(e).show()),r}function n(){for(var t;t=a.shift();)o.push(t.hide().unbind())}var r=this;r.renderOverlay=e,r.clearOverlays=n;var a=[],o=[]}function he(t){var e,n,r=this;r.build=function(){e=[],n=[],t(e,n)},r.cell=function(t,r){var a,o=e.length,i=n.length,s=-1,c=-1;for(a=0;o>a;a++)if(r>=e[a][0]&&e[a][1]>r){s=a;break}for(a=0;i>a;a++)if(t>=n[a][0]&&n[a][1]>t){c=a;break}return s>=0&&c>=0?{row:s,col:c}:null},r.rect=function(t,r,a,o,i){var s=i.offset();return{top:e[t][0]-s.top,left:n[r][0]-s.left,width:n[o][1]-n[r][0],height:e[a][1]-e[t][0]}}}function ge(e){function n(t){pe(t);var n=e.cell(t.pageX,t.pageY);(!n!=!i||n&&(n.row!=i.row||n.col!=i.col))&&(n?(o||(o=n),a(n,o,n.row-o.row,n.col-o.col)):a(n,o),i=n)}var r,a,o,i,s=this;s.start=function(s,c,l){a=s,o=i=null,e.build(),n(c),r=l||"mousemove",t(document).bind(r,n)},s.stop=function(){return t(document).unbind(r,n),i}}function pe(t){t.pageX===e&&(t.pageX=t.originalEvent.pageX,t.pageY=t.originalEvent.pageY)}function me(t){function n(e){return a[e]=a[e]||t(e)}var r=this,a={},o={},i={};r.left=function(t){return o[t]=o[t]===e?n(t).position().left:o[t]},r.right=function(t){return i[t]=i[t]===e?r.left(t)+n(t).width():i[t]},r.clear=function(){a={},o={},i={}}}var ye={defaultView:"month",aspectRatio:1.35,header:{left:"title",center:"",right:"today prev,next"},weekends:!0,weekNumbers:!1,weekNumberCalculation:"iso",weekNumberTitle:"W",allDayDefault:!0,ignoreTimezone:!0,lazyFetching:!0,startParam:"start",endParam:"end",titleFormat:{month:"MMMM yyyy",week:"MMM d[ yyyy]{ '—'[ MMM] d yyyy}",day:"dddd, MMM d, yyyy"},columnFormat:{month:"ddd",week:"ddd M/d",day:"dddd M/d"},timeFormat:{"":"h(:mm)t"},isRTL:!1,firstDay:0,monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],buttonText:{prev:"",next:"",prevYear:"«",nextYear:"»",today:"today",month:"month",week:"week",day:"day"},theme:!1,buttonIcons:{prev:"circle-triangle-w",next:"circle-triangle-e"},unselectAuto:!0,dropAccept:"*"},be={header:{left:"next,prev today",center:"",right:"title"},buttonText:{prev:"",next:"",prevYear:"»",nextYear:"«"},buttonIcons:{prev:"circle-triangle-e",next:"circle-triangle-w"}},we=t.fullCalendar={version:"1.6.1"},De=we.views={};t.fn.fullCalendar=function(n){if("string"==typeof n){var a,o=Array.prototype.slice.call(arguments,1);return this.each(function(){var r=t.data(this,"fullCalendar");if(r&&t.isFunction(r[n])){var i=r[n].apply(r,o);a===e&&(a=i),"destroy"==n&&t.removeData(this,"fullCalendar")}}),a!==e?a:this}var i=n.eventSources||[];return delete n.eventSources,n.events&&(i.push(n.events),delete n.events),n=t.extend(!0,{},ye,n.isRTL||n.isRTL===e&&ye.isRTL?be:{},n),this.each(function(e,a){var o=t(a),s=new r(o,n,i);o.data("fullCalendar",s),s.render()}),this},we.sourceNormalizers=[],we.sourceFetchers=[];var Me={dataType:"json",cache:!1},Ce=1;we.addDays=c,we.cloneDate=d,we.parseDate=m,we.parseISO8601=y,we.parseTime=b,we.formatDate=w,we.formatDates=D;var Se=["sun","mon","tue","wed","thu","fri","sat"],Ee=864e5,xe=36e5,Te=6e4,ke={s:function(t){return t.getSeconds()},ss:function(t){return P(t.getSeconds())},m:function(t){return t.getMinutes()},mm:function(t){return P(t.getMinutes())},h:function(t){return t.getHours()%12||12},hh:function(t){return P(t.getHours()%12||12)},H:function(t){return t.getHours()},HH:function(t){return P(t.getHours())},d:function(t){return t.getDate()},dd:function(t){return P(t.getDate())},ddd:function(t,e){return e.dayNamesShort[t.getDay()]},dddd:function(t,e){return e.dayNames[t.getDay()]},M:function(t){return t.getMonth()+1},MM:function(t){return P(t.getMonth()+1)},MMM:function(t,e){return e.monthNamesShort[t.getMonth()]},MMMM:function(t,e){return e.monthNames[t.getMonth()]},yy:function(t){return(t.getFullYear()+"").substring(2)},yyyy:function(t){return t.getFullYear()},t:function(t){return 12>t.getHours()?"a":"p"},tt:function(t){return 12>t.getHours()?"am":"pm"},T:function(t){return 12>t.getHours()?"A":"P"},TT:function(t){return 12>t.getHours()?"AM":"PM"},u:function(t){return w(t,"yyyy-MM-dd'T'HH:mm:ss'Z'")},S:function(t){var e=t.getDate();return e>10&&20>e?"th":["st","nd","rd"][e%10-1]||"th"},w:function(t,e){return e.weekNumberCalculation(t)},W:function(t){return M(t)}};we.dateFormatters=ke,we.applyAll=G,De.month=te,De.basicWeek=ee,De.basicDay=ne,n({weekMode:"fixed"}),De.agendaWeek=oe,De.agendaDay=ie,n({allDaySlot:!0,allDayText:"all-day",firstHour:6,slotMinutes:30,defaultEventMinutes:120,axisFormat:"h(:mm)tt",timeFormat:{agenda:"h:mm{ - h:mm}"},dragOpacity:{agenda:.5},minTime:0,maxTime:24})})(jQuery); \ No newline at end of file +FullCalendar Scheduler v5.8.0 +Docs & License: https://fullcalendar.io/scheduler +(c) 2021 Adam Shaw +*/ +var ie_args=navigator&&navigator.userAgent.match(/MSIE\s+(\d+)/),is_below_es6=!1,ie_ver,global,FullCalendar;ie_args&&(ie_ver=parseInt(ie_args[1]),(ie_ver<=10||!Object.__proto__)&&(Object.setPrototypeOf=function(n,t){n.prototype=Object.create(t.prototype);n.prototype.constructor=n;n.__proto__=t;var i=Object.getOwnPropertyNames(t);return i.forEach(function(i){try{if(i=="caller"||i=="length"||i=="arguments")return;n[i]=t[i]}catch(r){}}),n},global=(typeof globalThis).toLowerCase()=="undefined"?window:globalThis,(typeof DOMTokenList).toLowerCase()=="undefined"&&function(n,t){"use strict";var i="exports";typeof define=="function"&&define["amd"]?define(function(){return t(n)}):typeof module=="function"&&module[i]?module[i]=t(n):t(n)}(this,function(n){"use strict";function o(n){var t=this.prototype[n];this.prototype[n]=function(){for(var r,n=0,i=arguments.length;n-1;){if(this[t]===n)return t;t-=1}return-1}function h(){return e+=1}function u(){var n=this.classes,t=n.join(" ");this.isSVG?this.setAttribute("class",t):this.element.className=t;this.list.length=n.length}function c(n){return r.call(t[this.id].classes,n)!==-1}function l(){for(var n=0,f=t[this.id],e=f.classes,s=arguments.length,i,o=!1;n-1;)o=arguments[n],i=r.call(e,o),i!==-1&&(e.splice(i,1),s=!0),n-=1;s&&u.call(f)}function y(){var n=t[this.id];return u.call(n),n.element.className}function p(n,i){var f=r.call(t[this.id].classes,n)!==-1,u;return f?i!==!0&&(u="remove"):i!==!1&&(u="add"),u&&this[u](n),i===!0||i===!1?i:!f}function f(n){var r,i,u;if(i=n.domTokenListId,i&&i in t)return t[i].list;u=typeof n.className=="object";r=n.className;r=String(u?r.baseVal:r).replace(/^\s+|\s+$/,"");i=h();t[i]={classes:r.length!==0?r.split(/\s+/):[],element:n,list:this,isSVG:u};this.id=i;this.length=t[i].classes.length;n.domTokenListId=i}if(n.Element){var s=n.document,e=0,t={},i=s.createElement("_");"classList"in i?(i.classList.add("c1","c2"),i.classList.contains("c2")||(o.call(n.DOMTokenList,"add"),o.call(n.DOMTokenList,"remove")),i.classList.toggle("c3",!1),i.classList.contains("c3")&&(n.DOMTokenList.prototype.toggle=function(){var t=n.DOMTokenList.prototype.toggle;return function(n,i){var r=!i;return arguments.length>1&&!(this.contains(n)===r)?i:t.call(this,n)}}()),i=null):function(){function h(){var n=this.domTokenListId;return n&&n in t?t[n].list:new f(this)}for(var u=n.Element.prototype,o=[l,c,a,v,y,p],e=["add","contains","item","remove","toString","toggle"],r,s=f.prototype,i=e.length-1;i>-1;)s[e[i]]=o[i],i-=1;if(r={get:h,configurable:!0,enumerable:!0},Object.defineProperty)try{Object.defineProperty(u,"classList",r)}catch(w){w.number===-2146823252&&(r.enumerable=!1,Object.defineProperty(u,"classList",r))}else Object.prototype.__defineGetter__&&u.__defineGetter__("classList",r);n.DOMTokenList=f}()}}),is_below_es6=!0));FullCalendar=function(n){"use strict"; +/*! ***************************************************************************** + Copyright (c) Microsoft Corporation. + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted. + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + ***************************************************************************** */ +function u(n,t){function i(){this.constructor=n}if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");vh(n,t);n.__proto__=t;n.prototype=t===null?Object.create(t):(i.prototype=t.prototype,new i)}function l(n,t){for(var i=0,u=t.length,r=n.length;i3)for(i=[i],r=3;r0?re(c.type,c.props,c.key,null,c.__v):c)){if(c.__=i,c.__b=i.__b+1,null===(a=v[l])||a&&c.key==a.key&&c.type===a.type)v[l]=void 0;else for(p=0;p>>1,1);t.i.removeChild(n)}}),cu(si(cft,{context:t.context},n.__v),t.l)):t.l&&t.componentWillUnmount()}function aft(n,t){return si(lft,{__v:n,i:t})}function wft(){}function bft(){return this.cancelBubble}function kft(){return this.defaultPrevented}function dft(){function i(t){n.push(t)}var t=o.debounceRendering,n=[];for(o.debounceRendering=i,cu(si(ub,{}),document.createElement("div"));n.length;)n.shift()();o.debounceRendering=t}function gft(n){var t=oft(n),i=t.Provider;return t.Provider=function(){var t=this,r=!this.getChildContext,u=i.apply(this,arguments),n;return r&&(n=[],this.shouldComponentUpdate=function(i){t.props.value!==i.value&&n.forEach(function(n){n.context=i.value;n.forceUpdate()})},this.sub=function(t){n.push(t);var i=t.componentWillUnmount;t.componentWillUnmount=function(){n.splice(n.indexOf(t),1);i&&i.call(t)}}),u},t}function net(n){cu(null,n)}function vr(n){n.parentNode&&n.parentNode.removeChild(n)}function d(n,t){if(n.closest)return n.closest(t);if(!document.documentElement.contains(n))return null;do{if(he(n,t))return n;n=n.parentElement||n.parentNode}while(n!==null&&n.nodeType===1);return null}function he(n,t){var i=n.matches||n.matchesSelector||n.msMatchesSelector;return i.call(n,t)}function dt(n,t){for(var u,i,f=n instanceof HTMLElement?[n]:n,e=[],r=0;r=1)?Math.min(u,f):u}function wc(n,t,i,r){var u=et([t,0,1+cet(t,i,r)]),f=a(n),e=Math.round(ni(u,f));return Math.floor(e/7)+1}function cet(n,t,i){var r=7+t-i,u=(7+et([n,0,r]).getUTCDay()-t)%7;return-u+r-1}function db(n){return[n.getFullYear(),n.getMonth(),n.getDate(),n.getHours(),n.getMinutes(),n.getSeconds(),n.getMilliseconds(),]}function gb(n){return new Date(n[0],n[1]||0,n[2]==null?1:n[2],n[3]||0,n[4]||0,n[5]||0)}function ai(n){return[n.getUTCFullYear(),n.getUTCMonth(),n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds(),n.getUTCMilliseconds(),]}function et(n){return n.length===1&&(n=n.concat([0])),new Date(Date.UTC.apply(Date,n))}function le(n){return!isNaN(n.valueOf())}function vi(n){return n.getUTCHours()*36e5+n.getUTCMinutes()*6e4+n.getUTCSeconds()*1e3+n.getUTCMilliseconds()}function yu(n,t,i,r){return{instanceId:vt(),defId:n,range:t,forcedStartTzo:i==null?null:i,forcedEndTzo:r==null?null:r}}function bc(n,t){var u={},f,e,r,i,s,o;if(t)for(f in t){for(e=[],i=n.length-1;i>=0;i-=1)if(r=n[i][f],typeof r=="object"&&r)e.unshift(r);else if(r!==undefined){u[f]=r;break}e.length&&(u[f]=bc(e))}for(i=n.length-1;i>=0;i-=1){s=n[i];for(o in s)o in u||(u[o]=s[o])}return u}function pt(n,t){var r={};for(var i in n)t(n[i],i)&&(r[i]=n[i]);return r}function w(n,t){var r={};for(var i in n)r[i]=t(n[i],i);return r}function nk(n){for(var u,i={},t=0,r=n;t10&&(t==null?r=r.replace("Z",""):t!==0&&(r=r.replace("Z",rl(t,!0)))),r}function br(n){return n.toISOString().replace(/T.*$/,"")}function fk(n){return yt(n.getUTCHours(),2)+":"+yt(n.getUTCMinutes(),2)+":"+yt(n.getUTCSeconds(),2)}function rl(n,t){t===void 0&&(t=!1);var r=n<0?"-":"+",u=Math.abs(n),f=Math.floor(u/60),i=Math.round(u%60);return t?r+yt(f,2)+":"+yt(i,2):"GMT"+r+f+(i?":"+yt(i,2):"")}function ek(n,t){for(var r=0,i=0;i=tt(t)&&(i=p(i,1))),n.start&&(r=a(n.start),i&&i<=r&&(i=p(r,1))),{start:r,end:i}}function dk(n){var t=tf(n);return ni(t.start,t.end)>1}function tr(n,t,i,r){return r==="year"?s(i.diffWholeYears(n,t),"year"):r==="month"?s(i.diffWholeMonths(n,t),"month"):bb(n,t)}function got(n,t){var i=null,r=null;return(n.start&&(i=t.createMarker(n.start)),n.end&&(r=t.createMarker(n.end)),!i&&!r)?null:i&&r&&ri&&f.push({start:i,end:r.start}),r.end>i&&(i=r.end);return it.start)&&(n.start===null||t.end===null||n.start=n.start)&&(n.end===null||t.end!==null&&t.end<=n.end)}function wt(n,t){return(n.start===null||t>=n.start)&&(n.end===null||t=t.end?new Date(t.end.valueOf()-1):n}function ff(n,t,i,r){var h={},c={},k={},l=[],it=[],a=ro(n.defs,t),u,e,rt,d,w,g,f,y,p,b,tt,nt;for(f in n.defs)u=n.defs[f],e=a[u.defId],e.display==="inverse-background"&&(u.groupId?(h[u.groupId]=[],k[u.groupId]||(k[u.groupId]=u)):c[f]=[]);for(rt in n.instances){var v=n.instances[rt],u=n.defs[v.defId],e=a[u.defId],ut=v.range,s=!u.allDay&&r?tf(ut,r):ut,o=ui(s,i);o&&(e.display==="inverse-background"?u.groupId?h[u.groupId].push(o):c[v.defId].push(o):e.display!=="none"&&(e.display==="background"?l:it).push({def:u,ui:e,instance:v,range:o,isStart:s.start&&s.start.valueOf()===o.start.valueOf(),isEnd:s.end&&s.end.valueOf()===o.end.valueOf()}))}for(d in h)for(y=h[d],p=gk(y,i),w=0,g=p;w=(i||t.end),isToday:t&&wt(t,r.start)}}function ed(n){var t=["fc-event"];return n.isMirror&&t.push("fc-event-mirror"),n.isDraggable&&t.push("fc-event-draggable"),(n.isStartResizable||n.isEndResizable)&&t.push("fc-event-resizable"),n.isDragging&&t.push("fc-event-dragging"),n.isResizing&&t.push("fc-event-resizing"),n.isSelected&&t.push("fc-event-selected"),n.isStart&&t.push("fc-event-start"),n.isEnd&&t.push("fc-event-end"),n.isPast&&t.push("fc-event-past"),n.isToday&&t.push("fc-event-today"),n.isFuture&&t.push("fc-event-future"),t}function uo(n){return n.instance?n.instance.instanceId:n.def.defId+":"+n.range.start.toISOString()}function ist(n,t,i){var u=rst(n,t),r=u.range;if(!r.start)return null;if(!r.end){if(i==null)return null;r.end=t.add(r.start,i)}return u}function rst(n,t){var o=nr(n,od),r=o.refined,s=o.extra,u=r.start?t.createMarkerMeta(r.start):null,f=r.end?t.createMarkerMeta(r.end):null,e=r.allDay;return e==null&&(e=u&&u.isTimeUnspecified&&(!f||f.isTimeUnspecified)),i({range:{start:u?u.marker:null,end:f?f.marker:null},allDay:e},s)}function sd(n,t){return hl(n.range,t.range)&&n.allDay===t.allDay&&ust(n,t)}function ust(n,t){for(var i in t)if(i!=="range"&&i!=="allDay"&&n[i]!==t[i])return!1;for(i in n)if(!(i in t))return!1;return!0}function fst(n,t){return i(i({},cd(n.range,t,n.allDay)),{allDay:n.allDay})}function hd(n,t,r){return i(i({},cd(n,t,r)),{timeZone:t.timeZone})}function cd(n,t,i){return{start:t.toDate(n.start),end:t.toDate(n.end),startStr:t.formatIso(n.start,{omitTime:i}),endStr:t.formatIso(n.end,{omitTime:i})}}function est(n,t,i){var u=io({editable:!1},i),r=nf(u.refined,u.extra,"",n.allDay,!0,i);return{def:r,ui:td(r,t),instance:yu(r.defId,n.range),range:n.range,isStart:!0,isEnd:!0}}function ll(n,t,r){r.emitter.trigger("select",i(i({},al(n,r)),{jsEvent:t?t.origEvent:null,view:r.viewApi||r.calendarApi.view}))}function ost(n,t){t.emitter.trigger("unselect",{jsEvent:n?n.origEvent:null,view:t.viewApi||t.calendarApi.view})}function al(n,t){for(var e,r={},u=0,f=t.pluginHooks.dateSpanTransforms;u=0;i-=1)if(f=u[i],r=f.parseMeta(n),r)return{sourceDefId:i,meta:r};return null}function lst(n,t){switch(t.type){case"CHANGE_DATE":return t.dateMarker;default:return n}}function ast(n,t){var i=n.initialDate;return i!=null?t.createMarker(i):of(n.now,t)}function of(n,t){return(typeof n=="function"&&(n=n()),n==null)?t.createNowMarker():t.createMarker(n)}function yd(n){var t,i,u=n._def,r=n._instance;return{defs:(t={},t[u.defId]=u,t),instances:r?(i={},i[r.instanceId]=r,i):{}}}function wi(n,t,i){var s=n.defs,u=n.instances,f=[],h=i?i.instanceId:"",e,r,o;for(e in u)r=u[e],o=s[r.defId],r.instanceId!==h&&f.push(new v(t,o,r));return f}function vst(n,t){yl[n]=t}function yst(n){return new yl[n]}function bd(n){var t=wd.exec(n),i,r;return t&&(i=new Date(Date.UTC(Number(t[1]),t[3]?Number(t[3])-1:0,Number(t[5]||1),Number(t[7]||0),Number(t[8]||0),Number(t[10]||0),t[12]?Number("0."+t[12])*1e3:0)),le(i))?(r=null,t[13]&&(r=(t[15]==="-"?-1:1)*(Number(t[16]||0)*60+Number(t[18]||0))),{marker:i,isTimeUnspecified:!t[6],timeZoneOffset:r}):null}function dd(n){for(var i,f=n.length>0?n[0].code:"en",e=kd.concat(n),r={en:wl},t=0,u=e;t0;r-=1)if(f=u.slice(0,r).join("-"),t[f])return t[f];return null}function gd(n,t,i){var r=bc([wl,i],["buttonText"]),u;return delete r.code,u=r.week,delete r.week,{codeArg:n,codes:t,week:u,simpleNumberFormat:new Intl.NumberFormat(n),options:r}}function bst(n,t){t===void 0&&(t={});var r=ng(t),u=y(t),i=r.createMarkerMeta(n);return i?r.format(i.marker,u,{forcedTzo:i.forcedTzo}):""}function kst(n,t,i){var r=ng(typeof i=="object"&&i?i:{}),e=y(i),u=r.createMarkerMeta(n),f=r.createMarkerMeta(t);return!u||!f?"":r.formatRange(u.marker,f.marker,e,{forcedStartTzo:u.forcedTzo,forcedEndTzo:f.forcedTzo,isEndExclusive:i.isEndExclusive,defaultSeparator:ri.defaultRangeSeparator})}function ng(n){var t=bl(n.locale||"en",dd([]).map);return new pl(i(i({timeZone:ri.timeZone,calendarSystem:"gregory"},n),{locale:t}))}function kl(n,t){return de(dst(n),null,t)}function dst(n){var t;return t=n===!0?[{}]:Array.isArray(n)?n.filter(function(n){return n.daysOfWeek}):typeof n=="object"&&n?[n]:[],t.map(function(n){return i(i({},tg),n)})}function ig(n,t){return n.left>=t.left&&n.left=t.top&&n.top
<\/div><\/td><\/tr><\/table>",n.querySelector("table").style.height="100px",n.querySelector("div").style.height="100%",document.body.appendChild(n),t=n.querySelector("div"),i=t.offsetHeight>0,document.body.removeChild(n),i)}function nht(n,t,r){var u=[],f;return n&&u.push(n),t&&u.push(t),f={"":no(u)},r&&i(f,r),f}function nu(n,t,i,r){return{dow:n.getUTCDay(),isDisabled:Boolean(r&&!wt(r.activeRange,n)),isOther:Boolean(r&&!wt(r.currentRange,n)),isToday:Boolean(t&&wt(t,n)),isPast:Boolean(i?ni:t?n>=t.end:!1)}}function rr(n,t){var i=["fc-day","fc-day-"+yc[n.dow],];return n.isDisabled?i.push("fc-day-disabled"):(n.isToday&&(i.push("fc-day-today"),i.push(t.getClass("today"))),n.isPast&&i.push("fc-day-past"),n.isFuture&&i.push("fc-day-future"),n.isOther&&i.push("fc-day-other")),i}function ta(n,t){var i=["fc-slot","fc-slot-"+yc[n.dow],];return n.isDisabled?i.push("fc-slot-disabled"):(n.isToday&&(i.push("fc-slot-today"),i.push(t.getClass("today"))),n.isPast&&i.push("fc-slot-past"),n.isFuture&&i.push("fc-slot-future")),i}function ur(n,t){return t===void 0&&(t="day"),JSON.stringify({date:br(n),type:t})}function hf(){return ho===null&&(ho=tht()),ho}function tht(){var n=document.createElement("div"),t,i;return ci(n,{position:"absolute",top:-1e3,left:0,border:0,padding:0,overflow:"scroll",direction:"rtl"}),n.innerHTML="
<\/div>",document.body.appendChild(n),t=n.firstChild,i=t.getBoundingClientRect().left>n.getBoundingClientRect().left,vr(n),i}function ra(){return ia||(ia=iht()),ia}function iht(){var n=document.createElement("div"),t;return n.style.overflow="scroll",n.style.position="absolute",n.style.top="-9999px",n.style.left="-9999px",document.body.appendChild(n),t=eg(n),document.body.removeChild(n),t}function eg(n){return{x:n.offsetHeight-n.clientHeight,y:n.offsetWidth-n.clientWidth}}function ua(n,t){t===void 0&&(t=!1);var i=window.getComputedStyle(n),u=parseInt(i.borderLeftWidth,10)||0,f=parseInt(i.borderRightWidth,10)||0,e=parseInt(i.borderTopWidth,10)||0,o=parseInt(i.borderBottomWidth,10)||0,s=eg(n),h=s.y-u-f,c=s.x-e-o,r={borderLeft:u,borderRight:f,borderTop:e,borderBottom:o,scrollbarBottom:c,scrollbarLeft:0,scrollbarRight:0};return hf()&&i.direction==="rtl"?r.scrollbarLeft=h:r.scrollbarRight=h,t&&(r.paddingLeft=parseInt(i.paddingLeft,10)||0,r.paddingRight=parseInt(i.paddingRight,10)||0,r.paddingTop=parseInt(i.paddingTop,10)||0,r.paddingBottom=parseInt(i.paddingBottom,10)||0),r}function fa(n,t,i){t===void 0&&(t=!1);var f=i?n.getBoundingClientRect():co(n),r=ua(n,t),u={left:f.left+r.borderLeft+r.scrollbarLeft,right:f.right-r.borderRight-r.scrollbarRight,top:f.top+r.borderTop,bottom:f.bottom-r.borderBottom-r.scrollbarBottom};return t&&(u.left+=r.paddingLeft,u.right-=r.paddingRight,u.top+=r.paddingTop,u.bottom-=r.paddingBottom),u}function co(n){var t=n.getBoundingClientRect();return{left:t.left+window.pageXOffset,top:t.top+window.pageYOffset,right:t.right+window.pageXOffset,bottom:t.bottom+window.pageYOffset}}function rht(n){for(var f,r,e=ea(n),t=n.getBoundingClientRect(),i=0,u=e;in.fetchRange.end:!n.latestFetchId}function la(n,t,i,r,u){var o={},f,e;for(f in n)e=n[f],o[f]=t[f]?sct(e,i,r,u):e;return o}function sct(n,t,r,u){var f=u.options,e=u.calendarApi,s=u.pluginHooks.eventSourceDefs[n.sourceDefId],o=vt();return s.fetch({eventSource:n,range:t,isRefetch:r,context:u},function(i){var r=i.rawEvents;f.eventSourceSuccess&&(r=f.eventSourceSuccess.call(e,r,i.xhr)||r);n.success&&(r=n.success.call(e,r,i.xhr)||r);u.dispatch({type:"RECEIVE_EVENTS",sourceId:n.sourceId,fetchId:o,fetchRange:t,rawEvents:r})},function(i){console.warn(i.message,i);f.eventSourceFailure&&f.eventSourceFailure.call(e,i);n.failure&&n.failure(i);u.dispatch({type:"RECEIVE_EVENT_ERROR",sourceId:n.sourceId,fetchId:o,fetchRange:t,error:i})}),i(i({},n),{isFetching:!0,latestFetchId:o})}function hct(n,t,r,u){var f,e=n[t];return e&&r===e.latestFetchId?i(i({},n),(f={},f[t]=i(i({},e),{isFetching:!1,fetchRange:u}),f)):n}function gg(n,t){return pt(n,function(n){return nn(n,t)})}function cct(n,t){var s=vd(t),r=[].concat(n.eventSources||[]),e=[],i,u,o,f;for(n.initialEvents&&r.unshift(n.initialEvents),n.events&&r.unshift(n.events),i=0,u=r;i=200&&f.status<400){var n=!1,t=void 0;try{t=JSON.parse(f.responseText);n=!0}catch(i){}n?r(t,f):u("Failure parsing JSON",f)}else u("Request failed",f)};f.onerror=function(){u("Request failed",f)};f.send(e)}function elt(n,t){return n+(n.indexOf("?")===-1?"?":"&")+fn(t)}function fn(n){var t=[];for(var i in n)t.push(encodeURIComponent(i)+"="+encodeURIComponent(n[i]));return t.join("&")}function clt(n,t,r){var f=r.dateEnv,h=r.options,e,o,s,c,u={};return e=n.startParam,e==null&&(e=h.startParam),o=n.endParam,o==null&&(o=h.endParam),s=n.timeZoneParam,s==null&&(s=h.timeZoneParam),c=typeof n.extraParams=="function"?n.extraParams():n.extraParams||{},i(u,c),u[e]=f.formatIso(t.start),u[o]=f.formatIso(t.end),f.timeZone!=="local"&&(u[s]=f.timeZone),u}function ylt(n,t,i,r){for(var e=n?nk(n):null,u=a(i.start),s=i.end,o=[],f;u1)?{year:"numeric",month:"short",day:"numeric"}:{year:"numeric",month:"long",day:"numeric"}}function nat(n,t,i,r,u,f,e,o){var s=bl(t||e.defaultCode,e.map);return new pl({calendarSystem:"gregory",timeZone:n,namedTimeZoneImpl:f.namedTimeZonedImpl,locale:s,weekNumberCalculation:i,firstDay:r,weekText:u,cmdFormatter:f.cmdFormatter,defaultSeparator:o})}function tat(n,t){var i=t.themeClasses[n.themeSystem]||ei;return new i(n)}function iat(n){var t=n.dateProfileGeneratorClass||yo;return new t(n)}function rat(n,t,i){return new vl(n,t,i)}function uat(n){return w(n,function(n){return n.ui})}function fat(n,t,i){var f={"":t},u,r;for(u in n)r=n[u],r.sourceId&&i[r.sourceId]&&(f[u]=i[r.sourceId]);return f}function eat(n){var t=n.options;return{eventUiSingleBase:dr({display:t.eventDisplay,editable:t.editable,startEditable:t.eventStartEditable,durationEditable:t.eventDurationEditable,constraint:t.eventConstraint,overlap:typeof t.eventOverlap=="boolean"?t.eventOverlap:undefined,allow:t.eventAllow,backgroundColor:t.eventBackgroundColor,borderColor:t.eventBorderColor,textColor:t.eventTextColor,color:t.eventColor},n),selectionConfig:dr({constraint:t.selectConstraint,overlap:typeof t.selectOverlap=="boolean"?t.selectOverlap:undefined,allow:t.selectAllow},n)}}function aa(n,t){for(var u,i=0,r=t.pluginHooks.isLoadingFuncs;ii(n[u-1]))return[u,0];while(re)r=f+1;else return[f,1];return[r,0]}function hat(n,t){return{component:n,el:t.el,useEventCenter:t.useEventCenter!=null?t.useEventCenter:!0,isHitComboAllowed:t.isHitComboAllowed||null}}function go(n){var t;return t={},t[n.component.uid]=n,t}function ns(n){var i=nr(n,cat),t=i.refined,r=i.extra;return{startTime:t.startTime||null,duration:t.duration||null,create:t.create!=null?t.create:!0,sourceId:t.sourceId,leftoverProps:r}}function pat(n,t,i,r,u,f){var e=i.build(u,undefined,!1),o=i.buildPrev(t,r,!1),s=i.buildNext(t,r,!1);return{title:f,activeButton:n.type,isTodayEnabled:e.isValid&&!wt(t.currentRange,u),isPrevEnabled:o.isValid,isNextEnabled:s.isValid}}function wat(n){return n.map(function(n){return new n})}function da(n,t){return!n||t>10?y({weekday:"short"}):t>1?y({weekday:"short",month:"numeric",day:"numeric",omitCommas:!0}):y({weekday:"long"})}function pn(n){return n.text}function wn(n){var t=a(n),i=p(t,1);return{start:t,end:i}}function bat(n,t,i){return n||da(t,i)}function uv(n,t){var i=n.activeRange;return t?i:{start:gt(i.start,n.slotMinTime.milliseconds),end:gt(i.end,n.slotMaxTime.milliseconds-864e5)}}function rs(n,t,i){var r=n.mutatedEvents.instances;for(var u in r)if(!uf(t.validRange,r[u].range))return!1;return kn({eventDrag:n},i)}function bn(n,t,i){return uf(t.validRange,n.range)?kn({dateSelection:n},i):!1}function kn(n,t){var r=t.getCurrentData(),u=i({businessHours:r.businessHours,dateSelection:"",eventStore:r.eventStore,eventUiBases:r.eventUiBases,eventSelection:"",eventDrag:null,eventResize:null},n);return(t.pluginHooks.isPropsValid||fv)(u,t)}function fv(n,t,i,r){return(i===void 0&&(i={}),n.eventDrag&&!kat(n,t,i,r))?!1:n.dateSelection&&!dat(n,t,i,r)?!1:!0}function kat(n,t,r,u){var g=t.getCurrentData(),o=n.eventDrag,nt=o.mutatedEvents,tt=nt.defs,it=nt.instances,c=ro(tt,o.isEvent?n.eventUiBases:{"":g.selectionConfig}),a,p,b,et,e,ot,k,h,d;u&&(c=w(c,u));var l=wct(n.eventStore,o.affectedEvents.instances),rt=l.defs,ut=l.instances,ct=ro(rt,n.eventUiBases);for(a in it){var f=it[a],ft=f.range,y=c[f.defId],s=tt[f.defId];if(!dn(y.constraints,ft,l,n.businessHours,t))return!1;p=t.options.eventOverlap;b=typeof p=="function"?p:null;for(et in ut)if(e=ut[et],rf(ft,e.range)&&((ot=ct[e.defId].overlap,ot===!1&&o.isEvent)||y.overlap===!1||b&&!b(new v(t,rt[e.defId],e),new v(t,s,f))))return!1;for(k=g.eventStore,h=0,d=y.allows;ht.eventRange.range.end?n:t}function vvt(n){return n.button===0&&!n.ctrlKey}function yvt(){bv+=1;setTimeout(function(){bv-=1},ot.touchMouseIgnoreWait)}function pvt(){ls+=1;ls===1&&window.addEventListener("touchmove",rtt,{passive:!1})}function wvt(){ls-=1;ls||window.removeEventListener("touchmove",rtt,{passive:!1})}function rtt(n){kv&&n.preventDefault()}function nyt(n){var t=n.tagName;return t==="HTML"||t==="BODY"}function vs(n,t){return!n&&!t?!0:Boolean(n)!==Boolean(t)?!1:sd(n.dateSpan,t.dateSpan)}function dv(n,t){for(var e,r={},u=0,f=t.pluginHooks.datePointTransforms;ur.start)return{endDelta:u};return null}function cyt(n,t,r){for(var s,l,a,e=i({},t.leftoverProps),f=0,o=r.pluginHooks.externalDefTransforms;f1,k=r.span.start===u;f+=r.levelCoord-e;e=r.levelCoord+r.thickness;g?(f+=r.thickness,k&&h.push({seg:fu(s,r.span.start,r.span.end,i),isVisible:!0,isAbsolute:!0,absoluteTop:r.levelCoord,marginTop:0})):k&&(h.push({seg:fu(s,r.span.start,r.span.end,i),isVisible:!0,isAbsolute:!1,absoluteTop:0,marginTop:f}),f=0)}v.push(b);y.push(h);p.push(f)}return{singleColPlacements:v,multiColPlacements:y,leftoverMargins:p}}function ipt(n,t){for(var r,e,u,f=[],i=0;i=0;t-=1)if(i=s(vy[t]),r=ti(i,n),r!==null&&r>1)return i;return n}function wy(n,t){var i=new iv(n.renderRange,t);return new rv(i,!1)}function ywt(n){var r=n.navLinkData?{"data-navlink":n.navLinkData,tabIndex:0}:{};return t(c,null,n.text&&t("a",i({className:"fc-list-day-text"},r),n.text),n.sideText&&t("a",i({className:"fc-list-day-side-text"},r),n.sideText))}function pwt(n){var r=n.event,u=r.url,f=u?{href:u}:{};return t("a",i({},f),r.title)}function wwt(n,i,r){var u=r.options,s;if(u.displayEventTime!==!1){var h=n.eventRange.def,o=n.eventRange.instance,e=!1,f=void 0;return(h.allDay?e=!0:dk(n.eventRange.range)?n.isStart?f=gr(n,i,r,null,null,o.range.start,n.end):n.isEnd?f=gr(n,i,r,null,null,n.start,o.range.end):e=!0:f=gr(n,i,r),e)?(s={text:r.options.allDayText,view:r.viewApi},t(b,{hookProps:s,classNames:u.allDayClassNames,content:u.allDayContent,defaultContent:bwt,didMount:u.allDayDidMount,willUnmount:u.allDayWillUnmount},function(n,i,r,u){return t("td",{className:["fc-list-event-time"].concat(i).join(" "),ref:n},u)})):t("td",{className:"fc-list-event-time"},f)}return null}function bwt(n){return n.text}function kwt(n){return n.text}function dwt(n){for(var t=a(n.renderRange.start),u=n.renderRange.end,i=[],r=[];t0?t="positive":(n.scrollLeft=1,t=n.scrollLeft>0?"reverse":"negative"),vr(n),t}function nkt(n,t,i,r,u){n.forEach(function(n,f){var h=t[f],c=h.naturalBound,e=h.parentBound,l=e.right-e.left,a=e.bottom-e.bottom,o,s;l>r||a>u?(o=i[f].left-c.left,s=i[f].top-c.top):(o="",s="");ci(n,{position:"relative",left:o,right:-o,top:s})})}function tkt(n,t,i){n.forEach(function(n,r){var u=t[r],o=u.textAlign,s=u.elWidth,e=u.parentBound,h=e.right-e.left,f;f=o==="center"&&h>i?(i-s)/2:"";ci(n,{left:f,right:f,top:0})})}function ikt(){var n=document.createElement("div"),t;return(n.className="fc-sticky",document.body.appendChild(n),t=window.getComputedStyle(n).position,vr(n),t.indexOf("sticky")!==-1)?t:null}function fkt(n){for(var u,i=0,t=0,r=n;t .fc-scroller")}function kkt(n){return n.map(function(n){var t=window.getComputedStyle(n);return{scrollLeft:n.scrollLeft,scrollTop:n.scrollTop,overflowX:t.overflowX,overflowY:t.overflowY,marginBottom:t.marginBottom}})}function dkt(n,t){n.forEach(function(n,i){n.style.overflowX="visible";n.style.overflowY="visible";n.style.marginBottom="";n.style.left=-t[i].scrollLeft+"px"})}function gkt(n,t){n.forEach(function(n,i){var r=t[i];n.style.overflowX=r.overflowX;n.style.overflowY=r.overflowY;n.style.marginBottom=r.marginBottom;n.style.left="";n.scrollLeft=r.scrollLeft;n.scrollTop=r.scrollTop})}function ky(n,t,i,r){var u={labelInterval:i.slotLabelInterval,slotDuration:i.slotDuration},e,g,v,w,b,c,l,k,f;rdt(u,n,t);srt(u,n,t);udt(u,n,t);e=i.slotLabelFormat;g=Array.isArray(e)?e:e!=null?[e]:fdt(u,n,t,i);u.headerFormats=g.map(function(n){return y(n)});u.isTimeScale=Boolean(u.slotDuration.milliseconds);v=null;u.isTimeScale||(w=ii(u.slotDuration).unit,/year|month|week/.test(w)&&(v=w));u.largeUnit=v;u.emphasizeWeeks=tl(u.slotDuration)===1&&ou("weeks",n,t)>=2&&!i.businessHours;b=i.snapDuration;b&&(c=s(b),l=ti(u.slotDuration,c));l==null&&(c=u.slotDuration,l=1);u.snapDuration=c;u.snapsPerSlot=l;var rt=tt(n.slotMaxTime)-tt(n.slotMinTime),o=ort(n.renderRange.start,u,t),h=ort(n.renderRange.end,u,t);for(u.isTimeScale&&(o=t.add(o,n.slotMinTime),h=t.add(p(h,-1),n.slotMaxTime)),u.timeWindowMs=rt,u.normalizedRange={start:o,end:h},k=[],f=o;fot.MAX_TIMELINE_SLOTS&&(console.warn("slotLabelInterval results in too many cells"),n.labelInterval=null));n.slotDuration&&(e=i.countDurationsBetween(r.start,r.end,n.slotDuration),e>ot.MAX_TIMELINE_SLOTS&&(console.warn("slotDuration results in too many cells"),n.slotDuration=null));n.labelInterval&&n.slotDuration&&(u=ti(n.labelInterval,n.slotDuration),(u===null||u<1)&&(console.warn("slotLabelInterval must be a multiple of slotDuration"),n.slotDuration=null))}function srt(n,t,i){var a=t.currentRange,r=n.labelInterval,u,f,o,h,c,e,l,v;if(!r){if(u=void 0,n.slotDuration){for(f=0,o=th;f=ndt)break;n.labelInterval=r}return r}function udt(n,t,i){var h=t.currentRange,r=n.slotDuration,f,u,e,l;if(!r){for(f=srt(n,t,i),u=0,e=th;u1&&o<=nh){r=c;break}}r&&(l=i.countDurationsBetween(h.start,h.end,r),l>tdt&&(r=null));r||(r=f);n.slotDuration=r}return r}function fdt(n,t,i,r){var f,e,o=n.labelInterval,s=ii(o).unit,h=r.weekNumbers,u=f=e=null;s!=="week"||h||(s="day");switch(s){case"year":u={year:"numeric"};break;case"month":ou("years",t,i)>1&&(u={year:"numeric"});f={month:"short"};break;case"week":ou("years",t,i)>1&&(u={year:"numeric"});f={week:"narrow"};break;case"day":ou("years",t,i)>1?u={year:"numeric",month:"long"}:ou("months",t,i)>1&&(u={month:"long"});h&&(f={week:"short"});e={weekday:"narrow",day:"numeric"};break;case"hour":h&&(u={week:"short"});ou("days",t,i)>1&&(f={weekday:"short",day:"numeric",month:"numeric",omitCommas:!0});e={hour:"numeric",minute:"2-digit",omitZeroMinute:!0,meridiem:"short"};break;case"minute":rk(o)/60>=nh?(u={hour:"numeric",meridiem:"short"},f=function(n){return":"+yt(n.date.minute,2)}):u={hour:"numeric",minute:"numeric",meridiem:"short"};break;case"second":uk(o)/60>=nh?(u={hour:"numeric",minute:"2-digit",meridiem:"lowercase"},f=function(n){return":"+yt(n.date.second,2)}):u={hour:"numeric",minute:"2-digit",second:"2-digit",meridiem:"lowercase"};break;case"millisecond":u={hour:"numeric",minute:"2-digit",second:"2-digit",meridiem:"lowercase"};f=function(n){return"."+yt(n.millisecond,3)}}return[].concat(u||[],f||[],e||[])}function ou(n,t,i){var r=t.currentRange,u=null;return n==="years"?u=i.diffWholeYears(r.start,r.end):n==="months"?u=i.diffWholeMonths(r.start,r.end):n==="weeks"?u=i.diffWholeMonths(r.start,r.end):n==="days"&&(u=yr(r.start,r.end)),u||0}function edt(n,t){for(var o=n.slotDates,s=n.emphasizeWeeks,i=null,u=[],r=0,f=o;r1&&!p,e=null,w=k[i]||(p?b:null);d?(o=t.format(u,y),f&&f.text===o?f.colspan+=1:e=hrt(u,o,w)):!f||li(t.countDurationsBetween(n.normalizedRange.start,u,n.labelInterval))?(o=t.format(u,y),e=hrt(u,o,w)):f.colspan+=1;e&&(e.weekStart=v,h.push(e))}return l}function hrt(n,t,i){return{date:n,text:t,rowUnit:i,colspan:1,isWeekStart:!1}}function sdt(n){return n.text}function hdt(n){return{level:n.level,date:n.dateEnv.toDate(n.dateMarker),view:n.viewApi,text:n.text}}function dy(n,t,i){var u=i.countDurationsBetween(t.normalizedRange.start,n,t.snapDuration),f,r;return u<0?0:u>=t.snapDiffToIndex.length?t.snapCnt:(f=Math.floor(u),r=t.snapDiffToIndex[f],li(r)?r+=u-f:r=Math.ceil(r),r)}function rh(n,t){return n===null?{left:"",right:""}:t?{right:n,left:""}:{left:n,right:""}}function uh(n,t){return n?t?{right:n.start,left:-n.end}:{left:n.start,right:-n.end}:{left:"",right:""}}function vdt(n,t){return t.map(function(t){var i=t.toISOString();return n[i]})}function vrt(n,t,i){var o=[],r,u;if(i)for(r=0,u=n;r=0;t-=1)if(u=r[t],i=u.parseMeta(n),i)return{meta:i,sourceDefId:t};return null}function agt(n){for(var t in n)console.warn("Unknown resource prop '"+t+"'")}function vgt(n,t,i){var r=i.options,u=i.dateProfile;if(!n||!t)return nut(r.initialResources||r.resources,u.activeRange,r.refetchResourcesOnNavigate,i);switch(t.type){case"RESET_RESOURCE_SOURCE":return nut(t.resourceSourceInput,u.activeRange,r.refetchResourcesOnNavigate,i);case"PREV":case"NEXT":case"CHANGE_DATE":case"CHANGE_VIEW_TYPE":return ygt(n,u.activeRange,r.refetchResourcesOnNavigate,i);case"RECEIVE_RESOURCES":case"RECEIVE_RESOURCE_ERROR":return wgt(n,t.fetchId,t.fetchRange);case"REFETCH_RESOURCES":return op(n,u.activeRange,i);default:return n}}function nut(n,t,i,r){if(n){var u=cgt(n);return op(u,i?t:null,r)}return null}function ygt(n,t,i,r){return i&&!pgt(n)&&(!n.fetchRange||!hl(n.fetchRange,t))?op(n,t,r):n}function pgt(n){return Boolean(drt(n.sourceDefId).ignoreRange)}function op(n,t,r){var f=drt(n.sourceDefId),u=vt();return f.fetch({resourceSource:n,range:t,context:r},function(n){r.dispatch({type:"RECEIVE_RESOURCES",fetchId:u,fetchRange:t,rawResources:n.rawResources})},function(n){r.dispatch({type:"RECEIVE_RESOURCE_ERROR",fetchId:u,fetchRange:t,error:n})}),i(i({},n),{isFetching:!0,latestFetchId:u})}function wgt(n,t,r){return t===n.latestFetchId?i(i({},n),{isFetching:!1,fetchRange:r}):n}function hp(n,t,r,u){var o,s,c;t===void 0&&(t="");var h=nr(n,tut),f=h.refined,l=h.extra,e={id:f.id||sp+vt(),parentId:f.parentId||t,title:f.title||"",businessHours:f.businessHours?kl(f.businessHours,u):null,ui:dr({editable:f.eventEditable,startEditable:f.eventStartEditable,durationEditable:f.eventDurationEditable,constraint:f.eventConstraint,overlap:f.eventOverlap,allow:f.eventAllow,classNames:f.eventClassNames,backgroundColor:f.eventBackgroundColor,borderColor:f.eventBorderColor,textColor:f.eventTextColor,color:f.eventColor},u),extendedProps:i(i({},l),f.extendedProps)};if(Object.freeze(e.ui.classNames),Object.freeze(e.extendedProps),!r[e.id]&&(r[e.id]=e,f.children))for(o=0,s=f.children;o0)break;t.splice(r,0,n)}function kp(n){var t=i(i(i({},n.extendedProps),n.ui),n);return delete t.ui,delete t.extendedProps,t}function cut(n,t){return n.spec===t.spec&&n.value===t.value}function rti(n,t,i,r,u){var f=oy(n,t);return r?new vp(f,i,u):new ap(f,i,u)}function eti(n,t,i,r,u){var f=wy(n,t);return r?new vp(f,i,u):new ap(f,i,u)}function put(n){for(var i,e=n.depth,u=n.hasChildren,o=n.isExpanded,s=n.onExpanderClick,r=[],f=0;f3;)i.pop()();if(i[1]1&&(u.year==="numeric"||u.year==="2-digit")&&(u.month==="numeric"||u.month==="2-digit")&&(u.day==="numeric"||u.day==="2-digit")&&(e=1),f=this.format(n,i),o=this.format(t,i),f===o)return f;var w=lot(u,e),a=sk(w,c,i),v=a(n),y=a(t),s=aot(f,v,o,y),p=c.separator||r||i.defaultSeparator||"";return s?s.before+v+p+y+s.after:f+p+o},n.prototype.getLargestUnit=function(){switch(this.severity){case 7:case 6:case 5:return"year";case 4:return"month";case 3:return"week";case 2:return"day";default:return"time"}},n}();ck=function(){function n(n){this.cmdStr=n}return n.prototype.format=function(n,t,i){return t.cmdFormatter(this.cmdStr,be(n,null,t,i))},n.prototype.formatRange=function(n,t,i,r){return i.cmdFormatter(this.cmdStr,be(n,t,i,r))},n}();lk=function(){function n(n){this.func=n}return n.prototype.format=function(n,t,i){return this.func(be(n,null,t,i))},n.prototype.formatRange=function(n,t,i,r){return this.func(be(n,t,i,r))},n}();var fl={navLinkDayClick:r,navLinkWeekClick:r,duration:s,bootstrapFontAwesome:r,buttonIcons:r,customButtons:r,defaultAllDayEventDuration:s,defaultTimedEventDuration:s,nextDayThreshold:s,scrollTime:s,scrollTimeReset:Boolean,slotMinTime:s,slotMaxTime:s,dayPopoverFormat:y,slotDuration:s,snapDuration:s,headerToolbar:r,footerToolbar:r,defaultRangeSeparator:String,titleRangeSeparator:String,forceEventDuration:Boolean,dayHeaders:Boolean,dayHeaderFormat:y,dayHeaderClassNames:r,dayHeaderContent:r,dayHeaderDidMount:r,dayHeaderWillUnmount:r,dayCellClassNames:r,dayCellContent:r,dayCellDidMount:r,dayCellWillUnmount:r,initialView:String,aspectRatio:Number,weekends:Boolean,weekNumberCalculation:r,weekNumbers:Boolean,weekNumberClassNames:r,weekNumberContent:r,weekNumberDidMount:r,weekNumberWillUnmount:r,editable:Boolean,viewClassNames:r,viewDidMount:r,viewWillUnmount:r,nowIndicator:Boolean,nowIndicatorClassNames:r,nowIndicatorContent:r,nowIndicatorDidMount:r,nowIndicatorWillUnmount:r,showNonCurrentDates:Boolean,lazyFetching:Boolean,startParam:String,endParam:String,timeZoneParam:String,timeZone:String,locales:r,locale:r,themeSystem:String,dragRevertDuration:Number,dragScroll:Boolean,allDayMaintainDuration:Boolean,unselectAuto:Boolean,dropAccept:r,eventOrder:ce,eventOrderStrict:Boolean,handleWindowResize:Boolean,windowResizeDelay:Number,longPressDelay:Number,eventDragMinDistance:Number,expandRows:Boolean,height:r,contentHeight:r,direction:String,weekNumberFormat:y,eventResizableFromStart:Boolean,displayEventTime:Boolean,displayEventEnd:Boolean,weekText:String,progressiveEventRendering:Boolean,businessHours:r,initialDate:r,now:r,eventDataTransform:r,stickyHeaderDates:r,stickyFooterScrollbar:r,viewHeight:r,defaultAllDay:Boolean,eventSourceFailure:r,eventSourceSuccess:r,eventDisplay:String,eventStartEditable:Boolean,eventDurationEditable:Boolean,eventOverlap:r,eventConstraint:r,eventAllow:r,eventBackgroundColor:String,eventBorderColor:String,eventTextColor:String,eventColor:String,eventClassNames:r,eventContent:r,eventDidMount:r,eventWillUnmount:r,selectConstraint:r,selectOverlap:r,selectAllow:r,droppable:Boolean,unselectCancel:String,slotLabelFormat:r,slotLaneClassNames:r,slotLaneContent:r,slotLaneDidMount:r,slotLaneWillUnmount:r,slotLabelClassNames:r,slotLabelContent:r,slotLabelDidMount:r,slotLabelWillUnmount:r,dayMaxEvents:r,dayMaxEventRows:r,dayMinWidth:Number,slotLabelInterval:s,allDayText:String,allDayClassNames:r,allDayContent:r,allDayDidMount:r,allDayWillUnmount:r,slotMinWidth:Number,navLinks:Boolean,eventTimeFormat:y,rerenderDelay:Number,moreLinkText:r,selectMinDistance:Number,selectable:Boolean,selectLongPressDelay:Number,eventLongPressDelay:Number,selectMirror:Boolean,eventMaxStack:Number,eventMinHeight:Number,eventMinWidth:Number,eventShortHeight:Number,slotEventOverlap:Boolean,plugins:r,firstDay:Number,dayCount:Number,dateAlignment:String,dateIncrement:s,hiddenDays:r,monthMode:Boolean,fixedWeekCount:Boolean,validRange:r,visibleRange:r,titleFormat:r,noEventsText:String,moreLinkClick:r,moreLinkClassNames:r,moreLinkContent:r,moreLinkDidMount:r,moreLinkWillUnmount:r},ri={eventDisplay:"auto",defaultRangeSeparator:" - ",titleRangeSeparator:" – ",defaultTimedEventDuration:"01:00:00",defaultAllDayEventDuration:{day:1},forceEventDuration:!1,nextDayThreshold:"00:00:00",dayHeaders:!0,initialView:"",aspectRatio:1.35,headerToolbar:{start:"title",center:"",end:"today prev,next"},weekends:!0,weekNumbers:!1,weekNumberCalculation:"local",editable:!1,nowIndicator:!1,scrollTime:"06:00:00",scrollTimeReset:!0,slotMinTime:"00:00:00",slotMaxTime:"24:00:00",showNonCurrentDates:!0,lazyFetching:!0,startParam:"start",endParam:"end",timeZoneParam:"timeZone",timeZone:"local",locales:[],locale:"",themeSystem:"standard",dragRevertDuration:500,dragScroll:!0,allDayMaintainDuration:!1,unselectAuto:!0,dropAccept:"*",eventOrder:"start,-duration,allDay,title",dayPopoverFormat:{month:"long",day:"numeric",year:"numeric"},handleWindowResize:!0,windowResizeDelay:100,longPressDelay:1e3,eventDragMinDistance:5,expandRows:!1,navLinks:!1,selectable:!1,eventMinHeight:15,eventMinWidth:30,eventShortHeight:30},ak={datesSet:r,eventsSet:r,eventAdd:r,eventChange:r,eventRemove:r,windowResize:r,eventClick:r,eventMouseEnter:r,eventMouseLeave:r,select:r,unselect:r,loading:r,_unmount:r,_beforeprint:r,_afterprint:r,_noEventDrop:r,_noEventResize:r,_resize:r,_scrollRequest:r},vk={buttonText:r,views:r,plugins:r,initialEvents:r,events:r,eventSources:r},el={headerToolbar:ke,footerToolbar:ke,buttonText:ke,buttonIcons:ke};yk={type:String,component:r,buttonText:String,buttonTextKey:String,dateProfileGeneratorClass:r,usesMinMaxTime:Boolean,classNames:r,content:r,didMount:r,willUnmount:r};gu={display:String,editable:Boolean,startEditable:Boolean,durationEditable:Boolean,constraint:r,overlap:r,allow:r,className:du,classNames:du,color:String,backgroundColor:String,borderColor:String,textColor:String};pk={display:null,startEditable:null,durationEditable:null,constraints:[],overlap:null,allows:[],backgroundColor:"",borderColor:"",textColor:"",classNames:[]};var to={id:String,groupId:String,title:String,url:String},wk={start:r,end:r,date:r,allDay:Boolean},bot=i(i(i({},to),wk),{extendedProps:r});od={start:r,end:r,allDay:Boolean};vl=function(){function n(n,t,i){this.type=n;this.getCurrentData=t;this.dateEnv=i}return Object.defineProperty(n.prototype,"calendar",{get:function(){return this.getCurrentData().calendarApi},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"title",{get:function(){return this.getCurrentData().viewTitle},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"activeStart",{get:function(){return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.start)},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"activeEnd",{get:function(){return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.end)},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"currentStart",{get:function(){return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.start)},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"currentEnd",{get:function(){return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.end)},enumerable:!1,configurable:!0}),n.prototype.getOption=function(n){return this.getCurrentData().options[n]},n}();ld={id:String,defaultAllDay:Boolean,url:String,format:String,events:r,eventDataTransform:r,success:r,failure:r};pi=function(){function n(){}return n.prototype.getCurrentData=function(){return this.currentDataManager.getCurrentData()},n.prototype.dispatch=function(n){return this.currentDataManager.dispatch(n)},Object.defineProperty(n.prototype,"view",{get:function(){return this.getCurrentData().viewApi},enumerable:!1,configurable:!0}),n.prototype.batchRendering=function(n){n()},n.prototype.updateSize=function(){this.trigger("_resize",!0)},n.prototype.setOption=function(n,t){this.dispatch({type:"SET_OPTION",optionName:n,rawOptionValue:t})},n.prototype.getOption=function(n){return this.currentDataManager.currentCalendarOptionsInput[n]},n.prototype.getAvailableLocaleCodes=function(){return Object.keys(this.getCurrentData().availableRawLocales)},n.prototype.on=function(n,t){var i=this.currentDataManager;if(i.currentCalendarOptionsRefiners[n])i.emitter.on(n,t);else console.warn("Unknown listener name '"+n+"'")},n.prototype.off=function(n,t){this.currentDataManager.emitter.off(n,t)},n.prototype.trigger=function(n){for(var i,r=[],t=1;t=r[t]&&n=r[t]&&n0},n.prototype.canScrollHorizontally=function(){return this.getMaxScrollLeft()>0},n.prototype.canScrollUp=function(){return this.getScrollTop()>0},n.prototype.canScrollDown=function(){return this.getScrollTop()0},n.prototype.canScrollRight=function(){return this.getScrollLeft()1&&(t=a(t),t=p(t,-1),t=u.add(t,e))),{start:i,end:t}},n.prototype.buildRangeFromDuration=function(n,t,i,r){function l(){u=h.startOf(n,e);c=h.add(u,i);o={start:u,end:c}}var s=this.props,h=s.dateEnv,e=s.dateAlignment,u,c,o,f;return e||(f=this.props.dateIncrement,e=f?tt(f)u.end&&(f+=this.insertEntry({index:n.index,thickness:n.thickness,span:{start:u.end,end:r.end}},e)),f)?(i.push.apply(i,l([{index:n.index,thickness:n.thickness,span:ko(u,r)}],e)),f):(i.push(n),0)},n.prototype.insertEntryAt=function(n,t){var u=this,f=u.entriesByLevel,r=u.levelCoords,i=t.level;i>=r.length||r[i]>t.levelCoord?(pa(r,i,t.levelCoord),pa(f,i,[n])):pa(f[i],t.lateralEnd,n);this.stackCnts[ki(n)]=t.stackCnt},n.prototype.findInsertion=function(n){for(var r,f=this,h=f.levelCoords,p=f.entriesByLevel,w=f.stackCnts,c=f.strictOrder,b=h.length,t=0,l=0,s=0,e=0,a=-1,o=null,i=0;i=t+n.thickness)break;var v=p[i],u=void 0,y=wa(v,n.span.start,va);for(s=y[0]+y[1],e=s;(u=v[e])&&u.span.startr)&&(t=r+u.thickness,a=i,o=u),e+=1;r1?(w=a&&o.getClass("buttonGroup")||"",t.apply(void 0,l(["div",{className:w}],f))):f[0]},r}(e),vn=function(n){function i(){return n!==null&&n.apply(this,arguments)||this}return u(i,n),i.prototype.render=function(){var f=this.props,n=f.model,o=f.extraClassName,i=!1,r,u,s=n.center,e;return n.left?(i=!0,r=n.left):r=n.start,n.right?(i=!0,u=n.right):u=n.end,e=[o||"","fc-toolbar",i?"fc-toolbar-ltr":"",],t("div",{className:e.join(" ")},this.renderSection("start",r||[]),this.renderSection("center",s||[]),this.renderSection("end",u||[]))},i.prototype.renderSection=function(n,i){var r=this.props;return t(lat,{key:n,widgetGroups:i,title:r.title,activeButton:r.activeButton,isTodayEnabled:r.isTodayEnabled,isPrevEnabled:r.isPrevEnabled,isNextEnabled:r.isNextEnabled})},i}(e),aat=function(n){function i(){var t=n!==null&&n.apply(this,arguments)||this;return t.state={availableWidth:null},t.handleEl=function(n){t.el=n;g(t.props.elRef,n);t.updateAvailableWidth()},t.handleResize=function(){t.updateAvailableWidth()},t}return u(i,n),i.prototype.render=function(){var u=this,n=u.props,f=u.state,i=n.aspectRatio,o=["fc-view-harness",i||n.liquid||n.height?"fc-view-harness-active":"fc-view-harness-passive",],r="",e="";return i?f.availableWidth!==null?r=f.availableWidth/i:e=100/i+"%":r=n.height||"",t("div",{ref:this.handleEl,onClick:n.onClick,className:o.join(" "),style:{height:r,paddingBottom:e}},n.children)},i.prototype.componentDidMount=function(){this.context.addResizeHandler(this.handleResize)},i.prototype.componentWillUnmount=function(){this.context.removeResizeHandler(this.handleResize)},i.prototype.updateAvailableWidth=function(){this.el&&this.props.aspectRatio&&this.setState({availableWidth:this.el.offsetWidth})},i}(e),vat=function(n){function t(t){var i=n.call(this,t)||this;return i.handleSegClick=function(n,t){var r=i.component,o=r.context,u=ir(t),f,e;u&&r.isValidSegDownEl(n.target)&&(f=d(n.target,".fc-event-forced-url"),e=f?f.querySelector("a[href]").href:"",o.emitter.trigger("eventClick",{el:t,event:new v(r.context,u.eventRange.def,u.eventRange.instance),jsEvent:n,view:o.viewApi}),e&&!n.defaultPrevented&&(window.location.href=e))},i.destroy=hc(t.el,"click",".fc-event",i.handleSegClick),i}return u(t,n),t}(di),yat=function(n){function t(t){var i=n.call(this,t)||this;return i.handleEventElRemove=function(n){n===i.currentSegEl&&i.handleSegLeave(null,i.currentSegEl)},i.handleSegEnter=function(n,t){ir(t)&&(i.currentSegEl=t,i.triggerEvent("eventMouseEnter",n,t))},i.handleSegLeave=function(n,t){i.currentSegEl&&(i.currentSegEl=null,i.triggerEvent("eventMouseLeave",n,t))},i.removeHoverListeners=iet(t.el,".fc-event",i.handleSegEnter,i.handleSegLeave),i}return u(t,n),t.prototype.destroy=function(){this.removeHoverListeners()},t.prototype.triggerEvent=function(n,t,i){var u=this.component,r=u.context,f=ir(i);(!t||u.isValidSegDownEl(t.target))&&r.emitter.trigger(n,{el:i,event:new v(r,f.eventRange.def,f.eventRange.instance),jsEvent:t,view:r.viewApi})},t}(di),yn=function(n){function r(){var t=n!==null&&n.apply(this,arguments)||this;return t.buildViewContext=f(sht),t.buildViewPropTransformers=f(wat),t.buildToolbarProps=f(pat),t.handleNavLinkClick=ob("a[data-navlink]",t._handleNavLinkClick.bind(t)),t.headerRef=h(),t.footerRef=h(),t.interactionsStore={},t.registerInteractiveComponent=function(n,i){var r=hat(n,i),u=[vat,yat,],f=u.concat(t.props.pluginHooks.componentInteractions),e=f.map(function(n){return new n(r)});t.interactionsStore[n.uid]=e;vf[n.uid]=r},t.unregisterInteractiveComponent=function(n){for(var u,i=0,r=t.interactionsStore[n.uid];i1?{"data-navlink":ur(u),tabIndex:0}:{},y=i(i(i({date:o.toDate(u),view:h},n.extraHookProps),{text:a}),f);return t(b,{hookProps:y,classNames:r.dayHeaderClassNames,content:r.dayHeaderContent,defaultContent:pn,didMount:r.dayHeaderDidMount,willUnmount:r.dayHeaderWillUnmount},function(r,e,o,s){return t("th",i({ref:r,className:l.concat(e).join(" "),"data-date":f.isDisabled?undefined:br(u),colSpan:n.colSpan},n.extraDataAttrs),t("div",{className:"fc-scrollgrid-sync-inner"},!f.isDisabled&&t("a",i({ref:o,className:["fc-col-header-cell-cushion",n.isSticky?"fc-sticky":"",].join(" ")},v),s)))})},r}(e),tv=function(n){function r(){return n!==null&&n.apply(this,arguments)||this}return u(r,n),r.prototype.render=function(){var n=this.props,r=this.context,o=r.dateEnv,s=r.theme,h=r.viewApi,u=r.options,f=p(new Date(2592e5),n.dow),e={dow:n.dow,isDisabled:!1,isFuture:!1,isPast:!1,isToday:!1,isOther:!1},c=[ga].concat(rr(e,s),n.extraClassNames||[]),l=o.format(f,n.dayHeaderFormat),a=i(i(i(i({date:f},e),{view:h}),n.extraHookProps),{text:l});return t(b,{hookProps:a,classNames:u.dayHeaderClassNames,content:u.dayHeaderContent,defaultContent:pn,didMount:u.dayHeaderDidMount,willUnmount:u.dayHeaderWillUnmount},function(r,u,f,e){return t("th",i({ref:r,className:c.concat(u).join(" "),colSpan:n.colSpan},n.extraDataAttrs),t("div",{className:"fc-scrollgrid-sync-inner"},t("a",{className:["fc-col-header-cell-cushion",n.isSticky?"fc-sticky":"",].join(" "),ref:f},e)))})},r}(e),at=function(n){function t(t,i){var r=n.call(this,t,i)||this;return r.initialNowDate=of(i.options.now,i.dateEnv),r.initialNowQueriedMs=(new Date).valueOf(),r.state=r.computeTiming().currentState,r}return u(t,n),t.prototype.render=function(){var n=this,i=n.props,t=n.state;return i.children(t.nowDate,t.todayRange)},t.prototype.componentDidMount=function(){this.setTimeout()},t.prototype.componentDidUpdate=function(n){n.unit!==this.props.unit&&(this.clearTimeout(),this.setTimeout())},t.prototype.componentWillUnmount=function(){this.clearTimeout()},t.prototype.computeTiming=function(){var r=this,u=r.props,f=r.context,e=gt(this.initialNowDate,(new Date).valueOf()-this.initialNowQueriedMs),n=f.dateEnv.startOf(e,u.unit),t=f.dateEnv.add(n,s(1,u.unit)),i=t.valueOf()-e.valueOf();return i=Math.min(864e5,i),{currentState:{nowDate:n,todayRange:wn(n)},nextState:{nowDate:t,todayRange:wn(t)},waitMs:i}},t.prototype.setTimeout=function(){var n=this,t=this.computeTiming(),i=t.nextState,r=t.waitMs;this.timeoutId=setTimeout(function(){n.setState(i,function(){n.setTimeout()})},r)},t.prototype.clearTimeout=function(){this.timeoutId&&clearTimeout(this.timeoutId)},t.contextType=lt,t}(ao);ts=function(n){function i(){var t=n!==null&&n.apply(this,arguments)||this;return t.createDayHeaderFormatter=f(bat),t}return u(i,n),i.prototype.render=function(){var e=this.context,n=this.props,i=n.dates,o=n.dateProfile,r=n.datesRepDistinctDays,u=n.renderIntro,f=this.createDayHeaderFormatter(e.options.dayHeaderFormat,r,i.length);return t(at,{unit:"day"},function(n,e){return t("tr",null,u&&u("day"),i.map(function(n){return r?t(nv,{key:n.toISOString(),date:n,dateProfile:o,todayRange:e,colCnt:i.length,dayHeaderFormat:f}):t(tv,{key:n.getUTCDay(),dow:n.getUTCDay(),dayHeaderFormat:f})}))})},i}(e);var iv=function(){function n(n,t){for(var i=n.start,e=n.end,r=[],u=[],f=-1;i=t.length?t[t.length-1]+1:t[i]},n}(),rv=function(){function n(n,t){var r=n.dates,i,f,u;if(t){for(f=r[0].getUTCDay(),i=1;iu)return!0;return!1},i.prototype.needsYScrolling=function(){var n,i;if(us.test(this.props.overflowY))return!1;var r=this.el,u=this.el.getBoundingClientRect().height-this.getXScrollbarWidth(),t=r.children;for(n=0;nu)return!0;return!1},i.prototype.getXScrollbarWidth=function(){return us.test(this.props.overflowX)?0:this.el.offsetHeight-this.el.clientHeight},i.prototype.getYScrollbarWidth=function(){return us.test(this.props.overflowY)?0:this.el.offsetWidth-this.el.clientWidth},i}(e),nt=function(){function n(n){var t=this;this.masterCallback=n;this.currentMap={};this.depths={};this.callbackMap={};this.handleValue=function(n,i){var e=t,r=e.depths,u=e.currentMap,f=!1,o=!1;n!==null?(f=i in u,u[i]=n,r[i]=(r[i]||0)+1,o=!0):(r[i]-=1,r[i]||(delete u[i],delete t.callbackMap[i],f=!0));t.masterCallback&&(f&&t.masterCallback(null,String(i)),o&&t.masterCallback(n,String(i)))}}return n.prototype.createRef=function(n){var i=this,t=this.callbackMap[n];return t||(t=this.callbackMap[n]=function(t){i.handleValue(t,String(n))}),t},n.prototype.collect=function(n,t,i){return gc(this.currentMap,n,t,i)},n.prototype.getAll=function(){return kc(this.currentMap)},n}();pf=function(n){function r(){var t=n!==null&&n.apply(this,arguments)||this;return t.processCols=f(function(n){return n},cv),t.renderMicroColGroup=f(lv),t.scrollerRefs=new nt,t.scrollerElRefs=new nt(t._handleScrollerEl.bind(t)),t.state={shrinkWidth:null,forceYScrollbars:!1,scrollerClientWidths:{},scrollerClientHeights:{}},t.handleSizing=function(){t.setState(i({shrinkWidth:t.computeShrinkWidth()},t.computeScrollerDims()))},t}return u(r,n),r.prototype.render=function(){var h=this,r=h.props,y=h.state,p=h.context,f=r.sections||[],w=this.processCols(r.cols),c=this.renderMicroColGroup(w,y.shrinkWidth),v=yv(r.liquid,p),u;r.collapsibleWidth&&v.push("fc-scrollgrid-collapsible");for(var a=f.length,n=0,i,e=[],o=[],s=[];n=0&&n=0&&t0&&(this.everMovedDown=!0);f<0?this.everMovedLeft=!0:f>0&&(this.everMovedRight=!0);this.pointerScreenX=i;this.pointerScreenY=r;this.isAnimating||(this.isAnimating=!0,this.requestAnimation(ett()))}},n.prototype.stop=function(){var n,t,i;if(this.isEnabled){for(this.isAnimating=!1,n=0,t=this.scrollCaches;n=0&&o>=0&&s>=0&&h>=0&&(s<=u&&this.everMovedUp&&r.canScrollUp()&&(!i||i.distance>s)&&(i={scrollCache:r,name:"top",distance:s}),h<=u&&this.everMovedDown&&r.canScrollDown()&&(!i||i.distance>h)&&(i={scrollCache:r,name:"bottom",distance:h}),e<=u&&this.everMovedLeft&&r.canScrollLeft()&&(!i||i.distance>e)&&(i={scrollCache:r,name:"left",distance:e}),o<=u&&this.everMovedRight&&r.canScrollRight()&&(!i||i.distance>o)&&(i={scrollCache:r,name:"right",distance:o}))}return i},n.prototype.buildCaches=function(){return this.queryScrollEls().map(function(n){return n===window?new kvt(!1):new ftt(n,!1)})},n.prototype.queryScrollEls=function(){for(var t,n=[],i=0,r=this.scrollQuery;i=t*t&&r.handleDistanceSurpassed(n)}r.isDragging&&(n.origEvent.type!=="scroll"&&(r.mirror.handleMove(n.pageX,n.pageY),r.autoScroller.handleMove(n.pageX,n.pageY)),r.emitter.trigger("dragmove",n))}};r.onPointerUp=function(n){r.isInteracting&&(r.isInteracting=!1,cb(document.body),ab(document.body),r.emitter.trigger("pointerup",n),r.isDragging&&(r.autoScroller.stop(),r.tryStopDrag(n)),r.delayTimeoutId&&(clearTimeout(r.delayTimeoutId),r.delayTimeoutId=null))};u=r.pointer=new as(t);u.emitter.on("pointerdown",r.onPointerDown);u.emitter.on("pointermove",r.onPointerMove);u.emitter.on("pointerup",r.onPointerUp);return i&&(u.selector=i),r.mirror=new bvt,r.autoScroller=new dvt,r}return u(t,n),t.prototype.destroy=function(){this.pointer.destroy();this.onPointerUp({})},t.prototype.startDelay=function(n){var t=this;typeof this.delay=="number"?this.delayTimeoutId=setTimeout(function(){t.delayTimeoutId=null;t.handleDelayEnd(n)},this.delay):this.handleDelayEnd(n)},t.prototype.handleDelayEnd=function(n){this.isDelayEnded=!0;this.tryStartDrag(n)},t.prototype.handleDistanceSurpassed=function(n){this.isDistanceSurpassed=!0;this.tryStartDrag(n)},t.prototype.tryStartDrag=function(n){this.isDelayEnded&&this.isDistanceSurpassed&&(!this.pointer.wasTouchScroll||this.touchScrollAllowed)&&(this.isDragging=!0,this.mirrorNeedsRevert=!1,this.autoScroller.start(n.pageX,n.pageY),this.emitter.trigger("dragstart",n),this.touchScrollAllowed===!1&&this.pointer.cancelTouchScroll())},t.prototype.tryStopDrag=function(n){this.mirror.stop(this.mirrorNeedsRevert,this.stopDrag.bind(this,n))},t.prototype.stopDrag=function(n){this.isDragging=!1;this.emitter.trigger("dragend",n)},t.prototype.setIgnoreMove=function(n){this.pointer.shouldIgnoreMove=n},t.prototype.setMirrorIsVisible=function(n){this.mirror.setIsVisible(n)},t.prototype.setMirrorNeedsRevert=function(n){this.mirrorNeedsRevert=n},t.prototype.setAutoScrollEnabled=function(n){this.autoScroller.isEnabled=n},t}(ba),gvt=function(){function n(n){this.origRect=co(n);this.scrollCaches=ea(n).map(function(n){return new ftt(n,!0)})}return n.prototype.destroy=function(){for(var i,n=0,t=this.scrollCaches;n=0&&c=0&&lu.layer)&&(i.componentId=f,i.context=o.context,i.rect.left+=s,i.rect.right+=s,i.rect.top+=h,i.rect.bottom+=h,u=i))}return u},n}();ott=function(n){function t(t){var r=n.call(this,t)||this,u;r.handlePointerDown=function(n){var t=r.dragging,i=n.origEvent.target;t.setIgnoreMove(!r.component.isValidDateDownEl(i))};r.handleDragEnd=function(n){var s=r.component,h=r.dragging.pointer,t,o;if(!h.wasTouchScroll){var f=r.hitDragging,u=f.initialHit,e=f.finalHit;u&&e&&vs(u,e)&&(t=s.context,o=i(i({},dv(u.dateSpan,t)),{dayEl:u.dayEl,jsEvent:n.origEvent,view:t.viewApi||t.calendarApi.view}),t.emitter.trigger("dateClick",o))}};r.dragging=new lr(t.el);r.dragging.autoScroller.isEnabled=!1;u=r.hitDragging=new uu(r.dragging,go(t));u.emitter.on("pointerdown",r.handlePointerDown);u.emitter.on("dragend",r.handleDragEnd);return r}return u(t,n),t.prototype.destroy=function(){this.dragging.destroy()},t}(di);stt=function(n){function t(t){var i=n.call(this,t)||this,r;i.dragSelection=null;i.handlePointerDown=function(n){var r=i,t=r.component,u=r.dragging,f=t.context.options,e=f.selectable&&t.isValidDateDownEl(n.origEvent.target);u.setIgnoreMove(!e);u.delay=n.isTouch?iyt(t):null};i.handleDragStart=function(n){i.component.context.calendarApi.unselect(n)};i.handleHitUpdate=function(n,t){var u=i.component.context,r=null,e=!1,f,o;n&&(f=i.hitDragging.initialHit,o=n.componentId===f.componentId&&i.isHitComboAllowed&&!i.isHitComboAllowed(f,n),o||(r=ryt(f,n,u.pluginHooks.dateSelectionTransformers)),r&&bn(r,n.dateProfile,u)||(e=!0,r=null));r?u.dispatch({type:"SELECT_DATES",selection:r}):t||u.dispatch({type:"UNSELECT_DATES"});e?au():vu();t||(i.dragSelection=r)};i.handlePointerUp=function(n){i.dragSelection&&(ll(i.dragSelection,n,i.component.context),i.dragSelection=null)};var e=t.component,f=e.context.options,u=i.dragging=new lr(t.el);u.touchScrollAllowed=!1;u.minDistance=f.selectMinDistance||0;u.autoScroller.isEnabled=f.dragScroll;r=i.hitDragging=new uu(i.dragging,go(t));r.emitter.on("pointerdown",i.handlePointerDown);r.emitter.on("dragstart",i.handleDragStart);r.emitter.on("hitupdate",i.handleHitUpdate);r.emitter.on("pointerup",i.handlePointerUp);return i}return u(t,n),t.prototype.destroy=function(){this.dragging.destroy()},t}(di);gv=function(n){function t(r){var u=n.call(this,r)||this,f;u.subjectEl=null;u.subjectSeg=null;u.isDragging=!1;u.eventRange=null;u.relevantEvents=null;u.receivingContext=null;u.validMutation=null;u.mutatedRelevantEvents=null;u.handlePointerDown=function(n){var f=n.origEvent.target,o=u,t=o.component,i=o.dragging,s=i.mirror,r=t.context.options,c=t.context,e;u.subjectEl=n.subjectEl;var l=u.subjectSeg=ir(n.subjectEl),a=u.eventRange=l.eventRange,h=a.instance.instanceId;u.relevantEvents=ge(c.getCurrentData().eventStore,h);i.minDistance=n.isTouch?0:r.eventDragMinDistance;i.delay=n.isTouch&&h!==t.props.eventSelection?fyt(t):null;s.parentNode=r.fixedMirrorParent?r.fixedMirrorParent:d(f,".fc");s.revertDuration=r.dragRevertDuration;e=t.isValidSegDownEl(f)&&!d(f,".fc-event-resizer");i.setIgnoreMove(!e);u.isDragging=e&&n.subjectEl.classList.contains("fc-event-draggable")};u.handleDragStart=function(n){var t=u.component.context,i=u.eventRange,r=i.instance.instanceId;n.isTouch?r!==u.component.props.eventSelection&&t.dispatch({type:"SELECT_EVENT",eventInstanceId:r}):t.dispatch({type:"UNSELECT_EVENT"});u.isDragging&&(t.calendarApi.unselect(n),t.emitter.trigger("eventDragStart",{el:u.subjectEl,event:new v(t,i.def,i.instance),jsEvent:n.origEvent,view:t.viewApi}))};u.handleHitUpdate=function(n,t){var o;if(u.isDragging){var s=u.relevantEvents,h=u.hitDragging.initialHit,c=u.component.context,i=null,r=null,f=null,l=!1,e={affectedEvents:s,mutatedEvents:it(),isEvent:!0};n&&(i=n.context,o=i.options,c===i||o.editable&&o.droppable?(r=uyt(h,n,i.getCurrentData().pluginHooks.eventDragMutationMassagers),r&&(f=eo(s,i.getCurrentData().eventUiBases,r,i),e.mutatedEvents=f,rs(e,n.dateProfile,i)||(l=!0,r=null,f=null,e.mutatedEvents=it()))):i=null);u.displayDrag(i,e);l?au():vu();t||(c===i&&vs(h,n)&&(r=null),u.dragging.setMirrorNeedsRevert(!r),u.dragging.setMirrorIsVisible(!n||!document.querySelector(".fc-event-mirror")),u.receivingContext=i,u.validMutation=r,u.mutatedRelevantEvents=f)}};u.handlePointerUp=function(){u.isDragging||u.cleanup()};u.handleDragEnd=function(n){var nt,p,w,s,b,tt,k,d;if(u.isDragging){var t=u.component.context,h=t.viewApi,g=u,r=g.receivingContext,c=g.validMutation,l=u.eventRange.def,e=u.eventRange.instance,a=new v(t,l,e),o=u.relevantEvents,f=u.mutatedRelevantEvents,y=u.hitDragging.finalHit;if(u.clearDrag(),t.emitter.trigger("eventDragStop",{el:u.subjectEl,event:a,jsEvent:n.origEvent,view:h}),c){if(r===t){for(nt=new v(t,f.defs[l.defId],e?f.instances[e.instanceId]:null),t.dispatch({type:"MERGE_EVENTS",eventStore:f}),p={oldEvent:a,event:nt,relatedEvents:wi(f,t,e),revert:function(){t.dispatch({type:"MERGE_EVENTS",eventStore:o})}},w={},s=0,b=t.getCurrentData().pluginHooks.eventDropTransformers;s=0)for(o=t.lateralStart;o1,showWeekNumbers:n.showWeekNumbers,todayRange:o,dateProfile:h,cells:f,renderIntro:n.renderRowIntro,businessHourSegs:l[e],eventSelection:n.eventSelection,bgEventSegs:a[e].filter(fpt),fgEventSegs:v[e],dateSelectionSegs:y[e],eventDrag:p[e],eventResize:w[e],dayMaxEvents:u,dayMaxEventRows:r,clientWidth:n.clientWidth,clientHeight:n.clientHeight,forPrint:n.forPrint})}))))}))},r.prototype.prepareHits=function(){this.rowPositions=new fi(this.rootEl,this.rowRefs.collect().map(function(n){return n.getCellEls()[0]}),!1,!0);this.colPositions=new fi(this.rootEl,this.rowRefs.currentMap[0].getCellEls(),!0,!1)},r.prototype.queryHit=function(n,t){var o=this,f=o.colPositions,e=o.rowPositions,r=f.leftToIndex(n),u=e.topToIndex(t),s;return u!=null&&r!=null?(s=this.props.cells[u][r],{dateProfile:this.props.dateProfile,dateSpan:i({range:this.getCellRange(u,r),allDay:!0},s.extraDateSpan),dayEl:this.getCellEl(u,r),rect:{left:f.lefts[r],right:f.rights[r],top:e.tops[u],bottom:e.bottoms[u]},layer:0}):null},r.prototype.getCellEl=function(n,t){return this.rowRefs.currentMap[n].getCellEls()[t]},r.prototype.getCellRange=function(n,t){var i=this.props.cells[n][t].date,r=p(i,1);return{start:i,end:r}},r}(rt);var fy=function(n){function t(){var t=n!==null&&n.apply(this,arguments)||this;return t.forceDayIfListItem=!0,t}return u(t,n),t.prototype.sliceRange=function(n,t){return t.sliceRange(n)},t}(is),ey=function(n){function r(){var t=n!==null&&n.apply(this,arguments)||this;return t.slicer=new fy,t.tableRef=h(),t}return u(r,n),r.prototype.render=function(){var r=this,n=r.props,u=r.context;return t(ws,i({ref:this.tableRef},this.slicer.sliceProps(n,n.dateProfile,n.nextDayThreshold,u,n.dayTableModel),{dateProfile:n.dateProfile,cells:n.dayTableModel.cells,colGroupNode:n.colGroupNode,tableMinWidth:n.tableMinWidth,renderRowIntro:n.renderRowIntro,dayMaxEvents:n.dayMaxEvents,dayMaxEventRows:n.dayMaxEventRows,showWeekNumbers:n.showWeekNumbers,expandRows:n.expandRows,headerAlignElRef:n.headerAlignElRef,clientWidth:n.clientWidth,clientHeight:n.clientHeight,forPrint:n.forPrint}))},r}(rt),ktt=function(n){function i(){var t=n!==null&&n.apply(this,arguments)||this;return t.buildDayTableModel=f(oy),t.headerRef=h(),t.tableRef=h(),t}return u(i,n),i.prototype.render=function(){var u=this,f=this.context,i=f.options,s=f.dateProfileGenerator,n=this.props,r=this.buildDayTableModel(n.dateProfile,s),e=i.dayHeaders&&t(ts,{ref:this.headerRef,dateProfile:n.dateProfile,dates:r.headerDates,datesRepDistinctDays:r.rowCnt===1}),o=function(f){return t(ey,{ref:u.tableRef,dateProfile:n.dateProfile,dayTableModel:r,businessHours:n.businessHours,dateSelection:n.dateSelection,eventStore:n.eventStore,eventUiBases:n.eventUiBases,eventSelection:n.eventSelection,eventDrag:n.eventDrag,eventResize:n.eventResize,nextDayThreshold:i.nextDayThreshold,colGroupNode:f.tableColGroupNode,tableMinWidth:f.tableMinWidth,dayMaxEvents:i.dayMaxEvents,dayMaxEventRows:i.dayMaxEventRows,showWeekNumbers:i.weekNumbers,expandRows:!n.isHeightAuto,headerAlignElRef:u.headerElRef,clientWidth:f.clientWidth,clientHeight:f.clientHeight,forPrint:n.forPrint})};return i.dayMinWidth?this.renderHScrollLayout(e,o,r.colCnt,i.dayMinWidth):this.renderSimpleLayout(e,o)},i}(ny);var ept=function(n){function t(){return n!==null&&n.apply(this,arguments)||this}return u(t,n),t.prototype.buildRenderRange=function(t,i,r){var o=this.props.dateEnv,s=n.prototype.buildRenderRange.call(this,t,i,r),f=s.start,u=s.end,e,h;return/^(year|month)$/.test(i)&&(f=o.startOfWeek(f),e=o.startOfWeek(u),e.valueOf()!==u.valueOf()&&(u=pc(e,1))),this.props.monthMode&&this.props.fixedWeekCount&&(h=Math.ceil(wb(f,u)),u=pc(u,6-h)),{start:f,end:u}},t}(yo),dtt=k({initialView:"dayGridMonth",views:{dayGrid:{component:ktt,dateProfileGeneratorClass:ept},dayGridDay:{type:"dayGrid",duration:{days:1}},dayGridWeek:{type:"dayGrid",duration:{weeks:1}},dayGridMonth:{type:"dayGrid",duration:{months:1},monthMode:!0,fixedWeekCount:!0}}}),opt=function(n){function t(){return n!==null&&n.apply(this,arguments)||this}return u(t,n),t.prototype.getKeyInfo=function(){return{allDay:{},timed:{}}},t.prototype.getKeysForDateSpan=function(n){return n.allDay?["allDay"]:["timed"]},t.prototype.getKeysForEventDef=function(n){return n.allDay?nd(n)?["timed","allDay"]:["allDay"]:["timed"]},t}(sf),spt=y({hour:"numeric",minute:"2-digit",omitZeroMinute:!0,meridiem:"short"});var cpt=function(n){function r(){return n!==null&&n.apply(this,arguments)||this}return u(r,n),r.prototype.render=function(){return this.props.slatMetas.map(function(n){return t("tr",{key:n.key},t(gtt,i({},n)))})},r}(e),lpt=y({week:"short"}),apt=5,sy=function(n){function r(){var r=n!==null&&n.apply(this,arguments)||this;return r.allDaySplitter=new opt,r.headerElRef=h(),r.rootElRef=h(),r.scrollerElRef=h(),r.state={slatCoords:null},r.handleScrollTopRequest=function(n){var t=r.scrollerElRef.current;t&&(t.scrollTop=n)},r.renderHeadAxis=function(n,u){u===void 0&&(u="");var e=r.context.options,o=r.props.dateProfile,f=o.renderRange,s=ni(f.start,f.end),h=e.navLinks&&s===1?{"data-navlink":ur(f.start,"week"),tabIndex:0}:{};return e.weekNumbers&&n==="day"?t(hs,{date:f.start,defaultFormat:lpt},function(n,r,f,e){return t("th",{ref:n,className:["fc-timegrid-axis","fc-scrollgrid-shrink",].concat(r).join(" ")},t("div",{className:"fc-timegrid-axis-frame fc-scrollgrid-shrink-frame fc-timegrid-axis-frame-liquid",style:{height:u}},t("a",i({ref:f,className:"fc-timegrid-axis-cushion fc-scrollgrid-shrink-cushion fc-scrollgrid-sync-inner"},h),e)))}):t("th",{className:"fc-timegrid-axis"},t("div",{className:"fc-timegrid-axis-frame",style:{height:u}}))},r.renderTableRowAxis=function(n){var u=r.context,i=u.options,f=u.viewApi,e={text:i.allDayText,view:f};return t(b,{hookProps:e,classNames:i.allDayClassNames,content:i.allDayContent,defaultContent:vpt,didMount:i.allDayDidMount,willUnmount:i.allDayWillUnmount},function(i,r,u,f){return t("td",{ref:i,className:["fc-timegrid-axis","fc-scrollgrid-shrink",].concat(r).join(" ")},t("div",{className:"fc-timegrid-axis-frame fc-scrollgrid-shrink-frame"+(n==null?" fc-timegrid-axis-frame-liquid":""),style:{height:n}},t("span",{className:"fc-timegrid-axis-cushion fc-scrollgrid-shrink-cushion fc-scrollgrid-sync-inner",ref:u},f)))})},r.handleSlatCoords=function(n){r.setState({slatCoords:n})},r}return u(r,n),r.prototype.renderSimpleLayout=function(n,i,r){var o=this,f=o.context,e=o.props,u=[],s=hr(f.options);return n&&u.push({type:"header",key:"header",isSticky:s,chunk:{elRef:this.headerElRef,tableClassName:"fc-col-header",rowContent:n}}),i&&(u.push({type:"body",key:"all-day",chunk:{content:i}}),u.push({type:"body",key:"all-day-divider",outerContent:t("tr",{className:"fc-scrollgrid-section"},t("td",{className:"fc-timegrid-divider "+f.theme.getClass("tableCellShaded")}))})),u.push({type:"body",key:"body",liquid:!0,expandRows:Boolean(f.options.expandRows),chunk:{scrollerElRef:this.scrollerElRef,content:r}}),t(bt,{viewSpec:f.viewSpec,elRef:this.rootElRef},function(n,i){return t("div",{className:["fc-timegrid"].concat(i).join(" "),ref:n},t(pf,{liquid:!e.isHeightAuto&&!e.forPrint,collapsibleWidth:e.forPrint,cols:[{width:"shrink"}],sections:u}))})},r.prototype.renderHScrollLayout=function(n,i,r,u,f,e,o){var a=this,v=this.context.pluginHooks.scrollGridImpl,l;if(!v)throw new Error("No ScrollGrid implementation");var y=this,s=y.context,c=y.props,p=!c.forPrint&&hr(s.options),w=!c.forPrint&&yf(s.options),h=[];return n&&h.push({type:"header",key:"header",isSticky:p,syncRowHeights:!0,chunks:[{key:"axis",rowContent:function(n){return t("tr",null,a.renderHeadAxis("day",n.rowSyncHeights[0]))}},{key:"cols",elRef:this.headerElRef,tableClassName:"fc-col-header",rowContent:n},]}),i&&(h.push({type:"body",key:"all-day",syncRowHeights:!0,chunks:[{key:"axis",rowContent:function(n){return t("tr",null,a.renderTableRowAxis(n.rowSyncHeights[0]))}},{key:"cols",content:i},]}),h.push({key:"all-day-divider",type:"body",outerContent:t("tr",{className:"fc-scrollgrid-section"},t("td",{colSpan:2,className:"fc-timegrid-divider "+s.theme.getClass("tableCellShaded")}))})),l=s.options.nowIndicator,h.push({type:"body",key:"body",liquid:!0,expandRows:Boolean(s.options.expandRows),chunks:[{key:"axis",content:function(n){return t("div",{className:"fc-timegrid-axis-chunk"},t("table",{style:{height:n.expandRows?n.clientHeight:""}},n.tableColGroupNode,t("tbody",null,t(cpt,{slatMetas:e}))),t("div",{className:"fc-timegrid-now-indicator-container"},t(at,{unit:l?"minute":"day"},function(n){var i=l&&o&&o.safeComputeTop(n);return typeof i=="number"?t(cr,{isAxis:!0,date:n},function(n,r,u,f){return t("div",{ref:n,className:["fc-timegrid-now-indicator-arrow"].concat(r).join(" "),style:{top:i}},f)}):null})))}},{key:"cols",scrollerElRef:this.scrollerElRef,content:r},]}),w&&h.push({key:"footer",type:"footer",isSticky:!0,chunks:[{key:"axis",content:sr},{key:"cols",content:sr},]}),t(bt,{viewSpec:s.viewSpec,elRef:this.rootElRef},function(n,i){return t("div",{className:["fc-timegrid"].concat(i).join(" "),ref:n},t(v,{liquid:!c.isHeightAuto&&!c.forPrint,collapsibleWidth:!1,colGroups:[{width:"shrink",cols:[{width:"shrink"}]},{cols:[{span:u,minWidth:f}]},],sections:h}))})},r.prototype.getAllDayMaxEventProps=function(){var i=this.context.options,n=i.dayMaxEvents,t=i.dayMaxEventRows;return(n===!0||t===!0)&&(n=undefined,t=apt),{dayMaxEvents:n,dayMaxEventRows:t}},r}(rt);var nit=function(){function n(n,t,i){this.positions=n;this.dateProfile=t;this.slotDuration=i}return n.prototype.safeComputeTop=function(n){var i=this.dateProfile,r,t;return wt(i.currentRange,n)&&(r=a(n),t=n.valueOf()-r.valueOf(),t>=tt(i.slotMinTime)&&t0,b=Boolean(o)&&o.span.end-o.span.start0?r.renderSegList(e,s):r.renderEmptyMessage()))})},r.prototype.renderEmptyMessage=function(){var i=this.context,n=i.options,r=i.viewApi,u={text:n.noEventsText,view:r};return t(b,{hookProps:u,classNames:n.noEventsClassNames,content:n.noEventsContent,defaultContent:kwt,didMount:n.noEventsDidMount,willUnmount:n.noEventsWillUnmount},function(n,i,r,u){return t("div",{className:["fc-list-empty"].concat(i).join(" "),ref:n},t("div",{className:"fc-list-empty-cushion",ref:r},u))})},r.prototype.renderSegList=function(n,r){var u=this.context,e=u.theme,o=u.options,f=gwt(n);return t(at,{unit:"day"},function(n,u){for(var h,v,c,y,l,a=[],s=0;sthis.lastSizingDate.valueOf()+ot.SCROLLGRID_RESIZE_INTERVAL?(this.lastSizingDate=n,this.recentSizingCnt=0,!0):(this.recentSizingCnt+=1)<=10},r.prototype.computeShrinkWidths=function(){var r=this,u=this.compileColGroupStats(this.props.colGroups.map(function(n){return[n]})),n=this.getDims(),f=n[0],t=n[1],e=f*t,i=[];return u.forEach(function(n,u){if(n.hasShrinkCol){var f=r.chunkElRefs.collect(u,e,t);i[u]=ov(f)}}),i},r.prototype.computeSectionRowMaxHeights=function(){for(var u,f,i,s,h,d,c,g,r,a,v,it,n,y=new Map,p=this.getDims(),rt=p[0],t=p[1],w=[],o=0;o1)?t(kut,{key:o,colSpec:e,fieldValue:h,rowSpan:s}):t(but,{key:o,colSpec:e,resource:i,fieldValue:h,depth:u,hasChildren:n.hasChildren,isExpanded:n.isExpanded,innerHeight:n.innerHeight})}))},i}(e);ah.addPropsEquality({rowSpans:ht});gp=function(n){function i(){var t=n!==null&&n.apply(this,arguments)||this;return t.innerInnerRef=h(),t.onExpanderClick=function(){var n=t.props;t.context.dispatch({type:"SET_RESOURCE_ENTITY_EXPANDED",id:n.id,isExpanded:!n.isExpanded})},t}return u(i,n),i.prototype.render=function(){var r=this,u=this,n=u.props,f=u.context,e={groupValue:n.group.value,view:f.viewApi},i=n.group.spec;return t("tr",null,t(b,{hookProps:e,classNames:i.labelClassNames,content:i.labelContent,defaultContent:cti,didMount:i.labelDidMount,willUnmount:i.labelWillUnmount},function(i,u,e,o){return t("td",{ref:i,colSpan:n.spreadsheetColCnt,className:["fc-datagrid-cell","fc-resource-group",f.theme.getClass("tableCellShaded"),].concat(u).join(" ")},t("div",{className:"fc-datagrid-cell-frame",style:{height:n.innerHeight}},t("div",{className:"fc-datagrid-cell-cushion fc-scrollgrid-sync-inner",ref:r.innerInnerRef},t(put,{depth:0,hasChildren:!0,isExpanded:n.isExpanded,onExpanderClick:r.onExpanderClick}),t("span",{className:"fc-datagrid-cell-main",ref:e},o))))}))},i}(e);gp.addPropsEquality({group:cut});var lti=20,ati=function(n){function i(){var t=n!==null&&n.apply(this,arguments)||this;return t.resizerElRefs=new nt(t._handleColResizerEl.bind(t)),t.colDraggings={},t}return u(i,n),i.prototype.render=function(){var h=this,r=this.props,u=r.colSpecs,n=r.superHeaderRendering,i=r.rowInnerHeights,e={view:this.context.viewApi},f=[],o,s;return i=i.slice(),n&&(o=i.shift(),f.push(t("tr",{key:"row-super"},t(b,{hookProps:e,classNames:n.headerClassNames,content:n.headerContent,didMount:n.headerDidMount,willUnmount:n.headerWillUnmount},function(n,i,r,f){return t("th",{colSpan:u.length,ref:n,className:["fc-datagrid-cell","fc-datagrid-cell-super",].concat(i).join(" ")},t("div",{className:"fc-datagrid-cell-frame",style:{height:o}},t("div",{className:"fc-datagrid-cell-cushion fc-scrollgrid-sync-inner",ref:r},f)))})))),s=i.shift(),f.push(t("tr",{key:"row"},u.map(function(n,i){var r=i===u.length-1;return t(b,{key:i,hookProps:e,classNames:n.headerClassNames,content:n.headerContent,didMount:n.headerDidMount,willUnmount:n.headerWillUnmount},function(u,f,e,o){return t("th",{ref:u,className:["fc-datagrid-cell"].concat(f).join(" ")},t("div",{className:"fc-datagrid-cell-frame",style:{height:s}},t("div",{className:"fc-datagrid-cell-cushion fc-scrollgrid-sync-inner"},n.isMain&&t("span",{className:"fc-datagrid-expander fc-datagrid-expander-placeholder"},t("span",{className:"fc-icon"})),t("span",{className:"fc-datagrid-cell-main",ref:e},o)),!r&&t("div",{className:"fc-datagrid-cell-resizer",ref:h.resizerElRefs.createRef(i)})))})}))),t(c,null,f)},i.prototype._handleColResizerEl=function(n,t){var r=this.colDraggings,i;n?(i=this.initColResizing(n,parseInt(t,10)),i&&(r[t]=i)):(i=r[t],i&&(i.destroy(),delete r[t]))},i.prototype.initColResizing=function(n,t){var u=this.context,s=u.pluginHooks,h=u.isRtl,f=this.props.onColWidthChange,e=s.elementDraggingImpl,i,o,r;if(e){i=new e(n);i.emitter.on("dragstart",function(){var i=dt(d(n,"tr"),"th");r=i.map(function(n){return n.getBoundingClientRect().width});o=r[t]});i.emitter.on("dragmove",function(n){r[t]=Math.max(o+n.deltaX*(h?-1:1),lti);f&&f(r.slice())});return i.setAutoScrollEnabled(!1),i}return null},i}(e),vti=function(n){function i(){return n!==null&&n.apply(this,arguments)||this}return u(i,n),i.prototype.render=function(){var n=this,r=n.props,i=n.context,u={resource:new ft(i,r.resource)};return t(tu,{hookProps:u,content:i.options.resourceLaneContent},function(n,i){return i&&t("div",{className:"fc-timeline-lane-misc",ref:n},i)})},i}(e),dut=function(n){function i(){var t=n!==null&&n.apply(this,arguments)||this;return t.refineHookProps=yi(yti),t.normalizeClassNames=iu(),t.handleHeightChange=function(n,i){if(t.props.onHeightChange)t.props.onHeightChange(d(n,"tr"),i)},t}return u(i,n),i.prototype.render=function(){var e=this,r=this,n=r.props,u=r.context,i=u.options,f=this.refineHookProps({resource:n.resource,context:u}),o=this.normalizeClassNames(i.resourceLaneClassNames,f);return t("tr",{ref:n.elRef},t(bi,{hookProps:f,didMount:i.resourceLaneDidMount,willUnmount:i.resourceLaneWillUnmount},function(i){return t("td",{ref:i,className:["fc-timeline-lane","fc-resource"].concat(o).join(" "),"data-resource-id":n.resource.id},t("div",{className:"fc-timeline-lane-frame",style:{height:n.innerHeight}},t(vti,{resource:n.resource}),t(fh,{dateProfile:n.dateProfile,tDateProfile:n.tDateProfile,nowDate:n.nowDate,todayRange:n.todayRange,nextDayThreshold:n.nextDayThreshold,businessHours:n.businessHours,eventStore:n.eventStore,eventUiBases:n.eventUiBases,dateSelection:n.dateSelection,eventSelection:n.eventSelection,eventDrag:n.eventDrag,eventResize:n.eventResize,timelineCoords:n.timelineCoords,onHeightChange:e.handleHeightChange,resourceId:n.resource.id})))}))},i}(e);var pti=function(n){function i(){return n!==null&&n.apply(this,arguments)||this}return u(i,n),i.prototype.render=function(){var r=this,i=this.props,n=this.props.renderingHooks,u={groupValue:i.groupValue,view:this.context.viewApi};return t("tr",{ref:i.elRef},t(b,{hookProps:u,classNames:n.laneClassNames,content:n.laneContent,didMount:n.laneDidMount,willUnmount:n.laneWillUnmount},function(n,u,f,e){return t("td",{ref:n,className:["fc-timeline-lane","fc-resource-group",r.context.theme.getClass("tableCellShaded"),].concat(u).join(" ")},t("div",{style:{height:i.innerHeight},ref:f},e))}))},i}(e),wti=function(n){function r(){return n!==null&&n.apply(this,arguments)||this}return u(r,n),r.prototype.render=function(){var r=this,n=r.props,e=r.context,u=n.rowElRefs,f=n.innerHeights;return t("tbody",null,n.rowNodes.map(function(r,o){if(r.group)return t(pti,{key:r.id,elRef:u.createRef(r.id),groupValue:r.group.value,renderingHooks:r.group.spec,innerHeight:f[o]||""});if(r.resource){var s=r.resource;return t(dut,i({key:r.id,elRef:u.createRef(r.id)},n.splitProps[s.id],{resource:s,dateProfile:n.dateProfile,tDateProfile:n.tDateProfile,nowDate:n.nowDate,todayRange:n.todayRange,nextDayThreshold:e.options.nextDayThreshold,businessHours:s.businessHours||n.fallbackBusinessHours,innerHeight:f[o]||"",timelineCoords:n.slatCoords,onHeightChange:n.onRowHeightChange}))}return null}))},r}(e),bti=function(n){function i(){var t=n!==null&&n.apply(this,arguments)||this;return t.rootElRef=h(),t.rowElRefs=new nt,t}return u(i,n),i.prototype.render=function(){var i=this,n=i.props,r=i.context;return t("table",{ref:this.rootElRef,className:"fc-scrollgrid-sync-table "+r.theme.getClass("table"),style:{minWidth:n.tableMinWidth,width:n.clientWidth,height:n.minHeight}},t(wti,{rowElRefs:this.rowElRefs,rowNodes:n.rowNodes,dateProfile:n.dateProfile,tDateProfile:n.tDateProfile,nowDate:n.nowDate,todayRange:n.todayRange,splitProps:n.splitProps,fallbackBusinessHours:n.fallbackBusinessHours,slatCoords:n.slatCoords,innerHeights:n.innerHeights,onRowHeightChange:n.onRowHeightChange}))},i.prototype.componentDidMount=function(){this.updateCoords()},i.prototype.componentDidUpdate=function(){this.updateCoords()},i.prototype.componentWillUnmount=function(){if(this.props.onRowCoords)this.props.onRowCoords(null)},i.prototype.updateCoords=function(){var n=this.props;if(n.onRowCoords&&n.clientWidth!==null)this.props.onRowCoords(new fi(this.rootElRef.current,kti(this.rowElRefs.currentMap,n.rowNodes),!1,!0))},i}(e);gut=function(n){function i(){var t=n!==null&&n.apply(this,arguments)||this;return t.computeHasResourceBusinessHours=f(dti),t.resourceSplitter=new oh,t.bgSlicer=new ip,t.slatsRef=h(),t.state={slatCoords:null},t.handleEl=function(n){n?t.context.registerInteractiveComponent(t,{el:n}):t.context.unregisterInteractiveComponent(t)},t.handleSlatCoords=function(n){if(t.setState({slatCoords:n}),t.props.onSlatCoords)t.props.onSlatCoords(n)},t.handleRowCoords=function(n){if(t.rowCoords=n,t.props.onRowCoords)t.props.onRowCoords(n)},t}return u(i,n),i.prototype.render=function(){var o=this,s=this,n=s.props,h=s.state,i=s.context,f=n.dateProfile,e=n.tDateProfile,v=ii(e.slotDuration).unit,l=this.computeHasResourceBusinessHours(n.rowNodes),a=this.resourceSplitter.splitProps(n),y=a[""],r=this.bgSlicer.sliceProps(y,f,e.isTimeScale?null:n.nextDayThreshold,i,f,i.dateProfileGenerator,e,i.dateEnv),u=h.slatCoords&&h.slatCoords.dateProfile===n.dateProfile?h.slatCoords:null;return t("div",{ref:this.handleEl,className:["fc-timeline-body",n.expandRows?"fc-timeline-body-expandrows":"",].join(" "),style:{minWidth:n.tableMinWidth}},t(at,{unit:v},function(s,h){return t(c,null,t(np,{ref:o.slatsRef,dateProfile:f,tDateProfile:e,nowDate:s,todayRange:h,clientWidth:n.clientWidth,tableColGroupNode:n.tableColGroupNode,tableMinWidth:n.tableMinWidth,onCoords:o.handleSlatCoords,onScrollLeftRequest:n.onScrollLeftRequest}),t(tp,{businessHourSegs:l?null:r.businessHourSegs,bgEventSegs:r.bgEventSegs,timelineCoords:u,eventResizeSegs:r.eventResize?r.eventResize.segs:[],dateSelectionSegs:r.dateSelectionSegs,nowDate:s,todayRange:h}),t(bti,{rowNodes:n.rowNodes,dateProfile:f,tDateProfile:n.tDateProfile,nowDate:s,todayRange:h,splitProps:a,fallbackBusinessHours:l?n.businessHours:null,clientWidth:n.clientWidth,minHeight:n.expandRows?n.clientHeight:"",tableMinWidth:n.tableMinWidth,innerHeights:n.rowInnerHeights,slatCoords:u,onRowCoords:o.handleRowCoords,onRowHeightChange:n.onRowHeightChange}),i.options.nowIndicator&&u&&u.isDateInRange(s)&&t("div",{className:"fc-timeline-now-indicator-container"},t(cr,{isAxis:!1,date:s},function(n,r,f,e){return t("div",{ref:n,className:["fc-timeline-now-indicator-line"].concat(r).join(" "),style:rh(u.dateToCoord(s),i.isRtl)},e)})))}))},i.prototype.queryHit=function(n,t){var u=this.rowCoords,r=u.topToIndex(t),f,i;return r!=null&&(f=this.props.rowNodes[r].resource,f&&(i=this.slatsRef.current.positionToHit(n),i))?{dateProfile:this.props.dateProfile,dateSpan:{range:i.dateSpan.range,allDay:i.dateSpan.allDay,resourceId:f.id},rect:{left:i.left,right:i.right,top:u.tops[r],bottom:u.bottoms[r]},dayEl:i.dayEl,layer:0}:null},i}(rt);var nft=30,gti=function(n){function i(){var t=n!==null&&n.apply(this,arguments)||this;return t.scrollGridRef=h(),t.timeBodyScrollerElRef=h(),t.spreadsheetHeaderChunkElRef=h(),t.rootElRef=h(),t.ensureScrollGridResizeId=0,t.state={resourceAreaWidthOverride:null},t.ensureScrollGridResize=function(){t.ensureScrollGridResizeId&&clearTimeout(t.ensureScrollGridResizeId);t.ensureScrollGridResizeId=setTimeout(function(){t.scrollGridRef.current.handleSizing(!1)},ot.SCROLLGRID_RESIZE_INTERVAL+1)},t}return u(i,n),i.prototype.render=function(){var u=this,n=u.props,f=u.state,i=u.context,r=i.options,s=!n.forPrint&&hr(r),h=!n.forPrint&&yf(r),e=[{type:"header",key:"header",syncRowHeights:!0,isSticky:s,chunks:[{key:"datagrid",elRef:this.spreadsheetHeaderChunkElRef,tableClassName:"fc-datagrid-header",rowContent:n.spreadsheetHeaderRows},{key:"divider",outerContent:t("td",{className:"fc-resource-timeline-divider "+i.theme.getClass("tableCellShaded")})},{key:"timeline",content:n.timeHeaderContent},]},{type:"body",key:"body",syncRowHeights:!0,liquid:!0,expandRows:Boolean(r.expandRows),chunks:[{key:"datagrid",tableClassName:"fc-datagrid-body",rowContent:n.spreadsheetBodyRows},{key:"divider",outerContent:t("td",{className:"fc-resource-timeline-divider "+i.theme.getClass("tableCellShaded")})},{key:"timeline",scrollerElRef:this.timeBodyScrollerElRef,content:n.timeBodyContent},]},],o;return h&&e.push({type:"footer",key:"footer",isSticky:!0,chunks:[{key:"datagrid",content:sr},{key:"divider",outerContent:t("td",{className:"fc-resource-timeline-divider "+i.theme.getClass("tableCellShaded")})},{key:"timeline",content:sr},]}),o=f.resourceAreaWidthOverride!=null?f.resourceAreaWidthOverride:r.resourceAreaWidth,t(ne,{ref:this.scrollGridRef,elRef:this.rootElRef,liquid:!n.isHeightAuto&&!n.forPrint,collapsibleWidth:!1,colGroups:[{cols:n.spreadsheetCols,width:o},{cols:[]},{cols:n.timeCols},],sections:e})},i.prototype.forceTimeScroll=function(n){var t=this.scrollGridRef.current;t.forceScrollLeft(2,n)},i.prototype.forceResourceScroll=function(n){var t=this.scrollGridRef.current;t.forceScrollTop(1,n)},i.prototype.getResourceScroll=function(){var n=this.timeBodyScrollerElRef.current;return n.scrollTop},i.prototype.componentDidMount=function(){this.initSpreadsheetResizing()},i.prototype.componentWillUnmount=function(){this.destroySpreadsheetResizing()},i.prototype.initSpreadsheetResizing=function(){var i=this,r=this.context,o=r.isRtl,s=r.pluginHooks,u=s.elementDraggingImpl,h=this.spreadsheetHeaderChunkElRef.current,t,n,f,e;if(u){t=this.rootElRef.current;n=this.spreadsheetResizerDragging=new u(t,".fc-resource-timeline-divider");n.emitter.on("dragstart",function(){f=h.getBoundingClientRect().width;e=t.getBoundingClientRect().width});n.emitter.on("dragmove",function(n){var t=f+n.deltaX*(o?-1:1);t=Math.max(t,nft);t=Math.min(t,e-nft);i.setState({resourceAreaWidthOverride:t},i.ensureScrollGridResize)});n.setAutoScrollEnabled(!1)}},i.prototype.destroySpreadsheetResizing=function(){this.spreadsheetResizerDragging&&this.spreadsheetResizerDragging.destroy()},i}(e),nw=function(n){function i(t,i){var r=n.call(this,t,i)||this;return r.processColOptions=f(rii),r.buildTimelineDateProfile=f(ky),r.hasNesting=f(iii),r.buildRowNodes=f(bp),r.layoutRef=h(),r.rowNodes=[],r.renderedRowNodes=[],r.buildRowIndex=f(nii),r.handleSlatCoords=function(n){r.setState({slatCoords:n})},r.handleRowCoords=function(n){r.rowCoords=n;r.scrollResponder.update(!1)},r.handleMaxCushionWidth=function(n){r.setState({slotCushionMaxWidth:Math.ceil(n)})},r.handleScrollLeftRequest=function(n){var t=r.layoutRef.current;t.forceTimeScroll(n)},r.handleScrollRequest=function(n){var i=r.rowCoords,o=r.layoutRef.current,u=n.rowId||n.resourceId,f,t,e;return i?(u&&(f=r.buildRowIndex(r.renderedRowNodes),t=f[u],t!=null&&(e=n.fromBottom!=null?i.bottoms[t]-n.fromBottom:i.tops[t],o.forceResourceScroll(e))),!0):null},r.handleColWidthChange=function(n){r.setState({spreadsheetColWidths:n})},r.state={resourceAreaWidth:i.options.resourceAreaWidth,spreadsheetColWidths:[]},r}return u(i,n),i.prototype.render=function(){var i=this,o=this,n=o.props,l=o.state,r=o.context,f=r.options,v=r.viewSpec,u=this.processColOptions(r.options),y=u.superHeaderRendering,p=u.groupSpecs,w=u.orderSpecs,b=u.isVGrouping,s=u.colSpecs,e=this.buildTimelineDateProfile(n.dateProfile,r.dateEnv,f,r.dateProfileGenerator),h=this.rowNodes=this.buildRowNodes(n.resourceStore,p,w,b,n.resourceEntityExpansions,f.resourcesInitiallyExpanded),k=["fc-resource-timeline",this.hasNesting(h)?"":"fc-resource-timeline-flat","fc-timeline",f.eventOverlap===!1?"fc-timeline-overlap-disabled":"fc-timeline-overlap-enabled",],a=f.slotMinWidth,d=up(e,a||this.computeFallbackSlotMinWidth(e));return t(bt,{viewSpec:v},function(u,f){return t("div",{ref:u,className:k.concat(f).join(" ")},t(gti,{ref:i.layoutRef,forPrint:n.forPrint,isHeightAuto:n.isHeightAuto,spreadsheetCols:tii(s,l.spreadsheetColWidths,""),spreadsheetHeaderRows:function(n){return t(ati,{superHeaderRendering:y,colSpecs:s,onColWidthChange:i.handleColWidthChange,rowInnerHeights:n.rowSyncHeights})},spreadsheetBodyRows:function(n){return t(c,null,i.renderSpreadsheetRows(h,s,n.rowSyncHeights))},timeCols:d,timeHeaderContent:function(r){return t(gy,{clientWidth:r.clientWidth,clientHeight:r.clientHeight,tableMinWidth:r.tableMinWidth,tableColGroupNode:r.tableColGroupNode,dateProfile:n.dateProfile,tDateProfile:e,slatCoords:l.slatCoords,rowInnerHeights:r.rowSyncHeights,onMaxCushionWidth:a?null:i.handleMaxCushionWidth})},timeBodyContent:function(u){return t(gut,{dateProfile:n.dateProfile,clientWidth:u.clientWidth,clientHeight:u.clientHeight,tableMinWidth:u.tableMinWidth,tableColGroupNode:u.tableColGroupNode,expandRows:u.expandRows,tDateProfile:e,rowNodes:h,businessHours:n.businessHours,dateSelection:n.dateSelection,eventStore:n.eventStore,eventUiBases:n.eventUiBases,eventSelection:n.eventSelection,eventDrag:n.eventDrag,eventResize:n.eventResize,resourceStore:n.resourceStore,nextDayThreshold:r.options.nextDayThreshold,rowInnerHeights:u.rowSyncHeights,onSlatCoords:i.handleSlatCoords,onRowCoords:i.handleRowCoords,onScrollLeftRequest:i.handleScrollLeftRequest,onRowHeightChange:u.reportRowHeightChange})}}))})},i.prototype.renderSpreadsheetRows=function(n,i,r){return n.map(function(n,u){return n.group?t(gp,{key:n.id,id:n.id,spreadsheetColCnt:i.length,isExpanded:n.isExpanded,group:n.group,innerHeight:r[u]||""}):n.resource?t(ah,{key:n.id,colSpecs:i,rowSpans:n.rowSpans,depth:n.depth,isExpanded:n.isExpanded,hasChildren:n.hasChildren,resource:n.resource,innerHeight:r[u]||""}):null})},i.prototype.componentDidMount=function(){this.renderedRowNodes=this.rowNodes;this.scrollResponder=this.context.createScrollResponder(this.handleScrollRequest)},i.prototype.getSnapshotBeforeUpdate=function(){return this.props.forPrint?{}:{resourceScroll:this.queryResourceScroll()}},i.prototype.componentDidUpdate=function(n,t,i){this.renderedRowNodes=this.rowNodes;this.scrollResponder.update(n.dateProfile!==this.props.dateProfile);i.resourceScroll&&this.handleScrollRequest(i.resourceScroll)},i.prototype.componentWillUnmount=function(){this.scrollResponder.detach()},i.prototype.computeFallbackSlotMinWidth=function(n){return Math.max(30,(this.state.slotCushionMaxWidth||0)/n.slotsPerLabel)},i.prototype.queryResourceScroll=function(){var r=this,u=r.rowCoords,o=r.renderedRowNodes,n,e,i;if(u){var s=this.layoutRef.current,f=u.bottoms,h=s.getResourceScroll(),t={};for(n=0;n0){t.rowId=e.id;t.fromBottom=i;break}return t}return null},i}(e);return nw.addStateEquality({spreadsheetColWidths:ht}),tft=k({deps:[ar,lh,fp,],initialView:"resourceTimelineDay",views:{resourceTimeline:{type:"timeline",component:nw,needsResourceData:!0,resourceAreaWidth:"30%",resourcesInitiallyExpanded:!0,eventResizableFromStart:!0},resourceTimelineDay:{type:"resourceTimeline",duration:{days:1}},resourceTimelineWeek:{type:"resourceTimeline",duration:{weeks:1}},resourceTimelineMonth:{type:"resourceTimeline",duration:{months:1}},resourceTimelineYear:{type:"resourceTimeline",duration:{years:1}}}}),wo.push(wyt,dtt,sit,vit,nbt,lbt,urt,lkt,fp,lh,uti,yut,tft),n.AbstractResourceDayTableModel=lp,n.BASE_OPTION_DEFAULTS=ri,n.BASE_OPTION_REFINERS=fl,n.BaseComponent=e,n.BgEvent=kf,n.BootstrapTheme=kt,n.Calendar=itt,n.CalendarApi=pi,n.CalendarContent=yn,n.CalendarDataManager=bo,n.CalendarDataProvider=cn,n.CalendarRoot=ka,n.Component=ao,n.ContentHook=tu,n.CustomContentRenderContext=vo,n.DEFAULT_RESOURCE_ORDER=te,n.DateComponent=rt,n.DateEnv=pl,n.DateProfileGenerator=yo,n.DayCellContent=os,n.DayCellRoot=bf,n.DayGridView=ktt,n.DayHeader=ts,n.DayResourceTableModel=vp,n.DaySeriesModel=iv,n.DayTable=ey,n.DayTableModel=rv,n.DayTableSlicer=fy,n.DayTimeCols=ly,n.DayTimeColsSlicer=ks,n.DayTimeColsView=py,n.DelayedRunner=or,n.Draggable=vyt,n.ElementDragging=ba,n.ElementScrollController=og,n.Emitter=fr,n.EventApi=v,n.EventRoot=ru,n.EventSourceApi=hi,n.FeaturefulElementDragging=lr,n.Fragment=c,n.Interaction=di,n.ListView=by,n.MoreLinkRoot=cs,n.MountHook=bi,n.NamedTimeZoneImpl=ln,n.NowIndicatorRoot=cr,n.NowTimer=at,n.PointerDragging=as,n.PositionCache=fi,n.RefMap=nt,n.RenderHook=b,n.ResourceApi=ft,n.ResourceDayHeader=hh,n.ResourceDayTable=dp,n.ResourceDayTableModel=ap,n.ResourceDayTableView=lut,n.ResourceDayTimeCols=aut,n.ResourceDayTimeColsView=vut,n.ResourceLabelRoot=eut,n.ResourceSplitter=oh,n.ResourceTimelineLane=dut,n.ResourceTimelineView=nw,n.ScrollController=lo,n.ScrollGrid=ne,n.ScrollResponder=ag,n.Scroller=fs,n.SegHierarchy=af,n.SimpleScrollGrid=pf,n.Slicer=is,n.Splitter=sf,n.SpreadsheetRow=ah,n.StandardEvent=wf,n.Table=ws,n.TableDateCell=nv,n.TableDowCell=tv,n.TableView=ny,n.Theme=er,n.ThirdPartyDraggable=pyt,n.TimeCols=bs,n.TimeColsSlatsCoords=nit,n.TimeColsView=sy,n.TimelineCoords=art,n.TimelineHeader=gy,n.TimelineHeaderRows=lrt,n.TimelineLane=fh,n.TimelineLaneBg=tp,n.TimelineLaneSlicer=ip,n.TimelineSlats=np,n.TimelineView=rp,n.VResourceJoiner=yp,n.VResourceSplitter=pp,n.ViewApi=vl,n.ViewContextType=lt,n.ViewRoot=bt,n.WeekNumberRoot=hs,n.WindowScrollController=sg,n.addDays=p,n.addDurations=ve,n.addMs=gt,n.addWeeks=pc,n.allowContextMenu=ab,n.allowSelection=cb,n.applyMutationToEventStore=eo,n.applyStyle=ci,n.applyStyleProp=sc,n.asCleanDays=tl,n.asRoughMinutes=rk,n.asRoughMs=tt,n.asRoughSeconds=uk,n.binarySearch=wa,n.buildClassNameNormalizer=iu,n.buildDayRanges=ay,n.buildDayTableModel=oy,n.buildEntryKey=ki,n.buildEventApis=wi,n.buildEventRangeKey=uo,n.buildHashFromArray=aet,n.buildIsoString=wu,n.buildNavLinkData=ur,n.buildResourceFields=kp,n.buildRowNodes=bp,n.buildSegCompareObj=id,n.buildSegTimeText=gr,n.buildSlatCols=up,n.buildSlatMetas=yy,n.buildTimeColsModel=wy,n.buildTimelineDateProfile=ky,n.collectFromHash=gc,n.combineEventUis=no,n.compareByFieldSpec=vb,n.compareByFieldSpecs=ac,n.compareNumbers=yb,n.compareObjs=ae,n.computeEarliestSegStart=df,n.computeEdges=ua,n.computeFallbackHeaderFormat=da,n.computeHeightAndMargins=uht,n.computeInnerRect=fa,n.computeRect=co,n.computeSegDraggable=rd,n.computeSegEndResizable=fd,n.computeSegStartResizable=ud,n.computeShrinkWidth=ov,n.computeSmallestCellWidth=pb,n.computeVisibleDayRange=tf,n.config=ot,n.constrainPoint=rg,n.coordToCss=rh,n.coordsToCss=uh,n.createContext=sa,n.createDuration=s,n.createElement=t,n.createEmptyEventStore=it,n.createEventInstance=yu,n.createEventUi=dr,n.createFormatter=y,n.createPlugin=k,n.createPortal=cg,n.createRef=h,n.diffDates=tr,n.diffDayAndTime=bb,n.diffDays=ni,n.diffPoints=fg,n.diffWeeks=wb,n.diffWholeDays=yr,n.diffWholeWeeks=kb,n.disableCursor=au,n.elementClosest=d,n.elementMatches=he,n.enableCursor=vu,n.eventTupleToStore=kr,n.filterEventStoreDefs=ku,n.filterHash=pt,n.findDirectChildren=fb,n.findElements=dt,n.flattenResources=wp,n.flexibleCompare=vc,n.flushToDom=cf,n.formatDate=bst,n.formatDayString=br,n.formatIsoTimeString=fk,n.formatRange=kst,n.getAllowYScrolling=sv,n.getCanVGrowWithinCell=oo,n.getClippingParents=ea,n.getDateMeta=nu,n.getDayClassNames=rr,n.getDefaultEventEnd=fo,n.getElSeg=ir,n.getEntrySpanEnd=va,n.getEventClassNames=ed,n.getIsRtlScrollbarOnLeft=hf,n.getPublicId=cp,n.getRectCenter=ug,n.getRelevantEvents=ge,n.getScrollGridClassNames=yv,n.getScrollbarWidths=ra,n.getSectionClassNames=pv,n.getSectionHasLiquidHeight=es,n.getSegMeta=st,n.getSlotClassNames=ta,n.getStickyFooterScrollbar=yf,n.getStickyHeaderDates=hr,n.getUnequalProps=dc,n.globalLocales=kd,n.globalPlugins=wo,n.greatestDurationDenominator=ii,n.groupIntersectingEntries=ya,n.guid=vt,n.hasBgRendering=nd,n.hasShrinkWidth=vv,n.identity=r,n.interactionSettingsStore=vf,n.interactionSettingsToStore=go,n.intersectRanges=ui,n.intersectRects=dl,n.intersectSpans=ko,n.isArraysEqual=ht,n.isColPropsEqual=cv,n.isDateSelectionValid=bn,n.isDateSpansEqual=sd,n.isGroupsEqual=cut,n.isInt=li,n.isInteractionValid=rs,n.isMultiDayRange=dk,n.isPropsEqual=ut,n.isPropsValid=fv,n.isValidDate=le,n.joinSpans=an,n.listenBySelector=hc,n.mapHash=w,n.memoize=f,n.memoizeArraylike=ye,n.memoizeHashlike=ul,n.memoizeObjArg=yi,n.mergeEventStores=bu,n.multiplyDuration=il,n.padStart=yt,n.parseBusinessHours=kl,n.parseClassNames=du,n.parseDragMeta=ns,n.parseEventDef=nf,n.parseFieldSpecs=ce,n.parseMarker=bd,n.pointInsideRect=ig,n.preventContextMenu=lb,n.preventDefault=lu,n.preventSelection=hb,n.rangeContainsMarker=wt,n.rangeContainsRange=uf,n.rangesEqual=hl,n.rangesIntersect=rf,n.refineEventDef=io,n.refineProps=nr,n.removeElement=vr,n.removeExact=ek,n.render=hg,n.renderChunkContent=hv,n.renderFill=ss,n.renderMicroColGroup=lv,n.renderScrollShim=sr,n.requestJson=po,n.sanitizeShrinkWidth=av,n.setElSeg=cl,n.setRef=g,n.setScrollFromLeftEdge=bit,n.sliceEventStore=ff,n.sliceEvents=sat,n.sortEventSegs=ef,n.startOfDay=a,n.translateRect=gl,n.triggerDateSelect=ll,n.unmountComponentAtNode=lg,n.unpromisify=oa,n.version=ttt,n.whenTransitionDone=sb,n.wholeDivideDurations=ti,Object.defineProperty(n,"__esModule",{value:!0}),n}({}); \ No newline at end of file diff --git a/app/assets/stylesheets/property_hire_calendar.scss b/app/assets/stylesheets/property_hire_calendar.scss index 1371da9..a4c85bf 100644 --- a/app/assets/stylesheets/property_hire_calendar.scss +++ b/app/assets/stylesheets/property_hire_calendar.scss @@ -1,3 +1,11 @@ +#calendar.active_picker .fc-scrollgrid-sync-inner,#calendar.active_picker .fc-timegrid-slot{ + cursor: pointer; +} +#calendar.active_picker{ + .fc-scrollgrid-sync-inner:hover, .fc-timegrid-slot:hover{ + background: var(--fc-highlight-color, rgba(188, 232, 241, 0.3)); + } +} /* orbit calendar */ #orbit_calendar { transition: all 0.3s ease; @@ -96,7 +104,9 @@ & > * { margin: 0 5px; } - + & > select { + height: 3em; + } @media screen and (max-width: 479px) { margin-right: 0; @@ -253,6 +263,9 @@ .event_list td { padding: 0; } + .event_list th { + width: 25%; + } } .event_holder { @@ -627,8 +640,9 @@ } #calendar-loading { - position: absolute; - top: 40%; + position: fixed; + top: 50%; + left: 50%; z-index: 10; width: 120px; height: 120px; @@ -641,6 +655,7 @@ background-position: center 20px; background-size: 50%; box-shadow: 0 0 25px 0 rgba(0, 0, 0, 0.2); + transform: translate(-50%, -50%); &:after { content: "Loading..."; @@ -691,7 +706,7 @@ .calendar-modal { position: fixed; - z-index: 1050; + z-index: 10000; width: 300px; margin: 0; font-size: 12px; diff --git a/app/assets/stylesheets/property_hire_fullcalendar.css b/app/assets/stylesheets/property_hire_fullcalendar.css index c9add0b..a0416d0 100644 --- a/app/assets/stylesheets/property_hire_fullcalendar.css +++ b/app/assets/stylesheets/property_hire_fullcalendar.css @@ -1,579 +1,1811 @@ -/*! - * FullCalendar v1.6.1 Stylesheet - * Docs & License: http://arshaw.com/fullcalendar/ - * (c) 2013 Adam Shaw - */ +/* classes attached to */ +.table-bordered th, .table-bordered td { + border: 1px solid #dee2e6; +} +.fc-not-allowed, +.fc-not-allowed .fc-event { /* override events' custom cursors */ + cursor: not-allowed; +} + +.fc-unselectable { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-touch-callout: none; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +.fc { + /* layout of immediate children */ + display: flex; + flex-direction: column; + + font-size: 1em +} +.fc, + .fc *, + .fc *:before, + .fc *:after { + box-sizing: border-box; + } +.fc table { + border-collapse: collapse; + border-spacing: 0; + font-size: 1em; /* normalize cross-browser */ + } +.fc th { + text-align: center; + } +.fc th, + .fc td { + vertical-align: top; + padding: 0; + } +.fc a[data-navlink] { + cursor: pointer; + } +.fc a[data-navlink]:hover { + text-decoration: underline; + } +.fc-direction-ltr { + direction: ltr; + text-align: left; +} +.fc-direction-rtl { + direction: rtl; + text-align: right; +} +.fc-theme-standard td, + .fc-theme-standard th { + border: 1px solid #ddd; + border: 1px solid var(--fc-border-color, #ddd); + } +/* for FF, which doesn't expand a 100% div within a table cell. use absolute positioning */ +/* inner-wrappers are responsible for being absolute */ +/* TODO: best place for this? */ +.fc-liquid-hack td, + .fc-liquid-hack th { + position: relative; + } + +@font-face { + font-family: 'fcicons'; + src: url("data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SBfAAAAC8AAAAYGNtYXAXVtKNAAABHAAAAFRnYXNwAAAAEAAAAXAAAAAIZ2x5ZgYydxIAAAF4AAAFNGhlYWQUJ7cIAAAGrAAAADZoaGVhB20DzAAABuQAAAAkaG10eCIABhQAAAcIAAAALGxvY2ED4AU6AAAHNAAAABhtYXhwAA8AjAAAB0wAAAAgbmFtZXsr690AAAdsAAABhnBvc3QAAwAAAAAI9AAAACAAAwPAAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADpBgPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAADAAAAAwAAABwAAQADAAAAHAADAAEAAAAcAAQAOAAAAAoACAACAAIAAQAg6Qb//f//AAAAAAAg6QD//f//AAH/4xcEAAMAAQAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAABAWIAjQKeAskAEwAAJSc3NjQnJiIHAQYUFwEWMjc2NCcCnuLiDQ0MJAz/AA0NAQAMJAwNDcni4gwjDQwM/wANIwz/AA0NDCMNAAAAAQFiAI0CngLJABMAACUBNjQnASYiBwYUHwEHBhQXFjI3AZ4BAA0N/wAMJAwNDeLiDQ0MJAyNAQAMIw0BAAwMDSMM4uINIwwNDQAAAAIA4gC3Ax4CngATACcAACUnNzY0JyYiDwEGFB8BFjI3NjQnISc3NjQnJiIPAQYUHwEWMjc2NCcB87e3DQ0MIw3VDQ3VDSMMDQ0BK7e3DQ0MJAzVDQ3VDCQMDQ3zuLcMJAwNDdUNIwzWDAwNIwy4twwkDA0N1Q0jDNYMDA0jDAAAAgDiALcDHgKeABMAJwAAJTc2NC8BJiIHBhQfAQcGFBcWMjchNzY0LwEmIgcGFB8BBwYUFxYyNwJJ1Q0N1Q0jDA0Nt7cNDQwjDf7V1Q0N1QwkDA0Nt7cNDQwkDLfWDCMN1Q0NDCQMt7gMIw0MDNYMIw3VDQ0MJAy3uAwjDQwMAAADAFUAAAOrA1UAMwBoAHcAABMiBgcOAQcOAQcOARURFBYXHgEXHgEXHgEzITI2Nz4BNz4BNz4BNRE0JicuAScuAScuASMFITIWFx4BFx4BFx4BFREUBgcOAQcOAQcOASMhIiYnLgEnLgEnLgE1ETQ2Nz4BNz4BNz4BMxMhMjY1NCYjISIGFRQWM9UNGAwLFQkJDgUFBQUFBQ4JCRULDBgNAlYNGAwLFQkJDgUFBQUFBQ4JCRULDBgN/aoCVgQIBAQHAwMFAQIBAQIBBQMDBwQECAT9qgQIBAQHAwMFAQIBAQIBBQMDBwQECASAAVYRGRkR/qoRGRkRA1UFBAUOCQkVDAsZDf2rDRkLDBUJCA4FBQUFBQUOCQgVDAsZDQJVDRkLDBUJCQ4FBAVVAgECBQMCBwQECAX9qwQJAwQHAwMFAQICAgIBBQMDBwQDCQQCVQUIBAQHAgMFAgEC/oAZEhEZGRESGQAAAAADAFUAAAOrA1UAMwBoAIkAABMiBgcOAQcOAQcOARURFBYXHgEXHgEXHgEzITI2Nz4BNz4BNz4BNRE0JicuAScuAScuASMFITIWFx4BFx4BFx4BFREUBgcOAQcOAQcOASMhIiYnLgEnLgEnLgE1ETQ2Nz4BNz4BNz4BMxMzFRQWMzI2PQEzMjY1NCYrATU0JiMiBh0BIyIGFRQWM9UNGAwLFQkJDgUFBQUFBQ4JCRULDBgNAlYNGAwLFQkJDgUFBQUFBQ4JCRULDBgN/aoCVgQIBAQHAwMFAQIBAQIBBQMDBwQECAT9qgQIBAQHAwMFAQIBAQIBBQMDBwQECASAgBkSEhmAERkZEYAZEhIZgBEZGREDVQUEBQ4JCRUMCxkN/asNGQsMFQkIDgUFBQUFBQ4JCBUMCxkNAlUNGQsMFQkJDgUEBVUCAQIFAwIHBAQIBf2rBAkDBAcDAwUBAgICAgEFAwMHBAMJBAJVBQgEBAcCAwUCAQL+gIASGRkSgBkSERmAEhkZEoAZERIZAAABAOIAjQMeAskAIAAAExcHBhQXFjI/ARcWMjc2NC8BNzY0JyYiDwEnJiIHBhQX4uLiDQ0MJAzi4gwkDA0N4uINDQwkDOLiDCQMDQ0CjeLiDSMMDQ3h4Q0NDCMN4uIMIw0MDOLiDAwNIwwAAAABAAAAAQAAa5n0y18PPPUACwQAAAAAANivOVsAAAAA2K85WwAAAAADqwNVAAAACAACAAAAAAAAAAEAAAPA/8AAAAQAAAAAAAOrAAEAAAAAAAAAAAAAAAAAAAALBAAAAAAAAAAAAAAAAgAAAAQAAWIEAAFiBAAA4gQAAOIEAABVBAAAVQQAAOIAAAAAAAoAFAAeAEQAagCqAOoBngJkApoAAQAAAAsAigADAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABAAcAAAABAAAAAAACAAcAYAABAAAAAAADAAcANgABAAAAAAAEAAcAdQABAAAAAAAFAAsAFQABAAAAAAAGAAcASwABAAAAAAAKABoAigADAAEECQABAA4ABwADAAEECQACAA4AZwADAAEECQADAA4APQADAAEECQAEAA4AfAADAAEECQAFABYAIAADAAEECQAGAA4AUgADAAEECQAKADQApGZjaWNvbnMAZgBjAGkAYwBvAG4Ac1ZlcnNpb24gMS4wAFYAZQByAHMAaQBvAG4AIAAxAC4AMGZjaWNvbnMAZgBjAGkAYwBvAG4Ac2ZjaWNvbnMAZgBjAGkAYwBvAG4Ac1JlZ3VsYXIAUgBlAGcAdQBsAGEAcmZjaWNvbnMAZgBjAGkAYwBvAG4Ac0ZvbnQgZ2VuZXJhdGVkIGJ5IEljb01vb24uAEYAbwBuAHQAIABnAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4ALgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") format('truetype'); + font-weight: normal; + font-style: normal; +} + +.fc-icon { + /* added for fc */ + display: inline-block; + width: 1em; + height: 1em; + text-align: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'fcicons' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.fc-icon-chevron-left:before { + content: "\e900"; +} + +.fc-icon-chevron-right:before { + content: "\e901"; +} + +.fc-icon-chevrons-left:before { + content: "\e902"; +} + +.fc-icon-chevrons-right:before { + content: "\e903"; +} + +.fc-icon-minus-square:before { + content: "\e904"; +} + +.fc-icon-plus-square:before { + content: "\e905"; +} + +.fc-icon-x:before { + content: "\e906"; +} +/* +Lots taken from Flatly (MIT): https://bootswatch.com/4/flatly/bootstrap.css + +These styles only apply when the standard-theme is activated. +When it's NOT activated, the fc-button classes won't even be in the DOM. +*/ +.fc { + + /* reset */ + +} +.fc .fc-button { + border-radius: 0; + overflow: visible; + text-transform: none; + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; + } +.fc .fc-button:focus { + outline: 1px dotted; + outline: 5px auto -webkit-focus-ring-color; + } +.fc .fc-button { + -webkit-appearance: button; + } +.fc .fc-button:not(:disabled) { + cursor: pointer; + } +.fc .fc-button::-moz-focus-inner { + padding: 0; + border-style: none; + } +.fc { + + /* theme */ + +} +.fc .fc-button { + display: inline-block; + font-weight: 400; + text-align: center; + vertical-align: middle; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: transparent; + border: 1px solid transparent; + padding: 0.4em 0.65em; + font-size: 1em; + line-height: 1.5; + border-radius: 0.25em; + } +.fc .fc-button:hover { + text-decoration: none; + } +.fc .fc-button:focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(44, 62, 80, 0.25); + } +.fc .fc-button:disabled { + opacity: 0.65; + } +.fc { + + /* "primary" coloring */ + +} +.fc .fc-button-primary { + color: #fff; + color: var(--fc-button-text-color, #fff); + background-color: #2C3E50; + background-color: var(--fc-button-bg-color, #2C3E50); + border-color: #2C3E50; + border-color: var(--fc-button-border-color, #2C3E50); + } +.fc .fc-button-primary:hover { + color: #fff; + color: var(--fc-button-text-color, #fff); + background-color: #1e2b37; + background-color: var(--fc-button-hover-bg-color, #1e2b37); + border-color: #1a252f; + border-color: var(--fc-button-hover-border-color, #1a252f); + } +.fc .fc-button-primary:disabled { /* not DRY */ + color: #fff; + color: var(--fc-button-text-color, #fff); + background-color: #2C3E50; + background-color: var(--fc-button-bg-color, #2C3E50); + border-color: #2C3E50; + border-color: var(--fc-button-border-color, #2C3E50); /* overrides :hover */ + } +.fc .fc-button-primary:focus { + box-shadow: 0 0 0 0.2rem rgba(76, 91, 106, 0.5); + } +.fc .fc-button-primary:not(:disabled):active, + .fc .fc-button-primary:not(:disabled).fc-button-active { + color: #fff; + color: var(--fc-button-text-color, #fff); + background-color: #1a252f; + background-color: var(--fc-button-active-bg-color, #1a252f); + border-color: #151e27; + border-color: var(--fc-button-active-border-color, #151e27); + } +.fc .fc-button-primary:not(:disabled):active:focus, + .fc .fc-button-primary:not(:disabled).fc-button-active:focus { + box-shadow: 0 0 0 0.2rem rgba(76, 91, 106, 0.5); + } +.fc { + + /* icons within buttons */ + +} +.fc .fc-button .fc-icon { + vertical-align: middle; + font-size: 1.5em; /* bump up the size (but don't make it bigger than line-height of button, which is 1.5em also) */ + } +.fc .fc-button-group { + position: relative; + display: inline-flex; + vertical-align: middle; + } +.fc .fc-button-group > .fc-button { + position: relative; + flex: 1 1 auto; + } +.fc .fc-button-group > .fc-button:hover { + z-index: 1; + } +.fc .fc-button-group > .fc-button:focus, + .fc .fc-button-group > .fc-button:active, + .fc .fc-button-group > .fc-button.fc-button-active { + z-index: 1; + } +.fc-direction-ltr .fc-button-group > .fc-button:not(:first-child) { + margin-left: -1px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } +.fc-direction-ltr .fc-button-group > .fc-button:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } +.fc-direction-rtl .fc-button-group > .fc-button:not(:first-child) { + margin-right: -1px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } +.fc-direction-rtl .fc-button-group > .fc-button:not(:last-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } +.fc .fc-toolbar { + display: flex; + justify-content: space-between; + align-items: center; + } +.fc .fc-toolbar.fc-header-toolbar { + margin-bottom: 1.5em; + } +.fc .fc-toolbar.fc-footer-toolbar { + margin-top: 1.5em; + } +.fc .fc-toolbar-title { + font-size: 1.75em; + margin: 0; + } +.fc-direction-ltr .fc-toolbar > * > :not(:first-child) { + margin-left: .75em; /* space between */ + } +.fc-direction-rtl .fc-toolbar > * > :not(:first-child) { + margin-right: .75em; /* space between */ + } +.fc-direction-rtl .fc-toolbar-ltr { /* when the toolbar-chunk positioning system is explicitly left-to-right */ + flex-direction: row-reverse; + } +.fc .fc-scroller { + -webkit-overflow-scrolling: touch; + position: relative; /* for abs-positioned elements within */ + } +.fc .fc-scroller-liquid { + height: 100%; + } +.fc .fc-scroller-liquid-absolute { + position: absolute; + top: 0; + right: 0; + left: 0; + bottom: 0; + } +.fc .fc-scroller-harness { + position: relative; + overflow: hidden; + direction: ltr; + /* hack for chrome computing the scroller's right/left wrong for rtl. undone below... */ + /* TODO: demonstrate in codepen */ + } +.fc .fc-scroller-harness-liquid { + height: 100%; + } +.fc-direction-rtl .fc-scroller-harness > .fc-scroller { /* undo above hack */ + direction: rtl; + } +.fc-theme-standard .fc-scrollgrid { + border: 1px solid #ddd; + border: 1px solid var(--fc-border-color, #ddd); /* bootstrap does this. match */ + } +.fc .fc-scrollgrid, + .fc .fc-scrollgrid table { /* all tables (self included) */ + width: 100%; /* because tables don't normally do this */ + table-layout: fixed; + } +.fc .fc-scrollgrid table { /* inner tables */ + border-top-style: hidden; + border-left-style: hidden; + border-right-style: hidden; + } +.fc .fc-scrollgrid { + + border-collapse: separate; + border-right-width: 0; + border-bottom-width: 0; + + } +.fc .fc-scrollgrid-liquid { + height: 100%; + } +.fc .fc-scrollgrid-section { /* a
*/ + } +.fc-daygrid-event { /* make root-level, because will be dragged-and-dropped outside of a component root */ + position: relative; /* for z-indexes assigned later */ + white-space: normal; + border-radius: 3px; /* dot event needs this to when selected */ + font-size: .85em; + font-size: var(--fc-small-font-size, .85em); +} +/* --- the rectangle ("block") style of event --- */ +.fc-daygrid-block-event .fc-event-time { + font-weight: bold; + } +.fc-daygrid-block-event .fc-event-time, + .fc-daygrid-block-event .fc-event-title { + padding: 1px; + } +/* --- the dot style of event --- */ +.fc-daygrid-dot-event { + display: flex; + align-items: center; + padding: 2px 0 + +} +.fc-daygrid-dot-event .fc-event-title { + flex-grow: 1; + flex-shrink: 1; + min-width: 0; /* important for allowing to shrink all the way */ + overflow: hidden; + font-weight: bold; + } +.fc-daygrid-dot-event:hover, + .fc-daygrid-dot-event.fc-event-mirror { + background: rgba(0, 0, 0, 0.1); + } +.fc-daygrid-dot-event.fc-event-selected:before { + /* expand hit area */ + top: -10px; + bottom: -10px; + } +.fc-daygrid-event-dot { /* the actual dot */ + margin: 0 4px; + box-sizing: content-box; + width: 0; + height: 0; + border: 4px solid #3788d8; + border: calc(var(--fc-daygrid-event-dot-width, 8px) / 2) solid var(--fc-event-border-color, #3788d8); + border-radius: 4px; + border-radius: calc(var(--fc-daygrid-event-dot-width, 8px) / 2); +} +/* --- spacing between time and title --- */ +.fc-direction-ltr .fc-daygrid-event .fc-event-time { + margin-right: 3px; + } +.fc-direction-rtl .fc-daygrid-event .fc-event-time { + margin-left: 3px; + } + + +/* +A VERTICAL event +*/ + +.fc-v-event { /* allowed to be top-level */ + display: block; + border: 1px solid #3788d8; + border: 1px solid var(--fc-event-border-color, #3788d8); + background-color: #3788d8; + background-color: var(--fc-event-bg-color, #3788d8) + +} + +.fc-v-event .fc-event-main { + color: #fff; + color: var(--fc-event-text-color, #fff); + height: 100%; + } + +.fc-v-event .fc-event-main-frame { + height: 100%; + display: flex; + flex-direction: column; + } + +.fc-v-event .fc-event-time { + flex-grow: 0; + flex-shrink: 0; + max-height: 100%; + overflow: hidden; + } + +.fc-v-event .fc-event-title-container { /* a container for the sticky cushion */ + flex-grow: 1; + flex-shrink: 1; + min-height: 0; /* important for allowing to shrink all the way */ + } + +.fc-v-event .fc-event-title { /* will have fc-sticky on it */ + top: 0; + bottom: 0; + max-height: 100%; /* clip overflow */ + overflow: hidden; + } + +.fc-v-event:not(.fc-event-start) { + border-top-width: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; + } + +.fc-v-event:not(.fc-event-end) { + border-bottom-width: 0; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + } + +.fc-v-event.fc-event-selected:before { + /* expand hit area */ + left: -10px; + right: -10px; + } + +.fc-v-event { + + /* resizer (mouse AND touch) */ + +} + +.fc-v-event .fc-event-resizer-start { + cursor: n-resize; + } + +.fc-v-event .fc-event-resizer-end { + cursor: s-resize; + } + +.fc-v-event { + + /* resizer for MOUSE */ + +} + +.fc-v-event:not(.fc-event-selected) .fc-event-resizer { + height: 8px; + height: var(--fc-event-resizer-thickness, 8px); + left: 0; + right: 0; + } + +.fc-v-event:not(.fc-event-selected) .fc-event-resizer-start { + top: -4px; + top: calc(var(--fc-event-resizer-thickness, 8px) / -2); + } + +.fc-v-event:not(.fc-event-selected) .fc-event-resizer-end { + bottom: -4px; + bottom: calc(var(--fc-event-resizer-thickness, 8px) / -2); + } + +.fc-v-event { + + /* resizer for TOUCH (when event is "selected") */ + +} + +.fc-v-event.fc-event-selected .fc-event-resizer { + left: 50%; + margin-left: -4px; + margin-left: calc(var(--fc-event-resizer-dot-total-width, 8px) / -2); + } + +.fc-v-event.fc-event-selected .fc-event-resizer-start { + top: -4px; + top: calc(var(--fc-event-resizer-dot-total-width, 8px) / -2); + } + +.fc-v-event.fc-event-selected .fc-event-resizer-end { + bottom: -4px; + bottom: calc(var(--fc-event-resizer-dot-total-width, 8px) / -2); + } +.fc .fc-timegrid .fc-daygrid-body { /* the all-day daygrid within the timegrid view */ + z-index: 2; /* put above the timegrid-body so that more-popover is above everything. TODO: better solution */ + } +.fc .fc-timegrid-divider { + padding: 0 0 2px; /* browsers get confused when you set height. use padding instead */ + } +.fc .fc-timegrid-body { + position: relative; + z-index: 1; /* scope the z-indexes of slots and cols */ + min-height: 100%; /* fill height always, even when slat table doesn't grow */ + } +.fc .fc-timegrid-axis-chunk { /* for advanced ScrollGrid */ + position: relative /* offset parent for now-indicator-container */ + + } +.fc .fc-timegrid-axis-chunk > table { + position: relative; + z-index: 1; /* above the now-indicator-container */ + } +.fc .fc-timegrid-slots { + position: relative; + z-index: 1; + } +.fc .fc-timegrid-slot { /* a */ + height: 1.5em; + border-bottom: 0 /* each cell owns its top border */ + } +.fc .fc-timegrid-slot:empty:before { + content: '\00a0'; /* make sure there's at least an empty space to create height for height syncing */ + } +.fc .fc-timegrid-slot-minor { + border-top-style: dotted; + } +.fc .fc-timegrid-slot-label-cushion { + display: inline-block; + white-space: normal; + } +.fc .fc-timegrid-slot-label { + vertical-align: middle; /* vertical align the slots */ + } +.fc { + + + /* slots AND axis cells (top-left corner of view including the "all-day" text) */ + +} +.fc .fc-timegrid-axis-cushion, + .fc .fc-timegrid-slot-label-cushion { + padding: 0 4px; + } +.fc { + + + /* axis cells (top-left corner of view including the "all-day" text) */ + /* vertical align is more complicated, uses flexbox */ + +} +.fc .fc-timegrid-axis-frame-liquid { + height: 100%; /* will need liquid-hack in FF */ + } +.fc .fc-timegrid-axis-frame { + overflow: hidden; + display: flex; + align-items: center; /* vertical align */ + justify-content: flex-end; /* horizontal align. matches text-align below */ + } +.fc .fc-timegrid-axis-cushion { + max-width: 60px; /* limits the width of the "all-day" text */ + flex-shrink: 0; /* allows text to expand how it normally would, regardless of constrained width */ + } +.fc-direction-ltr .fc-timegrid-slot-label-frame { + text-align: right; + } +.fc-direction-rtl .fc-timegrid-slot-label-frame { + text-align: left; + } +.fc-liquid-hack .fc-timegrid-axis-frame-liquid { + height: auto; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + } +.fc .fc-timegrid-col.fc-day-today { + background-color: rgba(255, 220, 40, 0.15); + background-color: var(--fc-today-bg-color, rgba(255, 220, 40, 0.15)); + } +.fc .fc-timegrid-col-frame { + min-height: 100%; /* liquid-hack is below */ + position: relative; + } +.fc-liquid-hack .fc-timegrid-col-frame { + height: auto; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + } +.fc-media-screen .fc-timegrid-cols { + position: absolute; /* no z-index. children will decide and go above slots */ + top: 0; + left: 0; + right: 0; + bottom: 0 + } +.fc-media-screen .fc-timegrid-cols > table { + height: 100%; + } +.fc-media-screen .fc-timegrid-col-bg, + .fc-media-screen .fc-timegrid-col-events, + .fc-media-screen .fc-timegrid-now-indicator-container { + position: absolute; + top: 0; + left: 0; + right: 0; + } +.fc { + + /* bg */ + +} +.fc .fc-timegrid-col-bg { + z-index: 2; /* TODO: kill */ + } +.fc .fc-timegrid-col-bg .fc-non-business { z-index: 1 } +.fc .fc-timegrid-col-bg .fc-bg-event { z-index: 2 } +.fc .fc-timegrid-col-bg .fc-highlight { z-index: 3 } +.fc .fc-timegrid-bg-harness { + position: absolute; /* top/bottom will be set by JS */ + left: 0; + right: 0; + } +.fc { + + /* fg events */ + /* (the mirror segs are put into a separate container with same classname, */ + /* and they must be after the normal seg container to appear at a higher z-index) */ + +} +.fc .fc-timegrid-col-events { + z-index: 3; + /* child event segs have z-indexes that are scoped within this div */ + } +.fc { + + /* now indicator */ + +} +.fc .fc-timegrid-now-indicator-container { + bottom: 0; + overflow: hidden; /* don't let overflow of lines/arrows cause unnecessary scrolling */ + /* z-index is set on the individual elements */ + } +.fc-direction-ltr .fc-timegrid-col-events { + margin: 0 2.5% 0 2px; + } +.fc-direction-rtl .fc-timegrid-col-events { + margin: 0 2px 0 2.5%; + } +.fc-timegrid-event-harness { + position: absolute /* top/left/right/bottom will all be set by JS */ +} +.fc-timegrid-event-harness > .fc-timegrid-event { + position: absolute; /* absolute WITHIN the harness */ + top: 0; /* for when not yet positioned */ + bottom: 0; /* " */ + left: 0; + right: 0; + } +.fc-timegrid-event-harness-inset .fc-timegrid-event, +.fc-timegrid-event.fc-event-mirror, +.fc-timegrid-more-link { + box-shadow: 0px 0px 0px 1px #fff; + box-shadow: 0px 0px 0px 1px var(--fc-page-bg-color, #fff); +} +.fc-timegrid-event, +.fc-timegrid-more-link { /* events need to be root */ + font-size: .85em; + font-size: var(--fc-small-font-size, .85em); + border-radius: 3px; +} +.fc-timegrid-event { /* events need to be root */ + margin-bottom: 1px /* give some space from bottom */ +} +.fc-timegrid-event .fc-event-main { + padding: 1px 1px 0; + } +.fc-timegrid-event .fc-event-time { + white-space: normal; + font-size: .85em; + font-size: var(--fc-small-font-size, .85em); + margin-bottom: 1px; + } +.fc-timegrid-event-short .fc-event-main-frame { + flex-direction: row; + overflow: hidden; + } +.fc-timegrid-event-short .fc-event-time:after { + content: '\00a0-\00a0'; /* dash surrounded by non-breaking spaces */ + } +.fc-timegrid-event-short .fc-event-title { + font-size: .85em; + font-size: var(--fc-small-font-size, .85em) + } +.fc-timegrid-more-link { /* does NOT inherit from fc-timegrid-event */ + position: absolute; + z-index: 9999; /* hack */ + color: inherit; + color: var(--fc-more-link-text-color, inherit); + background: #d0d0d0; + background: var(--fc-more-link-bg-color, #d0d0d0); + cursor: pointer; + margin-bottom: 1px; /* match space below fc-timegrid-event */ +} +.fc-timegrid-more-link-inner { /* has fc-sticky */ + padding: 3px 2px; + top: 0; +} +.fc-direction-ltr .fc-timegrid-more-link { + right: 0; + } +.fc-direction-rtl .fc-timegrid-more-link { + left: 0; + } +.fc { + + /* line */ + +} +.fc .fc-timegrid-now-indicator-line { + position: absolute; + z-index: 4; + left: 0; + right: 0; + border-style: solid; + border-color: red; + border-color: var(--fc-now-indicator-color, red); + border-width: 1px 0 0; + } +.fc { + + /* arrow */ + +} +.fc .fc-timegrid-now-indicator-arrow { + position: absolute; + z-index: 4; + margin-top: -5px; /* vertically center on top coordinate */ + border-style: solid; + border-color: red; + border-color: var(--fc-now-indicator-color, red); + } +.fc-direction-ltr .fc-timegrid-now-indicator-arrow { + left: 0; + + /* triangle pointing right. TODO: mixin */ + border-width: 5px 0 5px 6px; + border-top-color: transparent; + border-bottom-color: transparent; + } +.fc-direction-rtl .fc-timegrid-now-indicator-arrow { + right: 0; + + /* triangle pointing left. TODO: mixin */ + border-width: 5px 6px 5px 0; + border-top-color: transparent; + border-bottom-color: transparent; + } + + +:root { + --fc-list-event-dot-width: 10px; + --fc-list-event-hover-bg-color: #f5f5f5; +} +.fc-theme-standard .fc-list { + border: 1px solid #ddd; + border: 1px solid var(--fc-border-color, #ddd); + } +.fc { + + /* message when no events */ + +} +.fc .fc-list-empty { + background-color: rgba(208, 208, 208, 0.3); + background-color: var(--fc-neutral-bg-color, rgba(208, 208, 208, 0.3)); + height: 100%; + display: flex; + justify-content: center; + align-items: center; /* vertically aligns fc-list-empty-inner */ + } +.fc .fc-list-empty-cushion { + margin: 5em 0; + } +.fc { + + /* table within the scroller */ + /* ---------------------------------------------------------------------------------------------------- */ + +} +.fc .fc-list-table { + width: 100%; + border-style: hidden; /* kill outer border on theme */ + } +.fc .fc-list-table tr > * { + border-left: 0; + border-right: 0; + } +.fc .fc-list-sticky .fc-list-day > * { /* the cells */ + position: sticky; + top: 0; + background: #fff; + background: var(--fc-page-bg-color, #fff); /* for when headers are styled to be transparent and sticky */ + } +.fc .fc-list-table th { + padding: 0; /* uses an inner-wrapper instead... */ + } +.fc .fc-list-table td, + .fc .fc-list-day-cushion { + padding: 8px 14px; + } +.fc { + + + /* date heading rows */ + /* ---------------------------------------------------------------------------------------------------- */ + +} +.fc .fc-list-day-cushion:after { + content: ""; + clear: both; + display: table; /* clear floating */ + } +.fc-theme-standard .fc-list-day-cushion { + background-color: rgba(208, 208, 208, 0.3); + background-color: var(--fc-neutral-bg-color, rgba(208, 208, 208, 0.3)); + } +.fc-direction-ltr .fc-list-day-text, +.fc-direction-rtl .fc-list-day-side-text { + float: left; +} +.fc-direction-ltr .fc-list-day-side-text, +.fc-direction-rtl .fc-list-day-text { + float: right; +} +/* make the dot closer to the event title */ +.fc-direction-ltr .fc-list-table .fc-list-event-graphic { padding-right: 0 } +.fc-direction-rtl .fc-list-table .fc-list-event-graphic { padding-left: 0 } +.fc .fc-list-event.fc-event-forced-url { + cursor: pointer; /* whole row will seem clickable */ + } +.fc .fc-list-event:hover td { + background-color: #f5f5f5; + background-color: var(--fc-list-event-hover-bg-color, #f5f5f5); + } +.fc { + + /* shrink certain cols */ + +} +.fc .fc-list-event-graphic, + .fc .fc-list-event-time { + white-space: normal; + width: 1px; + } +.fc .fc-list-event-dot { + display: inline-block; + box-sizing: content-box; + width: 0; + height: 0; + border: 5px solid #3788d8; + border: calc(var(--fc-list-event-dot-width, 10px) / 2) solid var(--fc-event-border-color, #3788d8); + border-radius: 5px; + border-radius: calc(var(--fc-list-event-dot-width, 10px) / 2); + } +.fc { + + /* reset styling */ + +} +.fc .fc-list-event-title a { + color: inherit; + text-decoration: none; + } +.fc { + + /* underline link when hovering over any part of row */ + +} +.fc .fc-list-event.fc-event-forced-url:hover a { + text-decoration: underline; + } + + + + .fc-theme-bootstrap a:not([href]) { + color: inherit; /* natural color for navlinks */ + } + + + + .fc .fc-event, + .fc .fc-scrollgrid table tr { + -moz-column-break-inside: avoid; + break-inside: avoid; + } + +.fc-media-print { + display: block; /* undo flexbox. FF doesn't know how to flow */ + max-width: 100% /* width will be hardcoded too */ +} + +.fc-media-print .fc-timegrid-slots, + .fc-media-print .fc-timegrid-axis-chunk, + .fc-media-print .fc-timeline-slots, + .fc-media-print .fc-non-business, + .fc-media-print .fc-bg-event { + display: none; + } + +.fc-media-print .fc-toolbar button, + .fc-media-print .fc-h-event, + .fc-media-print .fc-v-event { + color: #000 !important; + background: #fff !important; + } + +.fc-media-print .fc-event, + .fc-media-print .fc-event-main { /* often controls the text-color */ + color: #000 !important; + } + +.fc-media-print .fc-timegrid-event { + margin: 0.5em 0; + } + + + + .fc .fc-timeline-body { + min-height: 100%; + position: relative; + z-index: 1; /* scope slots, bg, etc */ + } +/* +vertical slots in both the header AND the body +*/ +.fc .fc-timeline-slots { + position: absolute; + z-index: 1; + top: 0; + bottom: 0 + } +.fc .fc-timeline-slots > table { + height: 100%; + } +.fc { + + /* border for both header AND body cells */ + +} +.fc .fc-timeline-slot-minor { + border-style: dotted; + } +.fc { + + /* header cells (aka "label") */ + +} +.fc .fc-timeline-slot-frame { + display: flex; + align-items: center; /* vertical align */ + justify-content: center; /* horizontal align */ + overflow: hidden; /* important so text doesn't bleed out and cause extra scroll */ + } +.fc .fc-timeline-header-row-chrono { /* a row of times */ + } +.fc .fc-timeline-header-row-chrono .fc-timeline-slot-frame { + justify-content: flex-start; /* horizontal align left or right */ + } +.fc .fc-timeline-slot-cushion { + padding: 4px 5px; /* TODO: unify with fc-col-header? */ + white-space: normal; + } +.fc { + + /* NOTE: how does the top row of cells get horizontally centered? */ + /* for the non-chrono-row, the fc-sticky system looks for text-align center, */ + /* and it's a fluke that the default browser stylesheet already does this for */ + /* TODO: have StickyScrolling look at natural left coord to detect centeredness. */ + +} +/* only owns one side, so can do dotted */ +.fc-direction-ltr .fc-timeline-slot { border-right: 0 !important } +.fc-direction-rtl .fc-timeline-slot { border-left: 0 !important } +.fc .fc-timeline-now-indicator-container { + position: absolute; + z-index: 4; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 0; + } +.fc .fc-timeline-now-indicator-arrow, + .fc .fc-timeline-now-indicator-line { + position: absolute; + top: 0; + border-style: solid; + border-color: red; + border-color: var(--fc-now-indicator-color, red); + } +.fc .fc-timeline-now-indicator-arrow { + margin: 0 -6px; /* 5, then one more to counteract scroller's negative margins */ + + /* triangle pointing down. TODO: mixin */ + border-width: 6px 5px 0 5px; + border-left-color: transparent; + border-right-color: transparent; + } +.fc .fc-timeline-now-indicator-line { + margin: 0 -1px; /* counteract scroller's negative margins */ + bottom: 0; + border-width: 0 0 0 1px; + } +.fc { + + /* container */ + +} +.fc .fc-timeline-events { + position: relative; + z-index: 3; + width: 0; /* for event positioning. will end up on correct side based on dir */ + } +.fc { + + /* harness */ + +} +.fc .fc-timeline-event-harness, + .fc .fc-timeline-more-link { + position: absolute; + top: 0; /* for when when top can't be computed yet */ + /* JS will set tht left/right */ + } +/* z-index, scoped within fc-timeline-events */ +.fc-timeline-event { z-index: 1 } +.fc-timeline-event.fc-event-mirror { z-index: 2 } +.fc-timeline-event { + position: relative; /* contains things. TODO: make part of fc-h-event and fc-v-event */ + display: flex; /* for v-aligning start/end arrows and making fc-event-main stretch all the way */ + align-items: center; + border-radius: 0; + padding: 2px 1px; + margin-bottom: 1px; + font-size: .85em; + font-size: var(--fc-small-font-size, .85em) + + /* time and title spacing */ + /* ---------------------------------------------------------------------------------------------------- */ +} +.fc-timeline-event .fc-event-main { + flex-grow: 1; + flex-shrink: 1; + min-width: 0; /* important for allowing to shrink all the way */ + } +.fc-timeline-event .fc-event-time { + font-weight: bold; + } +.fc-timeline-event .fc-event-time, + .fc-timeline-event .fc-event-title { + white-space: normal; + padding: 0 2px; + } +/* move 1px away from slot line */ +.fc-direction-ltr .fc-timeline-event.fc-event-end, + .fc-direction-ltr .fc-timeline-more-link { + margin-right: 1px; + } +.fc-direction-rtl .fc-timeline-event.fc-event-end, + .fc-direction-rtl .fc-timeline-more-link { + margin-left: 1px; + } +/* make event beefier when overlap not allowed */ +.fc-timeline-overlap-disabled .fc-timeline-event { + padding-top: 5px; + padding-bottom: 5px; + margin-bottom: 0; +} +/* arrows indicating the event continues into past/future */ +/* ---------------------------------------------------------------------------------------------------- */ +/* part of the flexbox flow */ +.fc-timeline-event:not(.fc-event-start):before, +.fc-timeline-event:not(.fc-event-end):after { + content: ""; + flex-grow: 0; + flex-shrink: 0; + opacity: .5; + + /* triangle. TODO: mixin */ + width: 0; + height: 0; + margin: 0 1px; + border: 5px solid #000; /* TODO: var */ + border-top-color: transparent; + border-bottom-color: transparent; +} +/* pointing left */ +.fc-direction-ltr .fc-timeline-event:not(.fc-event-start):before, +.fc-direction-rtl .fc-timeline-event:not(.fc-event-end):after { + border-left: 0; +} +/* pointing right */ +.fc-direction-ltr .fc-timeline-event:not(.fc-event-end):after, +.fc-direction-rtl .fc-timeline-event:not(.fc-event-start):before { + border-right: 0; +} +/* +more events indicator */ +/* ---------------------------------------------------------------------------------------------------- */ +.fc-timeline-more-link { + font-size: .85em; + font-size: var(--fc-small-font-size, .85em); + color: inherit; + color: var(--fc-more-link-text-color, inherit); + background: #d0d0d0; + background: var(--fc-more-link-bg-color, #d0d0d0); + padding: 1px; + cursor: pointer; +} +.fc-timeline-more-link-inner { /* has fc-sticky */ + display: inline-block; + left: 0; + right: 0; + padding: 2px; +} +.fc .fc-timeline-bg { /* a container for bg content */ + position: absolute; + z-index: 2; + top: 0; + bottom: 0; + width: 0; + left: 0; /* will take precedence when LTR */ + right: 0; /* will take precedence when RTL */ /* TODO: kill */ + } +.fc .fc-timeline-bg .fc-non-business { z-index: 1 } +.fc .fc-timeline-bg .fc-bg-event { z-index: 2 } +.fc .fc-timeline-bg .fc-highlight { z-index: 3 } +.fc .fc-timeline-bg-harness { + position: absolute; + top: 0; + bottom: 0; + } + + + + + .fc .fc-resource-timeline-divider { + width: 3px; /* important to have width to shrink this cell. no cross-browser problems */ + cursor: col-resize; + } .fc { - direction: ltr; - text-align: left; - } - -.fc table { - border-collapse: collapse; - border-spacing: 0; - } - -html .fc, -.fc table { - font-size: 1em; - } - -.fc td, -.fc th { - padding: 0; - vertical-align: top; - } + /* will match horizontal groups in the datagrid AND group lanes in the timeline area */ -/* Header -------------------------------------------------------------------------*/ +} -.fc-header td { - white-space: nowrap; - } +.fc .fc-resource-timeline .fc-resource-group:not([rowspan]) { + background: rgba(208, 208, 208, 0.3); + background: var(--fc-neutral-bg-color, rgba(208, 208, 208, 0.3)); + } -.fc-header-left { - width: 25%; - text-align: left; - } - -.fc-header-center { - text-align: center; - } - -.fc-header-right { - width: 25%; - text-align: right; - } - -.fc-header-title { - display: inline-block; - vertical-align: top; - } - -.fc-header-title h2 { - margin-top: 0; - white-space: nowrap; - } - -.fc .fc-header-space { - padding-left: 10px; - } - -.fc-header .fc-button { - margin-bottom: 1em; - vertical-align: top; - } - -/* buttons edges butting together */ +.fc .fc-timeline-lane-frame { + position: relative; /* contains the fc-timeline-bg container, which liquidly expands */ + /* the height is explicitly set by row-height-sync */ + } -.fc-header .fc-button { - margin-right: -1px; - } - -.fc-header .fc-corner-right, /* non-theme */ -.fc-header .ui-corner-right { /* theme */ - margin-right: 0; /* back to normal */ - } - -/* button layering (for border precedence) */ - -.fc-header .fc-state-hover, -.fc-header .ui-state-hover { - z-index: 2; - } - -.fc-header .fc-state-down { - z-index: 3; - } +.fc .fc-timeline-overlap-enabled .fc-timeline-lane-frame .fc-timeline-events { /* has height set on it */ + box-sizing: content-box; /* padding no longer part of height */ + padding-bottom: 10px; /* give extra spacing underneath for selecting */ + } -.fc-header .fc-state-active, -.fc-header .ui-state-active { - z-index: 4; - } - - - -/* Content -------------------------------------------------------------------------*/ - -.fc-content { - clear: both; - } - -.fc-view { - width: 100%; /* needed for view switching (when view is absolute) */ - overflow: hidden; - } - - +/* hack to make bg expand to lane's full height in resource-timeline with expandRows (#6134) */ +.fc-timeline-body-expandrows td.fc-timeline-lane { + position: relative; + } +.fc-timeline-body-expandrows .fc-timeline-lane-frame { + position: static; + } +/* the "frame" */ +.fc-datagrid-cell-frame-liquid { + height: 100%; /* needs liquid hack */ +} +.fc-liquid-hack .fc-datagrid-cell-frame-liquid { + height: auto; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + } +.fc { -/* Cell Styles -------------------------------------------------------------------------*/ + /* the "frame" in a HEADER */ + /* needs to position the column resizer */ + /* needs to vertically center content */ -.fc-widget-header, /* , usually */ -.fc-widget-content { /* , usually */ - border: 1px solid #ddd; - } - -.fc-state-highlight { /* today cell */ /* TODO: add .fc-today to */ - background: #fcf8e3; - } - -.fc-cell-overlay { /* semi-transparent rectangle while dragging */ - background: #bce8f1; - opacity: .3; - filter: alpha(opacity=30); /* for IE */ - } - +} +.fc .fc-datagrid-header .fc-datagrid-cell-frame { + position: relative; /* for resizer */ + display: flex; + justify-content: flex-start; /* horizontal align (natural left/right) */ + align-items: center; /* vertical align */ + } +.fc { + /* the column resizer (only in HEADER) */ -/* Buttons -------------------------------------------------------------------------*/ +} +.fc .fc-datagrid-cell-resizer { + position: absolute; + z-index: 1; + top: 0; + bottom: 0; + width: 5px; + cursor: col-resize; + } +.fc { -.fc-button { - position: relative; - display: inline-block; - padding: 0 .6em; - overflow: hidden; - height: 1.9em; - line-height: 1.9em; - white-space: nowrap; - cursor: pointer; - } - -.fc-state-default { /* non-theme */ - border: 1px solid; - } + /* the cushion */ -.fc-state-default.fc-corner-left { /* non-theme */ - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - } +} +.fc .fc-datagrid-cell-cushion { + padding: 8px; + white-space: normal; + overflow: hidden; /* problem for col resizer :( */ + } +.fc { -.fc-state-default.fc-corner-right { /* non-theme */ - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; - } + /* expander icons */ -/* - Our default prev/next buttons use HTML entities like ‹ › « » - and we'll try to make them look good cross-browser. -*/ +} +.fc .fc-datagrid-expander { + cursor: pointer; + opacity: 0.65 -.fc-text-arrow { - margin: 0 .1em; - font-size: 2em; - font-family: "Courier New", Courier, monospace; - vertical-align: baseline; /* for IE7 */ - } + } +.fc .fc-datagrid-expander .fc-icon { /* the expander and spacers before the expander */ + display: inline-block; + width: 1em; /* ensure constant width, esp for empty icons */ + } +.fc .fc-datagrid-expander-placeholder { + cursor: auto; + } +.fc .fc-resource-timeline-flat .fc-datagrid-expander-placeholder { + display: none; + } +.fc-direction-ltr .fc-datagrid-cell-resizer { right: -3px } +.fc-direction-rtl .fc-datagrid-cell-resizer { left: -3px } +.fc-direction-ltr .fc-datagrid-expander { margin-right: 3px } +.fc-direction-rtl .fc-datagrid-expander { margin-left: 3px } -.fc-button-prev .fc-text-arrow, -.fc-button-next .fc-text-arrow { /* for ‹ › */ - font-weight: bold; - } - -/* icon (for jquery ui) */ - -.fc-button .fc-icon-wrap { - position: relative; - float: left; - top: 50%; - } - -.fc-button .ui-icon { - position: relative; - float: left; - margin-top: -50%; - *margin-top: 0; - *top: -50%; - } - -/* - button states - borrowed from twitter bootstrap (http://twitter.github.com/bootstrap/) -*/ - -.fc-state-default { - background-color: #f5f5f5; - background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); - background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); - background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); - background-repeat: repeat-x; - border-color: #e6e6e6 #e6e6e6 #bfbfbf; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - color: #333; - text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - } - -.fc-state-hover, -.fc-state-down, -.fc-state-active, -.fc-state-disabled { - color: #333333; - background-color: #e6e6e6; - } - -.fc-state-hover { - color: #333333; - text-decoration: none; - background-position: 0 -15px; - -webkit-transition: background-position 0.1s linear; - -moz-transition: background-position 0.1s linear; - -o-transition: background-position 0.1s linear; - transition: background-position 0.1s linear; - } - -.fc-state-down, -.fc-state-active { - background-color: #cccccc; - background-image: none; - outline: 0; - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - } - -.fc-state-disabled { - cursor: default; - background-image: none; - opacity: 0.65; - filter: alpha(opacity=65); - box-shadow: none; - } - - - -/* Global Event Styles -------------------------------------------------------------------------*/ - -.fc-event { - border: 1px solid #3a87ad; /* default BORDER color */ - background-color: #3a87ad; /* default BACKGROUND color */ - color: #fff; /* default TEXT color */ - font-size: .85em; - cursor: default; - } - -a.fc-event { - text-decoration: none; - } - -a.fc-event, -.fc-event-draggable { - cursor: pointer; - } - -.fc-rtl .fc-event { - text-align: right; - } - -.fc-event-inner { - width: 100%; - height: 100%; - overflow: hidden; - } - -.fc-event-time, -.fc-event-title { - padding: 0 1px; - } - -.fc .ui-resizable-handle { - display: block; - position: absolute; - z-index: 99999; - overflow: hidden; /* hacky spaces (IE6/7) */ - font-size: 300%; /* */ - line-height: 50%; /* */ - } - - - -/* Horizontal Events -------------------------------------------------------------------------*/ - -.fc-event-hori { - border-width: 1px 0; - margin-bottom: 1px; - } - -.fc-ltr .fc-event-hori.fc-event-start, -.fc-rtl .fc-event-hori.fc-event-end { - border-left-width: 1px; - border-top-left-radius: 3px; - border-bottom-left-radius: 3px; - } - -.fc-ltr .fc-event-hori.fc-event-end, -.fc-rtl .fc-event-hori.fc-event-start { - border-right-width: 1px; - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - } - -/* resizable */ - -.fc-event-hori .ui-resizable-e { - top: 0 !important; /* importants override pre jquery ui 1.7 styles */ - right: -3px !important; - width: 7px !important; - height: 100% !important; - cursor: e-resize; - } - -.fc-event-hori .ui-resizable-w { - top: 0 !important; - left: -3px !important; - width: 7px !important; - height: 100% !important; - cursor: w-resize; - } - -.fc-event-hori .ui-resizable-handle { - _padding-bottom: 14px; /* IE6 had 0 height */ - } - - - -/* Reusable Separate-border Table -------------------------------------------------------------*/ - -table.fc-border-separate { - border-collapse: separate; - } - -.fc-border-separate th, -.fc-border-separate td { - border-width: 1px 0 0 1px; - } - -.fc-border-separate th.fc-last, -.fc-border-separate td.fc-last { - border-right-width: 1px; - } - -.fc-border-separate tr.fc-last th, -.fc-border-separate tr.fc-last td { - border-bottom-width: 1px; - } - -.fc-border-separate tbody tr.fc-first td, -.fc-border-separate tbody tr.fc-first th { - border-top-width: 0; - } - - - -/* Month View, Basic Week View, Basic Day View -------------------------------------------------------------------------*/ - -.fc-grid th { - text-align: center; - } - -.fc .fc-week-number { - width: 22px; - text-align: center; - } - -.fc .fc-week-number div { - padding: 0 2px; - } - -.fc-grid .fc-day-number { - float: right; - padding: 0 2px; - } - -.fc-grid .fc-other-month .fc-day-number { - opacity: 0.3; - filter: alpha(opacity=30); /* for IE */ - /* opacity with small font can sometimes look too faded - might want to set the 'color' property instead - making day-numbers bold also fixes the problem */ - } - -.fc-grid .fc-day-content { - clear: both; - padding: 2px 2px 1px; /* distance between events and day edges */ - } - -/* event styles */ - -.fc-grid .fc-event-time { - font-weight: bold; - } - -/* right-to-left */ - -.fc-rtl .fc-grid .fc-day-number { - float: left; - } - -.fc-rtl .fc-grid .fc-event-time { - float: right; - } - - - -/* Agenda Week View, Agenda Day View -------------------------------------------------------------------------*/ - -.fc-agenda table { - border-collapse: separate; - } - -.fc-agenda-days th { - text-align: center; - } - -.fc-agenda .fc-agenda-axis { - width: 50px; - padding: 0 4px; - vertical-align: middle; - text-align: right; - white-space: nowrap; - font-weight: normal; - } - -.fc-agenda .fc-week-number { - font-weight: bold; - } - -.fc-agenda .fc-day-content { - padding: 2px 2px 1px; - } - -/* make axis border take precedence */ - -.fc-agenda-days .fc-agenda-axis { - border-right-width: 1px; - } - -.fc-agenda-days .fc-col0 { - border-left-width: 0; - } - -/* all-day area */ - -.fc-agenda-allday th { - border-width: 0 1px; - } - -.fc-agenda-allday .fc-day-content { - /*min-height: 34px; *//* TODO: doesnt work well in quirksmode */ - _height: 34px; - } - -/* divider (between all-day and slots) */ - -.fc-agenda-divider-inner { - height: 2px; - overflow: hidden; - } - -.fc-widget-header .fc-agenda-divider-inner { - background: #eee; - } - -/* slot rows */ - -.fc-agenda-slots th { - border-width: 1px 1px 0; - } - -.fc-agenda-slots td { - border-width: 1px 0 0; - background: none; - } - -.fc-agenda-slots td div { - height: 20px; - } - -.fc-agenda-slots tr.fc-slot0 th, -.fc-agenda-slots tr.fc-slot0 td { - border-top-width: 0; - } - -.fc-agenda-slots tr.fc-minor th, -.fc-agenda-slots tr.fc-minor td { - border-top-style: dotted; - } - -.fc-agenda-slots tr.fc-minor th.ui-widget-header { - *border-top-style: solid; /* doesn't work with background in IE6/7 */ - } - - - -/* Vertical Events -------------------------------------------------------------------------*/ - -.fc-event-vert { - border-width: 0 1px; - } - -.fc-event-vert.fc-event-start { - border-top-width: 1px; - border-top-left-radius: 3px; - border-top-right-radius: 3px; - } - -.fc-event-vert.fc-event-end { - border-bottom-width: 1px; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; - } - -.fc-event-vert .fc-event-time { - white-space: nowrap; - font-size: 10px; - } - -.fc-event-vert .fc-event-inner { - position: relative; - z-index: 2; - } - -.fc-event-vert .fc-event-bg { /* makes the event lighter w/ a semi-transparent overlay */ - position: absolute; - z-index: 1; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: #fff; - opacity: .25; - filter: alpha(opacity=25); - } - -.fc .ui-draggable-dragging .fc-event-bg, /* TODO: something nicer like .fc-opacity */ -.fc-select-helper .fc-event-bg { - display: none\9; /* for IE6/7/8. nested opacity filters while dragging don't work */ - } - -/* resizable */ - -.fc-event-vert .ui-resizable-s { - bottom: 0 !important; /* importants override pre jquery ui 1.7 styles */ - width: 100% !important; - height: 8px !important; - overflow: hidden !important; - line-height: 8px !important; - font-size: 11px !important; - font-family: monospace; - text-align: center; - cursor: s-resize; - } - -.fc-agenda .ui-resizable-resizing { /* TODO: better selector */ - _overflow: hidden; - } - - diff --git a/app/controllers/admin/property_hires_controller.rb b/app/controllers/admin/property_hires_controller.rb index 40a1736..f984d5f 100644 --- a/app/controllers/admin/property_hires_controller.rb +++ b/app/controllers/admin/property_hires_controller.rb @@ -24,7 +24,14 @@ class Admin::PropertyHiresController < OrbitAdminController @locations = PropertyLocation.all.desc(:created_at).collect{|loc| [loc.title, loc.id.to_s]} @locations << ["Other", "other_location"] end - + def edit_hire + @phire = PHire.find(params[:id]) + end + def update_hire + @phire = PHire.find(params[:id]) + @phire.update_attributes(phire_params) + redirect_to admin_property_hire_path(:id=>@phire.property) + end def edit @property = Property.where(:uid => params[:id].split("-").last).first rescue nil create_set (true) @@ -178,7 +185,9 @@ class Admin::PropertyHiresController < OrbitAdminController def location_params params.require(:property_location).permit! end - + def phire_params + params.require(:p_hire).permit! + end def property_params prop = params.require(:property).permit! prop.delete(:property_location) if prop[:property_location] == "other" diff --git a/app/controllers/property_hires_controller.rb b/app/controllers/property_hires_controller.rb index b2bffdc..9a31955 100644 --- a/app/controllers/property_hires_controller.rb +++ b/app/controllers/property_hires_controller.rb @@ -214,7 +214,7 @@ class PropertyHiresController < ApplicationController end end respond_to do |format| - format.html # index.html.erb + format.html { render json: allevents.to_json }# index.html.erb format.json { render json: allevents.to_json } end end diff --git a/app/helpers/admin/property_hires_helper.rb b/app/helpers/admin/property_hires_helper.rb index bf07c87..78d05a1 100644 --- a/app/helpers/admin/property_hires_helper.rb +++ b/app/helpers/admin/property_hires_helper.rb @@ -2,32 +2,63 @@ module Admin::PropertyHiresHelper def check_for_availability(stime, etime, pid, interval=nil, recurring_end_date=nil) property = Property.find(pid) - return {"success" => false, "msg" => "Values are not ok."} if property.nil? || stime.blank? || etime.blank? + return {"success" => false, "msg" => I18n.t("property_hire.values_are_not_ok",:default=>"Values are not ok.")} if property.nil? || stime.blank? || etime.blank? + timezone = (params[:timezone] rescue nil) + timezone = timezone ? timezone : Time.zone.to_s if !stime.blank? - stime = DateTime.parse(stime + Time.zone.to_s) rescue nil + stime = DateTime.parse(stime + timezone) rescue nil else stime = nil end if !etime.blank? - etime = DateTime.parse(etime + Time.zone.to_s) rescue nil + etime = DateTime.parse(etime + timezone) rescue nil else etime = nil end if !recurring_end_date.blank? - recurring_end_date = DateTime.parse(recurring_end_date + Time.zone.to_s) rescue nil + recurring_end_date = DateTime.parse(recurring_end_date + timezone) rescue nil + begin + interval_time = 1.send(interval) + tmp_date = recurring_end_date - interval_time + if tmp_date < etime + I18n.with_locale(params[:locale]) do + interval_str= I18n.t("property_hire.1_#{interval}","1 #{interval}") + default_msg = "Recurring end date must exceed hire end time than #{interval_str}!" + msg = I18n.t("property_hire.recurring_end_date_must_exceed_time",{:time=>interval_str,:default=>default_msg}) + return {"success" => false, "msg" => msg} + end + end + rescue + end else recurring_end_date = nil end data = {} - return {"success" => false, "msg" => "Starting time cannot be greater than ending time."} if stime > etime - if property.is_available_for_hire?(stime, etime, interval, recurring_end_date) - if property.not_yet_hired?(stime, etime, interval, recurring_end_date) + if stime > etime + I18n.with_locale(params[:locale]) do + return {"success" => false, "msg" => I18n.t("property_hire.starting_time_cannot_be_greater_than_ending_time")} + end + end + available_flag = property.is_available_for_hire?(stime, etime, interval, recurring_end_date) + if available_flag + if property.not_yet_hired?(stime, etime, interval, recurring_end_date,params[:phire_id]) data = {"success" => true} else - data = {"success" => false, "msg" => "Property is already hired during this time."} + I18n.with_locale(params[:locale]) do + data = {"success" => false, "msg" => I18n.t("property_hire.property_is_already_hired_during_this_time")} + end end else - data = {"success" => false, "msg" => "Property is unavailable during this time."} + I18n.with_locale(params[:locale]) do + msg = I18n.t("property_hire.property_is_unavailable_during_this_time") + if available_flag.nil? + can_hire_date = stime - (property.can_hire_before_months).month + msg += ("
" + I18n.t("property_hire.please_hire_after_date",{:date=>"{#{can_hire_date.utc.to_json.gsub('"','')}}"})) + else + msg += ("
" + property.render_unavailable_message) + end + data = {"success" => false, "msg" => msg} + end end return data end diff --git a/app/models/p_hire.rb b/app/models/p_hire.rb index 19ffcfc..ea66182 100644 --- a/app/models/p_hire.rb +++ b/app/models/p_hire.rb @@ -34,10 +34,11 @@ class PHire :hiring_person_id => self.hiring_person_id, :hiring_person_name => self.hiring_person_name, :note => self.note_for_hire || "", - :start => self.start_time.rfc822, - :end => self.end_time.rfc822, - :allDay => false, - :color => "#FC4040" + :start => self.start_time.to_json.gsub('"',''), + :end => self.end_time.to_json.gsub('"',''), + :allDay => (self.end_time - self.start_time >= 1), + :color => (self.passed ? "#3788d8" : "#FC4040"), + :error_message => (self.passed ? nil : "Not approved") } end @@ -87,7 +88,7 @@ class PHire next if !((startt..endt) & (@start_date..@end_date)).blank? end if @start_date < re.recurring_end_date - @recurring << {:id => re.id.to_s, :hiring_person_name => re.hirer_name ,:title=>re.reason_for_hire, :note=>re.reason_for_hire, :start=>@start_date, :end => @end_date, :allDay => false, :recurring => re.recurring, :color => "#FC4040"} + @recurring << {:id => re.id.to_s, :hiring_person_name => re.hirer_name ,:title=>re.reason_for_hire, :note=>re.reason_for_hire, :start=>@start_date, :end => @end_date, :allDay => (re.end_time - re.start_time >= 1), :recurring => re.recurring, :color => (re.passed ? "#3788d8" : "#FC4040"), :error_message => (re.passed ? nil : "Not approved")} end end when "month" diff --git a/app/models/property.rb b/app/models/property.rb index a53927f..ef60f47 100644 --- a/app/models/property.rb +++ b/app/models/property.rb @@ -21,7 +21,7 @@ class Property mount_uploader :image, ImageUploader # unavailibility fields - + field :can_hire_before_months, type: Integer, default: 0 field :set_unavailibility, type: Boolean, default: false field :start_time field :end_time @@ -54,7 +54,79 @@ class Property "Friday", "Saturday" ] - + def render_unavailable_message + message = "" + property = self + weekdays_options = self.class::WEEKDAYS + weekdays_options = weekdays_options.map do |weekday| + trans = I18n.t("property_hire.#{weekday}", :default=>'') + if trans != "" + trans + else + weekday + end + end + if property.set_unavailibility + if property.weekdays.length > 0 + translation_missing = (I18n.t('property_hire.unavailable_hint1', {:default => ''}) == "") + str1 = (!property.start_date.nil? ? (I18n.t("property_hire.from",:default=>" from ") + property.start_date.strftime("%Y-%m-%d")) : "") + str2 = (!property.end_date.nil? ? (I18n.t("property_hire.to",:default=>" to ") + property.end_date.strftime("%Y-%m-%d")) : "") + if str1 == "" && str2 != "" + str1 = I18n.t("property_hire.from_now_on") + end + if str1 != "" || str2 != "" + str2 += I18n.t("property_hire.of",:default=>"") + else + str2 += I18n.t("property_hire.at",:default=>"") + end + week_str = "" + if translation_missing + week_str += "every " + else + week_str += I18n.t("property_hire.every") + end + dot_trans = I18n.t("property_hire.dot",:default=>", ") + property.weekdays.each_with_index do |d,i| + if i < (property.weekdays.count - 1) + week_str += (weekdays_options[d.to_i] + dot_trans) + else + week_str += weekdays_options[d.to_i] + end + end + str3 = "" + if property.end_time.blank? + if property.start_time.blank? + str3 = "." if translation_missing + else + str3 = I18n.t("property_hire.from_time",{:time=>property.start_time,:default=>" from #{property.start_time}."}) + end + else + if I18n.locale.to_s != "zh_tw" + str3 = " between #{property.start_time} & #{property.end_time}." + else + str3 = I18n.t("property_hire.time1_to_time2",{:time1=>property.start_time,:time2=>property.end_time}) + end + end + if str3 != "" + str3 = I18n.t("property_hire.of",:default=>"") + str3 + end + hint1 = I18n.t('property_hire.unavailable_hint1', {:str1=>str1,:str2=>str2,:week_str=>week_str,:str3=>str3, :default => ''}) + if hint1 == "" + message += "This property is unavaliable#{str1}#{str2} #{week_str}#{str3}" + else + message += hint1 + end + end + if property.can_hire_before_months != 0 + if message != "" + message += "
" + end + default_msg = "This property is unavaliable to hire before #{property.can_hire_before_months} month ago." + message += I18n.t("property_hire.unavailable_hint2",{:month=>property.can_hire_before_months,:default=>default_msg}) + end + end + return message.html_safe + end def get_location_name return self.property_location.nil? ? self.other_location : self.property_location.title end @@ -66,11 +138,14 @@ class Property def is_available_for_hire?(stime, etime, interval = nil, recurring_end_date = nil) available = false return true if self.set_unavailibility == false - return true if self.weekdays.empty? - available = true if !self.start_date.nil? && (self.start_date > stime && self.start_date > etime) - available = true if !self.end_date.nil? && self.end_date < stime - startt = self.start_date.nil? ? self.created_at : self.start_date - endt = self.end_date.nil? && !startt.nil? ? (startt + 5.years) : self.end_date + return true if self.weekdays.empty? && self.can_hire_before_months == 0 + if self.can_hire_before_months != 0 + return nil if (((stime - Time.now.to_datetime) * 1.day) > (self.can_hire_before_months).month) + end + startt = self.start_date.nil? ? stime : self.start_date + endt = self.end_date.nil? ? etime : self.end_date + available = true if (startt > stime && endt > etime) + available = true if (endt < stime) weekdays = self.weekdays.collect{|w| w.to_i} if !startt.nil? if !available @@ -83,8 +158,8 @@ class Property time_weekdays.uniq! weekdays = weekdays & time_weekdays return true if weekdays.blank? - startt = DateTime.parse(stime.strftime("%Y-%m-%d " + self.start_time + Time.zone.to_s)) - endt = DateTime.parse(etime.strftime("%Y-%m-%d " + self.end_time + Time.zone.to_s)) + startt = DateTime.parse(stime.strftime("%Y-%m-%d " + (self.start_time.blank? ? "00:00" : self.start_time) + Time.zone.to_s)) + endt = DateTime.parse(etime.strftime("%Y-%m-%d " + (self.end_time.blank? ? "23:59" : self.end_time) + Time.zone.to_s)) common_dates = (startt..endt) & (stime..etime) available = common_dates.nil? end @@ -119,17 +194,21 @@ class Property end end - def not_yet_hired?(stime, etime, interval, recurring_end_date) + def not_yet_hired?(stime, etime, interval, recurring_end_date,phire_id=nil) phires = self.p_hires - bookings_count = phires.where(:start_time.lte => stime,:end_time.gte => stime,:recurring => false).count - + phires.where(:start_time.gte => stime,:end_time.lte => etime,:recurring => false).count - +phires.where(:start_time.lte => etime,:end_time.gte => etime,:recurring => false).count + stime = stime.utc + etime = etime.utc + bookings_count = phires.where(:start_time.lte => stime,:end_time.gte => stime,:recurring => false,:id.ne=>phire_id).count + + phires.where(:start_time.gte => stime,:end_time.lte => etime,:recurring => false,:id.ne=>phire_id).count + +phires.where(:start_time.lte => etime,:end_time.gte => etime,:recurring => false,:id.ne=>phire_id).count available = true if bookings_count != 0 available = false end + puts ["phire_id",phire_id] if available - bookings = phires.where(:recurring_end_date.gte => stime, :recurring => true) + phires.where(:recurring => false,:recurring_end_date => nil) + phires.where(:recurring => false,:recurring_end_date.gte => stime) + recurring_bookings = phires.where(:recurring_end_date.gte => stime, :recurring => true,:id.ne=>phire_id) + bookings = phires.where(:recurring => false,:recurring_end_date => nil) case interval when 'week' d_step = 1.week @@ -138,53 +217,50 @@ class Property else d_step = 0 end - bookings.each do |booking| - stime_tp = stime - etime_tp = etime + if true#d_step != 0 + bookings += recurring_bookings + end + bookings.each_with_index do |booking,i| + stime_tp = stime.clone + etime_tp = etime.clone b_interval = booking.recurring_interval - if (b_interval == 'month' || b_interval == 'week') && booking.recurring_end_date.nil? + b_recurring_end_date = booking.recurring_end_date ? booking.recurring_end_date.utc : nil + b_sdata = booking.start_time.utc + b_edata = booking.end_time.utc + b_delta = b_edata - b_sdata + if (b_interval == 'month' || b_interval == 'week') && (booking.recurring_end_date.nil? || !booking.recurring) b_interval = nil end - while true - if b_interval == 'month' - diff_month = booking.end_time.month - booking.start_time.month - diff_month = diff_month + 12 if diff_month < 0 - e_month = stime_tp.month + diff_month - e_year = stime_tp.year + (booking.end_time.year-booking.start_time.year) - e_month = e_month - 12 if e_month >12 - b_sdata = Time.local(stime_tp.year,stime_tp.month,booking.start_time.day,booking.start_time.hour,booking.start_time.minute).to_datetime - b_edata = Time.local(e_year,e_month,booking.end_time.day,booking.end_time.hour,booking.end_time.minute).to_datetime - elsif b_interval == 'week' - diff_day = booking.end_time - booking.start_time - if (booking.end_time.wday <= booking.start_time.wday && diff_day>1) || diff_day > 7 - over_one_week = true + b_datas = [] + if b_interval.present? + b_interval = (1).send(b_interval) + b_datas = (b_edata..b_recurring_end_date).step(b_interval).to_a + b_datas = b_datas.map{|b_end| [b_end-b_delta,b_end]} + start_index = b_datas.count + b_datas.each_with_index do |(b_start,b_end),i| + if b_start >= stime_tp || b_end <= etime_tp + start_index = i + break end - b_sdata_tp = stime_tp - stime_tp.wday.day + booking.start_time.wday.day - b_sdata = Time.local(b_sdata_tp.year,b_sdata_tp.month,b_sdata_tp.day,booking.start_time.hour,booking.start_time.minute).to_datetime - if over_one_week && etime_tp.wday <= booking.start_time.wday - b_sdata = b_sdata - 7.day - end - now_diff_day = etime_tp - stime_tp - if (etime_tp.wday <= stime_tp.wday && now_diff_day>1) || now_diff_day > 7 - b_sdata = b_sdata + 7.day - end - b_edata_tp = b_sdata + (booking.end_time - booking.start_time).to_i.day - b_edata = Time.local(b_edata_tp.year,b_edata_tp.month,b_edata_tp.day,booking.end_time.hour,booking.end_time.minute).to_datetime - else - b_sdata = booking.start_time - b_edata = booking.end_time end + b_datas = b_datas[start_index..-1].to_a.map{|b_start,b_end| (b_start..b_end)} + else + b_datas = [b_sdata..b_edata] + end + while b_datas.present? sdata = stime_tp edata = etime_tp - if etime_tp > booking.start_time - if (sdata <= b_sdata && edata >= b_sdata) || (sdata >= b_sdata && edata <= b_edata) || (sdata <= b_edata && edata >= b_edata) - available = false - end - end + available = b_datas.find{|b_range| b_range & (stime_tp..etime_tp)}.nil? stime_tp = stime_tp + d_step etime_tp = etime_tp + d_step - break if recurring_end_date.blank? || d_step==0 || recurring_end_date < stime_tp - end + break if !available || recurring_end_date.blank? || d_step==0 + start_index = b_datas.find_index{|b_range| b_range.first >= stime_tp} + if start_index + b_datas = b_datas[start_index..-1] + else + b_datas = [] + end + end break if available == false end end diff --git a/app/views/admin/property_hires/_form.html.erb b/app/views/admin/property_hires/_form.html.erb index f0e41f8..392b52e 100644 --- a/app/views/admin/property_hires/_form.html.erb +++ b/app/views/admin/property_hires/_form.html.erb @@ -245,42 +245,20 @@ +
+ <%= f.label :start_time, t("property_hire.limit_start_time"), :class => "control-label muted" %> +
+ <%= f.datetime_picker :start_time, :picker_type => "time", :no_label => true, :new_record => @property.new_record?, :value => (Time.parse(@property.start_time) rescue "") %> +
+
+
+ <%= f.label :end_time, t("property_hire.limit_end_time"), :class => "control-label muted" %> +
+ <%= f.datetime_picker :end_time, :picker_type => "time", :no_label => true, :new_record => @property.new_record?, :value => (Time.parse(@property.end_time) rescue "") %> +
+
<% @site_in_use_locales.each do |locale| %> <%= f.fields_for :description_translations do |f| %>
diff --git a/app/views/admin/property_hires/edit_hire.html.erb b/app/views/admin/property_hires/edit_hire.html.erb new file mode 100644 index 0000000..6f16ee6 --- /dev/null +++ b/app/views/admin/property_hires/edit_hire.html.erb @@ -0,0 +1,496 @@ + +<%= content_for :page_specific_css do %> + <% ["basic/bootstrap-datetimepicker.css","property_hire_fullcalendar.css","property_hire_calendar"].each do |css| %> + <%= stylesheet_link_tag css %> + <% end %> +<% end %> + + + + +<% + hire = @phire + property = @phire.property +%> +

<%= property.title %>

+<% if session["hire-save-msg"].present? %> + + <% session.delete("hire-save-msg") %> +<% end %> +
+
+ +
+
+
+
+ + + +
+ +
+
+

+
+
+
+
+ +
+ +
+ +
+ + <%= fields_for :timepicker do |f|%> + <%= f.time_picker :timepicker, :no_label => true, :new_record => hire.new_record?,:format=>"HH:mm", :class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> + <% end %> +
+ + +
+
+
+
+
+<%= form_for hire, :url => update_hire_admin_property_hire_path(hire), html: { class: "form-horizontal" } do |f| %> +
+ <%= f.label :start_time, "*"+t("property_hire.start_time"), :class => "col-sm-2 control-label" %> +
+ <%= f.datetime_picker :start_time, :no_label => true, :new_record => hire.new_record?,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "start", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> + +
+
+
+ <%= f.label :end_time, "*"+t("property_hire.end_time"), :class => "col-sm-2 control-label" %> +
+ <%= f.datetime_picker :end_time, :no_label => true, :new_record => hire.new_record?,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> + +
+
+ +
+ <%= f.label :recurring, t("property_hire.recurring"), :class => "col-sm-2 control-label" %> +
+ <%= f.check_box :recurring %> +
+
+
> +
+ <%= f.label :recurring_interval, t("property_hire.recurring_interval"), :class => "col-sm-2 control-label" %> +
+ <%= f.select :recurring_interval, PHire::INTERVALS.collect{|int| [t("property_hire.recurring_interval_types.#{int}"), int] }, {:prompt => t('property_hire.select_interval')}, {:data => {"fv-validation" => "requiredifrecurring;" , "fv-messages" => "Cannot be empty;"}} %> +
+
+ +
+ <%= f.label :recurring_end_date, "*"+t("property_hire.recurring_end_date"), :class => "col-sm-2 control-label" %> +
+ <%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record?, :class=>"pull-left", :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %> + +
+
+
+ +
+
+ + + +
+ <% if property.set_unavailibility %> +
+ <%= t("property_hire.Unavailibility_Schedule") %> +
+ <%= property.render_unavailable_message%> +
+
+ <% end %> +
+ + +
+ <%= f.label :hiring_person_email, "*"+t("property_hire.hiring_person_email"), :class => "col-sm-2 control-label" %> +
+ <%= f.text_field :hiring_person_email, :class => "form-control", :value => current_user.member_profile.email, :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> +
+
+
+ <%= f.label :hiring_person_number, "*"+t("property_hire.hiring_person_number"), :class => "col-sm-2 control-label" %> +
+ <%= f.text_field :hiring_person_number, :class => "form-control", :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> +
+
+
+ <%= f.label :hiring_person_name, "*"+t("property_hire.hiring_person_name"), :class => "col-sm-2 control-label" %> +
+ <%= f.text_field :hiring_person_name, :class => "form-control", :value => (current_user.name rescue ""), :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> + <%= f.hidden_field :hiring_person_id, :value => (current_user.member_profile.id.to_s rescue "") %> +
+
+
+ <%= f.label :reason_for_hire, "*"+t("property_hire.reason_for_hire"), :class => "col-sm-2 control-label" %> +
+ <%= f.text_field :reason_for_hire, :class => "form-control", :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> +
+
+ <% if(property.enable_notes_selector rescue false) %> + <% property.notes_selector.each do |index,sub_hash| %> + <% name = sub_hash["name"][I18n.locale.to_s] %> + <% name = sub_hash["name"].values.select{|v| v.present?}.first.to_s if name.blank? %> + <% values = sub_hash["value"][I18n.locale.to_s] %> + <% values = sub_hash["value"].values.select{|v| v.present?}.first.to_s if values.blank? %> + <% type = sub_hash["type"] %> +
+ <%= f.label "notes_selector[#{index}]", name, :class => "col-sm-2 control-label" %> +
+ <% values.each_with_index do |v,i| %> + + <% end %> + <% if type == "checkbox" && (values.count > 1) %> + <%= t("property_hire.checkbox_hint") %> + <% end %> +
+
+ <% end %> + <% else %> +
+ <%= f.label :note_for_hire, t("property_hire.note_for_hire"), :class => "col-sm-2 control-label" %> +
+ <%= f.text_area :note_for_hire, :class => "form-control" %> +
+
+ <% end %> + <% fields_name = ["organization" ,"person_in_charge" , "tel_of_person_in_charge" , "department" , "contact_person" , "tel_of_contact_person" , "mobile_phone_of_contact_person" , "contact_person_Email" , "contact_person_department"] %> + <% fields_name.each do |field_name| %> + <% if(property[field_name]["enable"] == "1" rescue false) %> + <% required = (property[field_name]["required"] == "true" rescue false) %> +
+ <%= f.label field_name, (required ? "*" : "") + t("property_hire.#{field_name}"), :class => "col-sm-2 control-label" %> +
+ <% if required %> + <%= f.text_field field_name, :class => "form-control", :data => {"fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> + <% else %> + <%= f.text_field field_name, :class => "form-control" %> + <% end %> +
+
+ <% end %> + <% end %> +
+
+ <%= f.submit t("property_hire.save"), :class => "btn btn-primary" %> + <%= f.hidden_field :property_id, :value => property.id %> + +
+
+<% end %> +
+ + + + + + + diff --git a/app/views/admin/property_hires/show.html.erb b/app/views/admin/property_hires/show.html.erb index 1aa72b3..e2c6be0 100644 --- a/app/views/admin/property_hires/show.html.erb +++ b/app/views/admin/property_hires/show.html.erb @@ -1,4 +1,80 @@ <%= csrf_meta_tag %> + +
+<% if params[:type] == "Calendar" %> + + <%= content_for :page_specific_css do %> + <% ["basic/bootstrap-datetimepicker.css","property_hire_fullcalendar.css","property_hire_calendar"].each do |css| %> + <%= stylesheet_link_tag css %> + <% end %> + <% end %> + + + +
+
+ +
+
+
+
+ + + + +
+ +
+
+

+
+
+
+
+ +
+ +<% else %> @@ -31,6 +107,7 @@
<% if can_edit_or_delete?(p_hire.property) %> + Edit View <% if p_hire.passed %> "index") %>" class="btn btn-warning">Reject @@ -47,4 +124,5 @@
Back <%= content_tag(:div, paginate(@bookings), class: "pagination pagination-centered") %> -
\ No newline at end of file + +<% end %> \ No newline at end of file diff --git a/app/views/admin/property_hires/show_booking_details.html.erb b/app/views/admin/property_hires/show_booking_details.html.erb index 5c8fa03..0f55233 100644 --- a/app/views/admin/property_hires/show_booking_details.html.erb +++ b/app/views/admin/property_hires/show_booking_details.html.erb @@ -59,6 +59,7 @@
Back <% if can_edit_or_delete?(@booking.property) %> + Edit <% if @booking.passed %> " class="btn btn-warning">Reject <% else %> diff --git a/app/views/property_hires/hire.html.erb b/app/views/property_hires/hire.html.erb index 4eba779..122928d 100644 --- a/app/views/property_hires/hire.html.erb +++ b/app/views/property_hires/hire.html.erb @@ -1,7 +1,8 @@ -<% OrbitHelper.render_css_in_head(["basic/bootstrap-datetimepicker.css"]) %> -<%= javascript_include_tag "lib/bootstrap-datetimepicker" %> -<%= javascript_include_tag "lib/datetimepicker/datetimepicker.js" %> +<% OrbitHelper.render_css_in_head(["basic/bootstrap-datetimepicker.css","property_hire_fullcalendar.css","property_hire_calendar.scss"]) %> <%= javascript_include_tag "validator.js" %> + + + <% data = action_data hire = data["hire"] @@ -26,17 +27,159 @@ <% session.delete("hire-save-msg") %> <% end %> +
+
+ +
+
+
+
+ + + +
+ +
+
+

+
+
+
+
+ +
+ +
+ +
+ + <%= fields_for :timepicker do |f|%> + <%= f.time_picker :timepicker, :no_label => true, :new_record => hire.new_record?,:format=>"HH:mm", :class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> + <% end %> +
+ + +
+
+
+
+
<%= form_for hire, :url => "/xhr/property_hires/make_booking", html: { class: "form-horizontal" } do |f| %>
<%= f.label :start_time, "*"+t("property_hire.start_time"), :class => "col-sm-2 control-label" %>
- <%= f.datetime_picker :start_time, :no_label => true, :new_record => hire.new_record?, :data=>{"picker-type" => "range", "range" => "start", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> + <%= f.datetime_picker :start_time, :no_label => true, :new_record => hire.new_record?,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "start", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> +
<%= f.label :end_time, "*"+t("property_hire.end_time"), :class => "col-sm-2 control-label" %>
- <%= f.datetime_picker :end_time, :no_label => true, :new_record => hire.new_record?, :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> + <%= f.datetime_picker :end_time, :no_label => true, :new_record => hire.new_record?,:class => "pull-left", :data=>{"picker-type" => "range", "range" => "end", "fv-validation" => "required;", "fv-messages" => "Cannot be empty;"} %> +
@@ -57,7 +200,8 @@
<%= f.label :recurring_end_date, "*"+t("property_hire.recurring_end_date"), :class => "col-sm-2 control-label" %>
- <%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record?, :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %> + <%= f.datetime_picker :recurring_end_date, :no_label => true, :new_record => hire.new_record?, :class=>"pull-left", :data=>{"fv-validation" => "requiredifrecurring;", "fv-messages" => "Cannot be empty;"} %> +
@@ -66,21 +210,20 @@
- +
<% if property.set_unavailibility %>
<%= t("property_hire.Unavailibility_Schedule") %>
- This property is unavaliable <%= !property.start_date.nil? ? " from " + property.start_date.strftime("%Y-%m-%d") : "" %> <%= !property.end_date.nil? ? " to " + property.end_date.strftime("%Y-%m-%d") : "" %> every - <% property.weekdays.each_with_index do |d,i| %> - <% if i < (property.weekdays.count - 1) %> - <%= Property::WEEKDAYS[d.to_i] + ", " %> - <% else %> - <%= Property::WEEKDAYS[d.to_i] %> - <% end %> - <% end %> - between <%= property.start_time %> & <%= property.end_time %>. + <%= property.render_unavailable_message%>
<% end %> @@ -176,45 +319,76 @@
@@ -33,9 +34,9 @@
- - - + + +