1(function ($, window, document, undefined) { 2 $.support.cors = true; 3 4 // bootstrap-datepicker puts aria-selected on its day cells, but those cells have 5 // role="button" -- and aria-selected is only valid on gridcell/option/row/tab/treeitem. 6 // The selected state is already carried by aria-pressed on the same cell, so dropping 7 // aria-selected is lossless for AT users and clears axe's aria-allowed-attr rule. 8 function installCalendarAriaFix(root) { 9 if (window.__amEventsCalendarAriaFixInstalled) return; 10 window.__amEventsCalendarAriaFixInstalled = true; 11 var target = root && root.querySelectorAll ? root : (document.body || document.documentElement); 12 var strip = function () { 13 var tds = target.querySelectorAll('td.day[aria-selected]'); 14 for (var i = 0; i < tds.length; i++) tds[i].removeAttribute('aria-selected'); 15 }; 16 strip(); 17 if (window.MutationObserver) { 18 var scheduled = false; 19 var flush = function () { 20 scheduled = false; 21 strip(); 22 }; 23 var schedule = function () { 24 if (scheduled) return; 25 scheduled = true; 26 if (window.requestAnimationFrame) { 27 window.requestAnimationFrame(flush); 28 return; 29 } 30 window.setTimeout(flush, 0); 31 }; 32 var obs = new MutationObserver(schedule); 33 obs.observe(target, { childList: true, subtree: true }); 34 } 35 } 36 37 function escapeHtml(value) { 38 return String(value == null ? '' : value) 39 .replace(/&/g, '&') 40 .replace(/</g, '<') 41 .replace(/>/g, '>') 42 .replace(/"/g, '"') 43 .replace(/'/g, '''); 44 } 45 46 var pluginName = "amEvents", 47 defaults = { 48 title: '', 49 view: 'list', 50 range: 'today', 51 ages: [], 52 excludedAges: [], 53 types: [], 54 excludedTypes: [], 55 locale: 'en-US', 56 timezone: 'America/New_York', 57 locations: [], 58 excludedLocations: [], 59 linkTarget: '_blank', 60 inCellEvents: 3, 61 private: false, 62 eventsGroupCalenderBAge: false, 63 term: '', 64 end: '', 65 start: '', 66 gridDate: '', 67 filters: {}, // added for brochure 68 filterOptions: {}, 69 filterMaxItems: 15, 70 filterCurrentColumn: null, 71 filterCurrentColumnCount: 0, 72 showBrochure: false, 73 showRSS: false, 74 showICAL: false, 75 singleBranch: false, 76 limitWaitlist: false, 77 allowWaitlistSubscription: false, 78 customInterestedText: '', 79 brochuredata: null, 80 allowSubs: false, 81 brochureNoPopup: false, 82 showImagesInListGrid: false, 83 testMode: 0, 84 duration: '', 85 emitEvents: false, 86 embeddedMode: false, 87 embedSource: '', 88 parentOrigin: '', 89 }; 90 91 function Plugin(element, options) { 92 var self = this; 93 this.element = element; 94 this.$element = $(element); 95 96 if (!options.view) options.view = self._readCookie('eventsView') ? self._readCookie('eventsView') : 'list'; 97 this.settings = $.extend({}, defaults, options); 98 this._defaults = defaults; 99 this._name = pluginName; 100 this.paused = false; 101 this.rangeUpdating = false; 102 this.tagsLoaded = false; 103 this.locationsLoaded = false; 104 this.agesLoaded = false; 105 this._init(); 106 } 107 108 $.extend(Plugin.prototype, { 109 _init: function () { 110 var self = this; 111 var customEventLabel = escapeHtml(self.settings.customEventLabel); 112 var customEventsLabel = escapeHtml(self.settings.customEventsLabel); 113 var params = self._getURLSearchParameters(); 114 if (params.l) { 115 self.settings.locations = params.l 116 .split(',') 117 .map(s => s.trim().toLowerCase().replace(/,/g, '')) 118 .filter(Boolean); 119 } 120 if (params.et) { 121 self.settings.excludedTypes = params.et.split(',').map(s => s.trim().toLowerCase()); 122 } 123 if (params.t) { 124 try { 125 const decodedTypes = JSON.parse(decodeURIComponent(params.t)); 126 self.settings.types = decodedTypes.map(s => s.trim().toLowerCase()); 127 } catch (e) { 128 const splitTypes = decodeURIComponent(params.t).split(',').map(s => s.trim().toLowerCase()); 129 self.settings.types = [...new Set(splitTypes)]; 130 } 131 } 132 self.initComplete = false; 133 self._embeddedHeightFrame = null; 134 self._lastEmbeddedHeight = 0; 135 self._embeddedHeightObserver = null; 136 self._embeddedResizeObserver = null; 137 self.$element.addClass('events-holder'); 138 if (self.settings.embeddedMode) { 139 // When custom CSS is used to set the html/body height to 100% it breaks the height calculation used by this embedded widget. 140 // By setting the height to auto we mitigate this. 141 document.documentElement.style.cssText = 'height: auto !important;'; 142 document.body.style.cssText = 'height: auto !important;'; 143 self.$element.addClass('events-holder--embedded'); 144 self.$element.on('am-events-listings.url-update', function (event, data) { 145 if (data && data.data) { 146 self._postToParent('url-update', { pathAndQuery: data.data }); 147 } 148 }); 149 self._embeddedHostMessageHandler = function (event) { 150 var origin = self._getParentOrigin(); 151 if (!origin || event.origin !== origin) { 152 return; 153 } 154 if (event.source !== window.parent) { 155 return; 156 } 157 var data = (event.data && typeof event.data === 'object') ? event.data : {}; 158 if (data.source !== 'create-classic-attend-host' || !data.type) { 159 return; 160 } 161 if (data.type === 'height-request') { 162 self._scheduleHeightPost(true); 163 return; 164 } 165 if (data.type !== 'navigate' || !data.payload || !data.payload.pathAndQuery) { 166 return; 167 } 168 try { 169 var next = new URL(data.payload.pathAndQuery, window.location.origin); 170 if (next.pathname === window.location.pathname && next.search === window.location.search) { 171 return; 172 } 173 window.location.href = next.pathname + next.search + next.hash; 174 } catch (e) { 175 return; 176 } 177 }; 178 window.addEventListener('message', self._embeddedHostMessageHandler); 179 $(document).off('click.amEventsEmbeddedNavigate').on('click.amEventsEmbeddedNavigate', 'a[data-embedded-event-path]', function (event) { 180 if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.which === 2) { 181 return; 182 } 183 var pathAndQuery = $(this).attr('data-embedded-event-path'); 184 if (!pathAndQuery || !self._canPostToParent()) { 185 return; 186 } 187 event.preventDefault(); 188 self._postToParent('navigate', { pathAndQuery: pathAndQuery }); 189 }); 190 if (typeof MutationObserver !== 'undefined') { 191 self._embeddedHeightObserver = new MutationObserver(function () { 192 self._scheduleHeightPost(); 193 }); 194 self._embeddedHeightObserver.observe(self.element, { 195 attributes: true, 196 childList: true, 197 subtree: true 198 }); 199 } 200 if (typeof ResizeObserver !== 'undefined') { 201 self._embeddedResizeObserver = new ResizeObserver(function () { 202 self._scheduleHeightPost(); 203 }); 204 self._embeddedResizeObserver.observe(self.element); 205 } 206 window.addEventListener('load', function () { 207 self._scheduleHeightPost(); 208 }); 209 } 210 if (self.settings.singleBranch) { 211 self.$element.addClass('events-single-branch'); 212 } 213 var navigation = $('<div class="row events-filter-row"></div>').appendTo(self.element); 214 self.views = $('<div class="row events-view-row"></div>').appendTo(self.element); 215 216 $('<div class="col-md-4 col-sm-12 col-xs-12"><label for="eventsearch" class="sr-only">Search events</label><input id="eventsearch" class="form-control events-search-field" placeholder="Search for ' + customEventsLabel + '" type="text"/></div>').appendTo(navigation); 217 var filters = $('<div class="col-md-6 col-sm-12 col-xs-12"><span class="hidden-xs events-single-hidden">Filter by: </span></div>').appendTo(navigation);
218 self.viewPicker = $('<div class="col-md-2 col-sm-12 col-xs-12 events-views"></div>').appendTo(navigation); 219 220 $('<button class="events-option-dropdown noselect events-single-hidden" data-show-filter="events-location-section" aria-label="Location filter button" tabindex="0">Location</button>').appendTo(filters); 221 $('<button class="events-option-dropdown noselect" data-show-filter="events-age-section" aria-label="Age group filter button" tabindex="0">Age group</button>').appendTo(filters); 222 $('<button class="events-option-dropdown noselect" data-show-filter="events-type-section" aria-label="' + customEventLabel + ' type filter button" tabindex="0">' + customEventLabel + ' type</button>').appendTo(filters); 223 224 var checked = (self.settings.locations.length + self.settings.excludedLocations.length) === 0 ? 'checked="checked"' : ''; 225 226 self.locationList = $('<div id="event_locations"></div>'); 227 $('<div class="events-filter-section events-location-section">' + 228 '<div class="events-filter-close">close</div>' + 229 '<div class="heading4">Location</div>' + 230 '<div class="checkbox">' + 231 ' <label for="loc_all" class="check-all-filter-text">' + 232 ' <input id="loc_all" type="checkbox" ' + checked + ' aria-label="View all locations">View events at all branches' + 233 ' </label>' + 234 '</div><hr>' + 235 '</div>').append(self.locationList).appendTo(self.element); 236 237 var checked = self.settings.ages.length === 0 ? 'checked="checked"' : ''; 238 self.ageList = $('<div id="event_ages"></div>'); 239 $('<div class="events-filter-section events-age-section">' + 240 '<div class="events-filter-close">close</div>' + 241 '<div class="heading4">Age group</div>' + 242 '<div class="checkbox">' + 243 ' <label for="group_all" class="check-all-filter-text">' + 244 ' <input id="group_all" type="checkbox" ' + checked + ' aria-label="View all Ages">View all age groups' + 245 ' </label>' + 246 '</div><hr>' + 247 '</div>').append(self.ageList).appendTo(self.element); 248 249 var checked = self.settings.types.length === 0 ? 'checked="checked"' : ''; 250 self.typeList = $('<div id="event_types"></div>'); 251 $('<div class="events-filter-section events-type-section">' + 252 '<div class="events-filter-close">close</div>' + 253 '<div class="heading4">' + customEventLabel + ' type</div>' + 254 '<div class="checkbox">' + 255 ' <label for="type_all" class="check-all-filter-text">' + 256 ' <input id="type_all" type="checkbox" ' + checked + ' aria-label="View all Types">View all ' + customEventLabel + ' types' + 257 ' </label>' + 258 '</div><hr>' + 259 '</div>').append(self.typeList).appendTo(self.element); 260 261 262 self.todayButton = $('<button aria-label="Show events for today" class="events-option-dropdown">Today</button>').appendTo(self.viewPicker); 263 264 $('<i data-view="list" role="button" tabindex="0" aria-pressed="true" aria-label="Show list view" class="fa fa-list"></i>').appendTo(self.viewPicker); 265 $('<i data-view="grid" role="button" tabindex="0" aria-pressed="mixed" aria-label="Show calendar view" class="am-events"></i>').appendTo(self.viewPicker); 266 267 268 self.gridView = $('<div data-view="grid" class="events-list-view"></div>').appendTo(self.views); 269 var listView = $('<div data-view="list" class="events-list-view"></div>').appendTo(self.views); 270 var brochureButton = self.settings.showBrochure ? '<div class="events-brochure"><button class="events-option-dropdown events-brochure-button"><i class="fa fa-file-pdf-o" style="color: #ED0202;"></i> Create Brochure</button></div>' : ''; 271 272 if (self.settings.start !== '') { 273 self.settings.start = moment(self.settings.start); 274 self.settings.end = self.settings.end !== '' ? moment(self.settings.end) : self.settings.start; 275 } else { 276 self.settings.start = moment(); 277 self.settings.end = self.settings.start 278 } 279 280 self._quickRangeBase = (self.settings.embeddedMode && self._getParentOrigin()) 281 ? self._getParentOrigin() + window.location.pathname 282 : ''; 283 284 self.listViewLeft = $('<div class="events-left">' + 285 '<div class="events-details">' + 286 '<ul class="nav nav-tabs" role="tablist">' + 287 '<li role="presentation" class="active"><a href="#calendar" aria-controls="calendar" role="tab" data-toggle="tab">Calendar</a></li>' + 288 '<li role="presentation"><a href="#date_range" aria-controls="date_range" role="tab" data-toggle="tab">Date range</a></li>' + 289 '</ul>' + 290 '<div class="tab-content">' + 291 '<div role="tabpanel" class="tab-pane active" id="calendar">' + 292 '<div class="events-calendar"></div>' + 293 '</div>' + 294 '<div role="tabpanel" class="tab-pane" id="date_range">' + 295 '<div class="events-range input-daterange input-group" id="datepicker">' + 296 '<label for="start">From</label>' + 297 '<div class="input-group events-date-input">' + 298 '<input type="text" class="form-control" value="' + self.settings.start.format('MMMM D YYYY') + '" name="start" id="start" aria-label="Start Date"><span class="input-group-addon"><i class="am-events"></i></span>' + 299 '</div>' + 300 '<label for="end">To</label>' + 301 '<div class="input-group events-date-input">' + 302 '<input type="text" class="form-control" value="' + (self.settings.end !== '' ? self.settings.end.format('MMMM D YYYY') : self.settings.start.format('MMMM D YYYY')) + '" name="end" id="end" aria-label="End Date"><span class="input-group-addon"><i class="am-events"></i></span>' + 303 '</div>' + 304 '</div>' + 305 '</div>' + 306 '</div>' + 307 '</div>' + 308 '<div class="events-link hidden-xs">' + 309 '<a aria-label="Show events for today" href="' + self._quickRangeBase + '?r=today" data-type="today" data-embedded-nav-processed="1">Today</a>' + 310 '<a aria-label="Show events for tomorrow" href="' + self._quickRangeBase + '?r=tomorrow" data-type="tomorrow" data-embedded-nav-processed="1">Tomorrow</a>' + 311 '<a aria-label="Show events for this week" href="' + self._quickRangeBase + '?r=thisweek" data-type="thisweek" data-embedded-nav-processed="1">This week</a>' + 312 '<a aria-label="Show events for next week" href="' + self._quickRangeBase + '?r=nextweek" data-type="nextweek" data-embedded-nav-processed="1">Next week</a>' + 313 '<a aria-label="Show events for this month" href="' + self._quickRangeBase + '?r=thismonth" data-type="thismonth" data-embedded-nav-processed="1">This month</a>' + 314 '<a aria-label="Show events for next month" href="' + self._quickRangeBase + '?r=nextmonth" data-type="nextmonth" data-embedded-nav-processed="1">Next month</a>' + 315 '</div>' + 316 '</div>
316').appendTo(listView); 317 self.listViewRight = $('<div class="events-right">' + 318 '<h1 class="headingtext">' + customEventsLabel + '</h1>' + 319 '<div class="events-date-bar noselect">' + 320 '<div class="events-day-title">' + 321 '<span data-by="-1" tabindex="0" role="button" aria-label="Previous day" class="events-change-day events-change-prev fa fa-chevron-left"></span>' + 322 '<span aria-live="polite" class="events-date-string headingtext"></span>' + 323 '<span data-by="1" tabindex="0" role="button" aria-label="Next day" class="events-change-day events-change-next fa fa-chevron-right"></span>' + 324 '</div>' + 325 '<div class="events-range-title">' + 326 '<div class="events-date-range-string headingtext"></div>' + 327 '</div>' + 328 '</div>' + 329 '<div class="events-filter-details">' + 330 '<div aria-label="Clear the current filters" class="events-filter-clear">Clear filter</div>' + 331 '<div class="events-filter-message"></div>' + 332 '</div>' + 333 '<div class="events-body"></div>' + 334 '</div>').appendTo(listView); 335 336 var a = moment().startOf('week'); 337 var b = a.clone().add(7, 'days'); 338 var days = ''; 339 for (var m = a; m.isBefore(b); m.add(1, 'days')) { 340 days += '<div>' + m.format('dddd') + '</div>'; 341 } 342 $('<div class="events-grid">' + 343 '<h2 class="headingtext">' + customEventsLabel + '</h2>' + 344 '<div class="events-date-bar noselect">' + 345 '<div class="events-day-title">' + 346 '<span data-by="-1" tabindex="0" role="button" aria-label="Previous month" class="events-change-day events-change-prev fa fa-chevron-left"></span>' + 347 '<span aria-live="polite" class="events-date-string headingtext"></span>' + 348 '<span data-by="1" tabindex="0" role="button" aria-label="Next month" class="events-change-day events-change-next fa fa-chevron-right"></span>' + 349 '</div>' + 350 '</div>' + 351 '<div class="events-filter-details">' + 352 '<div class="events-filter-clear">Clear filter</div>' + 353 '<div class="events-filter-message"></div>' + 354 '</div>' + 355 '<div class="events-grid-header">' + days + '</div>' + 356 '<div class="events-grid-body"></div>' + 357 '</div>').appendTo(self.gridView); 358 359 360 self._loadFilters(); 361 self._bindEvents(); 362 if (self.settings.range === 'today' && !self.settings.filters.date && (self.settings.start && !self.settings.end)) { 363 var now = moment(); 364 $('.events-range.input-daterange input[name=start]', this.listViewLeft).datepicker('update', now.format('MMMM D YYYY')); 365 $('.events-range.input-daterange input[name=end]', this.listViewLeft).datepicker('update', now.endOf('month').format('MMMM D YYYY')); 366 $('.events-details a[href="#date_range"]', this.listViewLeft).tab('show'); 367 } 368 369 var acceptableRanges = ['days', 'weeks', 'months']; 370 if (acceptableRanges.includes(self.settings.range) && '' != self.settings.duration) { 371 self._updateDateRange(); 372 } else if (self.settings.range !== 'today' && $('a[data-type=' + self.settings.range + ']').length > 0) { 373 self._updateDateRange(); 374 } else { 375 376 if ((self.settings.start && self.settings.end) && (self.settings.start.format('MMMM D YYYY') !== self.settings.end.format('MMMM D YYYY'))) { 377 $('.events-details a[href="#date_range"]', this.listViewLeft).tab('show'); 378 $('.events-range.input-daterange input[name=start]', this.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 379 $('.events-range.input-daterange input[name=end]', this.listViewLeft).datepicker('update', (self.settings.end ? self.settings.end.format('MMMM D YYYY') : self.settings.start.format('MMMM D YYYY'))); 380 } 381 382 if (self.settings.start && !self.settings.end) { 383 $('.events-details a[href="#calendar"]', this.listViewLeft).tab('show'); 384 } 385 } 386 if (self.settings.term && self.settings.term.length > 0) { 387 $('.events-search-field', navigation).val(self.settings.term); 388 } 389 390 self.setView(self.settings.view); 391 // self.setView('grid'); 392 self.initComplete = true; 393 self._scheduleHeightPost(); 394 }, 395 _getURLSearchParameters: function () { 396 var self = this; 397 var prmstr = window.location.search.substr(1); 398 return prmstr != null && prmstr != "" ? this._transformToAssocArray(prmstr) : {}; 399 }, 400 _transformToAssocArray: function (prmstr) { 401 var params = {}; 402 var prmarr = prmstr.split("&"); 403 for (var i = 0; i < prmarr.length; i++) { 404 var tmparr = prmarr[i].split("="); 405 var key = decodeURIComponent(tmparr[0]); 406 var val = decodeURIComponent(tmparr[1] || "").replace(/\+/g, " "); 407 params[key] = val; 408 } 409 return params; 410 }, 411 _setURLPieces: function () { 412 var self = this; 413 var url = window.location.pathname + '?'; 414 var params = ''; 415 var vars = self._getURLSearchParameters(); 416 if (self.settings.range !== 'today') { 417 vars.r = self.settings.range; 418 } 419 420 if (self.settings.filters.locations.length > 0) { 421 vars.l = self.settings.filters.locations 422 .map(function (loc) { 423 return loc.replace(/,/g, ''); 424 }) 425 .join(','); 426 } else { 427 delete vars['l']; 428 } 429 if (self.settings.filters.ages.length > 0) { 430 vars.a = self.settings.filters.ages.join(','); 431 } else { 432 delete vars['a']; 433 } 434 if (self.settings.filters.types.length > 0) { 435 vars.t = encodeURIComponent(JSON.stringify(self.settings.filters.types)); 436 } else { 437 delete vars['t']; 438 } 439 if (self.settings.filters.term && self.settings.filters.term.length > 0) { 440 vars.term = self.settings.filters.term; 441 } else { 442 delete vars['term']; 443 } 444 delete vars['start']; 445 delete vars['end']; 446 delete vars['r']; 447 if (self.settings.range !== 'today') { 448 vars['r'] = self.settings.range; 449 } 450 //if the range is not specified with a duration then remove the duration 451 if (false == (['days', 'weeks', 'months', 'range'].includes(self.settings.range))) { 452 delete vars['n']; 453 } 454 if (self.settings.range === 'range' && this.settings.view !== 'grid') { 455 vars['start'] = self.settings.start.format('YYYY-MM-DD'); 456 if (self.settings.end === '' || self.settings.end.format('YYYY-MM-DD') === self.settings.start.format('YYYY-MM-DD')) { 457 delete vars['end']; 458 } else { 459 vars['end'] = self.settings.end.format('YYYY-MM-DD'); 460 } 461 } 462 if (this.settings.view === 'grid' && self.settings.gridDate) { 463 vars['d'] = self.settings.gridDate; 464 } 465 if (self.settings.view === 'list') { 466 delete vars['v']; 467 } else { 468 vars['v'] = self.settings.view; 469 } 470 471 if (Object.keys(vars).length > 0) { 472 params = $.param(vars, true); 473 } 474 475 if (self.settings.emitEvents) { 476 var data = { 'data': (url + params) }; 477 var event = new $.Event('am-events-listings.url-update', data); 478 self.$element.trigger(event, data); 479 } else { 480 window.history.pushState({ 'r': 'type' }, '', url + params); 481 } 482 }, 483 _getParentOrigin: function () { 484 if (typeof this.settings.parentOrigin === 'string' && this.settings.parentOrigin.length > 0) { 485 return this.settings.parentOrigin; 486 } 487 if (document.referrer && document.referrer.length > 0) { 488 try { 489 return (new URL(document.referrer)).origin; 490 } catch (e) { 491 return ''; 492 } 493 } 494 return ''; 495 },
496 _updateQuickRangeLinks: function () { 497 var self = this; 498 var filters = self.settings.filters; 499 var filterParams = { 500 l: filters.locations.length > 0 ? filters.locations.map(function (loc) { return loc.replace(/,/g, ''); }).join(',') : '', 501 a: filters.ages.length > 0 ? filters.ages.join(',') : '', 502 t: filters.types.length > 0 ? encodeURIComponent(JSON.stringify(filters.types)) : '', 503 term: filters.term || '' 504 }; 505 var vars = {}; 506 $.each(filterParams, function (key, value) { 507 if (value) { 508 vars[key] = value; 509 } 510 }); 511 self.listViewLeft.find('.events-link>a[data-type]').each(function () { 512 var $link = $(this); 513 vars.r = $link.attr('data-type'); 514 $link.attr('href', self._quickRangeBase + '?' + $.param(vars, true)); 515 }); 516 }, 517 _postToParent: function (type, payload) { 518 if (!this.settings.embeddedMode || !window.parent || window.parent === window) { 519 return; 520 } 521 var origin = this._getParentOrigin(); 522 if (!origin) { 523 return; 524 } 525 window.parent.postMessage({ 526 source: 'classic-attend', 527 type: type, 528 payload: payload || {} 529 }, origin); 530 }, 531 _canPostToParent: function () { 532 if (!this.settings.embeddedMode || !window.parent || window.parent === window) { 533 return false; 534 } 535 if (this.settings.embedSource !== 'create-classic-attend') { 536 return false; 537 } 538 return !!this._getParentOrigin(); 539 }, 540 _getEmbeddedEventPath: function (eventId) { 541 var id = String(eventId || '').trim(); 542 if (!id) { 543 return ''; 544 } 545 return '/event/' + encodeURIComponent(id); 546 }, 547 _getEmbeddedEventHref: function (pathAndQuery) { 548 if (!pathAndQuery || !this._canPostToParent()) { 549 return ''; 550 } 551 var origin = this.settings.parentOrigin; 552 if (origin) { 553 return origin + pathAndQuery; 554 } 555 return pathAndQuery; 556 }, 557 _bindEmbeddedEventLink: function ($link, pathAndQuery) { 558 if (!this.settings.embeddedMode || !$link || !pathAndQuery) { 559 return; 560 } 561 var embeddedHref = this._getEmbeddedEventHref(pathAndQuery); 562 if (embeddedHref) { 563 $link.attr('href', embeddedHref); 564 } 565 $link.attr('data-embedded-event-path', pathAndQuery); 566 }, 567 _scheduleHeightPost: function (forcePost) { 568 var self = this; 569 if (!self.settings.embeddedMode) { 570 return; 571 } 572 if (self._embeddedHeightFrame) { 573 window.cancelAnimationFrame(self._embeddedHeightFrame); 574 } 575 self._embeddedHeightFrame = window.requestAnimationFrame(function () { 576 self._embeddedHeightFrame = null; 577 var scrollY = window.scrollY || window.pageYOffset || 0; 578 var rootElement = (self.element && self.element.nodeType === 1 ? self.element : self.$element && self.$element[0]) || null; 579 var holderHeight = rootElement ? Math.ceil($(rootElement).outerHeight() || 0) : 0; 580 var holderScrollHeight = rootElement ? Math.ceil(rootElement.scrollHeight || 0) : 0; 581 var contentHeight = Math.max( 582 holderHeight, 583 holderScrollHeight, 584 rootElement ? Math.ceil(rootElement.getBoundingClientRect().bottom + scrollY) : 0 585 ); 586 if (document.body && document.body.children) { 587 for (var idx = 0; idx < document.body.children.length; idx++) { 588 var child = document.body.children[idx]; 589 if (!child || /^(SCRIPT|STYLE|LINK|META|NOSCRIPT)$/i.test(child.tagName) || child.getClientRects().length === 0) { 590 continue; 591 } 592 // Fixed elements (e.g. the amPopupCover dimmer) size to the viewport, and in an 593 // auto-height iframe the viewport is whatever we last reported — counting them 594 // makes the reported height chase itself and the host page jumps. 595 if (window.getComputedStyle(child).position === 'fixed') { 596 continue; 597 } 598 var childBottom = Math.ceil(child.getBoundingClientRect().bottom + scrollY); 599 contentHeight = Math.max(contentHeight, childBottom); 600 } 601 } 602 contentHeight += 8; 603 if (!contentHeight || (!forcePost && contentHeight === self._lastEmbeddedHeight)) { 604 return; 605 } 606 self._lastEmbeddedHeight = contentHeight; 607 self._postToParent('height-update', { height: contentHeight }); 608 }); 609 }, 610 _updateDateRange: function () { 611 var self = this; 612 self.paused = true; 613 var now = moment(); 614 615 switch (self.settings.range) { 616 case 'today': 617 self.settings.start = now.startOf('day'); 618 self.settings.end = now.clone(); 619 $('div.events-calendar').datepicker('setDate', now.startOf('day').toDate()); 620 $('.events-details a[href="#calendar"]').tab('show'); 621 break; 622 case 'tomorrow': 623 self.settings.start = now.add(1, 'day').startOf('day'); 624 self.settings.end = now.clone(); 625 $('div.events-calendar').datepicker('setDate', self.settings.start.toDate()); 626 $('.events-details a[href="#calendar"]').tab('show'); 627 break; 628 case 'thisweek': 629 self.settings.start = now; 630 self.settings.end = self.settings.start.clone().endOf('week'); 631 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 632 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 633 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 634 break; 635 case 'thismonth': 636 self.settings.start = now; 637 self.settings.end = self.settings.start.clone().endOf('month'); 638 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 639 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 640 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 641 break; 642 case 'nextweek': 643 self.settings.start = now.add(1, 'week').startOf('week'); 644 self.settings.end = self.settings.start.clone().endOf('week'); 645 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 646 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 647 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 648 break; 649 case 'nextmonth': 650 self.settings.start = now.add(1, 'month').startOf('month'); 651 self.settings.end = self.settings.start.clone().endOf('month'); 652 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 653 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 654 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 655 break; 656 case 'days': 657 self.settings.start = now; 658 self.settings.end = now.clone().add(self.settings.duration, 'days'); 659 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 660 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 661 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 662 break; 663 case 'weeks': 664 self.settings.start = now; 665 self.settings.end = now.clone().add(self.settings.duration, 'weeks'); 666 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 667 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 668 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 669 break; 670 case 'months': 671 self.settings.start = now; 672 self.settings.end = now.clone().add(self.settings.duration, 'months'); 673 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 674 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 675 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 676 break; 677 } 678 self.paused = false;
679 self._update(); 680 }, 681 _bindEvents: function () { 682 var self = this; 683 self.gridView.data('date', moment(self.settings.gridDate).startOf('month')); 684 self.viewPicker.on('click keyup', '[data-view]', function (e) { 685 e.preventDefault(); 686 687 var isSpace = e.type === 'keyup' && (e.which == 32 || e.keyCode == 32 || e.key == " "); 688 var isEnter = e.type === 'keyup' && (e.which == 13 || e.keyCode == 13 || e.key == "Enter"); 689 690 if (e.type === 'click' || isSpace || isEnter) { 691 $('[data-view]').each(function (_, el) { 692 $(el).attr('aria-pressed', 'mixed'); 693 }) 694 695 self.setView($(this).attr('data-view')); 696 $(this).attr('aria-pressed', true); 697 } 698 }); 699 installCalendarAriaFix(self.element); 700 $('.events-range.input-daterange', self.listViewLeft).datepicker({ 701 todayBtn: "linked", 702 title: "Events calendar", 703 orientation: "bottom left", 704 format: 'MM d yyyy', 705 todayHighlight: true 706 }).on('changeDate', function (event) { 707 self.settings.range = 'range'; 708 self.settings.start = moment($('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('getDate')); 709 self.settings.end = moment($('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('getDate')); 710 self._update(); 711 }); 712 $('.events-date-input').on('click', '.input-group-addon', function (event) { 713 event.preventDefault(); 714 event.stopPropagation(); 715 $(this).closest('.events-date-input').find('input').datepicker('show'); 716 }); 717 718 $('div.events-calendar', self.listViewLeft).datepicker({ 719 title: "Events calendar", 720 startDate: new Date() 721 }).on('changeDate', function (event) { 722 event.preventDefault(); 723 self.paused = true; 724 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', moment(event.date).format('MMMM D YYYY')); 725 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', moment(event.date).format('MMMM D YYYY')); 726 self.settings.start = moment(event.date).startOf('day'); 727 self.settings.end = moment(event.date).endOf('day'); 728 if (!self.rangeUpdating) { 729 self.settings.range = 'range'; 730 } 731 self.paused = false; 732 self._update(); 733 }); 734 735 if (self.settings.start === self.settings.end) { 736 self.rangeUpdating = true; 737 $('div.events-calendar', self.listViewLeft).datepicker('setDate', new Date(self.settings.start.format('MMMM D YYYY'))); 738 self.rangeUpdating = false; 739 } 740 741 self.$element.on('click', '.events-option-dropdown', function (event) { 742 if (!$(event.target).hasClass('events-option-dropdown')) return; 743 event.preventDefault(); 744 var hide = $('.' + $(this).attr('data-show-filter')).is(':visible'); 745 $('.events-filter-section', self.$element).fadeOut(); 746 if (!hide) { 747 $('div.' + $(this).attr('data-show-filter'), self.$element).css({ 748 top: 30, 749 left: 0 750 }).position({ 751 my: "left top", 752 at: "left bottom", 753 of: this, // or $("#otherdiv) 754 collision: "fit", 755 within: self.$element, 756 using: function (pos, data) { 757 var menu = data.element.element; 758 pos.top = data.target.top + data.target.height + 30; 759 $(menu).css(pos) 760 } 761 }).fadeIn(); 762 } 763 }).on('click', '.events-filter-close', function (event) { 764 event.preventDefault(); 765 $(this).closest('.events-filter-section').fadeOut(); 766 }).on('change', '#loc_all', function (event) { 767 if ($(this).is(':checked')) { 768 self.$element.find('#event_locations [id^=loc_]').prop('checked', false); 769 } else { 770 $(this).prop('checked', true); 771 } 772 self._update(); 773 }).on('change', '#event_locations [id^=loc_]', function (event) { 774 if ($(this).is(':checked')) { 775 self.$element.find('#loc_all').prop('checked', false); 776 } else if (self.$element.find('#event_locations [id^=loc_]:checked').length === 0) { 777 self.$element.find('#loc_all').prop('checked', true); 778 } 779 self._update(); 780 }).on('change', '#group_all', function (event) { 781 if ($(this).is(':checked')) { 782 self.$element.find('#event_ages [id^=group_]').prop('checked', false); 783 } else { 784 $(this).prop('checked', true); 785 } 786 self._update(); 787 }).on('change', '#event_ages [id^=group_]', function (event) { 788 if ($(this).is(':checked')) { 789 self.$element.find('#group_all').prop('checked', false); 790 } else if (self.$element.find('#event_locations [id^=group_]:checked').length === 0) { 791 self.$element.find('#group_all').prop('checked', true); 792 } 793 self._update(); 794 }).on('change', '#type_all', function (event) { 795 if ($(this).is(':checked')) { 796 self.$element.find('#event_types [id^=type_]').prop('checked', false); 797 } else { 798 $(this).prop('checked', true); 799 } 800 self._update(); 801 }).on('change', '#event_types [id^=type_]', function (event) { 802 if ($(this).is(':checked')) { 803 self.$element.find('#type_all').prop('checked', false); 804 } else if (self.$element.find('#event_types [id^=type_]:checked').length === 0) { 805 self.$element.find('#type_all').prop('checked', true); 806 } 807 self._update(); 808 }).on('click', '.events-filter-clear', function (event) { 809 event.preventDefault(); 810 self.$element.find('.events-search-field').val(''); 811 self.$element.find('#loc_all').prop('checked', true); 812 self.$element.find('#group_all').prop('checked', true); 813 self.$element.find('#type_all').prop('checked', true); 814 self.$element.find('#event_ages [id^=group_]').prop('checked', false); 815 self.$element.find('#event_types [id^=type_]').prop('checked', false); 816 self.$element.find('#event_locations [id^=loc_]').prop('checked', false); 817 self._update(); 818 }).on('keyup', '.events-search-field', function (event) { 819 if (self.SearchTimer) { 820 clearTimeout(self.SearchTimer); 821 self.SearchTimer = false;
822 } 823 var term = $(this).val(); 824 self.SearchTimer = setTimeout(function () { 825 self._doSearch(term); 826 }, 750); 827 }); 828 $('.events-change-day', self.listViewRight).on('click keyup', function (event) { 829 event.preventDefault(); 830 831 var isSpace = event.type === 'keyup' && (event.which === 32 || event.keyCode === 32 || event.key === " "); 832 var isEnter = event.type === 'keyup' && (event.which === 13 || event.keyCode === 13 || event.key === "Enter"); 833 834 if (event.type === 'click' || isSpace || isEnter) { 835 self.settings.range = 'range'; 836 var newdate = moment($('div.events-calendar', self.listViewLeft).datepicker('getDate')).add($(this).attr('data-by'), 'day').startOf('day'); 837 if (newdate.isBefore(moment().startOf('day'))) return; 838 $('div.events-calendar', self.listViewLeft).datepicker('setDate', newdate.toDate()); 839 } 840 }); 841 self.listViewLeft.on('click', '.events-link>a', function (event) { 842 if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.which === 2) { 843 return; 844 } 845 event.preventDefault(); 846 self.paused = true; 847 self.settings.range = $(this).attr('data-type'); 848 self.rangeUpdating = true; 849 self._updateDateRange(); 850 self.rangeUpdating = false; 851 }); 852 self.gridView.on('click', '.events-grid-cell', function (event) { 853 event.preventDefault(); 854 var selected = $(this).hasClass('events-grid-cell-selected'); 855 self.gridView.find('.events-grid-day-list').remove(); 856 self.gridView.find('.events-grid-cell-selected').removeClass('events-grid-cell-selected'); 857 if (!selected) { 858 $(this).addClass('events-grid-cell-selected'); 859 var dayView = $('<div class="events-grid-day-list"></div>').insertAfter($(this).closest('.events-grid-row')); 860 $.each($(this).data('events'), function (index, val) { 861 var hasPre = false; 862 var isBilled = false; 863 var preText = ''; 864 var tagString = ''; 865 var ticketIcon = '<span class="fa-stack ticket-symbol" style="font-size:12px"><i class="fa fa-circle fa-stack-2x" style="color: #2bafbe"></i><i class="fa fa-usd fa-stack-1x fa-inverse"></i></span> '; 866 var title = val.title; 867 868 if (typeof (val.enable_billing) !== 'undefined') { 869 isBilled = parseInt(val.enable_billing) === 1; 870 } 871 872 if (self.settings.eventsGroupCalenderBAge) { 873 if (val.ages) { 874 $.each(val.agesArray, function (index, val) { 875 var dotColour = typeof self.ages[val] !== 'undefined' ? self.ages[val] : self._genColour(val); 876 tagString += ' <i class="fa fa-circle" style="color:' + dotColour + '"></i> ' + val; 877 }); 878 } 879 } else { 880 if (val.tags) { 881 $.each(val.tagsArray, function (index, val) { 882 var dotColour = typeof self.tags[val] !== 'undefined' ? self.tags[val] : self._genColour(val); 883 tagString += ' <i class="fa fa-circle" style="color:' + dotColour + '"></i> ' + val; 884 }); 885 } 886 } 887 888 if (parseInt(val.changed) === 1) { 889 title = '<span class="eelist-changed-message">Cancelled</span> ' + title; 890 } 891 892 if (parseInt(val.changed) === 2 || parseInt(val.changed) === 3) { 893 title = '<span class="eelist-changed-message">Rescheduled</span> ' + title; 894 } 895 896 if (isBilled) { 897 title = ticketIcon + title; 898 } 899 900 if (hasPre) { 901 title = preText + title; 902 } 903 904 905 if (val.link) { 906 var link = $('<a target="' + self.settings.linkTarget + '" href="' + val.link + '"> ' + $('<div></div>').html(title).text() + '</a>'); 907 } else { 908 var id = val.new_event_id || val.id; 909 var embeddedEventPath = self._getEmbeddedEventPath(id); 910 var link = $('<a target="' + self.settings.linkTarget + '">' + title + '</a>'); 911 if (window.websiteUrl) { 912 link.attr('href', window.websiteUrl + '/event/' + id); 913 } else { 914 link.attr('href', '/event/' + id); 915 } 916 self._bindEmbeddedEventLink(link, embeddedEventPath); 917 } 918 if (val.sub_title) { 919 link.append('<span> - ' + val.sub_title + '</span>'); 920 } 921 922 923 link.qtip({ 924 content: { 925 text: function (event, api) { 926 return self._getEventBlock(val, true); 927 } 928 }, 929 style: { 930 classes: 'qtip-bootstrap events-popup', 931 def: false, 932 width: 500 933 }, 934 hide: { 935 fixed: true, 936 delay: 300 937 }, 938 position: { 939 viewport: $(window) 940 } 941 }); 942 if (parseInt(val.changed) === 1) { 943 $('<div> , ' + val.location + ' <span class="events-grid-day-list-tags">' + tagString + '</span></div>').prepend(link).appendTo(dayView); 944 } else if (parseInt(val.changed) === 2 || parseInt(val.changed) === 3) { 945 $('<div> <b>' + val.time_string + '</b>, ' + val.location + ' <span class="events-grid-day-list-tags">' + tagString + '</span></div>').prepend(link).appendTo(dayView); 946 } else { 947 $('<div> <b>' + val.time_string + '</b>, ' + val.location + ' <span class="events-grid-day-list-tags">' + tagString + '</span></div>').prepend(link).appendTo(dayView); 948 } 949 950 }); 951 } 952 }).on('click keyup', '.events-change-day', function (e) { 953 e.preventDefault(); 954 955 var isSpace = event.type === 'keyup' && (e.which == 32 || e.keyCode == 32 || e.key == " "); 956 var isEnter = event.type === 'keyup' && (e.which == 13 || e.keyCode == 13 || e.key == "Enter"); 957 958 if (e.type === 'click' || isSpace || isEnter) { 959 self.settings.range = 'range'; 960 self.gridView.data('date').add($(this).attr('data-by'), 'month'); 961 self.settings.gridDate = self.gridView.data('date').format('YYYY-MM-DD'); 962 self._update(); 963 } 964 }); 965 966 self.todayButton.on('click', function (event) { 967 event.preventDefault(); 968 self.settings.range = 'today'; 969 if (self.settings.view == 'list') { 970 self.rangeUpdating = true; 971 $('div.events-calendar', self.listViewLeft).datepicker('setDate', moment().startOf('day').toDate()); 972 self.rangeUpdating = false;
973 } else { 974 self.gridView.data('date', moment().startOf('month')); 975 976 } 977 self._update(); 978 }); 979 $(window).on('resize', function () { 980 var w = $(document).width(); 981 if (w < 768 && self.settings.view == 'grid') { 982 self.setView('list'); 983 } else { 984 985 } 986 self._scheduleHeightPost(); 987 }); 988 989 // Brochure button logic: 990 991 }, 992 _doSearch: function (term) { 993 this.paused = true; 994 var now = moment(); 995 if (this.settings.filters.days === 0) { 996 var startDate = now.format('MMMM D YYYY'); 997 var endDate = now.endOf('month').format('MMMM D YYYY'); 998 $('.events-range.input-daterange input[name=start]', this.listViewLeft).datepicker('update', startDate); 999 $('.events-range.input-daterange input[name=end]', this.listViewLeft).datepicker('update', endDate); 1000 } 1001 $('.events-details a[href="#date_range"]', this.listViewLeft).tab('show'); 1002 this.paused = false; 1003 this._update(); 1004 }, 1005 1006 // #4381 - CK 1007 // Hide external venue description on qtip 1008 _getEventBlock: function (event, inQtip) { 1009 var self = this; 1010 var $item = $('<div class="eelistevent-data"></div>'); 1011 if (parseInt(event.changed) === 3) { 1012 $item.addClass('eelistevent-postponed'); 1013 } 1014 if (parseInt(event.changed) === 2 || parseInt(event.changed) === 3) { 1015 $('<div class="eelist-changed-message"></div>').text('Rescheduled').prependTo($item); 1016 } else if (parseInt(event.changed) === 1) { 1017 $item.addClass('eelistevent-canceled'); 1018 $('<div class="eelist-changed-message"></div>').text('Cancelled').prependTo($item); 1019 } 1020 var title = event.title; 1021 var evtLink = ''; 1022 var imageLink = '' 1023 1024 if (event.sub_title) title += '<span>' + ' - ' + event.sub_title + '</span>'; 1025 if (event.link) { 1026 evtLink = $('<a target="' + self.settings.linkTarget + '" href="' + event.link + '"></a>'); 1027 } else { 1028 var id = event.new_event_id || event.id; 1029 evtLink = $('<a target="' + self.settings.linkTarget + '" href="' + (window.websiteUrl || "") + '/event/' + id + '"></a>'); 1030 self._bindEmbeddedEventLink(evtLink, self._getEmbeddedEventPath(id)); 1031 } 1032 1033 imageLink = evtLink.clone(); 1034 evtLink.html(title); 1035 $('<div class="eelisttitle"></div>').append(evtLink).appendTo($item); 1036 1037 // CH 14854 - Add in event images. 1038 // 1039 if (self.settings.showImagesInListGrid) { 1040 if (typeof event.image === 'string' && event.image.length > 0) { 1041 var url = 'https://' + self.settings.client + '.libnet.info/images/events/' + self.settings.client + '/' + event.image; 1042 //var image = '<img src="' + url + '" class="img-thumbnail event-list-image" alt="' + event.title + '"/>'; 1043 var imageFrame = $('<div/>'); 1044 var image = $('<span/>') 1045 .attr('role', 'img') 1046 .attr('aria-label', event.title) 1047 .css({ 1048 'display': 'inline-block', 1049 'width': '118px', 1050 'height': '118px', 1051 'background-image': 'url(\'' + url + '\')', 1052 'background-position': 'center center', 1053 'background-size': 'cover' 1054 }); 1055 1056 if (typeof event.image_alt_text === 'string' && event.image_alt_text.length > 0) { 1057 image.attr('aria-label', event.image_alt_text); 1058 } 1059 1060 imageFrame.append(image); 1061 imageLink.append(imageFrame); 1062 1063 $('<div class="eelistimage"></div>').append(imageLink).appendTo($item); 1064 } 1065 } 1066 1067 if (parseInt(event.changed) === 2) { 1068 $item.append('<div class="eelisttime eelisttime-postponed headingtext">(' + 1069 '<span>Rescheduled from </span>' + 1070 event.datestring + ': ' + event.time_string + 1071 ')</div>'); 1072 1073 var tt = $('<div class="eelisttime headingtext"></div>').append("<span class='eelist-changed-message'> New date </span>").appendTo($item); 1074 tt.append(document.createTextNode(event.changed_datestring + ': ' + event.changed_time_string)); 1075 } else if (parseInt(event.changed) === 3) { 1076 $item.append('<div class="eelisttime headingtext">' + event.datestring + ': ' + event.time_string + '</div>'); 1077 var tt = $('<div class="eelisttime headingtext"></div>').append("<span class='eelist-changed-message'> New date </span>").appendTo($item); 1078 tt.append(document.createTextNode(event.changed_datestring + ': ' + event.changed_time_string)); 1079 } else { 1080 $item.append('<div class="eelisttime headingtext">' + event.datestring + ': ' + event.time_string + '</div>'); 1081 } 1082 1083 var lstring = event.library; 1084 if (event.venues) {
1085 lstring += ' - <i>' + event.venues + '</i>'; 1086 } 1087 if (parseInt(event.changed_venue) == 1) { 1088 $item.append('<div class="eelocation"><i class="am-locations"/><span class="eelist-changed-message"> New venue </span> ' + lstring + '</div>'); 1089 } else { 1090 $item.append('<div class="eelocation"><i class="am-locations"/> ' + lstring + '</div>'); 1091 } 1092 1093 if (event.agesArray) { 1094 if (self.settings.eventsGroupCalenderBAge) { 1095 var tagsList = $('<div class="eelisttags"></div>').append('<span>Age group: </span>').appendTo($item); 1096 $.each(event.agesArray, function (index, val) { 1097 var dotColour = typeof self.ages[val] !== 'undefined' ? self.ages[val] : self._genColour(val); 1098 tagsList.append('<span><i class="fa fa-circle" style="color:' + dotColour + '"></i> ' + val + ' </span>'); 1099 }); 1100 } else { 1101 $('<div class="eelistgroup"></div>').append('<span>Age group: </span>').append(event.agesArray.join(", ")).appendTo($item); 1102 } 1103 } 1104 1105 if (event.tagsArray) { 1106 if (self.settings.eventsGroupCalenderBAge) { 1107 $('<div class="eelistgroup"></div>').append('<span>' + escapeHtml(self.settings.customEventLabel) + ' type: </span>').append(event.tagsArray.join(", ")).appendTo($item); 1108 } else { 1109 var tagsList = $('<div class="eelisttags"></div>').append('<span>' + escapeHtml(self.settings.customEventLabel) + ' type: </span>').appendTo($item); 1110 $.each(event.tagsArray, function (index, val) { 1111 var dotColour = typeof self.tags !== 'undefined' && typeof self.tags[val] !== 'undefined' ? self.tags[val] : self._genColour(val); 1112 tagsList.append('<span><i class="fa fa-circle" style="color:' + dotColour + '"></i> ' + val + ' </span>'); 1113 }); 1114 } 1115 } 1116 1117 $item.append('<div class="eelistdesc">' + event.description + '</div>'); 1118 // #4381 - CK 1119 // Hide external venue description on qtip 1120 if (event.venue_type && event.venue_type == 'external' && event.venue_description.length > 0 && !inQtip) { 1121 $item.append('<div class="eelistvenuedesc"><b>Venue details</b><br>' + event.venue_description + '</div>'); 1122 } 1123 1124 if ((parseInt(event.changed, 10) !== 1 && parseInt(event.changed, 10) !== 3) && parseInt(event.allow_reg, 10) === 1) { 1125 if (moment.tz(event.close_registration, self.settings.timezone).diff() < 0) { 1126 if (parseInt(event.third_party_reg, 10) == 0) { 1127 $item.append('<div class="regclosed">Registration is now closed</div>'); 1128 } 1129 } else { 1130 // If third-party-reg is off then run the numbers, otherwise jump to next if set. 1131 // CH #11417 - Added maximums for waitlists. 1132 if (event.ticketInfo) { 1133 var available = 0; 1134 if (event.ticketInfo.ticketData) { 1135 for (var t = 0; t < event.ticketInfo.ticketData.length; t++) { 1136 var tkt = event.ticketInfo.ticketData[t]; 1137 available += tkt.available; 1138 } 1139 } 1140 1141 if (event.ticketInfo.typeId === -1) { 1142 available = event.ticketInfo.available; 1143 } 1144 1145 if (available <= 0) { 1146 if (self.settings.allowWaitlistSubscription) { 1147 $item.append('<div class="regclosed">This ' + escapeHtml(self.settings.customEventLabel) + ' is full. Click the button below to be notified when a registration becomes available.</div>'); 1148 $('<button data-eventid="' + event.id + '" data-recurringid="' + event.recurring_id + '" data-regtype="-1" class="button subscribeToEvent"></button>') 1149 .text(self.settings.customInterestedText) 1150 .on('click', function () { 1151 self._showInterestedPopup($(this).attr('data-eventid'), $(this).attr('data-recurringid'), event); 1152 }) 1153 .appendTo($item) 1154 } else { 1155 $item.append('<div class="regclosed">This ' + escapeHtml(self.settings.customEventLabel) + ' is full</div>'); 1156 } 1157 1158 //$btn.text('Event Full').prop('disabled', true); 1159 return $item; 1160 } 1161 } 1162 1163 var allowWaitList = parseInt(event.allow_waitlist, 10) !== 0 && ((event.max_waitlist == 0 || (parseInt(event.max_waitlist) > 0) && (parseInt(event.total_waitlist) < parseInt(event.max_waitlist)))); 1164 var regAllowed = parseInt(event.total_registrants, 10) < parseInt(event.max_attendee, 10) || allowWaitList; 1165 1166 if (parseInt(event.third_party_reg, 10) === 0) { 1167 if (!regAllowed) { 1168 $item.append('<div class="regclosed">This ' + escapeHtml(self.settings.customEventLabel) + ' is full</div>'); 1169 return $item; 1170 } 1171 } 1172 1173 if (event.version == 2 && parseInt(event.third_party_reg, 10) === 1) { 1174 if (event.reg_url.length > 0) { 1175 $('<a target="' + self.settings.linkTarget + '" href="' + event.reg_url + '" class="button eventRegButton">Register</a>').appendTo($item); 1176 } 1177 } else if (parseInt(event.staff_only_registration, 10) === 1) { 1178 $('<div class="regclosed eventStaffRegMessage">Please contact the library to register for this event</div>').appendTo($item); 1179 } else {
1180 var event_id = event.id; 1181 var location_id = event.location_id; 1182 var $btn, $onlineBtn; 1183 1184 if (parseInt(event.total_registrants, 10) >= parseInt(event.max_attendee, 10)) { 1185 var m = 'Join the wait list'; 1186 var regstatus = '0'; 1187 var t = '2'; 1188 } else { 1189 var m = 'Register'; 1190 var regstatus = '1'; 1191 var t = '1'; 1192 } 1193 1194 if (parseInt(event.whole_serires_only, 10) === 1 && moment(event.series_starts).subtract(event.registration_close, 'minutes').tz(self.settings.timezone).diff() < 0) { 1195 if (parseInt(event.third_party_reg, 10) == 0) { 1196 $item.append('<div class="regclosed">Registration is now closed</div>'); 1197 } 1198 } else if (parseInt(event.whole_serires_only, 10) === 0 || (parseInt(event.whole_serires_only, 10) === 1)) { 1199 $btn = null, $onlineBtn = null; 1200 if (event.event_type !== undefined && event.event_type !== '') { 1201 if (event.event_type == 'INPERSON' && event.webinar_seats && event.venue_type == 'external') { 1202 event.event_type = 'HYBRID'; 1203 event.max_attendee_virtual = event.webinar_seats; 1204 } 1205 1206 switch (event.event_type) { 1207 case 'INPERSON': 1208 var ariaLabel = m + " for " + event.title + " in person" + " on " + event.datestring + " at " + event.start_time; 1209 $btn = $('<button aria-label="' + ariaLabel + '" data-eventid="' + event.id + '" data-recurringid="' + event.recurring_id + '" data-regtype="' + t + '" data-attendancetype="INPERSON" data-testmode="' + self.settings.testMode + '" class="button eventRegButton"></button>').text(m).appendTo($item).regButton(); 1210 break; 1211 case 'ONLINE': 1212 var ariaLabel = m + " for " + event.title + " on line" + " on " + event.datestring + " at " + event.start_time; 1213 $btn = $('<button aria-label="' + ariaLabel + '" data-eventid="' + event.id + '" data-recurringid="' + event.recurring_id + '" data-regtype="' + t + '" data-attendancetype="ONLINE" data-testmode="' + self.settings.testMode + '" class="button eventRegButton"></button>').text(m + ' to attend online').appendTo($item).regButton(); 1214 break; 1215 case 'HYBRID': 1216 if (parseInt(event.allow_waitlist, 10) == 1 && parseInt(event.total_inperson_registrants, 10) >= parseInt(event.max_attendee_in_branch, 10)) { 1217 var m_in_branch = 'Join the wait list'; 1218 var t_in_branch = '2'; 1219 } else if (parseInt(event.max_attendee_in_branch, 10) > 0) { 1220 var m_in_branch = 'Register'; 1221 var t_in_branch = '1'; 1222 } 1223 1224 if (parseInt(event.allow_waitlist, 10) == 1 && parseInt(event.total_online_registrants, 10) >= parseInt(event.max_attendee_virtual, 10)) { 1225 var m_online = 'Join the wait list'; 1226 var t_online = '2'; 1227 } else if (parseInt(event.max_attendee_virtual, 10) > 0) { 1228 var m_online = 'Register'; 1229 var t_online = '1'; 1230 } 1231 1232 if (parseInt(event.allow_waitlist, 10) == 1 || parseInt(event.total_inperson_registrants, 10) < parseInt(event.max_attendee_in_branch, 10)) { 1233 var ariaLabel = m_in_branch + " for " + event.title + " to attend in person" + " on " + event.datestring + " at " + event.start_time; 1234 if (parseInt(event.max_attendee_in_branch, 10) > 0) { 1235 $btn = $('<button aria-label="' + ariaLabel + '" data-eventid="' + event.id + '" data-recurringid="' + event.recurring_id + '" data-regtype="' + t_in_branch + '" data-attendancetype="INPERSON" data-testmode="' + self.settings.testMode + '" class="button eventRegButton"></button>').text(m_in_branch + ' to attend in person').appendTo($item).regButton(); 1236 } 1237 } 1238 1239 if (parseInt(event.allow_waitlist, 10) == 1 || parseInt(event.total_online_registrants, 10) < parseInt(event.max_attendee_virtual, 10)) { 1240 var ariaLabelOnline = m_online + " for " + event.title + " to attend online" + " on " + event.datestring + " at " + event.start_time; 1241 if (parseInt(event.max_attendee_virtual, 10) > 0) { 1242 $onlineBtn = $('<button aria-label="' + ariaLabelOnline + '" data-eventid="' + event.i
1242d + '" data-recurringid="' + event.recurring_id + '" data-regtype="' + t_online + '" data-attendancetype="ONLINE" data-testmode="' + self.settings.testMode + '" class="button eventRegButton"></button>').text(m_online + ' to attend online').appendTo($item).regButton(); 1243 } 1244 } 1245 1246 break; 1247 } 1248 } else { 1249 var ariaLabelOther = m + " for " + event.title + " on " + event.datestring + " at " + event.start_time; 1250 $btn = $('<button aria-label="' + ariaLabelOther + '" data-eventid="' + event.id + '" data-recurringid="' + event.recurring_id + '" data-regtype="' + t + '" data-attendancetype="UNKNOWN" data-testmode="' + self.settings.testMode + '" class="button eventRegButton"></button>').text(m).appendTo($item).regButton(); 1251 } 1252 1253 // Time juggling for the reg button CH10228. 1254 // Due to some oddities in the way moment works and calculates differences 1255 // No TZ conversion here since time is saved as a TZ time to the database. It also screws with comparisons. 1256 // E.g. IF we have 2019-02-01 12:00:00 stored in the database as a CST time, converting to a moment with tz included will produce something like this: 1257 // E.g(2). 2019-02-01T11:00:00-6:00 as tz calculation takes into account a tz-less time. Confusing. I know. 1258 var regOpens = moment(event.reg_opens).format('YYYY-MM-DD HH:mm:ss'); 1259 // Add the timezone here to account for local computer time 1260 // This is because if someone has EST set on their local computer, we want it to compare on that time so that someone can't abuse the system and just change the clock to get around it. 1261 var nowTime = moment().tz(self.settings.timezone).format('YYYY-MM-DD HH:mm:ss'); 1262 // Formatted times can now be compared, because the TZ string has been stripped. So basically we are comparing two different times. 1263 // E.g. 2019-02-01 1:30:00 (now) >= 2019-02-01 12:00:00 (opens) would be true. 1264 var regOpened = nowTime >= regOpens; 1265 1266 if (parseInt(event.open_registration_imidiatly, 10) === 0 && !regOpened) { 1267 if ($btn) { 1268 $btn.prop('disabled', true); 1269 } 1270 1271 if ($onlineBtn) { 1272 $onlineBtn.prop('disabled', true); 1273 } 1274 1275 $('<div class="events-reg-open-message"></div>').text("Registration opens on " + moment(event.reg_opens).format('dddd') + ", " + moment(event.reg_opens).format('MMMM D YYYY') + ' at ' + moment(event.reg_opens).format('h:mma')).appendTo($item); 1276 } 1277 } 1278 1279 1280 } 1281 } 1282 1283 if (typeof event.enable_billing !== 'undefined' && parseInt(event.enable_billing) === 1) { 1284 // Then there is class/ticketdata info 1285 $('.ticket-group', $item).remove(); 1286 var coEventBillingInfo = new EventBillingInfo(event.recurring_id, 1, event.ticketInfo); 1287 var infoBox = $('<div class="eelistgroup ticket-group"></div>'); 1288 infoBox.append(coEventBillingInfo.info).appendTo($item); 1289 } 1290 } 1291 return $item; 1292 }, 1293 _getFeed: function (type) { 1294 var self = this; 1295 var feedData = { 1296 feedType: type, 1297 filters: { 1298 location: [], 1299 ages: [], 1300 types: [], 1301 tags: [], 1302 term: '', 1303 days: 1 1304 } 1305 }; 1306 1307 if (self.settings.filters) { 1308 var filters = self.settings.filters; 1309 feedData.filters.ages = filters.ages.length > 0 ? filters.ages : ['all']; 1310 feedData.filters.types = filters.types.length > 0 ? filters.types : ['all']; 1311 feedData.filters.location = self.settings.locations.length > 0 ? self.settings.locations : ['all']; 1312 } 1313 if($('.events-search-field', self.element).val() && $('.events-search-field', self.element).val().length > 0) { 1314 feedData.filters.term = $('.events-search-field', self.element).val(); 1315 } else if (self.settings.term && self.settings.term.length > 0) { 1316 feedData.filters.term = self.settings.term; 1317 } 1318 1319 var urlFilters = JSON.stringify(feedData); 1320 var url = window.location.protocol + "//" + window.location.hostname + '/feeds?data=' + btoa(urlFilters); 1321 this._showFeedPopup(url, feedData); 1322 //window.open('/feeds?data='+ urlFilters , '_blank'); 1323 }, 1324 _showFeedPopup: function (url, filterData) { 1325 var self = this; 1326 var term = filterData.filters.term; 1327 var filterString = 'Showing '; 1328 1329 if (term && term.length > 2) { 1330 filterString += 'search results for <b>' + term + '</b> for '; 1331 } 1332 1333 if (filterData.filters.types.length > 0) { 1334 filterString += filterData.filters.types.join(', ') + ' events'; 1335 } else { 1336 filterString += 'all ' + self.settings.customEventLabel + 'types'; 1337 } 1338 filterString += ' at '; 1339 if (self.settings.filters.locations.length > 0) { 1340 if (self.settings.filters.locations.length > 1) { 1341 filterString += 'these locations ' + self.settings.filters.locations.join(', '); 1342 } else { 1343 if (self.settings.filters.locations[0] !== 'all') { 1344 filterString += self.settings.filters.locations[0]; 1345 } else { 1346 filterString += 'all locations'; 1347 } 1348 } 1349 } else { 1350 filterString += 'all locations'; 1351 } 1352 1353 filterString += ' for '; 1354 if (filterData.filters.ages.length > 0) { 1355 if (filterData.filters.ages.length > 1) { 1356 filterString += 'the age groups ' + filterData.filters.ages.join(', '); 1357 } else { 1358 filterString += 'the age group ' + filterData.filters.ages[0]; 1359 } 1360 } else { 1361 filterString += 'all ages'; 1362 } 1363 1364 1365 if (filterData) { 1366 var icon = "fa fa-rss"; 1367 var style = "color:#f26522"; 1368 var title = "RSS"; 1369 1370 if (filterData.feedType === 'ical') { 1371 icon = "fa fa-calendar"; 1372 style = "color:#3981c6"; 1373 title = "iCal"; 1374 } 1375 1376 var html = '<div id="brochure-popup">' + 1377 ' <div class="row">' + 1378 ' <div class="col-md-12">' + 1379 ' <div style="float:right;"><a class="close-brochure-popup" style="cursor: pointer;">close</a></div>' + 1380 ' <h3 class="patron-popup heading-text"><i class="' + icon + '" style="' + style + '"></i> ' + title + ' Events Feed</h3>' + 1381 ' </div>' + 1382 ' </div>' + 1383 ' <div class="patron-popup top-row row">' + 1384 ' <div class="col-md-12">' + 1385 ' <strong>Feed will contain up to 500 events with filters selected, excluding dates.</strong>' + 1386 ' </div>' + 1387 ' <div class="col-md-12">' + 1388 ' Filtered By: ' + filterString + 1389 ' </div>' + 1390 ' </div>' + 1391 ' <div class="patron-popup row" style="margin-left:15px;margin-right:15px;padding-top:35px;padding-bottom:20px;">' + 1392 ' <div class="col-md-12">' + 1393 ' <input type="text" id="feed-link" class="form-control" aria-label="Feed URL" value="' + url + '"/>' + 1394 ' </div>' + 1395 ' </div>' + 1396 ' <div class="patron-popup button-row" style="margin-left:15px;">' + 1397 ' <div class="col-md-3 col-md-offset-6" style="padding-top: 10px;">' + 1398 ' <button class="copy-button brochure-button btn-block">Copy Link to Clipboard</button>' + 1399 ' </div>' + 1400 ' <div class="col-md-3" style="padding-top: 10px;">' + 1401 ' <button class="view-button brochure-button btn-block">Download File</button>' + 1402 ' </div>' + 1403 ' </div>' + 1404 1405 '</div>'; 1406 1407 var popup = $('<div class="events2-brochure"></div>
1407').amPopup({ 1408 title: '', 1409 popUpClass: '', 1410 showTitle: false 1411 }); 1412 popup.append(html); 1413 popup.on('click', '.close-brochure-popup', function () { 1414 popup.data('plugin_amPopup').close(); 1415 }) 1416 .on('click', '.copy-button', function () { 1417 var el = document.getElementById("feed-link"); 1418 el.select(); 1419 document.execCommand('copy'); 1420 }).on('click', '.view-button', function () { 1421 window.open(url, '_blank'); 1422 }); 1423 popup.data('plugin_amPopup').open(); 1424 } 1425 }, 1426 _showBrochurePopup: function () { 1427 var filters = {}; 1428 var options = {}; 1429 var self = this; 1430 1431 if (self.settings.filters) { 1432 filters = self.settings.filters; 1433 } 1434 1435 if (self.settings.filterOptions) { 1436 options = self.settings.filterOptions; 1437 } 1438 1439 var subData = { 1440 filters: filters, 1441 options: options, 1442 allowSubs: self.settings.allowSubs, 1443 customEventsLabel: self.settings.customEventsLabel, 1444 customEventLabel: self.settings.customEventLabel 1445 }; 1446 1447 var ps = new patronSubscriptions(subData); 1448 ps.showPopup(); 1449 }, 1450 // CH14299 1451 _showInterestedPopup: function (dateId, recurringId, eventInfo) { 1452 var self = this; 1453 var eventInfo = { 1454 title: eventInfo.title + ' - ' + eventInfo.sub_title, 1455 datestring: eventInfo.datestring + ' - ' + eventInfo.time_string, 1456 location: eventInfo.location 1457 }; 1458 1459 var interested = new EventBillingSubscriptions(dateId, recurringId, eventInfo, true); 1460 var interestedForm = interested.subscriptionForm; 1461 interestedForm.appendTo('body'); 1462 1463 $('.Event_Full-dialog').modal({ 1464 backdrop: 'static', 1465 keyboard: false 1466 }).modal('show'); 1467 1468 }, 1469 _update: function () { 1470 var self = this; 1471 if (self.paused) return; 1472 if (!self.initComplete) return; 1473 var options = {}; 1474 var filter = {}; 1475 options.private = self.settings.private; 1476 1477 var term = $('.events-search-field', self.element).val(); 1478 if (term && term.length > 2) { 1479 options.search = term; 1480 } 1481 1482 if (self.settings.view == 'list') { 1483 var end = moment($('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('getDate')); 1484 var start = moment($('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('getDate')); 1485 var days = end.diff(start, 'days'); 1486 1487 if (self.settings.filters.date === start.format('YYYY-MM-DD')) { 1488 options.date = self.settings.filters.date; 1489 } else { 1490 options.date = start.format('YYYY-MM-DD'); 1491 } 1492 1493 if (self.settings.filters.days === days) { 1494 options.days = self.settings.filters.days; 1495 } else { 1496 options.days = end.diff(start, 'days'); 1497 } 1498 1499 } else { 1500 var date = self.gridView.data('date').clone(); 1501 // options.date=date.isoWeekday(1).format('YYYY-MM-DD'); 1502 options.date = date.startOf('week').format('YYYY-MM-DD'); 1503 options.days = 42; 1504 } 1505 1506 //if (options.days === 0) options.days = 1; 1507 1508 $(".events-brochure, .brochure-grid, .events-rss, .events-ical").remove(); 1509 var navigation = $('.events-filter-row').first(); 1510 var brochureButton = self.settings.showBrochure ? '<div class="events-brochure"><button class="events-option-dropdown events-brochure-button"><i class="fa fa-file-pdf-o" style="color: #ED0202;"></i> Create Brochure</button></div>' : ''; 1511 var rssButton = self.settings.showRSS ? '<div class="events-rss"><button class="events-option-dropdown events-rss-button"><i class="fa fa-rss" style="color: #f26522;"></i> RSS</button></div>' : ''; 1512 var icalButton = self.settings.showICAL ? '<div class="events-ical"><button class="events-option-dropdown events-ical-button"><i class="fa fa-calendar" style="color: #3981c6;"></i> Add to Calendar</button></div>' : ''; 1513 var left = $('.events-left'); 1514 1515 if (self.settings.view === "grid") { 1516 navigation.append($('<div class="col-md-12 brochure-grid" style="margin-top:10px;">' + brochureButton + '</div>')); 1517 } else { 1518 left.append(brochureButton); 1519 left.append(rssButton); 1520 left.append(icalButton); 1521 } 1522 1523 $('.events-brochure-button').on('click', function () { 1524 //self._getBrochure(); 1525 if (self.settings.brochureNoPopup) { 1526 window.location.href = "/brochure"; 1527 } else { 1528 self._showBrochurePopup(); 1529 } 1530 }); 1531 1532 $('.events-rss-button').on('click', function () { 1533 //self._getBrochure(); 1534 self._getFeed('rss'); 1535 }); 1536 1537 $('.events-ical-button').on('click', function () { 1538 //self._getBrochure(); 1539 self._getFeed('ical'); 1540 }); 1541 1542 $('.events-day-title', self.listViewRight).toggle(options.days == 0); 1543 $('.events-range-title', self.listViewRight).toggle(options.days >= 1); 1544 1545 if (!$('#loc_all', self.listViewLeft).is(':checked')) { 1546 options.locations = []; 1547 filter.locations = []; 1548 $('[id^=loc_]', self.locationList).each(function () { 1549 if ($(this).is(':checked')) { 1550 options.locations.push($(this).attr('id').substr(4)); 1551 filter.locations.push($.trim($(this).parent().text())); 1552 } 1553 }); 1554 } 1555 if (!$('#group_all', self.listViewLeft).is(':checked')) { 1556 options.ages = []; 1557 filter.ages = []; 1558 $('[id^=group_]', self.ageList).each(function () { 1559 if ($(this).is(':checked')) { 1560 options.ages.push(encodeURIComponent($(this).attr('value'))); 1561 filter.ages.push($.trim($(this).parent().text())); 1562 } 1563 }); 1564 } 1565 if (!$('#type_all', self.listViewLeft).is(':checked')) { 1566 options.types = []; 1567 filter.types = []; 1568 $('[id^=type_]', self.typeList).each(function () { 1569 if ($(this).is(':checked')) { 1570 options.types.push(encodeURIComponent($(this).attr('value'))); 1571 filter.types.push($.trim($(this).parent().text())); 1572 } 1573 }); 1574 } 1575 if ((term && term.length > 2) || filter.locations.length > 0 || filter.ages.length > 0 || filter.types.length > 0) { 1576 var filterString = 'Showing '; 1577 if (term && term.length > 2) { 1578 filterString += 'search results for <b>' + term + '</b> for '; 1579 } 1580 if (filter.types.length > 0) { 1581 filterString += filter.types.join(', ') + ' events'; 1582 } else { 1583 filterString += 'all ' + self.settings.customEventLabel + ' types'; 1584 } 1585 filterString += ' at '; 1586 if (filter.locations.length > 0) { 1587 filterString += filter.locations.join(', '); 1588 } else { 1589 filterString += 'all locations'; 1590 } 1591 filterString += ' for '; 1592 if (filter.ages.length > 0) { 1593 if (filter.ages.length > 1) { 1594 filterString += 'the age groups ' + filter.ages.join(', '); 1595 } else { 1596 filterString += 'the age group ' + filter.ages[0]; 1597 } 1598 } else { 1599 filterString += 'all ages'; 1600 } 1601 $('.events-filter-message', self.views).html(filterString); 1602 $('.events-filter-details', self.views).fadeIn(); 1603 } else { 1604 $('.events-filter-details', self.views).hide(); 1605 } 1606 $('.events-date-range-string', self.listViewRight).text(''); 1607 1608 var $list = $('.events-body', self.listViewRight).empty().text('Loading events...'); 1609 1610 var $grid = $('.events-grid-body', self.gridView).empty().text('Loading events...'); 1611 1612 // Fix for bad dates. 1613 options.days++; 1614 1615 // Request for brochure on front-end, need to save off the filters - which are all the options used to get event data 1616 var filterOptions = { 1617 ages: filter.ages, 1618 locations: filter.locations, 1619 types: filter.types, 1620 days: options.days, 1621 date: options.date, 1622 private: options.private, 1623 term: options.search 1624 }; 1625 1626 self.settings.locations = options.locations; 1627 self.settings.filters = filterOptions; 1628 if (typeof (filterString) !== "undefined") { 1629 self.settings.filters.display = filterString.substr(7); 1630 } else { 1631 self.settings.filters.display = "All events for date range, no filters."; 1632 } 1633 1634 if (typeof (options.display) !== "undefined") { 1635 delete options.display; 1636 } 1637 1638 self.settings.filterOptions = options; 1639 self._setURLPieces();
1640 self._updateQuickRangeLinks(); 1641 1642 var website = (window.websiteUrl || ""); 1643 $.getJSON(website + '/eeventcaldata?event_type=' + self.settings.type + '&req=' + encodeURIComponent(JSON.stringify(options)), function (data) { 1644 if (self.settings.view == 'list') { 1645 $('.events-date-string', self.listViewRight).text(start.format('MMMM D YYYY')); 1646 $('.events-date-range-string', self.listViewRight).text(start.format('MMMM D YYYY') + ' - ' + end.format('MMMM D YYYY')); 1647 $list.empty(); 1648 $.each(data, function (index, val) { 1649 1650 var cancelled = parseInt(val.changed); 1651 if ((cancelled !== 1 || isNaN(cancelled)) || self.settings.eventsCalendarShowCancelledEvents) { 1652 $('<div class="eelistevent"></div>').append(self._getEventBlock(val, false)).appendTo($list); 1653 } 1654 }); 1655 if ($list.children().length === 0) $list.html('<div class="eelisttitle" style="margin-left:20px">Sorry there are no events that match your selection.</div>'); 1656 } else if (self.settings.view == 'grid') { 1657 var sortedData = {}; 1658 $.each(data, function (index, val) { 1659 var d = moment(val.raw_start_time).format('YYYY-M-D'); 1660 if (!sortedData[d]) sortedData[d] = []; 1661 1662 var cancelled = parseInt(val.changed); 1663 if ((cancelled !== 1 || isNaN(cancelled)) || self.settings.eventsCalendarShowCancelledEvents) { 1664 sortedData[d].push(val); 1665 } 1666 }); 1667 $grid.empty(); 1668 var month = self.gridView.data('date').format('M'); 1669 $('.events-date-string', self.gridView).text(self.gridView.data('date').format('MMMM YYYY')); 1670 1671 var a = moment(options.date); 1672 var b = a.clone().add(42, 'days'); 1673 var row = false; 1674 for (var m = a; m.isBefore(b); m.add(1, 'days')) { 1675 if (m.format('e') == 0) { 1676 row = $('<div class="events-grid-row"></div>').appendTo($grid); 1677 } 1678 var cell = $('<div class="events-grid-cell noselect"></div>').appendTo(row); 1679 1680 $('<span class="events-grid-cell-date fa-stack fa-lg"><i class="fa fa-circle fa-stack-2x"></i><i class="events-grid-cell-date-number fa fa-stack-1x">' + m.format('D') + '</i></span>').appendTo(cell); 1681 var cellContent = $('<div class="events-grid-cell-content"></div>').appendTo(cell); 1682 var cellTypes = $('<div class="events-grid-cell-types"></div>').appendTo(cell); 1683 1684 if (m.format('M') !== month) cell.addClass('events-grid-cell-fade'); 1685 if (m.isSame(moment().startOf('day'))) cell.addClass('events-grid-cell-today'); 1686 cell.data('events', sortedData[m.format('YYYY-M-D')] || []); 1687 1688 if (cell.data('events').length > 0) { 1689 var dayData = cell.data('events'); 1690 var evts = $('<div class="events-grid-cell-event-holder"></div>').appendTo(cell); 1691 if (dayData.length <= self.settings.inCellEvents) { 1692 $.each(dayData, function (index, val) { 1693 if (self.settings.eventsGroupCalenderBAge) { 1694 var age = val.agesArray[0]; 1695 if (parseInt(val.changed, 10) === 2) { 1696 var start = (val.changed_start_time == '12:00am' && val.changed_end_time == '11:59pm') ? 'All day' : val.changed_start_time; 1697 } else { 1698 var start = (val.start_time == '12:00am' && val.end_time == '11:59pm') ? 'All day' : val.start_time; 1699 } 1700 var dotColour = typeof self.ages[age] !== 'undefined' ? self.ages[age] : self._genColour(age); 1701 } else { 1702 var tag = val.tagsArray[0]; 1703 if (parseInt(val.changed, 10) === 2) { 1704 var start = (val.changed_start_time == '12:00am' && val.changed_end_time == '11:59pm') ? 'All day' : val.changed_start_time; 1705 } else { 1706 var start = (val.start_time == '12:00am' && val.end_time == '11:59pm') ? 'All day' : val.start_time; 1707 } 1708 var dotColour = typeof self.tags[tag] !== 'undefined' ? self.tags[tag] : self._genColour(tag); 1709 } 1710 var evcell = $('<div class="events-grid-cell-event"><i class="fa fa-circle" style="color:' + dotColour + '"></i> <b>' + start + '</b> ' + val.title + '</div>').data('event', val).appendTo(evts); 1711 evcell.qtip({ 1712 content: { 1713 text: function (event, api) { 1714 return self._getEventBlock(val, true); 1715 } 1716 }, 1717 style: { 1718 classes: 'qtip-bootstrap events-popup', 1719 def: false, 1720 width: 500 1721 }, 1722 hide: { 1723 fixed: true, 1724 delay: 300 1725 }, 1726 position: { 1727 viewport: $(window) 1728 } 1729 }); 1730 1731 }); 1732 } else { 1733 var locs = []; 1734 var tags = {}; 1735 $.each(dayData, function (index, val) { 1736 if (parseInt(val.changed, 10) == 1) return;
1736 // Do not show cancelled events in total 1737 locs.push(val.location); 1738 if (self.settings.eventsGroupCalenderBAge) { 1739 if (val.ages) { 1740 $.each(val.agesArray, function (index, val) { 1741 if (!tags[val]) { 1742 tags[val] = 1; 1743 } else { 1744 tags[val]++; 1745 } 1746 }); 1747 } 1748 } else { 1749 if (val.tags) { 1750 $.each(val.tagsArray, function (index, val) { 1751 if (!tags[val]) { 1752 tags[val] = 1; 1753 } else { 1754 tags[val]++; 1755 } 1756 }); 1757 } 1758 } 1759 }); 1760 locs = locs.filter(function (item, i, ar) { 1761 return ar.indexOf(item) === i; 1762 }); 1763 1764 var i = 0; 1765 $.each(tags, function (type, total) { 1766 i++; 1767 if (i <= 14) { 1768 if (self.settings.eventsGroupCalenderBAge) { 1769 var textColour = self._getContrastYIQ(self.ages[type] || self._genColour(type)); 1770 $('<span title="' + type + '" class="events-grid-cell-type fa-stack fa-lg"><i class="fa fa-circle fa-stack-2x"></i><i style="color:' + textColour + '" class="events-grid-cell-type-number fa fa-stack-1x">' + total + '</i></span>').css('color', self.ages[type] || self._genColour(type)).appendTo(cellTypes); 1771 } else { 1772 var textColour = self._getContrastYIQ(self.tags[type] || self._genColour(type)); 1773 $('<span title="' + type + '" class="events-grid-cell-type fa-stack fa-lg"><i class="fa fa-circle fa-stack-2x"></i><i style="color:' + textColour + '" class="events-grid-cell-type-number fa fa-stack-1x">' + total + '</i></span>').css('color', self.tags[type] || self._genColour(type)).appendTo(cellTypes); 1774 } 1775 } 1776 }); 1777 if (i > 14) { 1778 $('<div class="events-grid-cell-more">+ ' + (i - 14) + ' more ' + escapeHtml(self.settings.customEventLabel) + ' types</div>').appendTo(cellTypes); 1779 } 1780 var summary = dayData.length + ' ' + escapeHtml(self.settings.customEventsLabel) + ' at<br>'; 1781 summary += locs.length > 1 ? locs.length + ' locations' : ' 1 location'; 1782 cellContent.prepend(summary); 1783 } 1784 } 1785 1786 } 1787 1788 } 1789 self._scheduleHeightPost(); 1790 }); 1791 }, 1792 _eraseCookie: function (name) { 1793 createCookie(name, "", -1); 1794 }, 1795 _createCookie: function (name, value, days) { 1796 var expires = ""; 1797 if (days) { 1798 var date = new Date(); 1799 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 1800 expires = "; expires=" + date.toGMTString(); 1801 } 1802 document.cookie = name + "=" + value + expires + "; path=/"; 1803 }, 1804 _readCookie: function (name) { 1805 var nameEQ = name + "="; 1806 var ca = document.cookie.split(';'); 1807 for (var i = 0; i < ca.length; i++) { 1808 var c = ca[i]; 1809 while (c.charAt(0) == ' ') c = c.substring(1, c.length); 1810 if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); 1811 } 1812 return null; 1813 }, 1814 setView: function (view) { 1815 var self = this; 1816 view = (view === 'list' || view === 'grid') ? view : 'list'; 1817 self._createCookie('eventsView', view, 365); 1818 $('.linkcolour', self.viewPicker).removeClass('linkcolour'); 1819 $('[data-view="' + view + '"]', self.viewPicker).addClass('linkcolour'); 1820 $('[data-view]', self.views).hide(); 1821 $('[data-view="' + view + '"]', self.views).show(); 1822 1823 if (self.settings.view == view) return; 1824 self.settings.view = view; 1825 self._update(); 1826 }, 1827 reload: function () { 1828 this._update(); 1829 }, 1830 _getContrastYIQ: function (hexcolor) { 1831 var r = parseInt(hexcolor.substr(1, 2), 16); 1832 var g = parseInt(hexcolor.substr(3, 2), 16); 1833 var b = parseInt(hexcolor.substr(5, 2), 16); 1834 var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000; 1835 return (yiq >= 128) ? 'black' : 'white'; 1836 }, 1837 _genColour: function (str) { 1838 for (var i = 0, hash = 0; i < str.length; hash = str.charCodeAt(i++) + ((hash << 5) - hash)); 1839 for (var i = 0, colour = "#"; i < 3; colour += ("00" + ((hash >> i++ * 8) & 0xFF).toString(16)).slice(-2)); 1840 return colour; 1841 }, 1842 _genColumn: function (item, idx, targetEle, last) { 1843 var self = this; 1844 if (self.settings.filterCurrentColumn === null) { 1845 self.settings.filterCurrentColumn = $('<div style="float:left;width:250px;" />'); 1846 } 1847 1848 var limit = (typeof this.settings.filterMaxItems !== "undefined") ? this.settings.filterMaxItems : 15; 1849 if (idx % limit === 0) { 1850 self.settings.filterCurrentColumn.appendTo(targetEle); 1851 if (idx > 0) { 1852 self.settings.filterCurrentColumn = $('<div style="float:left;width:250px;" />'); 1853 self.settings.filterCurrentColumnCount++; 1854 } 1855 } 1856 1857 item.appendTo(self.settings.filterCurrentColumn); 1858 1859 if (last) { 1860 var colsMax = 250; 1861 self.settings.filterCurrentColumn.appendTo(targetEle); 1862 colsMax = (self.settings.filterCurrentColumnCount + 1) * 250; 1863 targetEle.css('max-width', colsMax.toString() + "px !important"); 1864 self.settings.filterCurrentColumn = null; 1865 self.settings.filterCurrentColumnCount = 0; 1866 } 1867 }, 1868 _loadFilters: function () { 1869 var self = this; 1870 $.getJSON(this.settings.apiServer + '/v1/' + self.settings.client + '/locations', function (json, textStatus) { 1871 self.locations = json; 1872 1873 $.each(json, function (index, val) { 1874 var lcName = val.name.toLowerCase().replace(/,/g, ''); 1875 var checked = self.settings.locations.indexOf(lcName) >= 0 ? 'checked="checked"' : ''; 1876 if (self.settings.excludedLocations.length > 0) { 1877 checked = self.settings.excludedLocations.indexOf(lcName) >= 0 ? '' : 'checked="checked"'; 1878 } 1879 var item = $('<label for="loc_' + val.id + '"><input value="' + val.id + '" id="loc_' + val.id + '" type="checkbox" ' + checked + ' aria-label="Location Filter: ' + val.name + '"> ' + val.name + '</label>'); 1880 self._genColumn(item, index, self.locationList, index === (json.length - 1)); 1881 }); 1882 1883 self.locationsLoaded = true; 1884 if (self.agesLoaded && self.locationsLoaded && self.tagsLoaded) self._update(); 1885 }).error(function (jqXHR, textStatus, errorThrown) { 1886 console.log(errorThrown); 1887 }); 1888 1889 $.getJSON(this.settings.apiServer + '/v1/' + self.settings.client + '/eventstags', function (json, textStatus) { 1890 if (self.settings.eventsGroupCalenderBAge) { 1891 self.tags = json; 1892 1893 $.each(json, function (index, val) { 1894 var lcName = val.name.toLowerCase(); 1895 var checked = self.settings.types.indexOf(lcName) >= 0 ? 'checked="checked"' : ''; 1896 if (self.settings.excludedTypes.length > 0) { 1897 checked = self.settings.excludedTypes.indexOf(lcName) >= 0 ? '' : 'checked="checked"'; 1898 } 1899 var item = $('<label for="type_' + index + '"><input value="' + val.name + '" id="type_' + index + '" type="checkbox" ' + checked + ' aria-label="Age Filter: ' + val.name + '"> ' + val.name + '</label>'); 1900 self._genColumn(item, index, self.typeList, index === (json.length - 1)); 1901 }); 1902 } else { 1903 self.tags = {}; 1904 1905 $.each(json, function (index, val) { 1906 if (!val.colour) { 1907 val.colour = self._genColour(val.name); 1908 } 1909 1910 self.tags[val.name] = val.colour; 1911 var lcName = val.name.toLowerCase(); 1912 var checked = ''; 1913 if (self.settings.types.length > 0) { 1914 checked = self.settings.types.indexOf(lcName) >= 0 ? 'checked="checked"' : ''; 1915 } else if (self.settings.excludedTypes.length > 0) { 1916 checked = self.settings.excludedTypes.indexOf(lcName) >= 0 ? '' : 'checked="checked"'; 1917 } else { 1918 //checked = 'checked="checked"'; 1919 } 1920 var item = $('<label for="type_' + index + '"><input value="' + val.name + '" id="type_' + index + '" type="checkbox" ' + checked + ' aria-label="Type Filter: ' + val.name + '"> <i class="fa fa-circle" style="color:' + val.colour + '"></i> ' + val.name + '</label>'); 1921 self._genColumn(item, index, self.typeList, index === (json.length - 1)); 1922 }); 1923 } 1924 1925 self.tagsLoaded = true; 1926 if (self.agesLoaded && self.locationsLoaded && self.tagsLoaded) self._update(); 1927 }); 1928 $.getJSON(this.settings.apiServer + '/v1/' + self.settings.client + '/eventsages', function (json, textStatus) { 1929 if (self.settings.eventsGroupCalenderBAge) { 1930 self.ages = {}; 1931 1932 $.each(json, function (index, val) { 1933 if (!val.colour) { 1934 val.colour = self._genColour(val.name); 1935 } 1936 1937 self.ages[val.name] = val.colour; 1938 var lcName = val.name.toLowerCase(); 1939 var checked = self.settings.ages.indexOf(lcName) >= 0 ? 'checked="checked"' : ''; 1940 if (self.settings.excludedAges.length > 0) { 1941 checked = self.settings.excludedAges.indexOf(lcName) >= 0 ? '' : 'checked="checked"'; 1942 } 1943 var item = $('<label for="group_' + index + '"><input value="' + val.name + '" id="group_' + index + '" type="checkbox" ' + checked + ' aria-label="Ages Filter: ' + val.name + '"> <i class="fa fa-circle" style="color:' + val.colour + '"></i> ' + val.name + '</label>'); 1944 self._genColumn(item, index, self.ageList, index === (json.length - 1)); 1945 }); 1946 } else { 1947 self.ages = json; 1948 1949 $.each(json, function (index, val) { 1950 var lcName = val.name.toLowerCase(); 1951 var checked = self.settings.ages.indexOf(lcName) >= 0 ? 'checked="checked"' : ''; 1952 if (self.settings.excludedAges.length > 0) { 1953 checked = self.settings.excludedAges.indexOf(lcName) >= 0 ? '' : 'checked="checked"'; 1954 } 1955 var item = $('<label for="group_' + index + '"><input value="' + val.name + '" id="group_' + index + '" type="checkbox" ' + checked + ' aria-label="Ages Filter: ' + val.name + '"> ' + val.name + '</label>'); 1956 self._genColumn(item, index, self.ageList, index === (json.length - 1)); 1957 }); 1958 } 1959 self.agesLoaded = true; 1960 if (self.agesLoaded && self.locationsLoaded && self.tagsLoaded) self._update(); 1961 }); 1962 } 1963 }); 1964 1965 $.fn[pluginName] = function (options) { 1966 return this.each(function () { 1967 if (!$.data(this, "plugin_" + pluginName)) { 1968 $.data(this, "plugin_" + pluginName, new Plugin(this, options)); 1969 } 1970 }); 1971 }; 1972})(jQuery, window, document);
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.