PageSourceSearch

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

html cincyticket.com collected 2026-09-25 18:52:15 UTC 312,651 bytes, 7,595 lines download raw bytes

1
2
3<!DOCTYPE html>
4<html>
5<head>
6	<!-- CCU 03/2006 meta tags settings start -->
7	<title>CincyTicket</title>
8	<meta name="description" content="Visit CincyTicket.com to get tickets for the hottest events in Cincinnati, OH and the surrounding area.">
9    <meta name="keywords" content="CincyTicket, tickets,Buy Tickets, events, performances, shows, online ticketing">
10    <meta name="author" content="CincyTicket">
11    <meta name="abstract" content="Buy tickets and see performance listings from CincyTicket">
12    <meta name="robots" content="INDEX, FOLLOW">
13
14	<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.8, minimum-scale=1.0' name='viewport' />
15	<meta name="google-translate-customization" content="9aaf36daf6e43103-a12f76fcd2014ac8-g804c3b886a9cdf60-11"></meta> 
16    
17    <link rel="stylesheet" type="text/css" href="//www.cincyticket.com/include/structure.css?ver=20228">
18    <link rel="stylesheet" type="text/css" href="//www.cincyticket.com/include/style.css?ver=20228">
19    <link rel='stylesheet' content='text/css' href='/include/jqueryui-themes/default/jquery-ui.css' />
20    
21		<link rel="stylesheet" type="text/css" media="only screen and (max-width: 1024px)" href="//www.cincyticket.com/include/mobile.css?ver=20228">
22	
23	
23<script type="text/javascript" src="//www.cincyticket.com/include/javascript.js?ver=20228"></script>
23
24    
24<script type="text/javascript" src="//www.cincyticket.com/include/jq.js"></script>
24
25
26    
26<script type='text/javascript' src='/include/jquery-3.5.1.min.js'></script>
26<script type='text/javascript' src='/include/jqueryui-themes/jquery-ui.min.js'></script>
26
27        
27<script type="text/javascript" src="//www.cincyticket.com/include/mobile.js"></script>
27
28    
29<script type="text/javascript">
30    if (!navigator.cookieEnabled) {
31        alert("Your browser settings are currently configured to not allow cookies. Please enable cookies and try again.");
32        window.stop();
33        document.execCommand("Stop"); //works in IE, 
34    }
35</script>
35
36
37
38
39<script type="text/javascript" src="//www.cincyticket.com/include/swApi.js"></script>
vendor: 2 bytes, line 39
39
40<script type="text/javascript" src="//www.cincyticket.com/include/swApiPublic.js"></script>
vendor: 2 bytes, line 40
40
41<script type="text/javascript">
42
43var window = window || {};
44var Showare = Showare || {};
45var document = document || undefined;
46
47Showare.Logger = {
48   Settings: {
49      ShouldLogInDev: true
50   },
51   data: null,
52   env: {}
53}
54
55window.onerror = function(msg, url, lineNo, _, error) {
56    var envInfo = Showare.Logger._getEnvironmentDetails();
57
58    var message = {
59        Description: msg,
60        SourceFile: url,
61        SourceLine: lineNo,
62        Referer: envInfo.referer,
63        QueryString: envInfo.querystring,
64        ErrorType: Showare.Logger.Settings.ErrorType,
65        Website: envInfo.website,
66        ShouldLogInDev: Showare.Logger.Settings.ShouldLogInDev,
67        Browser: envInfo.browser,
68        IPAddress: envInfo.ipaddress
69    };
70
71    if (error != undefined) {
72        message.Exception = error.stack;
73    }
74
75    if (Showare.Logger.data) {
76        message.StateVariables = JSON.stringify(Showare.Logger.data);
77    }
78
79    swApiPublic.sendRequest("POST", "/v1/errorlog/", message);
80    Showare.Logger.data = null;
81    return false;
82
83    function shouldfilterError() {
84        return !(
85            // This error gets thrown by third party includes, to see full error, we need
86            // to do https://blog.sentry.io/2016/05/17/what-is-script-error.html
87            (msg.search("\s*Script error.*") == -1) &&
88            // Related to iOS issue: https://github.com/getsentry/raven-js/issues/756
89            (msg.search(".*evaluating 'elt.parentNode'.*") == -1))
90    }
91};
92
93Showare.Logger.log = function(exception, data) {
94    Showare.Logger.data = data;
95
96    if (Object.prototype.toString.call(exception) == "[object Error]") {
97        if (exception.stack) {
98            var ex = exception.stack.split('\n');
99            // Parse exceptions in the format of
100            // ' at src (javascript.js?ver=20228:510)'
101            var data = ex[1].match(/.+\((.+):(\d+):(\d+)\)/); 
102            // and 
103            // ' at src javascript.js?ver=20228:510'
104            if (!data) {
105                data = ex[1].match(/.+\s(.+):(\d+):(\d+)/);
106            }
107            window.onerror(ex[0], data[1], data[2], '', exception);
108        } else {
109            window.onerror(exception.name + ": " + exception.message, '', '');
110        }
111    } else {
112        window.onerror(exception, '', '');
113    }
114};
115
116Showare.Logger.warn = function(msg, data) {
117    var logDetails = {
118        environment: Showare.Logger._getEnvironmentDetails(),
119        message: msg,
120        data: data
121    }
122    
123    swApiPublic.sendRequest("POST", "/v1/errorlog/warn", logDetails);
124    return;
125};
126
127Showare.Logger._getEnvironmentDetails = function() {
128    Showare.Logger.Settings.ErrorType = 'Javascript';
129    return  {
130        browser: "Mozilla/5.0 AppleWebKit/537.36 KHTML, like Gecko compatible PageSourceSearchBot/1.0 https//pagesourcesearch.com/bot Chrome/128.0.0.0 Safari/537.36",
131        ipaddress: "181.215.65.76",
132        querystring: window.location.href,
133        referer: "",
134        website: "www.cincyticket.com",
135        basketid: "0FkQ0UVTLSTMzgwTMTgE10CMD2IyMMDNykxTNTIEx0CNDuExMOjL1E1jLjcY2xULEK9KRRUSRx__U_g_"
136    }
137}
138
139</script>
139<script type="text/javascript">
140//---------------------------DATEPICKER---------------------------------
141function buildDatepicker(options) {
142    //Calling this function should be sufficient to create a calendar within a designated div, with and
143    //EX: headerDP = buildDatepicker({"calendarID":"headerCalendar","linkedInputID":"headerCalendarInput","isModal":false,"forceDates":true, "defaultDate": "{{Output date from server Here}}"}); <~ would create a calendar object for the calendar presented at #headerCalendar, and link it to #headerCalendarInput
144    //most calendar methods are specific to the document the calendar resides on, and should be handled via the onChange event for the linked input
145    //Available Options:
146    //  calendarID (required)       == string, ID of calendar div
147    //  linkedInput (required)      == string, ID of input which will change when a date is selected
148    //  isModal                     == boolean, if true, calendar will be hidden, and display when the designated input recieves focus. If false, the calendar will be present and display as an inline block at all times.
149    //  forceDates                  == boolean, if true only highlighted dates will be clickable
150    //  detailedCalendar            == boolean, if true data is pulled to determine pricing information, sold out days, limited availablility - requires eventID
151    //  defaultDate                 == string, mm/dd/yyyy date that calendar should start on (this will only represent the month displayed at the begining)
152    //  type                        == string: defaults to "performancedates", which will add all visible performances
153    //  eventID                     == integer: defaults to -1 which means no event. Other values will filter by events with that ID, allowing for a search of performance dates for a specific event only
154    //  isMultiplePerformanceIndicator == boolean: if true, shows indicator for dates with multiple performance times
155    //
156    //Methods:
157    //  showDlg()/hideDlg()             : shows/hides modal calendars, no valid for non-modal calendars
158    //  addHighlightDay(mm/dd/yyyy)     : adds a date (presented as a mm/dd/yyyy string) to the list of highlight dates for the calendar - REQUIRES HighlightDays() function call to visually represent this change on the calendar
159    //  clearHihghlightDays()           : removes all stored highlight dates
160    //  highlightDays()                 : adds highlight class to stored days, visually highlighting them ont he calendar.
161    
162    var myID = options.calendarID; //required
163    var myLinkedInput = options.linkedInputID; //required
164    var isModal = options.isModal || false;
165    var showLoader = options.showLoader || false;
166    var forceDates = options.forceDates || false;
167    var myDefault = new Date();
168    if (options.defaultDate) {
169        try{
170            
171            myDefault = new Date(options.defaultDate);
172        } catch (e) {
173            console.log("date no valid for calendar: " + myID);
174            console.log(e);
175        }
176    }
177    var type = options.type || "performancedates";
178    var eventID = options.eventID || -1;
179    var detailedCalendar = options.detailedCalendar && eventID != -1 || false;
180    var bundleID = options.bundleID || -1;
181    var categoryID = options.CategoryID || -1;
182    var corporatePartnerPage = options.corporatePartnerPage || 0;
183    var bValidCoupon = options.bValidCoupon || 0;
184    var couponCode = options.couponCode || "";
185    var isMultiplePerformanceIndicator = options.isMultiplePerformanceIndicatorFlag || 0;
186
187    return new swDatepicker(myID, myLinkedInput, isModal, showLoader, forceDates, detailedCalendar, myDefault, type, eventID, bundleID, categoryID, corporatePartnerPage,bValidCoupon,couponCode,isMultiplePerformanceIndicator)
188}
189function swDatepicker(id, target, modal, loader, force, detailed, defaultDate, type, eventID, bundleID, categoryID, corporatePartnerPage,bValidCoupon,couponCode,isMultiplePerformanceIndicator) {
190
191    this.$id = $('#' + id); // element to attach widget to
192    this.$monthObj = this.$id.find('.month');
193    this.$prev = this.$id.find('.bn_prev');
194    this.$next = this.$id.find('.bn_next');
195    this.$grid = this.$id.find('.cal');
196    this.$target = $('#' + target); // div or text box that will receive the selected date string and focus (if modal)
197    this.bModal = modal; // true if datepicker should appear in a modal dialog box.
198    this.showLoader = loader;
199    this.forceDateSelection = force; //if true, will only allow users to click on highlighted dates - see addHighlightDay()
200    this.detailedCalendar = detailed;
201    this.active = !modal;
202    this.type = type;
203    this.eventID = eventID;
204    this.bundleID = bundleID;
205    this.categoryID = categoryID;
206    this.corporatePartnerPage = corporatePartnerPage;
207    this.fromDateRange = "";
208    this.toDateRange = "";
209    this.dateRangeEvents = [];
210    this.calendarName = id;
211
212    this.monthNames = ['January', 'February', 'March', 'April', 'May', 'June',
213    'July', 'August', 'September', 'October', 'November', 'December'];
214
215    this.dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
216
217    this.dateObj = new Date();
218
219    this.curYear = this.dateObj.getFullYear();
220    this.year = defaultDate.getFullYear();
221
222    this.curMonth = this.dateObj.getMonth();
223    this.month = defaultDate.getMonth();
224    this.getFirstDate(defaultDate.getMonth()); //update the month to the first performance ASAP
225
226    this.curDate = this.dateObj.getDate();
227    this.date = defaultDate.getDate();
228    this.currentDate = (this.month == this.curMonth && this.year == this.curYear);
229    this.activeMonth = (String(this.month + 1) + "/1/" + this.year);
230
231    this.keys = {
232        tab: 9,
233        enter: 13,
234        esc: 27,
235        space: 32,
236        pageup: 33,
237        pagedown: 34,
238        end: 35,
239        home: 36,
240        left: 37,
241        up: 38,
242        right: 39,
243        down: 40
244    };
245
246    this.bValidCoupon = bValidCoupon;
247    this.couponCode = couponCode;
248    this.isMultiplePerformanceIndicator = isMultiplePerformanceIndicator;
249
250    this.highlightDates = [];    
251
252    // display the current month
253    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
254
255    // populate the calendar grid
256    this.popGrid();
257
258    // update the table's activedescdendant to point to the current day
259    this.$grid.attr('aria-activedescendant', this.$grid.find('.today').attr('id'));
260
261    this.bindHandlers();
262
263    //show selected day
264        $('#' + this.calendarName + '-day' + this.date).addClass('focus').attr('aria-selected', 'true');
265
266    // hide dialog if in modal mode
267    if (this.bModal == true) {
268        this.$id.attr('aria-hidden', 'true');
269        //show/hide functionality may vary based on use, so should be handled after the datepicker is created.
270        //if we're on mobile, disable keyboard for the input:
271        if ($(window).width() < 1024) {
272            this.$target.attr("readonly", "true");
273        }
274    }
275
276    this.currencySymbol = "$";
277    this.buyTicketsButtonText = "Buy Tickets";
278}
279
280//
281// popGrid() is a member function to populate the datepicker grid with calendar days
282// representing the current month
283//
284// @return N/A
285//
286swDatepicker.prototype.popGrid = function () {
287    if(this.showLoader)
288        $(".calendar-loading").show();
289    var numDays = this.calcNumDays(this.year, this.month);
290    var startWeekday = this.calcStartWeekday(this.year, this.month);
291    //var lastMonth = this.month - 1;
292    //var lastMonthYear = this.year;
293    var weekday = 0;
294    var curDay = 1;
295    var rowCount = 1;
296    var $tbody = this.$grid.find('tbody');
297
298    var currentDateDay = this.dateObj.getDate();
299    var currentDateMonth = this.dateObj.getMonth();
300    var currentDateYear = this.dateObj.getFullYear();
301
302    var gridCells = '\t<tr id="row1">\n';
303
304    // Keeping in case the client (Gaylord) pushes back on not having previous month's dates selectable
305    // If the last month is -1, roll it over to December (11) and subtract 1 from the last month's year
306    /*if (lastMonth < 0) {
307        lastMonth = 11;
308        lastMonthYear = lastMonthYear - 1;
309    }
310
311    var lastMonthNumDays = this.calcNumDays(lastMonthYear, lastMonth);
312    var lastMonthStartDay = lastMonthNumDays - (startWeekday - 1);*/
313
314    // clear the grid
315    $tbody.empty();
316    $('#msg').empty();
317
318    // Keeping in case the client (Gaylord) pushes back on not having previous month's dates selectable
319    // Insert the leading empty cells
320    /*for (var weekday = 0; weekday < startWeekday; weekday++) {
321        gridCells += '\t\t<td id="' + this.calendarName + '-day' + lastMonthStartDay + '" class="day-cell muted last-month" headers="row' +
322            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false" data-year="' + lastMonthYear + '"><span class="calendar-day notranslate" data-month="' + lastMonth + '">' + lastMonthStartDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
323        //gridCells += '\t\t<td class="empty" data-month="' + lastMonth + '" data-year="' + lastMonthYear + '" data-day="' + lastMonthStartDay + '">&nbsp;</td>\n';
324        lastMonthStartDay++;
325    }*/
326
327    for (var weekday = 0; weekday < startWeekday; weekday++) {
328        gridCells += '\t\t<td class="empty">&nbsp;</td>\n';
329    }
330
331    // insert the days of the month.
332    for (curDay = 1; curDay <= numDays; curDay++) {
333
334        if (curDay == this.curDate && this.currentDate == true) {
335
336            gridCells += '\t\t<td id="' + this.calendarName + '-day' + curDay + '" class="today day-cell" aria-label="row' +
337            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false"><span class="calendar-day notranslate">' + curDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
338        }
339        else {
340            var addMuted = "";
341
342            // Only mute dates in the past for the date range selector widget
343            if (this.type == 'dateRangeSelect') {
344                // If the year is in the past, or the year is the same but the month is in the past, or the month and year are the same but the day is in the past, mute the date
345                if (this.year < currentDateYear
346                    || (this.year == currentDateYear && this.month < currentDateMonth)
347                    || (this.year == currentDateYear && this.month == currentDateMonth && curDay < currentDateDay)
348                ) {
349                    addMuted = " muted";
350                }
351            }
352            
353            gridCells += '\t\t<td id="' + this.calendarName + '-day' + curDay + '" class="day-cell' + addMuted + '" aria-label="row' +
354            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false"><span class="calendar-day notranslate">' + curDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
355        }
356
357
358        if (weekday == 6 && curDay < numDays) {
359            // This was the last day of the week, close it out
360            // and begin a new one
361            gridCells += '\t</tr>\n\t<tr id="row' + rowCount + '">\n';
362            rowCount++;
363            weekday = 0;
364        }
365        else {
366            weekday++;
367        }
368    }
369
370    // Insert any trailing empty cells
371    for (weekday; weekday < 7; weekday++) {
372
373        gridCells += '\t\t<td class="empty">&nbsp;</td>\n';
374    }
375
376    gridCells += '\t</tr>';
377
378    $tbody.append(gridCells);
379    if(this.detailedCalendar){
380        this.getCalendarDetails();
381    }else{
382        this.fetchDates();
383    }
384    
385}
386
387//
388// calcNumDays() is a member function to calculate the number of days in a given month
389//
390// @return (integer) number of days
391//
392swDatepicker.prototype.calcNumDays = function (year, month) {
393
394    return 32 - new Date(year, month, 32).getDate();
395}
396
397//
398// calcstartWeekday() is a member function to calculate the day of the week the first day of a
399// month lands on
400//
401// @return (integer) number representing the day of the week (0=Sunday....6=Saturday)
402//
403swDatepicker.prototype.calcStartWeekday = function (year, month) {
404
405    return new Date(year, month, 1).getDay();
406
407} // end calcStartWeekday()
408
409//
410// showPrevMonth() is a member function to show the previous month
411//
412// @param (offset int) offset may be used to specify an offset for setting
413//                      focus on a day the specified number of days from
414//                      the end of the month.
415// @return N/A
416//
417swDatepicker.prototype.showPrevMonth = function (offset) {
418    // show the previous month
419    if (this.month < 1) {
420        this.month = 11;
421        this.year--;
422    }
423    else {
424        this.month--;
425    }
426
427    if (this.month != this.curMonth || this.year != this.curYear) {
428        this.currentDate = false;
429    }
430    else {
431        this.currentDate = true;
432    }
433
434    this.activeMonth = (String(this.month + 1) + "/1/" + this.year)
435
436    // populate the calendar grid
437    this.popGrid();
438
439    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
440
441    // if offset was specified, set focus on the last day - specified offset
442    if (offset != null) {
443        var numDays = this.calcNumDays(this.year, this.month);
444        var day = 'day' + (numDays - offset);
445
446        this.$grid.attr('aria-activedescendant', this.calendarName + '-' + day);
447        $('#' + this.calendarName + '-' + day).addClass('focus').attr('aria-selected', 'true');
448    }
449
450
451} // end showPrevMonth()
452
453//
454// showNextMonth() is a member function to show the next month
455//
456// @param (offset int) offset may be used to specify an offset for setting
457//                      focus on a day the specified number of days from
458//                      the beginning of the month.
459// @return N/A
460//
461swDatepicker.prototype.showNextMonth = function (offset) {
462
463    // show the next month
464    if (this.month == 11) {
465        this.month = 0;
466        this.year++;
467    }
468    else {
469        this.month++;
470    }
471
472    if (this.month != this.curMonth || this.year != this.curYear) {
473        this.currentDate = false;
474    }
475    else {
476        this.currentDate = true;
477    }
478
479    this.activeMonth = (String(this.month + 1) + "/1/" + this.year)
480
481    // populate the calendar grid
482    this.popGrid();
483
484    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
485
486    // if offset was specified, set focus on the first day + specified offset
487    if (offset != null) {
488        var day = 'day' + offset;
489
490        this.$grid.attr('aria-activedescendant', this.calendarName + '-' + day);
491        $('#' + this.calendarName + '-' + day).addClass('focus').attr('aria-selected', 'true');
492    }
493
494} // end showNextMonth()
495
496//
497// showPrevYear() is a member function to show the previous year
498//
499// @return N/A
500//
501swDatepicker.prototype.showPrevYear = function () {
502
503    // decrement the year
504    this.year--;
505
506    if (this.month != this.curMonth || this.year != this.curYear) {
507        this.currentDate = false;
508    }
509    else {
510        this.currentDate = true;
511    }
512
513    // populate the calendar grid
514    this.popGrid();
515
516    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
517
518} // end showPrevYear()
519
520//
521// showNextYear() is a member function to show the next year
522//
523// @return N/A
524//
525swDatepicker.prototype.showNextYear = function () {
526
527    // increment the year
528    this.year++;
529
530    if (this.month != this.curMonth || this.year != this.curYear) {
531        this.currentDate = false;
532    }
533    else {
534        this.currentDate = true;
535    }
536
537    // populate the calendar grid
538    this.popGrid();
539
540    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
541
542} // end showNextYear()
543
544//
545// bindHandlers() is a member function to bind event handlers for the widget
546//
547// @return N/A
548//
549swDatepicker.prototype.bindHandlers = function () {
550
551    var thisObj = this;
552
553    ////////////////////// bind button handlers //////////////////////////////////
554    this.$prev.click(function (e) {
555        return thisObj.handlePrevClick(e);
556    });
557
558    this.$next.click(function (e) {
559        return thisObj.handleNextClick(e);
560    });
561
562    this.$prev.keydown(function (e) {
563        return thisObj.handlePrevKeyDown(e);
564    });
565
566    this.$next.keydown(function (e) {
567        return thisObj.handleNextKeyDown(e);
568    });
569
570    ///////////// bind grid handlers //////////////
571
572    this.$grid.keydown(function (e) {
573        return thisObj.handleGridKeyDown(e);
574    });
575
576    this.$grid.keypress(function (e) {
577        return thisObj.handleGridKeyPress(e);
578    });
579
580    this.$grid.focus(function (e) {
581        return thisObj.handleGridFocus(e);
582    });
583
584    this.$grid.blur(function (e) {
585        return thisObj.handleGridBlur(e);
586    });
587
588    this.$grid.delegate('td', 'click', function (e) {
589        return thisObj.handleGridClick(this, e);
590    });
591
592} // end bindHandlers();
593
594function scrollToFirstHighlightDay() {
595    // find all the heights of elements before the calendar
596    var EventInfoHeight = $('#EventInformationWrap').outerHeight() + 64; // 64 is the height mobile navigation
597    var EventLabelAndOptionsHeight = $('#eventCalendarLabelAndOptions').outerHeight(); 
598    var CalendarMonthHeight =  $('.sw-datepicker.large-datepicker .month-wrap').outerHeight(); 
599
600    var EventInfoAndOptionsHeight = EventInfoHeight + EventLabelAndOptionsHeight;
601    var CalendarTopInfoHeaderHeights = EventInfoHeight + EventLabelAndOptionsHeight + CalendarMonthHeight + 10; // 10 is just a gap added so it is not sticking against the month section
602
603    // set the Top section sticky so when it focuses on the first hightlight day you can still see the informations 
604    $('#EventInformationWrap').addClass("make-this-section-sticky");
605    $('#eventCalendarLabelAndOptions').addClass("make-this-section-sticky");
606    $('#eventCalendarLabelAndOptions').css("top", EventInfoHeight);
607    $('.sw-datepicker.large-datepicker .month-wrap').addClass("make-this-section-sticky");
608    $('.sw-datepicker.large-datepicker .month-wrap').css("top", EventInfoAndOptionsHeight);
609
610    // Check if any elements with the class .highlight-day exist
611    var highlightDay = $('.performance-list-calendar .highlight-day').first();
612
613    // set the first day cell
614    var firstDayCel = $('.day-cell').first();
615    var scrollToPosition = 0;
616
617    if (highlightDay.length > 0) { // Get the offset only if .highlight-day element exists
618        scrollToPosition = highlightDay.offset().top;
619        scrollToPosition = scrollToPosition - CalendarTopInfoHeaderHeights;  
620        $('html, body').animate({scrollTop: scrollToPosition}, 'slow');
621    } else { // if there's no highlights on this month, focus on the first day of the month
622        scrollToPosition = firstDayCel.offset().top;
623        scrollToPosition = scrollToPosition - (CalendarTopInfoHeaderHeights * 2);
624        $('html, body').animate({scrollTop: scrollToPosition}, 'slow');
625    }
626}
627
628//
629// handlePrevClick() is a member function to process click events for the prev month button
630//
631// @input (e obj) e is the event object associated with the event
632//
633// @return (boolean) false if consuming event, true if propagating
634//
635swDatepicker.prototype.handlePrevClick = function (e) {
636    
637    var active = this.$grid.attr('aria-activedescendant');
638
639    if (e.ctrlKey) {
640        this.showPrevYear();
641    }
642    else {
643        this.showPrevMonth();
644    }
645
646    if (this.currentDate == false) {
647        this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
648    }
649    else {
650        this.$grid.attr('aria-activedescendant', active);
651    }
652
653    e.stopPropagation();
654    return false;
655
656} // end handlePrevClick()
657
658//
659// handleNextClick() is a member function to process click events for the next month button
660//
661// @input (e obj) e is the event object associated with the event
662//
663// @return (boolean) false if consuming event, true if propagating
664//
665swDatepicker.prototype.handleNextClick = function (e) {
666    
667    var active = this.$grid.attr('aria-activedescendant');
668
669    if (e.ctrlKey) {
670        this.showNextYear();
671    }
672    else {
673        this.showNextMonth();
674    }
675
676    if (this.currentDate == false) {
677        this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
678    }
679    else {
680        this.$grid.attr('aria-activedescendant', active);
681    }
682
683    e.stopPropagation();
684    return false;
685
686} // end handleNextClick()
687
688//
689// handlePrevKeyDown() is a member function to process keydown events for the prev month button
690//
691// @input (e obj) e is the event object associated with the event
692//
693// @return (boolean) false if consuming event, true if propagating
694//
695swDatepicker.prototype.handlePrevKeyDown = function (e) {
696
697    if (e.altKey) {
698        return true;
699    }
700
701    switch (e.keyCode) {
702        case this.keys.tab: {
703            if (this.bModal == false || !e.shiftKey || e.ctrlKey) {
704                return true;
705            }
706
707            this.$grid.focus();
708            e.stopPropagation();
709            return false;
710        }
711        case this.keys.enter:
712        case this.keys.space: {
713            if (e.shiftKey) {
714                return true;
715            }
716
717            if (e.ctrlKey) {
718                this.showPrevYear();
719            }
720            else {
721                this.showPrevMonth();
722            }
723
724            e.stopPropagation();
725            return false;
726        }
727    }
728
729    return true;
730
731} // end handlePrevKeyDown()
732
733//
734// handleNextKeyDown() is a member function to process keydown events for the next month button
735//
736// @input (e obj) e is the event object associated with the event
737//
738// @return (boolean) false if consuming event, true if propagating
739//
740swDatepicker.prototype.handleNextKeyDown = function (e) {
741
742    if (e.altKey) {
743        return true;
744    }
745
746    switch (e.keyCode) {
747        case this.keys.enter:
748        case this.keys.space: {
749
750            if (e.ctrlKey) {
751                this.showNextYear();
752            }
753            else {
754                this.showNextMonth();
755            }
756
757            e.stopPropagation();
758            return false;
759        }
760    }
761
762    return true;
763
764} // end handleNextKeyDown()
765
766//
767// handleGridKeyDown() is a member function to process keydown events for the datepicker grid
768//
769// @input (e obj) e is the event object associated with the event
770//
771// @return (boolean) false if consuming event, true if propagating
772//
773swDatepicker.prototype.handleGridKeyDown = function (e) {
774
775    var $rows = this.$grid.find('tbody tr');
776    var $curDay = $('#' + this.$grid.attr('aria-activedescendant'));
777    var $days = this.$grid.find('td').not('.empty');
778    var $curRow = $curDay.parent();
779
780    if (e.altKey) {
781        return true;
782    }
783
784    switch (e.keyCode) {
785        case this.keys.tab: {
786
787            if (this.bModal == true) {
788                if (e.shiftKey) {
789                    this.$next.focus();
790                }
791                else {
792                    this.$prev.focus();
793                }
794                e.stopPropagation()
795                return false;
796            }
797            break;
798        }
799        case this.keys.enter:
800        case this.keys.space: {
801
802            if (e.ctrlKey) {
803                return true;
804            }
805
806            // update the target box
807            this.$target.val((this.month + 1) + '/' + $curDay.find(".calendar-day").text() + '/' + this.year).change();
808
809            // fall through
810        }
811        case this.keys.esc: {
812            // dismiss the dialog box
813            this.hideDlg();
814
815            e.stopPropagation();
816            return false;
817        }
818        case this.keys.left: {
819
820            if (e.ctrlKey || e.shiftKey) {
821                return true;
822            }
823
824            var dayIndex = $days.index($curDay) - 1;
825            var $prevDay = null;
826
827            if (dayIndex >= 0) {
828                $prevDay = $days.eq(dayIndex);
829
830                $curDay.removeClass('focus').attr('aria-selected', 'false');
831                $prevDay.addClass('focus').attr('aria-selected', 'true');
832
833                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
834            }
835            else {
836                this.showPrevMonth(0);
837            }
838
839            e.stopPropagation();
840            return false;
841        }
842        case this.keys.right: {
843
844            if (e.ctrlKey || e.shiftKey) {
845                return true;
846            }
847
848            var dayIndex = $days.index($curDay) + 1;
849            var $nextDay = null;
850
851            if (dayIndex < $days.length) {
852                $nextDay = $days.eq(dayIndex);
853                $curDay.removeClass('focus').attr('aria-selected', 'false');
854                $nextDay.addClass('focus').attr('aria-selected', 'true');
855
856                this.$grid.attr('aria-activedescendant', $nextDay.attr('id'));
857            }
858            else {
859                // move to the next month
860                this.showNextMonth(1);
861            }
862
863            e.stopPropagation();
864            return false;
865        }
866        case this.keys.up: {
867
868            if (e.ctrlKey || e.shiftKey) {
869                return true;
870            }
871
872            var dayIndex = $days.index($curDay) - 7;
873            var $prevDay = null;
874
875            if (dayIndex >= 0) {
876                $prevDay = $days.eq(dayIndex);
877
878                $curDay.removeClass('focus').attr('aria-selected', 'false');
879                $prevDay.addClass('focus').attr('aria-selected', 'true');
880
881                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
882            }
883            else {
884                // move to appropriate day in previous month
885                dayIndex = 6 - $days.index($curDay);
886
887                this.showPrevMonth(dayIndex);
888            }
889
890            e.stopPropagation();
891            return false;
892        }
893        case this.keys.down: {
894
895            if (e.ctrlKey || e.shiftKey) {
896                return true;
897            }
898
899            var dayIndex = $days.index($curDay) + 7;
900            var $prevDay = null;
901
902            if (dayIndex < $days.length) {
903                $prevDay = $days.eq(dayIndex);
904
905                $curDay.removeClass('focus').attr('aria-selected', 'false');
906                $prevDay.addClass('focus').attr('aria-selected', 'true');
907
908                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
909            }
910            else {
911                // move to appropriate day in next month
912                dayIndex = 8 - ($days.length - $days.index($curDay));
913
914                this.showNextMonth(dayIndex);
915            }
916
917            e.stopPropagation();
918            return false;
919        }
920        case this.keys.pageup: {
921            var active = this.$grid.attr('aria-activedescendant');
922
923
924            if (e.shiftKey) {
925                return true;
926            }
927
928
929            if (e.ctrlKey) {
930                this.showPrevYear();
931            }
932            else {
933                this.showPrevMonth();
934            }
935
936            if ($('#' + active).attr('id') == undefined) {
937                var lastDay = 'day' + this.calcNumDays(this.year, this.month);
938                $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
939            }
940            else {
941                $('#' + this.calendarName + '-' + active).addClass('focus').attr('aria-selected', 'true');
942            }
943
944            e.stopPropagation();
945            return false;
946        }
947        case this.keys.pagedown: {
948            var active = this.$grid.attr('aria-activedescendant');
949
950
951            if (e.shiftKey) {
952                return true;
953            }
954
955            if (e.ctrlKey) {
956                this.showNextYear();
957            }
958            else {
959                this.showNextMonth();
960            }
961
962            if ($('#' + active).attr('id') == undefined) {
963                var lastDay = 'day' + this.calcNumDays(this.year, this.month);
964                $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
965            }
966            else {
967                $('#' + this.calendarName + '-' + active).addClass('focus').attr('aria-selected', 'true');
968            }
969
970            e.stopPropagation();
971            return false;
972        }
973        case this.keys.home: {
974
975            if (e.ctrlKey || e.shiftKey) {
976                return true;
977            }
978
979            $curDay.removeClass('focus').attr('aria-selected', 'false');
980
981            $('#' + this.calendarName + '-day1').addClass('focus').attr('aria-selected', 'true');
982
983            this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
984
985            e.stopPropagation();
986            return false;
987        }
988        case this.keys.end: {
989
990            if (e.ctrlKey || e.shiftKey) {
991                return true;
992            }
993
994            var lastDay = 'day' + this.calcNumDays(this.year, this.month);
995
996            $curDay.removeClass('focus').attr('aria-selected', 'false');
997
998            $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
999
1000            this.$grid.attr('aria-activedescendant', this.calendarName + '-' + lastDay);
1001
1002            e.stopPropagation();
1003            return false;
1004        }
1005    }
1006
1007    return true;
1008
1009} // end handleGridKeyDown()
1010
1011//
1012// handleGridKeyPress() is a member function to consume keypress events for browsers that
1013// use keypress to scroll the screen and manipulate tabs
1014//
1015// @input (e obj) e is the event object associated with the event
1016//
1017// @return (boolean) false if consuming event, true if propagating
1018//
1019swDatepicker.prototype.handleGridKeyPress = function (e) {
1020
1021    if (e.altKey) {
1022        return true;
1023    }
1024
1025    switch (e.keyCode) {
1026        case this.keys.tab:
1027        case this.keys.enter:
1028        case this.keys.space:
1029        case this.keys.esc:
1030        case this.keys.left:
1031        case this.keys.right:
1032        case this.keys.up:
1033        case this.keys.down:
1034        case this.keys.pageup:
1035        case this.keys.pagedown:
1036        case this.keys.home:
1037        case this.keys.end: {
1038            e.stopPropagation();
1039            return false;
1040        }
1041    }
1042
1043    return true;
1044
1045} // end handleGridKeyPress()
1046
1047//
1048// handleGridClick() is a member function to process mouse click events for the datepicker grid
1049//
1050// @input (id obj) e is the id of the object triggering the event
1051//
1052// @input (e obj) e is the event object associated with the event
1053//
1054// @return (boolean) false if consuming event, true if propagating
1055//
1056swDatepicker.prototype.handleGridClick = function (id, e) {
1057    var $cell = $(id);
1058
1059    if ($cell.is('.empty')) {
1060        return true;
1061    }
1062
1063    this.$grid.find('.focus').removeClass('focus').attr('aria-selected', 'false');
1064    $cell.addClass('focus').attr('aria-selected', 'true');
1065    this.$grid.attr('aria-activedescendant', $cell.attr('id'));
1066
1067    var $curDay = $('#' + this.$grid.attr('aria-activedescendant'));
1068
1069    /*console.log($curDay);
1070    var isLastMonth = $curDay.hasClass('last-month');
1071
1072    var monthSelected = this.month + 1;
1073    var yearSelected = this.year;
1074    
1075    if (isLastMonth) {
1076        monthSelected--;
1077        
1078        if (monthSelected == 0)
1079            monthSelected = 12;
1080
1081        yearSelected = $curDay.data('year');
1082    }
1083
1084    console.log("month selected: " + monthSelected);
1085    console.log("year selected: " + yearSelected);*/
1086
1087    // update the target box
1088    if(this.type == 'dateRangeSelect'){
1089        if ($curDay.hasClass('muted'))
1090            return true;
1091        
1092        var $rangeSelDate = new Date((this.month + 1) + '/' + $curDay.children('.calendar-day').text() + '/' + this.year);
1093        if(this.fromDateRange == '' && this.toDateRange == ''){
1094            //no dates selected yet, store this in the from date range for now
1095            this.fromDateRange = $rangeSelDate;
1096        }else{
1097            //we've previously selected at least one date here, so figure out which one it should be
1098            if($rangeSelDate < this.fromDateRange){
1099                this.toDateRange = this.fromDateRange;
1100                this.fromDateRange = $rangeSelDate;
1101            }else{
1102                this.toDateRange = $rangeSelDate;
1103            }
1104        }
1105        
1106        var objDateRange = {}
1107        objDateRange.from = this.fromDateRange;
1108        objDateRange.to = this.toDateRange;
1109        this.$target.val(JSON.stringify(objDateRange)).change();
1110        if(objDateRange.from != '' && objDateRange.to != ''){
1111            this.hideDlg(); //NOTE: this only works if the date range is a modal, for other calendars you'll need to manage display according to needs based on current values.
1112        }
1113        e.stopPropagation();
1114        return false;
1115    }
1116    if (!this.forceDateSelection || $cell.hasClass("highlight-day")) {
1117        this.$target.val((this.month + 1) + '/' + $curDay.children('.calendar-day').text() + '/' + this.year).change();
1118        // dismiss the dialog box
1119        this.hideDlg();
1120    }
1121    e.stopPropagation();
1122    return false;
1123
1124} // end handleGridClick()
1125
1126//
1127// handleGridFocus() is a member function to process focus events for the datepicker grid
1128//
1129// @input (e obj) e is the event object associated with the event
1130//
1131// @return (boolean) true
1132//
1133swDatepicker.prototype.handleGridFocus = function (e) {
1134    var active = this.$grid.attr('aria-activedescendant');
1135
1136    if ($('#' + active).attr('id') == undefined) {
1137        var lastDay = 'day' + this.calcNumDays(this.year, this.month);
1138        $('#' + lastDay).addClass('focus').attr('aria-selected', 'true');
1139    }
1140    else {
1141        $('#' + active).addClass('focus').attr('aria-selected', 'true');
1142    }
1143
1144    return true;
1145
1146} // end handleGridFocus()
1147
1148//
1149// handleGridBlur() is a member function to process blur events for the datepicker grid
1150//
1151// @input (e obj) e is the event object associated with the event
1152//
1153// @return (boolean) true
1154//
1155swDatepicker.prototype.handleGridBlur = function (e) {
1156    $('#' + this.$grid.attr('aria-activedescendant')).removeClass('focus').attr('aria-selected', 'false');
1157
1158    return true;
1159
1160} // end handleGridBlur()
1161
1162//
1163// showDlg() is a member function to show the datepicker and give it focus. This function is only called if
1164// the datepicker is used in modal dialog mode.
1165//
1166// @return N/A
1167//
1168swDatepicker.prototype.showDlg = function () {
1169    if (!this.bModal)
1170        return;
1171
1172    var thisObj = this;
1173    var thisNode = this.$id;
1174
1175    this.highlightDays();
1176
1177    this.active = true;
1178
1179    //prevent calendar from pushing out of the right side of the window
1180    if (thisNode.parent()[0].getBoundingClientRect().left > (window.innerWidth / 2))
1181        thisNode.addClass("right-side");
1182
1183    $(".content-wrap").bind('click', function (e) {
1184        if (!thisNode[0].contains(e.target) && e.target != thisObj.$target[0]) {
1185            thisObj.hideDlg();
1186        }
1187    });
1188
1189    // show the dialog
1190    this.$id.attr('aria-hidden', 'false');
1191
1192    this.$grid.focus();
1193
1194} // end showDlg()
1195
1196//
1197// hideDlg() is a member function to hide the datepicker and remove focus. This function is only called if
1198// the datepicker is used in modal dialog mode.
1199//
1200// @return N/A
1201//
1202swDatepicker.prototype.hideDlg = function () {
1203    if (!this.bModal)
1204        return;
1205    
1206    this.active = false;
1207    var thisNode = this.$id;
1208
1209    // unbind the modal event sinks
1210    $(document).unbind('click');
1211
1212    // hide the dialog
1213    this.$id.attr('aria-hidden', 'true');
1214
1215    // set focus on the focus target
1216    //this.$target.focus();
1217
1218} // end showDlg()
1219
1220//function to highlight days with performances or valid information
1221//to prevent rewriting the calendar each time a date is added, popGrid() should be called after all dates have been added
1222swDatepicker.prototype.addHighlightDay = function (date) {
1223    var datesplit = String(date).split("/");
1224    for(var i = 0;i < datesplit.length; i++){
1225        datesplit[i] = datesplit[i].replace(/^0+/, '');
1226    }
1227    date = datesplit.join("/");
1228    if (datesplit.length != 3) {
1229        //date didn't come in in m/d/yyyy format, kick it back in the console
1230        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1231        console.log(date);
1232        return;
1233
1234    }
1235    this.highlightDates.push(date);
1236    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1237        $("#" + this.calendarName + "-day" + datesplit[1]).addClass("highlight-day");
1238    }
1239}
1240swDatepicker.prototype.addDateInfoBox = function (date, infoBoxText) {
1241    var datesplit = String(date).split("/");
1242    for(var i = 0;i < datesplit.length; i++){
1243        datesplit[i] = datesplit[i].replace(/^0+/, '');
1244    }
1245    date = datesplit.join("/");
1246    if (datesplit.length != 3) {
1247        //date didn't come in in m/d/yyyy format, kick it back in the console
1248        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1249        console.log(date);
1250        return;
1251
1252    }
1253    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1254        $("#" + this.calendarName + "-day" + datesplit[1]).append('<span class="date-info-box">' + infoBoxText + '</span>');
1255    }
1256}
1257swDatepicker.prototype.addDateSubNote = function (date, noteText) {
1258    var datesplit = String(date).split("/");
1259    for(var i = 0;i < datesplit.length; i++){
1260        datesplit[i] = datesplit[i].replace(/^0+/, '');
1261    }
1262    date = datesplit.join("/");
1263    if (datesplit.length != 3) {
1264        //date didn't come in in m/d/yyyy format, kick it back in the console
1265        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1266        console.log(date);
1267        return;
1268
1269    }
1270    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1271        var spanClass = this.isMultiplePerformanceIndicator ? 'date-info-box date-sub-note multiple-performancetime-subnote' : 'date-info-box date-sub-note';
1272        $("#" + this.calendarName + "-day" + datesplit[1]).append('<span class="' + spanClass + '">' + noteText + '</span>');
1273    }
1274}
1275swDatepicker.prototype.setDaySoldOut = function (date) {
1276    var datesplit = String(date).split("/");
1277    for(var i = 0;i < datesplit.length; i++){
1278        datesplit[i] = datesplit[i].replace(/^0+/, '');
1279    }
1280    date = datesplit.join("/");
1281    if (datesplit.length != 3) {
1282        //date didn't come in in m/d/yyyy format, kick it back in the console
1283        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1284        console.log(date);
1285        return;
1286
1287    }
1288    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1289        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('sold-out');
1290        
1291        this.addDateInfoBox(date, "Sold Out");
1292        $("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
1293    }
1294}
1295swDatepicker.prototype.setcustomStatus = function (date,showPhoneNumber,currenStatus) {
1296    var datesplit = String(date).split("/");
1297    for(var i = 0;i < datesplit.length; i++){
1298        datesplit[i] = datesplit[i].replace(/^0+/, '');
1299    }
1300    date = datesplit.join("/");
1301    if (datesplit.length != 3) {
1302        //date didn't come in in m/d/yyyy format, kick it back in the console
1303        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1304        console.log(date);
1305        return;
1306
1307    }
1308    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1309        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('sold-out');
1310        var phoneNumber = " <br> [email protected] "
1311        if (!showPhoneNumber)
1312            phoneNumber="";
1313        this.addDateInfoBox(date, currenStatus +phoneNumber);
1314        
1315        $("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
1316    }
1317}
1318swDatepicker.prototype.setDayLimitedAvailabilty = function (date) {
1319    var datesplit = String(date).split("/");
1320    for(var i = 0;i < datesplit.length; i++){
1321        datesplit[i] = datesplit[i].replace(/^0+/, '');
1322    }
1323    date = datesplit.join("/");
1324    if (datesplit.length != 3) {
1325        //date didn't come in in m/d/yyyy format, kick it back in the console
1326        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1327        console.log(date);
1328        return;
1329
1330    }
1331    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1332        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('limited-availability');
1333        
1334        this.addDateSubNote(date, 'Selling Quickly');
1335        //$("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
1336    }
1337    if($(".limited-availability-legend-item").length == 0){
1338        
1339            $(".calendar-notes-wrap").append('<div class="limited-availability-legend-item"><span classs="calendar-limited-availability-legend-icon">!</span> - Selling Quickly</div>')
1340         
1341       // $("#streamlinedCalendarLimitedAvailabilityLegend").append('<div class="limited-availability-legend-item"><span class="calendar-limited-availability-legend-icon">!</span> - Selling Quickly</div>')
1342    }
1343}
1344swDatepicker.prototype.setMultiplePerformanceTimes = function (date) {
1345    var datesplit = String(date).split("/");
1346    for(var i = 0;i < datesplit.length; i++){
1347        datesplit[i] = datesplit[i].replace(/^0+/, '');
1348    }
1349    
1350    date = datesplit.join("/");
1351    if (datesplit.length != 3) {
1352        //date didn't come in in m/d/yyyy format, kick it back in the console
1353        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1354        return;
1355
1356    }
1357    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1358        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('multipleperformancetimes');
1359
1360    }
1361    if($(".multiple-performancetimes-notes").length == 0){
1362        
1363    }
1364    
1365}
1366swDatepicker.prototype.setMutedDay = function (date) {
1367    var datesplit = String(date).split("/");
1368    for(var i = 0;i < datesplit.length; i++){
1369        datesplit[i] = datesplit[i].replace(/^0+/, '');
1370    }
1371    date = datesplit.join("/");
1372    if (datesplit.length != 3) {
1373        //date didn't come in in m/d/yyyy format, kick it back in the console
1374        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1375        return;
1376
1377    }
1378    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1379        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('muted');
1380    }
1381}
1382swDatepicker.prototype.clearMutedDay = function (date) {
1383    var datesplit = String(date).split("/");
1384    for(var i = 0;i < datesplit.length; i++){
1385        datesplit[i] = datesplit[i].replace(/^0+/, '');
1386    }
1387    date = datesplit.join("/");
1388    if (datesplit.length != 3) {
1389        //date didn't come in in m/d/yyyy format, kick it back in the console
1390        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1391        return;
1392
1393    }
1394    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1395        $("#" + this.calendarName + "-day" + datesplit[1]).removeClass('muted');
1396    }
1397}
1398swDatepicker.prototype.setCouponMutedDay = function (date) {
1399    var datesplit = String(date).split("/");
1400    for(var i = 0;i < datesplit.length; i++){
1401        datesplit[i] = datesplit[i].replace(/^0+/, '');
1402    }
1403    date = datesplit.join("/");
1404    if (datesplit.length != 3) {
1405        //date didn't come in in m/d/yyyy format, kick it back in the console
1406        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1407        return;
1408
1409    }
1410    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1411        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('coupon-muted');
1412    }
1413}
1414swDatepicker.prototype.setPasswordHiddenDay = function (date) {
1415    var datesplit = String(date).split("/");
1416    for(var i = 0;i < datesplit.length; i++){
1417        datesplit[i] = datesplit[i].replace(/^0+/, '');
1418    }
1419    date = datesplit.join("/");
1420    if (datesplit.length != 3) {
1421        //date didn't come in in m/d/yyyy format, kick it back in the console
1422        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
1423        return;
1424
1425    }
1426    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
1427        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('password-hidden');
1428        $("#" + this.calendarName + "-day" + datesplit[1]).removeClass('highlight-day');
1429    }
1430}
1431swDatepicker.prototype.clearAllMutedDays = function () {
1432    $(".muted").removeClass('muted');
1433}
1434swDatepicker.prototype.clearHighlightDays = function () {
1435    this.highlightDates = [];
1436    this.highlightDays();
1437}
1438//highlights all days in the highlightDates array
1439swDatepicker.prototype.highlightDays = function () {
1440    $("#" + this.calendarName + " .highlight-day").removeClass("highlight-day");
1441    var curYear = this.year;
1442    var curMonth = this.month;
1443    var calName = this.calendarName;
1444    var IEFix = new RegExp(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g);
1445
1446    this.highlightDates.forEach(function (o, i, a) {
1447        var datesplit = o.split("/");
1448        if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
1449            $("#" + calName + "-day" + datesplit[1].replace(IEFix, '')).addClass("highlight-day");
1450        }
1451    });
1452    this.setColors();
1453}
1454swDatepicker.prototype.setColors = function () {
1455    /*
1456        Custom color functionality. Utilized by dropping calendar-colors.txt file in root of custom folder
1457        requires json content of text file formatted as follows:
1458        {
1459            "events":
1460                {"528": 
1461                    [
1462                        {"date":"12/1/2025", "color": "#ccc"}, 
1463                        {"date":"12/2/2025", "color": "#ccc"}
1464                    ]
1465                ,
1466                "529":
1467                    [
1468                        {"date":"12/8/2025", "color": "#ccc"}, 
1469                        {"date":"12/9/2025", "color": "#ccc"}
1470                    ]
1471                }
1472            ,
1473            "bundles":[],
1474            "generic":
1475                {"dates": 
1476                    [
1477                        {"date":"12/23/2025", "color": "#def"}, 
1478                        {"date":"12/22/2025", "color": "#1a1"}
1479                    ]
1480                ,
1481                "weekdays":
1482                    [
1483                        {"day":"Saturday", "color": "#2a2"}, 
1484                        {"day":"Thursday", "color": "#3a3"}
1485                    ]
1486                }    
1487        }
1488    }
1489    */
1490    var thisDP = this;
1491    try{
1492        $.getJSON("/calendar-colors.txt")
1493        .done(function (data) {
1494            thisDP.renderColors(data);
1495        })
1496        .fail(function (jqxhr, textStatus, error) {
1497            console.log("No Custom Calendar Colors Found");
1498            return;
1499        });
1500    }catch(e){
1501        console.log("parsing error:");
1502        console.log(e);
1503        return;
1504    }
1505}
1506swDatepicker.prototype.renderColors = function (colorData) {
1507    var curYear = this.year;
1508    var curMonth = this.month;
1509    var calName = this.calendarName;
1510    var IEFix = new RegExp(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g);
1511    //set generic colors
1512    if(colorData.generic){
1513        if(colorData.generic.dates.length > 0){
1514            colorData.generic.dates.forEach(function (o, i, a) {
1515                var datesplit = o.date.split("/");
1516                if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
1517                    $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
1518                }
1519            });
1520        }
1521        if(colorData.generic.weekdays && colorData.generic.weekdays.length > 0){
1522            colorData.generic.weekdays.forEach(function (o, i, a) {
1523                $("td[headers*=" + o.day + "] .calendar-day").css("background-color", o.color);
1524            });
1525        }
1526    }
1527    if(colorData.events && colorData.events[this.eventID] && this.eventID !== -1){
1528        colorData.events[this.eventID].forEach(function (o, i, a) {
1529            var datesplit = o.date.split("/");
1530            if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
1531                $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
1532            }
1533        });
1534    }
1535    if(colorData.bundles && colorData.bundles[this.bundleID] && this.bundleID !== -1){
1536        colorData.bundles[this.bundleID].forEach(function (o, i, a) {
1537            var datesplit = o.date.split("/");
1538            if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
1539                $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
1540            }
1541        });
1542    }
1543}
1544swDatepicker.prototype.fetchDates = function(){
1545    var thisCalendar = this;
1546    var haveDates = thisCalendar.fetchLocalDates();
1547    if (thisCalendar.categoryID >= 0)
1548        haveDates = false;
1549    this.clearHighlightDays();
1550    if(haveDates){
1551        //valid local dates stored
1552        try{
1553            haveDates = JSON.parse(haveDates);
1554            if (haveDates.length > 0) {
1555                haveDates.forEach(function(o){
1556                    thisCalendar.addHighlightDay(o);
1557                })
1558                thisCalendar.highlightDays();
1559            }
1560        } catch (e) {
1561            console.log("Failed to grab dates. Date object not valid: ", haveDates);
1562            console.log(e);
1563        }
1564    } else {        
1565        $.getJSON("/include/widgets/calendar/calendarRequests.asp",
1566            {
1567                action: thisCalendar.type,
1568                calMonth: thisCalendar.activeMonth,
1569                iEvent: thisCalendar.eventID,
1570                iBundle: thisCalendar.bundleID,
1571                iCategory : thisCalendar.categoryID,
1572                cp : thisCalendar.corporatePartnerPage
1573            })
1574            .done(function (data) {
1575                thisCalendar.storeDates(data.performancedates);
1576                try {
1577                    if (data.performancedates.length > 0) {
1578                        data.performancedates.forEach(function (o) {
1579                            
1580                            thisCalendar.addHighlightDay(o);
1581                        })
1582                        thisCalendar.highlightDays();
1583                    }
1584                } catch (e) {
1585                    console.log("Failed to grab dates. Date object not valid: " + haveDates);
1586                    console.log(e);
1587                }
1588                $(".calendar-loading").hide();
1589            })
1590            .fail(function (jqxhr, textStatus, error) {
1591                var err = textStatus + ", " + error;
1592                console.log("Request Failed: " + err);
1593                $(".calendar-loading").hide();
1594            });
1595    }
1596}
1597swDatepicker.prototype.getCalendarDetails = function(){
1598    var thisCalendar = this;
1599    this.clearHighlightDays();
1600    $("#" + this.calendarName).removeClass("has-muted-days");
1601    $.getJSON("/include/widgets/calendar/calendarRequests.asp",
1602        {
1603            action: thisCalendar.type,
1604            calMonth: thisCalendar.activeMonth,
1605            iEvent: thisCalendar.eventID,
1606            iBundle: thisCalendar.bundleID,
1607            iCategory : thisCalendar.categoryID,
1608            cp : thisCalendar.corporatePartnerPage,
1609            bValidCoupon : thisCalendar.bValidCoupon,
1610            couponCode : thisCalendar.couponCode
1611        })
1612        .done(function (data) {
1613            //to save on request time, we need to resolve the data on the client a bit before we store it
1614            var performanceDates = [];
1615            data.performanceDateData.forEach(function(dd){
1616                
1617                if(dd.DoNotShowPublic == 0){
1618                    var detailsObj = {};
1619                    var currentDateIndex = fetchDateIndex(dd.CalendarDate, performanceDates);
1620                    if(currentDateIndex == -1){
1621                        detailsObj.date = dd.CalendarDate;
1622                        detailsObj.performances = [];
1623                        detailsObj.performances.push(dd.PerformanceCode);
1624                        detailsObj.defaultPrice = dd.LowestDefaultPrice;
1625                        detailsObj.PerformanceName = dd.PerformanceName;
1626                        detailsObj.PerformanceTime = dd.PerfTime;
1627                        detailsObj.PerformanceStartTimeAlias = dd.PerformanceStartTimeAlias;
1628                        detailsObj.DisplayType = dd.DisplayType;
1629                        detailsObj.CalendarViewShowPrice = dd.CalendarViewShowPrice;
1630                        detailsObj.CalendarViewShowPerformanceName = dd.CalendarViewShowPerformanceName;
1631                        detailsObj.CalendarViewShowPerformanceTime = dd.CalendarViewShowPerformanceTime;
1632                        detailsObj.CalendarViewShowBuyButton = dd.CalendarViewShowBuyButton;
1633                        detailsObj.defaultPricingCode = dd.LowestDefaultPricingCode;
1634                        detailsObj.secondaryPrice = dd.LowestSecondaryPrice;
1635                        detailsObj.secondaryPricingCode =dd.LowestSecondaryPricingCode;
1636                        detailsObj.NoCouponAvailable = dd.NoCouponAvailable;
1637                        detailsObj.passwordMatch = dd.passwordMatch;
1638                        detailsObj.qualifierPasswordMatch = dd.qualifierPasswordMatch;
1639                        detailsObj.hasPassword = dd.hasPassword;
1640                        detailsObj.hasQualifierPassword = dd.hasQualifierPassword;
1641                        detailsObj.hasCoupons = dd.hasCoupons; 
1642                        detailsObj.IsSalesPeriodEnded = dd.IsSalesPeriodEnded;
1643                        detailsObj.SaleIcon = dd.SaleIcon;
1644                        detailsObj.BSaleIcon = dd.BSaleIcon;
1645                        
1646                        detailsObj.hasQualifiers = dd.hasQualifiers;
1647                        performanceDates.push(detailsObj)
1648                       
1649                    }else{
1650                        performanceDates[currentDateIndex].performances.push(dd.PerformanceCode);
1651                        performanceDates[currentDateIndex].NoCouponAvailable = dd.NoCouponAvailable;
1652                        performanceDates[currentDateIndex].passwordMatch = dd.passwordMatch;
1653                        performanceDates[currentDateIndex].acMatch = dd.acMatch;
1654                        performanceDates[currentDateIndex].qualifierPasswordMatch = dd.qualifierPasswordMatch;
1655                        performanceDates[currentDateIndex].hasPassword = dd.hasPassword;
1656                        performanceDates[currentDateIndex].hasQualifierPassword = dd.hasQualifierPassword;
1657                        performanceDates[currentDateIndex].hasCoupons = dd.hasCoupons;
1658                        performanceDates[currentDateIndex].PerformanceName = dd.PerformanceName;
1659                        performanceDates[currentDateIndex].PerformanceTime = dd.PerfTime;
1660                        performanceDates[currentDateIndex].PerformanceStartTimeAlias = dd.PerformanceStartTimeAlias;
1661                        performanceDates[currentDateIndex].CalendarViewShowPrice = dd.CalendarViewShowPrice;
1662                        performanceDates[currentDateIndex].CalendarViewShowPerformanceName = dd.CalendarViewShowPerformanceName;
1663                        performanceDates[currentDateIndex].CalendarViewShowPerformanceTime = dd.CalendarViewShowPerformanceTime;
1664                        performanceDates[currentDateIndex].CalendarViewShowBuyButton = dd.CalendarViewShowBuyButton;
1665                        performanceDates[currentDateIndex].IsSalesPeriodEnded = dd.IsSalesPeriodEnded;
1666                        performanceDates[currentDateIndex].SaleIcon = dd.SaleIcon;
1667                        performanceDates[currentDateIndex].BSaleIcon = dd.BSaleIcon;                        
1668                        performanceDates[currentDateIndex].hasQualifiers = dd.hasQualifiers;
1669                        //check for lowest price
1670                        if(performanceDates[currentDateIndex].defaultPrice > dd.LowestDefaultPrice && dd.LowestDefaultPrice != null){
1671                            performanceDates[currentDateIndex].defaultPrice = dd.LowestDefaultPrice;
1672                            performanceDates[currentDateIndex].defaultPricingCode = dd.LowestDefaultPricingCode;
1673                        }
1674                        if(performanceDates[currentDateIndex].hasCoupons == 1 && performanceDates[currentDateIndex].defaultPrice < dd.LowestDefaultPrice && dd.LowestDefaultPrice != null && false){
1675                            performanceDates[currentDateIndex].defaultPrice = dd.LowestDefaultPrice;
1676                            performanceDates[currentDateIndex].defaultPricingCode = dd.LowestDefaultPricingCode;
1677                        }
1678                        if(performanceDates[currentDateIndex].secondaryPrice > dd.LowestSecondaryPrice && dd.LowestSecondaryPrice != null){
1679                            performanceDates[currentDateIndex].secondaryPrice = dd.LowestSecondaryPrice;
1680                            performanceDates[currentDateIndex].secondaryPricingCode = dd.LowestSecondaryPricingCode;
1681                        }
1682                         
1683                        
1684                    }
1685                    //set limited availaibility by matching up results from query with performances
1686                    for(perf in data.performances){
1687                        if(data.performances[perf].id == dd.PerformanceID){
1688                            data.performances[perf].LimitedAvailability = dd.LimitedAvailability;
1689                            data.performances[perf].TimeZone = dd.TimeZone.replace('"', "");
1690                            data.performances[perf].SingleAreaVenueAreaID = dd.SingleAreaVenueAreaID;
1691                            data.performances[perf].NoCouponAvailable = dd.NoCouponAvailable;
1692                            data.performances[perf].passwordMatch = dd.passwordMatch;
1693                            data.performances[perf].acMatch = dd.acMatch;
1694                            data.performances[perf].qualifierPasswordMatch = dd.qualifierPasswordMatch;
1695                            data.performances[perf].hasPassword = dd.hasPassword;
1696                            data.performances[perf].hasQualifierPassword = dd.hasQualifierPassword;
1697                        }
1698                    }
1699                }
1700                
1701            })
1702            
1703            data.performanceDates = performanceDates;
1704            delete data.performanceDateData;
1705            try {
1706                if (thisCalendar.couponCode != "" && $("#couponCode").length > 0)
1707                {
1708                    if($("#coupon-notify").length > 0)
1709                        $("#coupon-notify").remove();
1710
1711                    var notifyMessage = document.createElement("div");
1712                    notifyMessage.setAttribute("id","coupon-notify");
1713                    notifyMessage.setAttribute("class",data.hasValidCoupon ? 'coupon-notify-message' : 'coupon-error-message');
1714                    notifyMessage.innerHTML = (data.hasValidCoupon ? "Code <b>" + thisCalendar.couponCode + "</b> has been applied to valid dates and times." : "The code entered is either invalid, or no longer available.");
1715                    $("#plCalendar").prepend(notifyMessage);
1716                    window.scrollTo(0,0);
1717                }                
1718                
1719                thisCalendar.doCalendarDetailed(data);
1720            } catch (e) {
1721                console.log("Failed to parse details. Date object not valid: ", data);
1722                console.log(e);
1723            }
1724        })
1725        .fail(function (jqxhr, textStatus, error) {
1726            var err = textStatus + ", " + error;
1727            console.log("Request Failed: " + err);
1728        });
1729}
1730swDatepicker.prototype.doCalendarDetailed = function(detailData){
1731    var thisCalendar = this;
1732    this.detailData = detailData;
1733    var defaultPricingLegend = [], secondaryPricingLegend = [];
1734    detailData.performanceDates.forEach(function(d){
1735        thisCalendar.addHighlightDay(d.date);
1736        if (d.NoCouponAvailable > 0)
1737            thisCalendar.setCouponMutedDay(d.date);
1738        
1739        //check if date sold out
1740        var dateSoldOut = true;
1741        var customStatus = false;
1742        var showPhoneNumber =false;
1743        var dateLimitedAvailability = false;
1744        var performanceStatus="";
1745        var performanceOnSale = false;
1746        var IsSalesPeriodEnded = false;
1747        var aggregatedMentaInfo = {
1748            buttonVisible: false,
1749            buttonText: "",
1750            buttonUrl: "",
1751            totalCount: 0
1752        };
1753
1754        var isMentaResaleAvailable = false;
1755        var performanceTimesLength = 0;
1756        var QualiferButton = false;
1757        d.performances.forEach(function(datePerformance){
1758            var performanceKey = String(datePerformance).toLowerCase();
1759            var currentPerformance = detailData.performances[performanceKey];
1760
1761            if (!currentPerformance) {
1762                var perfIndex = d.performances.indexOf(datePerformance);
1763                if (perfIndex !== -1) {
1764                    d.performances.splice(perfIndex, 1);
1765                }
1766                console.log("Date Trimmed, child performance not contained in performance data: " + datePerformance);
1767                return;
1768            }
1769
1770            //let currentPerformance = detailData.performances[String(datePerformance).toLowerCase()];
1771            performanceTimesLength ++;
1772
1773            if(detailData.performances[String(datePerformance).toLowerCase()] && detailData.performances[String(datePerformance).toLowerCase()].status == "On Sale"){
1774                dateSoldOut = false;
1775                performanceOnSale=true;
1776                if(currentPerformance.LimitedAvailability == 1)
1777                    dateLimitedAvailability = true;
1778                        
1779                IsSalesPeriodEnded  =   currentPerformance.IsSalesPeriodEnded==1        
1780            }            
1781            else{
1782                
1783                if ((currentPerformance.status != "Sold Out") && (currentPerformance.status != "On Sale")  ){
1784                    
1785                    customStatus=true;
1786                    performanceStatus=currentPerformance.status;
1787                    dateSoldOut = false;
1788                    //dateLimitedAvailability=false;
1789                    if ( currentPerformance.bSalePhone==1 || currentPerformance.SalePhone==1){
1790                        showPhoneNumber=true;
1791                    }
1792                }
1793                var mentaMarketplace = currentPerformance.MentaMarketplace;
1794                var hasMentaOption = currentPerformance.IsMentaEnabled == 1 && mentaMarketplace && mentaMarketplace.buttonVisible;
1795
1796                if (hasMentaOption) {
1797                    var availableCount = parseInt(mentaMarketplace.totalCount, 10);
1798                    if (!isNaN(availableCount) && availableCount > 0) {
1799                        aggregatedMentaInfo.totalCount += availableCount;
1800                    }
1801                    if (mentaMarketplace.buttonText && aggregatedMentaInfo.buttonText === "") {
1802                        aggregatedMentaInfo.buttonText = mentaMarketplace.buttonText;
1803                    }
1804                    if (mentaMarketplace.buttonUrl && aggregatedMentaInfo.buttonUrl === "") {
1805                        aggregatedMentaInfo.buttonUrl = mentaMarketplace.buttonUrl;
1806                    }
1807                    aggregatedMentaInfo.buttonVisible = true;
1808                    dateSoldOut = false;
1809                    showPhoneNumber=false;
1810                    customStatus=true;
1811                }
1812            }
1813           
1814            // If date is sold out or custom status (not 'on sale'), check if qualifier access code or password match
1815            if (dateSoldOut || customStatus) {
1816                if (currentPerformance.acMatch == 1 || (currentPerformance.qualifierPasswordMatch == 1 && currentPerformance.hasQualifierPassword == 1)) {
1817                    dateSoldOut = false;
1818                    customStatus = false;
1819                    performanceOnSale = true;
1820                    showPhoneNumber = false;
1821                }
1822            }
1823            // If date is sold out or custom status (not 'on sale'), check if it has a public qualifier -- hasQualifiers is set on CalendarRequests.asp when qualifiers exist for performance
1824            if (currentPerformance.hasQualifiers) {
1825                    dateSoldOut = false;
1826                    customStatus = false;
1827                    performanceOnSale = true;
1828                    showPhoneNumber = false;
1829                    QualiferButton = true;
1830                  // If performance has qualifier but status is "On Sale", do not show "Premium Access" text on calendar date
1831                  if (currentPerformance.status == "On Sale") {
1832                    QualiferButton = false;
1833                 } 
1834                 
1835            }
1836        })
1837
1838        if (aggregatedMentaInfo.buttonVisible && aggregatedMentaInfo.buttonText === "") {
1839            aggregatedMentaInfo.buttonText = "Official Resale Available";
1840        }
1841        var hasMentaCtaForDate = aggregatedMentaInfo.buttonVisible && (aggregatedMentaInfo.totalCount > 0 || aggregatedMentaInfo.buttonUrl !== "");
1842        isMentaResaleAvailable = hasMentaCtaForDate && !performanceOnSale;
1843        d.MentaMarketplace = aggregatedMentaInfo;
1844        
1845        if(dateLimitedAvailability && !dateSoldOut){
1846            thisCalendar.setDayLimitedAvailabilty(d.date);
1847        }
1848        if (thisCalendar.isMultiplePerformanceIndicator == 1 && performanceTimesLength > 1) {
1849            thisCalendar.setMultiplePerformanceTimes(d.date);
1850        }
1851        if ( IsSalesPeriodEnded) {
1852            performanceStatus=d.SaleIcon;
1853        }
1854        else{
1855            if(isMentaResaleAvailable && !performanceOnSale){                
1856               
1857                thisCalendar.addDateSubNote(d.date, 'Sold Out');
1858                //thisCalendar.setDaySoldOut(d.date);
1859                //thisCalendar.addDateInfoBox(d.date, "Sold Out");
1860                 thisCalendar.configureMentaSettings(d);            
1861            }
1862            else{ 
1863              performanceStatus=d.BSaleIcon;
1864            }
1865        
1866        }
1867
1868        if (performanceStatus == null || performanceStatus == "")
1869            performanceStatus="sold out";
1870
1871        if(dateSoldOut){
1872            thisCalendar.setDaySoldOut(d.date);
1873        }else{
1874            if ( (customStatus && !dateLimitedAvailability && !performanceOnSale && !isMentaResaleAvailable) || IsSalesPeriodEnded)
1875            {
1876                thisCalendar.setcustomStatus(d.date,showPhoneNumber,performanceStatus)
1877            }
1878            else{
1879            //date not sold out, add details, add to legend if one exists
1880            var detailString = "";
1881
1882            // if the price option is checked in event landing page in the admin 
1883             if(d.CalendarViewShowPrice != 0){
1884                //for now, we'll just add the pricing, this would be a spot to modify what is displayed on the dates by changing the contents of this string
1885                if(d.defaultPrice != null){
1886                    if (QualiferButton) { // SHOWDEV-22142 - If date has public qualifier, show qualifier text (Premium Access) instead of price and buy button
1887                        detailString = detailString + "<span class='display-perfbuybutton'>Premium Access</span>";
1888                    }else {
1889                           
1890                            detailString = "<span class='display-perfprice'>" + thisCalendar.currencySymbol + d.defaultPrice.toFixed(2).replace('.00','') + "</span>";
1891                        
1892                    }
1893                    
1894                if(defaultPricingLegend.indexOf(d.defaultPricingCode) === -1)
1895                    defaultPricingLegend.push(d.defaultPricingCode);
1896                }
1897                if(d.secondaryPricingCode != "" && d.secondaryPricingCode != null){
1898                    if(secondaryPricingLegend.indexOf(d.secondaryPricingCode) === -1)
1899                        secondaryPricingLegend.push(d.secondaryPricingCode);           
1900                    
1901                    if (d.DisplayType === "calendar" || d.DisplayType === "streamlined") {
1902                           
1903                        detailString = "<span class='display-perfprice-withchild'>" + thisCalendar.currencySymbol + d.secondaryPrice.toFixed(2).replace('.00','') + "/</span>" + detailString;
1904                        
1905                    }
1906                }
1907            }
1908            if(d.CalendarViewShowPerformanceName != 0){
1909                detailString =  detailString + "<span class='display-perfname'>" + d.PerformanceName + "</span> ";
1910            }
1911           
1912            if(d.CalendarViewShowPerformanceTime != 0){
1913                if(d.PerformanceStartTimeAlias != ""){ // Performance Alias time is present
1914                    detailString = detailString + " <span class='display-perft
1914ime'>" + d.PerformanceStartTimeAlias + "</span>";
1915                } else {
1916                    detailString = detailString + " <span class='display-perftime'>" + d.PerformanceTime + "</span>";
1917                }
1918                
1919            }
1920            if(d.CalendarViewShowBuyButton != 0){
1921                var styleString = "";
1922                if (d.DisplayType === "streamlined")
1923                    styleString = " style='width: 100%;'";
1924                var buttonText = (isMentaResaleAvailable && d.OverrideBuyTicketsButtonText) ? d.OverrideBuyTicketsButtonText : thisCalendar.buyTicketsButtonText;
1925                detailString = detailString + "<span class='button display-perfbuybutton'"+styleString+">" + buttonText + "</span>";
1926            }
1927
1928            thisCalendar.addDateInfoBox(d.date, detailString);
1929            }
1930        }
1931        
1932    })
1933    //for now, we only generate the legend if there are one or two prices pesent
1934    if(defaultPricingLegend.length === 1 && secondaryPricingLegend.length === 1){
1935        $("#calendarLegend").html(secondaryPricingLegend[0] +" / " + defaultPricingLegend[0])
1936        
1937        $("#calendarLegend").show();
1938    }else{
1939        if(defaultPricingLegend.length === 1){
1940                $("#calendarLegend").html(defaultPricingLegend[0])
1941                
1942                $("#calendarLegend").show();
1943        }else{
1944            $("#calendarLegend").hide();
1945        }
1946    }
1947    if(typeof(setFilterOptions) == 'function'){
1948        setFilterOptions(thisCalendar);
1949    }
1950    if (detailData.hasValidCoupon) {
1951        $("#plCalendar").append("<input type='hidden' id='hasValidCoupon' value='1' />");
1952    } else {
1953        $("#plCalendar").append("<input type='hidden' id='hasValidCoupon' value='0' />");
1954    }
1955    $(".calendar-loading").hide();
1956}
1957swDatepicker.prototype.configureMentaSettings = function (dateDetail) {
1958    // Set Menta Resale Settings
1959    
1960}
1961
1962swDatepicker.prototype.getFirstDate = function(defaultMonth){
1963    var thisCalendar = this;
1964    //this should only happen once on calendar load - currently only enabled for bundles
1965    if(thisCalendar.bundleID == 0 || thisCalendar.bundleID == -1)
1966        return defaultMonth; //currently only developed for bundles TODO: add event, category, standard support.
1967
1968    $.getJSON("/include/widgets/calendar/calendarRequests.asp",
1969            {
1970                action: 'initialBundleDate',
1971                iBundle: thisCalendar.bundleID,
1972                cp : thisCalendar.corporatePartnerPage
1973            })
1974            .done(function (data) {
1975                try {
1976                    if (data.performancedates.length > 0) {
1977                        
1978    
1979                        var firstMonth = Number(String(data.performancedates).split("/")[0]) - 1;
1980                        var firstYear = Number(String(data.performancedates).split("/")[2]);
1981                        thisCalendar.month = firstMonth - 1; //to make this simple, we're using the showNextMonth() function, which means we need to set the month to 1 less than our target, as that function increments the month itself
1982                        thisCalendar.year = firstYear;
1983                        thisCalendar.showNextMonth();
1984                    }else{
1985                        return defaultMonth;
1986                    }
1987                }catch(e){
1988                    console.log("getFirstDate returned invalid date. Default used");
1989                    console.log(e);
1990                    return defaultMonth;
1991                }
1992            })
1993            .fail(function (jqxhr, textStatus, error) {
1994                var err = textStatus + ", " + error;
1995                console.log("Request Failed: " + err);
1996            });
1997}
1998swDatepicker.prototype.fetchLocalDates = function () {
1999    //utliize storage to store months
2000    var CalendarExpireTime = new Date().getTime(); var isExpired = false; var datesData = "";
2001    var calendarIDString = this.calendarName + this.type + this.eventID + this.bundleID + "-" + this.corporatePartnerPage + "_" + this.activeMonth;
2002    try {
2003        //check for local storage support
2004        isExpired = CalendarExpireTime > Number(localStorage.getItem("CalendarExpireTime_" + calendarIDString));
2005        if (isExpired) {
2006            //item expired, clear local results
2007            localStorage.setItem("ShowareDates_" + calendarIDString, "");
2008            localStorage.setItem("CalendarExpireTime_" + calendarIDString, CalendarExpireTime + (1000 * 60 * 30));  //item information expires after 30 minutes
2009            return false;
2010        }
2011        localStorage.setItem("CalendarExpireTime_" + calendarIDString, CalendarExpireTime + (1000 * 60 * 30));  //item information expires after 30 minutes
2012        if (localStorage.getItem("ShowareDates_" + calendarIDString) != null && localStorage.getItem("ShowareDates_" + calendarIDString) != "" && localStorage.getItem("ShowareDates_" + calendarIDString) != []) {
2013            return localStorage.getItem("ShowareDates_" + calendarIDString);
2014        } else {
2015            //date info not stored
2016            return false;
2017        }
2018    } catch (e) {
2019        return false;
2020    }
2021}
2022swDatepicker.prototype.storeDates = function (dateData) {
2023    
2024    var calendarIDString = this.calendarName + this.type + this.eventID + this.bundleID + "-" + this.corporatePartnerPage + "_" + this.activeMonth;
2025    try {
2026        localStorage.setItem("ShowareDates_" + calendarIDString, JSON.stringify(dateData));
2027    } catch (e) {
2028        //no local storage
2029    }
2030}
2031swDatepicker.prototype.getDateRangeEvents = function (dateRangeData) {
2032    var thisCalendar = this;
2033    try{
2034        $.getJSON("/include/widgets/calendar/calendarRequests.asp",
2035            {
2036                action: 'getDateRangeEvents',
2037                dateRange: JSON.stringify(dateRangeData),
2038            })
2039            .done(function (data) {
2040                try {
2041                    thisCalendar.dateRangeEvents = data;
2042                }catch(e){
2043                    console.log("getDateRangeEvents returned invali
2043d response.");
2044                    console.log(data, e);
2045                    return []//return empty array;
2046                }
2047            })
2048            .fail(function (jqxhr, textStatus, error) {
2049                var err = textStatus + ", " + error;
2050                console.log("Request Failed: " + err);
2051            });
2052
2053    }catch(e){
2054        console.log("Unable to fetch date range events:", e)
2055    }
2056}
2057swDatepicker.prototype.clearDateRange = function () {
2058    this.fromDateRange = '';
2059    this.toDateRange = '';
2060}
2061function fetchDateIndex(dateString, dateObjectArray){
2062    try{
2063        for(var i = 0;i < dateObjectArray.length;i++){
2064            if(dateObjectArray[i].date == dateString){
2065                return i;
2066                break;
2067            }
2068        }
2069        return -1;
2070    }catch(e){
2071        //this function requires specific objects with a date property, it will fail otherwise and we'll just return what one would expect from a failed indexof
2072        return -1;
2073    }
2074}
2075function swapMonthDay(d){
2076    //expects dd/mm/yyyy format
2077    try{
2078        let splitDate = d.split("/");
2079        let newDate = splitDate[1] + '/' + splitDate[0] + "/" + splitDate[2];
2080        return newDate;
2081    }catch(e){
2082        console.log("could not swap date:",d,e);
2083        return d;
2084    }
2085}
2086
2087</script>
2087
2088        
2088<script type="text/javascript">
2089            if (typeof localStorage === 'object') {
2090                try {
2091                    localStorage.setItem('localStorage', 1);
2092                    localStorage.removeItem('localStorage');
2093                } catch (e) {
2094                    Storage.prototype._setItem = Storage.prototype.setItem;
2095                    Storage.prototype.setItem = function () { };
2096                    console.log("local storage not availalbe, data tracking limited");
2097                }
2098            }
2099            function persistDataLayer(layerName, pageVal) {
2100                var ShoWareExpTime = new Date().getTime(); var isExpired = false;
2101
2102                try {
2103                    isExpired = ShoWareExpTime > Number(localStorage.getItem("swExpTime"));
2104                    if (isExpired) {
2105                        removeDataLayer();
2106                    }
2107                    localStorage.setItem("swExpTime", ShoWareExpTime + 1000 * 60 * 30);  //tag information expires after 30 minutes of inactivity
2108
2109                    //grab anything we might have in storage=
2110                    var existVal = localStorage.getItem(layerName);
2111                    if (pageVal != "") {
2112                        //page val trumps all, store it and send it back
2113                        localStorage.setItem(layerName, pageVal);
2114                        return pageVal;
2115                    } else {
2116                        //page val was empty, so we'll try to pull a value out of local storage
2117                        if (existVal != "" && existVal != null && existVal != undefined && !isExpired) {
2118                            return existVal;
2119                        } else {
2120                            //no value exists, or the values stored have expired;
2121                            return "";
2122                        }
2123                    }
2124                } catch(e) {
2125                    //no local storage, or other error, we'll just return the page value. Calls to this function should assume the possibility of failure as local storage does not work on IOS devices with private browsing enabled.
2126                    return pageVal;
2127                }
2128            }
2129            function addDataLayer(layerName, setVal) {
2130                try {
2131                    //the data layer MUST be set up before the container is introduced.
2132                    //We will rely on future loads to address these variables as they are added after the pageload.
2133                    localStorage.setItem(layerName, setVal);
2134                    //push data to dataLayer so we can retrieve it with non-load events (clicks, changes, etc...)
2135                    dataLayer.push({[layerName]: setVal});
2136                }
2137                catch (e) {
2138                    //local storage failed, or the data layer was not available.
2139                }
2140            }
2141            function removeDataLayer() {
2142                //empty showare data layer from local storage.
2143                for (var i = localStorage.length - 1; i >= 0; i--) {
2144                    layerName = localStorage.key(i);
2145                    if (layerName.indexOf("Ticketing") > -1) {
2146                        localStorage.removeItem(layerName);
2147                    }
2148                }
2149            }
2150            function tryParse(jsonString) {
2151                if (jsonString == "" || jsonString == null || jsonString == undefined) {
2152                    return '';
2153                }
2154                try {
2155                    JSON.parse(jsonString);
2156                } catch (e) {
2157                    console.log(e);
2158                    return '';
2159                }
2160                return JSON.parse(jsonString);
2161            }
2162        </script>
2162
2163
2164        
2164<script>
2165            window.dataLayer = window.dataLayer || [];
2166            dataLayer.push({
2167                'TicketingHasActivePerformances': 'True',
2168                'TicketingPage': 'basket.asp',
2169                'TicketingEventID': persistDataLayer("TicketingEventID", ""),
2170                'TicketingBundleID': persistDataLayer("TicketingBundleID", ""),
2171                'TicketingPerformanceID': persistDataLayer("TicketingPerformanceID", ""),
2172                'TicketingPerformanceCode': persistDataLayer("TicketingPerformanceCode", ""),
2173                'TicketingPerformanceDate': persistDataLayer("TicketingPerformanceDate", ""),
2174                'TicketingOrderID': persistDataLayer("TicketingOrderID", "0"),
2175                'TicketingNewCustomer': persistDataLayer("TicketingNewCustomer", ""),
2176                'TicketingCustomerID': "",
2177                'TicketingCustomerZipCode': persistDataLayer("TicketingCustomerZipCode", ""),
2178                'TicketingCustomerState': persistDataLayer("TicketingCustomerState", ""),
2179                'TicketingCustomerCountry': persistDataLayer("TicketingCustomerCountry", ""),
2180                'TicketingCustomerCity': persistDataLayer("TicketingCustomerCity", ""),
2181                'TicketingCurrencyCode': persistDataLayer("TicketingCurrencyCode", "USD"),
2182                'TicketingOrderTotal': persistDataLayer("TicketingOrderTotal", ""),
2183                'TicketingCoupon': persistDataLayer("TicketingCoupon", ""),
2184                'TicketingPromo': persistDataLayer("TicketingPromo", ""),
2185                'TicketingDiscountAmount': persistDataLayer("TicketingDiscountAmount", ""), //promo code dicount value only
2186                'TicketingHasMixedBasket': persistDataLayer("TicketingHasMixedBasket", ""),
2187                'TicketingOrderSubTotal': persistDataLayer("TicketingOrderSubTotal", ""),
2188                'TicketingItemCount': persistDataLayer("TicketingItemCount", ""),
2189                'TicketingBundleCount': persistDataLayer("TicketingBundleCount", ""),
2190                'TicketingShippingMethod': persistDataLayer("TicketingShippingMethod", ""),
2191                'TicketingIsWillCall': persistDataLayer("TicketingIsWillCall", ""),
2192                'TicketingHeardAbout': persistDataLayer("TicketingHeardAbout", ""),
2193                'TicketingShippingTotal': persistDataLayer("TicketingShippingTotal", ""),
2194                'TicketingTaxTotal': persistDataLayer("TicketingTaxTotal", ""),
2195                'TicketingFeesTotal': persistDataLayer("TicketingFeesTotal", ""),
2196                'TicketingProcessingFee': persistDataLayer("TicketingProcessingFee", ""),
2197                'TicketingTicketFeesTotal': persistDataLayer("TicketingTicketFeesTotal", ""),
2198                'TicketingTicketItems': persistDataLayer("TicketingTicketItems", ""),
2199                'TicketingDonationItems': persistDataLayer("TicketingDonationItems", ""),
2200                'TicketingMembershipItems': persistDataLayer("TicketingMembershipItems", ""),
2201                'TicketingSalesChannel': persistDataLayer("TicketingSalesChannel", ""),
2202                'TicketingPaymentType': persistDataLayer("TicketingPaymentType", ""),
2203                'TicketingEventName': persistDataLayer("TicketingEventName", ""),
2204                'TicketingPerformanceName': persistDataLayer("TicketingPerformanceName", ""),
2205                'TicketingBundleName': persistDataLayer("TicketingBundleName", ""),
2206                'TicketingPromoterID': persistDataLayer("TicketingPromoterID", ""),
2207                'TicketingEventCategories': persistDataLayer("TicketingEventCategories", ""),
2208                'GAClientID': persistDataLayer("GAClientID", ""),
2209                'transactionId': 0,
2210                'transactionTotal': parseFloat(persistDataLayer("transactionTotal", "")),
2211                'transactionAffiliation' : 'CincyTicket',
2212                'transactionTax': parseFloat(persistDataLayer("transactionTax", "")),
2213                'transactionShipping': parseFloat(persistDataLayer("transactionShipping", "")),
2214                'transactionProducts': tryParse(persistDataLayer("transactionProducts", ""))
2215            });
2216            if(typeof(customDataLayerPush) === "function"){
2217                customDataLayerPush(); //custom function can be defined in local files and values pushed prior to GTM loading to simplify tag implimentation
2218            }
2219        </script>
2219
2220        
2221            <!-- CLIENT Google Tag Manager -->
2222            
2222<script>
vendor: 373 bytes, lines 2222-2226
2222(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
2223            new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
2224            j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
2225            '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
2226            })(window,document,'script','dataLayer','
2226GTM-WZ8HC5
vendor: 3 bytes, line 2226
2226');
2226</script>
2226
2227            <!-- End CLIENT Google Tag Manager -->
2228        
2229                <!-- PRIMARY Google Tag Manager -->
2230                
2230<script>
vendor: 389 bytes, lines 2230-2234
2230(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
2231                new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
2232                j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
2233                '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
2234                })(window,document,'script','dataLayer','
2234GTM-MDGF2K
vendor: 3 bytes, line 2234
2234');
2234</script>
2234
2235                <!-- End PRIMARY Google Tag Manager -->
2236        
2237
2238
2239    
2239<script type="text/javascript">
2240        var simpleCacheBuster = {
2241            beforeLength: 0,
2242            afterLength: 0
2243        };
2244
2245        simpleCacheBuster.beforeLength = document.cookie.length;
2246        simpleCacheBuster.afterLength = document.cookie.replace("ShowareVersion=newUI", " ").length;
2247
2248        // If length is the same, then we haven't set this version cookie before, clear the cache.
2249        // If after length is smaller, then we have replaced the same version, do nothing.
2250        // After length shouldn't be greater, do nothing.
2251        if (simpleCacheBuster.beforeLength == simpleCacheBuster.afterLength) {
2252            document.cookie = "ShowareVersion=newUI";
2253
2254            // This will force browser to reload all includes from server instead of cache.
2255            // Sadly, this doesn't work on Chrome due to a bug that they refuse to fix.
2256            // https://bugs.chromium.org/p/chromium/issues/detail?id=443462
2257            location.reload(true);
2258        }
2259    </script>
2259
2260
2261	
2261<script language="JavaScript">
2262	    $(document).ready(function () {
2263	        var sessionKey;
2264	        sessionKey = '';
2265	        //v1Session variable declared in jq.js 
2266	        v1Session.setSessionKey(sessionKey);
2267	    });
2268
2269	</script>
2269
2270    
2270<script type="text/javascript">
2271        /*
2272         * Replace all SVG images with inline SVG - allows for image modificcation via CSS
2273         */
2274        function extractIcons() {
2275            $('img.sw-icon').each(function () {
2276                var $img = $(this);
2277                var imgID = $img.attr('id');
2278                var imgClass = $img.attr('class');
2279                var imgURL = $img.attr('src');
2280
2281                $.get(imgURL, function (data) {
2282                    // Get the SVG tag, ignore the rest
2283                    var $svg = jQuery(data).find('svg');
2284
2285                    // Add replaced image's ID to the new SVG
2286                    if (typeof imgID !== 'undefined') {
2287                        $svg = $svg.attr('id', imgID);
2288                    }
2289                    // Add replaced image's classes to the new SVG
2290                    if (typeof imgClass !== 'undefined') {
2291                        $svg = $svg.attr('class', imgClass + ' replaced-svg');
2292                    }
2293                    // Remove any invalid XML tags as per http://validator.w3.org
2294                    $svg = $svg.removeAttr('xmlns:a');
2295                    // Replace image with new SVG
2296                    $img.replaceWith($svg);
2297                }, 'xml');
2298            });
2299        }
2300    </script>
2300
2301    
2301<script type="text/javascript">
2302        function getGAClientID() {
2303            try {
2304                return ga.getAll()[0].get('clientId');
2305            } catch (e) {
2306                return "0";
2307            }
2308        }
2309        function addGAClient(){
2310            var gaID = getGAClientID();
2311            if(gaID == "0"){
2312                //no analytics (unlikely), or analytics not loaded yet
2313                setTimeout(function(){addGAClient()}, 500);
2314            }else{
2315                try{
2316                    addDataLayer('GAClientID', gaID);
2317                }catch(e){
2318                    console.log("Failed to add data layer object: GAClientID:");
2319                    console.log(e);
2320                }
2321            }
2322        }
2323        addGAClient();
2324
2325    </script>
2325
2326
2327	
2328
2329    <!-- Comodo SSL Seal -->
2330    
2331        
2331<script type="text/javascript">
2332            //<![CDATA[ 
2333            var tlJsHost = ((window.location.protocol == "https:") ? "https://secure.comodo.com/" : "http://www.trustlogo.com/"); document.write(unescape("%3Cscript src='" + tlJsHost + "trustlogo/javascript/trustlogo.js' type='text/javascript'%3E%3C/script%3E"));
2334            //]]>
2335        </script>
2335
2336    
2337
2338<script type="text/javascript">
2339
2340    var swEnhancedEcommerce = {
2341        basketProducts: [],
2342        myImpressions: [],
2343        myProducts: [],
2344
2345        //Building Up items to pass to analytics
2346        addImpressions: function (name, id, price, category, list, position) {
2347            //adds a product impression to myImpressions - represents a user being presented a specific product
2348            if (price != '') { //price is optional
2349                this.myImpressions.push(
2350                    {
2351                        'name': name,       // Name or ID is required.
2352                        'id': id,
2353                        'price': price,
2354                        'category': category,
2355                        'list': list,
2356                        'position': position
2357                    }
2358                );
2359            } else {
2360                this.myImpressions.push(
2361                    {
2362                        'name': name,       // Name or ID is required.
2363                        'id': id,
2364                        'category': category,
2365                        'list': list,
2366                        'position': position
2367                    }
2368                );
2369            }
2370        },
2371
2372        addProducts: function (name, id, price, category, position) {
2373            //product clicks represent a product being selected. For showare currently this will always be a single product, but future use may require allowing users to select multiple products
2374            //this represents a click on a product, NOT adding a product to the basket
2375            if (price != '') { //price is optional
2376
2377                this.myProducts.push(
2378                    {
2379                        'name': name,       // Name or ID is required.
2380                        'id': id,
2381                        'price': price,
2382                        'category': category,
2383                        'position': position
2384                    }
2385                );
2386            } else {
2387                this.myProducts.push(
2388                    {
2389                        'name': name,       // Name or ID is required.
2390                        'id': id,
2391                        'category': category,
2392                        'position': position
2393                    }
2394                );
2395            }
2396        },
2397
2398        //object management functions
2399        clearImpressions: function(){
2400            this.myImpressions = [];
2401        },
2402        clearProducts: function () {
2403            this.myProducts = [];
2404        },
2405
2406        //Passing data to analytics
2407        sendImpressions: function(){
2408            window.dataLayer.push({
2409                'event': 'impressionsPushed',
2410                'ecommerce': {
2411                    'impressions': this.myImpressions
2412                }
2413            });
2414        },
2415        sendProducts: function (list) {
2416            //list should be a string of the originator of the product click, for instance a performance list, event list, callout, or other
2417            window.dataLayer.push({
2418                'event': 'productClick',
2419                'ecommerce': {
2420                    'click': {
2421                        'actionField': { 'list': list },      // Optional list property.
2422                        'products': this.myProducts
2423                    }
2424                }
2425            });
2426        },
2427        sendDetails: function (name, id, category) {
2428            //tracks a user's view of product details
2429            window.dataLayer.push({
2430                'event': 'detailView',
2431                'ecommerce': {
2432                    'detail': {
2433                        'products': [{
2434                            'name': name,         // Name or ID is required.
2435                            'id': id,
2436                            'category': category,
2437                        }]
2438                    }
2439                }
2440            });
2441        },
2442
2443        sendAddToBasket: function(){
2444            var newAddedProducts = this.compareBasketProducts(this.basketProducts);
2445            if (newAddedProducts.length === 0) {
2446                return;
2447            }
2448            console.log("added items to basket:", newAddedProducts);
2449            //REQUIRES basketProducts populated via fetchBasketProducts or directly
2450            window.dataLayer.push({
2451                'event': 'addToCart',
2452                'ecommerce': {
2453                    'add': {                                // 'add' actionFieldObject measures.
2454                        'products': newAddedProducts                          //  adding a product to a shopping cart.
2455                    }
2456                }
2457            });
2458        },
2459
2460        sendAddItemToBasket: function(name, id, price, category, quantity){
2461            //REQUIRES basketProducts populated via fetchBasketProducts or directly
2462            window.dataLayer.push({
2463                'event': 'addToCart',
2464                'ecommerce': {
2465                    'add': {                                // 'add' actionFieldObject measures.
2466                        'products': [{                          //  removing a product to a shopping cart.
2467                            'name': name,
2468                            'id': id,
2469                            'price': price,
2470                            'category': category,
2471                            'quantity': quantity
2472                        }]
2473                    }
2474                }
2475            });
2476        },
2477
2478        sendRemoveFromBasket: function (name, id, price, category, quantity, doUpdate) {
2479            //the item should be removed from the actual basket before this is called, as the basket is updated immediately
2480            window.dataLayer.push({
2481                'event': 'removeFromCart',
2482                'ecommerce': {
2483                    'remove': {                               // 'remove' actionFieldObject measures.
2484                        'products': [{                          //  removing a product to a shopping cart.
2485                            'name': name,
2486                            'id': id,
2487                            'price': price,
2488                            'category': category,
2489                            'quantity': quantity
2490                        }]
2491                    }
2492                }
2493            });
2494            if (doUpdate) {
2495                this.fetchBasketProducts();
2496            }
2497        },
2498
2499        sendRemoveAllFromBasket: function () {
2500            //the item should be removed from the actual basket before this is called, as the basket is updated immediately
2501            window.dataLayer.push({
2502                'event': 'removeFromCart',
2503                'ecommerce': {
2504                    'remove': {                               // 'remove' actionFieldObject measures.
2505                        'products': this.basketProducts
2506                    }
2507                }
2508            });
2509            this.basketProducts = [];
2510            localStorage.removeItem('swAddedBasketProducts');
2511        },
2512
2513        //method to fetch basket - we should only call this if we intend to send products to analytics
2514        fetchBasketProducts: function (type, orderID, doAddToCartAfter) {
2515            if (typeof type === 'undefined') type = 'basket'; //defaults to grabbing basket items
2516            if (typeof orderID === 'undefined') orderID = 0;
2517            doAddToCartAfter = doAddToCartAfter || false;
2518            var fetchURL = "include/modules/enhancedEcommerceBasket.asp?type=" + type + "&orderid=" + orderID;
2519
2520            try {
2521                $.ajax({
2522                    context: this,
2523                    url: fetchURL
2524                })
2525                .done(function (data) {
2526                    //note that we'll only have basket details if this method is called. Functions like sendAddToBasket, and sendPurchase will not function if this method has not completed.
2527                    try{
2528                        this.basketProducts = JSON.parse(data);
2529                    } catch (e) {
2530                        console.log(e);
2531                        this.basketProducts = [];
2532                    }
2533                    //try to update the data layer with the most current products
2534                    try{
2535                        addDataLayer("TicketingTicketItems",data);
2536                    } catch (e){
2537                        console.log(e);
2538                    }
2539                    if(doAddToCartAfter){
2540                        this.sendAddToBasket();
2541                    }
2542                });
2543                //grab the basket and store contents
2544            } catch (e) {
2545                console.log(e);
2546                return
2547            }
2548        },
2549
2550        sendOrder: function (orderID, orderTotal, taxFees, shippingFees, couponCodes, orderCode) {
2551            var fetchURL = "include/modules/enhancedEcommerceBasket.asp?type=order&orderid=" + orderID + "&orderCode=" + orderCode;
2552            orderProducts = [];
2553
2554            try {
2555                $.ajax({
2556                    context: this,
2557                    url: fetchURL
2558                })
2559                .done(function (data) {
2560                    //note that we'll only have basket details if this method is called. Functions like sendAddToBasket, and sendPurchase will not function if this method has not completed.
2561                    try {
2562                        orderProducts = JSON.parse(data);
2563                    } catch (e) {
2564                        console.log(e);
2565                        orderProducts = [];
2566                    }
2567                    dataLayer.push({
2568                        'event': 'purchaseMade',
2569                        'ecommerce': {
2570                            'purchase': {
2571                                'actionField': {
2572                                    'id': orderID,                         // Transaction ID. Required for purchases and refunds.
2573                                    'affiliation': 'Online Ticketing',
2574                                    'revenue': orderTotal,                     // Total transaction value (incl. tax and shipping)
2575                                    'tax': taxFees,
2576                                    'shipping': shippingFees,
2577                                    'coupon': couponCodes
2578                                },
2579                                'products': orderProducts
2580                            }
2581                        }
2582                    });
2583                });
2584                //grab the basket and store contents
2585            } catch (e) {
2586                console.log(e);
2587                return
2588            }
2589
2590            
2591        },
2592
2593        // -------------------------------------------- CHECKOUT STEPS --------------------------------------------
2594        // 1. Basket Page "Checkout" Clicked
2595        // 2. login/guest/create
2596        // 3. Streamlined - select shipping method
2597        // 4. Streamlined - enter payment information
2598        // 5. Streamlined - complete clicked
2599        // 6. view order
2600        sendCheckoutStep: function(stepID, option){
2601            dataLayer.push({
2602                'event': 'checkout',
2603                'ecommerce': {
2604                    'checkout': {
2605                        'actionField': { 'step': stepID, 'option': option },
2606                        'products': this.basketProducts
2607                    }
2608                }
2609            });
2610        },
2611        sendViewPromotion: function(promotionItems){
2612            //promotion items should be an array of promotion items
2613            dataLayer.push({
2614                'event': 'view_promotion',
2615                'ecommerce': {
2616                    'items': promotionItems
2617                }
2618            });
2619            console.log("sent promotions");
2620            console.log(promotionItems);
2621        },
2622        sendSelectPromotion: function(promotionItems){
2623            //promotion items should be an array of promotion items
2624            dataLayer.push({
2625                'event': 'select_promotion',
2626                'ecommerce': {
2627                    'items': promotionItems
2628                }
2629            });
2630            console.log("selected promotions");
2631            console.log(promotionItems);
2632        },
2633
2634        getStoredAddedBasketProducts: function () {
2635            if (typeof localStorage === 'undefined') {
2636                return [];
2637            }
2638            try {
2639                var storedRaw = localStorage.getItem('swAddedBasketProducts');
2640                if (!storedRaw) {
2641                    return [];
2642                }
2643                var parsed = JSON.parse(storedRaw);
2644                return Array.isArray(parsed) ? parsed : [];
2645            } catch (e) {
2646                console.log(e);
2647                return [];
2648            }
2649        },
2650        cloneBasketProduct: function (product) {
2651            if (!product || typeof product !== 'object') {
2652                return product;
2653            }
2654            var clone = {};
2655            for (var prop in product) {
2656                if (Object.prototype.hasOwnProperty.call(product, prop)) {
2657                    clone[prop] = product[prop];
2658                }
2659            }
2660            return clone;
2661        },
2662        cloneBasketProducts: function (source) {
2663            var cloned = [];
2664            if (!Array.isArray(source)) {
2665                return cloned;
2666            }
2667            for (var i = 0; i < source.length; i++) {
2668                cloned.push(this.cloneBasketProduct(source[i]));
2669            }
2670            return cloned;
2671        },
2672        buildBasketProductSignature: function (product) {
2673            if (!product || typeof product !== 'object') {
2674                return '';
2675            }
2676            var keys = Object.keys(product).sort();
2677            var normalized = {};
2678            for (var i = 0; i < keys.length; i++) {
2679                var key = keys[i];
2680                normalized[key] = product[key];
2681            }
2682            try {
2683                return JSON.stringify(normalized);
2684            } catch (e) {
2685                console.log(e);
2686                return '';
2687            }
2688        },
2689        persistAddedBasketProducts: function (products) {
2690            if (typeof localStorage === 'undefined') {
2691                return;
2692            }
2693            try {
2694                localStorage.setItem('swAddedBasketProducts', JSON.stringify(this.cloneBasketProducts(products)));
2695            } catch (e) {
2696                console.log(e);
2697            }
2698        },
2699        storeAddedBasketProducts: function(basketProducts) {
2700            this.compareBasketProducts(basketProducts);
2701        },
2702        compareBasketProducts: function(basketProducts, options){
2703            var opts = options || {};
2704            var products = Array.isArray(basketProducts) ? basketProducts : [];
2705            if (typeof localStorage === 'undefined') {
2706                return opts.returnCombined ? { unmatched: products, combined: this.cloneBasketProducts(products) } : products;
2707            }
2708
2709            var storedProducts = this.getStoredAddedBasketProducts();
2710            var storedCounts = {};
2711            for (var i = 0; i < storedProducts.length; i++) {
2712                var storedSignature = this.buildBasketProductSignature(storedProducts[i]);
2713                if (storedSignature) {
2714                    storedCounts[storedSignature] = (storedCounts[storedSignature] || 0) + 1;
2715                }
2716            }
2717
2718            var unmatchedProducts = [];
2719            var combinedProducts = this.cloneBasketProducts(storedProducts);
2720            var pendingCounts = {};
2721
2722            for (var j = 0; j < products.length; j++) {
2723                var product = products[j];
2724                var productSignature = this.buildBasketProductSignature(product);
2725
2726                if (!productSignature) {
2727                    unmatchedProducts.push(product);
2728                    combinedProducts.push(this.cloneBasketProduct(product));
2729                    continue;
2730                }
2731
2732                var alreadyTracked = pendingCounts[productSignature] || 0;
2733                var existingCount = storedCounts[productSignature] || 0;
2734
2735                if (alreadyTracked < existingCount) {
2736                    pendingCounts[productSignature] = alreadyTracked + 1;
2737                } else {
2738                    unmatchedProducts.push(product);
2739                    pendingCounts[productSignature] = alreadyTracked + 1;
2740                    combinedProducts.push(this.cloneBasketProduct(product));
2741                }
2742            }
2743
2744            if (opts.persist !== false) {
2745                this.persistAddedBasketProducts(combinedProducts);
2746            }
2747
2748            if (opts.returnCombined) {
2749                return { unmatched: unmatchedProducts, combined: combinedProducts };
2750            }
2751
2752            return unmatchedProducts;
2753        }
2754
2755
2756    }
2757</script>
2757 
2758<script type="text/javascript">
2759//---------------------------DATEPICKER---------------------------------
2760function buildDatepicker(options) {
2761    //Calling this function should be sufficient to create a calendar within a designated div, with and
2762    //EX: headerDP = buildDatepicker({"calendarID":"headerCalendar","linkedInputID":"headerCalendarInput","isModal":false,"forceDates":true, "defaultDate": "{{Output date from server Here}}"}); <~ would create a calendar object for the calendar presented at #headerCalendar, and link it to #headerCalendarInput
2763    //most calendar methods are specific to the document the calendar resides on, and should be handled via the onChange event for the linked input
2764    //Available Options:
2765    //  calendarID (required)       == string, ID of calendar div
2766    //  linkedInput (required)      == string, ID of input which will change when a date is selected
2767    //  isModal                     == boolean, if true, calendar will be hidden, and display when the designated input recieves focus. If false, the calendar will be present and display as an inline block at all times.
2768    //  forceDates                  == boolean, if true only highlighted dates will be clickable
2769    //  detailedCalendar            == boolean, if true data is pulled to determine pricing information, sold out days, limited availablility - requires eventID
2770    //  defaultDate                 == string, mm/dd/yyyy date that calendar should start on (this will only represent the month displayed at the begining)
2771    //  type                        == string: defaults to "performancedates", which will add all visible performances
2772    //  eventID                     == integer: defaults to -1 which means no event. Other values will filter by events with that ID, allowing for a search of performance dates for a specific event only
2773    //  isMultiplePerformanceIndicator == boolean: if true, shows indicator for dates with multiple performance times
2774    //
2775    //Methods:
2776    //  showDlg()/hideDlg()             : shows/hides modal calendars, no valid for non-modal calendars
2777    //  addHighlightDay(mm/dd/yyyy)     : adds a date (presented as a mm/dd/yyyy string) to the list of highlight dates for the calendar - REQUIRES HighlightDays() function call to visually represent this change on the calendar
2778    //  clearHihghlightDays()           : removes all stored highlight dates
2779    //  highlightDays()                 : adds highlight class to stored days, visually highlighting them ont he calendar.
2780    
2781    var myID = options.calendarID; //required
2782    var myLinkedInput = options.linkedInputID; //required
2783    var isModal = options.isModal || false;
2784    var showLoader = options.showLoader || false;
2785    var forceDates = options.forceDates || false;
2786    var myDefault = new Date();
2787    if (options.defaultDate) {
2788        try{
2789            
2790            myDefault = new Date(options.defaultDate);
2791        } catch (e) {
2792            console.log("date no valid for calendar: " + myID);
2793            console.log(e);
2794        }
2795    }
2796    var type = options.type || "performancedates";
2797    var eventID = options.eventID || -1;
2798    var detailedCalendar = options.detailedCalendar && eventID != -1 || false;
2799    var bundleID = options.bundleID || -1;
2800    var categoryID = options.CategoryID || -1;
2801    var corporatePartnerPage = options.corporatePartnerPage || 0;
2802    var bValidCoupon = options.bValidCoupon || 0;
2803    var couponCode = options.couponCode || "";
2804    var isMultiplePerformanceIndicator = options.isMultiplePerformanceIndicatorFlag || 0;
2805
2806    return new swDatepicker(myID, myLinkedInput, isModal, showLoader, forceDates, detailedCalendar, myDefault, type, eventID, bundleID, categoryID, corporatePartnerPage,bValidCoupon,couponCode,isMultiplePerformanceIndicator)
2807}
2808function swDatepicker(id, target, modal, loader, force, detailed, defaultDate, type, eventID, bundleID, categoryID, corporatePartnerPage,bValidCoupon,couponCode,isMultiplePerformanceIndicator) {
2809
2810    this.$id = $('#' + id); // element to attach widget to
2811    this.$monthObj = this.$id.find('.month');
2812    this.$prev = this.$id.find('.bn_prev');
2813    this.$next = this.$id.find('.bn_next');
2814    this.$grid = this.$id.find('.cal');
2815    this.$target = $('#' + target); // div or text box that will receive the selected date string and focus (if modal)
2816    this.bModal = modal; // true if datepicker should appear in a modal dialog box.
2817    this.showLoader = loader;
2818    this.forceDateSelection = force; //if true, will only allow users to click on highlighted dates - see addHighlightDay()
2819    this.detailedCalendar = detailed;
2820    this.active = !modal;
2821    this.type = type;
2822    this.eventID = eventID;
2823    this.bundleID = bundleID;
2824    this.categoryID = categoryID;
2825    this.corporatePartnerPage = corporatePartnerPage;
2826    this.fromDateRange = "";
2827    this.toDateRange = "";
2828    this.dateRangeEvents = [];
2829    this.calendarName = id;
2830
2831    this.monthNames = ['January', 'February', 'March', 'April', 'May', 'June',
2832    'July', 'August', 'September', 'October', 'November', 'December'];
2833
2834    this.dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
2835
2836    this.dateObj = new Date();
2837
2838    this.curYear = this.dateObj.getFullYear();
2839    this.year = defaultDate.getFullYear();
2840
2841    this.curMonth = this.dateObj.getMonth();
2842    this.month = defaultDate.getMonth();
2843    this.getFirstDate(defaultDate.getMonth()); //update the month to the first performance ASAP
2844
2845    this.curDate = this.dateObj.getDate();
2846    this.date = defaultDate.getDate();
2847    this.currentDate = (this.month == this.curMonth && this.year == this.curYear);
2848    this.activeMonth = (String(this.month + 1) + "/1/" + this.year);
2849
2850    this.keys = {
2851        tab: 9,
2852        enter: 13,
2853        esc: 27,
2854        space: 32,
2855        pageup: 33,
2856        pagedown: 34,
2857        end: 35,
2858        home: 36,
2859        left: 37,
2860        up: 38,
2861        right: 39,
2862        down: 40
2863    };
2864
2865    this.bValidCoupon = bValidCoupon;
2866    this.couponCode = couponCode;
2867    this.isMultiplePerformanceIndicator = isMultiplePerformanceIndicator;
2868
2869    this.highlightDates = [];    
2870
2871    // display the current month
2872    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
2873
2874    // populate the calendar grid
2875    this.popGrid();
2876
2877    // update the table's activedescdendant to point to the current day
2878    this.$grid.attr('aria-activedescendant', this.$grid.find('.today').attr('id'));
2879
2880    this.bindHandlers();
2881
2882    //show selected day
2883        $('#' + this.calendarName + '-day' + this.date).addClass('focus').attr('aria-selected', 'true');
2884
2885    // hide dialog if in modal mode
2886    if (this.bModal == true) {
2887        this.$id.attr('aria-hidden', 'true');
2888        //show/hide functionality may vary based on use, so should be handled after the datepicker is created.
2889        //if we're on mobile, disable keyboard for the input:
2890        if ($(window).width() < 1024) {
2891            this.$target.attr("readonly", "true");
2892        }
2893    }
2894
2895    this.currencySymbol = "$";
2896    this.buyTicketsButtonText = "Buy Tickets";
2897}
2898
2899//
2900// popGrid() is a member function to populate the datepicker grid with calendar days
2901// representing the current month
2902//
2903// @return N/A
2904//
2905swDatepicker.prototype.popGrid = function () {
2906    if(this.showLoader)
2907        $(".calendar-loading").show();
2908    var numDays = this.calcNumDays(this.year, this.month);
2909    var startWeekday = this.calcStartWeekday(this.year, this.month);
2910    //var lastMonth = this.month - 1;
2911    //var lastMonthYear = this.year;
2912    var weekday = 0;
2913    var curDay = 1;
2914    var rowCount = 1;
2915    var $tbody = this.$grid.find('tbody');
2916
2917    var currentDateDay = this.dateObj.getDate();
2918    var currentDateMonth = this.dateObj.getMonth();
2919    var currentDateYear = this.dateObj.getFullYear();
2920
2921    var gridCells = '\t<tr id="row1">\n';
2922
2923    // Keeping in case the client (Gaylord) pushes back on not having previous month's dates selectable
2924    // If the last month is -1, roll it over to December (11) and subtract 1 from the last month's year
2925    /*if (lastMonth < 0) {
2926        lastMonth = 11;
2927        lastMonthYear = lastMonthYear - 1;
2928    }
2929
2930    var lastMonthNumDays = this.calcNumDays(lastMonthYear, lastMonth);
2931    var lastMonthStartDay = lastMonthNumDays - (startWeekday - 1);*/
2932
2933    // clear the grid
2934    $tbody.empty();
2935    $('#msg').empty();
2936
2937    // Keeping in case the client (Gaylord) pushes back on not having previous month's dates selectable
2938    // Insert the leading empty cells
2939    /*for (var weekday = 0; weekday < startWeekday; weekday++) {
2940        gridCells += '\t\t<td id="' + this.calendarName + '-day' + lastMonthStartDay + '" class="day-cell muted last-month" headers="row' +
2941            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false" data-year="' + lastMonthYear + '"><span class="calendar-day notranslate" data-month="' + lastMonth + '">' + lastMonthStartDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
2942        //gridCells += '\t\t<td class="empty" data-month="' + lastMonth + '" data-year="' + lastMonthYear + '" data-day="' + lastMonthStartDay + '">&nbsp;</td>\n';
2943        lastMonthStartDay++;
2944    }*/
2945
2946    for (var weekday = 0; weekday < startWeekday; weekday++) {
2947        gridCells += '\t\t<td class="empty">&nbsp;</td>\n';
2948    }
2949
2950    // insert the days of the month.
2951    for (curDay = 1; curDay <= numDays; curDay++) {
2952
2953        if (curDay == this.curDate && this.currentDate == true) {
2954
2955            gridCells += '\t\t<td id="' + this.calendarName + '-day' + curDay + '" class="today day-cell" aria-label="row' +
2956            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false"><span class="calendar-day notranslate">' + curDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
2957        }
2958        else {
2959            var addMuted = "";
2960
2961            // Only mute dates in the past for the date range selector widget
2962            if (this.type == 'dateRangeSelect') {
2963                // If the year is in the past, or the year is the same but the month is in the past, or the month and year are the same but the day is in the past, mute the date
2964                if (this.year < currentDateYear
2965                    || (this.year == currentDateYear && this.month < currentDateMonth)
2966                    || (this.year == currentDateYear && this.month == currentDateMonth && curDay < currentDateDay)
2967                ) {
2968                    addMuted = " muted";
2969                }
2970            }
2971            
2972            gridCells += '\t\t<td id="' + this.calendarName + '-day' + curDay + '" class="day-cell' + addMuted + '" aria-label="row' +
2973            rowCount + ' ' + this.dayNames[weekday] + '" role="gridcell" aria-selected="false"><span class="calendar-day notranslate">' + curDay + '</span> <span class="calendar-dayoftheweek" style="display: none;">' + this.dayNames[weekday] +  '</span></td>';
2974        }
2975
2976
2977        if (weekday == 6 && curDay < numDays) {
2978            // This was the last day of the week, close it out
2979            // and begin a new one
2980            gridCells += '\t</tr>\n\t<tr id="row' + rowCount + '">\n';
2981            rowCount++;
2982            weekday = 0;
2983        }
2984        else {
2985            weekday++;
2986        }
2987    }
2988
2989    // Insert any trailing empty cells
2990    for (weekday; weekday < 7; weekday++) {
2991
2992        gridCells += '\t\t<td class="empty">&nbsp;</td>\n';
2993    }
2994
2995    gridCells += '\t</tr>';
2996
2997    $tbody.append(gridCells);
2998    if(this.detailedCalendar){
2999        this.getCalendarDetails();
3000    }else{
3001        this.fetchDates();
3002    }
3003    
3004}
3005
3006//
3007// calcNumDays() is a member function to calculate the number of days in a given month
3008//
3009// @return (integer) number of days
3010//
3011swDatepicker.prototype.calcNumDays = function (year, month) {
3012
3013    return 32 - new Date(year, month, 32).getDate();
3014}
3015
3016//
3017// calcstartWeekday() is a member function to calculate the day of the week the first day of a
3018// month lands on
3019//
3020// @return (integer) number representing the day of the week (0=Sunday....6=Saturday)
3021//
3022swDatepicker.prototype.calcStartWeekday = function (year, month) {
3023
3024    return new Date(year, month, 1).getDay();
3025
3026} // end calcStartWeekday()
3027
3028//
3029// showPrevMonth() is a member function to show the previous month
3030//
3031// @param (offset int) offset may be used to specify an offset for setting
3032//                      focus on a day the specified number of days from
3033//                      the end of the month.
3034// @return N/A
3035//
3036swDatepicker.prototype.showPrevMonth = function (offset) {
3037    // show the previous month
3038    if (this.month < 1) {
3039        this.month = 11;
3040        this.year--;
3041    }
3042    else {
3043        this.month--;
3044    }
3045
3046    if (this.month != this.curMonth || this.year != this.curYear) {
3047        this.currentDate = false;
3048    }
3049    else {
3050        this.currentDate = true;
3051    }
3052
3053    this.activeMonth = (String(this.month + 1) + "/1/" + this.year)
3054
3055    // populate the calendar grid
3056    this.popGrid();
3057
3058    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
3059
3060    // if offset was specified, set focus on the last day - specified offset
3061    if (offset != null) {
3062        var numDays = this.calcNumDays(this.year, this.month);
3063        var day = 'day' + (numDays - offset);
3064
3065        this.$grid.attr('aria-activedescendant', this.calendarName + '-' + day);
3066        $('#' + this.calendarName + '-' + day).addClass('focus').attr('aria-selected', 'true');
3067    }
3068
3069
3070} // end showPrevMonth()
3071
3072//
3073// showNextMonth() is a member function to show the next month
3074//
3075// @param (offset int) offset may be used to specify an offset for setting
3076//                      focus on a day the specified number of days from
3077//                      the beginning of the month.
3078// @return N/A
3079//
3080swDatepicker.prototype.showNextMonth = function (offset) {
3081
3082    // show the next month
3083    if (this.month == 11) {
3084        this.month = 0;
3085        this.year++;
3086    }
3087    else {
3088        this.month++;
3089    }
3090
3091    if (this.month != this.curMonth || this.year != this.curYear) {
3092        this.currentDate = false;
3093    }
3094    else {
3095        this.currentDate = true;
3096    }
3097
3098    this.activeMonth = (String(this.month + 1) + "/1/" + this.year)
3099
3100    // populate the calendar grid
3101    this.popGrid();
3102
3103    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
3104
3105    // if offset was specified, set focus on the first day + specified offset
3106    if (offset != null) {
3107        var day = 'day' + offset;
3108
3109        this.$grid.attr('aria-activedescendant', this.calendarName + '-' + day);
3110        $('#' + this.calendarName + '-' + day).addClass('focus').attr('aria-selected', 'true');
3111    }
3112
3113} // end showNextMonth()
3114
3115//
3116// showPrevYear() is a member function to show the previous year
3117//
3118// @return N/A
3119//
3120swDatepicker.prototype.showPrevYear = function () {
3121
3122    // decrement the year
3123    this.year--;
3124
3125    if (this.month != this.curMonth || this.year != this.curYear) {
3126        this.currentDate = false;
3127    }
3128    else {
3129        this.currentDate = true;
3130    }
3131
3132    // populate the calendar grid
3133    this.popGrid();
3134
3135    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
3136
3137} // end showPrevYear()
3138
3139//
3140// showNextYear() is a member function to show the next year
3141//
3142// @return N/A
3143//
3144swDatepicker.prototype.showNextYear = function () {
3145
3146    // increment the year
3147    this.year++;
3148
3149    if (this.month != this.curMonth || this.year != this.curYear) {
3150        this.currentDate = false;
3151    }
3152    else {
3153        this.currentDate = true;
3154    }
3155
3156    // populate the calendar grid
3157    this.popGrid();
3158
3159    this.$monthObj.html(this.monthNames[this.month] + ' ' + this.year);
3160
3161} // end showNextYear()
3162
3163//
3164// bindHandlers() is a member function to bind event handlers for the widget
3165//
3166// @return N/A
3167//
3168swDatepicker.prototype.bindHandlers = function () {
3169
3170    var thisObj = this;
3171
3172    ////////////////////// bind button handlers //////////////////////////////////
3173    this.$prev.click(function (e) {
3174        return thisObj.handlePrevClick(e);
3175    });
3176
3177    this.$next.click(function (e) {
3178        return thisObj.handleNextClick(e);
3179    });
3180
3181    this.$prev.keydown(function (e) {
3182        return thisObj.handlePrevKeyDown(e);
3183    });
3184
3185    this.$next.keydown(function (e) {
3186        return thisObj.handleNextKeyDown(e);
3187    });
3188
3189    ///////////// bind grid handlers //////////////
3190
3191    this.$grid.keydown(function (e) {
3192        return thisObj.handleGridKeyDown(e);
3193    });
3194
3195    this.$grid.keypress(function (e) {
3196        return thisObj.handleGridKeyPress(e);
3197    });
3198
3199    this.$grid.focus(function (e) {
3200        return thisObj.handleGridFocus(e);
3201    });
3202
3203    this.$grid.blur(function (e) {
3204        return thisObj.handleGridBlur(e);
3205    });
3206
3207    this.$grid.delegate('td', 'click', function (e) {
3208        return thisObj.handleGridClick(this, e);
3209    });
3210
3211} // end bindHandlers();
3212
3213function scrollToFirstHighlightDay() {
3214    // find all the heights of elements before the calendar
3215    var EventInfoHeight = $('#EventInformationWrap').outerHeight() + 64; // 64 is the height mobile navigation
3216    var EventLabelAndOptionsHeight = $('#eventCalendarLabelAndOptions').outerHeight(); 
3217    var CalendarMonthHeight =  $('.sw-datepicker.large-datepicker .month-wrap').outerHeight(); 
3218
3219    var EventInfoAndOptionsHeight = EventInfoHeight + EventLabelAndOptionsHeight;
3220    var CalendarTopInfoHeaderHeights = EventInfoHeight + EventLabelAndOptionsHeight + CalendarMonthHeight + 10; // 10 is just a gap added so it is not sticking against the month section
3221
3222    // set the Top section sticky so when it focuses on the first hightlight day you can still see the informations 
3223    $('#EventInformationWrap').addClass("make-this-section-sticky");
3224    $('#eventCalendarLabelAndOptions').addClass("make-this-section-sticky");
3225    $('#eventCalendarLabelAndOptions').css("top", EventInfoHeight);
3226    $('.sw-datepicker.large-datepicker .month-wrap').addClass("make-this-section-sticky");
3227    $('.sw-datepicker.large-datepicker .month-wrap').css("top", EventInfoAndOptionsHeight);
3228
3229    // Check if any elements with the class .highlight-day exist
3230    var highlightDay = $('.performance-list-calendar .highlight-day').first();
3231
3232    // set the first day cell
3233    var firstDayCel = $('.day-cell').first();
3234    var scrollToPosition = 0;
3235
3236    if (highlightDay.length > 0) { // Get the offset only if .highlight-day element exists
3237        scrollToPosition = highlightDay.offset().top;
3238        scrollToPosition = scrollToPosition - CalendarTopInfoHeaderHeights;  
3239        $('html, body').animate({scrollTop: scrollToPosition}, 'slow');
3240    } else { // if there's no highlights on this month, focus on the first day of the month
3241        scrollToPosition = firstDayCel.offset().top;
3242        scrollToPosition = scrollToPosition - (CalendarTopInfoHeaderHeights * 2);
3243        $('html, body').animate({scrollTop: scrollToPosition}, 'slow');
3244    }
3245}
3246
3247//
3248// handlePrevClick() is a member function to process click events for the prev month button
3249//
3250// @input (e obj) e is the event object associated with the event
3251//
3252// @return (boolean) false if consuming event, true if propagating
3253//
3254swDatepicker.prototype.handlePrevClick = function (e) {
3255    
3256    var active = this.$grid.attr('aria-activedescendant');
3257
3258    if (e.ctrlKey) {
3259        this.showPrevYear();
3260    }
3261    else {
3262        this.showPrevMonth();
3263    }
3264
3265    if (this.currentDate == false) {
3266        this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
3267    }
3268    else {
3269        this.$grid.attr('aria-activedescendant', active);
3270    }
3271
3272    e.stopPropagation();
3273    return false;
3274
3275} // end handlePrevClick()
3276
3277//
3278// handleNextClick() is a member function to process click events for the next month button
3279//
3280// @input (e obj) e is the event object associated with the event
3281//
3282// @return (boolean) false if consuming event, true if propagating
3283//
3284swDatepicker.prototype.handleNextClick = function (e) {
3285    
3286    var active = this.$grid.attr('aria-activedescendant');
3287
3288    if (e.ctrlKey) {
3289        this.showNextYear();
3290    }
3291    else {
3292        this.showNextMonth();
3293    }
3294
3295    if (this.currentDate == false) {
3296        this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
3297    }
3298    else {
3299        this.$grid.attr('aria-activedescendant', active);
3300    }
3301
3302    e.stopPropagation();
3303    return false;
3304
3305} // end handleNextClick()
3306
3307//
3308// handlePrevKeyDown() is a member function to process keydown events for the prev month button
3309//
3310// @input (e obj) e is the event object associated with the event
3311//
3312// @return (boolean) false if consuming event, true if propagating
3313//
3314swDatepicker.prototype.handlePrevKeyDown = function (e) {
3315
3316    if (e.altKey) {
3317        return true;
3318    }
3319
3320    switch (e.keyCode) {
3321        case this.keys.tab: {
3322            if (this.bModal == false || !e.shiftKey || e.ctrlKey) {
3323                return true;
3324            }
3325
3326            this.$grid.focus();
3327            e.stopPropagation();
3328            return false;
3329        }
3330        case this.keys.enter:
3331        case this.keys.space: {
3332            if (e.shiftKey) {
3333                return true;
3334            }
3335
3336            if (e.ctrlKey) {
3337                this.showPrevYear();
3338            }
3339            else {
3340                this.showPrevMonth();
3341            }
3342
3343            e.stopPropagation();
3344            return false;
3345        }
3346    }
3347
3348    return true;
3349
3350} // end handlePrevKeyDown()
3351
3352//
3353// handleNextKeyDown() is a member function to process keydown events for the next month button
3354//
3355// @input (e obj) e is the event object associated with the event
3356//
3357// @return (boolean) false if consuming event, true if propagating
3358//
3359swDatepicker.prototype.handleNextKeyDown = function (e) {
3360
3361    if (e.altKey) {
3362        return true;
3363    }
3364
3365    switch (e.keyCode) {
3366        case this.keys.enter:
3367        case this.keys.space: {
3368
3369            if (e.ctrlKey) {
3370                this.showNextYear();
3371            }
3372            else {
3373                this.showNextMonth();
3374            }
3375
3376            e.stopPropagation();
3377            return false;
3378        }
3379    }
3380
3381    return true;
3382
3383} // end handleNextKeyDown()
3384
3385//
3386// handleGridKeyDown() is a member function to process keydown events for the datepicker grid
3387//
3388// @input (e obj) e is the event object associated with the event
3389//
3390// @return (boolean) false if consuming event, true if propagating
3391//
3392swDatepicker.prototype.handleGridKeyDown = function (e) {
3393
3394    var $rows = this.$grid.find('tbody tr');
3395    var $curDay = $('#' + this.$grid.attr('aria-activedescendant'));
3396    var $days = this.$grid.find('td').not('.empty');
3397    var $curRow = $curDay.parent();
3398
3399    if (e.altKey) {
3400        return true;
3401    }
3402
3403    switch (e.keyCode) {
3404        case this.keys.tab: {
3405
3406            if (this.bModal == true) {
3407                if (e.shiftKey) {
3408                    this.$next.focus();
3409                }
3410                else {
3411                    this.$prev.focus();
3412                }
3413                e.stopPropagation()
3414                return false;
3415            }
3416            break;
3417        }
3418        case this.keys.enter:
3419        case this.keys.space: {
3420
3421            if (e.ctrlKey) {
3422                return true;
3423            }
3424
3425            // update the target box
3426            this.$target.val((this.month + 1) + '/' + $curDay.find(".calendar-day").text() + '/' + this.year).change();
3427
3428            // fall through
3429        }
3430        case this.keys.esc: {
3431            // dismiss the dialog box
3432            this.hideDlg();
3433
3434            e.stopPropagation();
3435            return false;
3436        }
3437        case this.keys.left: {
3438
3439            if (e.ctrlKey || e.shiftKey) {
3440                return true;
3441            }
3442
3443            var dayIndex = $days.index($curDay) - 1;
3444            var $prevDay = null;
3445
3446            if (dayIndex >= 0) {
3447                $prevDay = $days.eq(dayIndex);
3448
3449                $curDay.removeClass('focus').attr('aria-selected', 'false');
3450                $prevDay.addClass('focus').attr('aria-selected', 'true');
3451
3452                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
3453            }
3454            else {
3455                this.showPrevMonth(0);
3456            }
3457
3458            e.stopPropagation();
3459            return false;
3460        }
3461        case this.keys.right: {
3462
3463            if (e.ctrlKey || e.shiftKey) {
3464                return true;
3465            }
3466
3467            var dayIndex = $days.index($curDay) + 1;
3468            var $nextDay = null;
3469
3470            if (dayIndex < $days.length) {
3471                $nextDay = $days.eq(dayIndex);
3472                $curDay.removeClass('focus').attr('aria-selected', 'false');
3473                $nextDay.addClass('focus').attr('aria-selected', 'true');
3474
3475                this.$grid.attr('aria-activedescendant', $nextDay.attr('id'));
3476            }
3477            else {
3478                // move to the next month
3479                this.showNextMonth(1);
3480            }
3481
3482            e.stopPropagation();
3483            return false;
3484        }
3485        case this.keys.up: {
3486
3487            if (e.ctrlKey || e.shiftKey) {
3488                return true;
3489            }
3490
3491            var dayIndex = $days.index($curDay) - 7;
3492            var $prevDay = null;
3493
3494            if (dayIndex >= 0) {
3495                $prevDay = $days.eq(dayIndex);
3496
3497                $curDay.removeClass('focus').attr('aria-selected', 'false');
3498                $prevDay.addClass('focus').attr('aria-selected', 'true');
3499
3500                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
3501            }
3502            else {
3503                // move to appropriate day in previous month
3504                dayIndex = 6 - $days.index($curDay);
3505
3506                this.showPrevMonth(dayIndex);
3507            }
3508
3509            e.stopPropagation();
3510            return false;
3511        }
3512        case this.keys.down: {
3513
3514            if (e.ctrlKey || e.shiftKey) {
3515                return true;
3516            }
3517
3518            var dayIndex = $days.index($curDay) + 7;
3519            var $prevDay = null;
3520
3521            if (dayIndex < $days.length) {
3522                $prevDay = $days.eq(dayIndex);
3523
3524                $curDay.removeClass('focus').attr('aria-selected', 'false');
3525                $prevDay.addClass('focus').attr('aria-selected', 'true');
3526
3527                this.$grid.attr('aria-activedescendant', $prevDay.attr('id'));
3528            }
3529            else {
3530                // move to appropriate day in next month
3531                dayIndex = 8 - ($days.length - $days.index($curDay));
3532
3533                this.showNextMonth(dayIndex);
3534            }
3535
3536            e.stopPropagation();
3537            return false;
3538        }
3539        case this.keys.pageup: {
3540            var active = this.$grid.attr('aria-activedescendant');
3541
3542
3543            if (e.shiftKey) {
3544                return true;
3545            }
3546
3547
3548            if (e.ctrlKey) {
3549                this.showPrevYear();
3550            }
3551            else {
3552                this.showPrevMonth();
3553            }
3554
3555            if ($('#' + active).attr('id') == undefined) {
3556                var lastDay = 'day' + this.calcNumDays(this.year, this.month);
3557                $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
3558            }
3559            else {
3560                $('#' + this.calendarName + '-' + active).addClass('focus').attr('aria-selected', 'true');
3561            }
3562
3563            e.stopPropagation();
3564            return false;
3565        }
3566        case this.keys.pagedown: {
3567            var active = this.$grid.attr('aria-activedescendant');
3568
3569
3570            if (e.shiftKey) {
3571                return true;
3572            }
3573
3574            if (e.ctrlKey) {
3575                this.showNextYear();
3576            }
3577            else {
3578                this.showNextMonth();
3579            }
3580
3581            if ($('#' + active).attr('id') == undefined) {
3582                var lastDay = 'day' + this.calcNumDays(this.year, this.month);
3583                $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
3584            }
3585            else {
3586                $('#' + this.calendarName + '-' + active).addClass('focus').attr('aria-selected', 'true');
3587            }
3588
3589            e.stopPropagation();
3590            return false;
3591        }
3592        case this.keys.home: {
3593
3594            if (e.ctrlKey || e.shiftKey) {
3595                return true;
3596            }
3597
3598            $curDay.removeClass('focus').attr('aria-selected', 'false');
3599
3600            $('#' + this.calendarName + '-day1').addClass('focus').attr('aria-selected', 'true');
3601
3602            this.$grid.attr('aria-activedescendant', this.calendarName + '-day1');
3603
3604            e.stopPropagation();
3605            return false;
3606        }
3607        case this.keys.end: {
3608
3609            if (e.ctrlKey || e.shiftKey) {
3610                return true;
3611            }
3612
3613            var lastDay = 'day' + this.calcNumDays(this.year, this.month);
3614
3615            $curDay.removeClass('focus').attr('aria-selected', 'false');
3616
3617            $('#' + this.calendarName + '-' + lastDay).addClass('focus').attr('aria-selected', 'true');
3618
3619            this.$grid.attr('aria-activedescendant', this.calendarName + '-' + lastDay);
3620
3621            e.stopPropagation();
3622            return false;
3623        }
3624    }
3625
3626    return true;
3627
3628} // end handleGridKeyDown()
3629
3630//
3631// handleGridKeyPress() is a member function to consume keypress events for browsers that
3632// use keypress to scroll the screen and manipulate tabs
3633//
3634// @input (e obj) e is the event object associated with the event
3635//
3636// @return (boolean) false if consuming event, true if propagating
3637//
3638swDatepicker.prototype.handleGridKeyPress = function (e) {
3639
3640    if (e.altKey) {
3641        return true;
3642    }
3643
3644    switch (e.keyCode) {
3645        case this.keys.tab:
3646        case this.keys.enter:
3647        case this.keys.space:
3648        case this.keys.esc:
3649        case this.keys.left:
3650        case this.keys.right:
3651        case this.keys.up:
3652        case this.keys.down:
3653        case this.keys.pageup:
3654        case this.keys.pagedown:
3655        case this.keys.home:
3656        case this.keys.end: {
3657            e.stopPropagation();
3658            return false;
3659        }
3660    }
3661
3662    return true;
3663
3664} // end handleGridKeyPress()
3665
3666//
3667// handleGridClick() is a member function to process mouse click events for the datepicker grid
3668//
3669// @input (id obj) e is the id of the object triggering the event
3670//
3671// @input (e obj) e is the event object associated with the event
3672//
3673// @return (boolean) false if consuming event, true if propagating
3674//
3675swDatepicker.prototype.handleGridClick = function (id, e) {
3676    var $cell = $(id);
3677
3678    if ($cell.is('.empty')) {
3679        return true;
3680    }
3681
3682    this.$grid.find('.focus').removeClass('focus').attr('aria-selected', 'false');
3683    $cell.addClass('focus').attr('aria-selected', 'true');
3684    this.$grid.attr('aria-activedescendant', $cell.attr('id'));
3685
3686    var $curDay = $('#' + this.$grid.attr('aria-activedescendant'));
3687
3688    /*console.log($curDay);
3689    var isLastMonth = $curDay.hasClass('last-month');
3690
3691    var monthSelected = this.month + 1;
3692    var yearSelected = this.year;
3693    
3694    if (isLastMonth) {
3695        monthSelected--;
3696        
3697        if (monthSelected == 0)
3698            monthSelected = 12;
3699
3700        yearSelected = $curDay.data('year');
3701    }
3702
3703    console.log("month selected: " + monthSelected);
3704    console.log("year selected: " + yearSelected);*/
3705
3706    // update the target box
3707    if(this.type == 'dateRangeSelect'){
3708        if ($curDay.hasClass('muted'))
3709            return true;
3710        
3711        var $rangeSelDate = new Date((this.month + 1) + '/' + $curDay.children('.calendar-day').text() + '/' + this.year);
3712        if(this.fromDateRange == '' && this.toDateRange == ''){
3713            //no dates selected yet, store this in the from date range for now
3714            this.fromDateRange = $rangeSelDate;
3715        }else{
3716            //we've previously selected at least one date here, so figure out which one it should be
3717            if($rangeSelDate < this.fromDateRange){
3718                this.toDateRange = this.fromDateRange;
3719                this.fromDateRange = $rangeSelDate;
3720            }else{
3721                this.toDateRange = $rangeSelDate;
3722            }
3723        }
3724        
3725        var objDateRange = {}
3726        objDateRange.from = this.fromDateRange;
3727        objDateRange.to = this.toDateRange;
3728        this.$target.val(JSON.stringify(objDateRange)).change();
3729        if(objDateRange.from != '' && objDateRange.to != ''){
3730            this.hideDlg(); //NOTE: this only works if the date range is a modal, for other calendars you'll need to manage display according to needs based on current values.
3731        }
3732        e.stopPropagation();
3733        return false;
3734    }
3735    if (!this.forceDateSelection || $cell.hasClass("highlight-day")) {
3736        this.$target.val((this.month + 1) + '/' + $curDay.children('.calendar-day').text() + '/' + this.year).change();
3737        // dismiss the dialog box
3738        this.hideDlg();
3739    }
3740    e.stopPropagation();
3741    return false;
3742
3743} // end handleGridClick()
3744
3745//
3746// handleGridFocus() is a member function to process focus events for the datepicker grid
3747//
3748// @input (e obj) e is the event object associated with the event
3749//
3750// @return (boolean) true
3751//
3752swDatepicker.prototype.handleGridFocus = function (e) {
3753    var active = this.$grid.attr('aria-activedescendant');
3754
3755    if ($('#' + active).attr('id') == undefined) {
3756        var lastDay = 'day' + this.calcNumDays(this.year, this.month);
3757        $('#' + lastDay).addClass('focus').attr('aria-selected', 'true');
3758    }
3759    else {
3760        $('#' + active).addClass('focus').attr('aria-selected', 'true');
3761    }
3762
3763    return true;
3764
3765} // end handleGridFocus()
3766
3767//
3768// handleGridBlur() is a member function to process blur events for the datepicker grid
3769//
3770// @input (e obj) e is the event object associated with the event
3771//
3772// @return (boolean) true
3773//
3774swDatepicker.prototype.handleGridBlur = function (e) {
3775    $('#' + this.$grid.attr('aria-activedescendant')).removeClass('focus').attr('aria-selected', 'false');
3776
3777    return true;
3778
3779} // end handleGridBlur()
3780
3781//
3782// showDlg() is a member function to show the datepicker and give it focus. This function is only called if
3783// the datepicker is used in modal dialog mode.
3784//
3785// @return N/A
3786//
3787swDatepicker.prototype.showDlg = function () {
3788    if (!this.bModal)
3789        return;
3790
3791    var thisObj = this;
3792    var thisNode = this.$id;
3793
3794    this.highlightDays();
3795
3796    this.active = true;
3797
3798    //prevent calendar from pushing out of the right side of the window
3799    if (thisNode.parent()[0].getBoundingClientRect().left > (window.innerWidth / 2))
3800        thisNode.addClass("right-side");
3801
3802    $(".content-wrap").bind('click', function (e) {
3803        if (!thisNode[0].contains(e.target) && e.target != thisObj.$target[0]) {
3804            thisObj.hideDlg();
3805        }
3806    });
3807
3808    // show the dialog
3809    this.$id.attr('aria-hidden', 'false');
3810
3811    this.$grid.focus();
3812
3813} // end showDlg()
3814
3815//
3816// hideDlg() is a member function to hide the datepicker and remove focus. This function is only called if
3817// the datepicker is used in modal dialog mode.
3818//
3819// @return N/A
3820//
3821swDatepicker.prototype.hideDlg = function () {
3822    if (!this.bModal)
3823        return;
3824    
3825    this.active = false;
3826    var thisNode = this.$id;
3827
3828    // unbind the modal event sinks
3829    $(document).unbind('click');
3830
3831    // hide the dialog
3832    this.$id.attr('aria-hidden', 'true');
3833
3834    // set focus on the focus target
3835    //this.$target.focus();
3836
3837} // end showDlg()
3838
3839//function to highlight days with performances or valid information
3840//to prevent rewriting the calendar each time a date is added, popGrid() should be called after all dates have been added
3841swDatepicker.prototype.addHighlightDay = function (date) {
3842    var datesplit = String(date).split("/");
3843    for(var i = 0;i < datesplit.length; i++){
3844        datesplit[i] = datesplit[i].replace(/^0+/, '');
3845    }
3846    date = datesplit.join("/");
3847    if (datesplit.length != 3) {
3848        //date didn't come in in m/d/yyyy format, kick it back in the console
3849        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3850        console.log(date);
3851        return;
3852
3853    }
3854    this.highlightDates.push(date);
3855    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3856        $("#" + this.calendarName + "-day" + datesplit[1]).addClass("highlight-day");
3857    }
3858}
3859swDatepicker.prototype.addDateInfoBox = function (date, infoBoxText) {
3860    var datesplit = String(date).split("/");
3861    for(var i = 0;i < datesplit.length; i++){
3862        datesplit[i] = datesplit[i].replace(/^0+/, '');
3863    }
3864    date = datesplit.join("/");
3865    if (datesplit.length != 3) {
3866        //date didn't come in in m/d/yyyy format, kick it back in the console
3867        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3868        console.log(date);
3869        return;
3870
3871    }
3872    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3873        $("#" + this.calendarName + "-day" + datesplit[1]).append('<span class="date-info-box">' + infoBoxText + '</span>');
3874    }
3875}
3876swDatepicker.prototype.addDateSubNote = function (date, noteText) {
3877    var datesplit = String(date).split("/");
3878    for(var i = 0;i < datesplit.length; i++){
3879        datesplit[i] = datesplit[i].replace(/^0+/, '');
3880    }
3881    date = datesplit.join("/");
3882    if (datesplit.length != 3) {
3883        //date didn't come in in m/d/yyyy format, kick it back in the console
3884        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3885        console.log(date);
3886        return;
3887
3888    }
3889    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3890        var spanClass = this.isMultiplePerformanceIndicator ? 'date-info-box date-sub-note multiple-performancetime-subnote' : 'date-info-box date-sub-note';
3891        $("#" + this.calendarName + "-day" + datesplit[1]).append('<span class="' + spanClass + '">' + noteText + '</span>');
3892    }
3893}
3894swDatepicker.prototype.setDaySoldOut = function (date) {
3895    var datesplit = String(date).split("/");
3896    for(var i = 0;i < datesplit.length; i++){
3897        datesplit[i] = datesplit[i].replace(/^0+/, '');
3898    }
3899    date = datesplit.join("/");
3900    if (datesplit.length != 3) {
3901        //date didn't come in in m/d/yyyy format, kick it back in the console
3902        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3903        console.log(date);
3904        return;
3905
3906    }
3907    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3908        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('sold-out');
3909        
3910        this.addDateInfoBox(date, "Sold Out");
3911        $("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
3912    }
3913}
3914swDatepicker.prototype.setcustomStatus = function (date,showPhoneNumber,currenStatus) {
3915    var datesplit = String(date).split("/");
3916    for(var i = 0;i < datesplit.length; i++){
3917        datesplit[i] = datesplit[i].replace(/^0+/, '');
3918    }
3919    date = datesplit.join("/");
3920    if (datesplit.length != 3) {
3921        //date didn't come in in m/d/yyyy format, kick it back in the console
3922        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3923        console.log(date);
3924        return;
3925
3926    }
3927    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3928        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('sold-out');
3929        var phoneNumber = " <br> [email protected] "
3930        if (!showPhoneNumber)
3931            phoneNumber="";
3932        this.addDateInfoBox(date, currenStatus +phoneNumber);
3933        
3934        $("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
3935    }
3936}
3937swDatepicker.prototype.setDayLimitedAvailabilty = function (date) {
3938    var datesplit = String(date).split("/");
3939    for(var i = 0;i < datesplit.length; i++){
3940        datesplit[i] = datesplit[i].replace(/^0+/, '');
3941    }
3942    date = datesplit.join("/");
3943    if (datesplit.length != 3) {
3944        //date didn't come in in m/d/yyyy format, kick it back in the console
3945        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3946        console.log(date);
3947        return;
3948
3949    }
3950    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3951        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('limited-availability');
3952        
3953        this.addDateSubNote(date, 'Selling Quickly');
3954        //$("#" + this.calendarName + "-day" + datesplit[1]).children(".date-info-box").removeClass("date-info-box").addClass("sold-out-info-box");
3955    }
3956    if($(".limited-availability-legend-item").length == 0){
3957        
3958            $(".calendar-notes-wrap").append('<div class="limited-availability-legend-item"><span classs="calendar-limited-availability-legend-icon">!</span> - Selling Quickly</div>')
3959         
3960       // $("#streamlinedCalendarLimitedAvailabilityLegend").append('<div class="limited-availability-legend-item"><span class="calendar-limited-availability-legend-icon">!</span> - Selling Quickly</div>')
3961    }
3962}
3963swDatepicker.prototype.setMultiplePerformanceTimes = function (date) {
3964    var datesplit = String(date).split("/");
3965    for(var i = 0;i < datesplit.length; i++){
3966        datesplit[i] = datesplit[i].replace(/^0+/, '');
3967    }
3968    
3969    date = datesplit.join("/");
3970    if (datesplit.length != 3) {
3971        //date didn't come in in m/d/yyyy format, kick it back in the console
3972        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3973        return;
3974
3975    }
3976    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3977        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('multipleperformancetimes');
3978
3979    }
3980    if($(".multiple-performancetimes-notes").length == 0){
3981        
3982    }
3983    
3984}
3985swDatepicker.prototype.setMutedDay = function (date) {
3986    var datesplit = String(date).split("/");
3987    for(var i = 0;i < datesplit.length; i++){
3988        datesplit[i] = datesplit[i].replace(/^0+/, '');
3989    }
3990    date = datesplit.join("/");
3991    if (datesplit.length != 3) {
3992        //date didn't come in in m/d/yyyy format, kick it back in the console
3993        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
3994        return;
3995
3996    }
3997    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
3998        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('muted');
3999    }
4000}
4001swDatepicker.prototype.clearMutedDay = function (date) {
4002    var datesplit = String(date).split("/");
4003    for(var i = 0;i < datesplit.length; i++){
4004        datesplit[i] = datesplit[i].replace(/^0+/, '');
4005    }
4006    date = datesplit.join("/");
4007    if (datesplit.length != 3) {
4008        //date didn't come in in m/d/yyyy format, kick it back in the console
4009        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
4010        return;
4011
4012    }
4013    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
4014        $("#" + this.calendarName + "-day" + datesplit[1]).removeClass('muted');
4015    }
4016}
4017swDatepicker.prototype.setCouponMutedDay = function (date) {
4018    var datesplit = String(date).split("/");
4019    for(var i = 0;i < datesplit.length; i++){
4020        datesplit[i] = datesplit[i].replace(/^0+/, '');
4021    }
4022    date = datesplit.join("/");
4023    if (datesplit.length != 3) {
4024        //date didn't come in in m/d/yyyy format, kick it back in the console
4025        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
4026        return;
4027
4028    }
4029    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
4030        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('coupon-muted');
4031    }
4032}
4033swDatepicker.prototype.setPasswordHiddenDay = function (date) {
4034    var datesplit = String(date).split("/");
4035    for(var i = 0;i < datesplit.length; i++){
4036        datesplit[i] = datesplit[i].replace(/^0+/, '');
4037    }
4038    date = datesplit.join("/");
4039    if (datesplit.length != 3) {
4040        //date didn't come in in m/d/yyyy format, kick it back in the console
4041        console.log("invalid date sent, datepicker accepts m/d/yyyy only - " + date);
4042        return;
4043
4044    }
4045    if (parseInt(datesplit[0]) - 1 == this.month && parseInt(datesplit[2]) == this.year) {
4046        $("#" + this.calendarName + "-day" + datesplit[1]).addClass('password-hidden');
4047        $("#" + this.calendarName + "-day" + datesplit[1]).removeClass('highlight-day');
4048    }
4049}
4050swDatepicker.prototype.clearAllMutedDays = function () {
4051    $(".muted").removeClass('muted');
4052}
4053swDatepicker.prototype.clearHighlightDays = function () {
4054    this.highlightDates = [];
4055    this.highlightDays();
4056}
4057//highlights all days in the highlightDates array
4058swDatepicker.prototype.highlightDays = function () {
4059    $("#" + this.calendarName + " .highlight-day").removeClass("highlight-day");
4060    var curYear = this.year;
4061    var curMonth = this.month;
4062    var calName = this.calendarName;
4063    var IEFix = new RegExp(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g);
4064
4065    this.highlightDates.forEach(function (o, i, a) {
4066        var datesplit = o.split("/");
4067        if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
4068            $("#" + calName + "-day" + datesplit[1].replace(IEFix, '')).addClass("highlight-day");
4069        }
4070    });
4071    this.setColors();
4072}
4073swDatepicker.prototype.setColors = function () {
4074    /*
4075        Custom color functionality. Utilized by dropping calendar-colors.txt file in root of custom folder
4076        requires json content of text file formatted as follows:
4077        {
4078            "events":
4079                {"528": 
4080                    [
4081                        {"date":"12/1/2025", "color": "#ccc"}, 
4082                        {"date":"12/2/2025", "color": "#ccc"}
4083                    ]
4084                ,
4085                "529":
4086                    [
4087                        {"date":"12/8/2025", "color": "#ccc"}, 
4088                        {"date":"12/9/2025", "color": "#ccc"}
4089                    ]
4090                }
4091            ,
4092            "bundles":[],
4093            "generic":
4094                {"dates": 
4095                    [
4096                        {"date":"12/23/2025", "color": "#def"}, 
4097                        {"date":"12/22/2025", "color": "#1a1"}
4098                    ]
4099                ,
4100                "weekdays":
4101                    [
4102                        {"day":"Saturday", "color": "#2a2"}, 
4103                        {"day":"Thursday", "color": "#3a3"}
4104                    ]
4105                }    
4106        }
4107    }
4108    */
4109    var thisDP = this;
4110    try{
4111        $.getJSON("/calendar-colors.txt")
4112        .done(function (data) {
4113            thisDP.renderColors(data);
4114        })
4115        .fail(function (jqxhr, textStatus, error) {
4116            console.log("No Custom Calendar Colors Found");
4117            return;
4118        });
4119    }catch(e){
4120        console.log("parsing error:");
4121        console.log(e);
4122        return;
4123    }
4124}
4125swDatepicker.prototype.renderColors = function (colorData) {
4126    var curYear = this.year;
4127    var curMonth = this.month;
4128    var calName = this.calendarName;
4129    var IEFix = new RegExp(/[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g);
4130    //set generic colors
4131    if(colorData.generic){
4132        if(colorData.generic.dates.length > 0){
4133            colorData.generic.dates.forEach(function (o, i, a) {
4134                var datesplit = o.date.split("/");
4135                if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
4136                    $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
4137                }
4138            });
4139        }
4140        if(colorData.generic.weekdays && colorData.generic.weekdays.length > 0){
4141            colorData.generic.weekdays.forEach(function (o, i, a) {
4142                $("td[headers*=" + o.day + "] .calendar-day").css("background-color", o.color);
4143            });
4144        }
4145    }
4146    if(colorData.events && colorData.events[this.eventID] && this.eventID !== -1){
4147        colorData.events[this.eventID].forEach(function (o, i, a) {
4148            var datesplit = o.date.split("/");
4149            if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
4150                $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
4151            }
4152        });
4153    }
4154    if(colorData.bundles && colorData.bundles[this.bundleID] && this.bundleID !== -1){
4155        colorData.bundles[this.bundleID].forEach(function (o, i, a) {
4156            var datesplit = o.date.split("/");
4157            if (parseInt(datesplit[0].replace(IEFix, '')) - 1 == parseInt(curMonth) && parseInt(datesplit[2].replace(IEFix, '')) == parseInt(curYear)) {
4158                $("#" + calName + "-day" + datesplit[1].replace(IEFix, '') + ' .calendar-day').css("background-color", o.color);
4159            }
4160        });
4161    }
4162}
4163swDatepicker.prototype.fetchDates = function(){
4164    var thisCalendar = this;
4165    var haveDates = thisCalendar.fetchLocalDates();
4166    if (thisCalendar.categoryID >= 0)
4167        haveDates = false;
4168    this.clearHighlightDays();
4169    if(haveDates){
4170        //valid local dates stored
4171        try{
4172            haveDates = JSON.parse(haveDates);
4173            if (haveDates.length > 0) {
4174                haveDates.forEach(function(o){
4175                    thisCalendar.addHighlightDay(o);
4176                })
4177                thisCalendar.highlightDays();
4178            }
4179        } catch (e) {
4180            console.log("Failed to grab dates. Date object not valid: ", haveDates);
4181            console.log(e);
4182        }
4183    } else {        
4184        $.getJSON("/include/widgets/calendar/calendarRequests.asp",
4185            {
4186                action: thisCalendar.type,
4187                calMonth: thisCalendar.activeMonth,
4188                iEvent: thisCalendar.eventID,
4189                iBundle: thisCalendar.bundleID,
4190                iCategory : thisCalendar.categoryID,
4191                cp : thisCalendar.corporatePartnerPage
4192            })
4193            .done(function (data) {
4194                thisCalendar.storeDates(data.performancedates);
4195                try {
4196                    if (data.performancedates.length > 0) {
4197                        data.performancedates.forEach(function (o) {
4198                            
4199                            thisCalendar.addHighlightDay(o);
4200                        })
4201                        thisCalendar.highlightDays();
4202                    }
4203                } catch (e) {
4204                    console.log("Failed to grab dates. Date object not valid: " + haveDates);
4205                    console.log(e);
4206                }
4207                $(".calendar-loading").hide();
4208            })
4209            .fail(function (jqxhr, textStatus, error) {
4210                var err = textStatus + ", " + error;
4211                console.log("Request Failed: " + err);
4212                $(".calendar-loading").hide();
4213            });
4214    }
4215}
4216swDatepicker.prototype.getCalendarDetails = function(){
4217    var thisCalendar = this;
4218    this.clearHighlightDays();
4219    $("#" + this.calendarName).removeClass("has-muted-days");
4220    $.getJSON("/include/widgets/calendar/calendarRequests.asp",
4221        {
4222            action: thisCalendar.type,
4223            calMonth: thisCalendar.activeMonth,
4224            iEvent: thisCalendar.eventID,
4225            iBundle: thisCalendar.bundleID,
4226            iCategory : thisCalendar.categoryID,
4227            cp : thisCalendar.corporatePartnerPage,
4228            bValidCoupon : thisCalendar.bValidCoupon,
4229            couponCode : thisCalendar.couponCode
4230        })
4231        .done(function (data) {
4232            //to save on request time, we need to resolve the data on the client a bit before we store it
4233            var performanceDates = [];
4234            data.performanceDateData.forEach(function(dd){
4235                
4236                if(dd.DoNotShowPublic == 0){
4237                    var detailsObj = {};
4238                    var currentDateIndex = fetchDateIndex(dd.CalendarDate, performanceDates);
4239                    if(currentDateIndex == -1){
4240                        detailsObj.date = dd.CalendarDate;
4241                        detailsObj.performances = [];
4242                        detailsObj.performances.push(dd.PerformanceCode);
4243                        detailsObj.defaultPrice = dd.LowestDefaultPrice;
4244                        detailsObj.PerformanceName = dd.PerformanceName;
4245                        detailsObj.PerformanceTime = dd.PerfTime;
4246                        detailsObj.PerformanceStartTimeAlias = dd.PerformanceStartTimeAlias;
4247                        detailsObj.DisplayType = dd.DisplayType;
4248                        detailsObj.CalendarViewShowPrice = dd.CalendarViewShowPrice;
4249                        detailsObj.CalendarViewShowPerformanceName = dd.CalendarViewShowPerformanceName;
4250                        detailsObj.CalendarViewShowPerformanceTime = dd.CalendarViewShowPerformanceTime;
4251                        detailsObj.CalendarViewShowBuyButton = dd.CalendarViewShowBuyButton;
4252                        detailsObj.defaultPricingCode = dd.LowestDefaultPricingCode;
4253                        detailsObj.secondaryPrice = dd.LowestSecondaryPrice;
4254                        detailsObj.secondaryPricingCode =dd.LowestSecondaryPricingCode;
4255                        detailsObj.NoCouponAvailable = dd.NoCouponAvailable;
4256                        detailsObj.passwordMatch = dd.passwordMatch;
4257                        detailsObj.qualifierPasswordMatch = dd.qualifierPasswordMatch;
4258                        detailsObj.hasPassword = dd.hasPassword;
4259                        detailsObj.hasQualifierPassword = dd.hasQualifierPassword;
4260                        detailsObj.hasCoupons = dd.hasCoupons; 
4261                        detailsObj.IsSalesPeriodEnded = dd.IsSalesPeriodEnded;
4262                        detailsObj.SaleIcon = dd.SaleIcon;
4263                        detailsObj.BSaleIcon = dd.BSaleIcon;
4264                        
4265                        detailsObj.hasQualifiers = dd.hasQualifiers;
4266                        performanceDates.push(detailsObj)
4267                       
4268                    }else{
4269                        performanceDates[currentDateIndex].performances.push(dd.PerformanceCode);
4270                        performanceDates[currentDateIndex].NoCouponAvailable = dd.NoCouponAvailable;
4271                        performanceDates[currentDateIndex].passwordMatch = dd.passwordMatch;
4272                        performanceDates[currentDateIndex].acMatch = dd.acMatch;
4273                        performanceDates[currentDateIndex].qualifierPasswordMatch = dd.qualifierPasswordMatch;
4274                        performanceDates[currentDateIndex].hasPassword = dd.hasPassword;
4275                        performanceDates[currentDateIndex].hasQualifierPassword = dd.hasQualifierPassword;
4276                        performanceDates[currentDateIndex].hasCoupons = dd.hasCoupons;
4277                        performanceDates[currentDateIndex].PerformanceName = dd.PerformanceName;
4278                        performanceDates[currentDateIndex].PerformanceTime = dd.PerfTime;
4279                        performanceDates[currentDateIndex].PerformanceStartTimeAlias = dd.PerformanceStartTimeAlias;
4280                        performanceDates[currentDateIndex].CalendarViewShowPrice = dd.CalendarViewShowPrice;
4281                        performanceDates[currentDateIndex].CalendarViewShowPerformanceName = dd.CalendarViewShowPerformanceName;
4282                        performanceDates[currentDateIndex].CalendarViewShowPerformanceTime = dd.CalendarViewShowPerformanceTime;
4283                        performanceDates[currentDateIndex].CalendarViewShowBuyButton = dd.CalendarViewShowBuyButton;
4284                        performanceDates[currentDateIndex].IsSalesPeriodEnded = dd.IsSalesPeriodEnded;
4285                        performanceDates[currentDateIndex].SaleIcon = dd.SaleIcon;
4286                        performanceDates[currentDateIndex].BSaleIcon = dd.BSaleIcon;                        
4287                        performanceDates[currentDateIndex].hasQualifiers = dd.hasQualifiers;
4288                        //check for lowest price
4289                        if(performanceDates[currentDateIndex].defaultPrice > dd.LowestDefaultPrice && dd.LowestDefaultPrice != null){
4290                            performanceDates[currentDateIndex].defaultPrice = dd.LowestDefaultPrice;
4291                            performanceDates[currentDateIndex].defaultPricingCode = dd.LowestDefaultPricingCode;
4292                        }
4293                        if(performanceDates[currentDateIndex].hasCoupons == 1 && performanceDates[currentDateIndex].defaultPrice < dd.LowestDefaultPrice && dd.LowestDefaultPrice != null && false){
4294                            performanceDates[currentDateIndex].defaultPrice = dd.LowestDefaultPrice;
4295                            performanceDates[currentDateIndex].defaultPricingCode = dd.LowestDefaultPricingCode;
4296                        }
4297                        if(performanceDates[currentDateIndex].secondaryPrice > dd.LowestSecondaryPrice && dd.LowestSecondaryPrice != null){
4298                            performanceDates[currentDateIndex].secondaryPrice = dd.LowestSecondaryPrice;
4299                            performanceDates[currentDateIndex].secondaryPricingCode = dd.LowestSecondaryPricingCode;
4300                        }
4301                         
4302                        
4303                    }
4304                    //set limited availaibility by matching up results from query with performances
4305                    for(perf in data.performances){
4306                        if(data.performances[perf].id == dd.PerformanceID){
4307                            data.performances[perf].LimitedAvailability = dd.LimitedAvailability;
4308                            data.performances[perf].TimeZone = dd.TimeZone.replace('"', "");
4309                            data.performances[perf].SingleAreaVenueAreaID = dd.SingleAreaVenueAreaID;
4310                            data.performances[perf].NoCouponAvailable = dd.NoCouponAvailable;
4311                            data.performances[perf].passwordMatch = dd.passwordMatch;
4312                            data.performances[perf].acMatch = dd.acMatch;
4313                            data.performances[perf].qualifierPasswordMatch = dd.qualifierPasswordMatch;
4314                            data.performances[perf].hasPassword = dd.hasPassword;
4315                            data.performances[perf].hasQualifierPassword = dd.hasQualifierPassword;
4316                        }
4317                    }
4318                }
4319                
4320            })
4321            
4322            data.performanceDates = performanceDates;
4323            delete data.performanceDateData;
4324            try {
4325                if (thisCalendar.couponCode != "" && $("#couponCode").length > 0)
4326                {
4327                    if($("#coupon-notify").length > 0)
4328                        $("#coupon-notify").remove();
4329
4330                    var notifyMessage = document.createElement("div");
4331                    notifyMessage.setAttribute("id","coupon-notify");
4332                    notifyMessage.setAttribute("class",data.hasValidCoupon ? 'coupon-notify-message' : 'coupon-error-message');
4333                    notifyMessage.innerHTML = (data.hasValidCoupon ? "Code <b>" + thisCalendar.couponCode + "</b> has been applied to valid dates and times." : "The code entered is either invalid, or no longer available.");
4334                    $("#plCalendar").prepend(notifyMessage);
4335                    window.scrollTo(0,0);
4336                }                
4337                
4338                thisCalendar.doCalendarDetailed(data);
4339            } catch (e) {
4340                console.log("Failed to parse details. Date object not valid: ", data);
4341                console.log(e);
4342            }
4343        })
4344        .fail(function (jqxhr, textStatus, error) {
4345            var err = textStatus + ", " + error;
4346            console.log("Request Failed: " + err);
4347        });
4348}
4349swDatepicker.prototype.doCalendarDetailed = function(detailData){
4350    var thisCalendar = this;
4351    this.detailData = detailData;
4352    var defaultPricingLegend = [], secondaryPricingLegend = [];
4353    detailData.performanceDates.forEach(function(d){
4354        thisCalendar.addHighlightDay(d.date);
4355        if (d.NoCouponAvailable > 0)
4356            thisCalendar.setCouponMutedDay(d.date);
4357        
4358        //check if date sold out
4359        var dateSoldOut = true;
4360        var customStatus = false;
4361        var showPhoneNumber =false;
4362        var dateLimitedAvailability = false;
4363        var performanceStatus="";
4364        var performanceOnSale = false;
4365        var IsSalesPeriodEnded = false;
4366        var aggregatedMentaInfo = {
4367            buttonVisible: false,
4368            buttonText: "",
4369            buttonUrl: "",
4370            totalCount: 0
4371        };
4372
4373        var isMentaResaleAvailable = false;
4374        var performanceTimesLength = 0;
4375        var QualiferButton = false;
4376        d.performances.forEach(function(datePerformance){
4377            var performanceKey = String(datePerformance).toLowerCase();
4378            var currentPerformance = detailData.performances[performanceKey];
4379
4380            if (!currentPerformance) {
4381                var perfIndex = d.performances.indexOf(datePerformance);
4382                if (perfIndex !== -1) {
4383                    d.performances.splice(perfIndex, 1);
4384                }
4385                console.log("Date Trimmed, child performance not contained in performance data: " + datePerformance);
4386                return;
4387            }
4388
4389            //let currentPerformance = detailData.performances[String(datePerformance).toLowerCase()];
4390            performanceTimesLength ++;
4391
4392            if(detailData.performances[String(datePerformance).toLowerCase()] && detailData.performances[String(datePerformance).toLowerCase()].status == "On Sale"){
4393                dateSoldOut = false;
4394                performanceOnSale=true;
4395                if(currentPerformance.LimitedAvailability == 1)
4396                    dateLimitedAvailability = true;
4397                        
4398                IsSalesPeriodEnded  =   currentPerformance.IsSalesPeriodEnded==1        
4399            }            
4400            else{
4401                
4402                if ((currentPerformance.status != "Sold Out") && (currentPerformance.status != "On Sale")  ){
4403                    
4404                    customStatus=true;
4405                    performanceStatus=currentPerformance.status;
4406                    dateSoldOut = false;
4407                    //dateLimitedAvailability=false;
4408                    if ( currentPerformance.bSalePhone==1 || currentPerformance.SalePhone==1){
4409                        showPhoneNumber=true;
4410                    }
4411                }
4412                var mentaMarketplace = currentPerformance.MentaMarketplace;
4413                var hasMentaOption = currentPerformance.IsMentaEnabled == 1 && mentaMarketplace && mentaMarketplace.buttonVisible;
4414
4415                if (hasMentaOption) {
4416                    var availableCount = parseInt(mentaMarketplace.totalCount, 10);
4417                    if (!isNaN(availableCount) && availableCount > 0) {
4418                        aggregatedMentaInfo.totalCount += availableCount;
4419                    }
4420                    if (mentaMarketplace.buttonText && aggregatedMentaInfo.buttonText === "") {
4421                        aggregatedMentaInfo.buttonText = mentaMarketplace.buttonText;
4422                    }
4423                    if (mentaMarketplace.buttonUrl && aggregatedMentaInfo.buttonUrl === "") {
4424                        aggregatedMentaInfo.buttonUrl = mentaMarketplace.buttonUrl;
4425                    }
4426                    aggregatedMentaInfo.buttonVisible = true;
4427                    dateSoldOut = false;
4428                    showPhoneNumber=false;
4429                    customStatus=true;
4430                }
4431            }
4432           
4433            // If date is sold out or custom status (not 'on sale'), check if qualifier access code or password match
4434            if (dateSoldOut || customStatus) {
4435                if (currentPerformance.acMatch == 1 || (currentPerformance.qualifierPasswordMatch == 1 && currentPerformance.hasQualifierPassword == 1)) {
4436                    dateSoldOut = false;
4437                    customStatus = false;
4438                    performanceOnSale = true;
4439                    showPhoneNumber = false;
4440                }
4441            }
4442            // If date is sold out or custom status (not 'on sale'), check if it has a public qualifier -- hasQualifiers is set on CalendarRequests.asp when qualifiers exist for performance
4443            if (currentPerformance.hasQualifiers) {
4444                    dateSoldOut = false;
4445                    customStatus = false;
4446                    performanceOnSale = true;
4447                    showPhoneNumber = false;
4448                    QualiferButton = true;
4449                  // If performance has qualifier but status is "On Sale", do not show "Premium Access" text on calendar date
4450                  if (currentPerformance.status == "On Sale") {
4451                    QualiferButton = false;
4452                 } 
4453                 
4454            }
4455        })
4456
4457        if (aggregatedMentaInfo.buttonVisible && aggregatedMentaInfo.buttonText === "") {
4458            aggregatedMentaInfo.buttonText = "Official Resale Available";
4459        }
4460        var hasMentaCtaForDate = aggregatedMentaInfo.buttonVisible && (aggregatedMentaInfo.totalCount > 0 || aggregatedMentaInfo.buttonUrl !== "");
4461        isMentaResaleAvailable = hasMentaCtaForDate && !performanceOnSale;
4462        d.MentaMarketplace = aggregatedMentaInfo;
4463        
4464        if(dateLimitedAvailability && !dateSoldOut){
4465            thisCalendar.setDayLimitedAvailabilty(d.date);
4466        }
4467        if (thisCalendar.isMultiplePerformanceIndicator == 1 && performanceTimesLength > 1) {
4468            thisCalendar.setMultiplePerformanceTimes(d.date);
4469        }
4470        if ( IsSalesPeriodEnded) {
4471            performanceStatus=d.SaleIcon;
4472        }
4473        else{
4474            if(isMentaResaleAvailable && !performanceOnSale){                
4475               
4476                thisCalendar.addDateSubNote(d.date, 'Sold Out');
4477                //thisCalendar.setDaySoldOut(d.date);
4478                //thisCalendar.addDateInfoBox(d.date, "Sold Out");
4479                 thisCalendar.configureMentaSettings(d);            
4480            }
4481            else{ 
4482              performanceStatus=d.BSaleIcon;
4483            }
4484        
4485        }
4486
4487        if (performanceStatus == null || performanceStatus == "")
4488            performanceStatus="sold out";
4489
4490        if(dateSoldOut){
4491            thisCalendar.setDaySoldOut(d.date);
4492        }else{
4493            if ( (customStatus && !dateLimitedAvailability && !performanceOnSale && !isMentaResaleAvailable) || IsSalesPeriodEnded)
4494            {
4495                thisCalendar.setcustomStatus(d.date,showPhoneNumber,performanceStatus)
4496            }
4497            else{
4498            //date not sold out, add details, add to legend if one exists
4499            var detailString = "";
4500
4501            // if the price option is checked in event landing page in the admin 
4502             if(d.CalendarViewShowPrice != 0){
4503                //for now, we'll just add the pricing, this would be a spot to modify what is displayed on the dates by changing the contents of this string
4504                if(d.defaultPrice != null){
4505                    if (QualiferButton) { // SHOWDEV-22142 - If date has public qualifier, show qualifier text (Premium Access) instead of price and buy button
4506                        detailString = detailString + "<span class='display-perfbuybutton'>Premium Access</span>";
4507                    }else {
4508                           
4509                            detailString = "<span class='display-perfprice'>" + thisCalendar.currencySymbol + d.defaultPrice.toFixed(2).replace('.00','') + "</span>";
4510                        
4511                    }
4512                    
4513                if(defaultPricingLegend.indexOf(d.defaultPricingCode) === -1)
4514                    defaultPricingLegend.push(d.defaultPricingCode);
4515                }
4516                if(d.secondaryPricingCode != "" && d.secondaryPricingCode != null){
4517                    if(secondaryPricingLegend.indexOf(d.secondaryPricingCode) === -1)
4518                        secondaryPricingLegend.push(d.secondaryPricingCode);           
4519                    
4520                    if (d.DisplayType === "calendar" || d.DisplayType === "streamlined") {
4521                           
4522                        detailString = "<span class='display-perfprice-withchild'>" + thisCalendar.currencySymbol + d.secondaryPrice.toFixed(2).replace('.00','') + "/</span>" + detailString;
4523                        
4524                    }
4525                }
4526            }
4527            if(d.CalendarViewShowPerformanceName != 0){
4528                detailString =  detailString + "<span class='display-perfname'>" + d.PerformanceName + "</span> ";
4529            }
4530           
4531            if(d.CalendarViewShowPerformanceTime != 0){
4532                if(d.PerformanceStartTimeAlias != ""){ // Performance Alias time is present
4533                    detailString = detailString + " <span class='display-perft
4533ime'>" + d.PerformanceStartTimeAlias + "</span>";
4534                } else {
4535                    detailString = detailString + " <span class='display-perftime'>" + d.PerformanceTime + "</span>";
4536                }
4537                
4538            }
4539            if(d.CalendarViewShowBuyButton != 0){
4540                var styleString = "";
4541                if (d.DisplayType === "streamlined")
4542                    styleString = " style='width: 100%;'";
4543                var buttonText = (isMentaResaleAvailable && d.OverrideBuyTicketsButtonText) ? d.OverrideBuyTicketsButtonText : thisCalendar.buyTicketsButtonText;
4544                detailString = detailString + "<span class='button display-perfbuybutton'"+styleString+">" + buttonText + "</span>";
4545            }
4546
4547            thisCalendar.addDateInfoBox(d.date, detailString);
4548            }
4549        }
4550        
4551    })
4552    //for now, we only generate the legend if there are one or two prices pesent
4553    if(defaultPricingLegend.length === 1 && secondaryPricingLegend.length === 1){
4554        $("#calendarLegend").html(secondaryPricingLegend[0] +" / " + defaultPricingLegend[0])
4555        
4556        $("#calendarLegend").show();
4557    }else{
4558        if(defaultPricingLegend.length === 1){
4559                $("#calendarLegend").html(defaultPricingLegend[0])
4560                
4561                $("#calendarLegend").show();
4562        }else{
4563            $("#calendarLegend").hide();
4564        }
4565    }
4566    if(typeof(setFilterOptions) == 'function'){
4567        setFilterOptions(thisCalendar);
4568    }
4569    if (detailData.hasValidCoupon) {
4570        $("#plCalendar").append("<input type='hidden' id='hasValidCoupon' value='1' />");
4571    } else {
4572        $("#plCalendar").append("<input type='hidden' id='hasValidCoupon' value='0' />");
4573    }
4574    $(".calendar-loading").hide();
4575}
4576swDatepicker.prototype.configureMentaSettings = function (dateDetail) {
4577    // Set Menta Resale Settings
4578    
4579}
4580
4581swDatepicker.prototype.getFirstDate = function(defaultMonth){
4582    var thisCalendar = this;
4583    //this should only happen once on calendar load - currently only enabled for bundles
4584    if(thisCalendar.bundleID == 0 || thisCalendar.bundleID == -1)
4585        return defaultMonth; //currently only developed for bundles TODO: add event, category, standard support.
4586
4587    $.getJSON("/include/widgets/calendar/calendarRequests.asp",
4588            {
4589                action: 'initialBundleDate',
4590                iBundle: thisCalendar.bundleID,
4591                cp : thisCalendar.corporatePartnerPage
4592            })
4593            .done(function (data) {
4594                try {
4595                    if (data.performancedates.length > 0) {
4596                        
4597    
4598                        var firstMonth = Number(String(data.performancedates).split("/")[0]) - 1;
4599                        var firstYear = Number(String(data.performancedates).split("/")[2]);
4600                        thisCalendar.month = firstMonth - 1; //to make this simple, we're using the showNextMonth() function, which means we need to set the month to 1 less than our target, as that function increments the month itself
4601                        thisCalendar.year = firstYear;
4602                        thisCalendar.showNextMonth();
4603                    }else{
4604                        return defaultMonth;
4605                    }
4606                }catch(e){
4607                    console.log("getFirstDate returned invalid date. Default used");
4608                    console.log(e);
4609                    return defaultMonth;
4610                }
4611            })
4612            .fail(function (jqxhr, textStatus, error) {
4613                var err = textStatus + ", " + error;
4614                console.log("Request Failed: " + err);
4615            });
4616}
4617swDatepicker.prototype.fetchLocalDates = function () {
4618    //utliize storage to store months
4619    var CalendarExpireTime = new Date().getTime(); var isExpired = false; var datesData = "";
4620    var calendarIDString = this.calendarName + this.type + this.eventID + this.bundleID + "-" + this.corporatePartnerPage + "_" + this.activeMonth;
4621    try {
4622        //check for local storage support
4623        isExpired = CalendarExpireTime > Number(localStorage.getItem("CalendarExpireTime_" + calendarIDString));
4624        if (isExpired) {
4625            //item expired, clear local results
4626            localStorage.setItem("ShowareDates_" + calendarIDString, "");
4627            localStorage.setItem("CalendarExpireTime_" + calendarIDString, CalendarExpireTime + (1000 * 60 * 30));  //item information expires after 30 minutes
4628            return false;
4629        }
4630        localStorage.setItem("CalendarExpireTime_" + calendarIDString, CalendarExpireTime + (1000 * 60 * 30));  //item information expires after 30 minutes
4631        if (localStorage.getItem("ShowareDates_" + calendarIDString) != null && localStorage.getItem("ShowareDates_" + calendarIDString) != "" && localStorage.getItem("ShowareDates_" + calendarIDString) != []) {
4632            return localStorage.getItem("ShowareDates_" + calendarIDString);
4633        } else {
4634            //date info not stored
4635            return false;
4636        }
4637    } catch (e) {
4638        return false;
4639    }
4640}
4641swDatepicker.prototype.storeDates = function (dateData) {
4642    
4643    var calendarIDString = this.calendarName + this.type + this.eventID + this.bundleID + "-" + this.corporatePartnerPage + "_" + this.activeMonth;
4644    try {
4645        localStorage.setItem("ShowareDates_" + calendarIDString, JSON.stringify(dateData));
4646    } catch (e) {
4647        //no local storage
4648    }
4649}
4650swDatepicker.prototype.getDateRangeEvents = function (dateRangeData) {
4651    var thisCalendar = this;
4652    try{
4653        $.getJSON("/include/widgets/calendar/calendarRequests.asp",
4654            {
4655                action: 'getDateRangeEvents',
4656                dateRange: JSON.stringify(dateRangeData),
4657            })
4658            .done(function (data) {
4659                try {
4660                    thisCalendar.dateRangeEvents = data;
4661                }catch(e){
4662                    console.log("getDateRangeEvents returned invali
4662d response.");
4663                    console.log(data, e);
4664                    return []//return empty array;
4665                }
4666            })
4667            .fail(function (jqxhr, textStatus, error) {
4668                var err = textStatus + ", " + error;
4669                console.log("Request Failed: " + err);
4670            });
4671
4672    }catch(e){
4673        console.log("Unable to fetch date range events:", e)
4674    }
4675}
4676swDatepicker.prototype.clearDateRange = function () {
4677    this.fromDateRange = '';
4678    this.toDateRange = '';
4679}
4680function fetchDateIndex(dateString, dateObjectArray){
4681    try{
4682        for(var i = 0;i < dateObjectArray.length;i++){
4683            if(dateObjectArray[i].date == dateString){
4684                return i;
4685                break;
4686            }
4687        }
4688        return -1;
4689    }catch(e){
4690        //this function requires specific objects with a date property, it will fail otherwise and we'll just return what one would expect from a failed indexof
4691        return -1;
4692    }
4693}
4694function swapMonthDay(d){
4695    //expects dd/mm/yyyy format
4696    try{
4697        let splitDate = d.split("/");
4698        let newDate = splitDate[1] + '/' + splitDate[0] + "/" + splitDate[2];
4699        return newDate;
4700    }catch(e){
4701        console.log("could not swap date:",d,e);
4702        return d;
4703    }
4704}
4705
4706</script>
4706
4707<link rel="stylesheet" type="text/css" href="//www.cincyticket.com/include/accessodesign-core-addition.css?ver=20228b0075">
4708
4709<link rel="stylesheet" type="text/css" href="//www.cincyticket.com/include/style.css?ver=20228b0075">
4710
4711    <link rel="stylesheet" type="text/css" media="only screen and (max-width: 1024px)" href="//www.cincyticket.com/include/mobile.css?ver=20228b0075">
4712
4713</head>
4714
4715<body class="body-class default-font">
4716		
4717            <!-- CLIENT Google Tag Manager -->
vendor: 75 bytes, lines 4717-4718
4717
4718            <noscript><iframe src="//www.googletagmanager.com/ns.html?id=
4718GTM-WZ8HC5
vendor: 109 bytes, lines 4718-4720
4718"
4719            height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
4720            
4720<!-- End CLIENT Google Tag Manager -->
4721        
4722                <!-- PRIMARY Google Tag Manager -->
vendor: 79 bytes, lines 4722-4723
4722
4723                <noscript><iframe src="//www.googletagmanager.com/ns.html?id=
4723GTM-MDGF2K
vendor: 117 bytes, lines 4723-4725
4723"
4724                height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
4725                
4725<!-- End PRIMARY Google Tag Manager -->
4726            
4727<div style="position:relative;">
4728<button class="skip-nav" title="Skip to Main Content">Skip to Main Content</button>
4729</div>
4730<script type="text/javascript">
4731	$(function(){
4732		$(".main-container").attr("tabindex", 0);
4733	})
4734	$(".skip-nav").on("click", function(){
4735		console.log("s");
4736		$(".main-container").focus();
4737	});
4738</script>
4738
4739
4740<script type="text/javascript">
4741	window.SW_ADS_CONFIG = {
4742		cacheUrl: "//www.cincyticket.com/data/adLocations/adLocationCache.txt?ver=20228",
4743		writerUrl: "https://www.cincyticket.com/include/modules/Advertising/request/saveAdLocationCache.asp",
4744		logUrl: "https://www.cincyticket.com/include/modules/Advertising/request/logAdImpression.asp"
4745	};
4746</script>
vendor: 2 bytes, line 4746
4746
4747<script type="text/javascript" src="//www.cincyticket.com/include/modules/Advertising/banner-ads.js?ver=20228"></script>
4747
4748
4749
4750
4751	<div id="page-wrap"><!--Main Page Wrap - Ends in HTMLfooter-->
4752	<div id="fb-root"></div>
4753
4754	
4754<script>
4755		(function(d, s, id) {
4756		  var js, fjs = d.getElementsByTagName(s)[0];
4757		  if (d.getElementById(id)) return;
4758		  js = d.createElement(s); js.id = id;
4759		  js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=0";
4760		  fjs.parentNode.insertBefore(js, fjs);
4761		}(document, 'script', 'facebook-jssdk'));
4762	</script>
4762
4763
4764	
4765        <!-- BEGIN Mobile Navigation BEGIN -->
4766		<nav class="navigation sw-nav mobile-only">
4767            <i id="menu-icon" class="sw-icon-menu" style="display:inline-block;" onClick="actMenu();hideWidgets();"></i>
4768            <div class="tab-nav-wrap">
4769                
4770                <a class="tab-nav" HREF="https://www.cincyticket.com/myaccount.asp?gifrompage=1&gitopage=1">my account</a>
4771            </div>
4772            <ul id="mobile-menu" onClick="actMenu();">
4773                    <!--<li><a HREF="/">home</a></li>       <!--CLIENT Home URL-->
4774                    <li><a HREF="https://www.cincyticket.com/default.asp">ticketing home</a></li>
4775                    <li class="mobile-only"><a HREF="https://www.cincyticket.com/myaccount.asp?gifrompage=1&gitopage=1">my account</a></li>
4776                    <li class="sw-sep mobile-only"></li>
4777                    
4778                        <li class="sw-sep no-tab"></li>
4779                    
4780                        <li><a onClick="actSearch();actMenu();return 0">search</a></li>
4781                    
4782                        <li class="mobile-calendar-option"><a onClick="actWidget('calendar');return 0;">calendar</a></li>
4783                    
4784                        <li><a onClick="actWidget('categories');return 0;">categories</a></li>
4785                    
4786                        <li><a onClick="actWidget('venues');return 0;">venues</a></li>
4787                    
4788                    <li class="sw-sep"></li>
4789                    <li><a HREF="https://www.cincyticket.com/basket.asp">shopping cart</a></li>
4790                    
4791                    <li class="sw-sep"></li>
4792                    <li><a href="https://www.cincyticket.net/help">contact us</a></li>
4793                    <li><a href="https://www.cincyticket.net/faq">FAQ</a></li>
4794					<li><a href="https://www.cincyticket.net/">Sell Tickets With Us</a></li>
4795                    <li class="sw-sep"></li>
4796                    <li onClick="actMenu();hideWidgets();"><a >close</a></li>
4797                </ul>
4798            <a style="color:inherit;" href="http://www.cincyticket.com/basket.asp"><i class="sw-icon-basket" style="float:right;"></i></a>
4799            
4800                <i class="sw-icon-search" style="float:right;" onClick="actSearch();"></i>
4801                <div id="swSearch" style="display:none;">
4802                    <input type="text" id="swSearchTxt" value="" placeholder="search events, venues, artists etc..." />
4803                    
4803<script type="text/javascript">
4804                        $('#swSearchTxt').keyup(function (e) {
4805                            if (e.which === 13) {
4806                                //update the performance list
4807                                updatePerformanceList_Search($("#swSearchTxt").val())
4808                            }
4809                        })
4810
4811                    </script>
4811
4812                </div>
4813            
4814        </nav>
4815        <!--END Mobile Navigation END -->
4816        <header class="mobile-header mobile-only">
4817            <!--custom branding location for mobile -->
4818            <!--Header Ads can be placed here if client desires:
4819            <div class='sw-banner-ad' data-sw-ad-location='header_mobile'></div>
4820            -->
4821            <a href="https://www.cincyticket.com/"><img src="../Images/mobile-logo.png"></a>
4822        </header>
4823        
4823<script type="text/javascript">
4824            $(function () {
4825                $(".control-box").append("<a class='close-widget mobile-only' onclick='hideWidgets()'>close</a>");
4826            })
4827       </script>
4827
4828	
4829	<header class="head-wrap no-mobile">
4830        <!--This header will not be present on mobile. Use the mobile header area if a branding location for mobile is required.-->
4831		<div class="head-inner center-div site-width">
4832			<a href="https://www.cincyticket.com/"><img src="../Images/top_header.jpg" border="0" hidefocus="true" style="width: 100%;"></a>
4833
4834            <div class="clear-float"></div>
4835            <div class="nav-container">
4836           	  <ul class="showare-nav">
4837               	  <li><img src="../Images/left_nav.gif" border="0" usemap="#Map2" hidefocus="true">
4838                      <map name="Map2">
4839                      	<area shape="rect" coords="8,4,84,22" href="http://www.cincyticket.com/default.asp">
4840                        <area shape="rect" coords="119,4,178,23" href="https://www.cincyticket.net/faq">
4841                        <area shape="rect" coords="217,4,336,23" href="https://www.cincyticket.net/help">
4842                        <area shape="rect" coords="370,4,550,23" href="https://www.cincyticket.net/"></map>
4843                   </li>
4844                	<li class="basket-widget"><div id="ShoWareBasketWidget" class="internal"></div></li>
4845                    <li style="float: right;"><a href="http://www.cincyticket.com/myaccount.asp?gifrompage=1&gitopage=1"><img src="../Images/nav-account.gif"></a></li>
4846              </ul>
4847                <div class="clear-float"></div>
4848            </div>
4849            
4850		</div><!--END head-inner END-->
4851	</header><!--END head-wrap END-->
4852
4853
4854	
4855
4856	<!--MAIN BODY-->
4857	<div class="content-wrap"><!--Main Content Wrap - this and content-inner end in HTMLfooter-->
4858		<div class="content-inner center-div site-width">
4859		    
4860			<!--LEFT SIDE-->
4861			<div class="control-wrap hide-wrap">	
4862				
4863					<div class="control-box search-control">
4864						<span class="heading-text">Search</span>
4865						<!--<img src="images/hdrCategories.gif" width="162" height="20" alt="" border="0"><br>-->
4866						
4867<input class="search-text showare-text" type="text" size="16" name="SearchText" value="" placeholder="search..."><input id="searchButton" class="search-button; " type="button" name="Go" value="Go"/>
4868<script language="javascript">
4869    $('.search-text').keyup(function(e) {
4870        if(e.which === 13){
4871            //update the performance list
4872            
4873            updatePerformanceList_Search($(".search-text").val());
4874            
4875        }
4876    })        
4877    $("#searchButton").click(function(){
4878        
4879        updatePerformanceList_Search($(".search-text").val())
4880        
4881    });
4882    function updatePerformanceList_Search(searchVal) {
4883        
4884            window.location.href= "/default.asp?search="+searchVal
4885        
4886    }
4887    function updateStreamlinedEventList_Search(searchVal) {
4888        
4889            window.location.href= "/default.asp?search="+searchVal
4890        
4891    }
4892</script>
4892
4893					</div>
4894				
4895					<div id="categoriesWidget" class="control-box categories-control">
4896			 			<span class="heading-text">Categories</span>
4897						<!--<img src="images/hdrCategories.gif" width="162" height="20" alt="" border="0"><br>-->
4898						
4899
4900<select id="categorySelect" class="showare-select" aria-label="Select a Category">
4901    <option value="0">Select a Category</option>
4902</select>
4903<script language="javascript">
4904    var CategoriesExpireTime = new Date().getTime(); var isExpired = false; var CategoriesData = "";
4905    try {
4906        //check for local storage support
4907        isExpired = CategoriesExpireTime > Number(localStorage.getItem("CategoriesExpireTime"));
4908        if(isExpired){
4909            //item expired, clear local results
4910            localStorage.setItem("ShoWareCategories", "");
4911        }
4912        localStorage.setItem("CategoriesExpireTime", CategoriesExpireTime + (1000 * 60 * 60 * 24));  //item information expires after 24 hours
4913        CategoriesData = localStorage.getItem("ShoWareCategories");
4914    } catch(e){
4915        CategoriesData = "";
4916    }
4917    function getCategories(){
4918        //attempt to get local data for widget
4919        if(CategoriesData == "" || CategoriesData == null){
4920            //no data found, pull data from request
4921            $.getJSON("https://www.cincyticket.com/include/widgets/controls/RequestCategories.asp")
4922            .done(function (data) {
4923                //build select box
4924                populateCategories(data);
4925                try{
4926                    localStorage.setItem("ShoWareCategories",JSON.stringify(data));
4927                }catch(e){
4928                    console.log("No local storage");
4929                }
4930            })
4931            .fail(function (jqxhr, textStatus, error) {
4932                var err = textStatus + ", " + error;
4933                console.log("Request Failed: " + err);
4934            })
4935        }else{
4936            CategoriesData = JSON.parse(CategoriesData);
4937            populateCategories(CategoriesData);
4938        }
4939    }
4940    function populateCategories(categoryOptions){
4941        oSelect = document.getElementById("categorySelect");
4942        for(var i = 0; i < categoryOptions.length; i++){
4943            //add an option for each category in data
4944            if (categoryOptions[i].CatActive == 1 && categoryOptions[i].IsHidden != 1)
4945            {
4946                var opt = document.createElement("option");
4947                opt.value = categoryOptions[i].ID;
4948                if(categoryOptions[i].Rank == 1){
4949                    opt.innerHTML = categoryOptions[i].Name;
4950                    opt.style.fontWeight = "bold";
4951                }else{
4952                    opt.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;" + categoryOptions[i].Name;
4953                }
4954                oSelect.appendChild(opt);
4955            }            
4956        }
4957        $("#categorySelect").val(0);
4958        }
4959    getCategories();
4960    var gCategoryVal = 0
4961    $("#categorySelect").change(function(){
4962        updatePerformanceList_Category($(this).val())
4963        gCategoryVal = $(this).val();
4964    });
4965    function updatePerformanceList_Category(categoryVal) {
4966        
4967            window.location.href= "/default.asp?category="+categoryVal;
4968        
4969    }
4970	
4971	var headerDP = "";	
4972    if ($("#categorySelect").length == 0 || 'True' == 'False'){ 
4973    	headerDP = buildDatepicker({ "calendarID": "headerCalendar", "linkedInputID": "headerCalendarInput", "isModal": false, "forceDates": true, "defaultDate": "9/1/2026"});
4974    }	
4975    function updateCalendarDateByCategory(categoryVal)
4976    {   
4977        
4978            return;
4979        
4980
4981    }
4982</script>
4982
4983					</div>
4984				
4985					<div id="calendarWidget" class="control-box calendar-control">
4986						<span class="heading-text">Browse Dates</span>
4987						<!--<img src="images/hdrDates.gif" width="162" height="20" alt="" border="0"><br>-->
4988						
4989<input type="hidden" id="headerCalendarInput" value=""/>
4990<div id="headerCalendar" class="sw-datepicker"><link rel="stylesheet" href="/include/font-awesome/css/font-awesome.min.css" />
4991<div tabindex="0" class="calendar-object" style="position:relative;">
4992    <style type="text/css" scoped>
4993        .sw-datepicker
4994        {
4995            font-size:inherit;/*Calendar size is determined by parent's font size.*/
4996        }
4997         .sw-datepicker.large-datepicker
4998        {
4999            margin-top: 20px;
5000        }
5001        .sw-datepicker[aria-hidden=true]
5002        {
5003            display:none;
5004        }
5005
5006        .sw-datepicker.is-modal{
5007            margin: 10px;
5008            padding: 2px;
5009            -webkit-border-radius: 4px;
5010            -moz-border-radius: 4px;
5011            border-radius: 4px;
5012            position: absolute;
5013            top:30px;
5014            left:0px;
5015            z-index:99;
5016            background-color: #fff;
5017            border: 1px solid #ccc;
5018            box-shadow: 0px 0px 6px RGBA(0,0,0,0.4);
5019        }
5020            .sw-datepicker.is-modal.right-side
5021            {
5022                left:auto;
5023                right:0px;
5024            }
5025        .sw-datepicker .month-wrap
5026        {
5027            background-color: #337ab7;
5028            border: 1px solid #2e6da4;
5029            -webkit-border-radius: 4px;
5030            -moz-border-radius: 4px;
5031            border-radius: 4px;
5032            text-align:center;
5033        }
5034        .sw-datepicker .bn_next, div.bn_prev{
5035            margin: 2px;
5036            border:1px solid transparent;
5037            line-height:1.3em;
5038            color:#fff;
5039            padding:0 .25em;
5040            font-weight:bold;
5041            cursor:pointer;
5042        }
5043        .sw-datepicker .bn_prev
5044        {
5045            float: left;
5046        }
5047
5048        .sw-datepicker .bn_next
5049        {
5050            float: right;
5051        }
5052
5053            .sw-datepicker .bn_prev:hover,
5054            .sw-datepicker .bn_prev:focus,
5055            .sw-datepicker .bn_next:hover,
5056            .sw-datepicker .bn_next:focus
5057            {
5058                margin: 2px;
5059                background-color: #4fbae0;
5060                border: 1px solid #00a4df;
5061                -webkit-border-radius: 4px;
5062                -moz-border-radius: 4px;
5063                border-radius: 4px;
5064            }
5065
5066        .sw-datepicker .bn_img
5067        {
5068            margin: 0;
5069            padding: 2px;
5070        }
5071
5072        .sw-datepicker .month
5073        {
5074            display:inline-block;
5075            line-height:1.5em;
5076            font-weight: bold;
5077            font-size: 1.2em;
5078            color:#fff;
5079        }
5080
5081        .sw-datepicker .cal
5082        {
5083            font-size: 1.2em;
5084            text-align: center;
5085        }
5086
5087
5088        .sw-datepicker .offscreen
5089        {
5090            position: absolute;
5091            left: -200em;
5092            top: -100em;
5093        }
5094        .sw-datepicker td.day-cell.highlight-day{
5095            cursor:pointer;
5096        }
5097        td span.calendar-day{
5098            display:inline-block;
5099            height:1.5em;
5100            width:1.5em;
5101            line-height:1.5em;
5102            border-radius:3px;
5103            margin:.1em;
5104            position:relative;
5105        }
5106        td.highlight-day span.calendar-day{
5107            border:1px solid #337ab7;
5108            background:#fcfcfc;
5109            color:#00458A;
5110            cursor:pointer;
5111        }
5112        td.limited-availability:after{
5113            content:'!';
5114            display:inline-block;
5115            font-weight:bold;
5116            position:absolute;
5117            top:3px;
5118            right:5px;
5119            font-size:3vw;
5120            color:#aa0;
5121        }
5122        .sw-datepicker abbr{
5123            text-decoration:none;
5124            opacity:1;
5125            display:inline-block;
5126            margin:.3em 0;
5127        }
5128        td.today{
5129            background:#eee;
5130        }
5131        td.focus{
5132            background:#8ecae0;
5133        }
5134        .sw-datepicker td{
5135            position:relative;
5136        }
5137        .sw-datepicker.large-datepicker, .sw-datepicker.large-datepicker table{
5138            width:100%;
5139        }
5140        .sw-datepicker.large-datepicker .month-wrap{
5141            font-size:1.5em;
5142            background:RGBA(255,255,255,0.0);
5143            border:none;
5144            border-bottom:1px solid #eee;
5145        }
5146        .sw-datepicker.large-datepicker .month-wrap *{
5147            color:inherit!important;
5148        }
5149        .sw-datepicker.large-datepicker .day-cell{
5150            height:8vh;
5151            width:14%;
5152            border:1px solid #eee;
5153            opacity:.7;
5154            transition:opacity .5s;
5155        }
5156        .sw-datepicker.large-datepicker .day-cell.highlight-day{
5157            opacity:1;
5158        }
5159        .sw-datepicker.large-datepicker td span.calendar-day{
5160            position:absolute;
5161            top:5px;
5162            left:5px;
5163            font-size:.7em;
5164            text-align:center;
5165            font-weight:bold;
5166            height:2em;
5167            width:2em;
5168            padding:.25em;
5169            line-height:1.3em;
5170            display:inline-block;
5171            background:RGBA(255,255,255,0.0);
5172            border:none;
5173            pointer-events:none;
5174        }
5175        .sw-datepicker .date-info-box{
5176            font-size: 1.5vw;
5177            padding: 30px 5px 15px;
5178            display: block;
5179            position: relative;
5180        }
5181        .sw-datepicker .date-info-box .display-perfstatus{
5182            font-size: .72vw;
5183            display: block;
5184            text-align: center!important;
5185            padding: 5px 10px;
5186            border: 1px solid var(--gap-error);
5187            border-radius: 8px;
5188            color: var(--gap-error);
5189            width: 90%;
5190            margin: auto;
5191            box-sizing: border-box;
5192            background: rgba(222,27,60,.05);
5193        }
5194        .sw-datepicker .date-info-box .display-perfprice{
5195            font-size: 1vw;
5196        }
5197        .sw-datepicker .date-info-box .display-perfprice-withchild{
5198            font-size: 1vw;
5199        }
5200        .sw-datepicker .date-info-box .display-perfname{
5201            font-size: .8vw;
5202            display: block;
5203            text-align: center;
5204            padding: 0px 10px;
5205            
5206        }
5207        .sw-datepicker .date-info-box .display-perftime{
5208            font-size: .93vw;
5209            display: block;
5210            padding-top: 5px;
5211        }
5212        .sw-datepicker .date-info-box .display-perfbuybutton{
5213            font-size: .7vw;
5214            display: block;
5215            padding: 5px 10px;
5216            width: 90%;
5217            margin: 5px auto;
5218        }
5219        .sw-datepicker .date-sub-note{
5220            font-style: italic;
5221            font-size: .93vw;
5222            opacity: .8;
5223            position: absolute;
5224            bottom: auto;
5225            top: 0px;
5226            padding-bottom: 20px;
5227            padding-top: 15px;
5228            margin-bottom: 30px;
5229            width: 100%;
5230        }
5231        @media only screen and (max-width: 1500px){
5232            .sw-datepicker .date-info-box .display-perfname{
5233                font-size: 1.1vw;
5234            }
5235            .sw-datepicker .date-info-box .display-perftime, 
5236            .sw-datepicker .date-info-box .display-perfprice,
5237            .sw-datepicker .date-info-box .display-perfprice-withchild{
5238                font-size: 1.2vw;
5239            }
5240            .sw-datepicker .date-info-box .display-perfbuybutton{
5241                font-size: 1vw;
5242            }
5243        }
5244        @media only screen and (max-width: 1300px){
5245            .sw-datepicker .date-info-box .display-perfname{
5246                font-size: 1.3vw;
5247            }
5248            .sw-datepicker .date-info-box .display-perftime, 
5249            .sw-datepicker .date-info-box .display-perfprice,
5250            .sw-datepicker .date-info-box .display-perfprice-withchild{
5251                font-size: 1.3vw;
5252            }
5253        }
5254        @media only screen and (max-width: 1024px){
5255            .sw-datepicker .date-sub-note{
5256                display:none!important;
5257            }
5258            .sw-datepicker .date-info-box .display-perfname{
5259                font-size: 12px;
5260            }
5261            .sw-datepicker .date-info-box .display-perftime, 
5262            .sw-datepicker .date-info-box .display-perfprice,
5263            .sw-datepicker .date-info-box .display-perfprice-withchild{
5264                font-size: 12px;
5265            }
5266            .sw-datepicker .date-info-box .display-perfbuybutton{
5267                font-size: 12px;
5268                white-space: unset;
5269                line-height: 1.2;
5270            }
5271            /* adjustment for coupon codes on mobile*/
5272            .couponecode-wrap {
5273                display: flex;
5274                flex-direction: row-reverse;
5275                align-items: stretch;
5276                flex-wrap: nowrap;
5277                gap: 20px;
5278                width: 100%;
5279            }
5280            #FilterSelect {
5281                margin-bottom: 8px;
5282            }
5283            #couponCodeSubmitButton {
5284                margin-top: 0;
5285            }
5286            #couponCode {
5287                flex: 1;
5288                height: auto;
5289            }
5290        }
5291        @media only screen and (max-width: 800px){
5292            .sw-datepicker.large-datepicker .day-cell {
5293                height: auto!important;
5294                width: 14%;
5295                min-height: 50px;
5296                border: 1px solid #eee;
5297                opacity: .7;
5298                transition: opacity .5s;
5299            }
5300            .sw-datepicker.large-datepicker table td.empty,
5301            .sw-datepicker.large-datepicker table th {
5302                width: 14%;
5303                min-width: 14%;
5304            }
5305            .sw-datepicker .date-info-box .display-perfbuybutton {
5306                width: 100%;
5307                line-height: 1.1!important;
5308                font-size: 11px!important;
5309                white-space: unset;
5310                padding: 5px!important;
5311            }
5312            .sw-datepicker .date-info-box .display-perftime, 
5313            .sw-datepicker .date-info-box .display-perfprice,
5314            .sw-datepicker .date-info-box .display-perfprice-withchild,
5315            .sw-datepicker .date-info-box .display-perfname{
5316                font-size: 11px;
5317
5318            }
5319            .sw-datepicker table tr {
5320                display: flex;
5321                justify-content: space-evenly;
5322            }
5323            .sw-datepicker .date-info-box .display-perfname{
5324                padding: 5px 0px 0;  
5325            }
5326            .sw-datepicker .date-info-box {
5327                overflow-wrap: normal;
5328            }
5329            .sw-datepicker.large-datepicker table td.empty,
5330            .sw-datepicker.large-datepicker table th,
5331            .sw-datepicker table td.empty,
5332            .sw-datepicker table th
5333            {
5334                width: calc((100% / 7) - 4px);
5335                min-width: 10%;
5336            }
5337            .sw-datepicker.large-datepicker .day-cell,
5338            .sw-datepicker .day-cell {
5339                width: calc((100% / 7) - 4px);
5340            }
5341            .sw-datepicker .day-cell.sold-out{
5342                padding-top: 35px!important;
5343                line-height: 1.2!important;
5344            }
5345        }
5346        @media only screen and (max-width: 550px){
5347            #epPerformanceList #eventCalendar {
5348                width: 100%;
5349            }
5350            .sw-datepicker .date-info-box .display-perfbuybutton {
5351                font-size: 7px!important;
5352                font-weight: 400!important;
5353            }
5354            .sw-datepicker .date-info-box .display-perftime, 
5355            .sw-datepicker .date-info-box .display-perfprice,
5356            .sw-datepicker .date-info-box .display-perfprice-withchild,
5357            .sw-datepicker .date-info-box .display-perfname{
5358                font-size: 10px;
5359
5360            }
5361            .sw-datepicker .day-cell.sold-out{
5362                padding-top: 30px!important;
5363                line-height: .9!important;
5364            }
5365            .sw-datepicker.large-datepicker table  tr{
5366                display: flex;
5367                justify-content: space-evenly;
5368            }
5369            .sw-datepicker.large-datepicker table td.empty,
5370            .sw-datepicker.large-datepicker table th,
5371            .sw-datepicker.large-datepicker table td,
5372            .sw-datepicker.large-datepicker .day-cell {
5373                width: calc(96vw / 7);
5374            }
5375            #TimeSelectModalBody {
5376                width: 100%!important;
5377            }
5378        }
5379        .sw-datepicker .day-cell.sold-out{
5380            opacity:.7!important;
5381            color:#a00;
5382            pointer-events:none;
5383        }
5384        .sw-datepicker .day-cell.muted{
5385            opacity:.3!important;
5386        }
5387
5388        .sw-datepicker .day-cell.coupon-muted{
5389            opacity:.3!important;
5390        }
5391
5392        .sw-datepicker .day-cell.password-hidden .date-info-box{
5393            display: none!important;
5394        }
5395
5396        .sw-datepicker .day-cell.muted .calendar-day{
5397            color:inherit!important;
5398            border:none!important;
5399            cursor:default!important;
5400        }
5401
5402        .sw-datepicker .day-cell.coupon-muted .calendar-day{
5403            color:inherit!important;
5404            border:none!important;
5405        }
5406        .sw-datepicker .day-cell.sold-out .date-info-box{
5407            display:none;
5408        }
5409        .sw-datepicker .day-cell.sold-out .calendar-day{
5410            color:#a00;
5411            border:none;
5412            text-decoration:line-through;
5413        }
5414        @media only screen and (max-width: 1024px){
5415            .sw-datepicker .date-info-box, .sw-datepicker .sold-out-info-box{
5416                font-size:2vw;
5417            }
5418        }
5419        .calendar-loading{
5420            position:absolute;
5421            top:50%;
5422            left:50%;
5423            font-size:4vw;
5424            font-weight:bold;
5425            color:RGBA(0,0,0,0.4);
5426            width:66vw;
5427            margin-left:-33vw;
5428            height:20vw;
5429            margin-top:-10vh;
5430            line-height:20vw;
5431            text-align:center;
5432            background:RGBA(255,255,255,0.9);
5433            border-radius:1em;
5434            border:1px solid RGBA(0,0,0,0.4);
5435            box-shadow:2px 2px 4px RGBA(0,0,0,0.2);
5436        }
5437        .limited-availability-legend-item{
5438            text-align:right;
5439        }
5440        .calendar-limited-availability-legend-icon{
5441            font-weight:bold;
5442            color:#aa0;
5443        }
5444        .calendar-dayoftheweek {display: none!important;}
5445        #calendarWidget .calendar-dayoftheweek {display: none!important;}
5446    </style>
5447
5448    <div class="month-wrap">
5449        <div class="bn_prev" role="button" aria-labelledby="bn_prev-label" tabindex="0" title="Previous Month"><i class="fa fa-backward" aria-hidden="true"></i></div>
5450        <div tabindex="0" class="month" role="heading" aria-live="assertive" aria-atomic="true">Loading...</div>
5451        <div class="bn_next" role="button" aria-labelledby="bn_next-label" tabindex="0" title="Next Month"><i class="fa fa-forward" aria-hidden="true"></i></div>
5452    </div>
5453    <table title="Search Date - Select a date to search" class="cal" role="grid" aria-labelledby="month" tabindex="0" style="margin: 0px auto;outline:none!important;">
5454        <thead>
5455        <tr class="weekdays">
5456            <th class="Sunday"><abbr title="Sunday">Su</abbr></th>
5457            <th class="Monday"><abbr title="Monday">Mo</abbr></th>
5458            <th class="Tuesday"><abbr title="Tuesday">Tu</abbr></th>
5459            <th class="Wednesday"><abbr title="Wednesday">We</abbr></th>
5460            <th class="Thursday"><abbr title="Thursday">Th</abbr></th>
5461            <th class="Friday"><abbr title="Friday">Fr</abbr></th>
5462            <th class="Saturday"><abbr title="Saturday">Sa</abbr></th>
5463        </tr>
5464        </thead>
5465        <tbody>
5466            <tr><td class="errMsg" colspan="7">Loading...</td></tr>
5467        </tbody>
5468    </table>
5469    <div class="bn_prev-label offscreen">Go to previous month</div>
5470    <div class="bn_next-label offscreen">Go to next month</div>
5471    <div class="calendar-loading" style="display:none;"><i class="fa fa-spin fa-spinner" style="margin-right:.5em;"></i>Loading...</div>
5472</div>
5473<div class="calendar-notes-wrap"></div>
5474</div>
5475<script type="text/javascript">
5476	var headerDP = "";	
5477    if ($("#categorySelect").length == 0 || 'True' == 'False')
5478    	headerDP = buildDatepicker({ "calendarID": "headerCalendar", "linkedInputID": "headerCalendarInput", "isModal": false, "forceDates": true, "defaultDate": "9/1/2026", "corporatePartnerPage":0});
5479 	$("#headerCalendarInput").on("change", function () {
5480        var properDate = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
5481        if (!properDate.test($(this).val())) {
5482            console.log("Main calendar attempted an invalid date: " + $(this).val());
5483            return;//invalid date
5484        }
5485		
5486        window.location.href= "/default.asp?searchdate="+$(this).val()+"";        
5487    });
5488    extractIcons();
5489</script>
5489
5490
5491
5492
5493					</div>
5494				
5495					<div id="venuesWidget" class="control-box venue-control">
5496						<span class="heading-text">Browse by Venue</span>
5497						
5498					
5499							
5500							
5501<select id="venueSelect" class="showare-select" name="venue" aria-label="Choose Venue">
5502	<option value="0"> Choose Venue </option>
5503</select>
5504<div align="right">
5505    <a  class="button small-button sw-button-muted" style="margin-top:1em;margin-right:0px;" href="//www.cincyticket.com/venuelisting.asp">View Venue listing</a>
5506</div>		
5507					
5508<script language="javascript">
5509    var VenuesExpireTime = new Date().getTime(); var isExpired = false; var VenuesData = "";
5510    try {
5511        //check for local storage support
5512        isExpired = VenuesExpireTime > Number(localStorage.getItem("VenuesExpireTime"));
5513        if(isExpired){
5514            //item expired, clear local results
5515            localStorage.setItem("ShoWareVenues", "");
5516        }
5517        localStorage.setItem("VenuesExpireTime", VenuesExpireTime + (1000 * 60 * 60 * 24));  //item information expires after 24 hours
5518        VenuesData = localStorage.getItem("ShoWareVenues");
5519    } catch(e){
5520        VenuesData = "";
5521    }
5522    function getVenues(){
5523        //attempt to get local data for widget
5524        if(VenuesData == "" || VenuesData == null){
5525            //no data found, pull data from request
5526            $.getJSON("https://www.cincyticket.com/include/widgets/controls/RequestVenues.asp")
5527            .done(function (data) {
5528                //build select box
5529                populateVenues(data);
5530                try{
5531                    localStorage.setItem("ShoWareVenues",JSON.stringify(data));
5532                }catch(e){
5533                    console.log("No local storage");
5534                }
5535            })
5536            .fail(function (jqxhr, textStatus, error) {
5537                var err = textStatus + ", " + error;
5538                console.log("Request Failed: " + err);
5539            });
5540        }else{
5541            VenuesData = JSON.parse(VenuesData);
5542            populateVenues(VenuesData);
5543        }
5544    }
5545    function populateVenues(venueOptions){
5546        oSelect = document.getElementById("venueSelect");
5547        for(var i = 0; i < venueOptions.length; i++){
5548            //add an option for each venue in data
5549            var opt = document.createElement("option");
5550            opt.value = venueOptions[i].ID;
5551            opt.innerHTML =  venueOptions[i].Name;
5552            oSelect.appendChild(opt);
5553        }
5554        $("#venueSelect").val(0);
5555        }
5556    getVenues();
5557
5558    $("#venueSelect").change(function(){
5559        updatePerformanceList_Venue($(this).val())
5560    });
5561    function updatePerformanceList_Venue(venueVal) {
5562        
5563            window.location.href= "/default.asp?venue="+venueVal;
5564        
5565        }
5566</script>
5566
5567					</div>
5568				
5569					<div id="infoWidget" class="control-box info-control">
5570						<span class="heading-text">Information</span>
5571						<!--<img src="images/hdrInfo.gif" width="162" height="20" alt="" border="0"><br>-->
5572						<span class="info-text small-text"><p><strong>Customer Service:</strong><br /> <span style="text-decoration: underline;"><span style="font-size: medium;"><a href="https://www.cincyticket.net/help">CONTACT US</a></span></span><br /><br /> 9891 Montgomery Rd.<br />Suite 189<br /> Cincinnati, OH 45242</p>
5573<a href="https://www.facebook.com/cincyticket" target="_blank"><img src="https://www.cincyticket.com/uplimage/icon_facebook.png" alt="" width="35" height="35" /></a>&nbsp;<a href="https://www.twitter.com/cincyticket" target="_blank"><img src="https://www.cincyticket.com/uplimage/icon_twitter.png" alt="" width="35" height="35" /><br /></a>
5574<p><a href="https://www.cincyticket.net" target="_blank"><img src="../uplimage/sellticketswithus_new.png" alt="" border="0" /></a></p>
5575<center><em><br />Ticketing System by</em><br /><a href="https://www.cincyticket.net" target="_blank"><img src="../uplimage/cincyticket_logo_clearbg.png" alt="" border="0" /></a></center><!-- Meta Pixel Code -->
5576<script>// <![CDATA[
vendor: 408 bytes, lines 5576-5585
5576
5577!function(f,b,e,v,n,t,s)
5578{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
5579n.callMethod.apply(n,arguments):n.queue.push(arguments)};
5580if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
5581n.queue=[];t=b.createElement(e);t.async=!0;
5582t.src=v;s=b.getElementsByTagName(e)[0];
5583s.parentNode.insertBefore(t,s)}(window, document,'script',
5584'https://connect.facebook.net/en_US/fbevents.js');
5585fbq('init', '
5585802935397828854
vendor: 32 bytes, lines 5585-5586
5585');
5586fbq('track', 'PageView');
5587// ]]></script>
5587
5588<noscript><img height="1" width="1" style="display:none"
5589src="https://www.facebook.com/tr?id=802935397828854&ev=PageView&noscript=1"
5590/></noscript><!-- End Meta Pixel Code --></span>
5591					</div>
5592				
5593					<a class="reporting-link" href="/reporting/login.asp">Promoter Login</a>
5594				
5595				<div class="ads-control">
5596					<center>
5597					<div class='sw-banner-ad' data-sw-ad-location='side_01'></div><div class='sw-banner-ad' data-sw-ad-location='side_02'></div><div class='sw-banner-ad' data-sw-ad-location='side_03'></div><div class='sw-banner-ad' data-sw-ad-location='side_04'></div><div class='sw-banner-ad' data-sw-ad-location='side_05'></div><div class='sw-banner-ad' data-sw-ad-location='side_06'></div><div class='sw-banner-ad' data-sw-ad-location='side_07'></div><div class='sw-banner-ad' data-sw-ad-location='side_08'></div><div class='sw-banner-ad' data-sw-ad-location='side_09'></div><div class='sw-banner-ad' data-sw-ad-location='side_10'></div>
5598					</center>
5599				</div>					
5600				
5601                    <!--Special basket widget to notify users that a ticket has changed-->
5602                    <div id="basketChangeWidget" class="control-box basket-change" style="width:100%;">
5603                        <span style="text-align:center;font-weight:bold;display:block;">Your basket has been updated.</span>
5604                        <span style="text-align:center;display:block;">You will have a chance to review your order during <a style="font-weight:bold;" href='#' onclick='$("#checkout-button").click();'>checkout</a></span>
5605                    </div>
5606                
5607			</div><!--END control-wrap END-->
5608			<!--END LEFT SIDE-->
5609			<div id="epImage2"></div>
5610
5611			<div class="main-container ">
5612				<!-- Main Area -->
5613				
5614				<!-- end HTMLheader.asp -->
5615
5616<div id="ng-app" ng-app='Showare' class="basket-wrap">
5617	<link rel="stylesheet" type="text/css" href="/admin/include/select.css?ver=20228b0075"/>
5618<script src="/admin/include/angular.1.8.min.js?ver=20228b0075"></script>
vendor: 2 bytes, line 5618
5618
5619<script src="/admin/include/ui-bootstrap-custom-tpls-2.1.3.min.js?ver=20228b0075"></script>
vendor: 2 bytes, line 5619
5619
5620<script src="/admin/include/select.js?ver=20228b0075"></script>
vendor: 2 bytes, line 5620
5620
5621<script type="text/javascript" src='/admin/include/angular/dependencies/date.angular1.5.js'></script>
vendor: 2 bytes, line 5621
5621
5622<script type="text/javascript" src='/admin/include/angular/dependencies/tinymce.angular1.5.js'></script>
vendor: 2 bytes, line 5622
5622
5623<script>
5624
5625var app = angular.module('Showare', ['Showare.Controllers', 'Showare.Services', 'Showare.Directives'], function ($httpProvider) {
5626    // Use x-www-form-urlencoded Content-Type
5627	$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
5628	
5629	// Override $http service's default transformRequest to use form serialization
5630	$httpProvider.defaults.transformRequest = [function(data) {
5631		if(angular.isObject(data) && String(data) !== '[object File]') {
5632			data.sessionKey = v1Session.sessionKey;
5633			
5634			return jQuery.param(data);
5635		} else {
5636			return data;
5637		}
5638	}];
5639})
5640.config([
5641  '$provide', function($provide) {
5642    return $provide.decorator('$rootScope', [
5643      '$delegate', function($delegate) {
5644        $delegate.$safeApply = function(fn) {
5645          var phase = $delegate.$$phase;
5646          if (phase === "$apply" || phase === "$digest") {
5647            if (fn && typeof fn === 'function') {
5648              fn();
5649            }
5650          } else {
5651            $delegate.$apply(fn);
5652          }
5653        };
5654        return $delegate;
5655      }
5656    ]);
5657  }
5658])
5659.value('tinymceOptions', {
5660  theme: "modern",
5661  skin: 'light',
5662  statusbar: false,
5663  menubar: false,
5664  plugins: 'code textcolor image link paste',
5665  paste_as_text: true,
5666  width: 620,
5667  height: 145,
5668  force_br_newlines: false,
5669  force_p_newlines: false,
5670  convert_urls: false,
5671  remove_script_host: false,
5672  forced_root_block: '',
5673  extended_valid_elements: "script[charset|defer|language|src|type], style[type|media]",
5674  valid_children : "+body[style]",
5675  toolbar: 'undo redo | bold italic underline strikethrough | alignleft alignjustify alignright al
5675igncenter | bullist numlist | forecolor backcolor fontsizeselect | link unlink code removeformat | image'
5676});
5677
5678var controllerModule = angular.module('Showare.Controllers', ['ui.select', 'ui.bootstrap', 'ui.date', 'ui.timepicker', 'ui.tinymce']);
5679var serviceModule = angular.module('Showare.Services', []);
5680var directiveModule = angular.module('Showare.Directives', []);
5681
5682
5683</script>
5683
5684
5685	
5685<script type="text/javascript" src="include/underscore.min.js"></script>
5685
5686	
5686<script type="text/javascript" src='admin/include/angular/controllers/BasketCtrl.js'></script>
5686
5687	
5687<script type="text/javascript" src='admin/include/angular/services/UnderscoreService.js'></script>
5687
5688	
5688<script type="text/javascript" src="//www.cincyticket.com/include/modules/paymentPlans/ppFunctions.js"></script>
5688
5689	
5689<script type="text/javascript">
5690/**
5691 * Basket Payment Plan Widget - Client-side functionality
5692 * Handles payment plan selection, calculations, and UI updates in basket.asp
5693 */
5694
5695(function() {
5696    'use strict';
5697    
5698    var basketPaymentPlan = {
5699        currentTotal: 0,
5700        selectedPlanId: 0,
5701        selectedInstallments: 0,
5702        // --- new ---
5703        tilaDataCache: {},
5704        tilaAccepted: false,
5705        tilaModalShowing: false,
5706        
5707        /**
5708         * Initialize the basket payment plan widget
5709         */
5710        init: function() {                        
5711            // Get current basket total from the page
5712            this.updateBasketTotal();
5713            
5714            // Set up event listeners
5715            this.bindEvents();
5716            
5717            // No longer calculate amounts client-side - they come pre-calculated from server
5718            // this.updateAllPlanAmounts();
5719            
5720            // Set initial selection
5721            this.updateSelection();
5722            // Read any pre-selected radio (server may have marked one based on session)
5723            var $checked = $('input[name="basket_pp_option"]:checked');
5724            if ($checked.length) {
5725                this.selectedPlanId = parseInt($checked.data('plan-id')) || 0;
5726                this.selectedInstallments = parseInt($checked.data('installments')) || 0;
5727                $('#basket_selected_payment_plan_id').val(this.selectedPlanId);
5728                if (this.selectedPlanId > 0) {
5729                    // Preload TILA terms for preselected plan
5730                    this.preloadTila(this.selectedPlanId);
5731                }
5732            }
5733            this.ensureHiddenFields();
5734                       
5735            // Update Due Today if a plan was preselected
5736            if (this.selectedPlanId > 0) {
5737                this.updateDueToday();
5738            }
5739        },
5740        
5741        /**
5742         * Bind event listeners
5743         */
5744        bindEvents: function() {
5745            var self = this;
5746            
5747            // Handle payment plan selection
5748            $(document).on('change', 'input[name="basket_pp_option"]', function() {
5749                self.handlePlanSelection($(this));
5750            });
5751            
5752            // Show the payment schedule detail modal for a specific plan
5753            $(document).on('click', '.basket-pp-view-schedule', function(e) {
5754                e.preventDefault();
5755                e.stopPropagation();
5756                var planId = parseInt($(this).data('plan-id')) || 0;
5757                var planName = $(this).data('plan-name') || '';
5758                self.showScheduleModal(planId, planName);
5759            });
5760            
5761            // // Listen for basket total changes (if basket updates dynamically)
5762            $(document).on('basketTotalUpdated', function(event, newTotal) {
5763                self.currentTotal = parseFloat(newTotal);
5764                self.updateAllPlanAmounts();
5765            });
5766        },
5767        
5768        // --- new: ensure hidden field for TILA acceptance ---
5769        ensureHiddenFields: function() {
5770            if ($('#basket_tila_accepted').length === 0) {
5771                var $form = $('#basketForm');
5772                if ($form.length === 0) { $form = $('form').first(); }
5773                $form.append('<input type="hidden" id="basket_tila_accepted" name="basket_tila_accepted" value="0">');
5774            }
5775        },
5776        
5777        shouldRequireTila: function() {
5778            return this.selectedPlanId > 0 && typeof this.tilaDataCache[this.selectedPlanId] !== 'undefined';
5779        },
5780        
5781        /**
5782         * Handle payment plan selection change
5783         */
5784        handlePlanSelection: function($radio) {
5785            var planId = parseInt($radio.data('plan-id')) || 0;
5786            var installments = parseInt($radio.data('installments')) || 0;
5787            
5788            this.selectedPlanId = planId;
5789            this.selectedInstallments = installments;
5790            this.tilaAccepted = false;
5791            $('#basket_tila_accepted').val('0');
5792            
5793            // Preload TILA si plan > 0
5794            if (planId > 0) {
5795                this.preloadTila(planId);
5796            } else {
5797                // Pay in Full selected: clear any previously stored payment plan
5798                // data from the user session (mirrors the TILA modal'
5798s Pay in Full path)
5799                $.ajax({
5800                    url: '/include/modules/paymentPlans/requests/ppAjax.asp',
5801                    method: 'POST',
5802                    dataType: 'json',
5803                    async: true,
5804                    data: {
5805                        action: 'removePaymentPlanSessions',
5806                        sessionKey: ''
5807                    }
5808                });
5809            }
5810            
5811            // Update hidden field
5812            $('#basket_selected_payment_plan_id').val(planId);
5813            
5814            // Update visual selection
5815            this.updateSelection();
5816            
5817            // Update "Due Today" section if payment plan is selected
5818            this.updateDueToday();
5819            
5820            // Trigger event for other components
5821            $(document).trigger('basketPaymentPlanChanged', {
5822                planId: planId,
5823                installments: installments,
5824                total: this.currentTotal
5825            });
5826                        
5827        },
5828        
5829        /**
5830         * Update visual selection state
5831         */
5832        updateSelection: function() {
5833            // Remove selected class from all options
5834            $('.payment-option-row').removeClass('selected');
5835            
5836            // Add selected class to current selection
5837            $('input[name="basket_pp_option"]:checked').closest('.payment-option-row').addClass('selected');
5838        },
5839        
5840        /**
5841         * Get current basket total from the page
5842         */
5843        updateBasketTotal: function() {
5844            //basketTotalCell is for basket.asp; OrderTotal is for bundleBasket.asp
5845            var totalText = '';
5846            var $basketTotalCell = $('#basketTotalCell');
5847            if ($basketTotalCell.length && $.trim($basketTotalCell.text()) !== '') {
5848                totalText = $.trim($basketTotalCell.text());
5849            } else {
5850                var $orderTotal = $('#OrderTotal');
5851                totalText = $.trim($orderTotal.text());
5852            }
5853            // Remove currency symbol and parse
5854            var match = totalText.match(/[\d,]+\.?\d*/);
5855            if (match) {
5856                this.currentTotal = parseFloat(match[0].replace(/,/g, ''));
5857            }
5858            
5859            // Update the "Pay in Full" amount display
5860            $('#basket-total-value').text(this.formatCurrency(this.currentTotal));                    
5861        },
5862        
5863        /**
5864         * Calculate and update amounts for all payment plans
5865         */
5866        updateAllPlanAmounts: function(iOrderFee) {
5867            var self = this;
5868            $.ajax({
5869                url: '/include/modules/paymentPlans/requests/ppAjax.asp',
5870                method: 'GET',
5871                dataType: 'json',
5872                data: {
5873                    action: 'updateAsyncPaymentPlanAmounts'                    
5874                },
5875                success: function(response) {                    
5876                    // Update payment plan amounts in the UI
5877                    self.updatePaymentPlanAmounts(response, iOrderFee);
5878                },
5879                error: function(xhr, status, error) {
5880                    console.error('Error updating payment plan amounts:', status, error);
5881                }
5882            });
5883        },
5884
5885        /**
5886         * Update payment plan amounts in the UI based on server response
5887         * @param {Array} planData - Array of plan objects with paymentPlanID, firstPayment, monthlyPayment, numberOfPayments
5888         */
5889        updatePaymentPlanAmounts: function(planData, orderProcessingFee) {
5890            if (!planData || !Array.isArray(planData) || planData.length === 0) {
5891                console.warn('No plan data to update');
5892                return;
5893            }                        
5894            
5895            // Update basket total first (in case it changed with promo codes)
5896            this.updateBasketTotal();
5897            
5898            // Iterate through each plan in the response
5899            planData.forEach(function(plan) {
5900                var planID = plan.planID;
5901                var firstPayment = parseFloat(plan.firstPayment || 0);
5902                var monthlyPayment = parseFloat(plan.monthlyPayment || 0);
5903                var numberOfPayments = parseInt(plan.numberOfPayments || 0);
5904                var remainingPayments = numberOfPayments - 1;
5905                
5906                // Update first payment amount
5907                var $firstPaymentSpan = $('[data-plan-first-id="' + planID + '"]');
5908                if ($firstPaymentSpan.length > 0) {
5909                    $firstPaymentSpan.text(basketPaymentPlan.formatCurrency(firstPayment + orderProcessingFee));                    
5910                }
5911                
5912                // Update monthly payment amount
5913                var $monthlyPaymentSpan = $('[data-plan-monthly-id="' + planID + '"]');
5914                if ($monthlyPaymentSpan.length > 0) {
5915                    $monthlyPaymentSpan.text(basketPaymentPlan.formatCurrency(monthlyPayment));                    
5916                }
5917                
5918                // Update remaining payments count
5919                var $remainingCountSpan = $('[data-plan-remaining-id="' + planID + '"]');
5920                if ($remainingCountSpan.length > 0) {
5921                    $remainingCountSpan.text(remainingPayments);                
5922                }
5923                
5924                // Update total installments count
5925                var $installmentsSpan = $('[data-plan-installments-id="' + planID + '"]');
5926                if ($installmentsSpan.length > 0) {
5927                    $installmentsSpan.text(numberOfPayments);
5928                }
5929                
5930                // Update the data-installments attribute on the radio button
5931                var $radioButton = $('input[name="basket_pp_option"][data-plan-id="' + planID + '"]');
5932                if ($radioButton.length > 0) {
5933                    $radioButton.attr('data-installments', numberOfPayments);
5934                }
5935            });
5936            
5937            // Trigger event for other components that might need to react
5938            $(document).trigger('basketPaymentPlanAmountsUpdated', { plans: planData });
5939        },
5940        
5941        /**
5942         * Calculate payment plan amounts
5943         * @param {number} total - Total order amount
5944         * @param {number} installments - Number of installments
5945         * @returns {object} - Object with firstPayment, monthlyPayment, remainingPayments
5946         */
5947        calculatePlanAmounts: function(total, installments) {
5948            if (installments <= 0 || total <= 0) {
5949                return {
5950                    firstPayment: 0,
5951                    monthlyPayment: 0,
5952                    remainingPayments: 0
5953                };
5954            }
5955            
5956            // Use the calculateInstalments function from ppFunctions.js if available
5957            var instalmentAmounts;
5958            if (typeof calculateInstalments === 'function') {
5959                instalmentAmounts = calculateInstalments(total, installments, 'ROUND_UP'); //from ppFunctions.js.asp
5960            } else {
5961                // Fallback calculation
5962                var monthlyPayment = Math.ceil((total / installments) * 100) / 100;
5963                var firstPayment = total - (monthlyPayment * (installments - 1));
5964                instalmentAmounts = [firstPayment].concat(Array(installments - 1).fill(monthlyPayment));
5965            }
5966            
5967            return {
5968                firstPayment: instalmentAmounts[0],
5969                monthlyPayment: instalmentAmounts[1] || 0,
5970                remainingPayments: installments - 1
5971            };
5972        },
5973        
5974        /**
5975         * Update "Due Today" section based on selected plan
5976         */
5977        updateDueToday: function() {
5978            if (this.selectedPlanId === 0) {
5979                // Pay in Full - due today is full amount
5980                // The existing Due Today section should be hidden or show full amount
5981                return;
5982            }
5983            
5984            // Calculate first payment for selected plan
5985            var amounts = this.calculatePlanAmounts(this.currentTotal, this.selectedInstallments);
5986            
5987            // Update Due Today display if it exists
5988            var $dueToday = $('#basketDueTodayCell');
5989            if ($dueToday.length > 0) {
5990                $dueToday.show();
5991                var currencySymbol = $dueToday.text().match(/^[^\d]+/)[0] || '$';
5992                $dueToday.html(currencySymbol + '<strong>' + this.formatCurrency(amounts.firstPayment) + '</strong>');
5993            }
5994        },
5995        
5996        /**
5997         * Format number as currency
5998         */
5999        formatCurrency: function(amount) {
6000            return parseFloat(amount).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
6001        },
6002        
6003        // --- new: load TILA via AJAX ---
6004        preloadTila: function(planId) {
6005            var self = this;
6006            if (self.tilaDataCache[planId]) {
6007                return; // already cached
6008            }
6009            $.ajax({
6010                url: '/include/modules/paymentPlans/requests/ppAjax.asp',
6011                method: 'GET',
6012                data: {
6013                    action: 'getPaymentPlanTILA',      
6014                    paymentPlanSelection: planId
6015                },
6016                cache: false,
6017                success: function(resp) {
6018                    // Could be HTML or JSON. If JSON parse.
6019                    var tilaContent = resp;
6020                    try {                        
6021                        if (typeof resp === 'string' && resp.trim().charAt(0) === '{') {
6022                            var j = JSON.parse(resp);
6023                            tilaContent = j.tilaText || resp;
6024                        }                        
6025                    } catch(e) { /* keep resp as-is */ }
6026                    self.tilaDataCache[planId] = tilaContent;
6027                    $(document).trigger('basketTilaPreloaded', { planId: planId });
6028                },
6029                error: function() {
6030                    console.warn('Failed to preload TILA for plan ' + planId);
6031                    self.tilaDataCache[planId] = '<div style="padding:12px;">Terms unavailable.</div>';
6032                }
6033            });
6034        },
6035        
6036        
6037        showTilaModal: function(onAccept) {
6038            var self = this;
6039            if (self.tilaModalShowing) return;
6040            self.tilaModalShowing = true;
6041            
6042            var planId = self.selectedPlanId;
6043            var html = self.tilaDataCache[planId] || '<div style="padding:12px;">Terms not loaded.</div>';
6044            
6045            // Build overlay
6046            var $overlay = $('<div id="tilaOverlay" style="position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:9998;"></div>');
6047            var $modal = $('<div id="tilaModal" style="position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:#fff;max-width:640px;width:92%;max-height:80vh;overflow:auto;border-radius:8px;box-shadow:0 10px 28px rgba(0,0,0,.35);z-index:9999;font-family:Arial,sans-serif;"></div>');
6048            var $header = $('<div style="padding:14px 18px;border-bottom:1px solid #eee;font-weight:600;font-size:15px;letter-spacing:.3px;">Payment Plan Terms (TILA)</div>');
6049            var $body = $('<div style="padding:16px;font-size:12px;line-height:1.45;color:#222;"></div>').html(html);
6050            
6051            // Checkbox agreement section
6052            var $checkboxSection = $('<div style="padding:12px 16px;border-top:1px solid #eee;display:flex;align-items:center;gap:8px;"></div>');
6053            var $checkbox = $('<input type="checkbox" id="tilaAgreeCheckbox" style="width:16px;height:16px;cursor:pointer;margin:0;">');
6054            var $checkboxLabel = $('<label for="tilaAgreeCheckbox" style="cursor:pointer;font-size:13px;color:#333;margin:0;user-select:none;">I have read and agree to the payment plan terms and conditions</label>');
6055            $checkboxSection.append($checkbox, $checkboxLabel);
6056            
6057            // Action buttons
6058            var $actions = $('<div style="padding:12px 16px;border-top:1px solid #eee;display:flex;justify-content:flex-end;gap:10px;"></div>');
6059            var $btnPayInFull = $('<button type="button" style="background:#888;color:#fff;border:0;padding:8px 14px;border-radius:4px;font-size:12px;cursor:pointer;">Pay in Full</button>');
6060            var $btnAccept = $('<button type="button" disabled style="background:#ccc;color:#999;border:0;padding:8px 18px;border-radius:4px;font-size:12px;cursor:not-allowed;font-weight:600;">Accept & Continue</button>');
6061            var $errorBar = $('<div class="tila-error" style="display:none;margin:0 16px 8px 16px;background:#fbe9e9;color:#b32626;border:1px solid #e5b6b6;padding:8px 10px;border-radius:4px;font-size:12px;line-height:1.3;"></div>');
6062            
6063            $actions.append($btnPayInFull, $btnAccept);
6064            $modal.append($header, $body, $errorBar, $checkboxSection, $actions);
6065            $('body').append($overlay, $modal);
6066            
6067            // Enable/disable Accept button based on checkbox
6068            $checkbox.on('change', function() {
6069                if ($(this).is(':checked')) {
6070                    $btnAccept.prop('disabled', false)
6071                        .css({
6072                            'background': '#2f5d9f',
6073                            'color': '#fff',
6074                            'cursor': 'pointer'
6075                        });
6076                } else {
6077                    $btnAccept.prop('disabled', true)
6078                        .css({
6079                            'background': '#ccc',
6080                            'color': '#999',
6081                            'cursor': 'not-allowed'
6082                        });
6083                }
6084            });
6085            
6086            function closeModal() {
6087                $overlay.remove();
6088                $modal.remove();
6089                self.tilaModalShowing = false;
6090            }
6091            
6092            // Pay in Full button - closes modal and resets to pay-in-full option
6093            $btnPayInFull.on('click', function() {
6094                closeModal();
6095                // Reset to pay in full option (planId = 0)
6096                // Triggering 'change' will invoke handlePlanSelection which already posts removePaymentPlanSessions
6097                $('input[name="basket_pp_option"][data-plan-id="0"]').prop('checked', true).trigger('change');
6098            });
6099            
6100            // Accept button - only enabled when checkbox is checked
6101            $btnAccept.on('click', function() {
6102                if (!$checkbox.is(':checked') || $btnAccept.prop('disabled')) return; // safety
6103                $errorBar.hide();
6104                // Lock UI
6105                $btnAccept.prop('disabled', true).data('origText', $btnAccept.text())
6106                    .html('<span class="spinner" style="display:inline-block;width:14px;
6106height:14px;border:2px solid #fff;border-right-color:transparent;border-radius:50%;animation:tilaSpin .7s linear infinite;vertical-align:-2px;margin-right:6px;"></span>Processing...')
6107                    .css({ cursor: 'wait' });
6108                $btnPayInFull.prop('disabled', true).css({ opacity: .6, cursor: 'not-allowed' });
6109                $checkbox.prop('disabled', true);
6110                
6111                // Perform single AJAX call to confirmTILA and fill session data
6112                $.ajax({
6113                    url: '/include/modules/paymentPlans/requests/ppAjax.asp',
6114                    method: 'POST',
6115                    dataType: 'json',
6116                    async: false,
6117                    data: {
6118                        action: 'confirmTILA',
6119                        paymentPlanSelection: planId,
6120                        sessionKey: ''
6121                    },
6122                    timeout: 15000,
6123                    success: function(resp){
6124                        if (resp && resp.success){
6125                            closeModal();
6126                            if (typeof onAccept === 'function') {
6127                                onAccept();
6128                            }
6129                        } else {
6130                            showTilaError(resp && resp.message ? resp.message : 'Unable to confirm payment plan. Please try again.');
6131                        }
6132                    },
6133                    error: function(xhr, status, error){
6134                        showTilaError('Network or server error. Please try again.');
6135                        console.error('Error confirming TILA:', status, error);
6136
6137                    },
6138                    complete: function(){
6139                        if ($modal.parent().length){ // still open
6140                            restoreAcceptButton();
6141                        }
6142                    }
6143                });
6144            });
6145
6146            function showTilaError(msg){
6147                $errorBar.text(msg).fadeIn(150);
6148            }
6149
6150            function restoreAcceptButton(){
6151                $btnAccept.prop('disabled', !$checkbox.is(':checked'))
6152                    .html($btnAccept.data('origText') || 'Accept & Continue')
6153                    .css({ cursor: $checkbox.is(':checked') ? 'pointer' : 'not-allowed', background: $checkbox.is(':checked') ? '#2f5d9f' : '#ccc', color: $checkbox.is(':checked') ? '#fff' : '#999' });
6154                $btnPayInFull.prop('disabled', false).css({ opacity: 1, cursor: 'pointer' });
6155                $checkbox.prop('disabled', false);
6156            }
6157        },
6158        
6159        /**
6160         * Get the currency symbol rendered by the widget
6161         */
6162        getCurrencySymbol: function() {
6163            var sym = $('#basket-payment-plan-selection').data('currency-symbol');
6164            return (sym === undefined || sym === null || sym === '') ? '$' : String(sym);
6165        },
6166        
6167        /**
6168         * Advance a date by a number of months, preserving the day of month
6169         * (clamped to the last day of the target month). Mirrors the server-side
6170         * getNextMonthDatePreservingDay logic used to schedule installments.
6171         */
6172        addMonthsPreservingDay: function(originalDate, monthsToAdd) {
6173            var original = new Date(originalDate);
6174            var targetMonth = original.getMonth() + monthsToAdd;
6175            var firstOfTarget = new Date(original.getFullYear(), targetMonth, 1);
6176            var daysInTargetMonth = new Date(firstOfTarget.getFullYear(), firstOfTarget.getMonth() + 1, 0).getDate();
6177            var targetDay = Math.min(original.getDate(), daysInTargetMonth);
6178            return new Date(firstOfTarget.getFullYear(), firstOfTarget.getMonth(), targetDay);
6179        },
6180        
6181        /**
6182         * Format a Date as a localized short date (falls back to ISO if needed)
6183         */
6184        formatScheduleDate: function(date) {
6185            try {
6186                return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
6187            } catch (e) {
6188                return date.toISOString().split('T')[0];
6189            }
6190        },
6191        
6192        /**
6193         * Build the installment schedule for a plan from the amounts currently
6194         * rendered in the widget. Returns an array of { number, date, amount }.
6195         */
6196        buildScheduleForPlan: function(planId) {
6197            var firstText = $.trim($('[data-plan-first-id="' + planId + '"]').first().text());
6198            var monthlyText = $.trim($('[data-plan-monthly-id="' + planId + '"]').first().text());
6199            var firstPayment = parseFloat(firstText.replace(/,/g, '')) || 0;
6200            var monthlyPayment = parseFloat(monthlyText.replace(/,/g, '')) || 0;
6201            var $radio = $('input[name="basket_pp_option"][data-plan-id="' + planId + '"]');
6202            var numberOfPayments = parseInt($radio.data('installments'), 10) || 0;
6203            
6204            var schedule = [];
6205            var today = new Date();
6206            for (var i = 0; i < numberOfPayments; i++) {
6207                schedule.push({
6208                    number: i + 1,
6209                    date: (i === 0) ? today : this.addMonthsPreservingDay(today, i),
6210                    amount: (i === 0) ? firstPayment : monthlyPayment
6211                });
6212            }
6213            return schedule;
6214        },
6215        
6216        /**
6217         * Display a modal with the full payment schedule (dates + amounts) for a plan
6218         */
6219        showScheduleModal: function(planId, planName) {
6220            var self = this;
6221            if (planId <= 0) { return; }
6222            
6223            var currencySymbol = self.getCurrencySymbol();
6224            var safeCurrencySymbol = $('<div/>').text(currencySymbol).html();
6225            var schedule = self.buildScheduleForPlan(planId);
6226            if (!schedule.length) { return; }
6227            
6228            var total = 0;
6229            var rowsHtml = '';
6230            for (var i = 0; i < schedule.length; i++) {
6231                var item = schedule[i];
6232                total += item.amount;
6233                var label = (item.number === 1) ? 'Today' : self.formatScheduleDate(item.date);
6234                rowsHtml += '<tr>' +
6235                    '<td style="padding:6px 10px;border-bottom:1px solid #f0f0f0;color:#555;">' + item.number + '</td>' +
6236                    '<td style="padding:6px 10px;border-bottom:1px solid #f0f0f0;color:#333;">' + label + '</td>' +
6237                    '<td style="padding:6px 10px;border-bottom:1px solid #f0f0f0;text-align:right;font-weight:600;color:#222;">' + safeCurrencySymbol + self.formatCurrency(item.amount) + '</td>' +
6238                    '</tr>';
6239            }
6240            
6241            var title = planName ? String(planName) : 'Payment Schedule';
6242            
6243            // Ensure only one schedule modal exists at a time
6244            $('#ppScheduleOverlay, #ppScheduleModal').remove();
6245            
6246            var $overlay = $('<div id="ppScheduleOverlay" style="position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:9998;"></div>');
6247            var $modal = $('<div id="ppScheduleModal" style="position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:#fff;max-width:520px;width:92%;max-height:80vh;overflow:auto;border-radius:8px;box-shadow:0 10px 28px rgba(0,0,0,.35);z-index:9999;font-family:Arial,sans-serif;"></div>');
6248            var $header = $('<div style="padding:14px 18px;border-bottom:1px solid #eee;font-weight:600;font-size:15px;letter-spacing:.3px;display:flex;justify-content:space-between;align-items:center;"></div>');
6249            $header.append($('<span></span>').text(title));
6250            var $close = $('<button type="button" aria-label="Close" style="background:none;border:0;font-size:20px;line-height:1;cursor:pointer;color:#888;">&times;</button>');
6251            $header.append($close);
6252            
6253            var $body = $('<div style="padding:12px 16px;"></div>');
6254            var $table = $('<table style="width:100%;border-collapse:collapse;font-size:12px;"></table>');
6255            $table.append('<thead><tr>' +
6256                '<th style="padding:6px 10px;text-align:left;border-bottom:2px solid #e4e4e4;color:#666;font-weight:600;">#</th>' +
6257                '<th style="padding:6px 10px;text-align:left;border-bottom:2px solid #e4e4e4;color:#666;font-weight:600;">Due date</th>' +
6258                '<th style="padding:6px 10px;text-align:right;border-bottom:2px solid #e4e4e4;color:#666;font-weight:600;">Amount</th>' +
6259                '</tr></thead>');
6260            $table.append('<tbody>' + rowsHtml + '</tbody>');
6261            $table.append('<tfoot><tr>' +
6262                '<td colspan="2" style="padding:8px 10px;text-align:right;font-weight:600;color:#333;">Total</td>' +
6263                '<td style="padding:8px 10px;text-align:right;font-weight:700;color:#2f5d9f;">' + currencySymbol + self.formatCurrency(total) + '</td>' +
6264                '</tr></tfoot>');
6265            $body.append($table);
6266            
6267            var $note = $('<div style="padding:0 16px 14px 16px;font-size:10px;color:#666;line-height:1.3;">First payment may adjust for shipping, taxes, fees, and rounding differences. Dates and amounts shown are illustrative only.</div>');
6268            
6269            $modal.append($header, $body, $note);
6270            $('body').append($overlay, $modal);
6271            
6272            function closeModal() {
6273                $overlay.remove();
6274                $modal.remove();
6275            }
6276            $close.on('click', closeModal);
6277            $overlay.on('click', closeModal);
6278        },
6279        
6280        /**
6281         * Public method to refresh payment plan amounts (called after promo code application)
6282         */
6283        refreshAmounts: function(iOrderFee) {            
6284            this.updateAllPlanAmounts(iOrderFee);
6285        },
6286
6287        clearPaymentPlanSessions: function() {
6288            $.ajax({
6289                url: '/include/modules/paymentPlans/requests/ppAjax.asp',
6290                method: 'POST',
6291                dataType: 'json',
6292                async: true,
6293                data: {
6294                    action: 'removePaymentPlanSessions',
6295                    sessionKey: ''
6296                }
6297            });
6298        },
6299
6300        isPayInFullSelected: function() {
6301            return this.selectedPlanId === 0;
6302        }
6303    };
6304    
6305    // Initialize when document is ready
6306    $(document).ready(function() {
6307        // Check if payment plans are enabled and widget exists
6308        if ($('#basket-payment-plan-selection').length > 0) {
6309            basketPaymentPlan.init();
6310        }
6311    });
6312    
6313    // Expose for external access if needed
6314    window.basketPaymentPlan = basketPaymentPlan;
6315    
6316})();
6317</script>
6317<div class='sw-banner-ad' data-sw-ad-location='basket_top1'></div>
6318<div class="clear">
6319    <span class="heading-text sub-head-text" style="float:left;">Shopping Cart</span>
6320</div>
6321
6322<div class="basketSystemMessage">
6323<p><!-- Meta Pixel Code -->
6324<script>// <![CDATA[
vendor: 408 bytes, lines 6324-6333
6324
6325!function(f,b,e,v,n,t,s)
6326{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
6327n.callMethod.apply(n,arguments):n.queue.push(arguments)};
6328if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
6329n.queue=[];t=b.createElement(e);t.async=!0;
6330t.src=v;s=b.getElementsByTagName(e)[0];
6331s.parentNode.insertBefore(t,s)}(window, document,'script',
6332'https://connect.facebook.net/en_US/fbevents.js');
6333fbq('init', '
6333802935397828854
vendor: 32 bytes, lines 6333-6334
6333');
6334fbq('track', 'PageView');
6335// ]]></script>
6335
6336<noscript><img height="1" width="1" style="display:none"
6337src="https://www.facebook.com/tr?id=802935397828854&ev=PageView&noscript=1"
6338/></noscript><!-- End Meta Pixel Code --><!-- Google tag (gtag.js) -->
6339<script src="https://www.googletagmanager.com/gtag/js?id=AW-11164002043">// <![CDATA[
6340
6341// ]]></script>
vendor: 2 bytes, line 6341
6341
6342<script>// <![CDATA[
6343  
vendor: 138 bytes, lines 6343-6347
6343window.dataLayer = window.dataLayer || [];
6344  function gtag(){dataLayer.push(arguments);}
6345  gtag('js', new Date());
6346
6347  gtag('config', '
6347AW-11164002043
vendor: 5 bytes, line 6347
6347');
6348// ]]></script>
6348</p>
6349
6350</div>
6351
6352<style>
6353.event-header{
6354	float:left;
6355	display:inline-block;
6356	margin: 5px 0px 5px 20px;
6357	max-width:300px;
6358}
6359
6360.select-all{
6361	width:2em;
6362	height:2em;
6363}
6364
6365.membership-remove{
6366	display:none;
6367}
6368.mobile-only.mobile-remove.membership-remove{
6369display:none !important;
6370}
6371.orderpromo-wrap {display: block; width: 100%; padding-bottom: 32px;}
6372</style>
6373<link rel="stylesheet" type="text/css" href="../Include/callout.css?v=2">
6374
6375
6376
6377
6378	<!--Messages-->
6379	<span id="error-messages" class=""></span>
6380
6381
6382	<br>
6383	<br>
6384	<center>
6385		<span>Your Shopping Cart is empty</span>
6386		<br>
6387		<br>
6388		
6389		
6390		<input type="button" id="EmptyCartContinueButton" aria-label="Empty Cart Continue button" class="button sw-button-primary" value="Continue" onclick="window.location.href='default.asp'">
6391	</center>
6392
6393
6394	<br>
6395	<br>
6396	<br>
6397
6398	<!--GEM21073 - Seatmap in Basket Includes - thickbox jquery plugin - Begin-->
6399	
6399<script type="text/javascript" src="include/thickbox-compressed.js"></script>
6399
6400	<style type="text/css" media="all">@import "include/thickbox.css";</style>
6401	<!--GEM21073 - Seatmap in basket END -->
6402	
6402<script type="text/javascript">
6403	
6404		
6405		
6406        //update orderinfo in data layer for Tag Manager and tracking
6407		if (typeof addDataLayer == 'function') {
6408		    addDataLayer('TicketingOrderTotal', '0');
6409		    addDataLayer('TicketingTicketItems', '');
6410		    addDataLayer('TicketingDonationItems', '');
6411		    addDataLayer('TicketingMembershipItems', '');
6412		    addDataLayer('TicketingOrderSubTotal', '0');
6413		    addDataLayer('TicketingItemCount', '0');
6414		    addDataLayer('TicketingProcessingFee', '0');
6415		    addDataLayer('TicketingSalesChannel', '0');
6416		    addDataLayer('TicketingHasMixedBasket', '0');
6417			addDataLayer('TicketingEventCategories', '');
6418		}
6419
6420
6421		var hasSaneDeliveryOption = true;
6422		
6423		/*If we don't have a set of compatible delivery options warn the user, since they won't be able to continue*/
6424		if(!hasSaneDeliveryOption){
6425			$("#checkout-button").attr("disabled","disabled");
6426			$("#checkout-button").attr("title", "The basket's items don't have compatible delivery options, please order the items individually.");
6427		}
6428		
6429		//add even-item class to every other basket-item
6430		$(".basket-item:odd").addClass("even-item");
6431		
6432		var Basket = function(basketID, bundleID){
6433			this.expiredTickets = [];
6434
6435			var isChangePriceSaveMode = {};
6436			
6437			this.selectAll = function(selector) {
6438				$(selector).prop("checked", true);
6439			}
6440			
6441			this.deselectAll = function(selector) {
6442				$(selector).prop("checked", false);
6443			}
6444			
6445			this.deleteItems = function(options) {
6446				var hasItemsChecked = $(".line-item-checkbox").is(":checked"),
6447					defaults = {
6448						bypassPrompt: false,
6449						reloadBasket: true
6450					};
6451
6452				options = _.extend(defaults, options);
6453
6454				if (hasItemsChecked) {
6455					if (options.bypassPrompt || confirm('Are you sure that you want to remove the selected items?')) {
6456						document.getElementById("activity").value = "deleteItems";
6457						document.basket.action = "BasketUpdate.asp";
6458						var removeTickets = document.getElementById("RemoveTickets");
6459						if(removeTickets){
6460						   removeTickets.disabled = true;
6461						}
6462						this.postToBasketUpdate(function(){
6463							if (options.reloadBasket) {
6464								window.location.reload();
6465							}
6466						});
6467					}
6468				} else {
6469					alert('No items selected.');
6470				}	
6471			}
6472			
6473			this.deleteBasket = function() {
6474				if (confirm('Are you sure, that you want to remove ALL items from the Shopping Cart?')) {
6475					document.getElementById("activity").value = 'deleteBasket';
6476					document.basket.action = "BasketUpdate.asp";
6477					var removeTickets = document.getElementById("RemoveTickets");
6478					if(removeTickets){
6479					    removeTickets.disabled = true;
6480					}
6481				    try{
6482				        //update tag manager if present
6483				        addDataLayer('TicketingTicketItems', '');
6484				        dataLayer.push({'event': 'BasketEmptied'});
6485				        //update enhanced ecommerce
6486				        swEnhancedEcommerce.sendRemoveAllFromBasket();
6487				    }catch(e){
6488				        console.log(e);
6489				    }
6490					this.postToBasketUpdate(function(){
6491						window.location.reload();
6492					});
6493				}
6494			}
6495			
6496			this.addCoupon = function(){
6497				var couponCodeParameter = encodeURIComponent($("#couponCode").val().replace(/[^0-9a-zA-Z_]+/g,"")); //coupon codes only allows alphanumeric and underscores
6498				var basketIDParameter = encodeURIComponent(basketID);
6499				var updateURL = "BasketUpdate.asp?couponcode=" + couponCodeParameter + "&basketid=" + basketIDParameter + "&activity=addCoupon" ;
6500	
6501				$.get(updateURL, function(data){	
6502					var url = window.location.href;
6503					url = url.replace(/([&?])((ic|doAutoApply)=[a-zA-Z0-9])/g, (match, p1, p2) => {
6504					  if (match.charAt(0) === "?") {
6505					    return p1 === "?" ? "?" : "";
6506					  } else {
6507					    return "";
6508					  }
6509					});
6510					var hasQueryStringParams = /\?/.test(url) && url[url.length-1] != "?";
6511					var additionalParam = "?doAutoApply=x";
6512					
6513					if(hasQueryStringParams){
6514						additionalParam = "&doAutoApply=x";
6515					}
6516					
6517					additionalParam = additionalParam + "&ic=" + (data.messages.hasInvalidCoupon ? "1" : "0");
6518
6519					window.location.href = (url + additionalParam);
6520				});
6521			}
6522			
6523			this.removeCoupon = function(couponCode){
6524				var couponCodeParameter = encodeURIComponent(couponCode);
6525				var basketIDParameter = encodeURIComponent(basketID);
6526				var updateURL = "BasketUpdate.asp?couponcode=" + couponCodeParameter + "&basketid=" + basketIDParameter + "&activity=removeCoupon" ;
6527				
6528				$.get(updateURL, function(data){
6529					window.location.reload();
6530				});
6531			}
6532			
6533			this.changeMembershipPricing = function(context){
6534				var $item = $(context).parents(".basket-item");		
6535				var itemID = ($item.attr("id")).replace("item-", "");
6536				var $priceSpan = $item.find(".level-price-value");
6537				
6538				if(isChangePriceSaveMode[itemID]){
6539					$(context).text("change");
6540					isChangePriceSaveMode[itemID] = false; 
6541					
6542					var previousValue = isChangePriceSaveMode["prev" + itemID];
6543					var enteredVal = $priceSpan.find("#changePrice").val().replace(/[^0-9\.]+/g,"");
6544
6545					$priceSpan.html("");
6546					
6547					enteredVal = isNaN(enteredVal) ? 0.00 : enteredVal;
6548					
6549					/*format as currency*/
6550					enteredVal = $.trim('$' + parseFloat(enteredVal, 10).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,").toString());
6551			
6552					$priceSpan.text(enteredVal);
6553					
6554					var updateURL ="BasketUpdate.asp?activity=changeMembershipPrice&membershipPrice=" + encodeURIComponent(enteredVal.replace("$", "")) + "&basketItemID=" + encodeURIComponent(itemID) + "&basketID="+ encodeURIComponent(basketID);
6555					
6556					this.sendGet(updateURL, function(data){						
6557						if(data){	
6558							if (data.messages.errors[0]){
6559								//revert on error
6560								$priceSpan.text(previousValue);								
6561								return;
6562							}	
6563							$priceSpan.text(enteredVal);
6564							
6565							// Update price in basket.items.memberships object
6566							if(basket.items && basket.items.memberships){
6567								var numericPrice = parseFloat(enteredVal.replace(/[^0-9\.]+/g,""));
6568								for(var i = 0; i < basket.items.memberships.length; i++){
6569									if(basket.items.memberships[i].BasketItemID == itemID){
6570										basket.items.memberships[i].Price = numericPrice;
6571										break;
6572									}
6573								}
6574							}
6575							
6576							// Reload basket and update totals
6577							getClientBasket(function() {
6578								calculateTotals();
6579								updatePaymentPlansTotals();								
6580							});
6581						}else{
6582							window.location.reload();
6583						}
6584					});					
6585				}else{
6586					$(context).text("save");
6587					isChangePriceSaveMode[itemID] = true;
6588					
6589					/*Add Textbox if editing*/
6590					if($("#changePrice").length <= 0){			
6591						var priceValue = $priceSpan.text();
6592						isChangePriceSaveMode["prev" + itemID] = priceValue;
6593						
6594						if($("#changePrice").length <= 0){
6595							$priceSpan.html("<input class='showare-text' id='changePrice' aria-label='Change Price' type='text' style='width:5.5em;margin-bottom:.5em;' />");
6596							
6597							$("#changePrice").val(priceValue.replace(/[^0-9\.]+/g,""))
6598						}
6599					}
6600				}				
6601			}
6602			
6603			this.changePricingCode = function(context){
6604			    var pcErrors = ""
6605
6606			    $(context).attr("disabled", "true");
6607			    $(context).css("background","RGBA(0,0,0,0.5)");
6608
6609			    var updateURL = "/BasketUpdate.asp?pricingcode=" + encodeURIComponent($(context).val()) + "&activity=changePricing" 
6610
6611			    var ticketIDs = "&ticketID=" + encodeURIComponent($(context).attr("id").replace("pricingCode-", ""));
6612		
6613			    updateURL += ticketIDs;
6614		
6615			    $.get(updateURL)
6616                    .then(function(data){
6617                        if(data.messages.errors[0]){
6618                        	if (data.messages.errors[0].message == undefined)
6619                        		pcErrors += "The pricing code you selected is not valid.<br>";
6620                        	else
6621                            	pcErrors += data.messages.errors[0].message;
6622                            revertCart(pcErrors, context);
6623                        }else{							
6624                            updateCart(context, data);
6625							updatePaymentPlansTotals();
6626							//re-apply any promo codes if we have basket discounts
6627							//this is needed because changing ticket pricing codes will need to re-apply promos to the new pricings
6628							//and get and render the correct totals again
6629							if (basket.discounts.HasBasketDiscounts)
6630							{
6631								applyPromoCode();
6632								getClientBasket();								
6633							}
6634                        }
6635                    })
6636                    .catch(function(){
6637                        pcErrors += "We were unable to process your request.<br>"
6638                        revertCart(pcErrors, context);
6639                    });
6640			    
6641			}
6642			this.changeSinglePricingCode = function(context){
6643			    var pcErrors = ""
6644
6645			    $(context).attr("disabled", "true");
6646			    $(context).css("background","RGBA(0,0,0,0.5)");
6647
6648			    var updateURL = "/BasketUpdate.asp?pricingcode=" + encodeURIComponent($(context).val()) + "&activity=changeSingleTicketPricing" 
6649
6650			    var ticketIDs = "&ticketID=" + encodeURIComponent($(context).attr("id").replace("pricingCode-", ""));
6651		
6652			    updateURL += ticketIDs;
6653		
6654			    $.get(updateURL)
6655                    .then(function(data){
6656                        if(data.messages.errors[0]){
6657                            if (data.messages.errors[0].message == undefined)
6658                        		pcErrors += "The pricing code you selected is not valid.<br>";
6659                        	else
6660                            	pcErrors += data.messages.errors[0].message;
6661								
6662                            revertCart(pcErrors, context);
6663                        }else{                            
6664                            updateCart(context, data);
6665							updatePaymentPlansTotals();
6666							//re-apply any promo codes if we have basket discounts
6667							//this is needed because changing ticket pricing codes will need to re-apply promos to the new pricings
6668							//and get and render the correct totals again
6669							if (basket.discounts.HasBasketDiscounts)
6670							{
6671								applyPromoCode();
6672								getClientBasket();
6673							}
6674							
6675                        }
6676                    })
6677                    .catch(function(){
6678                        pcErrors += "We were unable to process your request.<br>"
6679                        revertCart(pcErrors, context);
6680                    });
6681			    
6682			}
6683
6684			function updateCart(context, data){
6685			    var currencySymbol = '$'
6686			    var basketTickets = data.items.tickets; var basketDonations = data.items.donations; var basketMemberships = data.items.memberships; var orderProcessingFees =  data.items.orderFee[0];
6687				var workingTicketID  =0;
6688				try{					
6689					workingTicketID = parseInt($(context).attr("id").replace("pricingCode-", ""));
6690				}catch(e){
6691					console.log(e);
6692				}
6693				
6694				var orderProcessingFee = 0;
6695				if (typeof(orderProcessingFees) === 'undefined'){
6696					orderProcessingFees = 0;
6697				}else{
6698					orderProcessingFee = orderProcessingFees.OrderFee;
6699				}
6700			    
6701			    var extFee3Total = 0;
6702			    var basketTotal = 0;
6703				var ticketTotal = 0;
6704				var ticketPrintedPriceTotal = 0;
6705				var extFee1Total = 0;
6706				var extFee2Total = 0;
6707				var donationTotal = 0;
6708				var membershipTotal = 0;
6709			    console.log(data);
6710			    //update totals
6711                for(var i = 0;i<basketDonations.length;i++){
6712					donationTotal += basketDonations[i].Price;
6713                    basketTotal += basketDonations[i].Price;
6714                }
6715                for(var i = 0;i<basketMemberships.length;i++){
6716					membershipTotal += basketMemberships[i].Price;
6717                    basketTotal += basketMemberships[i].Price;
6718                }
6719			    for(var i = 0;i<basketTickets.length;i++){
6720			        if(basketTickets[i].TicketID == workingTicketID){
6721			            var totalPrice = basketTickets[i].Price + basketTickets[i].ExtFee2 + basketTickets[i].ExtFee3 + basketTickets[i].Tax + basketTickets[i].TransactionFee;
6722			            //update fees for this item here///////////////////////
6723			            $("#" + basketTickets[i].TicketID + "-Price .fees-item").html(currencySymbol + basketTickets[i].Price.toFixed(2));
6724			            $("#" + basketTickets[i].TicketID + "-TransactionFee .fees-item").html(currencySymbol + basketTickets[i].TransactionFee.toFixed(2));
6725			            $("#" + basketTickets[i].TicketID + "-PriceWithFees .fees-item").html(currencySymbol + totalPrice.toFixed(2));
6726			            
6727                            $("#" + basketTickets[i].TicketID + "-ExtFee2 .fees-item").html(currencySymbol + basketTickets[i].ExtFee2.toFixed(2));
6728                        
6729		            }
6730		            
6731					ticketTotal += basketTickets[i].Price;
6732					ticketPrintedPriceTotal += basketTickets[i].PrintedPrice;
6733					
6734					ticketTotal += basketTickets[i].ExtFee2 + basketTickets[i].ExtFee3 + basketTickets[i].TransactionFee;
6735					ticketPrintedPriceTotal += basketTickets[i].ExtFee2 + basketTickets[i].ExtFee3 + basketTickets[i].TransactionFee;
6736					
6737					extFee1Total += basketTickets[i].TransactionFee;
6738					extFee2Total += basketTickets[i].ExtFee2;
6739			        basketTotal += basketTickets[i].Price + basketTickets[i].ExtFee2 + basketTickets[i].ExtFee3 + basketTickets[i].Tax + basketTickets[i].TransactionFee;
6740
6741					// Update strikethrough pricing if applicable
6742					
6743					$("#" + basketTickets[i].TicketID + "-strikethrough-display").hide();
6744					
6745			    }
6746
6747			    
6748				    if (basketTotal == 0 && true)
6749						$(".basket-processing-fee").html(currencySymbol + 0.00);	
6750					else
6751					{
6752						$(".basket-processing-fee").html(currencySymbol + orderProcessingFee.toFixed(2));	
6753						basketTotal = basketTotal + orderProcessingFee;		    	
6754					}
6755				
6756				$(".basket-extFee3").html(currencySymbol + extFee3Total.toFixed(2));
6757			    $("#basketTotalCell").html(currencySymbol + basketTotal.toFixed(2));
6758			    $(".basket-item-updated-alert").remove();
6759			    $(context).parent().parent().append("<span class='no-mobie basket-item-updated-alert'>updated</span>");
6760			    $(context).removeAttr("disabled");
6761			    $("#error-messages").html("");
6762			    $("#error-messages").removeClass("error-message");
6763			    $(context).css("background","RGBA(0,255,0,0.05)");
6764			    $(".basket-toggle-fees").removeClass("mobile-only"); //class forces item to be visible on mobile to prevent confusion, we have to remove it to hide properly.
6765			    //actWidget("basketChange");
6766				
6767				$(".baskettotal-wrap .ordertotal-subtotal").html(currencySymbol + (ticketTotal + donationTotal + membershipTotal).toFixed(2));
6768				$(".baskettotal-wrap .ordertotal-offfer").html(currencySymbol + (ticketPrintedPriceTotal - ticketTotal).toFixed(2));
6769				$(".baskettotal-wrap .fee1 .ordertotal-tax").html(currencySymbol + extFee1Total.toFixed(2));
6770				$(".baskettotal-wrap .fee2 .ordertotal-tax").html(currencySymbol + extFee2Total.toFixed(2));
6771				$(".baskettotal-wrap .fee3 .ordertotal-tax").html(currencySymbol + extFee3Total.toFixed(2));
6772				$(".baskettotal-wrap .ordertotal-ordertotal").html(currencySymbol + basketTotal.toFixed(2));
6773			}
6774
6775			function revertCart(errors, context){
6776			    $(context).removeAttr("disabled");
6777			    $("#error-messages").html("<div id='pricingCodeErrors'>" + errors + "<div>");
6778			    $("#error-messages").addClass("error-message");
6779			    $(window).scrollTop( 0 );
6780			    $(context).val($(context).data("default"));
6781			    $(context).css("background","RGBA(255,0,0,0.05)");
6782			}
6783
6784			this.sendGet = function(updateURL, callback){
6785				$.get(updateURL, function(basketData){
6786					if($("#pricingCodeErrors").length > 0){
6787						$("#pricingCodeErrors").remove();
6788
6789						if(parseInt($("#error-messages").text().length) <= 0){
6790							$("#error-messages").removeClass("error-message")
6791						}
6792					}
6793					
6794					if(_.isObject(basketData) && _.isArray(basketData.messages.errors) && basketData.messages.errors.length > 0){
6795						for(var i = 0; i < basketData.messages.errors.length; i++){
6796							$("#error-messages").html("<div id='pricingCodeErrors'>" + basketData.messages.errors[i].message + "<div>");
6797						}
6798						
6799						if(!$("#error-messages").hasClass("error-message")){
6800							$("#error-messages").addClass("error-message")
6801						}
6802					}
6803					
6804					callback(basketData);
6805				}, "json");
6806			}
6807
6808			
6809			this.postToBasketUpdate = function(callback){
6810				var o = {};
6811				var a = $("#basket").serializeArray();
6812				$.each(a, function() {
6813					if (o[this.name]) {
6814						if (!o[this.name].push) {
6815							o[this.name] = [o[this.name]];
6816						}
6817						o[this.name].push(this.value || '');
6818					} else {
6819						o[this.name] = this.value || '';
6820					}
6821				});
6822
6823				$.ajax({
6824					type: "POST",
6825					url: "/BasketUpdate.asp",
6826					data: o,			
6827					success: function(data) {
6828						
6829					if (data.messages.errors.length > 0 )
6830					{
6831					for (var i =0;i<data.messages.errors.length;i++)
6832						{
6833							alert(data.messages.errors[i].message);
6834						}
6835					}				 
6836						callback();
6837					}
6838					
6839				});
6840			}
6841
6842			this.startTicketTimers = function() {
6843				var timer,
6844					self = this;
6845
6846				for(var i = 0; i < Basket.expirationTimers.length; i++) {
6847					timer = Basket.expirationTimers[i];
6848					_startExpirationTimer(timer.id, timer.remainingSeconds, timer.serverTime);
6849				}
6850
6851
6852				function _startExpirationTimer(id, remainingSeconds, serverTime) {
6853					var counter,
6854						secondsOffset = (Date() - Date(serverTime))/1000,
6855						$timerDiv = $("#" + id);
6856					
6857					$timerDiv.text("");
6858					counter = setInterval(timer, 1000);
6859					
6860					function timer(){
6861						remainingSeconds--;
6862						if (remainingSeconds <= 0){
6863							clearInterval(counter);
6864							self.setTicketExpired(id);
6865						}
6866						displayRemainingText();
6867					}
6868
6869					function displayRemainingText() {
6870						var timeDisplay;
6871
6872						if(remainingSeconds <= 0){
6873							timeDisplay = "expired";
6874						}else if(remainingSeconds < 3600){
6875							timeDisplay = parseInt(remainingSeconds/60) + ":" + ("0"+(remainingSeconds%60)).slice(-2);
6876						}else{
6877							timeDisplay = parseInt(remainingSeconds/3600) + "+ hours";
6878						}
6879						
6880						$timerDiv.text(timeDisplay);
6881					}
6882				};
6883			};
6884
6885
6886			this.setTicketExpired = function(id) {
6887				$("#expired-error").show();
6888				this.expiredTickets.push(id);
6889			};
6890
6891			this.removeExpiredTickets = function() {
6892				var id,
6893					isBasketEmpty,
6894					$ticketCheckbox;
6895
6896				for(var i = 0; i < this.expiredTickets.length; i++) {
6897					id = "#" + this.expiredTickets[i];
6898					$ticketCheckbox = $(id).parents(".basket-ticket-item").first().find(".ticket-line-item-checkbox");
6899					$ticketCheckbox.prop('checked', true);
6900				}
6901
6902				isBasketEmpty = $(".basket-item").length == this.expiredTickets.length;
6903				this.deleteItems({bypassPrompt: true, reloadBasket: isBasketEmpty});
6904			}
6905		}
6906		Basket.expirationTimers = [];
6907		
6908		$(document).ready(function(){
6909			var basket = new Basket("0FkQ0UVTLSTMzgwTMTgE10CMD2IyMMDNykxTNTIEx0CNDuExMOjL1E1jLjcY2xULEK9KRRUSRx~__U_g_", 0);
6910			basket.startTicketTimers();
6911
6912			$(".select-all-button").on("click", function(){
6913				basket.selectAll('.line-item-checkbox');
6914			});
6915			
6916			$(".deselect-all-button").on("click", function(){
6917				basket.deselectAll('.line-item-checkbox');
6918			});			
6919			
6920			$(".add-coupon").on("click", function(){
6921				basket.addCoupon();
6922			});
6923			$("#couponCode").on("keypress",function(e){
6924			    if(e.keyCode === 13){
6925			        basket.addCoupon();
6926			        e.preventDefault();
6927			    }
6928			})
6929
6930			$(".delete-coupon").on("click", function(){
6931				basket.removeCoupon($(this).siblings(".coupon-value").text());
6932			});
6933			
6934			$("#RemoveTickets").on("click", function(){
6935				basket.deleteItems();
6936			});
6937			
6938			$("#delete-basket").on("click", function(){
6939			    basket.deleteBasket();
6940			});
6941			
6942			$(".change-price-anchor").on("click", function(e){
6943				e.preventDefault();
6944				basket.changeMembershipPricing(this);
6945			});
6946			
6947			$(".pricingcode-dropdown").on("change", function(){
6948				basket.changeSinglePricingCode(this);
6949			});
6950
6951			
6952
6953			$(".mobile-remove, .item-remove").click(function(){
6954                var thisIndex = $(this).data("removeid");
6955				$(".line-item-checkbox-"+thisIndex).prop("checked", true);	
6956				
6957			    basket.deleteItems();
6958			});
6959		});
6960		
6961		function makedonation() {
6962			window.location = "Donate.asp";
6963		}
6964		
6965		function buildCallout(tagId, productType, productId, areaID, message, actionLink){
6966			var productHref;
6967			
6968			//Construct link
6969			switch(productType){
6970				case "event":
6971					productHref = "eventperformances.asp?evt=" + productId;
6972				break;
6973				case "performance":
6974					if(areaID > 0){
6975						productHref = "orderticketsarea.asp?p=" + productId + "&a=" + areaID;
6976					}else{
6977						productHref = "ordertickets.asp?p=" + productId;
6978					}
6979				break;
6980				case "bundle":
6981					productHref = "BundlePurchase_Qty.asp?BundleID=" + productId;
6982				break;
6983				case "campaign":
6984					productHref = "DonationAddToBasket.asp?camp=" + productId;
6985				break;
6986				case "membership":
6987					productHref = "MembershipSelection.asp?type=" + productId;
6988					break;
6989				case "fund"	:
6990					productHref = "DonationSelection.asp?acc=" + productId;
6991					break;
6992				case "0":
6993					productHref=""
6994				break;
6995			}
6996			
6997			//construct bubble text and attach to bubble
6998		
6999			$(tagId).html("<p id=\"message-paragraph\"></p>");
7000			$(tagId + " #message-paragraph").html(message);
7001			if($(tagId + " #message-paragraph p").length){
7002				if (productHref.length>0){
7003					$(tagId + " #message-paragraph p").last().append("<a href=\"" + productHref + "\" style='float:none;'> (" + actionLink + ")</a>");				
7004				}
7005			}else{
7006				if (productType != "0"){
7007				$(tagId + " #message-paragraph").append("<a href=\"" + productHref + "\" style='float:none;'> (&nbsp" + actionLink + "&nbsp)</a>");
7008				}
7009			}
7010			$(".bubble-container").css("visibility", "inherit"); //show with the text already rendered.
7011			
7012		}
7013		
7014		function startExpirationTimer(id, remainingSeconds, serverTime){
7015			Basket.expirationTimers.push({'id': id, 'remainingSeconds': remainingSeconds, 'serverTime': serverTime});
7016		}
7017		function toggleFees(){
7018		    $("#basket").toggleClass("basket-hide-fees");
7019		    $(".ticket-legend-total a.basket-toggle-fees").html("Hide Fees");
7020		    $(".basket-hide-fees .ticket-legend-total a.basket-toggle-fees").html("Show Fees");
7021		    $("a.basket-toggle-fees").html("Hide Fees");
7022		    $(".basket-hide-fees a.basket-toggle-fees").html("Show Fees");
7023		}
7024	</script>
7024
7025</div>
7026<!--footer here-->
7027
7028			<div class="clear-float"></div>
7029			</div><!--End main-container #END-->
7030			<!-- end main arean -->
7031			<div class="clear-float"></div><!--force inner-content pas floated left and right sections-->
7032			
7033		</div><!--END content-inner END-->
7034	</div><!--END content-wrap END-->
7035
7036	<div class="foot-wrap">
7037		<div class="foot-inner center-div site-width">
7038			
7039			<center><div class='sw-banner-ad' data-sw-ad-location='footer'></div>	  </center>
7040
7041			<span class="copyright-text">
7042			Copyright &copy; 2026&nbsp;CincyTicket, All Rights Reserved. <span class="no-mobile">-</span> <br class="mobile-only" />
7043			Ticketing System by <a class="Copyrightlink" target="_blank" href="https://www.cincyticket.net">CincyTicket Solutions</a><br><br>
7044			<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>
7045			<br><br>
7046			</span><!--END copyright-text span END-->
7047
7048			
7049			
7049<script language="JavaScript" type="text/javascript">
7050                //variable defined via external script from HTMLHeadClose.asp
7051                if (typeof TrustLogo !== "undefined") {
7052                    TrustLogo("https://www.cincyticket.com/images/comodo.png", "CL1", "none");
7053                }
7054            </script>
7054
7055		
7056		</div><!--END foot-inner END-->
7057	</div><!--END foot-wrap END-->
7058
7059
7060
7061</div><!--END page-wrap END-->
7062
7063
7064<script language="javascript">
7065    $(function () {
7066        //activate modals
7067        hoverModal();
7068    });
7069</script>
7069
7070
7071
7072    
7072<script async src="//www.cincyticket.com/include/widgets/basket/basketwidget.js?ver=20228b0075" id="showarebasketscript" type="text/javascript"></script>
7072
7073
7074
7075<script>
7076    var cb = function() {
7077    var l = document.createElement('link'); l.rel = 'stylesheet';
7078    l.href = '/include/jqueryui-themes/default/jquery-ui.css';
7079    var h = document.getElementsByTagName('head')[0]; h.parentNode.insertBefore(l, h);
7080    };
7081    var raf = window.requestAnimationFrame       || 
7082          window.webkitRequestAnimationFrame || 
7083          window.mozRequestAnimationFrame    || 
7084          window.oRequestAnimationFrame      || 
7085          window.msRequestAnimationFrame     ;
7086    if (raf) raf(cb);
7087    else window.addEventListener('load', cb);
7088</script>
7088
7089
7090<script type="text/javascript">
7091    $("body").addClass("basket");
7092    if(window.location.hostname.toLowerCase() != "www.cincyticket.com"){
7093        Showare.Logger.warn("Bad Domain Request","www.cincyticket.com - " + window.location.hostname);
7094        window.location.replace("//www.cincyticket.com");
7095    }
7096
7097</script>
7097
7098
7099<!-- ARIA ACCESSABILITY FEATURES -->
7100<script type="text/javascript">
7101    try{
7102                
7103        $(".main-container").attr("role","main");
7104        $("ul.showare-nav").attr("role","list");
7105        $("ul.showare-nav li").attr("role","listitem");
7106        $("ul.showare-nav li a").attr("role","button");
7107        $(".search-control").attr("role","listitem");
7108        $("input.search-text").attr("aria-label","Search");
7109        $(".theme-custom-field-set input").attr("aria-labelledby","custom-field-label").attr("aria-label","Additional Information box");
7110        $(".theme-custom-field-set select").attr("role","listbox").attr("aria-labelledby","custom-field-label").attr("aria-label","Additional Information list");
7111        $(".control-wrap").attr("role","complementary").attr("aria-label","Side Navigation");
7112        $("header.head-wrap").attr("role","banner");
7113        $("div.foot-wrap").attr("role","contentinfo");
7114        $("a.header-logo-link h1").attr("aria-hidden","true");
7115        $(".copyright-text:last").find("a").attr("role", "button");
7116        $(".tab-nav-wrap").find("a").attr("role", "button");
7117        $("#mobile-menu").attr("role","list");
7118        $("#mobile-menu li").attr("role","listitem");
7119        $("#mobile-menu li a").attr("role","button");
7120        $(".heading-text").attr("role","heading").attr("aria-level","2");
7121        
7122        $("a.bodylink").attr("role","button");
7123        $("a.getmembership-link").attr("role","button");
7124        
7125        $("a.header-logo-link h1").attr("aria-level","1");
7126        $("#demo-div").attr("role","region").attr("aria-label","Only a Demo Site");
7127        $("#swCustomListings").attr("aria-label","Featured Custom Listing");
7128
7129        
7130        $(".ad-image").attr("role","presentation");
7131        
7132        
7133        //add a basket link for aria to read
7134        $("li.basket-widget").prepend('<a tabindex="0" class="aria-basket-link" href="basket.asp?fw=1">Shopping Cart</a>');
7135
7136        //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
7137        $('a[target="_blank"]').each(function() {
7138            if (!$(this).attr('aria-label')) {
7139                $(this).attr('aria-label', 'Opens in a new tab.');
7140            }
7141        });
7142        // address the "button can not be empty" - add the Next Month and Previous month to the arrow buttons 
7143        var spanNextMonth = $('<span>', {id: 'bn_next-label',  class: 'sr-only', text: 'Next Month'});
7144        var spanPrevMonth = $('<span>', {id: 'bn_prev-label',  class: 'sr-only', text: 'Previous Month'});  
7145        $('.bn_next').prepend(spanNextMonth);
7146        $('.bn_prev').prepend(spanPrevMonth);
7147
7148        // add ID attribute to main sections
7149        $("header.head-wrap.no-mobile").attr("id","mainheadwrap");
7150        $("div.content-wrap").attr("id","maincontentwrap");
7151        $("div.foot-wrap").attr("id","mainfootwrap");
7152        
7153        // adding Skip link
7154        var skipLinkToHeader = $('<a>', {href: '#mainheadwrap',  class: 'skip-link', text: 'Skip to header content', 'aria-label': 'Skip to header content', 'role': 'link'});
7155        var skipLinkToMainContent = $('<a>', {href: '#maincontentwrap',  class: 'skip-link', text: 'Skip to main content', 'aria-label': 'Skip to main content', 'role': 'link'});  
7156        var skipLinkToFooterContent = $('<a>', {href: '#mainfootwrap',  class: 'skip-link', text: 'Skip to footer content', 'aria-label': 'Skip to footer content', 'role': 'link'}); 
7157
7158        // add created skip link above the main sections
7159        $(skipLinkToHeader).insertBefore("header.head-wrap.no-mobile");  
7160        $(skipLinkToMainContent).insertBefore("div.content-wrap");  
7161        $(skipLinkToFooterContent).insertBefore("div.foot-wrap");  
7162
7163        // use setTimeout to make sure all are loaded before adding attributes
7164        setTimeout(function() { 
7165            $('html').attr('lang', 'en'); 
7166            $(".day-cell.highlight-day").attr("tabindex", "0"); // address the interactive elements should be navigable using the keyboard
7167            $("#ShoWareBasketWidget").find(".cart-item").attr("role", "button").attr("tabindex", "0");
7168            $("#ShoWareBasketWidget .cart-item .cart-item-pic").attr("role", "cart presentation");
7169            $("#ShoWareBasketWidget .cart-item .cart-item-pic .sw-i-cart").attr("role", "cart presentation");
7170            $(".featured-items-item .streaming-note").attr("role","presentation");
7171            $(".pl-item a.pl-popup-link").attr("role","button");
7172            $(".pl-date-block-image").attr("role","img");
7173            $("#epImage2 img").attr("alt","Event Banner");
7174            $('.navigation.sw-nav > a[href*="basket.asp"]').attr({
7175                'title': 'View Basket',
7176                'aria-label': 'View Basket'
7177            });
7178
7179            // address the "Incorrect use of aria-describedy" - this is used in the header cart but there's no ID to refer it to
7180            var cartTitle = $('.cart-item-desc').attr('title');
7181            var spanCartItemDesc = $('<span>', {id: 'cart-text',  class: 'sr-only', text: cartTitle});
7182            $('.cart-item-desc').prepend(spanCartItemDesc);
7183            
7184            // address the "Incorrect use of aria-describedy" - this is used in the calendar and no ID to refer it to
7185            var calendarTableTitle = $('.calendar-object table:first').attr('title');
7186            var spanCalendarIDAdded = $('<span>', {id: 'month',  class: 'sr-only', text: calendarTableTitle});
7187            $('.calendar-object table:first').prepend(spanCalendarIDAdded);
7188            $('img[src$="sectigo_trust_seal_lg_140x54.png"]').attr({alt: "Sectigo Seal", 'aria-label': "Sectigo Seal"});
7189            $("a.aria-basket-link").attr("role","button").attr("aria-label","Shopping Cart");
7190            $(".month-wrap .month").attr("aria-level","3");
7191            
7192            var $metaViewport = $('meta[name="viewport"]');
7193            if ($metaViewport.length) {
7194                $metaViewport.attr('content', 'width=device-width, initial-scale=1.0, minimum-scale=1.0');
7195            } else {
7196                $('head').append('<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0">');
7197            }
7198
7199        }, 1200);
7200
7201        setTimeout(function() {   
7202            $('[data-index]').removeAttr('data-index');
7203            $('[tabindex]').removeAttr('tabindex');
7204            $('[tabindes]').removeAttr('tabindes');
7205            
7206            let HeaderElements = $('.head-inner').find('.logo-container a, .showare-nav-inner a, select, textarea, input, a.button,#ShoWareBasketWidget .cart-item');
7207            let SideBarElements = $('.show-wrap').find('a, .sw-datepicker td.highlight-day, .bn_prev, .month, .bn_next');
7208            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
7209                    
7210            // Header
7211            HeaderElements.each(function() {
7212                $(this).removeAttr('tabindex');
7213            });
7214            $(".showare-nav li").removeAttr('tabindex');
7215            $("#ShoWareBasketWidget .cart-item").removeAttr('tabindex');
7216            $(".aria-basket-link").removeAttr('tabindex');
7217            $("#searchButton").removeAttr('tabindex');
7218            $(".show-wrap .control-box").removeAttr('tabindex');
7219    
7220                HeaderElements.each(function(index) {
7221                    $(this).attr('tabindex', 0);
7222                });	
7223                // Sidebar
7224                SideBarElements.each(function() {
7225                    $(this).removeAttr('tabindex');
7226                });
7227    
7228                SideBarElements.each(function(index) {
7229                    $(this).attr('tabindex', 0);
7230                });
7231    
7232                // Main Content
7233                allElements.each(function() {
7234                    $(this).removeAttr('tabindex');
7235                });
7236    
7237                allElements.each(function(index) {
7238                    if (!$(this).attr('tabindex')) {
7239                        $(this).attr('tabindex', 0);
7240                    }
7241                });
7242            
7243            $(".performance-block-date-link").attr('tabindex', -1);
7244            $(".basket-widget a.aria-basket-link").attr('tabindex', -1);
7245            $("a.skip-link").attr('tabindex', -1);
7246            $(".copyright-text a").each(function(index) {
7247                $(this).attr('tabindex', 0);
7248            });
7249
7250            $(".highlightinfo-wrap .prevevent-btn").attr("aria-label", "Previous Event");
7251            $(".highlightinfo-wrap .nextevent-btn").attr("aria-label", "Next Event");
7252            $(".highlightinfo-wrap .button-wrap a.button").attr("role", "button").attr("aria-label", "Buy Tickets");
7253            $(".featuredevent-box  .bottominfo-wrap a.button.featured-togglelink").attr("role", "button").attr("aria-label", "Toggle Down to Open event information");
7254            $('img[src$="sectigo_trust_seal_lg_140x54.png"]').attr({alt: "Sectigo Seal", 'aria-label': "Sectigo Seal"});
7255            $(".info-box a").attr("role", "button").attr("aria-label", "Venue Link");
7256            $("a.forgot-password-link").attr("role", "button").attr("aria-label", "Forgot Password");
7257           
7258            $("#EventInformationWrap").attr("tabindex", "0"); 
7259            $("#venuesWidget .right a.button").attr("role", "button"); 
7260            $("table.cal thead th").attr('scope', 'col');
7261            $('.otherimages img').each(function () {
7262                var src = $(this).attr('src');
7263                if (src) {
7264                    var filename = src.substring(src.lastIndexOf('/') + 1); // Get the filename
7265                    $(this).attr('alt', filename); // Set as alt
7266                }
7267            });
7268            $('.mainimage img').each(function () {
7269                var src = $(this).attr('src');
7270                if (src) {
7271                    var filename = src.substring(src.lastIndexOf('/') + 1); // Get the filename
7272                    $(this).attr('alt', filename); // Set as alt
7273                }
7274            });
7275            $('.bundle-event-container').each(function() {
7276                var altText = $(this).find('.event-container-header').text().trim();
7277                $(this).find('.bundle-event-image').attr('alt', altText);
7278            });
7279            $('.related-event').each(function() {
7280                var altTextH3 = $(this).find('h3').text().trim();
7281                $(this).find('img').attr('alt', altTextH3);
7282            });
7283
7284        }, 3500);
7285        
7286
7287    }catch(e){
7288        console.log("Failed to update header for accessability:");
7289        console.log(e);
7290    }
7291</script>
7291
7292<style>
7293*:focus {box-shadow: 0 0 0 3px #fff,0 0 4px 6px #ccc!important;}
7294
7295/* Hide visually but keep accessible to screen readers */   
7296    .sr-only {
7297        position: absolute !important;
7298        width: 1px !important;
7299        height: 1px !important;
7300        padding: 0 !important;
7301        margin: -1px !important;
7302        overflow: hidden !important;
7303        clip: rect(0, 0, 0, 0) !important;
7304        border: 0 !important;
7305    }
7306    .skip-link {
7307        position: absolute;
7308        left: -10000px;
7309        top: auto;
7310        width: 1px;
7311        height: 1px;
7312        overflow: hidden;
7313    }
7314/* Style for focused interactive elements visible to accessibility readers */
7315    :focus-visible {
7316        outline: 2px solid #ccc; /* Show the outline for accessibility readers */
7317        outline-offset: 2px; /* Optional: Adjust the spacing between the element and the outline */
7318    }
7319</style>
7320
7321<script>
7322setTimeout(function() {
7323	$( document ).ready(function() {
7324		$('#mobile-menu li a').each(function(){			
7325			if($(this).is(':contains("close")')) {
7326				$(this).attr("onclick","actWidget('');");
7327			}
7328			if($(this).is(':contains("search")')) {
7329				$(this).attr("onclick","actSearch();return 0;");
7330			}
7331
7332            if($(this).is(':contains("shopping cart")')) {
7333                $(this).attr("HREF","https://www.cincyticket.com/basket.asp?fw=1");
7334            }
7335		});
7336		$('#mobile-menu').removeAttr("onclick");
7337	});
7338}, 300);
7339</script>
7339
7340
7341<script>
7342// Add control wrap's height as the min-height for main-constrain-width so the sidebar won't overlap to the footer
7343setTimeout(function() {
7344	$( document ).ready(function() {
7345        varControlWrapHeight = $(".control-wrap").height() + "px";
7346		$(".main-constrain-width").css( "min-height", varControlWrapHeight );
7347	});
7348}, 300);
7349</script>
7349
7350
7351
7352
7353</body>
7354</html>
7355<script type="text/javascript">
7356
7357try{
7358    swEnhancedEcommerce.fetchBasketProducts('basket', 0, true);
7359
7360}catch(e){
7361    console.log(e);
7362}
7363extractIcons();
7364$("#checkout-button").click(function(){
7365    //add ecommerce
7366    try{
7367        swEnhancedEcommerce.sendCheckoutStep(1, "checkout");
7368    }catch(e){
7369        console.log(e);
7370    }
7371    if(false){
7372        //OPS-CS functionality
7373        //validate heard about
7374        var heardAbout = $("#heard-about").val();
7375        var soldFor = $("#soldfor").val();
7376        if(heardAbout == "" && true){
7377            alert('Please select a value for "How did you hear about us"');
7378            return 0;
7379        }else{
7380            $.get("/include/ajax.asp",
7381		        {
7382		            action: "setBasketSoldforHeardabout",
7383		            HeardAboutValue: heardAbout,
7384                    soldForValue: soldFor
7385		        })
7386		        .done(function (data) {					
7387                    goToCheckoutTicketInfo();
7388		        })
7389		        .fail(function (jqxhr, textStatus, error) {
7390		            var err = textStatus + ", " + error;		            
7391					goToCheckoutTicketInfo();
7392		        })
7393            
7394        }
7395    }else{	
7396        goToCheckoutTicketInfo();
7397    }
7398	
7399});
7400
7401// Consolidated checkout navigation ensuring TILA acceptance when required
7402function goToCheckoutTicketInfo(){
7403	// Use the payment plan state if available (tilaAccepted lives inside basketPaymentPlan closure)
7404	if (window.basketPaymentPlan) {
7405		if (typeof basketPaymentPlan.isPayInFullSelected === 'function' && basketPaymentPlan.isPayInFullSelected()) {
7406			basketPaymentPlan.clearPaymentPlanSessions();
7407		}
7408		if (basketPaymentPlan.tilaAccepted) {
7409			window.location.href="Checkout_TicketInfo.asp";
7410			return;
7411		}
7412		// If a plan is selected that requires TILA and not yet accepted, invoke modal then proceed
7413		if (typeof basketPaymentPlan.shouldRequireTila === 'function' && basketPaymentPlan.shouldRequireTila()) {
7414			basketPaymentPlan.showTilaModal(function(){		
7415				// If TILA is accepted, proceed to checkout
7416				//if (basketPaymentPlan.tilaAccepted) {
7417					window.location.href="Checkout_TicketInfo.asp";
7418				//}
7419			});
7420			return;
7421		}
7422	}
7423	// Fallback (no payment plan)
7424	window.location.href="Checkout_TicketInfo.asp";
7425}
7426
7427						 
7428    toggleFees();                     
7429
7430var cartTotal, basket = {};
7431
7432function getClientBasket(callback) {
7433    $.ajax({
7434        type: "GET",
7435        dataType: "json",
7436        url: "/include/modules/checkout/client_basket.asp",
7437        data: {},
7438        timeout: 30000
7439    }).done(function(data) {
7440        loadBasket(data);
7441        if(callback && typeof callback === 'function') {
7442            callback();
7443        }
7444    }).fail(function(xhr, errorText, error) {
7445        return 0;
7446    });
7447}
7448
7449function loadBasket(data) {
7450    if (data.basket) {
7451        console.log(basket)
7452        basket = data.basket;
7453        if(basket.discounts.HasBasketDiscounts == 1){
7454            if(basket.appliedPromoCode.PromoCode){
7455                $("#PromoCodeInput").val(basket.appliedPromoCode.PromoCode);
7456                applyPromoCode();
7457            }else{
7458                calculateTotals()
7459            }
7460        }
7461    }
7462}
7463getClientBasket();
7464
7465function updatePaymentPlansTotals(){
7466	if(typeof basketPaymentPlan !== 'undefined'){
7467		basketPaymentPlan.refreshAmounts(0);
7468	}
7469}
7470
7471function applyPromoCode(){
7472    clearErrors($("#PromoCodeWrap"))
7473    $.ajax({
7474        url: '/include/modules/checkout/applyPromoCode.asp',
7475        method: 'GET',
7476        headers: {
7477           'Content-Type': "application/x-www-form-urlencoded;charset=utf-8"
7478         },
7479        data: {
7480            "promocode" : $("#PromoCodeInput").val()
7481        }, 
7482        success: function(resp) {   
7483            resp = JSON.parse(resp);
7484            if (resp.success == 1){
7485                try {
7486                    addDataLayer("TicketingPromo", String($("#PromoCodeInput").val()));
7487                } catch (e) {
7488                    console.log(e);
7489                }
7490                $(".applied-code-info").html(resp.promoCode);
7491                $("#ActivePromoInfo").show();
7492                basket.discounts = resp;
7493                basket.discounts.HasBasketDiscounts = basket.discounts.HasBasketDiscounts ? 1 : 0;
7494                basket.discounts.discountAmount = basket.discounts.TotalBasketDiscountAmount;
7495                addDataLayer("TicketingDiscountAmount", basket.discounts.discountAmount);
7496
7497				if (basket.discounts.HasBasketDiscounts === 1) {
7498					updatePaymentPlansTotals();
7499				}
7500
7501                if($("#checkoutPayment").hasClass("active")){
7502                    calculateTotals(true);
7503                }else{
7504                    calculateTotals(false);
7505                    $("#paymentChangeType").show();
7506                }
7507                
7508            }else{
7509                displayPromoCodeError($("#PromoCodeWrap"), resp.error)
7510            }
7511        }
7512    })
7513}
7514$("#PromoCodeInput").on('keyup', function(e){
7515    if(e.key === 'Enter' || e.keyCode === 13){
7516        console.log(e);
7517        applyPromoCode();
7518    }
7519});
7520function clearErrors(myForm) {
7521    myForm.find(".promocode-error-msg").remove();
7522
7523}
7524function displayPromoCodeError(blockObj, message) {
7525    //blockObj should be an instance of a DOM element
7526    if (!(blockObj[0] instanceof HTMLElement)) return;
7527    $("<div tabindex='0' class='promocode-error-msg' role='alert'><span class='error-message floating-error'>" + message + "</span></div>").insertAfter("#PromoControlsWrap");
7528    $(".error-message").focus();
7529    setTimeout(function() {
7530        $("#PromoApplyCodeButton").css("margin-bottom","2px");
7531        $('#PromoCodeInput').addClass("has-error");
7532    }, 10);
7533
7534}
7535function calculateTotals() {
7536    var ticketTotal = 0, membershipTotal = 0, donationTotal = 0;
7537    if (basket.items.tickets) {
7538        $.each(basket.items.tickets, function(index, ticket) {
7539            ticketTotal += ticket.PriceWithFees;
7540        });
7541    }
7542    if (basket.items.donations) {
7543        $.each(basket.items.donations, function(index, donation) {
7544            donationTotal += donation.Price;
7545        });
7546    }
7547    if (basket.items.memberships) {
7548        $.each(basket.items.memberships, function(index, membership) {
7549            membershipTotal += membership.Price;
7550        });
7551    }
7552
7553    //basket item total
7554    cartTotal = ticketTotal + membershipTotal + donationTotal; 
7555    if(basket.discounts.HasBasketDiscounts === 1){
7556        basket.discounts.discountAmount = Math.round(basket.discounts.discountAmount * 1e2)/1e2;
7557        basket.discounts.TotalAdjustedExtFee1 = Math.round(basket.discounts.TotalAdjustedExtFee1 * 1e2)/1e2;
7558        basket.discounts.TotalAdjustedExtFee2 = Math.round(basket.discounts.TotalAdjustedExtFee2 * 1e2)/1e2;
7559        basket.discounts.TotalAdjustedExtFee3 = Math.round(basket.discounts.TotalAdjustedExtFee3 * 1e2)/1e2;
7560		
7561		cartTotal = cartTotal - basket.discounts.discountAmount - basket.discounts.TotalAdjustedExtFee1 - basket.discounts.TotalAdjustedExtFee2 - basket.discounts.TotalAdjustedExtFee3;
7562		cartTotal += basket.orderFee;
7563        cartTotal = parseFloat(cartTotal).toFixed(2);
7564    }
7565    updateBasketTotals(cartTotal);
7566}
7567function updateBasketTotals(cartTotal) {        
7568    if(basket.discounts.HasBasketDiscounts === 1){
7569		$("#promoCodeLabel").text("Promo Code Discount:");
7570        $("#promoCodeLabel, #promoCodeDiscount").show();
7571        $("#promoCodeDiscount").html(formatCurrency((basket.discounts.discountAmount + basket.discounts.TotalAdjustedExtFee1 + basket.discounts.TotalAdjustedExtFee2 + basket.discounts.TotalAdjustedExtFee3)*-1));        
7572    }    
7573	$("#basketTotalCell").html(formatCurrency(cartTotal));
7574}
7575function formatCurrency(num) {
7576    if (typeof num != 'undefined' && num != null) {
7577        num = num.toString().replace(basket.currencySymbol, '').replace(',', '');
7578        if (isNaN(num))
7579            num = "0";
7580        sign = (num == (num = Math.abs(num)));
7581        num = Math.floor(num * 100 + 0.50000000001);
7582        cents = num % 100;
7583        num = Math.floor(num / 100).toString();
7584        if (cents < 10)
7585            cents = "0" + cents;
7586        for (var i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++)
7587            num = num.substring(0, num.length - (4 * i + 3)) + ',' +
7588            num.substring(num.length - (4 * i + 3));
7589        return (((sign) ? '' : '-') + basket.currencySymbol + num + '.' + cents);
7590    } else {
7591        return '';
7592    }
7593}
7594
7595</script>
vendor: 2 bytes, line 7595
7595

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.