PageSourceSearch

https://www.cincyticket.com/login.asp?gifrompage=2&gitopage=2

html cincyticket.com collected 2026-09-25 18:52:13 UTC 251,650 bytes, 6,093 lines download raw bytes

1
2
3<!DOCTYPE html>
4<html>
5<head>
6	<!-- CCU 03/2006 meta tags settings start -->
7	<title>CincyTicket</title>
8	<meta name="description" content="Visit CincyTicket.com to get tickets for the hottest events in Cincinnati, OH and the surrounding area.">
9    <meta name="keywords" content="CincyTicket, tickets,Buy Tickets, events, performances, shows, online ticketing">
10    <meta name="author" content="CincyTicket">
11    <meta name="abstract" content="Buy tickets and see performance listings from CincyTicket">
12    <meta name="robots" content="INDEX, FOLLOW">
13
14	<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.8, minimum-scale=1.0' name='viewport' />
15	<meta name="google-translate-customization" content="9aaf36daf6e43103-a12f76fcd2014ac8-g804c3b886a9cdf60-11"></meta> 
16    
17    <link rel="stylesheet" type="text/css" href="//www.cincyticket.com/include/structure.css?ver=20228">
18    <link rel="stylesheet" type="text/css" href="//www.cincyticket.com/include/style.css?ver=20228">
19    <link rel='stylesheet' content='text/css' href='/include/jqueryui-themes/default/jquery-ui.css' />
20    
21		<link rel="stylesheet" type="text/css" media="only screen and (max-width: 1024px)" href="//www.cincyticket.com/include/mobile.css?ver=20228">
22	
23	
23<script type="text/javascript" src="//www.cincyticket.com/include/javascript.js?ver=20228"></script>
23
24    
24<script type="text/javascript" src="//www.cincyticket.com/include/jq.js"></script>
24
25
26    
26<script type='text/javascript' src='/include/jquery-3.5.1.min.js'></script>
26<script type='text/javascript' src='/include/jqueryui-themes/jquery-ui.min.js'></script>
26
27        
27<script type="text/javascript" src="//www.cincyticket.com/include/mobile.js"></script>
27
28    
29<script type="text/javascript">
30    if (!navigator.cookieEnabled) {
31        alert("Your browser settings are currently configured to not allow cookies. Please enable cookies and try again.");
32        window.stop();
33        document.execCommand("Stop"); //works in IE, 
34    }
35</script>
35
36
37
38
39<script type="text/javascript" src="//www.cincyticket.com/include/swApi.js"></script>
vendor: 2 bytes, line 39
39
40<script type="text/javascript" src="//www.cincyticket.com/include/swApiPublic.js"></script>
vendor: 2 bytes, line 40
40
41<script type="text/javascript">
42
43var window = window || {};
44var Showare = Showare || {};
45var document = document || undefined;
46
47Showare.Logger = {
48   Settings: {
49      ShouldLogInDev: true
50   },
51   data: null,
52   env: {}
53}
54
55window.onerror = function(msg, url, lineNo, _, error) {
56    var envInfo = Showare.Logger._getEnvironmentDetails();
57
58    var message = {
59        Description: msg,
60        SourceFile: url,
61        SourceLine: lineNo,
62        Referer: envInfo.referer,
63        QueryString: envInfo.querystring,
64        ErrorType: Showare.Logger.Settings.ErrorType,
65        Website: envInfo.website,
66        ShouldLogInDev: Showare.Logger.Settings.ShouldLogInDev,
67        Browser: envInfo.browser,
68        IPAddress: envInfo.ipaddress
69    };
70
71    if (error != undefined) {
72        message.Exception = error.stack;
73    }
74
75    if (Showare.Logger.data) {
76        message.StateVariables = JSON.stringify(Showare.Logger.data);
77    }
78
79    swApiPublic.sendRequest("POST", "/v1/errorlog/", message);
80    Showare.Logger.data = null;
81    return false;
82
83    function shouldfilterError() {
84        return !(
85            // This error gets thrown by third party includes, to see full error, we need
86            // to do https://blog.sentry.io/2016/05/17/what-is-script-error.html
87            (msg.search("\s*Script error.*") == -1) &&
88            // Related to iOS issue: https://github.com/getsentry/raven-js/issues/756
89            (msg.search(".*evaluating 'elt.parentNode'.*") == -1))
90    }
91};
92
93Showare.Logger.log = function(exception, data) {
94    Showare.Logger.data = data;
95
96    if (Object.prototype.toString.call(exception) == "[object Error]") {
97        if (exception.stack) {
98            var ex = exception.stack.split('\n');
99            // Parse exceptions in the format of
100            // ' at src (javascript.js?ver=20228:510)'
101            var data = ex[1].match(/.+\((.+):(\d+):(\d+)\)/); 
102            // and 
103            // ' at src javascript.js?ver=20228:510'
104            if (!data) {
105                data = ex[1].match(/.+\s(.+):(\d+):(\d+)/);
106            }
107            window.onerror(ex[0], data[1], data[2], '', exception);
108        } else {
109            window.onerror(exception.name + ": " + exception.message, '', '');
110        }
111    } else {
112        window.onerror(exception, '', '');
113    }
114};
115
116Showare.Logger.warn = function(msg, data) {
117    var logDetails = {
118        environment: Showare.Logger._getEnvironmentDetails(),
119        message: msg,
120        data: data
121    }
122    
123    swApiPublic.sendRequest("POST", "/v1/errorlog/warn", logDetails);
124    return;
125};
126
127Showare.Logger._getEnvironmentDetails = function() {
128    Showare.Logger.Settings.ErrorType = 'Javascript';
129    return  {
130        browser: "Mozilla/5.0 AppleWebKit/537.36 KHTML, like Gecko compatible PageSourceSearchBot/1.0 https//pagesourcesearch.com/bot Chrome/128.0.0.0 Safari/537.36",
131        ipaddress: "181.215.65.76",
132        querystring: window.location.href,
133        referer: "",
134        website: "www.cincyticket.com",
135        basketid: "0FkQ0UVTLSTMzgwTMTgE00yMD2IyMMDNykxTNTIEx0iMDuExMOjL1E1jLjcY21ULVLBLRRkSS1__k_o_"
136    }
137}
138
139</script>
139<script type="text/javascript">
140//---------------------------DATEPICKER---------------------------------
141function buildDatepicker(options) {
142    //Calling this function should be sufficient to create a calendar within a designated div, with and
143    //EX: headerDP = buildDatepicker({"calendarID":"headerCalendar","linkedInputID":"headerCalendarInput","isModal":false,"forceDates":true, "defaultDate": "{{Output date from server Here}}"}); <~ would create a calendar object for the calendar presented at #headerCalendar, and link it to #headerCalendarInput
144    //most calendar methods are specific to the document the calendar resides on, and should be handled via the onChange event for the linked input
145    //Available Options:
146    //  calendarID (required)       == string, ID of calendar div
147    //  linkedInput (required)      == string, ID of input which will change when a date is selected
148    //  isModal                     == boolean, if true, calendar will be hidden, and display when the designated input recieves focus. If false, the calendar will be present and display as an inline block at all times.
149    //  forceDates                  == boolean, if true only highlighted dates will be clickable
150    //  detailedCalendar            == boolean, if true data is pulled to determine pricing information, sold out days, limited availablility - requires eventID
151    //  defaultDate                 == string, mm/dd/yyyy date that calendar should start on (this will only represent the month displayed at the begining)
152    //  type                        == string: defaults to "performancedates", which will add all visible performances
153    //  eventID                     == integer: defaults to -1 which means no event. Other values will filter by events with that ID, allowing for a search of performance dates for a specific event only
154    //  isMultiplePerformanceIndicator == boolean: if true, shows indicator for dates with multiple performance times
155    //
156    //Methods:
157    //  showDlg()/hideDlg()             : shows/hides modal calendars, no valid for non-modal calendars
158    //  addHighlightDay(mm/dd/yyyy)     : adds a date (presented as a mm/dd/yyyy string) to the list of highlight dates for the calendar - REQUIRES HighlightDays() function call to visually represent this change on the calendar
159    //  clearHihghlightDays()           : removes all stored highlight dates
160    //  highlightDays()                 : adds highlight class to stored days, visually highlighting them ont he calendar.
161    
162    var myID = options.calendarID; //required
163    var myLinkedInput = options.linkedInputID; //required
164    var isModal = options.isModal || false;
165    var showLoader = options.showLoader || false;
166    var forceDates = options.forceDates || false;
167    var myDefault = new Date();
168    if (options.defaultDate) {
169        try{
170            
171            myDefault = new Date(options.defaultDate);
172        } catch (e) {
173            console.log("date no valid for calendar: " + myID);
174            console.log(e);
175        }
176    }
177    var type = options.type || "performancedates";
178    var eventID = options.eventID || -1;
179    var detailedCalendar = options.detailedCalendar && eventID != -1 || false;
180    var bundleID = options.bundleID || -1;
181    var categoryID = options.CategoryID || -1;
182    var corporatePartnerPage = options.corporatePartnerPage || 0;
183    var bValidCoupon = options.bValidCoupon || 0;
184    var couponCode = options.couponCode || "";
185    var isMultiplePerformanceIndicator = options.isMultiplePerformanceIndicatorFlag || 0;
186
187    return new swDatepicker(myID, myLinkedInput, isModal, showLoader, forceDates, detailedCalendar, myDefault, type, eventID, bundleID, categoryID, corporatePartnerPage,bValidCoupon,couponCode,isMultiplePerformanceIndicator)
188}
189function swDatepicker(id, target, modal, loader, force, detailed, defaultDate, type, eventID, bundleID, categoryID, corporatePartnerPage,bValidCoupon,couponCode,isMultiplePerformanceIndicator) {
190
191    this.$id = $('#' + id); // element to attach widget to
192    this.$monthObj = this.$id.find('.month');
193    this.$prev = this.$id.find('.bn_prev');
194    this.$next = this.$id.find('.bn_next');
195    this.$grid = this.$id.find('.cal');
196    this.$target = $('#' + target); // div or text box that will receive the selected date string and focus (if modal)
197    this.bModal = modal; // true if datepicker should appear in a modal dialog box.
198    this.showLoader = loader;
199    this.forceDateSelection = force; //if true, will only allow users to click on highlighted dates - see addHighlightDay()
200    this.detailedCalendar = detailed;
201    this.active = !modal;
202    this.type = type;
203    this.eventID = eventID;
204    this.bundleID = bundleID;
205    this.categoryID = categoryID;
206    this.corporatePartnerPage = corporatePartnerPage;
207    this.fromDateRange = "";
208    this.toDateRange = "";
209    this.dateRangeEvents = [];
210    this.calendarName = id;
211
212    this.monthNames = ['January', 'February', 'March', 'April', 'May', 'June',
213    'July', 'August', 'September', 'October', 'November', 'December'];
214
215    this.dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
216
217    this.dateObj = new Date();
218
219    this.curYear = this.dateObj.getFullYear();
220    this.year = defaultDate.getFullYear();
221
222    this.curMonth = this.dateObj.getMonth();
223    this.month = defaultDate.getMonth();
224    this.getFirstDate(defaultDate.getMonth()); //update the month to the first performance ASAP
225
226    this.curDate = this.dateObj.getDate();
227    this.date = defaultDate.getDate();
228    this.currentDate = (this.month == this.curMonth && this.year == this.curYear);
229    this.activeMonth = (String(this.month + 1) + "/1/" + this.year);
230
231    this.keys = {
232        tab: 9,
233        enter: 13,
234        esc: 27,
235        space: 32,
236        pageup: 33,
237        pagedown: 34,
238        end: 35,
239        home: 36,
240        left: 37,
241        up: 38,
242        right: 39,
243        down: 40
244    };
245
246    this.bValidCoupon = bValidCoupon;
247    this.couponCode = couponCode;
248    this.isMultiplePerformanceIndicator = isMultiplePerformanceIndicator;
249
250    this.highlightDates = [];    
251
252    // display the current month
253    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
254
255    // populate the calendar grid
256    this.popGrid();
257
258    // update the table's activedescdendant to point to the current day
259    this.$grid.attr('aria-activedescendant', this.$grid.find('.today').attr('id'));
260
261    this.bindHandlers();
262
263    //show selected day
264        $('#' + this.calendarName + '-day' + this.date).addClass('focus').attr('aria-selected', 'true');
265
266    // hide dialog if in modal mode
267    if (this.bModal == true) {
268        this.$id.attr('aria-hidden', 'true');
269        //show/hide functionality may vary based on use, so should be handled after the datepicker is created.
270        //if we're on mobile, disable keyboard for the input:
271        if ($(window).width() < 1024) {
272            this.$target.attr("readonly", "true");
273        }
274    }
275
276    this.currencySymbol = "$";
277    this.buyTicketsButtonText = "Buy Tickets";
278}
279
280//
281// popGrid() is a member function to populate the datepicker grid with calendar days
282// representing the current month
283//
284// @return N/A
285//
286swDatepicker.prototype.popGrid = function () {
287    if(this.showLoader)
288        $(".calendar-loading").show();
289    var numDays = this.calcNumDays(this.year, this.month);
290    var startWeekday = this.calcStartWeekday(this.year, this.month);
291    //var lastMonth = this.month - 1;
292    //var lastMonthYear = this.year;
293    var weekday = 0;
294    var curDay = 1;
295    var rowCount = 1;
296    var $tbody = this.$grid.find('tbody');
297
298    var currentDateDay = this.dateObj.getDate();
299    var currentDateMonth = this.dateObj.getMonth();
300    var currentDateYear = this.dateObj.getFullYear();
301
302    var gridCells = '\t<tr id="row1">\n';
303
304    // Keeping in case the client (Gaylord) pushes back on not having previous month's dates selectable
305    // If the last month is -1, roll it over to December (11) and subtract 1 from the last month's year
306    /*if (lastMonth < 0) {
307        lastMonth = 11;
308        lastMonthYear = lastMonthYear - 1;
309    }
310
311    var lastMonthNumDays = this.calcNumDays(lastMonthYear, lastMonth);
312    var lastMonthStartDay = lastMonthNumDays - (startWeekday - 1);*/
313
314    // clear the grid
315    $tbody.empty();
316    $('#msg').empty();
317
318    // Keeping in case the client (Gaylord) pushes back on not having previous month's dates selectable
319    // Insert the leading empty cells
320    /*for (var weekday = 0; weekday < startWeekday; weekday++) {
321        gridCells += '\t\t<td id="' + this.calendarName + '-day' + lastMonthStartDay + '" class="day-cell muted last-month" headers="row' +
322            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false" data-year="' + lastMonthYear + '"><span class="calendar-day notranslate" data-month="' + lastMonth + '">' + lastMonthStartDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
323        //gridCells += '\t\t<td class="empty" data-month="' + lastMonth + '" data-year="' + lastMonthYear + '" data-day="' + lastMonthStartDay + '">&nbsp;</td>\n';
324        lastMonthStartDay++;
325    }*/
326
327    for (var weekday = 0; weekday < startWeekday; weekday++) {
328        gridCells += '\t\t<td class="empty">&nbsp;</td>\n';
329    }
330
331    // insert the days of the month.
332    for (curDay = 1; curDay <= numDays; curDay++) {
333
334        if (curDay == this.curDate && this.currentDate == true) {
335
336            gridCells += '\t\t<td id="' + this.calendarName + '-day' + curDay + '" class="today day-cell" aria-label="row' +
337            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false"><span class="calendar-day notranslate">' + curDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
338        }
339        else {
340            var addMuted = "";
341
342            // Only mute dates in the past for the date range selector widget
343            if (this.type == 'dateRangeSelect') {
344                // If the year is in the past, or the year is the same but the month is in the past, or the month and year are the same but the day is in the past, mute the date
345                if (this.year < currentDateYear
346                    || (this.year == currentDateYear && this.month < currentDateMonth)
347                    || (this.year == currentDateYear && this.month == currentDateMonth && curDay < currentDateDay)
348                ) {
349                    addMuted = " muted";
350                }
351            }
352            
353            gridCells += '\t\t<td id="' + this.calendarName + '-day' + curDay + '" class="day-cell' + addMuted + '" aria-label="row' +
354            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false"><span class="calendar-day notranslate">' + curDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
355        }
356
357
358        if (weekday == 6 && curDay < numDays) {
359            // This was the last day of the week, close it out
360            // and begin a new one
361            gridCells += '\t</tr>\n\t<tr id="row' + rowCount + '">\n';
362            rowCount++;
363            weekday = 0;
364        }
365        else {
366            weekday++;
367        }
368    }
369
370    // Insert any trailing empty cells
371    for (weekday; weekday < 7; weekday++) {
372
373        gridCells += '\t\t<td class="empty">&nbsp;</td>\n';
374    }
375
376    gridCells += '\t</tr>';
377
378    $tbody.append(gridCells);
379    if(this.detailedCalendar){
380        this.getCalendarDetails();
381    }else{
382        this.fetchDates();
383    }
384    
385}
386
387//
388// calcNumDays() is a member function to calculate the number of days in a given month
389//
390// @return (integer) number of days
391//
392swDatepicker.prototype.calcNumDays = function (year, month) {
393
394    return 32 - new Date(year, month, 32).getDate();
395}
396
397//
398// calcstartWeekday() is a member function to calculate the day of the week the first day of a
399// month lands on
400//
401// @return (integer) number representing the day of the week (0=Sunday....6=Saturday)
402//
403swDatepicker.prototype.calcStartWeekday = function (year, month) {
404
405    return new Date(year, month, 1).getDay();
406
407} // end calcStartWeekday()
408
409//
410// showPrevMonth() is a member function to show the previous month
411//
412// @param (offset int) offset may be used to specify an offset for setting
413//                      focus on a day the specified number of days from
414//                      the end of the month.
415// @return N/A
416//
417swDatepicker.prototype.showPrevMonth = function (offset) {
418    // show the previous month
419    if (this.month < 1) {
420        this.month = 11;
421        this.year--;
422    }
423    else {
424        this.month--;
425    }
426
427    if (this.month != this.curMonth || this.year != this.curYear) {
428        this.currentDate = false;
429    }
430    else {
431        this.currentDate = true;
432    }
433
434    this.activeMonth = (String(this.month + 1) + "/1/" + this.year)
435
436    // populate the calendar grid
437    this.popGrid();
438
439    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
440
441    // if offset was specified, set focus on the last day - specified offset
442    if (offset != null) {
443        var numDays = this.calcNumDays(this.year, this.month);
444        var day = 'day' + (numDays - offset);
445
446        this.$grid.attr('aria-activedescendant', this.calendarName + '-' + day);
447        $('#' + this.calendarName + '-' + day).addClass('focus').attr('aria-selected', 'true');
448    }
449
450
451} // end showPrevMonth()
452
453//
454// showNextMonth() is a member function to show the next month
455//
456// @param (offset int) offset may be used to specify an offset for setting
457//                      focus on a day the specified number of days from
458//                      the beginning of the month.
459// @return N/A
460//
461swDatepicker.prototype.showNextMonth = function (offset) {
462
463    // show the next month
464    if (this.month == 11) {
465        this.month = 0;
466        this.year++;
467    }
468    else {
469        this.month++;
470    }
471
472    if (this.month != this.curMonth || this.year != this.curYear) {
473        this.currentDate = false;
474    }
475    else {
476        this.currentDate = true;
477    }
478
479    this.activeMonth = (String(this.month + 1) + "/1/" + this.year)
480
481    // populate the calendar grid
482    this.popGrid();
483
484    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
485
486    // if offset was specified, set focus on the first day + specified offset
487    if (offset != null) {
488        var day = 'day' + offset;
489
490        this.$grid.attr('aria-activedescendant', this.calendarName + '-' + day);
491        $('#' + this.calendarName + '-' + day).addClass('focus').attr('aria-selected', 'true');
492    }
493
494} // end showNextMonth()
495
496//
497// showPrevYear() is a member function to show the previous year
498//
499// @return N/A
500//
501swDatepicker.prototype.showPrevYear = function () {
502
503    // decrement the year
504    this.year--;
505
506    if (this.month != this.curMonth || this.year != this.curYear) {
507        this.currentDate = false;
508    }
509    else {
510        this.currentDate = true;
511    }
512
513    // populate the calendar grid
514    this.popGrid();
515
516    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
517
518} // end showPrevYear()
519
520//
521// showNextYear() is a member function to show the next year
522//
523// @return N/A
524//
525swDatepicker.prototype.showNextYear = function () {
526
527    // increment the year
528    this.year++;
529
530    if (this.month != this.curMonth || this.year != this.curYear) {
531        this.currentDate = false;
532    }
533    else {
534        this.currentDate = true;
535    }
536
537    // populate the calendar grid
538    this.popGrid();
539
540    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
541
542} // end showNextYear()
543
544//
545// bindHandlers() is a member function to bind event handlers for the widget
546//
547// @return N/A
548//
549swDatepicker.prototype.bindHandlers = function () {
550
551    var thisObj = this;
552
553    ////////////////////// bind button handlers //////////////////////////////////
554    this.$prev.click(function (e) {
555        return thisObj.handlePrevClick(e);
556    });
557
558    this.$next.click(function (e) {
559        return thisObj.handleNextClick(e);
560    });
561
562    this.$prev.keydown(function (e) {
563        return thisObj.handlePrevKeyDown(e);
564    });
565
566    this.$next.keydown(function (e) {
567        return thisObj.handleNextKeyDown(e);
568    });
569
570    ///////////// bind grid handlers //////////////
571
572    this.$grid.keydown(function (e) {
573        return thisObj.handleGridKeyDown(e);
574    });
575
576    this.$grid.keypress(function (e) {
577        return thisObj.handleGridKeyPress(e);
578    });
579
580    this.$grid.focus(function (e) {
581        return thisObj.handleGridFocus(e);
582    });
583
584    this.$grid.blur(function (e) {
585        return thisObj.handleGridBlur(e);
586    });
587
588    this.$grid.delegate('td', 'click', function (e) {
589        return thisObj.handleGridClick(this, e);
590    });
591
592} // end bindHandlers();
593
594function scrollToFirstHighlightDay() {
595    // find all the heights of elements before the calendar
596    var EventInfoHeight = $('#EventInformationWrap').outerHeight() + 64; // 64 is the height mobile navigation
597    var EventLabelAndOptionsHeight = $('#eventCalendarLabelAndOptions').outerHeight(); 
598    var CalendarMonthHeight =  $('.sw-datepicker.large-datepicker .month-wrap').outerHeight(); 
599
600    var EventInfoAndOptionsHeight = EventInfoHeight + EventLabelAndOptionsHeight;
601    var CalendarTopInfoHeaderHeights = EventInfoHeight + EventLabelAndOptionsHeight + CalendarMonthHeight + 10; // 10 is just a gap added so it is not sticking against the month section
602
603    // set the Top section sticky so when it focuses on the first hightlight day you can still see the informations 
604    $('#EventInformationWrap').addClass("make-this-section-sticky");
605    $('#eventCalendarLabelAndOptions').addClass("make-this-section-sticky");
606    $('#eventCalendarLabelAndOptions').css("top", EventInfoHeight);
607    $('.sw-datepicker.large-datepicker .month-wrap').addClass("make-this-section-sticky");
608    $('.sw-datepicker.large-datepicker .month-wrap').css("top", EventInfoAndOptionsHeight);
609
610    // Check if any elements with the class .highlight-day exist
611    var highlightDay = $('.performance-list-calendar .highlight-day').first();
612
613    // set the first day cell
614    var firstDayCel = $('.day-cell').first();
615    var scrollToPosition = 0;
616
617    if (highlightDay.length > 0) { // Get the offset only if .highlight-day element exists
618        scrollToPosition = highlightDay.offset().top;
619        scrollToPosition = scrollToPosition - CalendarTopInfoHeaderHeights;  
620        $('html, body').animate({scrollTop: scrollToPosition}, 'slow');
621    } else { // if there's no highlights on this month, focus on the first day of the month
622        scrollToPosition = firstDayCel.offset().top;
623        scrollToPosition = scrollToPosition - (CalendarTopInfoHeaderHeights * 2);
624        $('html, body').animate({scrollTop: scrollToPosition}, 'slow');
625    }
626}
627
628//
629// handlePrevClick() is a member function to process click events for the prev month button
630//
631// @input (e obj) e is the event object associated with the event
632//
633// @return (boolean) false if consuming event, true if propagating
634//
635swDatepicker.prototype.handlePrevClick = function (e) {
636    
637    var active = this.$grid.attr('aria-activedescendant');
638
639    if (e.ctrlKey) {
640        this.showPrevYear();
641    }
642    else {
643        this.showPrevMonth();
644    }
645
646    if (this.currentDate == false) {
647        this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
648    }
649    else {
650        this.$grid.attr('aria-activedescendant', active);
651    }
652
653    e.stopPropagation();
654    return false;
655
656} // end handlePrevClick()
657
658//
659// handleNextClick() is a member function to process click events for the next month button
660//
661// @input (e obj) e is the event object associated with the event
662//
663// @return (boolean) false if consuming event, true if propagating
664//
665swDatepicker.prototype.handleNextClick = function (e) {
666    
667    var active = this.$grid.attr('aria-activedescendant');
668
669    if (e.ctrlKey) {
670        this.showNextYear();
671    }
672    else {
673        this.showNextMonth();
674    }
675
676    if (this.currentDate == false) {
677        this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
678    }
679    else {
680        this.$grid.attr('aria-activedescendant', active);
681    }
682
683    e.stopPropagation();
684    return false;
685
686} // end handleNextClick()
687
688//
689// handlePrevKeyDown() is a member function to process keydown events for the prev month button
690//
691// @input (e obj) e is the event object associated with the event
692//
693// @return (boolean) false if consuming event, true if propagating
694//
695swDatepicker.prototype.handlePrevKeyDown = function (e) {
696
697    if (e.altKey) {
698        return true;
699    }
700
701    switch (e.keyCode) {
702        case this.keys.tab: {
703            if (this.bModal == false || !e.shiftKey || e.ctrlKey) {
704                return true;
705            }
706
707            this.$grid.focus();
708            e.stopPropagation();
709            return false;
710        }
711        case this.keys.enter:
712        case this.keys.space: {
713            if (e.shiftKey) {
714                return true;
715            }
716
717            if (e.ctrlKey) {
718                this.showPrevYear();
719            }
720            else {
721                this.showPrevMonth();
722            }
723
724            e.stopPropagation();
725            return false;
726        }
727    }
728
729    return true;
730
731} // end handlePrevKeyDown()
732
733//
734// handleNextKeyDown() is a member function to process keydown events for the next month button
735//
736// @input (e obj) e is the event object associated with the event
737//
738// @return (boolean) false if consuming event, true if propagating
739//
740swDatepicker.prototype.handleNextKeyDown = function (e) {
741
742    if (e.altKey) {
743        return true;
744    }
745
746    switch (e.keyCode) {
747        case this.keys.enter:
748        case this.keys.space: {
749
750            if (e.ctrlKey) {
751                this.showNextYear();
752            }
753            else {
754                this.showNextMonth();
755            }
756
757            e.stopPropagation();
758            return false;
759        }
760    }
761
762    return true;
763
764} // end handleNextKeyDown()
765
766//
767// handleGridKeyDown() is a member function to process keydown events for the datepicker grid
768//
769// @input (e obj) e is the event object associated with the event
770//
771// @return (boolean) false if consuming event, true if propagating
772//
773swDatepicker.prototype.handleGridKeyDown = function (e) {
774
775    var $rows = this.$grid.find('tbody tr');
776    var $curDay = $('#' + this.$grid.attr('aria-activedescendant'));
777    var $days = this.$grid.find('td').not('.empty');
778    var $curRow = $curDay.parent();
779
780    if (e.altKey) {
781        return true;
782    }
783
784    switch (e.keyCode) {
785        case this.keys.tab: {
786
787            if (this.bModal == true) {
788                if (e.shiftKey) {
789                    this.$next.focus();
790                }
791                else {
792                    this.$prev.focus();
793                }
794                e.stopPropagation()
795                return false;
796            }
797            break;
798        }
799        case this.keys.enter:
800        case this.keys.space: {
801
802            if (e.ctrlKey) {
803                return true;
804            }
805
806            // update the target box
807            this.$target.val((this.month + 1) + '/' + $curDay.find(".calendar-day").text() + '/' + this.year).change();
808
809            // fall through
810        }
811        case this.keys.esc: {
812            // dismiss the dialog box
813            this.hideDlg();
814
815            e.stopPropagation();
816            return false;
817        }
818        case this.keys.left: {
819
820            if (e.ctrlKey || e.shiftKey) {
821                return true;
822            }
823
824            var dayIndex = $days.index($curDay) - 1;
825            var $prevDay = null;
826
827            if (dayIndex >= 0) {
828                $prevDay = $days.eq(dayIndex);
829
830                $curDay.removeClass('focus').attr('aria-selected', 'false');
831                $prevDay.addClass('focus').attr('aria-selected', 'true');
832
833                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
834            }
835            else {
836                this.showPrevMonth(0);
837            }
838
839            e.stopPropagation();
840            return false;
841        }
842        case this.keys.right: {
843
844            if (e.ctrlKey || e.shiftKey) {
845                return true;
846            }
847
848            var dayIndex = $days.index($curDay) + 1;
849            var $nextDay = null;
850
851            if (dayIndex < $days.length) {
852                $nextDay = $days.eq(dayIndex);
853                $curDay.removeClass('focus').attr('aria-selected', 'false');
854                $nextDay.addClass('focus').attr('aria-selected', 'true');
855
856                this.$grid.attr('aria-activedescendant', $nextDay.attr('id'));
857            }
858            else {
859                // move to the next month
860                this.showNextMonth(1);
861            }
862
863            e.stopPropagation();
864            return false;
865        }
866        case this.keys.up: {
867
868            if (e.ctrlKey || e.shiftKey) {
869                return true;
870            }
871
872            var dayIndex = $days.index($curDay) - 7;
873            var $prevDay = null;
874
875            if (dayIndex >= 0) {
876                $prevDay = $days.eq(dayIndex);
877
878                $curDay.removeClass('focus').attr('aria-selected', 'false');
879                $prevDay.addClass('focus').attr('aria-selected', 'true');
880
881                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
882            }
883            else {
884                // move to appropriate day in previous month
885                dayIndex = 6 - $days.index($curDay);
886
887                this.showPrevMonth(dayIndex);
888            }
889
890            e.stopPropagation();
891            return false;
892        }
893        case this.keys.down: {
894
895            if (e.ctrlKey || e.shiftKey) {
896                return true;
897            }
898
899            var dayIndex = $days.index($curDay) + 7;
900            var $prevDay = null;
901
902            if (dayIndex < $days.length) {
903                $prevDay = $days.eq(dayIndex);
904
905                $curDay.removeClass('focus').attr('aria-selected', 'false');
906                $prevDay.addClass('focus').attr('aria-selected', 'true');
907
908                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
909            }
910            else {
911                // move to appropriate day in next month
912                dayIndex = 8 - ($days.length - $days.index($curDay));
913
914                this.showNextMonth(dayIndex);
915            }
916
917            e.stopPropagation();
918            return false;
919        }
920        case this.keys.pageup: {
921            var active = this.$grid.attr('aria-activedescendant');
922
923
924            if (e.shiftKey) {
925                return true;
926            }
927
928
929            if (e.ctrlKey) {
930                this.showPrevYear();
931            }
932            else {
933                this.showPrevMonth();
934            }
935
936            if ($('#' + active).attr('id') == undefined) {
937                var lastDay = 'day' + this.calcNumDays(this.year, this.month);
938                $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
939            }
940            else {
941                $('#' + this.calendarName + '-' + active).addClass('focus').attr('aria-selected', 'true');
942            }
943
944            e.stopPropagation();
945            return false;
946        }
947        case this.keys.pagedown: {
948            var active = this.$grid.attr('aria-activedescendant');
949
950
951            if (e.shiftKey) {
952                return true;
953            }
954
955            if (e.ctrlKey) {
956                this.showNextYear();
957            }
958            else {
959                this.showNextMonth();
960            }
961
962            if ($('#' + active).attr('id') == undefined) {
963                var lastDay = 'day' + this.calcNumDays(this.year, this.month);
964                $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
965            }
966            else {
967                $('#' + this.calendarName + '-' + active).addClass('focus').attr('aria-selected', 'true');
968            }
969
970            e.stopPropagation();
971            return false;
972        }
973        case this.keys.home: {
974
975            if (e.ctrlKey || e.shiftKey) {
976                return true;
977            }
978
979            $curDay.removeClass('focus').attr('aria-selected', 'false');
980
981            $('#' + this.calendarName + '-day1').addClass('focus').attr('aria-selected', 'true');
982
983            this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
984
985            e.stopPropagation();
986            return false;
987        }
988        case this.keys.end: {
989
990            if (e.ctrlKey || e.shiftKey) {
991                return true;
992            }
993
994            var lastDay = 'day' + this.calcNumDays(this.year, this.month);
995
996            $curDay.removeClass('focus').attr('aria-selected', 'false');
997
998            $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
999
1000            this.$grid.attr('aria-activedescendant', this.calendarName + '-' + lastDay);
1001
1002            e.stopPropagation();
1003            return false;
1004        }
1005    }
1006
1007    return true;
1008
1009} // end handleGridKeyDown()
1010
1011//
1012// handleGridKeyPress() is a member function to consume keypress events for browsers that
1013// use keypress to scroll the screen and manipulate tabs
1014//
1015// @input (e obj) e is the event object associated with the event
1016//
1017// @return (boolean) false if consuming event, true if propagating
1018//
1019swDatepicker.prototype.handleGridKeyPress = function (e) {
1020
1021    if (e.altKey) {
1022        return true;
1023    }
1024
1025    switch (e.keyCode) {
1026        case this.keys.tab:
1027        case this.keys.enter:
1028        case this.keys.space:
1029        case this.keys.esc:
1030        case this.keys.left:
1031        case this.keys.right:
1032        case this.keys.up:
1033        case this.keys.down:
1034        case this.keys.pageup:
1035        case this.keys.pagedown:
1036        case this.keys.home:
1037        case this.keys.end: {
1038            e.stopPropagation();
1039            return false;
1040        }
1041    }
1042
1043    return true;
1044
1045} // end handleGridKeyPress()
1046
1047//
1048// handleGridClick() is a member function to process mouse click events for the datepicker grid
1049//
1050// @input (id obj) e is the id of the object triggering the event
1051//
1052// @input (e obj) e is the event object associated with the event
1053//
1054// @return (boolean) false if consuming event, true if propagating
1055//
1056swDatepicker.prototype.handleGridClick = function (id, e) {
1057    var $cell = $(id);
1058
1059    if ($cell.is('.empty')) {
1060        return true;
1061    }
1062
1063    this.$grid.find('.focus').removeClass('focus').attr('aria-selected', 'false');
1064    $cell.addClass('focus').attr('aria-selected', 'true');
1065    this.$grid.attr('aria-activedescendant', $cell.attr('id'));
1066
1067    var $curDay = $('#' + this.$grid.attr('aria-activedescendant'));
1068
1069    /*console.log($curDay);
1070    var isLastMonth = $curDay.hasClass('last-month');
1071
1072    var monthSelected = this.month + 1;
1073    var yearSelected = this.year;
1074    
1075    if (isLastMonth) {
1076        monthSelected--;
1077        
1078        if (monthSelected == 0)
1079            monthSelected = 12;
1080
1081        yearSelected = $curDay.data('year');
1082    }
1083
1084    console.log("month selected: " + monthSelected);
1085    console.log("year selected: " + yearSelected);*/
1086
1087    // update the target box
1088    if(this.type == 'dateRangeSelect'){
1089        if ($curDay.hasClass('muted'))
1090            return true;
1091        
1092        var $rangeSelDate = new Date((this.month + 1) + '/' + $curDay.children('.calendar-day').text() + '/' + this.year);
1093        if(this.fromDateRange == '' && this.toDateRange == ''){
1094            //no dates selected yet, store this in the from date range for now
1095            this.fromDateRange = $rangeSelDate;
1096        }else{
1097            //we've previously selected at least one date here, so figure out which one it should be
1098            if($rangeSelDate < this.fromDateRange){
1099                this.toDateRange = this.fromDateRange;
1100                this.fromDateRange = $rangeSelDate;
1101            }else{
1102                this.toDateRange = $rangeSelDate;
1103            }
1104        }
1105        
1106        var objDateRange = {}
1107        objDateRange.from = this.fromDateRange;
1108        objDateRange.to = this.toDateRange;
1109        this.$target.val(JSON.stringify(objDateRange)).change();
1110        if(objDateRange.from != '' && objDateRange.to != ''){
1111            this.hideDlg(); //NOTE: this only works if the date range is a modal, for other calendars you'll need to manage display according to needs based on current values.
1112        }
1113        e.stopPropagation();
1114        return false;
1115    }
1116    if (!this.forceDateSelection || $cell.hasClass("highlight-day")) {
1117        this.$target.val((this.month + 1) + '/' + $curDay.children('.calendar-day').text() + '/' + this.year).change();
1118        // dismiss the dialog box
1119        this.hideDlg();
1120    }
1121    e.stopPropagation();
1122    return false;
1123
1124} // end handleGridClick()
1125
1126//
1127// handleGridFocus() is a member function to process focus events for the datepicker grid
1128//
1129// @input (e obj) e is the event object associated with the event
1130//
1131// @return (boolean) true
1132//
1133swDatepicker.prototype.handleGridFocus = function (e) {
1134    var active = this.$grid.attr('aria-activedescendant');
1135
1136    if ($('#' + active).attr('id') == undefined) {
1137        var lastDay = 'day' + this.calcNumDays(this.year, this.month);
1138        $('#' + lastDay).addClass('focus').attr('aria-selected', 'true');
1139    }
1140    else {
1141        $('#' + active).addClass('focus').attr('aria-selected', 'true');
1142    }
1143
1144    return true;
1145
1146} // end handleGridFocus()
1147
1148//
1149// handleGridBlur() is a member function to process blur events for the datepicker grid
1150//
1151// @input (e obj) e is the event object associated with the event
1152//
1153// @return (boolean) true
1154//
1155swDatepicker.prototype.handleGridBlur = function (e) {
1156    $('#' + this.$grid.attr('aria-activedescendant')).removeClass('focus').attr('aria-selected', 'false');
1157
1158    return true;
1159
1160} // end handleGridBlur()
1161
1162//
1163// showDlg() is a member function to show the datepicker and give it focus. This function is only called if
1164// the datepicker is used in modal dialog mode.
1165//
1166// @return N/A
1167//
1168swDatepicker.prototype.showDlg = function () {
1169    if (!this.bModal)
1170        return;
1171
1172    var thisObj = this;
1173    var thisNode = this.$id;
1174
1175    this.highlightDays();
1176
1177    this.active = true;
1178
1179    //prevent calendar from pushing out of the right side of the window
1180    if (thisNode.parent()[0].getBoundingClientRect().left > (window.innerWidth / 2))
1181        thisNode.addClass("right-side");
1182
1183    $(".content-wrap").bind('click', function (e) {
1184        if (!thisNode[0].contains(e.target) && e.target != thisObj.$target[0]) {
1185            thisObj.hideDlg();
1186        }
1187    });
1188
1189    // show the dialog
1190    this.$id.attr('aria-hidden', 'false');
1191
1192    this.$grid.focus();
1193
1194} // end showDlg()
1195
1196//
1197// hideDlg() is a member function to hide the datepicker and remove focus. This function is only called if
1198// the datepicker is used in modal dialog mode.
1199//
1200// @return N/A
1201//
1202swDatepicker.prototype.hideDlg = function () {
1203    if (!this.bModal)
1204        return;
1205    
1206    this.active = false;
1207    var thisNode = this.$id;
1208
1209    // unbind the modal event sinks
1210    $(document).unbind('click');
1211
1212    // hide the dialog
1213    this.$id.attr('aria-hidden', 'true');
1214
1215    // set focus on the focus target
1216    //this.$target.focus();
1217
1218} // end showDlg()
1219
1220//function to highlight days with performances or valid information
1221//to prevent rewriting the calendar each time a date is added, popGrid() should be called after all dates have been added
1222swDatepicker.prototype.addHighlightDay = function (date) {
1223    var datesplit = String(date).split("/");
1224    for(var i = 0;i < datesplit.length; i++){
1225        datesplit[i] = datesplit[i].replace(/^0+/, '');
1226    }
1227    date = datesplit.join("/");
1228    if (datesplit.length != 3) {
1229        //date didn't come in in m/d/yyyy format, kick it back in the console
1230        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1231        console.log(date);
1232        return;
1233
1234    }
1235    this.highlightDates.push(date);
1236    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1237        $("#" + this.calendarName + "-day" + datesplit[1]).addClass("highlight-day");
1238    }
1239}
1240swDatepicker.prototype.addDateInfoBox = function (date, infoBoxText) {
1241    var datesplit = String(date).split("/");
1242    for(var i = 0;i < datesplit.length; i++){
1243        datesplit[i] = datesplit[i].replace(/^0+/, '');
1244    }
1245    date = datesplit.join("/");
1246    if (datesplit.length != 3) {
1247        //date didn't come in in m/d/yyyy format, kick it back in the console
1248        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1249        console.log(date);
1250        return;
1251
1252    }
1253    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1254        $("#" + this.calendarName + "-day" + datesplit[1]).append('<span class="date-info-box">' + infoBoxText + '</span>');
1255    }
1256}
1257swDatepicker.prototype.addDateSubNote = function (date, noteText) {
1258    var datesplit = String(date).split("/");
1259    for(var i = 0;i < datesplit.length; i++){
1260        datesplit[i] = datesplit[i].replace(/^0+/, '');
1261    }
1262    date = datesplit.join("/");
1263    if (datesplit.length != 3) {
1264        //date didn't come in in m/d/yyyy format, kick it back in the console
1265        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1266        console.log(date);
1267        return;
1268
1269    }
1270    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1271        var spanClass = this.isMultiplePerformanceIndicator ? 'date-info-box date-sub-note multiple-performancetime-subnote' : 'date-info-box date-sub-note';
1272        $("#" + this.calendarName + "-day" + datesplit[1]).append('<span class="' + spanClass + '">' + noteText + '</span>');
1273    }
1274}
1275swDatepicker.prototype.setDaySoldOut = function (date) {
1276    var datesplit = String(date).split("/");
1277    for(var i = 0;i < datesplit.length; i++){
1278        datesplit[i] = datesplit[i].replace(/^0+/, '');
1279    }
1280    date = datesplit.join("/");
1281    if (datesplit.length != 3) {
1282        //date didn't come in in m/d/yyyy format, kick it back in the console
1283        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1284        console.log(date);
1285        return;
1286
1287    }
1288    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1289        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('sold-out');
1290        
1291        this.addDateInfoBox(date, "Sold Out");
1292        $("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
1293    }
1294}
1295swDatepicker.prototype.setcustomStatus = function (date,showPhoneNumber,currenStatus) {
1296    var datesplit = String(date).split("/");
1297    for(var i = 0;i < datesplit.length; i++){
1298        datesplit[i] = datesplit[i].replace(/^0+/, '');
1299    }
1300    date = datesplit.join("/");
1301    if (datesplit.length != 3) {
1302        //date didn't come in in m/d/yyyy format, kick it back in the console
1303        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1304        console.log(date);
1305        return;
1306
1307    }
1308    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1309        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('sold-out');
1310        var phoneNumber = " <br> [email protected] "
1311        if (!showPhoneNumber)
1312            phoneNumber="";
1313        this.addDateInfoBox(date, currenStatus +phoneNumber);
1314        
1315        $("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
1316    }
1317}
1318swDatepicker.prototype.setDayLimitedAvailabilty = function (date) {
1319    var datesplit = String(date).split("/");
1320    for(var i = 0;i < datesplit.length; i++){
1321        datesplit[i] = datesplit[i].replace(/^0+/, '');
1322    }
1323    date = datesplit.join("/");
1324    if (datesplit.length != 3) {
1325        //date didn't come in in m/d/yyyy format, kick it back in the console
1326        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1327        console.log(date);
1328        return;
1329
1330    }
1331    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1332        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('limited-availability');
1333        
1334        this.addDateSubNote(date, 'Selling Quickly');
1335        //$("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
1336    }
1337    if($(".limited-availability-legend-item").length == 0){
1338        
1339            $(".calendar-notes-wrap").append('<div class="limited-availability-legend-item"><span classs="calendar-limited-availability-legend-icon">!</span> - Selling Quickly</div>')
1340         
1341       // $("#streamlinedCalendarLimitedAvailabilityLegend").append('<div class="limited-availability-legend-item"><span class="calendar-limited-availability-legend-icon">!</span> - Selling Quickly</div>')
1342    }
1343}
1344swDatepicker.prototype.setMultiplePerformanceTimes = function (date) {
1345    var datesplit = String(date).split("/");
1346    for(var i = 0;i < datesplit.length; i++){
1347        datesplit[i] = datesplit[i].replace(/^0+/, '');
1348    }
1349    
1350    date = datesplit.join("/");
1351    if (datesplit.length != 3) {
1352        //date didn't come in in m/d/yyyy format, kick it back in the console
1353        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1354        return;
1355
1356    }
1357    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1358        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('multipleperformancetimes');
1359
1360    }
1361    if($(".multiple-performancetimes-notes").length == 0){
1362        
1363    }
1364    
1365}
1366swDatepicker.prototype.setMutedDay = function (date) {
1367    var datesplit = String(date).split("/");
1368    for(var i = 0;i < datesplit.length; i++){
1369        datesplit[i] = datesplit[i].replace(/^0+/, '');
1370    }
1371    date = datesplit.join("/");
1372    if (datesplit.length != 3) {
1373        //date didn't come in in m/d/yyyy format, kick it back in the console
1374        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1375        return;
1376
1377    }
1378    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1379        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('muted');
1380    }
1381}
1382swDatepicker.prototype.clearMutedDay = function (date) {
1383    var datesplit = String(date).split("/");
1384    for(var i = 0;i < datesplit.length; i++){
1385        datesplit[i] = datesplit[i].replace(/^0+/, '');
1386    }
1387    date = datesplit.join("/");
1388    if (datesplit.length != 3) {
1389        //date didn't come in in m/d/yyyy format, kick it back in the console
1390        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1391        return;
1392
1393    }
1394    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1395        $("#" + this.calendarName + "-day" + datesplit[1]).removeClass('muted');
1396    }
1397}
1398swDatepicker.prototype.setCouponMutedDay = function (date) {
1399    var datesplit = String(date).split("/");
1400    for(var i = 0;i < datesplit.length; i++){
1401        datesplit[i] = datesplit[i].replace(/^0+/, '');
1402    }
1403    date = datesplit.join("/");
1404    if (datesplit.length != 3) {
1405        //date didn't come in in m/d/yyyy format, kick it back in the console
1406        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1407        return;
1408
1409    }
1410    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1411        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('coupon-muted');
1412    }
1413}
1414swDatepicker.prototype.setPasswordHiddenDay = function (date) {
1415    var datesplit = String(date).split("/");
1416    for(var i = 0;i < datesplit.length; i++){
1417        datesplit[i] = datesplit[i].replace(/^0+/, '');
1418    }
1419    date = datesplit.join("/");
1420    if (datesplit.length != 3) {
1421        //date didn't come in in m/d/yyyy format, kick it back in the console
1422        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1423        return;
1424
1425    }
1426    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1427        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('password-hidden');
1428        $("#" + this.calendarName + "-day" + datesplit[1]).removeClass('highlight-day');
1429    }
1430}
1431swDatepicker.prototype.clearAllMutedDays = function () {
1432    $(".muted").removeClass('muted');
1433}
1434swDatepicker.prototype.clearHighlightDays = function () {
1435    this.highlightDates = [];
1436    this.highlightDays();
1437}
1438//highlights all days in the highlightDates array
1439swDatepicker.prototype.highlightDays = function () {
1440    $("#" + this.calendarName + " .highlight-day").removeClass("highlight-day");
1441    var curYear = this.year;
1442    var curMonth = this.month;
1443    var calName = this.calendarName;
1444    var IEFix = new RegExp(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g);
1445
1446    this.highlightDates.forEach(function (o, i, a) {
1447        var datesplit = o.split("/");
1448        if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
1449            $("#" + calName + "-day" + datesplit[1].replace(IEFix, '')).addClass("highlight-day");
1450        }
1451    });
1452    this.setColors();
1453}
1454swDatepicker.prototype.setColors = function () {
1455    /*
1456        Custom color functionality. Utilized by dropping calendar-colors.txt file in root of custom folder
1457        requires json content of text file formatted as follows:
1458        {
1459            "events":
1460                {"528": 
1461                    [
1462                        {"date":"12/1/2025", "color": "#ccc"}, 
1463                        {"date":"12/2/2025", "color": "#ccc"}
1464                    ]
1465                ,
1466                "529":
1467                    [
1468                        {"date":"12/8/2025", "color": "#ccc"}, 
1469                        {"date":"12/9/2025", "color": "#ccc"}
1470                    ]
1471                }
1472            ,
1473            "bundles":[],
1474            "generic":
1475                {"dates": 
1476                    [
1477                        {"date":"12/23/2025", "color": "#def"}, 
1478                        {"date":"12/22/2025", "color": "#1a1"}
1479                    ]
1480                ,
1481                "weekdays":
1482                    [
1483                        {"day":"Saturday", "color": "#2a2"}, 
1484                        {"day":"Thursday", "color": "#3a3"}
1485                    ]
1486                }    
1487        }
1488    }
1489    */
1490    var thisDP = this;
1491    try{
1492        $.getJSON("/calendar-colors.txt")
1493        .done(function (data) {
1494            thisDP.renderColors(data);
1495        })
1496        .fail(function (jqxhr, textStatus, error) {
1497            console.log("No Custom Calendar Colors Found");
1498            return;
1499        });
1500    }catch(e){
1501        console.log("parsing error:");
1502        console.log(e);
1503        return;
1504    }
1505}
1506swDatepicker.prototype.renderColors = function (colorData) {
1507    var curYear = this.year;
1508    var curMonth = this.month;
1509    var calName = this.calendarName;
1510    var IEFix = new RegExp(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g);
1511    //set generic colors
1512    if(colorData.generic){
1513        if(colorData.generic.dates.length > 0){
1514            colorData.generic.dates.forEach(function (o, i, a) {
1515                var datesplit = o.date.split("/");
1516                if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
1517                    $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
1518                }
1519            });
1520        }
1521        if(colorData.generic.weekdays && colorData.generic.weekdays.length > 0){
1522            colorData.generic.weekdays.forEach(function (o, i, a) {
1523                $("td[headers*=" + o.day + "] .calendar-day").css("background-color", o.color);
1524            });
1525        }
1526    }
1527    if(colorData.events && colorData.events[this.eventID] && this.eventID !== -1){
1528        colorData.events[this.eventID].forEach(function (o, i, a) {
1529            var datesplit = o.date.split("/");
1530            if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
1531                $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
1532            }
1533        });
1534    }
1535    if(colorData.bundles && colorData.bundles[this.bundleID] && this.bundleID !== -1){
1536        colorData.bundles[this.bundleID].forEach(function (o, i, a) {
1537            var datesplit = o.date.split("/");
1538            if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
1539                $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
1540            }
1541        });
1542    }
1543}
1544swDatepicker.prototype.fetchDates = function(){
1545    var thisCalendar = this;
1546    var haveDates = thisCalendar.fetchLocalDates();
1547    if (thisCalendar.categoryID >= 0)
1548        haveDates = false;
1549    this.clearHighlightDays();
1550    if(haveDates){
1551        //valid local dates stored
1552        try{
1553            haveDates = JSON.parse(haveDates);
1554            if (haveDates.length > 0) {
1555                haveDates.forEach(function(o){
1556                    thisCalendar.addHighlightDay(o);
1557                })
1558                thisCalendar.highlightDays();
1559            }
1560        } catch (e) {
1561            console.log("Failed to grab dates. Date object not valid: ", haveDates);
1562            console.log(e);
1563        }
1564    } else {        
1565        $.getJSON("/include/widgets/calendar/calendarRequests.asp",
1566            {
1567                action: thisCalendar.type,
1568                calMonth: thisCalendar.activeMonth,
1569                iEvent: thisCalendar.eventID,
1570                iBundle: thisCalendar.bundleID,
1571                iCategory : thisCalendar.categoryID,
1572                cp : thisCalendar.corporatePartnerPage
1573            })
1574            .done(function (data) {
1575                thisCalendar.storeDates(data.performancedates);
1576                try {
1577                    if (data.performancedates.length > 0) {
1578                        data.performancedates.forEach(function (o) {
1579                            
1580                            thisCalendar.addHighlightDay(o);
1581                        })
1582                        thisCalendar.highlightDays();
1583                    }
1584                } catch (e) {
1585                    console.log("Failed to grab dates. Date object not valid: " + haveDates);
1586                    console.log(e);
1587                }
1588                $(".calendar-loading").hide();
1589            })
1590            .fail(function (jqxhr, textStatus, error) {
1591                var err = textStatus + ", " + error;
1592                console.log("Request Failed: " + err);
1593                $(".calendar-loading").hide();
1594            });
1595    }
1596}
1597swDatepicker.prototype.getCalendarDetails = function(){
1598    var thisCalendar = this;
1599    this.clearHighlightDays();
1600    $("#" + this.calendarName).removeClass("has-muted-days");
1601    $.getJSON("/include/widgets/calendar/calendarRequests.asp",
1602        {
1603            action: thisCalendar.type,
1604            calMonth: thisCalendar.activeMonth,
1605            iEvent: thisCalendar.eventID,
1606            iBundle: thisCalendar.bundleID,
1607            iCategory : thisCalendar.categoryID,
1608            cp : thisCalendar.corporatePartnerPage,
1609            bValidCoupon : thisCalendar.bValidCoupon,
1610            couponCode : thisCalendar.couponCode
1611        })
1612        .done(function (data) {
1613            //to save on request time, we need to resolve the data on the client a bit before we store it
1614            var performanceDates = [];
1615            data.performanceDateData.forEach(function(dd){
1616                
1617                if(dd.DoNotShowPublic == 0){
1618                    var detailsObj = {};
1619                    var currentDateIndex = fetchDateIndex(dd.CalendarDate, performanceDates);
1620                    if(currentDateIndex == -1){
1621                        detailsObj.date = dd.CalendarDate;
1622                        detailsObj.performances = [];
1623                        detailsObj.performances.push(dd.PerformanceCode);
1624                        detailsObj.defaultPrice = dd.LowestDefaultPrice;
1625                        detailsObj.PerformanceName = dd.PerformanceName;
1626                        detailsObj.PerformanceTime = dd.PerfTime;
1627                        detailsObj.PerformanceStartTimeAlias = dd.PerformanceStartTimeAlias;
1628                        detailsObj.DisplayType = dd.DisplayType;
1629                        detailsObj.CalendarViewShowPrice = dd.CalendarViewShowPrice;
1630                        detailsObj.CalendarViewShowPerformanceName = dd.CalendarViewShowPerformanceName;
1631                        detailsObj.CalendarViewShowPerformanceTime = dd.CalendarViewShowPerformanceTime;
1632                        detailsObj.CalendarViewShowBuyButton = dd.CalendarViewShowBuyButton;
1633                        detailsObj.defaultPricingCode = dd.LowestDefaultPricingCode;
1634                        detailsObj.secondaryPrice = dd.LowestSecondaryPrice;
1635                        detailsObj.secondaryPricingCode =dd.LowestSecondaryPricingCode;
1636                        detailsObj.NoCouponAvailable = dd.NoCouponAvailable;
1637                        detailsObj.passwordMatch = dd.passwordMatch;
1638                        detailsObj.qualifierPasswordMatch = dd.qualifierPasswordMatch;
1639                        detailsObj.hasPassword = dd.hasPassword;
1640                        detailsObj.hasQualifierPassword = dd.hasQualifierPassword;
1641                        detailsObj.hasCoupons = dd.hasCoupons; 
1642                        detailsObj.IsSalesPeriodEnded = dd.IsSalesPeriodEnded;
1643                        detailsObj.SaleIcon = dd.SaleIcon;
1644                        detailsObj.BSaleIcon = dd.BSaleIcon;
1645                        
1646                        detailsObj.hasQualifiers = dd.hasQualifiers;
1647                        performanceDates.push(detailsObj)
1648                       
1649                    }else{
1650                        performanceDates[currentDateIndex].performances.push(dd.PerformanceCode);
1651                        performanceDates[currentDateIndex].NoCouponAvailable = dd.NoCouponAvailable;
1652                        performanceDates[currentDateIndex].passwordMatch = dd.passwordMatch;
1653                        performanceDates[currentDateIndex].acMatch = dd.acMatch;
1654                        performanceDates[currentDateIndex].qualifierPasswordMatch = dd.qualifierPasswordMatch;
1655                        performanceDates[currentDateIndex].hasPassword = dd.hasPassword;
1656                        performanceDates[currentDateIndex].hasQualifierPassword = dd.hasQualifierPassword;
1657                        performanceDates[currentDateIndex].hasCoupons = dd.hasCoupons;
1658                        performanceDates[currentDateIndex].PerformanceName = dd.PerformanceName;
1659                        performanceDates[currentDateIndex].PerformanceTime = dd.PerfTime;
1660                        performanceDates[currentDateIndex].PerformanceStartTimeAlias = dd.PerformanceStartTimeAlias;
1661                        performanceDates[currentDateIndex].CalendarViewShowPrice = dd.CalendarViewShowPrice;
1662                        performanceDates[currentDateIndex].CalendarViewShowPerformanceName = dd.CalendarViewShowPerformanceName;
1663                        performanceDates[currentDateIndex].CalendarViewShowPerformanceTime = dd.CalendarViewShowPerformanceTime;
1664                        performanceDates[currentDateIndex].CalendarViewShowBuyButton = dd.CalendarViewShowBuyButton;
1665                        performanceDates[currentDateIndex].IsSalesPeriodEnded = dd.IsSalesPeriodEnded;
1666                        performanceDates[currentDateIndex].SaleIcon = dd.SaleIcon;
1667                        performanceDates[currentDateIndex].BSaleIcon = dd.BSaleIcon;                        
1668                        performanceDates[currentDateIndex].hasQualifiers = dd.hasQualifiers;
1669                        //check for lowest price
1670                        if(performanceDates[currentDateIndex].defaultPrice > dd.LowestDefaultPrice && dd.LowestDefaultPrice != null){
1671                            performanceDates[currentDateIndex].defaultPrice = dd.LowestDefaultPrice;
1672                            performanceDates[currentDateIndex].defaultPricingCode = dd.LowestDefaultPricingCode;
1673                        }
1674                        if(performanceDates[currentDateIndex].hasCoupons == 1 && performanceDates[currentDateIndex].defaultPrice < dd.LowestDefaultPrice && dd.LowestDefaultPrice != null && false){
1675                            performanceDates[currentDateIndex].defaultPrice = dd.LowestDefaultPrice;
1676                            performanceDates[currentDateIndex].defaultPricingCode = dd.LowestDefaultPricingCode;
1677                        }
1678                        if(performanceDates[currentDateIndex].secondaryPrice > dd.LowestSecondaryPrice && dd.LowestSecondaryPrice != null){
1679                            performanceDates[currentDateIndex].secondaryPrice = dd.LowestSecondaryPrice;
1680                            performanceDates[currentDateIndex].secondaryPricingCode = dd.LowestSecondaryPricingCode;
1681                        }
1682                         
1683                        
1684                    }
1685                    //set limited availaibility by matching up results from query with performances
1686                    for(perf in data.performances){
1687                        if(data.performances[perf].id == dd.PerformanceID){
1688                            data.performances[perf].LimitedAvailability = dd.LimitedAvailability;
1689                            data.performances[perf].TimeZone = dd.TimeZone.replace('"', "");
1690                            data.performances[perf].SingleAreaVenueAreaID = dd.SingleAreaVenueAreaID;
1691                            data.performances[perf].NoCouponAvailable = dd.NoCouponAvailable;
1692                            data.performances[perf].passwordMatch = dd.passwordMatch;
1693                            data.performances[perf].acMatch = dd.acMatch;
1694                            data.performances[perf].qualifierPasswordMatch = dd.qualifierPasswordMatch;
1695                            data.performances[perf].hasPassword = dd.hasPassword;
1696                            data.performances[perf].hasQualifierPassword = dd.hasQualifierPassword;
1697                        }
1698                    }
1699                }
1700                
1701            })
1702            
1703            data.performanceDates = performanceDates;
1704            delete data.performanceDateData;
1705            try {
1706                if (thisCalendar.couponCode != "" && $("#couponCode").length > 0)
1707                {
1708                    if($("#coupon-notify").length > 0)
1709                        $("#coupon-notify").remove();
1710
1711                    var notifyMessage = document.createElement("div");
1712                    notifyMessage.setAttribute("id","coupon-notify");
1713                    notifyMessage.setAttribute("class",data.hasValidCoupon ? 'coupon-notify-message' : 'coupon-error-message');
1714                    notifyMessage.innerHTML = (data.hasValidCoupon ? "Code <b>" + thisCalendar.couponCode + "</b> has been applied to valid dates and times." : "The code entered is either invalid, or no longer available.");
1715                    $("#plCalendar").prepend(notifyMessage);
1716                    window.scrollTo(0,0);
1717                }                
1718                
1719                thisCalendar.doCalendarDetailed(data);
1720            } catch (e) {
1721                console.log("Failed to parse details. Date object not valid: ", data);
1722                console.log(e);
1723            }
1724        })
1725        .fail(function (jqxhr, textStatus, error) {
1726            var err = textStatus + ", " + error;
1727            console.log("Request Failed: " + err);
1728        });
1729}
1730swDatepicker.prototype.doCalendarDetailed = function(detailData){
1731    var thisCalendar = this;
1732    this.detailData = detailData;
1733    var defaultPricingLegend = [], secondaryPricingLegend = [];
1734    detailData.performanceDates.forEach(function(d){
1735        thisCalendar.addHighlightDay(d.date);
1736        if (d.NoCouponAvailable > 0)
1737            thisCalendar.setCouponMutedDay(d.date);
1738        
1739        //check if date sold out
1740        var dateSoldOut = true;
1741        var customStatus = false;
1742        var showPhoneNumber =false;
1743        var dateLimitedAvailability = false;
1744        var performanceStatus="";
1745        var performanceOnSale = false;
1746        var IsSalesPeriodEnded = false;
1747        var aggregatedMentaInfo = {
1748            buttonVisible: false,
1749            buttonText: "",
1750            buttonUrl: "",
1751            totalCount: 0
1752        };
1753
1754        var isMentaResaleAvailable = false;
1755        var performanceTimesLength = 0;
1756        var QualiferButton = false;
1757        d.performances.forEach(function(datePerformance){
1758            var performanceKey = String(datePerformance).toLowerCase();
1759            var currentPerformance = detailData.performances[performanceKey];
1760
1761            if (!currentPerformance) {
1762                var perfIndex = d.performances.indexOf(datePerformance);
1763                if (perfIndex !== -1) {
1764                    d.performances.splice(perfIndex, 1);
1765                }
1766                console.log("Date Trimmed, child performance not contained in performance data: " + datePerformance);
1767                return;
1768            }
1769
1770            //let currentPerformance = detailData.performances[String(datePerformance).toLowerCase()];
1771            performanceTimesLength ++;
1772
1773            if(detailData.performances[String(datePerformance).toLowerCase()] && detailData.performances[String(datePerformance).toLowerCase()].status == "On Sale"){
1774                dateSoldOut = false;
1775                performanceOnSale=true;
1776                if(currentPerformance.LimitedAvailability == 1)
1777                    dateLimitedAvailability = true;
1778                        
1779                IsSalesPeriodEnded  =   currentPerformance.IsSalesPeriodEnded==1        
1780            }            
1781            else{
1782                
1783                if ((currentPerformance.status != "Sold Out") && (currentPerformance.status != "On Sale")  ){
1784                    
1785                    customStatus=true;
1786                    performanceStatus=currentPerformance.status;
1787                    dateSoldOut = false;
1788                    //dateLimitedAvailability=false;
1789                    if ( currentPerformance.bSalePhone==1 || currentPerformance.SalePhone==1){
1790                        showPhoneNumber=true;
1791                    }
1792                }
1793                var mentaMarketplace = currentPerformance.MentaMarketplace;
1794                var hasMentaOption = currentPerformance.IsMentaEnabled == 1 && mentaMarketplace && mentaMarketplace.buttonVisible;
1795
1796                if (hasMentaOption) {
1797                    var availableCount = parseInt(mentaMarketplace.totalCount, 10);
1798                    if (!isNaN(availableCount) && availableCount > 0) {
1799                        aggregatedMentaInfo.totalCount += availableCount;
1800                    }
1801                    if (mentaMarketplace.buttonText && aggregatedMentaInfo.buttonText === "") {
1802                        aggregatedMentaInfo.buttonText = mentaMarketplace.buttonText;
1803                    }
1804                    if (mentaMarketplace.buttonUrl && aggregatedMentaInfo.buttonUrl === "") {
1805                        aggregatedMentaInfo.buttonUrl = mentaMarketplace.buttonUrl;
1806                    }
1807                    aggregatedMentaInfo.buttonVisible = true;
1808                    dateSoldOut = false;
1809                    showPhoneNumber=false;
1810                    customStatus=true;
1811                }
1812            }
1813           
1814            // If date is sold out or custom status (not 'on sale'), check if qualifier access code or password match
1815            if (dateSoldOut || customStatus) {
1816                if (currentPerformance.acMatch == 1 || (currentPerformance.qualifierPasswordMatch == 1 && currentPerformance.hasQualifierPassword == 1)) {
1817                    dateSoldOut = false;
1818                    customStatus = false;
1819                    performanceOnSale = true;
1820                    showPhoneNumber = false;
1821                }
1822            }
1823            // If date is sold out or custom status (not 'on sale'), check if it has a public qualifier -- hasQualifiers is set on CalendarRequests.asp when qualifiers exist for performance
1824            if (currentPerformance.hasQualifiers) {
1825                    dateSoldOut = false;
1826                    customStatus = false;
1827                    performanceOnSale = true;
1828                    showPhoneNumber = false;
1829                    QualiferButton = true;
1830                  // If performance has qualifier but status is "On Sale", do not show "Premium Access" text on calendar date
1831                  if (currentPerformance.status == "On Sale") {
1832                    QualiferButton = false;
1833                 } 
1834                 
1835            }
1836        })
1837
1838        if (aggregatedMentaInfo.buttonVisible && aggregatedMentaInfo.buttonText === "") {
1839            aggregatedMentaInfo.buttonText = "Official Resale Available";
1840        }
1841        var hasMentaCtaForDate = aggregatedMentaInfo.buttonVisible && (aggregatedMentaInfo.totalCount > 0 || aggregatedMentaInfo.buttonUrl !== "");
1842        isMentaResaleAvailable = hasMentaCtaForDate && !performanceOnSale;
1843        d.MentaMarketplace = aggregatedMentaInfo;
1844        
1845        if(dateLimitedAvailability && !dateSoldOut){
1846            thisCalendar.setDayLimitedAvailabilty(d.date);
1847        }
1848        if (thisCalendar.isMultiplePerformanceIndicator == 1 && performanceTimesLength > 1) {
1849            thisCalendar.setMultiplePerformanceTimes(d.date);
1850        }
1851        if ( IsSalesPeriodEnded) {
1852            performanceStatus=d.SaleIcon;
1853        }
1854        else{
1855            if(isMentaResaleAvailable && !performanceOnSale){                
1856               
1857                thisCalendar.addDateSubNote(d.date, 'Sold Out');
1858                //thisCalendar.setDaySoldOut(d.date);
1859                //thisCalendar.addDateInfoBox(d.date, "Sold Out");
1860                 thisCalendar.configureMentaSettings(d);            
1861            }
1862            else{ 
1863              performanceStatus=d.BSaleIcon;
1864            }
1865        
1866        }
1867
1868        if (performanceStatus == null || performanceStatus == "")
1869            performanceStatus="sold out";
1870
1871        if(dateSoldOut){
1872            thisCalendar.setDaySoldOut(d.date);
1873        }else{
1874            if ( (customStatus && !dateLimitedAvailability && !performanceOnSale && !isMentaResaleAvailable) || IsSalesPeriodEnded)
1875            {
1876                thisCalendar.setcustomStatus(d.date,showPhoneNumber,performanceStatus)
1877            }
1878            else{
1879            //date not sold out, add details, add to legend if one exists
1880            var detailString = "";
1881
1882            // if the price option is checked in event landing page in the admin 
1883             if(d.CalendarViewShowPrice != 0){
1884                //for now, we'll just add the pricing, this would be a spot to modify what is displayed on the dates by changing the contents of this string
1885                if(d.defaultPrice != null){
1886                    if (QualiferButton) { // SHOWDEV-22142 - If date has public qualifier, show qualifier text (Premium Access) instead of price and buy button
1887                        detailString = detailString + "<span class='display-perfbuybutton'>Premium Access</span>";
1888                    }else {
1889                           
1890                            detailString = "<span class='display-perfprice'>" + thisCalendar.currencySymbol + d.defaultPrice.toFixed(2).replace('.00','') + "</span>";
1891                        
1892                    }
1893                    
1894                if(defaultPricingLegend.indexOf(d.defaultPricingCode) === -1)
1895                    defaultPricingLegend.push(d.defaultPricingCode);
1896                }
1897                if(d.secondaryPricingCode != "" && d.secondaryPricingCode != null){
1898                    if(secondaryPricingLegend.indexOf(d.secondaryPricingCode) === -1)
1899                        secondaryPricingLegend.push(d.secondaryPricingCode);           
1900                    
1901                    if (d.DisplayType === "calendar" || d.DisplayType === "streamlined") {
1902                           
1903                        detailString = "<span class='display-perfprice-withchild'>" + thisCalendar.currencySymbol + d.secondaryPrice.toFixed(2).replace('.00','') + "/</span>" + detailString;
1904                        
1905                    }
1906                }
1907            }
1908            if(d.CalendarViewShowPerformanceName != 0){
1909                detailString =  detailString + "<span class='display-perfname'>" + d.PerformanceName + "</span> ";
1910            }
1911           
1912            if(d.CalendarViewShowPerformanceTime != 0){
1913                if(d.PerformanceStartTimeAlias != ""){ // Performance Alias time is present
1914                    detailString = detailString + " <span class='display-perft
1914ime'>" + d.PerformanceStartTimeAlias + "</span>";
1915                } else {
1916                    detailString = detailString + " <span class='display-perftime'>" + d.PerformanceTime + "</span>";
1917                }
1918                
1919            }
1920            if(d.CalendarViewShowBuyButton != 0){
1921                var styleString = "";
1922                if (d.DisplayType === "streamlined")
1923                    styleString = " style='width: 100%;'";
1924                var buttonText = (isMentaResaleAvailable && d.OverrideBuyTicketsButtonText) ? d.OverrideBuyTicketsButtonText : thisCalendar.buyTicketsButtonText;
1925                detailString = detailString + "<span class='button display-perfbuybutton'"+styleString+">" + buttonText + "</span>";
1926            }
1927
1928            thisCalendar.addDateInfoBox(d.date, detailString);
1929            }
1930        }
1931        
1932    })
1933    //for now, we only generate the legend if there are one or two prices pesent
1934    if(defaultPricingLegend.length === 1 && secondaryPricingLegend.length === 1){
1935        $("#calendarLegend").html(secondaryPricingLegend[0] +" / " + defaultPricingLegend[0])
1936        
1937        $("#calendarLegend").show();
1938    }else{
1939        if(defaultPricingLegend.length === 1){
1940                $("#calendarLegend").html(defaultPricingLegend[0])
1941                
1942                $("#calendarLegend").show();
1943        }else{
1944            $("#calendarLegend").hide();
1945        }
1946    }
1947    if(typeof(setFilterOptions) == 'function'){
1948        setFilterOptions(thisCalendar);
1949    }
1950    if (detailData.hasValidCoupon) {
1951        $("#plCalendar").append("<input type='hidden' id='hasValidCoupon' value='1' />");
1952    } else {
1953        $("#plCalendar").append("<input type='hidden' id='hasValidCoupon' value='0' />");
1954    }
1955    $(".calendar-loading").hide();
1956}
1957swDatepicker.prototype.configureMentaSettings = function (dateDetail) {
1958    // Set Menta Resale Settings
1959    
1960}
1961
1962swDatepicker.prototype.getFirstDate = function(defaultMonth){
1963    var thisCalendar = this;
1964    //this should only happen once on calendar load - currently only enabled for bundles
1965    if(thisCalendar.bundleID == 0 || thisCalendar.bundleID == -1)
1966        return defaultMonth; //currently only developed for bundles TODO: add event, category, standard support.
1967
1968    $.getJSON("/include/widgets/calendar/calendarRequests.asp",
1969            {
1970                action: 'initialBundleDate',
1971                iBundle: thisCalendar.bundleID,
1972                cp : thisCalendar.corporatePartnerPage
1973            })
1974            .done(function (data) {
1975                try {
1976                    if (data.performancedates.length > 0) {
1977                        
1978    
1979                        var firstMonth = Number(String(data.performancedates).split("/")[0]) - 1;
1980                        var firstYear = Number(String(data.performancedates).split("/")[2]);
1981                        thisCalendar.month = firstMonth - 1; //to make this simple, we're using the showNextMonth() function, which means we need to set the month to 1 less than our target, as that function increments the month itself
1982                        thisCalendar.year = firstYear;
1983                        thisCalendar.showNextMonth();
1984                    }else{
1985                        return defaultMonth;
1986                    }
1987                }catch(e){
1988                    console.log("getFirstDate returned invalid date. Default used");
1989                    console.log(e);
1990                    return defaultMonth;
1991                }
1992            })
1993            .fail(function (jqxhr, textStatus, error) {
1994                var err = textStatus + ", " + error;
1995                console.log("Request Failed: " + err);
1996            });
1997}
1998swDatepicker.prototype.fetchLocalDates = function () {
1999    //utliize storage to store months
2000    var CalendarExpireTime = new Date().getTime(); var isExpired = false; var datesData = "";
2001    var calendarIDString = this.calendarName + this.type + this.eventID + this.bundleID + "-" + this.corporatePartnerPage + "_" + this.activeMonth;
2002    try {
2003        //check for local storage support
2004        isExpired = CalendarExpireTime > Number(localStorage.getItem("CalendarExpireTime_" + calendarIDString));
2005        if (isExpired) {
2006            //item expired, clear local results
2007            localStorage.setItem("ShowareDates_" + calendarIDString, "");
2008            localStorage.setItem("CalendarExpireTime_" + calendarIDString, CalendarExpireTime + (1000 * 60 * 30));  //item information expires after 30 minutes
2009            return false;
2010        }
2011        localStorage.setItem("CalendarExpireTime_" + calendarIDString, CalendarExpireTime + (1000 * 60 * 30));  //item information expires after 30 minutes
2012        if (localStorage.getItem("ShowareDates_" + calendarIDString) != null && localStorage.getItem("ShowareDates_" + calendarIDString) != "" && localStorage.getItem("ShowareDates_" + calendarIDString) != []) {
2013            return localStorage.getItem("ShowareDates_" + calendarIDString);
2014        } else {
2015            //date info not stored
2016            return false;
2017        }
2018    } catch (e) {
2019        return false;
2020    }
2021}
2022swDatepicker.prototype.storeDates = function (dateData) {
2023    
2024    var calendarIDString = this.calendarName + this.type + this.eventID + this.bundleID + "-" + this.corporatePartnerPage + "_" + this.activeMonth;
2025    try {
2026        localStorage.setItem("ShowareDates_" + calendarIDString, JSON.stringify(dateData));
2027    } catch (e) {
2028        //no local storage
2029    }
2030}
2031swDatepicker.prototype.getDateRangeEvents = function (dateRangeData) {
2032    var thisCalendar = this;
2033    try{
2034        $.getJSON("/include/widgets/calendar/calendarRequests.asp",
2035            {
2036                action: 'getDateRangeEvents',
2037                dateRange: JSON.stringify(dateRangeData),
2038            })
2039            .done(function (data) {
2040                try {
2041                    thisCalendar.dateRangeEvents = data;
2042                }catch(e){
2043                    console.log("getDateRangeEvents returned invali
2043d response.");
2044                    console.log(data, e);
2045                    return []//return empty array;
2046                }
2047            })
2048            .fail(function (jqxhr, textStatus, error) {
2049                var err = textStatus + ", " + error;
2050                console.log("Request Failed: " + err);
2051            });
2052
2053    }catch(e){
2054        console.log("Unable to fetch date range events:", e)
2055    }
2056}
2057swDatepicker.prototype.clearDateRange = function () {
2058    this.fromDateRange = '';
2059    this.toDateRange = '';
2060}
2061function fetchDateIndex(dateString, dateObjectArray){
2062    try{
2063        for(var i = 0;i < dateObjectArray.length;i++){
2064            if(dateObjectArray[i].date == dateString){
2065                return i;
2066                break;
2067            }
2068        }
2069        return -1;
2070    }catch(e){
2071        //this function requires specific objects with a date property, it will fail otherwise and we'll just return what one would expect from a failed indexof
2072        return -1;
2073    }
2074}
2075function swapMonthDay(d){
2076    //expects dd/mm/yyyy format
2077    try{
2078        let splitDate = d.split("/");
2079        let newDate = splitDate[1] + '/' + splitDate[0] + "/" + splitDate[2];
2080        return newDate;
2081    }catch(e){
2082        console.log("could not swap date:",d,e);
2083        return d;
2084    }
2085}
2086
2087</script>
2087
2088        
2088<script type="text/javascript">
2089            if (typeof localStorage === 'object') {
2090                try {
2091                    localStorage.setItem('localStorage', 1);
2092                    localStorage.removeItem('localStorage');
2093                } catch (e) {
2094                    Storage.prototype._setItem = Storage.prototype.setItem;
2095                    Storage.prototype.setItem = function () { };
2096                    console.log("local storage not availalbe, data tracking limited");
2097                }
2098            }
2099            function persistDataLayer(layerName, pageVal) {
2100                var ShoWareExpTime = new Date().getTime(); var isExpired = false;
2101
2102                try {
2103                    isExpired = ShoWareExpTime > Number(localStorage.getItem("swExpTime"));
2104                    if (isExpired) {
2105                        removeDataLayer();
2106                    }
2107                    localStorage.setItem("swExpTime", ShoWareExpTime + 1000 * 60 * 30);  //tag information expires after 30 minutes of inactivity
2108
2109                    //grab anything we might have in storage=
2110                    var existVal = localStorage.getItem(layerName);
2111                    if (pageVal != "") {
2112                        //page val trumps all, store it and send it back
2113                        localStorage.setItem(layerName, pageVal);
2114                        return pageVal;
2115                    } else {
2116                        //page val was empty, so we'll try to pull a value out of local storage
2117                        if (existVal != "" && existVal != null && existVal != undefined && !isExpired) {
2118                            return existVal;
2119                        } else {
2120                            //no value exists, or the values stored have expired;
2121                            return "";
2122                        }
2123                    }
2124                } catch(e) {
2125                    //no local storage, or other error, we'll just return the page value. Calls to this function should assume the possibility of failure as local storage does not work on IOS devices with private browsing enabled.
2126                    return pageVal;
2127                }
2128            }
2129            function addDataLayer(layerName, setVal) {
2130                try {
2131                    //the data layer MUST be set up before the container is introduced.
2132                    //We will rely on future loads to address these variables as they are added after the pageload.
2133                    localStorage.setItem(layerName, setVal);
2134                    //push data to dataLayer so we can retrieve it with non-load events (clicks, changes, etc...)
2135                    dataLayer.push({[layerName]: setVal});
2136                }
2137                catch (e) {
2138                    //local storage failed, or the data layer was not available.
2139                }
2140            }
2141            function removeDataLayer() {
2142                //empty showare data layer from local storage.
2143                for (var i = localStorage.length - 1; i >= 0; i--) {
2144                    layerName = localStorage.key(i);
2145                    if (layerName.indexOf("Ticketing") > -1) {
2146                        localStorage.removeItem(layerName);
2147                    }
2148                }
2149            }
2150            function tryParse(jsonString) {
2151                if (jsonString == "" || jsonString == null || jsonString == undefined) {
2152                    return '';
2153                }
2154                try {
2155                    JSON.parse(jsonString);
2156                } catch (e) {
2157                    console.log(e);
2158                    return '';
2159                }
2160                return JSON.parse(jsonString);
2161            }
2162        </script>
2162
2163
2164        
2164<script>
2165            window.dataLayer = window.dataLayer || [];
2166            dataLayer.push({
2167                'TicketingHasActivePerformances': 'True',
2168                'TicketingPage': 'login.asp',
2169                'TicketingEventID': persistDataLayer("TicketingEventID", ""),
2170                'TicketingBundleID': persistDataLayer("TicketingBundleID", ""),
2171                'TicketingPerformanceID': persistDataLayer("TicketingPerformanceID", ""),
2172                'TicketingPerformanceCode': persistDataLayer("TicketingPerformanceCode", ""),
2173                'TicketingPerformanceDate': persistDataLayer("TicketingPerformanceDate", ""),
2174                'TicketingOrderID': persistDataLayer("TicketingOrderID", "0"),
2175                'TicketingNewCustomer': persistDataLayer("TicketingNewCustomer", ""),
2176                'TicketingCustomerID': "",
2177                'TicketingCustomerZipCode': persistDataLayer("TicketingCustomerZipCode", ""),
2178                'TicketingCustomerState': persistDataLayer("TicketingCustomerState", ""),
2179                'TicketingCustomerCountry': persistDataLayer("TicketingCustomerCountry", ""),
2180                'TicketingCustomerCity': persistDataLayer("TicketingCustomerCity", ""),
2181                'TicketingCurrencyCode': persistDataLayer("TicketingCurrencyCode", "USD"),
2182                'TicketingOrderTotal': persistDataLayer("TicketingOrderTotal", ""),
2183                'TicketingCoupon': persistDataLayer("TicketingCoupon", ""),
2184                'TicketingPromo': persistDataLayer("TicketingPromo", ""),
2185                'TicketingDiscountAmount': persistDataLayer("TicketingDiscountAmount", ""), //promo code dicount value only
2186                'TicketingHasMixedBasket': persistDataLayer("TicketingHasMixedBasket", ""),
2187                'TicketingOrderSubTotal': persistDataLayer("TicketingOrderSubTotal", ""),
2188                'TicketingItemCount': persistDataLayer("TicketingItemCount", ""),
2189                'TicketingBundleCount': persistDataLayer("TicketingBundleCount", ""),
2190                'TicketingShippingMethod': persistDataLayer("TicketingShippingMethod", ""),
2191                'TicketingIsWillCall': persistDataLayer("TicketingIsWillCall", ""),
2192                'TicketingHeardAbout': persistDataLayer("TicketingHeardAbout", ""),
2193                'TicketingShippingTotal': persistDataLayer("TicketingShippingTotal", ""),
2194                'TicketingTaxTotal': persistDataLayer("TicketingTaxTotal", ""),
2195                'TicketingFeesTotal': persistDataLayer("TicketingFeesTotal", ""),
2196                'TicketingProcessingFee': persistDataLayer("TicketingProcessingFee", ""),
2197                'TicketingTicketFeesTotal': persistDataLayer("TicketingTicketFeesTotal", ""),
2198                'TicketingTicketItems': persistDataLayer("TicketingTicketItems", ""),
2199                'TicketingDonationItems': persistDataLayer("TicketingDonationItems", ""),
2200                'TicketingMembershipItems': persistDataLayer("TicketingMembershipItems", ""),
2201                'TicketingSalesChannel': persistDataLayer("TicketingSalesChannel", ""),
2202                'TicketingPaymentType': persistDataLayer("TicketingPaymentType", ""),
2203                'TicketingEventName': persistDataLayer("TicketingEventName", ""),
2204                'TicketingPerformanceName': persistDataLayer("TicketingPerformanceName", ""),
2205                'TicketingBundleName': persistDataLayer("TicketingBundleName", ""),
2206                'TicketingPromoterID': persistDataLayer("TicketingPromoterID", ""),
2207                'TicketingEventCategories': persistDataLayer("TicketingEventCategories", ""),
2208                'GAClientID': persistDataLayer("GAClientID", ""),
2209                'transactionId': 0,
2210                'transactionTotal': parseFloat(persistDataLayer("transactionTotal", "")),
2211                'transactionAffiliation' : 'CincyTicket',
2212                'transactionTax': parseFloat(persistDataLayer("transactionTax", "")),
2213                'transactionShipping': parseFloat(persistDataLayer("transactionShipping", "")),
2214                'transactionProducts': tryParse(persistDataLayer("transactionProducts", ""))
2215            });
2216            if(typeof(customDataLayerPush) === "function"){
2217                customDataLayerPush(); //custom function can be defined in local files and values pushed prior to GTM loading to simplify tag implimentation
2218            }
2219        </script>
2219
2220        
2221            <!-- CLIENT Google Tag Manager -->
2222            
2222<script>
vendor: 373 bytes, lines 2222-2226
2222(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
2223            new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
2224            j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
2225            '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
2226            })(window,document,'script','dataLayer','
2226GTM-WZ8HC5
vendor: 3 bytes, line 2226
2226');
2226</script>
2226
2227            <!-- End CLIENT Google Tag Manager -->
2228        
2229                <!-- PRIMARY Google Tag Manager -->
2230                
2230<script>
vendor: 389 bytes, lines 2230-2234
2230(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
2231                new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
2232                j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
2233                '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
2234                })(window,document,'script','dataLayer','
2234GTM-MDGF2K
vendor: 3 bytes, line 2234
2234');
2234</script>
2234
2235                <!-- End PRIMARY Google Tag Manager -->
2236        
2237
2238
2239    
2239<script type="text/javascript">
2240        var simpleCacheBuster = {
2241            beforeLength: 0,
2242            afterLength: 0
2243        };
2244
2245        simpleCacheBuster.beforeLength = document.cookie.length;
2246        simpleCacheBuster.afterLength = document.cookie.replace("ShowareVersion=newUI", " ").length;
2247
2248        // If length is the same, then we haven't set this version cookie before, clear the cache.
2249        // If after length is smaller, then we have replaced the same version, do nothing.
2250        // After length shouldn't be greater, do nothing.
2251        if (simpleCacheBuster.beforeLength == simpleCacheBuster.afterLength) {
2252            document.cookie = "ShowareVersion=newUI";
2253
2254            // This will force browser to reload all includes from server instead of cache.
2255            // Sadly, this doesn't work on Chrome due to a bug that they refuse to fix.
2256            // https://bugs.chromium.org/p/chromium/issues/detail?id=443462
2257            location.reload(true);
2258        }
2259    </script>
2259
2260
2261	
2261<script language="JavaScript">
2262	    $(document).ready(function () {
2263	        var sessionKey;
2264	        sessionKey = '';
2265	        //v1Session variable declared in jq.js 
2266	        v1Session.setSessionKey(sessionKey);
2267	    });
2268
2269	</script>
2269
2270    
2270<script type="text/javascript">
2271        /*
2272         * Replace all SVG images with inline SVG - allows for image modificcation via CSS
2273         */
2274        function extractIcons() {
2275            $('img.sw-icon').each(function () {
2276                var $img = $(this);
2277                var imgID = $img.attr('id');
2278                var imgClass = $img.attr('class');
2279                var imgURL = $img.attr('src');
2280
2281                $.get(imgURL, function (data) {
2282                    // Get the SVG tag, ignore the rest
2283                    var $svg = jQuery(data).find('svg');
2284
2285                    // Add replaced image's ID to the new SVG
2286                    if (typeof imgID !== 'undefined') {
2287                        $svg = $svg.attr('id', imgID);
2288                    }
2289                    // Add replaced image's classes to the new SVG
2290                    if (typeof imgClass !== 'undefined') {
2291                        $svg = $svg.attr('class', imgClass + ' replaced-svg');
2292                    }
2293                    // Remove any invalid XML tags as per http://validator.w3.org
2294                    $svg = $svg.removeAttr('xmlns:a');
2295                    // Replace image with new SVG
2296                    $img.replaceWith($svg);
2297                }, 'xml');
2298            });
2299        }
2300    </script>
2300
2301    
2301<script type="text/javascript">
2302        function getGAClientID() {
2303            try {
2304                return ga.getAll()[0].get('clientId');
2305            } catch (e) {
2306                return "0";
2307            }
2308        }
2309        function addGAClient(){
2310            var gaID = getGAClientID();
2311            if(gaID == "0"){
2312                //no analytics (unlikely), or analytics not loaded yet
2313                setTimeout(function(){addGAClient()}, 500);
2314            }else{
2315                try{
2316                    addDataLayer('GAClientID', gaID);
2317                }catch(e){
2318                    console.log("Failed to add data layer object: GAClientID:");
2319                    console.log(e);
2320                }
2321            }
2322        }
2323        addGAClient();
2324
2325    </script>
2325
2326
2327	
2328
2329    <!-- Comodo SSL Seal -->
2330    
2331        
2331<script type="text/javascript">
2332            //<![CDATA[ 
2333            var tlJsHost = ((window.location.protocol == "https:") ? "https://secure.comodo.com/" : "http://www.trustlogo.com/"); document.write(unescape("%3Cscript src='" + tlJsHost + "trustlogo/javascript/trustlogo.js' type='text/javascript'%3E%3C/script%3E"));
2334            //]]>
2335        </script>
2335
2336    
2337
2338<script type="text/javascript">
2339
2340    var swEnhancedEcommerce = {
2341        basketProducts: [],
2342        myImpressions: [],
2343        myProducts: [],
2344
2345        //Building Up items to pass to analytics
2346        addImpressions: function (name, id, price, category, list, position) {
2347            //adds a product impression to myImpressions - represents a user being presented a specific product
2348            if (price != '') { //price is optional
2349                this.myImpressions.push(
2350                    {
2351                        'name': name,       // Name or ID is required.
2352                        'id': id,
2353                        'price': price,
2354                        'category': category,
2355                        'list': list,
2356                        'position': position
2357                    }
2358                );
2359            } else {
2360                this.myImpressions.push(
2361                    {
2362                        'name': name,       // Name or ID is required.
2363                        'id': id,
2364                        'category': category,
2365                        'list': list,
2366                        'position': position
2367                    }
2368                );
2369            }
2370        },
2371
2372        addProducts: function (name, id, price, category, position) {
2373            //product clicks represent a product being selected. For showare currently this will always be a single product, but future use may require allowing users to select multiple products
2374            //this represents a click on a product, NOT adding a product to the basket
2375            if (price != '') { //price is optional
2376
2377                this.myProducts.push(
2378                    {
2379                        'name': name,       // Name or ID is required.
2380                        'id': id,
2381                        'price': price,
2382                        'category': category,
2383                        'position': position
2384                    }
2385                );
2386            } else {
2387                this.myProducts.push(
2388                    {
2389                        'name': name,       // Name or ID is required.
2390                        'id': id,
2391                        'category': category,
2392                        'position': position
2393                    }
2394                );
2395            }
2396        },
2397
2398        //object management functions
2399        clearImpressions: function(){
2400            this.myImpressions = [];
2401        },
2402        clearProducts: function () {
2403            this.myProducts = [];
2404        },
2405
2406        //Passing data to analytics
2407        sendImpressions: function(){
2408            window.dataLayer.push({
2409                'event': 'impressionsPushed',
2410                'ecommerce': {
2411                    'impressions': this.myImpressions
2412                }
2413            });
2414        },
2415        sendProducts: function (list) {
2416            //list should be a string of the originator of the product click, for instance a performance list, event list, callout, or other
2417            window.dataLayer.push({
2418                'event': 'productClick',
2419                'ecommerce': {
2420                    'click': {
2421                        'actionField': { 'list': list },      // Optional list property.
2422                        'products': this.myProducts
2423                    }
2424                }
2425            });
2426        },
2427        sendDetails: function (name, id, category) {
2428            //tracks a user's view of product details
2429            window.dataLayer.push({
2430                'event': 'detailView',
2431                'ecommerce': {
2432                    'detail': {
2433                        'products': [{
2434                            'name': name,         // Name or ID is required.
2435                            'id': id,
2436                            'category': category,
2437                        }]
2438                    }
2439                }
2440            });
2441        },
2442
2443        sendAddToBasket: function(){
2444            var newAddedProducts = this.compareBasketProducts(this.basketProducts);
2445            if (newAddedProducts.length === 0) {
2446                return;
2447            }
2448            console.log("added items to basket:", newAddedProducts);
2449            //REQUIRES basketProducts populated via fetchBasketProducts or directly
2450            window.dataLayer.push({
2451                'event': 'addToCart',
2452                'ecommerce': {
2453                    'add': {                                // 'add' actionFieldObject measures.
2454                        'products': newAddedProducts                          //  adding a product to a shopping cart.
2455                    }
2456                }
2457            });
2458        },
2459
2460        sendAddItemToBasket: function(name, id, price, category, quantity){
2461            //REQUIRES basketProducts populated via fetchBasketProducts or directly
2462            window.dataLayer.push({
2463                'event': 'addToCart',
2464                'ecommerce': {
2465                    'add': {                                // 'add' actionFieldObject measures.
2466                        'products': [{                          //  removing a product to a shopping cart.
2467                            'name': name,
2468                            'id': id,
2469                            'price': price,
2470                            'category': category,
2471                            'quantity': quantity
2472                        }]
2473                    }
2474                }
2475            });
2476        },
2477
2478        sendRemoveFromBasket: function (name, id, price, category, quantity, doUpdate) {
2479            //the item should be removed from the actual basket before this is called, as the basket is updated immediately
2480            window.dataLayer.push({
2481                'event': 'removeFromCart',
2482                'ecommerce': {
2483                    'remove': {                               // 'remove' actionFieldObject measures.
2484                        'products': [{                          //  removing a product to a shopping cart.
2485                            'name': name,
2486                            'id': id,
2487                            'price': price,
2488                            'category': category,
2489                            'quantity': quantity
2490                        }]
2491                    }
2492                }
2493            });
2494            if (doUpdate) {
2495                this.fetchBasketProducts();
2496            }
2497        },
2498
2499        sendRemoveAllFromBasket: function () {
2500            //the item should be removed from the actual basket before this is called, as the basket is updated immediately
2501            window.dataLayer.push({
2502                'event': 'removeFromCart',
2503                'ecommerce': {
2504                    'remove': {                               // 'remove' actionFieldObject measures.
2505                        'products': this.basketProducts
2506                    }
2507                }
2508            });
2509            this.basketProducts = [];
2510            localStorage.removeItem('swAddedBasketProducts');
2511        },
2512
2513        //method to fetch basket - we should only call this if we intend to send products to analytics
2514        fetchBasketProducts: function (type, orderID, doAddToCartAfter) {
2515            if (typeof type === 'undefined') type = 'basket'; //defaults to grabbing basket items
2516            if (typeof orderID === 'undefined') orderID = 0;
2517            doAddToCartAfter = doAddToCartAfter || false;
2518            var fetchURL = "include/modules/enhancedEcommerceBasket.asp?type=" + type + "&orderid=" + orderID;
2519
2520            try {
2521                $.ajax({
2522                    context: this,
2523                    url: fetchURL
2524                })
2525                .done(function (data) {
2526                    //note that we'll only have basket details if this method is called. Functions like sendAddToBasket, and sendPurchase will not function if this method has not completed.
2527                    try{
2528                        this.basketProducts = JSON.parse(data);
2529                    } catch (e) {
2530                        console.log(e);
2531                        this.basketProducts = [];
2532                    }
2533                    //try to update the data layer with the most current products
2534                    try{
2535                        addDataLayer("TicketingTicketItems",data);
2536                    } catch (e){
2537                        console.log(e);
2538                    }
2539                    if(doAddToCartAfter){
2540                        this.sendAddToBasket();
2541                    }
2542                });
2543                //grab the basket and store contents
2544            } catch (e) {
2545                console.log(e);
2546                return
2547            }
2548        },
2549
2550        sendOrder: function (orderID, orderTotal, taxFees, shippingFees, couponCodes, orderCode) {
2551            var fetchURL = "include/modules/enhancedEcommerceBasket.asp?type=order&orderid=" + orderID + "&orderCode=" + orderCode;
2552            orderProducts = [];
2553
2554            try {
2555                $.ajax({
2556                    context: this,
2557                    url: fetchURL
2558                })
2559                .done(function (data) {
2560                    //note that we'll only have basket details if this method is called. Functions like sendAddToBasket, and sendPurchase will not function if this method has not completed.
2561                    try {
2562                        orderProducts = JSON.parse(data);
2563                    } catch (e) {
2564                        console.log(e);
2565                        orderProducts = [];
2566                    }
2567                    dataLayer.push({
2568                        'event': 'purchaseMade',
2569                        'ecommerce': {
2570                            'purchase': {
2571                                'actionField': {
2572                                    'id': orderID,                         // Transaction ID. Required for purchases and refunds.
2573                                    'affiliation': 'Online Ticketing',
2574                                    'revenue': orderTotal,                     // Total transaction value (incl. tax and shipping)
2575                                    'tax': taxFees,
2576                                    'shipping': shippingFees,
2577                                    'coupon': couponCodes
2578                                },
2579                                'products': orderProducts
2580                            }
2581                        }
2582                    });
2583                });
2584                //grab the basket and store contents
2585            } catch (e) {
2586                console.log(e);
2587                return
2588            }
2589
2590            
2591        },
2592
2593        // -------------------------------------------- CHECKOUT STEPS --------------------------------------------
2594        // 1. Basket Page "Checkout" Clicked
2595        // 2. login/guest/create
2596        // 3. Streamlined - select shipping method
2597        // 4. Streamlined - enter payment information
2598        // 5. Streamlined - complete clicked
2599        // 6. view order
2600        sendCheckoutStep: function(stepID, option){
2601            dataLayer.push({
2602                'event': 'checkout',
2603                'ecommerce': {
2604                    'checkout': {
2605                        'actionField': { 'step': stepID, 'option': option },
2606                        'products': this.basketProducts
2607                    }
2608                }
2609            });
2610        },
2611        sendViewPromotion: function(promotionItems){
2612            //promotion items should be an array of promotion items
2613            dataLayer.push({
2614                'event': 'view_promotion',
2615                'ecommerce': {
2616                    'items': promotionItems
2617                }
2618            });
2619            console.log("sent promotions");
2620            console.log(promotionItems);
2621        },
2622        sendSelectPromotion: function(promotionItems){
2623            //promotion items should be an array of promotion items
2624            dataLayer.push({
2625                'event': 'select_promotion',
2626                'ecommerce': {
2627                    'items': promotionItems
2628                }
2629            });
2630            console.log("selected promotions");
2631            console.log(promotionItems);
2632        },
2633
2634        getStoredAddedBasketProducts: function () {
2635            if (typeof localStorage === 'undefined') {
2636                return [];
2637            }
2638            try {
2639                var storedRaw = localStorage.getItem('swAddedBasketProducts');
2640                if (!storedRaw) {
2641                    return [];
2642                }
2643                var parsed = JSON.parse(storedRaw);
2644                return Array.isArray(parsed) ? parsed : [];
2645            } catch (e) {
2646                console.log(e);
2647                return [];
2648            }
2649        },
2650        cloneBasketProduct: function (product) {
2651            if (!product || typeof product !== 'object') {
2652                return product;
2653            }
2654            var clone = {};
2655            for (var prop in product) {
2656                if (Object.prototype.hasOwnProperty.call(product, prop)) {
2657                    clone[prop] = product[prop];
2658                }
2659            }
2660            return clone;
2661        },
2662        cloneBasketProducts: function (source) {
2663            var cloned = [];
2664            if (!Array.isArray(source)) {
2665                return cloned;
2666            }
2667            for (var i = 0; i < source.length; i++) {
2668                cloned.push(this.cloneBasketProduct(source[i]));
2669            }
2670            return cloned;
2671        },
2672        buildBasketProductSignature: function (product) {
2673            if (!product || typeof product !== 'object') {
2674                return '';
2675            }
2676            var keys = Object.keys(product).sort();
2677            var normalized = {};
2678            for (var i = 0; i < keys.length; i++) {
2679                var key = keys[i];
2680                normalized[key] = product[key];
2681            }
2682            try {
2683                return JSON.stringify(normalized);
2684            } catch (e) {
2685                console.log(e);
2686                return '';
2687            }
2688        },
2689        persistAddedBasketProducts: function (products) {
2690            if (typeof localStorage === 'undefined') {
2691                return;
2692            }
2693            try {
2694                localStorage.setItem('swAddedBasketProducts', JSON.stringify(this.cloneBasketProducts(products)));
2695            } catch (e) {
2696                console.log(e);
2697            }
2698        },
2699        storeAddedBasketProducts: function(basketProducts) {
2700            this.compareBasketProducts(basketProducts);
2701        },
2702        compareBasketProducts: function(basketProducts, options){
2703            var opts = options || {};
2704            var products = Array.isArray(basketProducts) ? basketProducts : [];
2705            if (typeof localStorage === 'undefined') {
2706                return opts.returnCombined ? { unmatched: products, combined: this.cloneBasketProducts(products) } : products;
2707            }
2708
2709            var storedProducts = this.getStoredAddedBasketProducts();
2710            var storedCounts = {};
2711            for (var i = 0; i < storedProducts.length; i++) {
2712                var storedSignature = this.buildBasketProductSignature(storedProducts[i]);
2713                if (storedSignature) {
2714                    storedCounts[storedSignature] = (storedCounts[storedSignature] || 0) + 1;
2715                }
2716            }
2717
2718            var unmatchedProducts = [];
2719            var combinedProducts = this.cloneBasketProducts(storedProducts);
2720            var pendingCounts = {};
2721
2722            for (var j = 0; j < products.length; j++) {
2723                var product = products[j];
2724                var productSignature = this.buildBasketProductSignature(product);
2725
2726                if (!productSignature) {
2727                    unmatchedProducts.push(product);
2728                    combinedProducts.push(this.cloneBasketProduct(product));
2729                    continue;
2730                }
2731
2732                var alreadyTracked = pendingCounts[productSignature] || 0;
2733                var existingCount = storedCounts[productSignature] || 0;
2734
2735                if (alreadyTracked < existingCount) {
2736                    pendingCounts[productSignature] = alreadyTracked + 1;
2737                } else {
2738                    unmatchedProducts.push(product);
2739                    pendingCounts[productSignature] = alreadyTracked + 1;
2740                    combinedProducts.push(this.cloneBasketProduct(product));
2741                }
2742            }
2743
2744            if (opts.persist !== false) {
2745                this.persistAddedBasketProducts(combinedProducts);
2746            }
2747
2748            if (opts.returnCombined) {
2749                return { unmatched: unmatchedProducts, combined: combinedProducts };
2750            }
2751
2752            return unmatchedProducts;
2753        }
2754
2755
2756    }
2757</script>
2757 
2758<script type="text/javascript">
2759//---------------------------DATEPICKER---------------------------------
2760function buildDatepicker(options) {
2761    //Calling this function should be sufficient to create a calendar within a designated div, with and
2762    //EX: headerDP = buildDatepicker({"calendarID":"headerCalendar","linkedInputID":"headerCalendarInput","isModal":false,"forceDates":true, "defaultDate": "{{Output date from server Here}}"}); <~ would create a calendar object for the calendar presented at #headerCalendar, and link it to #headerCalendarInput
2763    //most calendar methods are specific to the document the calendar resides on, and should be handled via the onChange event for the linked input
2764    //Available Options:
2765    //  calendarID (required)       == string, ID of calendar div
2766    //  linkedInput (required)      == string, ID of input which will change when a date is selected
2767    //  isModal                     == boolean, if true, calendar will be hidden, and display when the designated input recieves focus. If false, the calendar will be present and display as an inline block at all times.
2768    //  forceDates                  == boolean, if true only highlighted dates will be clickable
2769    //  detailedCalendar            == boolean, if true data is pulled to determine pricing information, sold out days, limited availablility - requires eventID
2770    //  defaultDate                 == string, mm/dd/yyyy date that calendar should start on (this will only represent the month displayed at the begining)
2771    //  type                        == string: defaults to "performancedates", which will add all visible performances
2772    //  eventID                     == integer: defaults to -1 which means no event. Other values will filter by events with that ID, allowing for a search of performance dates for a specific event only
2773    //  isMultiplePerformanceIndicator == boolean: if true, shows indicator for dates with multiple performance times
2774    //
2775    //Methods:
2776    //  showDlg()/hideDlg()             : shows/hides modal calendars, no valid for non-modal calendars
2777    //  addHighlightDay(mm/dd/yyyy)     : adds a date (presented as a mm/dd/yyyy string) to the list of highlight dates for the calendar - REQUIRES HighlightDays() function call to visually represent this change on the calendar
2778    //  clearHihghlightDays()           : removes all stored highlight dates
2779    //  highlightDays()                 : adds highlight class to stored days, visually highlighting them ont he calendar.
2780    
2781    var myID = options.calendarID; //required
2782    var myLinkedInput = options.linkedInputID; //required
2783    var isModal = options.isModal || false;
2784    var showLoader = options.showLoader || false;
2785    var forceDates = options.forceDates || false;
2786    var myDefault = new Date();
2787    if (options.defaultDate) {
2788        try{
2789            
2790            myDefault = new Date(options.defaultDate);
2791        } catch (e) {
2792            console.log("date no valid for calendar: " + myID);
2793            console.log(e);
2794        }
2795    }
2796    var type = options.type || "performancedates";
2797    var eventID = options.eventID || -1;
2798    var detailedCalendar = options.detailedCalendar && eventID != -1 || false;
2799    var bundleID = options.bundleID || -1;
2800    var categoryID = options.CategoryID || -1;
2801    var corporatePartnerPage = options.corporatePartnerPage || 0;
2802    var bValidCoupon = options.bValidCoupon || 0;
2803    var couponCode = options.couponCode || "";
2804    var isMultiplePerformanceIndicator = options.isMultiplePerformanceIndicatorFlag || 0;
2805
2806    return new swDatepicker(myID, myLinkedInput, isModal, showLoader, forceDates, detailedCalendar, myDefault, type, eventID, bundleID, categoryID, corporatePartnerPage,bValidCoupon,couponCode,isMultiplePerformanceIndicator)
2807}
2808function swDatepicker(id, target, modal, loader, force, detailed, defaultDate, type, eventID, bundleID, categoryID, corporatePartnerPage,bValidCoupon,couponCode,isMultiplePerformanceIndicator) {
2809
2810    this.$id = $('#' + id); // element to attach widget to
2811    this.$monthObj = this.$id.find('.month');
2812    this.$prev = this.$id.find('.bn_prev');
2813    this.$next = this.$id.find('.bn_next');
2814    this.$grid = this.$id.find('.cal');
2815    this.$target = $('#' + target); // div or text box that will receive the selected date string and focus (if modal)
2816    this.bModal = modal; // true if datepicker should appear in a modal dialog box.
2817    this.showLoader = loader;
2818    this.forceDateSelection = force; //if true, will only allow users to click on highlighted dates - see addHighlightDay()
2819    this.detailedCalendar = detailed;
2820    this.active = !modal;
2821    this.type = type;
2822    this.eventID = eventID;
2823    this.bundleID = bundleID;
2824    this.categoryID = categoryID;
2825    this.corporatePartnerPage = corporatePartnerPage;
2826    this.fromDateRange = "";
2827    this.toDateRange = "";
2828    this.dateRangeEvents = [];
2829    this.calendarName = id;
2830
2831    this.monthNames = ['January', 'February', 'March', 'April', 'May', 'June',
2832    'July', 'August', 'September', 'October', 'November', 'December'];
2833
2834    this.dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
2835
2836    this.dateObj = new Date();
2837
2838    this.curYear = this.dateObj.getFullYear();
2839    this.year = defaultDate.getFullYear();
2840
2841    this.curMonth = this.dateObj.getMonth();
2842    this.month = defaultDate.getMonth();
2843    this.getFirstDate(defaultDate.getMonth()); //update the month to the first performance ASAP
2844
2845    this.curDate = this.dateObj.getDate();
2846    this.date = defaultDate.getDate();
2847    this.currentDate = (this.month == this.curMonth && this.year == this.curYear);
2848    this.activeMonth = (String(this.month + 1) + "/1/" + this.year);
2849
2850    this.keys = {
2851        tab: 9,
2852        enter: 13,
2853        esc: 27,
2854        space: 32,
2855        pageup: 33,
2856        pagedown: 34,
2857        end: 35,
2858        home: 36,
2859        left: 37,
2860        up: 38,
2861        right: 39,
2862        down: 40
2863    };
2864
2865    this.bValidCoupon = bValidCoupon;
2866    this.couponCode = couponCode;
2867    this.isMultiplePerformanceIndicator = isMultiplePerformanceIndicator;
2868
2869    this.highlightDates = [];    
2870
2871    // display the current month
2872    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
2873
2874    // populate the calendar grid
2875    this.popGrid();
2876
2877    // update the table's activedescdendant to point to the current day
2878    this.$grid.attr('aria-activedescendant', this.$grid.find('.today').attr('id'));
2879
2880    this.bindHandlers();
2881
2882    //show selected day
2883        $('#' + this.calendarName + '-day' + this.date).addClass('focus').attr('aria-selected', 'true');
2884
2885    // hide dialog if in modal mode
2886    if (this.bModal == true) {
2887        this.$id.attr('aria-hidden', 'true');
2888        //show/hide functionality may vary based on use, so should be handled after the datepicker is created.
2889        //if we're on mobile, disable keyboard for the input:
2890        if ($(window).width() < 1024) {
2891            this.$target.attr("readonly", "true");
2892        }
2893    }
2894
2895    this.currencySymbol = "$";
2896    this.buyTicketsButtonText = "Buy Tickets";
2897}
2898
2899//
2900// popGrid() is a member function to populate the datepicker grid with calendar days
2901// representing the current month
2902//
2903// @return N/A
2904//
2905swDatepicker.prototype.popGrid = function () {
2906    if(this.showLoader)
2907        $(".calendar-loading").show();
2908    var numDays = this.calcNumDays(this.year, this.month);
2909    var startWeekday = this.calcStartWeekday(this.year, this.month);
2910    //var lastMonth = this.month - 1;
2911    //var lastMonthYear = this.year;
2912    var weekday = 0;
2913    var curDay = 1;
2914    var rowCount = 1;
2915    var $tbody = this.$grid.find('tbody');
2916
2917    var currentDateDay = this.dateObj.getDate();
2918    var currentDateMonth = this.dateObj.getMonth();
2919    var currentDateYear = this.dateObj.getFullYear();
2920
2921    var gridCells = '\t<tr id="row1">\n';
2922
2923    // Keeping in case the client (Gaylord) pushes back on not having previous month's dates selectable
2924    // If the last month is -1, roll it over to December (11) and subtract 1 from the last month's year
2925    /*if (lastMonth < 0) {
2926        lastMonth = 11;
2927        lastMonthYear = lastMonthYear - 1;
2928    }
2929
2930    var lastMonthNumDays = this.calcNumDays(lastMonthYear, lastMonth);
2931    var lastMonthStartDay = lastMonthNumDays - (startWeekday - 1);*/
2932
2933    // clear the grid
2934    $tbody.empty();
2935    $('#msg').empty();
2936
2937    // Keeping in case the client (Gaylord) pushes back on not having previous month's dates selectable
2938    // Insert the leading empty cells
2939    /*for (var weekday = 0; weekday < startWeekday; weekday++) {
2940        gridCells += '\t\t<td id="' + this.calendarName + '-day' + lastMonthStartDay + '" class="day-cell muted last-month" headers="row' +
2941            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false" data-year="' + lastMonthYear + '"><span class="calendar-day notranslate" data-month="' + lastMonth + '">' + lastMonthStartDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
2942        //gridCells += '\t\t<td class="empty" data-month="' + lastMonth + '" data-year="' + lastMonthYear + '" data-day="' + lastMonthStartDay + '">&nbsp;</td>\n';
2943        lastMonthStartDay++;
2944    }*/
2945
2946    for (var weekday = 0; weekday < startWeekday; weekday++) {
2947        gridCells += '\t\t<td class="empty">&nbsp;</td>\n';
2948    }
2949
2950    // insert the days of the month.
2951    for (curDay = 1; curDay <= numDays; curDay++) {
2952
2953        if (curDay == this.curDate && this.currentDate == true) {
2954
2955            gridCells += '\t\t<td id="' + this.calendarName + '-day' + curDay + '" class="today day-cell" aria-label="row' +
2956            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false"><span class="calendar-day notranslate">' + curDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
2957        }
2958        else {
2959            var addMuted = "";
2960
2961            // Only mute dates in the past for the date range selector widget
2962            if (this.type == 'dateRangeSelect') {
2963                // If the year is in the past, or the year is the same but the month is in the past, or the month and year are the same but the day is in the past, mute the date
2964                if (this.year < currentDateYear
2965                    || (this.year == currentDateYear && this.month < currentDateMonth)
2966                    || (this.year == currentDateYear && this.month == currentDateMonth && curDay < currentDateDay)
2967                ) {
2968                    addMuted = " muted";
2969                }
2970            }
2971            
2972            gridCells += '\t\t<td id="' + this.calendarName + '-day' + curDay + '" class="day-cell' + addMuted + '" aria-label="row' +
2973            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false"><span class="calendar-day notranslate">' + curDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
2974        }
2975
2976
2977        if (weekday == 6 && curDay < numDays) {
2978            // This was the last day of the week, close it out
2979            // and begin a new one
2980            gridCells += '\t</tr>\n\t<tr id="row' + rowCount + '">\n';
2981            rowCount++;
2982            weekday = 0;
2983        }
2984        else {
2985            weekday++;
2986        }
2987    }
2988
2989    // Insert any trailing empty cells
2990    for (weekday; weekday < 7; weekday++) {
2991
2992        gridCells += '\t\t<td class="empty">&nbsp;</td>\n';
2993    }
2994
2995    gridCells += '\t</tr>';
2996
2997    $tbody.append(gridCells);
2998    if(this.detailedCalendar){
2999        this.getCalendarDetails();
3000    }else{
3001        this.fetchDates();
3002    }
3003    
3004}
3005
3006//
3007// calcNumDays() is a member function to calculate the number of days in a given month
3008//
3009// @return (integer) number of days
3010//
3011swDatepicker.prototype.calcNumDays = function (year, month) {
3012
3013    return 32 - new Date(year, month, 32).getDate();
3014}
3015
3016//
3017// calcstartWeekday() is a member function to calculate the day of the week the first day of a
3018// month lands on
3019//
3020// @return (integer) number representing the day of the week (0=Sunday....6=Saturday)
3021//
3022swDatepicker.prototype.calcStartWeekday = function (year, month) {
3023
3024    return new Date(year, month, 1).getDay();
3025
3026} // end calcStartWeekday()
3027
3028//
3029// showPrevMonth() is a member function to show the previous month
3030//
3031// @param (offset int) offset may be used to specify an offset for setting
3032//                      focus on a day the specified number of days from
3033//                      the end of the month.
3034// @return N/A
3035//
3036swDatepicker.prototype.showPrevMonth = function (offset) {
3037    // show the previous month
3038    if (this.month < 1) {
3039        this.month = 11;
3040        this.year--;
3041    }
3042    else {
3043        this.month--;
3044    }
3045
3046    if (this.month != this.curMonth || this.year != this.curYear) {
3047        this.currentDate = false;
3048    }
3049    else {
3050        this.currentDate = true;
3051    }
3052
3053    this.activeMonth = (String(this.month + 1) + "/1/" + this.year)
3054
3055    // populate the calendar grid
3056    this.popGrid();
3057
3058    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
3059
3060    // if offset was specified, set focus on the last day - specified offset
3061    if (offset != null) {
3062        var numDays = this.calcNumDays(this.year, this.month);
3063        var day = 'day' + (numDays - offset);
3064
3065        this.$grid.attr('aria-activedescendant', this.calendarName + '-' + day);
3066        $('#' + this.calendarName + '-' + day).addClass('focus').attr('aria-selected', 'true');
3067    }
3068
3069
3070} // end showPrevMonth()
3071
3072//
3073// showNextMonth() is a member function to show the next month
3074//
3075// @param (offset int) offset may be used to specify an offset for setting
3076//                      focus on a day the specified number of days from
3077//                      the beginning of the month.
3078// @return N/A
3079//
3080swDatepicker.prototype.showNextMonth = function (offset) {
3081
3082    // show the next month
3083    if (this.month == 11) {
3084        this.month = 0;
3085        this.year++;
3086    }
3087    else {
3088        this.month++;
3089    }
3090
3091    if (this.month != this.curMonth || this.year != this.curYear) {
3092        this.currentDate = false;
3093    }
3094    else {
3095        this.currentDate = true;
3096    }
3097
3098    this.activeMonth = (String(this.month + 1) + "/1/" + this.year)
3099
3100    // populate the calendar grid
3101    this.popGrid();
3102
3103    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
3104
3105    // if offset was specified, set focus on the first day + specified offset
3106    if (offset != null) {
3107        var day = 'day' + offset;
3108
3109        this.$grid.attr('aria-activedescendant', this.calendarName + '-' + day);
3110        $('#' + this.calendarName + '-' + day).addClass('focus').attr('aria-selected', 'true');
3111    }
3112
3113} // end showNextMonth()
3114
3115//
3116// showPrevYear() is a member function to show the previous year
3117//
3118// @return N/A
3119//
3120swDatepicker.prototype.showPrevYear = function () {
3121
3122    // decrement the year
3123    this.year--;
3124
3125    if (this.month != this.curMonth || this.year != this.curYear) {
3126        this.currentDate = false;
3127    }
3128    else {
3129        this.currentDate = true;
3130    }
3131
3132    // populate the calendar grid
3133    this.popGrid();
3134
3135    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
3136
3137} // end showPrevYear()
3138
3139//
3140// showNextYear() is a member function to show the next year
3141//
3142// @return N/A
3143//
3144swDatepicker.prototype.showNextYear = function () {
3145
3146    // increment the year
3147    this.year++;
3148
3149    if (this.month != this.curMonth || this.year != this.curYear) {
3150        this.currentDate = false;
3151    }
3152    else {
3153        this.currentDate = true;
3154    }
3155
3156    // populate the calendar grid
3157    this.popGrid();
3158
3159    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
3160
3161} // end showNextYear()
3162
3163//
3164// bindHandlers() is a member function to bind event handlers for the widget
3165//
3166// @return N/A
3167//
3168swDatepicker.prototype.bindHandlers = function () {
3169
3170    var thisObj = this;
3171
3172    ////////////////////// bind button handlers //////////////////////////////////
3173    this.$prev.click(function (e) {
3174        return thisObj.handlePrevClick(e);
3175    });
3176
3177    this.$next.click(function (e) {
3178        return thisObj.handleNextClick(e);
3179    });
3180
3181    this.$prev.keydown(function (e) {
3182        return thisObj.handlePrevKeyDown(e);
3183    });
3184
3185    this.$next.keydown(function (e) {
3186        return thisObj.handleNextKeyDown(e);
3187    });
3188
3189    ///////////// bind grid handlers //////////////
3190
3191    this.$grid.keydown(function (e) {
3192        return thisObj.handleGridKeyDown(e);
3193    });
3194
3195    this.$grid.keypress(function (e) {
3196        return thisObj.handleGridKeyPress(e);
3197    });
3198
3199    this.$grid.focus(function (e) {
3200        return thisObj.handleGridFocus(e);
3201    });
3202
3203    this.$grid.blur(function (e) {
3204        return thisObj.handleGridBlur(e);
3205    });
3206
3207    this.$grid.delegate('td', 'click', function (e) {
3208        return thisObj.handleGridClick(this, e);
3209    });
3210
3211} // end bindHandlers();
3212
3213function scrollToFirstHighlightDay() {
3214    // find all the heights of elements before the calendar
3215    var EventInfoHeight = $('#EventInformationWrap').outerHeight() + 64; // 64 is the height mobile navigation
3216    var EventLabelAndOptionsHeight = $('#eventCalendarLabelAndOptions').outerHeight(); 
3217    var CalendarMonthHeight =  $('.sw-datepicker.large-datepicker .month-wrap').outerHeight(); 
3218
3219    var EventInfoAndOptionsHeight = EventInfoHeight + EventLabelAndOptionsHeight;
3220    var CalendarTopInfoHeaderHeights = EventInfoHeight + EventLabelAndOptionsHeight + CalendarMonthHeight + 10; // 10 is just a gap added so it is not sticking against the month section
3221
3222    // set the Top section sticky so when it focuses on the first hightlight day you can still see the informations 
3223    $('#EventInformationWrap').addClass("make-this-section-sticky");
3224    $('#eventCalendarLabelAndOptions').addClass("make-this-section-sticky");
3225    $('#eventCalendarLabelAndOptions').css("top", EventInfoHeight);
3226    $('.sw-datepicker.large-datepicker .month-wrap').addClass("make-this-section-sticky");
3227    $('.sw-datepicker.large-datepicker .month-wrap').css("top", EventInfoAndOptionsHeight);
3228
3229    // Check if any elements with the class .highlight-day exist
3230    var highlightDay = $('.performance-list-calendar .highlight-day').first();
3231
3232    // set the first day cell
3233    var firstDayCel = $('.day-cell').first();
3234    var scrollToPosition = 0;
3235
3236    if (highlightDay.length > 0) { // Get the offset only if .highlight-day element exists
3237        scrollToPosition = highlightDay.offset().top;
3238        scrollToPosition = scrollToPosition - CalendarTopInfoHeaderHeights;  
3239        $('html, body').animate({scrollTop: scrollToPosition}, 'slow');
3240    } else { // if there's no highlights on this month, focus on the first day of the month
3241        scrollToPosition = firstDayCel.offset().top;
3242        scrollToPosition = scrollToPosition - (CalendarTopInfoHeaderHeights * 2);
3243        $('html, body').animate({scrollTop: scrollToPosition}, 'slow');
3244    }
3245}
3246
3247//
3248// handlePrevClick() is a member function to process click events for the prev month button
3249//
3250// @input (e obj) e is the event object associated with the event
3251//
3252// @return (boolean) false if consuming event, true if propagating
3253//
3254swDatepicker.prototype.handlePrevClick = function (e) {
3255    
3256    var active = this.$grid.attr('aria-activedescendant');
3257
3258    if (e.ctrlKey) {
3259        this.showPrevYear();
3260    }
3261    else {
3262        this.showPrevMonth();
3263    }
3264
3265    if (this.currentDate == false) {
3266        this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
3267    }
3268    else {
3269        this.$grid.attr('aria-activedescendant', active);
3270    }
3271
3272    e.stopPropagation();
3273    return false;
3274
3275} // end handlePrevClick()
3276
3277//
3278// handleNextClick() is a member function to process click events for the next month button
3279//
3280// @input (e obj) e is the event object associated with the event
3281//
3282// @return (boolean) false if consuming event, true if propagating
3283//
3284swDatepicker.prototype.handleNextClick = function (e) {
3285    
3286    var active = this.$grid.attr('aria-activedescendant');
3287
3288    if (e.ctrlKey) {
3289        this.showNextYear();
3290    }
3291    else {
3292        this.showNextMonth();
3293    }
3294
3295    if (this.currentDate == false) {
3296        this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
3297    }
3298    else {
3299        this.$grid.attr('aria-activedescendant', active);
3300    }
3301
3302    e.stopPropagation();
3303    return false;
3304
3305} // end handleNextClick()
3306
3307//
3308// handlePrevKeyDown() is a member function to process keydown events for the prev month button
3309//
3310// @input (e obj) e is the event object associated with the event
3311//
3312// @return (boolean) false if consuming event, true if propagating
3313//
3314swDatepicker.prototype.handlePrevKeyDown = function (e) {
3315
3316    if (e.altKey) {
3317        return true;
3318    }
3319
3320    switch (e.keyCode) {
3321        case this.keys.tab: {
3322            if (this.bModal == false || !e.shiftKey || e.ctrlKey) {
3323                return true;
3324            }
3325
3326            this.$grid.focus();
3327            e.stopPropagation();
3328            return false;
3329        }
3330        case this.keys.enter:
3331        case this.keys.space: {
3332            if (e.shiftKey) {
3333                return true;
3334            }
3335
3336            if (e.ctrlKey) {
3337                this.showPrevYear();
3338            }
3339            else {
3340                this.showPrevMonth();
3341            }
3342
3343            e.stopPropagation();
3344            return false;
3345        }
3346    }
3347
3348    return true;
3349
3350} // end handlePrevKeyDown()
3351
3352//
3353// handleNextKeyDown() is a member function to process keydown events for the next month button
3354//
3355// @input (e obj) e is the event object associated with the event
3356//
3357// @return (boolean) false if consuming event, true if propagating
3358//
3359swDatepicker.prototype.handleNextKeyDown = function (e) {
3360
3361    if (e.altKey) {
3362        return true;
3363    }
3364
3365    switch (e.keyCode) {
3366        case this.keys.enter:
3367        case this.keys.space: {
3368
3369            if (e.ctrlKey) {
3370                this.showNextYear();
3371            }
3372            else {
3373                this.showNextMonth();
3374            }
3375
3376            e.stopPropagation();
3377            return false;
3378        }
3379    }
3380
3381    return true;
3382
3383} // end handleNextKeyDown()
3384
3385//
3386// handleGridKeyDown() is a member function to process keydown events for the datepicker grid
3387//
3388// @input (e obj) e is the event object associated with the event
3389//
3390// @return (boolean) false if consuming event, true if propagating
3391//
3392swDatepicker.prototype.handleGridKeyDown = function (e) {
3393
3394    var $rows = this.$grid.find('tbody tr');
3395    var $curDay = $('#' + this.$grid.attr('aria-activedescendant'));
3396    var $days = this.$grid.find('td').not('.empty');
3397    var $curRow = $curDay.parent();
3398
3399    if (e.altKey) {
3400        return true;
3401    }
3402
3403    switch (e.keyCode) {
3404        case this.keys.tab: {
3405
3406            if (this.bModal == true) {
3407                if (e.shiftKey) {
3408                    this.$next.focus();
3409                }
3410                else {
3411                    this.$prev.focus();
3412                }
3413                e.stopPropagation()
3414                return false;
3415            }
3416            break;
3417        }
3418        case this.keys.enter:
3419        case this.keys.space: {
3420
3421            if (e.ctrlKey) {
3422                return true;
3423            }
3424
3425            // update the target box
3426            this.$target.val((this.month + 1) + '/' + $curDay.find(".calendar-day").text() + '/' + this.year).change();
3427
3428            // fall through
3429        }
3430        case this.keys.esc: {
3431            // dismiss the dialog box
3432            this.hideDlg();
3433
3434            e.stopPropagation();
3435            return false;
3436        }
3437        case this.keys.left: {
3438
3439            if (e.ctrlKey || e.shiftKey) {
3440                return true;
3441            }
3442
3443            var dayIndex = $days.index($curDay) - 1;
3444            var $prevDay = null;
3445
3446            if (dayIndex >= 0) {
3447                $prevDay = $days.eq(dayIndex);
3448
3449                $curDay.removeClass('focus').attr('aria-selected', 'false');
3450                $prevDay.addClass('focus').attr('aria-selected', 'true');
3451
3452                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
3453            }
3454            else {
3455                this.showPrevMonth(0);
3456            }
3457
3458            e.stopPropagation();
3459            return false;
3460        }
3461        case this.keys.right: {
3462
3463            if (e.ctrlKey || e.shiftKey) {
3464                return true;
3465            }
3466
3467            var dayIndex = $days.index($curDay) + 1;
3468            var $nextDay = null;
3469
3470            if (dayIndex < $days.length) {
3471                $nextDay = $days.eq(dayIndex);
3472                $curDay.removeClass('focus').attr('aria-selected', 'false');
3473                $nextDay.addClass('focus').attr('aria-selected', 'true');
3474
3475                this.$grid.attr('aria-activedescendant', $nextDay.attr('id'));
3476            }
3477            else {
3478                // move to the next month
3479                this.showNextMonth(1);
3480            }
3481
3482            e.stopPropagation();
3483            return false;
3484        }
3485        case this.keys.up: {
3486
3487            if (e.ctrlKey || e.shiftKey) {
3488                return true;
3489            }
3490
3491            var dayIndex = $days.index($curDay) - 7;
3492            var $prevDay = null;
3493
3494            if (dayIndex >= 0) {
3495                $prevDay = $days.eq(dayIndex);
3496
3497                $curDay.removeClass('focus').attr('aria-selected', 'false');
3498                $prevDay.addClass('focus').attr('aria-selected', 'true');
3499
3500                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
3501            }
3502            else {
3503                // move to appropriate day in previous month
3504                dayIndex = 6 - $days.index($curDay);
3505
3506                this.showPrevMonth(dayIndex);
3507            }
3508
3509            e.stopPropagation();
3510            return false;
3511        }
3512        case this.keys.down: {
3513
3514            if (e.ctrlKey || e.shiftKey) {
3515                return true;
3516            }
3517
3518            var dayIndex = $days.index($curDay) + 7;
3519            var $prevDay = null;
3520
3521            if (dayIndex < $days.length) {
3522                $prevDay = $days.eq(dayIndex);
3523
3524                $curDay.removeClass('focus').attr('aria-selected', 'false');
3525                $prevDay.addClass('focus').attr('aria-selected', 'true');
3526
3527                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
3528            }
3529            else {
3530                // move to appropriate day in next month
3531                dayIndex = 8 - ($days.length - $days.index($curDay));
3532
3533                this.showNextMonth(dayIndex);
3534            }
3535
3536            e.stopPropagation();
3537            return false;
3538        }
3539        case this.keys.pageup: {
3540            var active = this.$grid.attr('aria-activedescendant');
3541
3542
3543            if (e.shiftKey) {
3544                return true;
3545            }
3546
3547
3548            if (e.ctrlKey) {
3549                this.showPrevYear();
3550            }
3551            else {
3552                this.showPrevMonth();
3553            }
3554
3555            if ($('#' + active).attr('id') == undefined) {
3556                var lastDay = 'day' + this.calcNumDays(this.year, this.month);
3557                $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
3558            }
3559            else {
3560                $('#' + this.calendarName + '-' + active).addClass('focus').attr('aria-selected', 'true');
3561            }
3562
3563            e.stopPropagation();
3564            return false;
3565        }
3566        case this.keys.pagedown: {
3567            var active = this.$grid.attr('aria-activedescendant');
3568
3569
3570            if (e.shiftKey) {
3571                return true;
3572            }
3573
3574            if (e.ctrlKey) {
3575                this.showNextYear();
3576            }
3577            else {
3578                this.showNextMonth();
3579            }
3580
3581            if ($('#' + active).attr('id') == undefined) {
3582                var lastDay = 'day' + this.calcNumDays(this.year, this.month);
3583                $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
3584            }
3585            else {
3586                $('#' + this.calendarName + '-' + active).addClass('focus').attr('aria-selected', 'true');
3587            }
3588
3589            e.stopPropagation();
3590            return false;
3591        }
3592        case this.keys.home: {
3593
3594            if (e.ctrlKey || e.shiftKey) {
3595                return true;
3596            }
3597
3598            $curDay.removeClass('focus').attr('aria-selected', 'false');
3599
3600            $('#' + this.calendarName + '-day1').addClass('focus').attr('aria-selected', 'true');
3601
3602            this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
3603
3604            e.stopPropagation();
3605            return false;
3606        }
3607        case this.keys.end: {
3608
3609            if (e.ctrlKey || e.shiftKey) {
3610                return true;
3611            }
3612
3613            var lastDay = 'day' + this.calcNumDays(this.year, this.month);
3614
3615            $curDay.removeClass('focus').attr('aria-selected', 'false');
3616
3617            $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
3618
3619            this.$grid.attr('aria-activedescendant', this.calendarName + '-' + lastDay);
3620
3621            e.stopPropagation();
3622            return false;
3623        }
3624    }
3625
3626    return true;
3627
3628} // end handleGridKeyDown()
3629
3630//
3631// handleGridKeyPress() is a member function to consume keypress events for browsers that
3632// use keypress to scroll the screen and manipulate tabs
3633//
3634// @input (e obj) e is the event object associated with the event
3635//
3636// @return (boolean) false if consuming event, true if propagating
3637//
3638swDatepicker.prototype.handleGridKeyPress = function (e) {
3639
3640    if (e.altKey) {
3641        return true;
3642    }
3643
3644    switch (e.keyCode) {
3645        case this.keys.tab:
3646        case this.keys.enter:
3647        case this.keys.space:
3648        case this.keys.esc:
3649        case this.keys.left:
3650        case this.keys.right:
3651        case this.keys.up:
3652        case this.keys.down:
3653        case this.keys.pageup:
3654        case this.keys.pagedown:
3655        case this.keys.home:
3656        case this.keys.end: {
3657            e.stopPropagation();
3658            return false;
3659        }
3660    }
3661
3662    return true;
3663
3664} // end handleGridKeyPress()
3665
3666//
3667// handleGridClick() is a member function to process mouse click events for the datepicker grid
3668//
3669// @input (id obj) e is the id of the object triggering the event
3670//
3671// @input (e obj) e is the event object associated with the event
3672//
3673// @return (boolean) false if consuming event, true if propagating
3674//
3675swDatepicker.prototype.handleGridClick = function (id, e) {
3676    var $cell = $(id);
3677
3678    if ($cell.is('.empty')) {
3679        return true;
3680    }
3681
3682    this.$grid.find('.focus').removeClass('focus').attr('aria-selected', 'false');
3683    $cell.addClass('focus').attr('aria-selected', 'true');
3684    this.$grid.attr('aria-activedescendant', $cell.attr('id'));
3685
3686    var $curDay = $('#' + this.$grid.attr('aria-activedescendant'));
3687
3688    /*console.log($curDay);
3689    var isLastMonth = $curDay.hasClass('last-month');
3690
3691    var monthSelected = this.month + 1;
3692    var yearSelected = this.year;
3693    
3694    if (isLastMonth) {
3695        monthSelected--;
3696        
3697        if (monthSelected == 0)
3698            monthSelected = 12;
3699
3700        yearSelected = $curDay.data('year');
3701    }
3702
3703    console.log("month selected: " + monthSelected);
3704    console.log("year selected: " + yearSelected);*/
3705
3706    // update the target box
3707    if(this.type == 'dateRangeSelect'){
3708        if ($curDay.hasClass('muted'))
3709            return true;
3710        
3711        var $rangeSelDate = new Date((this.month + 1) + '/' + $curDay.children('.calendar-day').text() + '/' + this.year);
3712        if(this.fromDateRange == '' && this.toDateRange == ''){
3713            //no dates selected yet, store this in the from date range for now
3714            this.fromDateRange = $rangeSelDate;
3715        }else{
3716            //we've previously selected at least one date here, so figure out which one it should be
3717            if($rangeSelDate < this.fromDateRange){
3718                this.toDateRange = this.fromDateRange;
3719                this.fromDateRange = $rangeSelDate;
3720            }else{
3721                this.toDateRange = $rangeSelDate;
3722            }
3723        }
3724        
3725        var objDateRange = {}
3726        objDateRange.from = this.fromDateRange;
3727        objDateRange.to = this.toDateRange;
3728        this.$target.val(JSON.stringify(objDateRange)).change();
3729        if(objDateRange.from != '' && objDateRange.to != ''){
3730            this.hideDlg(); //NOTE: this only works if the date range is a modal, for other calendars you'll need to manage display according to needs based on current values.
3731        }
3732        e.stopPropagation();
3733        return false;
3734    }
3735    if (!this.forceDateSelection || $cell.hasClass("highlight-day")) {
3736        this.$target.val((this.month + 1) + '/' + $curDay.children('.calendar-day').text() + '/' + this.year).change();
3737        // dismiss the dialog box
3738        this.hideDlg();
3739    }
3740    e.stopPropagation();
3741    return false;
3742
3743} // end handleGridClick()
3744
3745//
3746// handleGridFocus() is a member function to process focus events for the datepicker grid
3747//
3748// @input (e obj) e is the event object associated with the event
3749//
3750// @return (boolean) true
3751//
3752swDatepicker.prototype.handleGridFocus = function (e) {
3753    var active = this.$grid.attr('aria-activedescendant');
3754
3755    if ($('#' + active).attr('id') == undefined) {
3756        var lastDay = 'day' + this.calcNumDays(this.year, this.month);
3757        $('#' + lastDay).addClass('focus').attr('aria-selected', 'true');
3758    }
3759    else {
3760        $('#' + active).addClass('focus').attr('aria-selected', 'true');
3761    }
3762
3763    return true;
3764
3765} // end handleGridFocus()
3766
3767//
3768// handleGridBlur() is a member function to process blur events for the datepicker grid
3769//
3770// @input (e obj) e is the event object associated with the event
3771//
3772// @return (boolean) true
3773//
3774swDatepicker.prototype.handleGridBlur = function (e) {
3775    $('#' + this.$grid.attr('aria-activedescendant')).removeClass('focus').attr('aria-selected', 'false');
3776
3777    return true;
3778
3779} // end handleGridBlur()
3780
3781//
3782// showDlg() is a member function to show the datepicker and give it focus. This function is only called if
3783// the datepicker is used in modal dialog mode.
3784//
3785// @return N/A
3786//
3787swDatepicker.prototype.showDlg = function () {
3788    if (!this.bModal)
3789        return;
3790
3791    var thisObj = this;
3792    var thisNode = this.$id;
3793
3794    this.highlightDays();
3795
3796    this.active = true;
3797
3798    //prevent calendar from pushing out of the right side of the window
3799    if (thisNode.parent()[0].getBoundingClientRect().left > (window.innerWidth / 2))
3800        thisNode.addClass("right-side");
3801
3802    $(".content-wrap").bind('click', function (e) {
3803        if (!thisNode[0].contains(e.target) && e.target != thisObj.$target[0]) {
3804            thisObj.hideDlg();
3805        }
3806    });
3807
3808    // show the dialog
3809    this.$id.attr('aria-hidden', 'false');
3810
3811    this.$grid.focus();
3812
3813} // end showDlg()
3814
3815//
3816// hideDlg() is a member function to hide the datepicker and remove focus. This function is only called if
3817// the datepicker is used in modal dialog mode.
3818//
3819// @return N/A
3820//
3821swDatepicker.prototype.hideDlg = function () {
3822    if (!this.bModal)
3823        return;
3824    
3825    this.active = false;
3826    var thisNode = this.$id;
3827
3828    // unbind the modal event sinks
3829    $(document).unbind('click');
3830
3831    // hide the dialog
3832    this.$id.attr('aria-hidden', 'true');
3833
3834    // set focus on the focus target
3835    //this.$target.focus();
3836
3837} // end showDlg()
3838
3839//function to highlight days with performances or valid information
3840//to prevent rewriting the calendar each time a date is added, popGrid() should be called after all dates have been added
3841swDatepicker.prototype.addHighlightDay = function (date) {
3842    var datesplit = String(date).split("/");
3843    for(var i = 0;i < datesplit.length; i++){
3844        datesplit[i] = datesplit[i].replace(/^0+/, '');
3845    }
3846    date = datesplit.join("/");
3847    if (datesplit.length != 3) {
3848        //date didn't come in in m/d/yyyy format, kick it back in the console
3849        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3850        console.log(date);
3851        return;
3852
3853    }
3854    this.highlightDates.push(date);
3855    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3856        $("#" + this.calendarName + "-day" + datesplit[1]).addClass("highlight-day");
3857    }
3858}
3859swDatepicker.prototype.addDateInfoBox = function (date, infoBoxText) {
3860    var datesplit = String(date).split("/");
3861    for(var i = 0;i < datesplit.length; i++){
3862        datesplit[i] = datesplit[i].replace(/^0+/, '');
3863    }
3864    date = datesplit.join("/");
3865    if (datesplit.length != 3) {
3866        //date didn't come in in m/d/yyyy format, kick it back in the console
3867        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3868        console.log(date);
3869        return;
3870
3871    }
3872    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3873        $("#" + this.calendarName + "-day" + datesplit[1]).append('<span class="date-info-box">' + infoBoxText + '</span>');
3874    }
3875}
3876swDatepicker.prototype.addDateSubNote = function (date, noteText) {
3877    var datesplit = String(date).split("/");
3878    for(var i = 0;i < datesplit.length; i++){
3879        datesplit[i] = datesplit[i].replace(/^0+/, '');
3880    }
3881    date = datesplit.join("/");
3882    if (datesplit.length != 3) {
3883        //date didn't come in in m/d/yyyy format, kick it back in the console
3884        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3885        console.log(date);
3886        return;
3887
3888    }
3889    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3890        var spanClass = this.isMultiplePerformanceIndicator ? 'date-info-box date-sub-note multiple-performancetime-subnote' : 'date-info-box date-sub-note';
3891        $("#" + this.calendarName + "-day" + datesplit[1]).append('<span class="' + spanClass + '">' + noteText + '</span>');
3892    }
3893}
3894swDatepicker.prototype.setDaySoldOut = function (date) {
3895    var datesplit = String(date).split("/");
3896    for(var i = 0;i < datesplit.length; i++){
3897        datesplit[i] = datesplit[i].replace(/^0+/, '');
3898    }
3899    date = datesplit.join("/");
3900    if (datesplit.length != 3) {
3901        //date didn't come in in m/d/yyyy format, kick it back in the console
3902        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3903        console.log(date);
3904        return;
3905
3906    }
3907    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3908        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('sold-out');
3909        
3910        this.addDateInfoBox(date, "Sold Out");
3911        $("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
3912    }
3913}
3914swDatepicker.prototype.setcustomStatus = function (date,showPhoneNumber,currenStatus) {
3915    var datesplit = String(date).split("/");
3916    for(var i = 0;i < datesplit.length; i++){
3917        datesplit[i] = datesplit[i].replace(/^0+/, '');
3918    }
3919    date = datesplit.join("/");
3920    if (datesplit.length != 3) {
3921        //date didn't come in in m/d/yyyy format, kick it back in the console
3922        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3923        console.log(date);
3924        return;
3925
3926    }
3927    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3928        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('sold-out');
3929        var phoneNumber = " <br> [email protected] "
3930        if (!showPhoneNumber)
3931            phoneNumber="";
3932        this.addDateInfoBox(date, currenStatus +phoneNumber);
3933        
3934        $("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
3935    }
3936}
3937swDatepicker.prototype.setDayLimitedAvailabilty = function (date) {
3938    var datesplit = String(date).split("/");
3939    for(var i = 0;i < datesplit.length; i++){
3940        datesplit[i] = datesplit[i].replace(/^0+/, '');
3941    }
3942    date = datesplit.join("/");
3943    if (datesplit.length != 3) {
3944        //date didn't come in in m/d/yyyy format, kick it back in the console
3945        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3946        console.log(date);
3947        return;
3948
3949    }
3950    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3951        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('limited-availability');
3952        
3953        this.addDateSubNote(date, 'Selling Quickly');
3954        //$("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
3955    }
3956    if($(".limited-availability-legend-item").length == 0){
3957        
3958            $(".calendar-notes-wrap").append('<div class="limited-availability-legend-item"><span classs="calendar-limited-availability-legend-icon">!</span> - Selling Quickly</div>')
3959         
3960       // $("#streamlinedCalendarLimitedAvailabilityLegend").append('<div class="limited-availability-legend-item"><span class="calendar-limited-availability-legend-icon">!</span> - Selling Quickly</div>')
3961    }
3962}
3963swDatepicker.prototype.setMultiplePerformanceTimes = function (date) {
3964    var datesplit = String(date).split("/");
3965    for(var i = 0;i < datesplit.length; i++){
3966        datesplit[i] = datesplit[i].replace(/^0+/, '');
3967    }
3968    
3969    date = datesplit.join("/");
3970    if (datesplit.length != 3) {
3971        //date didn't come in in m/d/yyyy format, kick it back in the console
3972        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3973        return;
3974
3975    }
3976    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3977        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('multipleperformancetimes');
3978
3979    }
3980    if($(".multiple-performancetimes-notes").length == 0){
3981        
3982    }
3983    
3984}
3985swDatepicker.prototype.setMutedDay = function (date) {
3986    var datesplit = String(date).split("/");
3987    for(var i = 0;i < datesplit.length; i++){
3988        datesplit[i] = datesplit[i].replace(/^0+/, '');
3989    }
3990    date = datesplit.join("/");
3991    if (datesplit.length != 3) {
3992        //date didn't come in in m/d/yyyy format, kick it back in the console
3993        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3994        return;
3995
3996    }
3997    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3998        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('muted');
3999    }
4000}
4001swDatepicker.prototype.clearMutedDay = function (date) {
4002    var datesplit = String(date).split("/");
4003    for(var i = 0;i < datesplit.length; i++){
4004        datesplit[i] = datesplit[i].replace(/^0+/, '');
4005    }
4006    date = datesplit.join("/");
4007    if (datesplit.length != 3) {
4008        //date didn't come in in m/d/yyyy format, kick it back in the console
4009        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
4010        return;
4011
4012    }
4013    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
4014        $("#" + this.calendarName + "-day" + datesplit[1]).removeClass('muted');
4015    }
4016}
4017swDatepicker.prototype.setCouponMutedDay = function (date) {
4018    var datesplit = String(date).split("/");
4019    for(var i = 0;i < datesplit.length; i++){
4020        datesplit[i] = datesplit[i].replace(/^0+/, '');
4021    }
4022    date = datesplit.join("/");
4023    if (datesplit.length != 3) {
4024        //date didn't come in in m/d/yyyy format, kick it back in the console
4025        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
4026        return;
4027
4028    }
4029    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
4030        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('coupon-muted');
4031    }
4032}
4033swDatepicker.prototype.setPasswordHiddenDay = function (date) {
4034    var datesplit = String(date).split("/");
4035    for(var i = 0;i < datesplit.length; i++){
4036        datesplit[i] = datesplit[i].replace(/^0+/, '');
4037    }
4038    date = datesplit.join("/");
4039    if (datesplit.length != 3) {
4040        //date didn't come in in m/d/yyyy format, kick it back in the console
4041        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
4042        return;
4043
4044    }
4045    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
4046        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('password-hidden');
4047        $("#" + this.calendarName + "-day" + datesplit[1]).removeClass('highlight-day');
4048    }
4049}
4050swDatepicker.prototype.clearAllMutedDays = function () {
4051    $(".muted").removeClass('muted');
4052}
4053swDatepicker.prototype.clearHighlightDays = function () {
4054    this.highlightDates = [];
4055    this.highlightDays();
4056}
4057//highlights all days in the highlightDates array
4058swDatepicker.prototype.highlightDays = function () {
4059    $("#" + this.calendarName + " .highlight-day").removeClass("highlight-day");
4060    var curYear = this.year;
4061    var curMonth = this.month;
4062    var calName = this.calendarName;
4063    var IEFix = new RegExp(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g);
4064
4065    this.highlightDates.forEach(function (o, i, a) {
4066        var datesplit = o.split("/");
4067        if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
4068            $("#" + calName + "-day" + datesplit[1].replace(IEFix, '')).addClass("highlight-day");
4069        }
4070    });
4071    this.setColors();
4072}
4073swDatepicker.prototype.setColors = function () {
4074    /*
4075        Custom color functionality. Utilized by dropping calendar-colors.txt file in root of custom folder
4076        requires json content of text file formatted as follows:
4077        {
4078            "events":
4079                {"528": 
4080                    [
4081                        {"date":"12/1/2025", "color": "#ccc"}, 
4082                        {"date":"12/2/2025", "color": "#ccc"}
4083                    ]
4084                ,
4085                "529":
4086                    [
4087                        {"date":"12/8/2025", "color": "#ccc"}, 
4088                        {"date":"12/9/2025", "color": "#ccc"}
4089                    ]
4090                }
4091            ,
4092            "bundles":[],
4093            "generic":
4094                {"dates": 
4095                    [
4096                        {"date":"12/23/2025", "color": "#def"}, 
4097                        {"date":"12/22/2025", "color": "#1a1"}
4098                    ]
4099                ,
4100                "weekdays":
4101                    [
4102                        {"day":"Saturday", "color": "#2a2"}, 
4103                        {"day":"Thursday", "color": "#3a3"}
4104                    ]
4105                }    
4106        }
4107    }
4108    */
4109    var thisDP = this;
4110    try{
4111        $.getJSON("/calendar-colors.txt")
4112        .done(function (data) {
4113            thisDP.renderColors(data);
4114        })
4115        .fail(function (jqxhr, textStatus, error) {
4116            console.log("No Custom Calendar Colors Found");
4117            return;
4118        });
4119    }catch(e){
4120        console.log("parsing error:");
4121        console.log(e);
4122        return;
4123    }
4124}
4125swDatepicker.prototype.renderColors = function (colorData) {
4126    var curYear = this.year;
4127    var curMonth = this.month;
4128    var calName = this.calendarName;
4129    var IEFix = new RegExp(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g);
4130    //set generic colors
4131    if(colorData.generic){
4132        if(colorData.generic.dates.length > 0){
4133            colorData.generic.dates.forEach(function (o, i, a) {
4134                var datesplit = o.date.split("/");
4135                if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
4136                    $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
4137                }
4138            });
4139        }
4140        if(colorData.generic.weekdays && colorData.generic.weekdays.length > 0){
4141            colorData.generic.weekdays.forEach(function (o, i, a) {
4142                $("td[headers*=" + o.day + "] .calendar-day").css("background-color", o.color);
4143            });
4144        }
4145    }
4146    if(colorData.events && colorData.events[this.eventID] && this.eventID !== -1){
4147        colorData.events[this.eventID].forEach(function (o, i, a) {
4148            var datesplit = o.date.split("/");
4149            if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
4150                $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
4151            }
4152        });
4153    }
4154    if(colorData.bundles && colorData.bundles[this.bundleID] && this.bundleID !== -1){
4155        colorData.bundles[this.bundleID].forEach(function (o, i, a) {
4156            var datesplit = o.date.split("/");
4157            if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
4158                $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
4159            }
4160        });
4161    }
4162}
4163swDatepicker.prototype.fetchDates = function(){
4164    var thisCalendar = this;
4165    var haveDates = thisCalendar.fetchLocalDates();
4166    if (thisCalendar.categoryID >= 0)
4167        haveDates = false;
4168    this.clearHighlightDays();
4169    if(haveDates){
4170        //valid local dates stored
4171        try{
4172            haveDates = JSON.parse(haveDates);
4173            if (haveDates.length > 0) {
4174                haveDates.forEach(function(o){
4175                    thisCalendar.addHighlightDay(o);
4176                })
4177                thisCalendar.highlightDays();
4178            }
4179        } catch (e) {
4180            console.log("Failed to grab dates. Date object not valid: ", haveDates);
4181            console.log(e);
4182        }
4183    } else {        
4184        $.getJSON("/include/widgets/calendar/calendarRequests.asp",
4185            {
4186                action: thisCalendar.type,
4187                calMonth: thisCalendar.activeMonth,
4188                iEvent: thisCalendar.eventID,
4189                iBundle: thisCalendar.bundleID,
4190                iCategory : thisCalendar.categoryID,
4191                cp : thisCalendar.corporatePartnerPage
4192            })
4193            .done(function (data) {
4194                thisCalendar.storeDates(data.performancedates);
4195                try {
4196                    if (data.performancedates.length > 0) {
4197                        data.performancedates.forEach(function (o) {
4198                            
4199                            thisCalendar.addHighlightDay(o);
4200                        })
4201                        thisCalendar.highlightDays();
4202                    }
4203                } catch (e) {
4204                    console.log("Failed to grab dates. Date object not valid: " + haveDates);
4205                    console.log(e);
4206                }
4207                $(".calendar-loading").hide();
4208            })
4209            .fail(function (jqxhr, textStatus, error) {
4210                var err = textStatus + ", " + error;
4211                console.log("Request Failed: " + err);
4212                $(".calendar-loading").hide();
4213            });
4214    }
4215}
4216swDatepicker.prototype.getCalendarDetails = function(){
4217    var thisCalendar = this;
4218    this.clearHighlightDays();
4219    $("#" + this.calendarName).removeClass("has-muted-days");
4220    $.getJSON("/include/widgets/calendar/calendarRequests.asp",
4221        {
4222            action: thisCalendar.type,
4223            calMonth: thisCalendar.activeMonth,
4224            iEvent: thisCalendar.eventID,
4225            iBundle: thisCalendar.bundleID,
4226            iCategory : thisCalendar.categoryID,
4227            cp : thisCalendar.corporatePartnerPage,
4228            bValidCoupon : thisCalendar.bValidCoupon,
4229            couponCode : thisCalendar.couponCode
4230        })
4231        .done(function (data) {
4232            //to save on request time, we need to resolve the data on the client a bit before we store it
4233            var performanceDates = [];
4234            data.performanceDateData.forEach(function(dd){
4235                
4236                if(dd.DoNotShowPublic == 0){
4237                    var detailsObj = {};
4238                    var currentDateIndex = fetchDateIndex(dd.CalendarDate, performanceDates);
4239                    if(currentDateIndex == -1){
4240                        detailsObj.date = dd.CalendarDate;
4241                        detailsObj.performances = [];
4242                        detailsObj.performances.push(dd.PerformanceCode);
4243                        detailsObj.defaultPrice = dd.LowestDefaultPrice;
4244                        detailsObj.PerformanceName = dd.PerformanceName;
4245                        detailsObj.PerformanceTime = dd.PerfTime;
4246                        detailsObj.PerformanceStartTimeAlias = dd.PerformanceStartTimeAlias;
4247                        detailsObj.DisplayType = dd.DisplayType;
4248                        detailsObj.CalendarViewShowPrice = dd.CalendarViewShowPrice;
4249                        detailsObj.CalendarViewShowPerformanceName = dd.CalendarViewShowPerformanceName;
4250                        detailsObj.CalendarViewShowPerformanceTime = dd.CalendarViewShowPerformanceTime;
4251                        detailsObj.CalendarViewShowBuyButton = dd.CalendarViewShowBuyButton;
4252                        detailsObj.defaultPricingCode = dd.LowestDefaultPricingCode;
4253                        detailsObj.secondaryPrice = dd.LowestSecondaryPrice;
4254                        detailsObj.secondaryPricingCode =dd.LowestSecondaryPricingCode;
4255                        detailsObj.NoCouponAvailable = dd.NoCouponAvailable;
4256                        detailsObj.passwordMatch = dd.passwordMatch;
4257                        detailsObj.qualifierPasswordMatch = dd.qualifierPasswordMatch;
4258                        detailsObj.hasPassword = dd.hasPassword;
4259                        detailsObj.hasQualifierPassword = dd.hasQualifierPassword;
4260                        detailsObj.hasCoupons = dd.hasCoupons; 
4261                        detailsObj.IsSalesPeriodEnded = dd.IsSalesPeriodEnded;
4262                        detailsObj.SaleIcon = dd.SaleIcon;
4263                        detailsObj.BSaleIcon = dd.BSaleIcon;
4264                        
4265                        detailsObj.hasQualifiers = dd.hasQualifiers;
4266                        performanceDates.push(detailsObj)
4267                       
4268                    }else{
4269                        performanceDates[currentDateIndex].performances.push(dd.PerformanceCode);
4270                        performanceDates[currentDateIndex].NoCouponAvailable = dd.NoCouponAvailable;
4271                        performanceDates[currentDateIndex].passwordMatch = dd.passwordMatch;
4272                        performanceDates[currentDateIndex].acMatch = dd.acMatch;
4273                        performanceDates[currentDateIndex].qualifierPasswordMatch = dd.qualifierPasswordMatch;
4274                        performanceDates[currentDateIndex].hasPassword = dd.hasPassword;
4275                        performanceDates[currentDateIndex].hasQualifierPassword = dd.hasQualifierPassword;
4276                        performanceDates[currentDateIndex].hasCoupons = dd.hasCoupons;
4277                        performanceDates[currentDateIndex].PerformanceName = dd.PerformanceName;
4278                        performanceDates[currentDateIndex].PerformanceTime = dd.PerfTime;
4279                        performanceDates[currentDateIndex].PerformanceStartTimeAlias = dd.PerformanceStartTimeAlias;
4280                        performanceDates[currentDateIndex].CalendarViewShowPrice = dd.CalendarViewShowPrice;
4281                        performanceDates[currentDateIndex].CalendarViewShowPerformanceName = dd.CalendarViewShowPerformanceName;
4282                        performanceDates[currentDateIndex].CalendarViewShowPerformanceTime = dd.CalendarViewShowPerformanceTime;
4283                        performanceDates[currentDateIndex].CalendarViewShowBuyButton = dd.CalendarViewShowBuyButton;
4284                        performanceDates[currentDateIndex].IsSalesPeriodEnded = dd.IsSalesPeriodEnded;
4285                        performanceDates[currentDateIndex].SaleIcon = dd.SaleIcon;
4286                        performanceDates[currentDateIndex].BSaleIcon = dd.BSaleIcon;                        
4287                        performanceDates[currentDateIndex].hasQualifiers = dd.hasQualifiers;
4288                        //check for lowest price
4289                        if(performanceDates[currentDateIndex].defaultPrice > dd.LowestDefaultPrice && dd.LowestDefaultPrice != null){
4290                            performanceDates[currentDateIndex].defaultPrice = dd.LowestDefaultPrice;
4291                            performanceDates[currentDateIndex].defaultPricingCode = dd.LowestDefaultPricingCode;
4292                        }
4293                        if(performanceDates[currentDateIndex].hasCoupons == 1 && performanceDates[currentDateIndex].defaultPrice < dd.LowestDefaultPrice && dd.LowestDefaultPrice != null && false){
4294                            performanceDates[currentDateIndex].defaultPrice = dd.LowestDefaultPrice;
4295                            performanceDates[currentDateIndex].defaultPricingCode = dd.LowestDefaultPricingCode;
4296                        }
4297                        if(performanceDates[currentDateIndex].secondaryPrice > dd.LowestSecondaryPrice && dd.LowestSecondaryPrice != null){
4298                            performanceDates[currentDateIndex].secondaryPrice = dd.LowestSecondaryPrice;
4299                            performanceDates[currentDateIndex].secondaryPricingCode = dd.LowestSecondaryPricingCode;
4300                        }
4301                         
4302                        
4303                    }
4304                    //set limited availaibility by matching up results from query with performances
4305                    for(perf in data.performances){
4306                        if(data.performances[perf].id == dd.PerformanceID){
4307                            data.performances[perf].LimitedAvailability = dd.LimitedAvailability;
4308                            data.performances[perf].TimeZone = dd.TimeZone.replace('"', "");
4309                            data.performances[perf].SingleAreaVenueAreaID = dd.SingleAreaVenueAreaID;
4310                            data.performances[perf].NoCouponAvailable = dd.NoCouponAvailable;
4311                            data.performances[perf].passwordMatch = dd.passwordMatch;
4312                            data.performances[perf].acMatch = dd.acMatch;
4313                            data.performances[perf].qualifierPasswordMatch = dd.qualifierPasswordMatch;
4314                            data.performances[perf].hasPassword = dd.hasPassword;
4315                            data.performances[perf].hasQualifierPassword = dd.hasQualifierPassword;
4316                        }
4317                    }
4318                }
4319                
4320            })
4321            
4322            data.performanceDates = performanceDates;
4323            delete data.performanceDateData;
4324            try {
4325                if (thisCalendar.couponCode != "" && $("#couponCode").length > 0)
4326                {
4327                    if($("#coupon-notify").length > 0)
4328                        $("#coupon-notify").remove();
4329
4330                    var notifyMessage = document.createElement("div");
4331                    notifyMessage.setAttribute("id","coupon-notify");
4332                    notifyMessage.setAttribute("class",data.hasValidCoupon ? 'coupon-notify-message' : 'coupon-error-message');
4333                    notifyMessage.innerHTML = (data.hasValidCoupon ? "Code <b>" + thisCalendar.couponCode + "</b> has been applied to valid dates and times." : "The code entered is either invalid, or no longer available.");
4334                    $("#plCalendar").prepend(notifyMessage);
4335                    window.scrollTo(0,0);
4336                }                
4337                
4338                thisCalendar.doCalendarDetailed(data);
4339            } catch (e) {
4340                console.log("Failed to parse details. Date object not valid: ", data);
4341                console.log(e);
4342            }
4343        })
4344        .fail(function (jqxhr, textStatus, error) {
4345            var err = textStatus + ", " + error;
4346            console.log("Request Failed: " + err);
4347        });
4348}
4349swDatepicker.prototype.doCalendarDetailed = function(detailData){
4350    var thisCalendar = this;
4351    this.detailData = detailData;
4352    var defaultPricingLegend = [], secondaryPricingLegend = [];
4353    detailData.performanceDates.forEach(function(d){
4354        thisCalendar.addHighlightDay(d.date);
4355        if (d.NoCouponAvailable > 0)
4356            thisCalendar.setCouponMutedDay(d.date);
4357        
4358        //check if date sold out
4359        var dateSoldOut = true;
4360        var customStatus = false;
4361        var showPhoneNumber =false;
4362        var dateLimitedAvailability = false;
4363        var performanceStatus="";
4364        var performanceOnSale = false;
4365        var IsSalesPeriodEnded = false;
4366        var aggregatedMentaInfo = {
4367            buttonVisible: false,
4368            buttonText: "",
4369            buttonUrl: "",
4370            totalCount: 0
4371        };
4372
4373        var isMentaResaleAvailable = false;
4374        var performanceTimesLength = 0;
4375        var QualiferButton = false;
4376        d.performances.forEach(function(datePerformance){
4377            var performanceKey = String(datePerformance).toLowerCase();
4378            var currentPerformance = detailData.performances[performanceKey];
4379
4380            if (!currentPerformance) {
4381                var perfIndex = d.performances.indexOf(datePerformance);
4382                if (perfIndex !== -1) {
4383                    d.performances.splice(perfIndex, 1);
4384                }
4385                console.log("Date Trimmed, child performance not contained in performance data: " + datePerformance);
4386                return;
4387            }
4388
4389            //let currentPerformance = detailData.performances[String(datePerformance).toLowerCase()];
4390            performanceTimesLength ++;
4391
4392            if(detailData.performances[String(datePerformance).toLowerCase()] && detailData.performances[String(datePerformance).toLowerCase()].status == "On Sale"){
4393                dateSoldOut = false;
4394                performanceOnSale=true;
4395                if(currentPerformance.LimitedAvailability == 1)
4396                    dateLimitedAvailability = true;
4397                        
4398                IsSalesPeriodEnded  =   currentPerformance.IsSalesPeriodEnded==1        
4399            }            
4400            else{
4401                
4402                if ((currentPerformance.status != "Sold Out") && (currentPerformance.status != "On Sale")  ){
4403                    
4404                    customStatus=true;
4405                    performanceStatus=currentPerformance.status;
4406                    dateSoldOut = false;
4407                    //dateLimitedAvailability=false;
4408                    if ( currentPerformance.bSalePhone==1 || currentPerformance.SalePhone==1){
4409                        showPhoneNumber=true;
4410                    }
4411                }
4412                var mentaMarketplace = currentPerformance.MentaMarketplace;
4413                var hasMentaOption = currentPerformance.IsMentaEnabled == 1 && mentaMarketplace && mentaMarketplace.buttonVisible;
4414
4415                if (hasMentaOption) {
4416                    var availableCount = parseInt(mentaMarketplace.totalCount, 10);
4417                    if (!isNaN(availableCount) && availableCount > 0) {
4418                        aggregatedMentaInfo.totalCount += availableCount;
4419                    }
4420                    if (mentaMarketplace.buttonText && aggregatedMentaInfo.buttonText === "") {
4421                        aggregatedMentaInfo.buttonText = mentaMarketplace.buttonText;
4422                    }
4423                    if (mentaMarketplace.buttonUrl && aggregatedMentaInfo.buttonUrl === "") {
4424                        aggregatedMentaInfo.buttonUrl = mentaMarketplace.buttonUrl;
4425                    }
4426                    aggregatedMentaInfo.buttonVisible = true;
4427                    dateSoldOut = false;
4428                    showPhoneNumber=false;
4429                    customStatus=true;
4430                }
4431            }
4432           
4433            // If date is sold out or custom status (not 'on sale'), check if qualifier access code or password match
4434            if (dateSoldOut || customStatus) {
4435                if (currentPerformance.acMatch == 1 || (currentPerformance.qualifierPasswordMatch == 1 && currentPerformance.hasQualifierPassword == 1)) {
4436                    dateSoldOut = false;
4437                    customStatus = false;
4438                    performanceOnSale = true;
4439                    showPhoneNumber = false;
4440                }
4441            }
4442            // If date is sold out or custom status (not 'on sale'), check if it has a public qualifier -- hasQualifiers is set on CalendarRequests.asp when qualifiers exist for performance
4443            if (currentPerformance.hasQualifiers) {
4444                    dateSoldOut = false;
4445                    customStatus = false;
4446                    performanceOnSale = true;
4447                    showPhoneNumber = false;
4448                    QualiferButton = true;
4449                  // If performance has qualifier but status is "On Sale", do not show "Premium Access" text on calendar date
4450                  if (currentPerformance.status == "On Sale") {
4451                    QualiferButton = false;
4452                 } 
4453                 
4454            }
4455        })
4456
4457        if (aggregatedMentaInfo.buttonVisible && aggregatedMentaInfo.buttonText === "") {
4458            aggregatedMentaInfo.buttonText = "Official Resale Available";
4459        }
4460        var hasMentaCtaForDate = aggregatedMentaInfo.buttonVisible && (aggregatedMentaInfo.totalCount > 0 || aggregatedMentaInfo.buttonUrl !== "");
4461        isMentaResaleAvailable = hasMentaCtaForDate && !performanceOnSale;
4462        d.MentaMarketplace = aggregatedMentaInfo;
4463        
4464        if(dateLimitedAvailability && !dateSoldOut){
4465            thisCalendar.setDayLimitedAvailabilty(d.date);
4466        }
4467        if (thisCalendar.isMultiplePerformanceIndicator == 1 && performanceTimesLength > 1) {
4468            thisCalendar.setMultiplePerformanceTimes(d.date);
4469        }
4470        if ( IsSalesPeriodEnded) {
4471            performanceStatus=d.SaleIcon;
4472        }
4473        else{
4474            if(isMentaResaleAvailable && !performanceOnSale){                
4475               
4476                thisCalendar.addDateSubNote(d.date, 'Sold Out');
4477                //thisCalendar.setDaySoldOut(d.date);
4478                //thisCalendar.addDateInfoBox(d.date, "Sold Out");
4479                 thisCalendar.configureMentaSettings(d);            
4480            }
4481            else{ 
4482              performanceStatus=d.BSaleIcon;
4483            }
4484        
4485        }
4486
4487        if (performanceStatus == null || performanceStatus == "")
4488            performanceStatus="sold out";
4489
4490        if(dateSoldOut){
4491            thisCalendar.setDaySoldOut(d.date);
4492        }else{
4493            if ( (customStatus && !dateLimitedAvailability && !performanceOnSale && !isMentaResaleAvailable) || IsSalesPeriodEnded)
4494            {
4495                thisCalendar.setcustomStatus(d.date,showPhoneNumber,performanceStatus)
4496            }
4497            else{
4498            //date not sold out, add details, add to legend if one exists
4499            var detailString = "";
4500
4501            // if the price option is checked in event landing page in the admin 
4502             if(d.CalendarViewShowPrice != 0){
4503                //for now, we'll just add the pricing, this would be a spot to modify what is displayed on the dates by changing the contents of this string
4504                if(d.defaultPrice != null){
4505                    if (QualiferButton) { // SHOWDEV-22142 - If date has public qualifier, show qualifier text (Premium Access) instead of price and buy button
4506                        detailString = detailString + "<span class='display-perfbuybutton'>Premium Access</span>";
4507                    }else {
4508                           
4509                            detailString = "<span class='display-perfprice'>" + thisCalendar.currencySymbol + d.defaultPrice.toFixed(2).replace('.00','') + "</span>";
4510                        
4511                    }
4512                    
4513                if(defaultPricingLegend.indexOf(d.defaultPricingCode) === -1)
4514                    defaultPricingLegend.push(d.defaultPricingCode);
4515                }
4516                if(d.secondaryPricingCode != "" && d.secondaryPricingCode != null){
4517                    if(secondaryPricingLegend.indexOf(d.secondaryPricingCode) === -1)
4518                        secondaryPricingLegend.push(d.secondaryPricingCode);           
4519                    
4520                    if (d.DisplayType === "calendar" || d.DisplayType === "streamlined") {
4521                           
4522                        detailString = "<span class='display-perfprice-withchild'>" + thisCalendar.currencySymbol + d.secondaryPrice.toFixed(2).replace('.00','') + "/</span>" + detailString;
4523                        
4524                    }
4525                }
4526            }
4527            if(d.CalendarViewShowPerformanceName != 0){
4528                detailString =  detailString + "<span class='display-perfname'>" + d.PerformanceName + "</span> ";
4529            }
4530           
4531            if(d.CalendarViewShowPerformanceTime != 0){
4532                if(d.PerformanceStartTimeAlias != ""){ // Performance Alias time is present
4533                    detailString = detailString + " <span class='display-perft
4533ime'>" + d.PerformanceStartTimeAlias + "</span>";
4534                } else {
4535                    detailString = detailString + " <span class='display-perftime'>" + d.PerformanceTime + "</span>";
4536                }
4537                
4538            }
4539            if(d.CalendarViewShowBuyButton != 0){
4540                var styleString = "";
4541                if (d.DisplayType === "streamlined")
4542                    styleString = " style='width: 100%;'";
4543                var buttonText = (isMentaResaleAvailable && d.OverrideBuyTicketsButtonText) ? d.OverrideBuyTicketsButtonText : thisCalendar.buyTicketsButtonText;
4544                detailString = detailString + "<span class='button display-perfbuybutton'"+styleString+">" + buttonText + "</span>";
4545            }
4546
4547            thisCalendar.addDateInfoBox(d.date, detailString);
4548            }
4549        }
4550        
4551    })
4552    //for now, we only generate the legend if there are one or two prices pesent
4553    if(defaultPricingLegend.length === 1 && secondaryPricingLegend.length === 1){
4554        $("#calendarLegend").html(secondaryPricingLegend[0] +" / " + defaultPricingLegend[0])
4555        
4556        $("#calendarLegend").show();
4557    }else{
4558        if(defaultPricingLegend.length === 1){
4559                $("#calendarLegend").html(defaultPricingLegend[0])
4560                
4561                $("#calendarLegend").show();
4562        }else{
4563            $("#calendarLegend").hide();
4564        }
4565    }
4566    if(typeof(setFilterOptions) == 'function'){
4567        setFilterOptions(thisCalendar);
4568    }
4569    if (detailData.hasValidCoupon) {
4570        $("#plCalendar").append("<input type='hidden' id='hasValidCoupon' value='1' />");
4571    } else {
4572        $("#plCalendar").append("<input type='hidden' id='hasValidCoupon' value='0' />");
4573    }
4574    $(".calendar-loading").hide();
4575}
4576swDatepicker.prototype.configureMentaSettings = function (dateDetail) {
4577    // Set Menta Resale Settings
4578    
4579}
4580
4581swDatepicker.prototype.getFirstDate = function(defaultMonth){
4582    var thisCalendar = this;
4583    //this should only happen once on calendar load - currently only enabled for bundles
4584    if(thisCalendar.bundleID == 0 || thisCalendar.bundleID == -1)
4585        return defaultMonth; //currently only developed for bundles TODO: add event, category, standard support.
4586
4587    $.getJSON("/include/widgets/calendar/calendarRequests.asp",
4588            {
4589                action: 'initialBundleDate',
4590                iBundle: thisCalendar.bundleID,
4591                cp : thisCalendar.corporatePartnerPage
4592            })
4593            .done(function (data) {
4594                try {
4595                    if (data.performancedates.length > 0) {
4596                        
4597    
4598                        var firstMonth = Number(String(data.performancedates).split("/")[0]) - 1;
4599                        var firstYear = Number(String(data.performancedates).split("/")[2]);
4600                        thisCalendar.month = firstMonth - 1; //to make this simple, we're using the showNextMonth() function, which means we need to set the month to 1 less than our target, as that function increments the month itself
4601                        thisCalendar.year = firstYear;
4602                        thisCalendar.showNextMonth();
4603                    }else{
4604                        return defaultMonth;
4605                    }
4606                }catch(e){
4607                    console.log("getFirstDate returned invalid date. Default used");
4608                    console.log(e);
4609                    return defaultMonth;
4610                }
4611            })
4612            .fail(function (jqxhr, textStatus, error) {
4613                var err = textStatus + ", " + error;
4614                console.log("Request Failed: " + err);
4615            });
4616}
4617swDatepicker.prototype.fetchLocalDates = function () {
4618    //utliize storage to store months
4619    var CalendarExpireTime = new Date().getTime(); var isExpired = false; var datesData = "";
4620    var calendarIDString = this.calendarName + this.type + this.eventID + this.bundleID + "-" + this.corporatePartnerPage + "_" + this.activeMonth;
4621    try {
4622        //check for local storage support
4623        isExpired = CalendarExpireTime > Number(localStorage.getItem("CalendarExpireTime_" + calendarIDString));
4624        if (isExpired) {
4625            //item expired, clear local results
4626            localStorage.setItem("ShowareDates_" + calendarIDString, "");
4627            localStorage.setItem("CalendarExpireTime_" + calendarIDString, CalendarExpireTime + (1000 * 60 * 30));  //item information expires after 30 minutes
4628            return false;
4629        }
4630        localStorage.setItem("CalendarExpireTime_" + calendarIDString, CalendarExpireTime + (1000 * 60 * 30));  //item information expires after 30 minutes
4631        if (localStorage.getItem("ShowareDates_" + calendarIDString) != null && localStorage.getItem("ShowareDates_" + calendarIDString) != "" && localStorage.getItem("ShowareDates_" + calendarIDString) != []) {
4632            return localStorage.getItem("ShowareDates_" + calendarIDString);
4633        } else {
4634            //date info not stored
4635            return false;
4636        }
4637    } catch (e) {
4638        return false;
4639    }
4640}
4641swDatepicker.prototype.storeDates = function (dateData) {
4642    
4643    var calendarIDString = this.calendarName + this.type + this.eventID + this.bundleID + "-" + this.corporatePartnerPage + "_" + this.activeMonth;
4644    try {
4645        localStorage.setItem("ShowareDates_" + calendarIDString, JSON.stringify(dateData));
4646    } catch (e) {
4647        //no local storage
4648    }
4649}
4650swDatepicker.prototype.getDateRangeEvents = function (dateRangeData) {
4651    var thisCalendar = this;
4652    try{
4653        $.getJSON("/include/widgets/calendar/calendarRequests.asp",
4654            {
4655                action: 'getDateRangeEvents',
4656                dateRange: JSON.stringify(dateRangeData),
4657            })
4658            .done(function (data) {
4659                try {
4660                    thisCalendar.dateRangeEvents = data;
4661                }catch(e){
4662                    console.log("getDateRangeEvents returned invali
4662d response.");
4663                    console.log(data, e);
4664                    return []//return empty array;
4665                }
4666            })
4667            .fail(function (jqxhr, textStatus, error) {
4668                var err = textStatus + ", " + error;
4669                console.log("Request Failed: " + err);
4670            });
4671
4672    }catch(e){
4673        console.log("Unable to fetch date range events:", e)
4674    }
4675}
4676swDatepicker.prototype.clearDateRange = function () {
4677    this.fromDateRange = '';
4678    this.toDateRange = '';
4679}
4680function fetchDateIndex(dateString, dateObjectArray){
4681    try{
4682        for(var i = 0;i < dateObjectArray.length;i++){
4683            if(dateObjectArray[i].date == dateString){
4684                return i;
4685                break;
4686            }
4687        }
4688        return -1;
4689    }catch(e){
4690        //this function requires specific objects with a date property, it will fail otherwise and we'll just return what one would expect from a failed indexof
4691        return -1;
4692    }
4693}
4694function swapMonthDay(d){
4695    //expects dd/mm/yyyy format
4696    try{
4697        let splitDate = d.split("/");
4698        let newDate = splitDate[1] + '/' + splitDate[0] + "/" + splitDate[2];
4699        return newDate;
4700    }catch(e){
4701        console.log("could not swap date:",d,e);
4702        return d;
4703    }
4704}
4705
4706</script>
4706
4707<link rel="stylesheet" type="text/css" href="//www.cincyticket.com/include/accessodesign-core-addition.css?ver=20228b0075">
4708
4709<link rel="stylesheet" type="text/css" href="//www.cincyticket.com/include/style.css?ver=20228b0075">
4710
4711    <link rel="stylesheet" type="text/css" media="only screen and (max-width: 1024px)" href="//www.cincyticket.com/include/mobile.css?ver=20228b0075">
4712
4713</head>
4714
4715<body class="body-class default-font">
4716		
4717            <!-- CLIENT Google Tag Manager -->
vendor: 75 bytes, lines 4717-4718
4717
4718            <noscript><iframe src="//www.googletagmanager.com/ns.html?id=
4718GTM-WZ8HC5
vendor: 109 bytes, lines 4718-4720
4718"
4719            height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
4720            
4720<!-- End CLIENT Google Tag Manager -->
4721        
4722                <!-- PRIMARY Google Tag Manager -->
vendor: 79 bytes, lines 4722-4723
4722
4723                <noscript><iframe src="//www.googletagmanager.com/ns.html?id=
4723GTM-MDGF2K
vendor: 117 bytes, lines 4723-4725
4723"
4724                height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
4725                
4725<!-- End PRIMARY Google Tag Manager -->
4726            
4727<div style="position:relative;">
4728<button class="skip-nav" title="Skip to Main Content">Skip to Main Content</button>
4729</div>
4730<script type="text/javascript">
4731	$(function(){
4732		$(".main-container").attr("tabindex", 0);
4733	})
4734	$(".skip-nav").on("click", function(){
4735		console.log("s");
4736		$(".main-container").focus();
4737	});
4738</script>
4738
4739
4740<script type="text/javascript">
4741	window.SW_ADS_CONFIG = {
4742		cacheUrl: "//www.cincyticket.com/data/adLocations/adLocationCache.txt?ver=20228",
4743		writerUrl: "https://www.cincyticket.com/include/modules/Advertising/request/saveAdLocationCache.asp",
4744		logUrl: "https://www.cincyticket.com/include/modules/Advertising/request/logAdImpression.asp"
4745	};
4746</script>
vendor: 2 bytes, line 4746
4746
4747<script type="text/javascript" src="//www.cincyticket.com/include/modules/Advertising/banner-ads.js?ver=20228"></script>
4747
4748
4749
4750
4751	<div id="page-wrap"><!--Main Page Wrap - Ends in HTMLfooter-->
4752	<div id="fb-root"></div>
4753
4754	
4754<script>
4755		(function(d, s, id) {
4756		  var js, fjs = d.getElementsByTagName(s)[0];
4757		  if (d.getElementById(id)) return;
4758		  js = d.createElement(s); js.id = id;
4759		  js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=0";
4760		  fjs.parentNode.insertBefore(js, fjs);
4761		}(document, 'script', 'facebook-jssdk'));
4762	</script>
4762
4763
4764	
4765        <!-- BEGIN Mobile Navigation BEGIN -->
4766		<nav class="navigation sw-nav mobile-only">
4767            <i id="menu-icon" class="sw-icon-menu" style="display:inline-block;" onClick="actMenu();hideWidgets();"></i>
4768            <div class="tab-nav-wrap">
4769                
4770                <a class="tab-nav" HREF="https://www.cincyticket.com/myaccount.asp?gifrompage=1&gitopage=1">my account</a>
4771            </div>
4772            <ul id="mobile-menu" onClick="actMenu();">
4773                    <!--<li><a HREF="/">home</a></li>       <!--CLIENT Home URL-->
4774                    <li><a HREF="https://www.cincyticket.com/default.asp">ticketing home</a></li>
4775                    <li class="mobile-only"><a HREF="https://www.cincyticket.com/myaccount.asp?gifrompage=1&gitopage=1">my account</a></li>
4776                    <li class="sw-sep mobile-only"></li>
4777                    
4778                        <li class="sw-sep no-tab"></li>
4779                    
4780                        <li><a onClick="actSearch();actMenu();return 0">search</a></li>
4781                    
4782                        <li class="mobile-calendar-option"><a onClick="actWidget('calendar');return 0;">calendar</a></li>
4783                    
4784                        <li><a onClick="actWidget('categories');return 0;">categories</a></li>
4785                    
4786                        <li><a onClick="actWidget('venues');return 0;">venues</a></li>
4787                    
4788                    <li class="sw-sep"></li>
4789                    <li><a HREF="https://www.cincyticket.com/basket.asp">shopping cart</a></li>
4790                    
4791                    <li class="sw-sep"></li>
4792                    <li><a href="https://www.cincyticket.net/help">contact us</a></li>
4793                    <li><a href="https://www.cincyticket.net/faq">FAQ</a></li>
4794					<li><a href="https://www.cincyticket.net/">Sell Tickets With Us</a></li>
4795                    <li class="sw-sep"></li>
4796                    <li onClick="actMenu();hideWidgets();"><a >close</a></li>
4797                </ul>
4798            <a style="color:inherit;" href="http://www.cincyticket.com/basket.asp"><i class="sw-icon-basket" style="float:right;"></i></a>
4799            
4800                <i class="sw-icon-search" style="float:right;" onClick="actSearch();"></i>
4801                <div id="swSearch" style="display:none;">
4802                    <input type="text" id="swSearchTxt" value="" placeholder="search events, venues, artists etc..." />
4803                    
4803<script type="text/javascript">
4804                        $('#swSearchTxt').keyup(function (e) {
4805                            if (e.which === 13) {
4806                                //update the performance list
4807                                updatePerformanceList_Search($("#swSearchTxt").val())
4808                            }
4809                        })
4810
4811                    </script>
4811
4812                </div>
4813            
4814        </nav>
4815        <!--END Mobile Navigation END -->
4816        <header class="mobile-header mobile-only">
4817            <!--custom branding location for mobile -->
4818            <!--Header Ads can be placed here if client desires:
4819            <div class='sw-banner-ad' data-sw-ad-location='header_mobile'></div>
4820            -->
4821            <a href="https://www.cincyticket.com/"><img src="../Images/mobile-logo.png"></a>
4822        </header>
4823        
4823<script type="text/javascript">
4824            $(function () {
4825                $(".control-box").append("<a class='close-widget mobile-only' onclick='hideWidgets()'>close</a>");
4826            })
4827       </script>
4827
4828	
4829	<header class="head-wrap no-mobile">
4830        <!--This header will not be present on mobile. Use the mobile header area if a branding location for mobile is required.-->
4831		<div class="head-inner center-div site-width">
4832			<a href="https://www.cincyticket.com/"><img src="../Images/top_header.jpg" border="0" hidefocus="true" style="width: 100%;"></a>
4833
4834            <div class="clear-float"></div>
4835            <div class="nav-container">
4836           	  <ul class="showare-nav">
4837               	  <li><img src="../Images/left_nav.gif" border="0" usemap="#Map2" hidefocus="true">
4838                      <map name="Map2">
4839                      	<area shape="rect" coords="8,4,84,22" href="http://www.cincyticket.com/default.asp">
4840                        <area shape="rect" coords="119,4,178,23" href="https://www.cincyticket.net/faq">
4841                        <area shape="rect" coords="217,4,336,23" href="https://www.cincyticket.net/help">
4842                        <area shape="rect" coords="370,4,550,23" href="https://www.cincyticket.net/"></map>
4843                   </li>
4844                	<li class="basket-widget"><div id="ShoWareBasketWidget" class="internal"></div></li>
4845                    <li style="float: right;"><a href="http://www.cincyticket.com/myaccount.asp?gifrompage=1&gitopage=1"><img src="../Images/nav-account.gif"></a></li>
4846              </ul>
4847                <div class="clear-float"></div>
4848            </div>
4849            
4850		</div><!--END head-inner END-->
4851	</header><!--END head-wrap END-->
4852
4853
4854	
4855
4856	<!--MAIN BODY-->
4857	<div class="content-wrap"><!--Main Content Wrap - this and content-inner end in HTMLfooter-->
4858		<div class="content-inner center-div site-width">
4859		    
4860			<!--LEFT SIDE-->
4861			<div class="control-wrap hide-wrap">	
4862				
4863					<div class="control-box search-control">
4864						<span class="heading-text">Search</span>
4865						<!--<img src="images/hdrCategories.gif" width="162" height="20" alt="" border="0"><br>-->
4866						
4867<input class="search-text showare-text" type="text" size="16" name="SearchText" value="" placeholder="search..."><input id="searchButton" class="search-button; " type="button" name="Go" value="Go"/>
4868<script language="javascript">
4869    $('.search-text').keyup(function(e) {
4870        if(e.which === 13){
4871            //update the performance list
4872            
4873            updatePerformanceList_Search($(".search-text").val());
4874            
4875        }
4876    })        
4877    $("#searchButton").click(function(){
4878        
4879        updatePerformanceList_Search($(".search-text").val())
4880        
4881    });
4882    function updatePerformanceList_Search(searchVal) {
4883        
4884            window.location.href= "/default.asp?search="+searchVal
4885        
4886    }
4887    function updateStreamlinedEventList_Search(searchVal) {
4888        
4889            window.location.href= "/default.asp?search="+searchVal
4890        
4891    }
4892</script>
4892
4893					</div>
4894				
4895					<div id="categoriesWidget" class="control-box categories-control">
4896			 			<span class="heading-text">Categories</span>
4897						<!--<img src="images/hdrCategories.gif" width="162" height="20" alt="" border="0"><br>-->
4898						
4899
4900<select id="categorySelect" class="showare-select" aria-label="Select a Category">
4901    <option value="0">Select a Category</option>
4902</select>
4903<script language="javascript">
4904    var CategoriesExpireTime = new Date().getTime(); var isExpired = false; var CategoriesData = "";
4905    try {
4906        //check for local storage support
4907        isExpired = CategoriesExpireTime > Number(localStorage.getItem("CategoriesExpireTime"));
4908        if(isExpired){
4909            //item expired, clear local results
4910            localStorage.setItem("ShoWareCategories", "");
4911        }
4912        localStorage.setItem("CategoriesExpireTime", CategoriesExpireTime + (1000 * 60 * 60 * 24));  //item information expires after 24 hours
4913        CategoriesData = localStorage.getItem("ShoWareCategories");
4914    } catch(e){
4915        CategoriesData = "";
4916    }
4917    function getCategories(){
4918        //attempt to get local data for widget
4919        if(CategoriesData == "" || CategoriesData == null){
4920            //no data found, pull data from request
4921            $.getJSON("https://www.cincyticket.com/include/widgets/controls/RequestCategories.asp")
4922            .done(function (data) {
4923                //build select box
4924                populateCategories(data);
4925                try{
4926                    localStorage.setItem("ShoWareCategories",JSON.stringify(data));
4927                }catch(e){
4928                    console.log("No local storage");
4929                }
4930            })
4931            .fail(function (jqxhr, textStatus, error) {
4932                var err = textStatus + ", " + error;
4933                console.log("Request Failed: " + err);
4934            })
4935        }else{
4936            CategoriesData = JSON.parse(CategoriesData);
4937            populateCategories(CategoriesData);
4938        }
4939    }
4940    function populateCategories(categoryOptions){
4941        oSelect = document.getElementById("categorySelect");
4942        for(var i = 0; i < categoryOptions.length; i++){
4943            //add an option for each category in data
4944            if (categoryOptions[i].CatActive == 1 && categoryOptions[i].IsHidden != 1)
4945            {
4946                var opt = document.createElement("option");
4947                opt.value = categoryOptions[i].ID;
4948                if(categoryOptions[i].Rank == 1){
4949                    opt.innerHTML = categoryOptions[i].Name;
4950                    opt.style.fontWeight = "bold";
4951                }else{
4952                    opt.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;" + categoryOptions[i].Name;
4953                }
4954                oSelect.appendChild(opt);
4955            }            
4956        }
4957        $("#categorySelect").val(0);
4958        }
4959    getCategories();
4960    var gCategoryVal = 0
4961    $("#categorySelect").change(function(){
4962        updatePerformanceList_Category($(this).val())
4963        gCategoryVal = $(this).val();
4964    });
4965    function updatePerformanceList_Category(categoryVal) {
4966        
4967            window.location.href= "/default.asp?category="+categoryVal;
4968        
4969    }
4970	
4971	var headerDP = "";	
4972    if ($("#categorySelect").length == 0 || 'True' == 'False'){ 
4973    	headerDP = buildDatepicker({ "calendarID": "headerCalendar", "linkedInputID": "headerCalendarInput", "isModal": false, "forceDates": true, "defaultDate": "9/1/2026"});
4974    }	
4975    function updateCalendarDateByCategory(categoryVal)
4976    {   
4977        
4978            return;
4979        
4980
4981    }
4982</script>
4982
4983					</div>
4984				
4985					<div id="calendarWidget" class="control-box calendar-control">
4986						<span class="heading-text">Browse Dates</span>
4987						<!--<img src="images/hdrDates.gif" width="162" height="20" alt="" border="0"><br>-->
4988						
4989<input type="hidden" id="headerCalendarInput" value=""/>
4990<div id="headerCalendar" class="sw-datepicker"><link rel="stylesheet" href="/include/font-awesome/css/font-awesome.min.css" />
4991<div tabindex="0" class="calendar-object" style="position:relative;">
4992    <style type="text/css" scoped>
4993        .sw-datepicker
4994        {
4995            font-size:inherit;/*Calendar size is determined by parent's font size.*/
4996        }
4997         .sw-datepicker.large-datepicker
4998        {
4999            margin-top: 20px;
5000        }
5001        .sw-datepicker[aria-hidden=true]
5002        {
5003            display:none;
5004        }
5005
5006        .sw-datepicker.is-modal{
5007            margin: 10px;
5008            padding: 2px;
5009            -webkit-border-radius: 4px;
5010            -moz-border-radius: 4px;
5011            border-radius: 4px;
5012            position: absolute;
5013            top:30px;
5014            left:0px;
5015            z-index:99;
5016            background-color: #fff;
5017            border: 1px solid #ccc;
5018            box-shadow: 0px 0px 6px RGBA(0,0,0,0.4);
5019        }
5020            .sw-datepicker.is-modal.right-side
5021            {
5022                left:auto;
5023                right:0px;
5024            }
5025        .sw-datepicker .month-wrap
5026        {
5027            background-color: #337ab7;
5028            border: 1px solid #2e6da4;
5029            -webkit-border-radius: 4px;
5030            -moz-border-radius: 4px;
5031            border-radius: 4px;
5032            text-align:center;
5033        }
5034        .sw-datepicker .bn_next, div.bn_prev{
5035            margin: 2px;
5036            border:1px solid transparent;
5037            line-height:1.3em;
5038            color:#fff;
5039            padding:0 .25em;
5040            font-weight:bold;
5041            cursor:pointer;
5042        }
5043        .sw-datepicker .bn_prev
5044        {
5045            float: left;
5046        }
5047
5048        .sw-datepicker .bn_next
5049        {
5050            float: right;
5051        }
5052
5053            .sw-datepicker .bn_prev:hover,
5054            .sw-datepicker .bn_prev:focus,
5055            .sw-datepicker .bn_next:hover,
5056            .sw-datepicker .bn_next:focus
5057            {
5058                margin: 2px;
5059                background-color: #4fbae0;
5060                border: 1px solid #00a4df;
5061                -webkit-border-radius: 4px;
5062                -moz-border-radius: 4px;
5063                border-radius: 4px;
5064            }
5065
5066        .sw-datepicker .bn_img
5067        {
5068            margin: 0;
5069            padding: 2px;
5070        }
5071
5072        .sw-datepicker .month
5073        {
5074            display:inline-block;
5075            line-height:1.5em;
5076            font-weight: bold;
5077            font-size: 1.2em;
5078            color:#fff;
5079        }
5080
5081        .sw-datepicker .cal
5082        {
5083            font-size: 1.2em;
5084            text-align: center;
5085        }
5086
5087
5088        .sw-datepicker .offscreen
5089        {
5090            position: absolute;
5091            left: -200em;
5092            top: -100em;
5093        }
5094        .sw-datepicker td.day-cell.highlight-day{
5095            cursor:pointer;
5096        }
5097        td span.calendar-day{
5098            display:inline-block;
5099            height:1.5em;
5100            width:1.5em;
5101            line-height:1.5em;
5102            border-radius:3px;
5103            margin:.1em;
5104            position:relative;
5105        }
5106        td.highlight-day span.calendar-day{
5107            border:1px solid #337ab7;
5108            background:#fcfcfc;
5109            color:#00458A;
5110            cursor:pointer;
5111        }
5112        td.limited-availability:after{
5113            content:'!';
5114            display:inline-block;
5115            font-weight:bold;
5116            position:absolute;
5117            top:3px;
5118            right:5px;
5119            font-size:3vw;
5120            color:#aa0;
5121        }
5122        .sw-datepicker abbr{
5123            text-decoration:none;
5124            opacity:1;
5125            display:inline-block;
5126            margin:.3em 0;
5127        }
5128        td.today{
5129            background:#eee;
5130        }
5131        td.focus{
5132            background:#8ecae0;
5133        }
5134        .sw-datepicker td{
5135            position:relative;
5136        }
5137        .sw-datepicker.large-datepicker, .sw-datepicker.large-datepicker table{
5138            width:100%;
5139        }
5140        .sw-datepicker.large-datepicker .month-wrap{
5141            font-size:1.5em;
5142            background:RGBA(255,255,255,0.0);
5143            border:none;
5144            border-bottom:1px solid #eee;
5145        }
5146        .sw-datepicker.large-datepicker .month-wrap *{
5147            color:inherit!important;
5148        }
5149        .sw-datepicker.large-datepicker .day-cell{
5150            height:8vh;
5151            width:14%;
5152            border:1px solid #eee;
5153            opacity:.7;
5154            transition:opacity .5s;
5155        }
5156        .sw-datepicker.large-datepicker .day-cell.highlight-day{
5157            opacity:1;
5158        }
5159        .sw-datepicker.large-datepicker td span.calendar-day{
5160            position:absolute;
5161            top:5px;
5162            left:5px;
5163            font-size:.7em;
5164            text-align:center;
5165            font-weight:bold;
5166            height:2em;
5167            width:2em;
5168            padding:.25em;
5169            line-height:1.3em;
5170            display:inline-block;
5171            background:RGBA(255,255,255,0.0);
5172            border:none;
5173            pointer-events:none;
5174        }
5175        .sw-datepicker .date-info-box{
5176            font-size: 1.5vw;
5177            padding: 30px 5px 15px;
5178            display: block;
5179            position: relative;
5180        }
5181        .sw-datepicker .date-info-box .display-perfstatus{
5182            font-size: .72vw;
5183            display: block;
5184            text-align: center!important;
5185            padding: 5px 10px;
5186            border: 1px solid var(--gap-error);
5187            border-radius: 8px;
5188            color: var(--gap-error);
5189            width: 90%;
5190            margin: auto;
5191            box-sizing: border-box;
5192            background: rgba(222,27,60,.05);
5193        }
5194        .sw-datepicker .date-info-box .display-perfprice{
5195            font-size: 1vw;
5196        }
5197        .sw-datepicker .date-info-box .display-perfprice-withchild{
5198            font-size: 1vw;
5199        }
5200        .sw-datepicker .date-info-box .display-perfname{
5201            font-size: .8vw;
5202            display: block;
5203            text-align: center;
5204            padding: 0px 10px;
5205            
5206        }
5207        .sw-datepicker .date-info-box .display-perftime{
5208            font-size: .93vw;
5209            display: block;
5210            padding-top: 5px;
5211        }
5212        .sw-datepicker .date-info-box .display-perfbuybutton{
5213            font-size: .7vw;
5214            display: block;
5215            padding: 5px 10px;
5216            width: 90%;
5217            margin: 5px auto;
5218        }
5219        .sw-datepicker .date-sub-note{
5220            font-style: italic;
5221            font-size: .93vw;
5222            opacity: .8;
5223            position: absolute;
5224            bottom: auto;
5225            top: 0px;
5226            padding-bottom: 20px;
5227            padding-top: 15px;
5228            margin-bottom: 30px;
5229            width: 100%;
5230        }
5231        @media only screen and (max-width: 1500px){
5232            .sw-datepicker .date-info-box .display-perfname{
5233                font-size: 1.1vw;
5234            }
5235            .sw-datepicker .date-info-box .display-perftime, 
5236            .sw-datepicker .date-info-box .display-perfprice,
5237            .sw-datepicker .date-info-box .display-perfprice-withchild{
5238                font-size: 1.2vw;
5239            }
5240            .sw-datepicker .date-info-box .display-perfbuybutton{
5241                font-size: 1vw;
5242            }
5243        }
5244        @media only screen and (max-width: 1300px){
5245            .sw-datepicker .date-info-box .display-perfname{
5246                font-size: 1.3vw;
5247            }
5248            .sw-datepicker .date-info-box .display-perftime, 
5249            .sw-datepicker .date-info-box .display-perfprice,
5250            .sw-datepicker .date-info-box .display-perfprice-withchild{
5251                font-size: 1.3vw;
5252            }
5253        }
5254        @media only screen and (max-width: 1024px){
5255            .sw-datepicker .date-sub-note{
5256                display:none!important;
5257            }
5258            .sw-datepicker .date-info-box .display-perfname{
5259                font-size: 12px;
5260            }
5261            .sw-datepicker .date-info-box .display-perftime, 
5262            .sw-datepicker .date-info-box .display-perfprice,
5263            .sw-datepicker .date-info-box .display-perfprice-withchild{
5264                font-size: 12px;
5265            }
5266            .sw-datepicker .date-info-box .display-perfbuybutton{
5267                font-size: 12px;
5268                white-space: unset;
5269                line-height: 1.2;
5270            }
5271            /* adjustment for coupon codes on mobile*/
5272            .couponecode-wrap {
5273                display: flex;
5274                flex-direction: row-reverse;
5275                align-items: stretch;
5276                flex-wrap: nowrap;
5277                gap: 20px;
5278                width: 100%;
5279            }
5280            #FilterSelect {
5281                margin-bottom: 8px;
5282            }
5283            #couponCodeSubmitButton {
5284                margin-top: 0;
5285            }
5286            #couponCode {
5287                flex: 1;
5288                height: auto;
5289            }
5290        }
5291        @media only screen and (max-width: 800px){
5292            .sw-datepicker.large-datepicker .day-cell {
5293                height: auto!important;
5294                width: 14%;
5295                min-height: 50px;
5296                border: 1px solid #eee;
5297                opacity: .7;
5298                transition: opacity .5s;
5299            }
5300            .sw-datepicker.large-datepicker table td.empty,
5301            .sw-datepicker.large-datepicker table th {
5302                width: 14%;
5303                min-width: 14%;
5304            }
5305            .sw-datepicker .date-info-box .display-perfbuybutton {
5306                width: 100%;
5307                line-height: 1.1!important;
5308                font-size: 11px!important;
5309                white-space: unset;
5310                padding: 5px!important;
5311            }
5312            .sw-datepicker .date-info-box .display-perftime, 
5313            .sw-datepicker .date-info-box .display-perfprice,
5314            .sw-datepicker .date-info-box .display-perfprice-withchild,
5315            .sw-datepicker .date-info-box .display-perfname{
5316                font-size: 11px;
5317
5318            }
5319            .sw-datepicker table tr {
5320                display: flex;
5321                justify-content: space-evenly;
5322            }
5323            .sw-datepicker .date-info-box .display-perfname{
5324                padding: 5px 0px 0;  
5325            }
5326            .sw-datepicker .date-info-box {
5327                overflow-wrap: normal;
5328            }
5329            .sw-datepicker.large-datepicker table td.empty,
5330            .sw-datepicker.large-datepicker table th,
5331            .sw-datepicker table td.empty,
5332            .sw-datepicker table th
5333            {
5334                width: calc((100% / 7) - 4px);
5335                min-width: 10%;
5336            }
5337            .sw-datepicker.large-datepicker .day-cell,
5338            .sw-datepicker .day-cell {
5339                width: calc((100% / 7) - 4px);
5340            }
5341            .sw-datepicker .day-cell.sold-out{
5342                padding-top: 35px!important;
5343                line-height: 1.2!important;
5344            }
5345        }
5346        @media only screen and (max-width: 550px){
5347            #epPerformanceList #eventCalendar {
5348                width: 100%;
5349            }
5350            .sw-datepicker .date-info-box .display-perfbuybutton {
5351                font-size: 7px!important;
5352                font-weight: 400!important;
5353            }
5354            .sw-datepicker .date-info-box .display-perftime, 
5355            .sw-datepicker .date-info-box .display-perfprice,
5356            .sw-datepicker .date-info-box .display-perfprice-withchild,
5357            .sw-datepicker .date-info-box .display-perfname{
5358                font-size: 10px;
5359
5360            }
5361            .sw-datepicker .day-cell.sold-out{
5362                padding-top: 30px!important;
5363                line-height: .9!important;
5364            }
5365            .sw-datepicker.large-datepicker table  tr{
5366                display: flex;
5367                justify-content: space-evenly;
5368            }
5369            .sw-datepicker.large-datepicker table td.empty,
5370            .sw-datepicker.large-datepicker table th,
5371            .sw-datepicker.large-datepicker table td,
5372            .sw-datepicker.large-datepicker .day-cell {
5373                width: calc(96vw / 7);
5374            }
5375            #TimeSelectModalBody {
5376                width: 100%!important;
5377            }
5378        }
5379        .sw-datepicker .day-cell.sold-out{
5380            opacity:.7!important;
5381            color:#a00;
5382            pointer-events:none;
5383        }
5384        .sw-datepicker .day-cell.muted{
5385            opacity:.3!important;
5386        }
5387
5388        .sw-datepicker .day-cell.coupon-muted{
5389            opacity:.3!important;
5390        }
5391
5392        .sw-datepicker .day-cell.password-hidden .date-info-box{
5393            display: none!important;
5394        }
5395
5396        .sw-datepicker .day-cell.muted .calendar-day{
5397            color:inherit!important;
5398            border:none!important;
5399            cursor:default!important;
5400        }
5401
5402        .sw-datepicker .day-cell.coupon-muted .calendar-day{
5403            color:inherit!important;
5404            border:none!important;
5405        }
5406        .sw-datepicker .day-cell.sold-out .date-info-box{
5407            display:none;
5408        }
5409        .sw-datepicker .day-cell.sold-out .calendar-day{
5410            color:#a00;
5411            border:none;
5412            text-decoration:line-through;
5413        }
5414        @media only screen and (max-width: 1024px){
5415            .sw-datepicker .date-info-box, .sw-datepicker .sold-out-info-box{
5416                font-size:2vw;
5417            }
5418        }
5419        .calendar-loading{
5420            position:absolute;
5421            top:50%;
5422            left:50%;
5423            font-size:4vw;
5424            font-weight:bold;
5425            color:RGBA(0,0,0,0.4);
5426            width:66vw;
5427            margin-left:-33vw;
5428            height:20vw;
5429            margin-top:-10vh;
5430            line-height:20vw;
5431            text-align:center;
5432            background:RGBA(255,255,255,0.9);
5433            border-radius:1em;
5434            border:1px solid RGBA(0,0,0,0.4);
5435            box-shadow:2px 2px 4px RGBA(0,0,0,0.2);
5436        }
5437        .limited-availability-legend-item{
5438            text-align:right;
5439        }
5440        .calendar-limited-availability-legend-icon{
5441            font-weight:bold;
5442            color:#aa0;
5443        }
5444        .calendar-dayoftheweek {display: none!important;}
5445        #calendarWidget .calendar-dayoftheweek {display: none!important;}
5446    </style>
5447
5448    <div class="month-wrap">
5449        <div class="bn_prev" role="button" aria-labelledby="bn_prev-label" tabindex="0" title="Previous Month"><i class="fa fa-backward" aria-hidden="true"></i></div>
5450        <div tabindex="0" class="month" role="heading" aria-live="assertive" aria-atomic="true">Loading...</div>
5451        <div class="bn_next" role="button" aria-labelledby="bn_next-label" tabindex="0" title="Next Month"><i class="fa fa-forward" aria-hidden="true"></i></div>
5452    </div>
5453    <table title="Search Date - Select a date to search" class="cal" role="grid" aria-labelledby="month" tabindex="0" style="margin: 0px auto;outline:none!important;">
5454        <thead>
5455        <tr class="weekdays">
5456            <th class="Sunday"><abbr title="Sunday">Su</abbr></th>
5457            <th class="Monday"><abbr title="Monday">Mo</abbr></th>
5458            <th class="Tuesday"><abbr title="Tuesday">Tu</abbr></th>
5459            <th class="Wednesday"><abbr title="Wednesday">We</abbr></th>
5460            <th class="Thursday"><abbr title="Thursday">Th</abbr></th>
5461            <th class="Friday"><abbr title="Friday">Fr</abbr></th>
5462            <th class="Saturday"><abbr title="Saturday">Sa</abbr></th>
5463        </tr>
5464        </thead>
5465        <tbody>
5466            <tr><td class="errMsg" colspan="7">Loading...</td></tr>
5467        </tbody>
5468    </table>
5469    <div class="bn_prev-label offscreen">Go to previous month</div>
5470    <div class="bn_next-label offscreen">Go to next month</div>
5471    <div class="calendar-loading" style="display:none;"><i class="fa fa-spin fa-spinner" style="margin-right:.5em;"></i>Loading...</div>
5472</div>
5473<div class="calendar-notes-wrap"></div>
5474</div>
5475<script type="text/javascript">
5476	var headerDP = "";	
5477    if ($("#categorySelect").length == 0 || 'True' == 'False')
5478    	headerDP = buildDatepicker({ "calendarID": "headerCalendar", "linkedInputID": "headerCalendarInput", "isModal": false, "forceDates": true, "defaultDate": "9/1/2026", "corporatePartnerPage":0});
5479 	$("#headerCalendarInput").on("change", function () {
5480        var properDate = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
5481        if (!properDate.test($(this).val())) {
5482            console.log("Main calendar attempted an invalid date: " + $(this).val());
5483            return;//invalid date
5484        }
5485		
5486        window.location.href= "/default.asp?searchdate="+$(this).val()+"";        
5487    });
5488    extractIcons();
5489</script>
5489
5490
5491
5492
5493					</div>
5494				
5495					<div id="venuesWidget" class="control-box venue-control">
5496						<span class="heading-text">Browse by Venue</span>
5497						
5498					
5499							
5500							
5501<select id="venueSelect" class="showare-select" name="venue" aria-label="Choose Venue">
5502	<option value="0"> Choose Venue </option>
5503</select>
5504<div align="right">
5505    <a  class="button small-button sw-button-muted" style="margin-top:1em;margin-right:0px;" href="//www.cincyticket.com/venuelisting.asp">View Venue listing</a>
5506</div>		
5507					
5508<script language="javascript">
5509    var VenuesExpireTime = new Date().getTime(); var isExpired = false; var VenuesData = "";
5510    try {
5511        //check for local storage support
5512        isExpired = VenuesExpireTime > Number(localStorage.getItem("VenuesExpireTime"));
5513        if(isExpired){
5514            //item expired, clear local results
5515            localStorage.setItem("ShoWareVenues", "");
5516        }
5517        localStorage.setItem("VenuesExpireTime", VenuesExpireTime + (1000 * 60 * 60 * 24));  //item information expires after 24 hours
5518        VenuesData = localStorage.getItem("ShoWareVenues");
5519    } catch(e){
5520        VenuesData = "";
5521    }
5522    function getVenues(){
5523        //attempt to get local data for widget
5524        if(VenuesData == "" || VenuesData == null){
5525            //no data found, pull data from request
5526            $.getJSON("https://www.cincyticket.com/include/widgets/controls/RequestVenues.asp")
5527            .done(function (data) {
5528                //build select box
5529                populateVenues(data);
5530                try{
5531                    localStorage.setItem("ShoWareVenues",JSON.stringify(data));
5532                }catch(e){
5533                    console.log("No local storage");
5534                }
5535            })
5536            .fail(function (jqxhr, textStatus, error) {
5537                var err = textStatus + ", " + error;
5538                console.log("Request Failed: " + err);
5539            });
5540        }else{
5541            VenuesData = JSON.parse(VenuesData);
5542            populateVenues(VenuesData);
5543        }
5544    }
5545    function populateVenues(venueOptions){
5546        oSelect = document.getElementById("venueSelect");
5547        for(var i = 0; i < venueOptions.length; i++){
5548            //add an option for each venue in data
5549            var opt = document.createElement("option");
5550            opt.value = venueOptions[i].ID;
5551            opt.innerHTML =  venueOptions[i].Name;
5552            oSelect.appendChild(opt);
5553        }
5554        $("#venueSelect").val(0);
5555        }
5556    getVenues();
5557
5558    $("#venueSelect").change(function(){
5559        updatePerformanceList_Venue($(this).val())
5560    });
5561    function updatePerformanceList_Venue(venueVal) {
5562        
5563            window.location.href= "/default.asp?venue="+venueVal;
5564        
5565        }
5566</script>
5566
5567					</div>
5568				
5569					<div id="infoWidget" class="control-box info-control">
5570						<span class="heading-text">Information</span>
5571						<!--<img src="images/hdrInfo.gif" width="162" height="20" alt="" border="0"><br>-->
5572						<span class="info-text small-text"><p><strong>Customer Service:</strong><br /> <span style="text-decoration: underline;"><span style="font-size: medium;"><a href="https://www.cincyticket.net/help">CONTACT US</a></span></span><br /><br /> 9891 Montgomery Rd.<br />Suite 189<br /> Cincinnati, OH 45242</p>
5573<a href="https://www.facebook.com/cincyticket" target="_blank"><img src="https://www.cincyticket.com/uplimage/icon_facebook.png" alt="" width="35" height="35" /></a>&nbsp;<a href="https://www.twitter.com/cincyticket" target="_blank"><img src="https://www.cincyticket.com/uplimage/icon_twitter.png" alt="" width="35" height="35" /><br /></a>
5574<p><a href="https://www.cincyticket.net" target="_blank"><img src="../uplimage/sellticketswithus_new.png" alt="" border="0" /></a></p>
5575<center><em><br />Ticketing System by</em><br /><a href="https://www.cincyticket.net" target="_blank"><img src="../uplimage/cincyticket_logo_clearbg.png" alt="" border="0" /></a></center><!-- Meta Pixel Code -->
5576<script>// <![CDATA[
vendor: 408 bytes, lines 5576-5585
5576
5577!function(f,b,e,v,n,t,s)
5578{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
5579n.callMethod.apply(n,arguments):n.queue.push(arguments)};
5580if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
5581n.queue=[];t=b.createElement(e);t.async=!0;
5582t.src=v;s=b.getElementsByTagName(e)[0];
5583s.parentNode.insertBefore(t,s)}(window, document,'script',
5584'https://connect.facebook.net/en_US/fbevents.js');
5585fbq('init', '
5585802935397828854
vendor: 32 bytes, lines 5585-5586
5585');
5586fbq('track', 'PageView');
5587// ]]></script>
5587
5588<noscript><img height="1" width="1" style="display:none"
5589src="https://www.facebook.com/tr?id=802935397828854&ev=PageView&noscript=1"
5590/></noscript><!-- End Meta Pixel Code --></span>
5591					</div>
5592				
5593					<a class="reporting-link" href="/reporting/login.asp">Promoter Login</a>
5594				
5595				<div class="ads-control">
5596					<center>
5597					<div class='sw-banner-ad' data-sw-ad-location='side_01'></div><div class='sw-banner-ad' data-sw-ad-location='side_02'></div><div class='sw-banner-ad' data-sw-ad-location='side_03'></div><div class='sw-banner-ad' data-sw-ad-location='side_04'></div><div class='sw-banner-ad' data-sw-ad-location='side_05'></div><div class='sw-banner-ad' data-sw-ad-location='side_06'></div><div class='sw-banner-ad' data-sw-ad-location='side_07'></div><div class='sw-banner-ad' data-sw-ad-location='side_08'></div><div class='sw-banner-ad' data-sw-ad-location='side_09'></div><div class='sw-banner-ad' data-sw-ad-location='side_10'></div>
5598					</center>
5599				</div>					
5600				
5601			</div><!--END control-wrap END-->
5602			<!--END LEFT SIDE-->
5603			<div id="epImage2"></div>
5604
5605			<div class="main-container ">
5606				<!-- Main Area -->
5607				
5608				<!-- end HTMLheader.asp -->
5609<!-- begin myaccount.asp -->
5610
5611<form class="login-form-wrap multiple-login clear" action="https://www.cincyticket.com/login.asp?gifrompage=2&gitopage=2&agent=0" method="post" name="loginfrm" id="loginfrm" autocomplete="off">
5612	<div class="login-column primary-login-column">
5613        <div class="login-column-header">
5614			
5615				<span class="heading-text sub-head-text">Returning Users</span>
5616				<div class="login-text">
5617					Sign in below to check out with an existing account.
5618				</div>
5619			
5620        </div>
5621	    <div class="login-form">
5622            <div class="login-form-row">
5623                <label class="login-label" for="email">E-mail/Username</label>
5624                <input title="Email Address" aria-label="Email Address" type="text" id="username" name="email" maxlength="128" value="" class="showare-text" placeholder="Email">
5625				
5626            </div>
5627		    <div class="login-form-row">
5628			    <label class="login-label">Password</label>
5629			    <input title="Password" aria-label="Password" type="password" id="password" name="password" maxlength="128" autocomplete="off" class="showare-text" placeholder="Password">
5630		    </div>
5631		    
5632		    <div class="login-form-row login-buttons clear">
5633			    <a id="btnLogin" class="button sw-button-primary"><img class="sw-icon lock-icon" src="images/lock-icon.svg" />Login</a>
5634			    
5635				<a class="forgot-password-link" href="/Patron_ForgotPassword.asp?BackURL=">Forgot your Password?</a>
5636				
5637	        </div>
5638	       	
5639	    </div>
5640    </div>
5641	
5642		<div class="multi-login-divider"></div>
5643		<div class="login-column alternate-login-column">
5644			<div class="login-column-header">
5645				<span class="heading-text sub-head-text">New Users</span>
5646				<div class="login-text">
5647					Create a new account to speed up your next order, or checkout safely and securely as a guest.
5648					
5649				</div>
5650			</div>
5651
5652			
5653			<a id="btnNewUser" class="button">Create Account</a>
5654		</div>
5655		
5656	<!--- Start Verisign / Geotrust Seal ----->
5657	
5658	<input type="hidden" name="haction" value="login">
5659	<input type="hidden" name="gitopage" value="2">
5660	<input type="hidden" name="gifrompage" value="2">	
5661	<input type="hidden" name="backurl" value="">
5662	<input type="hidden" name="pahFileOrderID" value="">
5663	
5664
5665	<input style="display:none;" type="submit" />
5666</form>
5667
5668<script type="text/javascript">
5669	$(function(){	
5670			/*Wait till after the dom has loaded and check if an email value exists, if so focus password*/
5671			if(document.loginfrm.email.value.length > 0){
5672				document.loginfrm.password.focus();
5673			}
5674			
5675			function checkEmail(email){
5676                if(!emailPattern.test($(this).val())){
5677                    //not a valid email. no need to check
5678                    return;
5679                }
5680				$.post("/patronnew.asp?activity=patronExists", {"soughtUsername":$("#username").val()}, function(data){
5681					if(data){
5682						var isEmailAvailable = String(data.isEmailAvailable) === "true";
5683						$(".login-form-row .error-message").hide();	
5684						if(isEmailAvailable){
5685							$("#username").addClass("has-error");
5686							$("#username").parent().append('<div class="error-message floating-error username-error"><b>No account for the supplied email exists.</b> Please check that the email provided is correct, and that it is the primary email associated with your account. If you have not set up an account yet, you can do so by clicking the "Create Account" button below.</div><div class="clear-float clear></div>');
5687						}
5688					}
5689				}, "json");
5690				return 1;
5691			}
5692			
5693			function validateLogin(){
5694				$(".username-error").hide();
5695				if(!emailPattern.test($("#username").val())){
5696					$("#username").parent().append('<div class="error-message floating-error username-error">Please provide a valid email address.</div>');
5697					$("#username").addClass("has-error");
5698					return 0;
5699				}
5700				if($("#password").val() == ""){
5701					$("#password").parent().append('<div class="error-message floating-error username-error">Please enter a password.</div>');
5702					$("#password").addClass("has-error");
5703					return 0;
5704				}
5705			    //valid login attempt, send ecommerce checkout step
5706			    try{
5707			        swEnhancedEcommerce.sendCheckoutStep(2, "login");
5708			    }catch(e){
5709			        console.log(e);
5710			    }
5711				$("#loginfrm").submit();
5712			}
5713			
5714				
5715			 var emailPattern = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;
5716				
5717			 $("#btnLogin").click(function(){ validateLogin(); });
5718			 $("#password").keydown(function(e){
5719			     if(e.keyCode == 13){
5720			         validateLogin();
5721			     }
5722			 })
5723			
5724			 $("#btnNewUser").click(function () {
5725			     try{swEnhancedEcommerce.sendCheckoutStep(2, "new");}catch(e){console.log(e);}
5726				window.location.assign("https://www.cincyticket.com/patronnew.asp?gifrompage=2&gitopage=2&isGuestCheckoutSelected=on")
5727			});
5728
5729			$("#username").keydown(function(e){
5730				if(e.keyCode == 13){
5731					//enter should NOT submit in the username field
5732					e.preventDefault();
5733					$("#password").focus();
5734					return 0;
5735				}
5736			}).blur(function(){
5737				if(!emailPattern.test($(this).val())){			
5738					$(this).addClass("has-error");
5739					$(this).parent().append('<span class="error-message floating-error username-error">Please provide a valid email address.</span>');
5740					$(this).addClass("has-error");
5741					return 0;
5742                }
5743				checkEmail($(this).val());
5744			}).focus(function(){
5745				$(this).removeClass("has-error");
5746				$(".username-error").remove();
5747			});
5748			//switch icons to SVG
5749			extractIcons();
5750	});
5751
5752    //if an email reminder was sent, attempt to inser the time.
5753    if(  document.addEventListener  ){  //IE9+ only
5754        var reminderTimeString = "", dNow = new Date();
5755        dNow.setMinutes(dNow.getMinutes() + 45);
5756        reminderTimeString = ", and will expire at " + dNow.toLocaleTimeString(navigator.language, {hour: '2-digit', minute:'2-digit'});
5757
5758        $("#reminder-expire-time").html(reminderTimeString);
5759    }
5760    //notify development if SSL is not present.
5761    if (location.protocol != 'https:') {
5762        // page is not secure
5763        $.get("error/SSL.asp");
5764    }
5765</script>
5765
5766
5767			<div class="clear-float"></div>
5768			</div><!--End main-container #END-->
5769			<!-- end main arean -->
5770			<div class="clear-float"></div><!--force inner-content pas floated left and right sections-->
5771			
5772		</div><!--END content-inner END-->
5773	</div><!--END content-wrap END-->
5774
5775	<div class="foot-wrap">
5776		<div class="foot-inner center-div site-width">
5777			
5778			<center><div class='sw-banner-ad' data-sw-ad-location='footer'></div>	  </center>
5779
5780			<span class="copyright-text">
5781			Copyright &copy; 2026&nbsp;CincyTicket, All Rights Reserved. <span class="no-mobile">-</span> <br class="mobile-only" />
5782			Ticketing System by <a class="Copyrightlink" target="_blank" href="https://www.cincyticket.net">CincyTicket Solutions</a><br><br>
5783			<span class="copyright-text">Please read our <a href="Javascript:popUp('Privacy Statement','privacystatement.asp',350,420,'no','yes','no','no')">Privacy Statement</a> and <a href="Javascript:popUp('Terms of Use','termsofuse.asp',350,420,'no','yes','no','no')">Terms of Use</a>.</span>
5784			<br><br>
5785			</span><!--END copyright-text span END-->
5786
5787			
5788			
5788<script language="JavaScript" type="text/javascript">
5789                //variable defined via external script from HTMLHeadClose.asp
5790                if (typeof TrustLogo !== "undefined") {
5791                    TrustLogo("https://www.cincyticket.com/images/comodo.png", "CL1", "none");
5792                }
5793            </script>
5793
5794		
5795		</div><!--END foot-inner END-->
5796	</div><!--END foot-wrap END-->
5797
5798
5799
5800</div><!--END page-wrap END-->
5801
5802
5803<script language="javascript">
5804    $(function () {
5805        //activate modals
5806        hoverModal();
5807    });
5808</script>
5808
5809
5810
5811    
5811<script async src="//www.cincyticket.com/include/widgets/basket/basketwidget.js?ver=20228b0075" id="showarebasketscript" type="text/javascript"></script>
5811
5812
5813
5814<script>
5815    var cb = function() {
5816    var l = document.createElement('link'); l.rel = 'stylesheet';
5817    l.href = '/include/jqueryui-themes/default/jquery-ui.css';
5818    var h = document.getElementsByTagName('head')[0]; h.parentNode.insertBefore(l, h);
5819    };
5820    var raf = window.requestAnimationFrame       || 
5821          window.webkitRequestAnimationFrame || 
5822          window.mozRequestAnimationFrame    || 
5823          window.oRequestAnimationFrame      || 
5824          window.msRequestAnimationFrame     ;
5825    if (raf) raf(cb);
5826    else window.addEventListener('load', cb);
5827</script>
5827
5828
5829<script type="text/javascript">
5830    $("body").addClass("login");
5831    if(window.location.hostname.toLowerCase() != "www.cincyticket.com"){
5832        Showare.Logger.warn("Bad Domain Request","www.cincyticket.com - " + window.location.hostname);
5833        window.location.replace("//www.cincyticket.com");
5834    }
5835
5836</script>
5836
5837
5838<!-- ARIA ACCESSABILITY FEATURES -->
5839<script type="text/javascript">
5840    try{
5841                
5842        $(".main-container").attr("role","main");
5843        $("ul.showare-nav").attr("role","list");
5844        $("ul.showare-nav li").attr("role","listitem");
5845        $("ul.showare-nav li a").attr("role","button");
5846        $(".search-control").attr("role","listitem");
5847        $("input.search-text").attr("aria-label","Search");
5848        $(".theme-custom-field-set input").attr("aria-labelledby","custom-field-label").attr("aria-label","Additional Information box");
5849        $(".theme-custom-field-set select").attr("role","listbox").attr("aria-labelledby","custom-field-label").attr("aria-label","Additional Information list");
5850        $(".control-wrap").attr("role","complementary").attr("aria-label","Side Navigation");
5851        $("header.head-wrap").attr("role","banner");
5852        $("div.foot-wrap").attr("role","contentinfo");
5853        $("a.header-logo-link h1").attr("aria-hidden","true");
5854        $(".copyright-text:last").find("a").attr("role", "button");
5855        $(".tab-nav-wrap").find("a").attr("role", "button");
5856        $("#mobile-menu").attr("role","list");
5857        $("#mobile-menu li").attr("role","listitem");
5858        $("#mobile-menu li a").attr("role","button");
5859        $(".heading-text").attr("role","heading").attr("aria-level","2");
5860        
5861        $("a.bodylink").attr("role","button");
5862        $("a.getmembership-link").attr("role","button");
5863        
5864        $("a.header-logo-link h1").attr("aria-level","1");
5865        $("#demo-div").attr("role","region").attr("aria-label","Only a Demo Site");
5866        $("#swCustomListings").attr("aria-label","Featured Custom Listing");
5867
5868        
5869        $(".ad-image").attr("role","presentation");
5870        
5871        
5872        //add a basket link for aria to read
5873        $("li.basket-widget").prepend('<a tabindex="0" class="aria-basket-link" href="basket.asp?fw=1">Shopping Cart</a>');
5874
5875        //adds aria-label explaining that the link is opening a new tab if the link has target="blank" on it and no aria-label added
5876        $('a[target="_blank"]').each(function() {
5877            if (!$(this).attr('aria-label')) {
5878                $(this).attr('aria-label', 'Opens in a new tab.');
5879            }
5880        });
5881        // address the "button can not be empty" - add the Next Month and Previous month to the arrow buttons 
5882        var spanNextMonth = $('<span>', {id: 'bn_next-label',  class: 'sr-only', text: 'Next Month'});
5883        var spanPrevMonth = $('<span>', {id: 'bn_prev-label',  class: 'sr-only', text: 'Previous Month'});  
5884        $('.bn_next').prepend(spanNextMonth);
5885        $('.bn_prev').prepend(spanPrevMonth);
5886
5887        // add ID attribute to main sections
5888        $("header.head-wrap.no-mobile").attr("id","mainheadwrap");
5889        $("div.content-wrap").attr("id","maincontentwrap");
5890        $("div.foot-wrap").attr("id","mainfootwrap");
5891        
5892        // adding Skip link
5893        var skipLinkToHeader = $('<a>', {href: '#mainheadwrap',  class: 'skip-link', text: 'Skip to header content', 'aria-label': 'Skip to header content', 'role': 'link'});
5894        var skipLinkToMainContent = $('<a>', {href: '#maincontentwrap',  class: 'skip-link', text: 'Skip to main content', 'aria-label': 'Skip to main content', 'role': 'link'});  
5895        var skipLinkToFooterContent = $('<a>', {href: '#mainfootwrap',  class: 'skip-link', text: 'Skip to footer content', 'aria-label': 'Skip to footer content', 'role': 'link'}); 
5896
5897        // add created skip link above the main sections
5898        $(skipLinkToHeader).insertBefore("header.head-wrap.no-mobile");  
5899        $(skipLinkToMainContent).insertBefore("div.content-wrap");  
5900        $(skipLinkToFooterContent).insertBefore("div.foot-wrap");  
5901
5902        // use setTimeout to make sure all are loaded before adding attributes
5903        setTimeout(function() { 
5904            $('html').attr('lang', 'en'); 
5905            $(".day-cell.highlight-day").attr("tabindex", "0"); // address the interactive elements should be navigable using the keyboard
5906            $("#ShoWareBasketWidget").find(".cart-item").attr("role", "button").attr("tabindex", "0");
5907            $("#ShoWareBasketWidget .cart-item .cart-item-pic").attr("role", "cart presentation");
5908            $("#ShoWareBasketWidget .cart-item .cart-item-pic .sw-i-cart").attr("role", "cart presentation");
5909            $(".featured-items-item .streaming-note").attr("role","presentation");
5910            $(".pl-item a.pl-popup-link").attr("role","button");
5911            $(".pl-date-block-image").attr("role","img");
5912            $("#epImage2 img").attr("alt","Event Banner");
5913            $('.navigation.sw-nav > a[href*="basket.asp"]').attr({
5914                'title': 'View Basket',
5915                'aria-label': 'View Basket'
5916            });
5917
5918            // address the "Incorrect use of aria-describedy" - this is used in the header cart but there's no ID to refer it to
5919            var cartTitle = $('.cart-item-desc').attr('title');
5920            var spanCartItemDesc = $('<span>', {id: 'cart-text',  class: 'sr-only', text: cartTitle});
5921            $('.cart-item-desc').prepend(spanCartItemDesc);
5922            
5923            // address the "Incorrect use of aria-describedy" - this is used in the calendar and no ID to refer it to
5924            var calendarTableTitle = $('.calendar-object table:first').attr('title');
5925            var spanCalendarIDAdded = $('<span>', {id: 'month',  class: 'sr-only', text: calendarTableTitle});
5926            $('.calendar-object table:first').prepend(spanCalendarIDAdded);
5927            $('img[src$="sectigo_trust_seal_lg_140x54.png"]').attr({alt: "Sectigo Seal", 'aria-label': "Sectigo Seal"});
5928            $("a.aria-basket-link").attr("role","button").attr("aria-label","Shopping Cart");
5929            $(".month-wrap .month").attr("aria-level","3");
5930            
5931            var $metaViewport = $('meta[name="viewport"]');
5932            if ($metaViewport.length) {
5933                $metaViewport.attr('content', 'width=device-width, initial-scale=1.0, minimum-scale=1.0');
5934            } else {
5935                $('head').append('<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0">');
5936            }
5937
5938        }, 1200);
5939
5940        setTimeout(function() {   
5941            $('[data-index]').removeAttr('data-index');
5942            $('[tabindex]').removeAttr('tabindex');
5943            $('[tabindes]').removeAttr('tabindes');
5944            
5945            let HeaderElements = $('.head-inner').find('.logo-container a, .showare-nav-inner a, select, textarea, input, a.button,#ShoWareBasketWidget .cart-item');
5946            let SideBarElements = $('.show-wrap').find('a, .sw-datepicker td.highlight-day, .bn_prev, .month, .bn_next');
5947            let allElements = $('.main-container').find('input, select, textarea, a.button,  .info-box a, button, h2 a, h3 a, a.pl-popup-link, #basket a, .login-form a'); // find all elements that needed tab index
5948                    
5949            // Header
5950            HeaderElements.each(function() {
5951                $(this).removeAttr('tabindex');
5952            });
5953            $(".showare-nav li").removeAttr('tabindex');
5954            $("#ShoWareBasketWidget .cart-item").removeAttr('tabindex');
5955            $(".aria-basket-link").removeAttr('tabindex');
5956            $("#searchButton").removeAttr('tabindex');
5957            $(".show-wrap .control-box").removeAttr('tabindex');
5958    
5959                HeaderElements.each(function(index) {
5960                    $(this).attr('tabindex', 0);
5961                });	
5962                // Sidebar
5963                SideBarElements.each(function() {
5964                    $(this).removeAttr('tabindex');
5965                });
5966    
5967                SideBarElements.each(function(index) {
5968                    $(this).attr('tabindex', 0);
5969                });
5970    
5971                // Main Content
5972                allElements.each(function() {
5973                    $(this).removeAttr('tabindex');
5974                });
5975    
5976                allElements.each(function(index) {
5977                    if (!$(this).attr('tabindex')) {
5978                        $(this).attr('tabindex', 0);
5979                    }
5980                });
5981            
5982            $(".performance-block-date-link").attr('tabindex', -1);
5983            $(".basket-widget a.aria-basket-link").attr('tabindex', -1);
5984            $("a.skip-link").attr('tabindex', -1);
5985            $(".copyright-text a").each(function(index) {
5986                $(this).attr('tabindex', 0);
5987            });
5988
5989            $(".highlightinfo-wrap .prevevent-btn").attr("aria-label", "Previous Event");
5990            $(".highlightinfo-wrap .nextevent-btn").attr("aria-label", "Next Event");
5991            $(".highlightinfo-wrap .button-wrap a.button").attr("role", "button").attr("aria-label", "Buy Tickets");
5992            $(".featuredevent-box  .bottominfo-wrap a.button.featured-togglelink").attr("role", "button").attr("aria-label", "Toggle Down to Open event information");
5993            $('img[src$="sectigo_trust_seal_lg_140x54.png"]').attr({alt: "Sectigo Seal", 'aria-label': "Sectigo Seal"});
5994            $(".info-box a").attr("role", "button").attr("aria-label", "Venue Link");
5995            $("a.forgot-password-link").attr("role", "button").attr("aria-label", "Forgot Password");
5996           
5997            $("#EventInformationWrap").attr("tabindex", "0"); 
5998            $("#venuesWidget .right a.button").attr("role", "button"); 
5999            $("table.cal thead th").attr('scope', 'col');
6000            $('.otherimages img').each(function () {
6001                var src = $(this).attr('src');
6002                if (src) {
6003                    var filename = src.substring(src.lastIndexOf('/') + 1); // Get the filename
6004                    $(this).attr('alt', filename); // Set as alt
6005                }
6006            });
6007            $('.mainimage img').each(function () {
6008                var src = $(this).attr('src');
6009                if (src) {
6010                    var filename = src.substring(src.lastIndexOf('/') + 1); // Get the filename
6011                    $(this).attr('alt', filename); // Set as alt
6012                }
6013            });
6014            $('.bundle-event-container').each(function() {
6015                var altText = $(this).find('.event-container-header').text().trim();
6016                $(this).find('.bundle-event-image').attr('alt', altText);
6017            });
6018            $('.related-event').each(function() {
6019                var altTextH3 = $(this).find('h3').text().trim();
6020                $(this).find('img').attr('alt', altTextH3);
6021            });
6022
6023        }, 3500);
6024        
6025
6026    }catch(e){
6027        console.log("Failed to update header for accessability:");
6028        console.log(e);
6029    }
6030</script>
6030
6031<style>
6032*:focus {box-shadow: 0 0 0 3px #fff,0 0 4px 6px #ccc!important;}
6033
6034/* Hide visually but keep accessible to screen readers */   
6035    .sr-only {
6036        position: absolute !important;
6037        width: 1px !important;
6038        height: 1px !important;
6039        padding: 0 !important;
6040        margin: -1px !important;
6041        overflow: hidden !important;
6042        clip: rect(0, 0, 0, 0) !important;
6043        border: 0 !important;
6044    }
6045    .skip-link {
6046        position: absolute;
6047        left: -10000px;
6048        top: auto;
6049        width: 1px;
6050        height: 1px;
6051        overflow: hidden;
6052    }
6053/* Style for focused interactive elements visible to accessibility readers */
6054    :focus-visible {
6055        outline: 2px solid #ccc; /* Show the outline for accessibility readers */
6056        outline-offset: 2px; /* Optional: Adjust the spacing between the element and the outline */
6057    }
6058</style>
6059
6060<script>
6061setTimeout(function() {
6062	$( document ).ready(function() {
6063		$('#mobile-menu li a').each(function(){			
6064			if($(this).is(':contains("close")')) {
6065				$(this).attr("onclick","actWidget('');");
6066			}
6067			if($(this).is(':contains("search")')) {
6068				$(this).attr("onclick","actSearch();return 0;");
6069			}
6070
6071            if($(this).is(':contains("shopping cart")')) {
6072                $(this).attr("HREF","https://www.cincyticket.com/basket.asp?fw=1");
6073            }
6074		});
6075		$('#mobile-menu').removeAttr("onclick");
6076	});
6077}, 300);
6078</script>
6078
6079
6080<script>
6081// Add control wrap's height as the min-height for main-constrain-width so the sidebar won't overlap to the footer
6082setTimeout(function() {
6083	$( document ).ready(function() {
6084        varControlWrapHeight = $(".control-wrap").height() + "px";
6085		$(".main-constrain-width").css( "min-height", varControlWrapHeight );
6086	});
6087}, 300);
6088</script>
6088
6089
6090
6091
6092</body>
6093</html>

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