PageSourceSearch

https://www.cincyticket.com/default.asp

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