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 var childBottom = Math.ceil(child.getBoundingClientRect().bottom + scrollY); 593 contentHeight = Math.max(contentHeight, childBottom); 594 } 595 } 596 contentHeight += 8; 597 if (!contentHeight || (!forcePost && contentHeight === self._lastEmbeddedHeight)) { 598 return; 599 } 600 self._lastEmbeddedHeight = contentHeight; 601 self._postToParent('height-update', { height: contentHeight }); 602 }); 603 }, 604 _updateDateRange: function () { 605 var self = this; 606 self.paused = true; 607 var now = moment(); 608 609 switch (self.settings.range) { 610 case 'today': 611 self.settings.start = now.startOf('day'); 612 self.settings.end = now.clone(); 613 $('div.events-calendar').datepicker('setDate', now.startOf('day').toDate()); 614 $('.events-details a[href="#calendar"]').tab('show'); 615 break; 616 case 'tomorrow': 617 self.settings.start = now.add(1, 'day').startOf('day'); 618 self.settings.end = now.clone(); 619 $('div.events-calendar').datepicker('setDate', self.settings.start.toDate()); 620 $('.events-details a[href="#calendar"]').tab('show'); 621 break; 622 case 'thisweek': 623 self.settings.start = now; 624 self.settings.end = self.settings.start.clone().endOf('week'); 625 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 626 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 627 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 628 break; 629 case 'thismonth': 630 self.settings.start = now; 631 self.settings.end = self.settings.start.clone().endOf('month'); 632 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 633 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 634 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 635 break; 636 case 'nextweek': 637 self.settings.start = now.add(1, 'week').startOf('week'); 638 self.settings.end = self.settings.start.clone().endOf('week'); 639 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 640 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 641 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 642 break; 643 case 'nextmonth': 644 self.settings.start = now.add(1, 'month').startOf('month'); 645 self.settings.end = self.settings.start.clone().endOf('month'); 646 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 647 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 648 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 649 break; 650 case 'days': 651 self.settings.start = now; 652 self.settings.end = now.clone().add(self.settings.duration, 'days'); 653 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 654 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 655 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 656 break; 657 case 'weeks': 658 self.settings.start = now; 659 self.settings.end = now.clone().add(self.settings.duration, 'weeks'); 660 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 661 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 662 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 663 break; 664 case 'months': 665 self.settings.start = now; 666 self.settings.end = now.clone().add(self.settings.duration, 'months'); 667 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', self.settings.start.format('MMMM D YYYY')); 668 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', self.settings.end.format('MMMM D YYYY')); 669 $('.events-details a[href="#date_range"]', self.listViewLeft).tab('show'); 670 break; 671 } 672 self.paused = false;
673 self._update(); 674 }, 675 _bindEvents: function () { 676 var self = this; 677 self.gridView.data('date', moment(self.settings.gridDate).startOf('month')); 678 self.viewPicker.on('click keyup', '[data-view]', function (e) { 679 e.preventDefault(); 680 681 var isSpace = e.type === 'keyup' && (e.which == 32 || e.keyCode == 32 || e.key == " "); 682 var isEnter = e.type === 'keyup' && (e.which == 13 || e.keyCode == 13 || e.key == "Enter"); 683 684 if (e.type === 'click' || isSpace || isEnter) { 685 $('[data-view]').each(function (_, el) { 686 $(el).attr('aria-pressed', 'mixed'); 687 }) 688 689 self.setView($(this).attr('data-view')); 690 $(this).attr('aria-pressed', true); 691 } 692 }); 693 installCalendarAriaFix(self.element); 694 $('.events-range.input-daterange', self.listViewLeft).datepicker({ 695 todayBtn: "linked", 696 title: "Events calendar", 697 orientation: "bottom left", 698 format: 'MM d yyyy', 699 todayHighlight: true 700 }).on('changeDate', function (event) { 701 self.settings.range = 'range'; 702 self.settings.start = moment($('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('getDate')); 703 self.settings.end = moment($('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('getDate')); 704 self._update(); 705 }); 706 $('.events-date-input').on('click', '.input-group-addon', function (event) { 707 event.preventDefault(); 708 event.stopPropagation(); 709 $(this).closest('.events-date-input').find('input').datepicker('show'); 710 }); 711 712 $('div.events-calendar', self.listViewLeft).datepicker({ 713 title: "Events calendar", 714 startDate: new Date() 715 }).on('changeDate', function (event) { 716 event.preventDefault(); 717 self.paused = true; 718 $('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('update', moment(event.date).format('MMMM D YYYY')); 719 $('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('update', moment(event.date).format('MMMM D YYYY')); 720 self.settings.start = moment(event.date).startOf('day'); 721 self.settings.end = moment(event.date).endOf('day'); 722 if (!self.rangeUpdating) { 723 self.settings.range = 'range'; 724 } 725 self.paused = false; 726 self._update(); 727 }); 728 729 if (self.settings.start === self.settings.end) { 730 self.rangeUpdating = true; 731 $('div.events-calendar', self.listViewLeft).datepicker('setDate', new Date(self.settings.start.format('MMMM D YYYY'))); 732 self.rangeUpdating = false; 733 } 734 735 self.$element.on('click', '.events-option-dropdown', function (event) { 736 if (!$(event.target).hasClass('events-option-dropdown')) return; 737 event.preventDefault(); 738 var hide = $('.' + $(this).attr('data-show-filter')).is(':visible'); 739 $('.events-filter-section', self.$element).fadeOut(); 740 if (!hide) { 741 $('div.' + $(this).attr('data-show-filter'), self.$element).css({ 742 top: 30, 743 left: 0 744 }).position({ 745 my: "left top", 746 at: "left bottom", 747 of: this, // or $("#otherdiv) 748 collision: "fit", 749 within: self.$element, 750 using: function (pos, data) { 751 var menu = data.element.element; 752 pos.top = data.target.top + data.target.height + 30; 753 $(menu).css(pos) 754 } 755 }).fadeIn(); 756 } 757 }).on('click', '.events-filter-close', function (event) { 758 event.preventDefault(); 759 $(this).closest('.events-filter-section').fadeOut(); 760 }).on('change', '#loc_all', function (event) { 761 if ($(this).is(':checked')) { 762 self.$element.find('#event_locations [id^=loc_]').prop('checked', false); 763 } else { 764 $(this).prop('checked', true); 765 } 766 self._update(); 767 }).on('change', '#event_locations [id^=loc_]', function (event) { 768 if ($(this).is(':checked')) { 769 self.$element.find('#loc_all').prop('checked', false); 770 } else if (self.$element.find('#event_locations [id^=loc_]:checked').length === 0) { 771 self.$element.find('#loc_all').prop('checked', true); 772 } 773 self._update(); 774 }).on('change', '#group_all', function (event) { 775 if ($(this).is(':checked')) { 776 self.$element.find('#event_ages [id^=group_]').prop('checked', false); 777 } else { 778 $(this).prop('checked', true); 779 } 780 self._update(); 781 }).on('change', '#event_ages [id^=group_]', function (event) { 782 if ($(this).is(':checked')) { 783 self.$element.find('#group_all').prop('checked', false); 784 } else if (self.$element.find('#event_locations [id^=group_]:checked').length === 0) { 785 self.$element.find('#group_all').prop('checked', true); 786 } 787 self._update(); 788 }).on('change', '#type_all', function (event) { 789 if ($(this).is(':checked')) { 790 self.$element.find('#event_types [id^=type_]').prop('checked', false); 791 } else { 792 $(this).prop('checked', true); 793 } 794 self._update(); 795 }).on('change', '#event_types [id^=type_]', function (event) { 796 if ($(this).is(':checked')) { 797 self.$element.find('#type_all').prop('checked', false); 798 } else if (self.$element.find('#event_types [id^=type_]:checked').length === 0) { 799 self.$element.find('#type_all').prop('checked', true); 800 } 801 self._update(); 802 }).on('click', '.events-filter-clear', function (event) { 803 event.preventDefault(); 804 self.$element.find('.events-search-field').val(''); 805 self.$element.find('#loc_all').prop('checked', true); 806 self.$element.find('#group_all').prop('checked', true); 807 self.$element.find('#type_all').prop('checked', true); 808 self.$element.find('#event_ages [id^=group_]').prop('checked', false); 809 self.$element.find('#event_types [id^=type_]').prop('checked', false); 810 self.$element.find('#event_locations [id^=loc_]').prop('checked', false); 811 self._update(); 812 }).on('keyup', '.events-search-field', function (event) { 813 if (self.SearchTimer) { 814 clearTimeout(self.SearchTimer); 815 self.SearchTimer = false;
816 } 817 var term = $(this).val(); 818 self.SearchTimer = setTimeout(function () { 819 self._doSearch(term); 820 }, 750); 821 }); 822 $('.events-change-day', self.listViewRight).on('click keyup', function (event) { 823 event.preventDefault(); 824 825 var isSpace = event.type === 'keyup' && (event.which === 32 || event.keyCode === 32 || event.key === " "); 826 var isEnter = event.type === 'keyup' && (event.which === 13 || event.keyCode === 13 || event.key === "Enter"); 827 828 if (event.type === 'click' || isSpace || isEnter) { 829 self.settings.range = 'range'; 830 var newdate = moment($('div.events-calendar', self.listViewLeft).datepicker('getDate')).add($(this).attr('data-by'), 'day').startOf('day'); 831 if (newdate.isBefore(moment().startOf('day'))) return; 832 $('div.events-calendar', self.listViewLeft).datepicker('setDate', newdate.toDate()); 833 } 834 }); 835 self.listViewLeft.on('click', '.events-link>a', function (event) { 836 if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.which === 2) { 837 return; 838 } 839 event.preventDefault(); 840 self.paused = true; 841 self.settings.range = $(this).attr('data-type'); 842 self.rangeUpdating = true; 843 self._updateDateRange(); 844 self.rangeUpdating = false; 845 }); 846 self.gridView.on('click', '.events-grid-cell', function (event) { 847 event.preventDefault(); 848 var selected = $(this).hasClass('events-grid-cell-selected'); 849 self.gridView.find('.events-grid-day-list').remove(); 850 self.gridView.find('.events-grid-cell-selected').removeClass('events-grid-cell-selected'); 851 if (!selected) { 852 $(this).addClass('events-grid-cell-selected'); 853 var dayView = $('<div class="events-grid-day-list"></div>').insertAfter($(this).closest('.events-grid-row')); 854 $.each($(this).data('events'), function (index, val) { 855 var hasPre = false; 856 var isBilled = false; 857 var preText = ''; 858 var tagString = ''; 859 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> '; 860 var title = val.title; 861 862 if (typeof (val.enable_billing) !== 'undefined') { 863 isBilled = parseInt(val.enable_billing) === 1; 864 } 865 866 if (self.settings.eventsGroupCalenderBAge) { 867 if (val.ages) { 868 $.each(val.agesArray, function (index, val) { 869 var dotColour = typeof self.ages[val] !== 'undefined' ? self.ages[val] : self._genColour(val); 870 tagString += ' <i class="fa fa-circle" style="color:' + dotColour + '"></i> ' + val; 871 }); 872 } 873 } else { 874 if (val.tags) { 875 $.each(val.tagsArray, function (index, val) { 876 var dotColour = typeof self.tags[val] !== 'undefined' ? self.tags[val] : self._genColour(val); 877 tagString += ' <i class="fa fa-circle" style="color:' + dotColour + '"></i> ' + val; 878 }); 879 } 880 } 881 882 if (parseInt(val.changed) === 1) { 883 title = '<span class="eelist-changed-message">Cancelled</span> ' + title; 884 } 885 886 if (parseInt(val.changed) === 2 || parseInt(val.changed) === 3) { 887 title = '<span class="eelist-changed-message">Rescheduled</span> ' + title; 888 } 889 890 if (isBilled) { 891 title = ticketIcon + title; 892 } 893 894 if (hasPre) { 895 title = preText + title; 896 } 897 898 899 if (val.link) { 900 var link = $('<a target="' + self.settings.linkTarget + '" href="' + val.link + '"> ' + $('<div></div>').html(title).text() + '</a>'); 901 } else { 902 var id = val.new_event_id || val.id; 903 var embeddedEventPath = self._getEmbeddedEventPath(id); 904 var link = $('<a target="' + self.settings.linkTarget + '">' + title + '</a>'); 905 if (window.websiteUrl) { 906 link.attr('href', window.websiteUrl + '/event/' + id); 907 } else { 908 link.attr('href', '/event/' + id); 909 } 910 self._bindEmbeddedEventLink(link, embeddedEventPath); 911 } 912 if (val.sub_title) { 913 link.append('<span> - ' + val.sub_title + '</span>'); 914 } 915 916 917 link.qtip({ 918 content: { 919 text: function (event, api) { 920 return self._getEventBlock(val, true); 921 } 922 }, 923 style: { 924 classes: 'qtip-bootstrap events-popup', 925 def: false, 926 width: 500 927 }, 928 hide: { 929 fixed: true, 930 delay: 300 931 }, 932 position: { 933 viewport: $(window) 934 } 935 }); 936 if (parseInt(val.changed) === 1) { 937 $('<div> , ' + val.location + ' <span class="events-grid-day-list-tags">' + tagString + '</span></div>').prepend(link).appendTo(dayView); 938 } else if (parseInt(val.changed) === 2 || parseInt(val.changed) === 3) { 939 $('<div> <b>' + val.time_string + '</b>, ' + val.location + ' <span class="events-grid-day-list-tags">' + tagString + '</span></div>').prepend(link).appendTo(dayView); 940 } else { 941 $('<div> <b>' + val.time_string + '</b>, ' + val.location + ' <span class="events-grid-day-list-tags">' + tagString + '</span></div>').prepend(link).appendTo(dayView); 942 } 943 944 }); 945 } 946 }).on('click keyup', '.events-change-day', function (e) { 947 e.preventDefault(); 948 949 var isSpace = event.type === 'keyup' && (e.which == 32 || e.keyCode == 32 || e.key == " "); 950 var isEnter = event.type === 'keyup' && (e.which == 13 || e.keyCode == 13 || e.key == "Enter"); 951 952 if (e.type === 'click' || isSpace || isEnter) { 953 self.settings.range = 'range'; 954 self.gridView.data('date').add($(this).attr('data-by'), 'month'); 955 self.settings.gridDate = self.gridView.data('date').format('YYYY-MM-DD'); 956 self._update(); 957 } 958 }); 959 960 self.todayButton.on('click', function (event) { 961 event.preventDefault(); 962 self.settings.range = 'today'; 963 if (self.settings.view == 'list') { 964 self.rangeUpdating = true; 965 $('div.events-calendar', self.listViewLeft).datepicker('setDate', moment().startOf('day').toDate()); 966 self.rangeUpdating = false;
967 } else { 968 self.gridView.data('date', moment().startOf('month')); 969 970 } 971 self._update(); 972 }); 973 $(window).on('resize', function () { 974 var w = $(document).width(); 975 if (w < 768 && self.settings.view == 'grid') { 976 self.setView('list'); 977 } else { 978 979 } 980 self._scheduleHeightPost(); 981 }); 982 983 // Brochure button logic: 984 985 }, 986 _doSearch: function (term) { 987 this.paused = true; 988 var now = moment(); 989 if (this.settings.filters.days === 0) { 990 var startDate = now.format('MMMM D YYYY'); 991 var endDate = now.endOf('month').format('MMMM D YYYY'); 992 $('.events-range.input-daterange input[name=start]', this.listViewLeft).datepicker('update', startDate); 993 $('.events-range.input-daterange input[name=end]', this.listViewLeft).datepicker('update', endDate); 994 } 995 $('.events-details a[href="#date_range"]', this.listViewLeft).tab('show'); 996 this.paused = false; 997 this._update(); 998 }, 999 1000 // #4381 - CK 1001 // Hide external venue description on qtip 1002 _getEventBlock: function (event, inQtip) { 1003 var self = this; 1004 var $item = $('<div class="eelistevent-data"></div>'); 1005 if (parseInt(event.changed) === 3) { 1006 $item.addClass('eelistevent-postponed'); 1007 } 1008 if (parseInt(event.changed) === 2 || parseInt(event.changed) === 3) { 1009 $('<div class="eelist-changed-message"></div>').text('Rescheduled').prependTo($item); 1010 } else if (parseInt(event.changed) === 1) { 1011 $item.addClass('eelistevent-canceled'); 1012 $('<div class="eelist-changed-message"></div>').text('Cancelled').prependTo($item); 1013 } 1014 var title = event.title; 1015 var evtLink = ''; 1016 var imageLink = '' 1017 1018 if (event.sub_title) title += '<span>' + ' - ' + event.sub_title + '</span>'; 1019 if (event.link) { 1020 evtLink = $('<a target="' + self.settings.linkTarget + '" href="' + event.link + '"></a>'); 1021 } else { 1022 var id = event.new_event_id || event.id; 1023 evtLink = $('<a target="' + self.settings.linkTarget + '" href="' + (window.websiteUrl || "") + '/event/' + id + '"></a>'); 1024 self._bindEmbeddedEventLink(evtLink, self._getEmbeddedEventPath(id)); 1025 } 1026 1027 imageLink = evtLink.clone(); 1028 evtLink.html(title); 1029 $('<div class="eelisttitle"></div>').append(evtLink).appendTo($item); 1030 1031 // CH 14854 - Add in event images. 1032 // 1033 if (self.settings.showImagesInListGrid) { 1034 if (typeof event.image === 'string' && event.image.length > 0) { 1035 var url = 'https://' + self.settings.client + '.libnet.info/images/events/' + self.settings.client + '/' + event.image; 1036 //var image = '<img src="' + url + '" class="img-thumbnail event-list-image" alt="' + event.title + '"/>'; 1037 var imageFrame = $('<div/>'); 1038 var image = $('<span/>') 1039 .attr('role', 'img') 1040 .attr('aria-label', event.title) 1041 .css({ 1042 'display': 'inline-block', 1043 'width': '118px', 1044 'height': '118px', 1045 'background-image': 'url(\'' + url + '\')', 1046 'background-position': 'center center', 1047 'background-size': 'cover' 1048 }); 1049 1050 if (typeof event.image_alt_text === 'string' && event.image_alt_text.length > 0) { 1051 image.attr('aria-label', event.image_alt_text); 1052 } 1053 1054 imageFrame.append(image); 1055 imageLink.append(imageFrame); 1056 1057 $('<div class="eelistimage"></div>').append(imageLink).appendTo($item); 1058 } 1059 } 1060 1061 if (parseInt(event.changed) === 2) { 1062 $item.append('<div class="eelisttime eelisttime-postponed headingtext">(' + 1063 '<span>Rescheduled from </span>' + 1064 event.datestring + ': ' + event.time_string + 1065 ')</div>'); 1066 1067 var tt = $('<div class="eelisttime headingtext"></div>').append("<span class='eelist-changed-message'> New date </span>").appendTo($item); 1068 tt.append(document.createTextNode(event.changed_datestring + ': ' + event.changed_time_string)); 1069 } else if (parseInt(event.changed) === 3) { 1070 $item.append('<div class="eelisttime headingtext">' + event.datestring + ': ' + event.time_string + '</div>'); 1071 var tt = $('<div class="eelisttime headingtext"></div>').append("<span class='eelist-changed-message'> New date </span>").appendTo($item); 1072 tt.append(document.createTextNode(event.changed_datestring + ': ' + event.changed_time_string)); 1073 } else { 1074 $item.append('<div class="eelisttime headingtext">' + event.datestring + ': ' + event.time_string + '</div>'); 1075 } 1076 1077 var lstring = event.library; 1078 if (event.venues) {
1079 lstring += ' - <i>' + event.venues + '</i>'; 1080 } 1081 if (parseInt(event.changed_venue) == 1) { 1082 $item.append('<div class="eelocation"><i class="am-locations"/><span class="eelist-changed-message"> New venue </span> ' + lstring + '</div>'); 1083 } else { 1084 $item.append('<div class="eelocation"><i class="am-locations"/> ' + lstring + '</div>'); 1085 } 1086 1087 if (event.agesArray) { 1088 if (self.settings.eventsGroupCalenderBAge) { 1089 var tagsList = $('<div class="eelisttags"></div>').append('<span>Age group: </span>').appendTo($item); 1090 $.each(event.agesArray, function (index, val) { 1091 var dotColour = typeof self.ages[val] !== 'undefined' ? self.ages[val] : self._genColour(val); 1092 tagsList.append('<span><i class="fa fa-circle" style="color:' + dotColour + '"></i> ' + val + ' </span>'); 1093 }); 1094 } else { 1095 $('<div class="eelistgroup"></div>').append('<span>Age group: </span>').append(event.agesArray.join(", ")).appendTo($item); 1096 } 1097 } 1098 1099 if (event.tagsArray) { 1100 if (self.settings.eventsGroupCalenderBAge) { 1101 $('<div class="eelistgroup"></div>').append('<span>' + escapeHtml(self.settings.customEventLabel) + ' type: </span>').append(event.tagsArray.join(", ")).appendTo($item); 1102 } else { 1103 var tagsList = $('<div class="eelisttags"></div>').append('<span>' + escapeHtml(self.settings.customEventLabel) + ' type: </span>').appendTo($item); 1104 $.each(event.tagsArray, function (index, val) { 1105 var dotColour = typeof self.tags !== 'undefined' && typeof self.tags[val] !== 'undefined' ? self.tags[val] : self._genColour(val); 1106 tagsList.append('<span><i class="fa fa-circle" style="color:' + dotColour + '"></i> ' + val + ' </span>'); 1107 }); 1108 } 1109 } 1110 1111 $item.append('<div class="eelistdesc">' + event.description + '</div>'); 1112 // #4381 - CK 1113 // Hide external venue description on qtip 1114 if (event.venue_type && event.venue_type == 'external' && event.venue_description.length > 0 && !inQtip) { 1115 $item.append('<div class="eelistvenuedesc"><b>Venue details</b><br>' + event.venue_description + '</div>'); 1116 } 1117 1118 if ((parseInt(event.changed, 10) !== 1 && parseInt(event.changed, 10) !== 3) && parseInt(event.allow_reg, 10) === 1) { 1119 if (moment.tz(event.close_registration, self.settings.timezone).diff() < 0) { 1120 if (parseInt(event.third_party_reg, 10) == 0) { 1121 $item.append('<div class="regclosed">Registration is now closed</div>'); 1122 } 1123 } else { 1124 // If third-party-reg is off then run the numbers, otherwise jump to next if set. 1125 // CH #11417 - Added maximums for waitlists. 1126 if (event.ticketInfo) { 1127 var available = 0; 1128 if (event.ticketInfo.ticketData) { 1129 for (var t = 0; t < event.ticketInfo.ticketData.length; t++) { 1130 var tkt = event.ticketInfo.ticketData[t]; 1131 available += tkt.available; 1132 } 1133 } 1134 1135 if (event.ticketInfo.typeId === -1) { 1136 available = event.ticketInfo.available; 1137 } 1138 1139 if (available <= 0) { 1140 if (self.settings.allowWaitlistSubscription) { 1141 $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>'); 1142 $('<button data-eventid="' + event.id + '" data-recurringid="' + event.recurring_id + '" data-regtype="-1" class="button subscribeToEvent"></button>') 1143 .text(self.settings.customInterestedText) 1144 .on('click', function () { 1145 self._showInterestedPopup($(this).attr('data-eventid'), $(this).attr('data-recurringid'), event); 1146 }) 1147 .appendTo($item) 1148 } else { 1149 $item.append('<div class="regclosed">This ' + escapeHtml(self.settings.customEventLabel) + ' is full</div>'); 1150 } 1151 1152 //$btn.text('Event Full').prop('disabled', true); 1153 return $item; 1154 } 1155 } 1156 1157 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)))); 1158 var regAllowed = parseInt(event.total_registrants, 10) < parseInt(event.max_attendee, 10) || allowWaitList; 1159 1160 if (parseInt(event.third_party_reg, 10) === 0) { 1161 if (!regAllowed) { 1162 $item.append('<div class="regclosed">This ' + escapeHtml(self.settings.customEventLabel) + ' is full</div>'); 1163 return $item; 1164 } 1165 } 1166 1167 if (event.version == 2 && parseInt(event.third_party_reg, 10) === 1) { 1168 if (event.reg_url.length > 0) { 1169 $('<a target="' + self.settings.linkTarget + '" href="' + event.reg_url + '" class="button eventRegButton">Register</a>').appendTo($item); 1170 } 1171 } else if (parseInt(event.staff_only_registration, 10) === 1) { 1172 $('<div class="regclosed eventStaffRegMessage">Please contact the library to register for this event</div>').appendTo($item); 1173 } else {
1174 var event_id = event.id; 1175 var location_id = event.location_id; 1176 var $btn, $onlineBtn; 1177 1178 if (parseInt(event.total_registrants, 10) >= parseInt(event.max_attendee, 10)) { 1179 var m = 'Join the wait list'; 1180 var regstatus = '0'; 1181 var t = '2'; 1182 } else { 1183 var m = 'Register'; 1184 var regstatus = '1'; 1185 var t = '1'; 1186 } 1187 1188 if (parseInt(event.whole_serires_only, 10) === 1 && moment(event.series_starts).subtract(event.registration_close, 'minutes').tz(self.settings.timezone).diff() < 0) { 1189 if (parseInt(event.third_party_reg, 10) == 0) { 1190 $item.append('<div class="regclosed">Registration is now closed</div>'); 1191 } 1192 } else if (parseInt(event.whole_serires_only, 10) === 0 || (parseInt(event.whole_serires_only, 10) === 1)) { 1193 $btn = null, $onlineBtn = null; 1194 if (event.event_type !== undefined && event.event_type !== '') { 1195 if (event.event_type == 'INPERSON' && event.webinar_seats && event.venue_type == 'external') { 1196 event.event_type = 'HYBRID'; 1197 event.max_attendee_virtual = event.webinar_seats; 1198 } 1199 1200 switch (event.event_type) { 1201 case 'INPERSON': 1202 var ariaLabel = m + " for " + event.title + " in person" + " on " + event.datestring + " at " + event.start_time; 1203 $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(); 1204 break; 1205 case 'ONLINE': 1206 var ariaLabel = m + " for " + event.title + " on line" + " on " + event.datestring + " at " + event.start_time; 1207 $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(); 1208 break; 1209 case 'HYBRID': 1210 if (parseInt(event.allow_waitlist, 10) == 1 && parseInt(event.total_inperson_registrants, 10) >= parseInt(event.max_attendee_in_branch, 10)) { 1211 var m_in_branch = 'Join the wait list'; 1212 var t_in_branch = '2'; 1213 } else if (parseInt(event.max_attendee_in_branch, 10) > 0) { 1214 var m_in_branch = 'Register'; 1215 var t_in_branch = '1'; 1216 } 1217 1218 if (parseInt(event.allow_waitlist, 10) == 1 && parseInt(event.total_online_registrants, 10) >= parseInt(event.max_attendee_virtual, 10)) { 1219 var m_online = 'Join the wait list'; 1220 var t_online = '2'; 1221 } else if (parseInt(event.max_attendee_virtual, 10) > 0) { 1222 var m_online = 'Register'; 1223 var t_online = '1'; 1224 } 1225 1226 if (parseInt(event.allow_waitlist, 10) == 1 || parseInt(event.total_inperson_registrants, 10) < parseInt(event.max_attendee_in_branch, 10)) { 1227 var ariaLabel = m_in_branch + " for " + event.title + " to attend in person" + " on " + event.datestring + " at " + event.start_time; 1228 if (parseInt(event.max_attendee_in_branch, 10) > 0) { 1229 $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(); 1230 } 1231 } 1232 1233 if (parseInt(event.allow_waitlist, 10) == 1 || parseInt(event.total_online_registrants, 10) < parseInt(event.max_attendee_virtual, 10)) { 1234 var ariaLabelOnline = m_online + " for " + event.title + " to attend online" + " on " + event.datestring + " at " + event.start_time; 1235 if (parseInt(event.max_attendee_virtual, 10) > 0) { 1236 $onlineBtn = $('<button aria-label="' + ariaLabelOnline + '" data-eventid="' + event.i
1236d + '" 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(); 1237 } 1238 } 1239 1240 break; 1241 } 1242 } else { 1243 var ariaLabelOther = m + " for " + event.title + " on " + event.datestring + " at " + event.start_time; 1244 $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(); 1245 } 1246 1247 // Time juggling for the reg button CH10228. 1248 // Due to some oddities in the way moment works and calculates differences 1249 // No TZ conversion here since time is saved as a TZ time to the database. It also screws with comparisons. 1250 // 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: 1251 // E.g(2). 2019-02-01T11:00:00-6:00 as tz calculation takes into account a tz-less time. Confusing. I know. 1252 var regOpens = moment(event.reg_opens).format('YYYY-MM-DD HH:mm:ss'); 1253 // Add the timezone here to account for local computer time 1254 // 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. 1255 var nowTime = moment().tz(self.settings.timezone).format('YYYY-MM-DD HH:mm:ss'); 1256 // Formatted times can now be compared, because the TZ string has been stripped. So basically we are comparing two different times. 1257 // E.g. 2019-02-01 1:30:00 (now) >= 2019-02-01 12:00:00 (opens) would be true. 1258 var regOpened = nowTime >= regOpens; 1259 1260 if (parseInt(event.open_registration_imidiatly, 10) === 0 && !regOpened) { 1261 if ($btn) { 1262 $btn.prop('disabled', true); 1263 } 1264 1265 if ($onlineBtn) { 1266 $onlineBtn.prop('disabled', true); 1267 } 1268 1269 $('<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); 1270 } 1271 } 1272 1273 1274 } 1275 } 1276 1277 if (typeof event.enable_billing !== 'undefined' && parseInt(event.enable_billing) === 1) { 1278 // Then there is class/ticketdata info 1279 $('.ticket-group', $item).remove(); 1280 var coEventBillingInfo = new EventBillingInfo(event.recurring_id, 1, event.ticketInfo); 1281 var infoBox = $('<div class="eelistgroup ticket-group"></div>'); 1282 infoBox.append(coEventBillingInfo.info).appendTo($item); 1283 } 1284 } 1285 return $item; 1286 }, 1287 _getFeed: function (type) { 1288 var self = this; 1289 var feedData = { 1290 feedType: type, 1291 filters: { 1292 location: [], 1293 ages: [], 1294 types: [], 1295 tags: [], 1296 term: '', 1297 days: 1 1298 } 1299 }; 1300 1301 if (self.settings.filters) { 1302 var filters = self.settings.filters; 1303 feedData.filters.ages = filters.ages.length > 0 ? filters.ages : ['all']; 1304 feedData.filters.types = filters.types.length > 0 ? filters.types : ['all']; 1305 feedData.filters.location = self.settings.locations.length > 0 ? self.settings.locations : ['all']; 1306 } 1307 if($('.events-search-field', self.element).val() && $('.events-search-field', self.element).val().length > 0) { 1308 feedData.filters.term = $('.events-search-field', self.element).val(); 1309 } else if (self.settings.term && self.settings.term.length > 0) { 1310 feedData.filters.term = self.settings.term; 1311 } 1312 1313 var urlFilters = JSON.stringify(feedData); 1314 var url = window.location.protocol + "//" + window.location.hostname + '/feeds?data=' + btoa(urlFilters); 1315 this._showFeedPopup(url, feedData); 1316 //window.open('/feeds?data='+ urlFilters , '_blank'); 1317 }, 1318 _showFeedPopup: function (url, filterData) { 1319 var self = this; 1320 var term = filterData.filters.term; 1321 var filterString = 'Showing '; 1322 1323 if (term && term.length > 2) { 1324 filterString += 'search results for <b>' + term + '</b> for '; 1325 } 1326 1327 if (filterData.filters.types.length > 0) { 1328 filterString += filterData.filters.types.join(', ') + ' events'; 1329 } else { 1330 filterString += 'all ' + self.settings.customEventLabel + 'types'; 1331 } 1332 filterString += ' at '; 1333 if (self.settings.filters.locations.length > 0) { 1334 if (self.settings.filters.locations.length > 1) { 1335 filterString += 'these locations ' + self.settings.filters.locations.join(', '); 1336 } else { 1337 if (self.settings.filters.locations[0] !== 'all') { 1338 filterString += self.settings.filters.locations[0]; 1339 } else { 1340 filterString += 'all locations'; 1341 } 1342 } 1343 } else { 1344 filterString += 'all locations'; 1345 } 1346 1347 filterString += ' for '; 1348 if (filterData.filters.ages.length > 0) { 1349 if (filterData.filters.ages.length > 1) { 1350 filterString += 'the age groups ' + filterData.filters.ages.join(', '); 1351 } else { 1352 filterString += 'the age group ' + filterData.filters.ages[0]; 1353 } 1354 } else { 1355 filterString += 'all ages'; 1356 } 1357 1358 1359 if (filterData) { 1360 var icon = "fa fa-rss"; 1361 var style = "color:#f26522"; 1362 var title = "RSS"; 1363 1364 if (filterData.feedType === 'ical') { 1365 icon = "fa fa-calendar"; 1366 style = "color:#3981c6"; 1367 title = "iCal"; 1368 } 1369 1370 var html = '<div id="brochure-popup">' + 1371 ' <div class="row">' + 1372 ' <div class="col-md-12">' + 1373 ' <div style="float:right;"><a class="close-brochure-popup" style="cursor: pointer;">close</a></div>' + 1374 ' <h3 class="patron-popup heading-text"><i class="' + icon + '" style="' + style + '"></i> ' + title + ' Events Feed</h3>' + 1375 ' </div>' + 1376 ' </div>' + 1377 ' <div class="patron-popup top-row row">' + 1378 ' <div class="col-md-12">' + 1379 ' <strong>Feed will contain up to 500 events with filters selected, excluding dates.</strong>' + 1380 ' </div>' + 1381 ' <div class="col-md-12">' + 1382 ' Filtered By: ' + filterString + 1383 ' </div>' + 1384 ' </div>' + 1385 ' <div class="patron-popup row" style="margin-left:15px;margin-right:15px;padding-top:35px;padding-bottom:20px;">' + 1386 ' <div class="col-md-12">' + 1387 ' <input type="text" id="feed-link" class="form-control" aria-label="Feed URL" value="' + url + '"/>' + 1388 ' </div>' + 1389 ' </div>' + 1390 ' <div class="patron-popup button-row" style="margin-left:15px;">' + 1391 ' <div class="col-md-3 col-md-offset-6" style="padding-top: 10px;">' + 1392 ' <button class="copy-button brochure-button btn-block">Copy Link to Clipboard</button>' + 1393 ' </div>' + 1394 ' <div class="col-md-3" style="padding-top: 10px;">' + 1395 ' <button class="view-button brochure-button btn-block">Download File</button>' + 1396 ' </div>' + 1397 ' </div>' + 1398 1399 '</div>'; 1400 1401 var popup = $('<div class="events2-brochure"></div>
1401').amPopup({ 1402 title: '', 1403 popUpClass: '', 1404 showTitle: false 1405 }); 1406 popup.append(html); 1407 popup.on('click', '.close-brochure-popup', function () { 1408 popup.data('plugin_amPopup').close(); 1409 }) 1410 .on('click', '.copy-button', function () { 1411 var el = document.getElementById("feed-link"); 1412 el.select(); 1413 document.execCommand('copy'); 1414 }).on('click', '.view-button', function () { 1415 window.open(url, '_blank'); 1416 }); 1417 popup.data('plugin_amPopup').open(); 1418 } 1419 }, 1420 _showBrochurePopup: function () { 1421 var filters = {}; 1422 var options = {}; 1423 var self = this; 1424 1425 if (self.settings.filters) { 1426 filters = self.settings.filters; 1427 } 1428 1429 if (self.settings.filterOptions) { 1430 options = self.settings.filterOptions; 1431 } 1432 1433 var subData = { 1434 filters: filters, 1435 options: options, 1436 allowSubs: self.settings.allowSubs, 1437 customEventsLabel: self.settings.customEventsLabel, 1438 customEventLabel: self.settings.customEventLabel 1439 }; 1440 1441 var ps = new patronSubscriptions(subData); 1442 ps.showPopup(); 1443 }, 1444 // CH14299 1445 _showInterestedPopup: function (dateId, recurringId, eventInfo) { 1446 var self = this; 1447 var eventInfo = { 1448 title: eventInfo.title + ' - ' + eventInfo.sub_title, 1449 datestring: eventInfo.datestring + ' - ' + eventInfo.time_string, 1450 location: eventInfo.location 1451 }; 1452 1453 var interested = new EventBillingSubscriptions(dateId, recurringId, eventInfo, true); 1454 var interestedForm = interested.subscriptionForm; 1455 interestedForm.appendTo('body'); 1456 1457 $('.Event_Full-dialog').modal({ 1458 backdrop: 'static', 1459 keyboard: false 1460 }).modal('show'); 1461 1462 }, 1463 _update: function () { 1464 var self = this; 1465 if (self.paused) return; 1466 if (!self.initComplete) return; 1467 var options = {}; 1468 var filter = {}; 1469 options.private = self.settings.private; 1470 1471 var term = $('.events-search-field', self.element).val(); 1472 if (term && term.length > 2) { 1473 options.search = term; 1474 } 1475 1476 if (self.settings.view == 'list') { 1477 var end = moment($('.events-range.input-daterange input[name=end]', self.listViewLeft).datepicker('getDate')); 1478 var start = moment($('.events-range.input-daterange input[name=start]', self.listViewLeft).datepicker('getDate')); 1479 var days = end.diff(start, 'days'); 1480 1481 if (self.settings.filters.date === start.format('YYYY-MM-DD')) { 1482 options.date = self.settings.filters.date; 1483 } else { 1484 options.date = start.format('YYYY-MM-DD'); 1485 } 1486 1487 if (self.settings.filters.days === days) { 1488 options.days = self.settings.filters.days; 1489 } else { 1490 options.days = end.diff(start, 'days'); 1491 } 1492 1493 } else { 1494 var date = self.gridView.data('date').clone(); 1495 // options.date=date.isoWeekday(1).format('YYYY-MM-DD'); 1496 options.date = date.startOf('week').format('YYYY-MM-DD'); 1497 options.days = 42; 1498 } 1499 1500 //if (options.days === 0) options.days = 1; 1501 1502 $(".events-brochure, .brochure-grid, .events-rss, .events-ical").remove(); 1503 var navigation = $('.events-filter-row').first(); 1504 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>' : ''; 1505 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>' : ''; 1506 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>' : ''; 1507 var left = $('.events-left'); 1508 1509 if (self.settings.view === "grid") { 1510 navigation.append($('<div class="col-md-12 brochure-grid" style="margin-top:10px;">' + brochureButton + '</div>')); 1511 } else { 1512 left.append(brochureButton); 1513 left.append(rssButton); 1514 left.append(icalButton); 1515 } 1516 1517 $('.events-brochure-button').on('click', function () { 1518 //self._getBrochure(); 1519 if (self.settings.brochureNoPopup) { 1520 window.location.href = "/brochure"; 1521 } else { 1522 self._showBrochurePopup(); 1523 } 1524 }); 1525 1526 $('.events-rss-button').on('click', function () { 1527 //self._getBrochure(); 1528 self._getFeed('rss'); 1529 }); 1530 1531 $('.events-ical-button').on('click', function () { 1532 //self._getBrochure(); 1533 self._getFeed('ical'); 1534 }); 1535 1536 $('.events-day-title', self.listViewRight).toggle(options.days == 0); 1537 $('.events-range-title', self.listViewRight).toggle(options.days >= 1); 1538 1539 if (!$('#loc_all', self.listViewLeft).is(':checked')) { 1540 options.locations = []; 1541 filter.locations = []; 1542 $('[id^=loc_]', self.locationList).each(function () { 1543 if ($(this).is(':checked')) { 1544 options.locations.push($(this).attr('id').substr(4)); 1545 filter.locations.push($.trim($(this).parent().text())); 1546 } 1547 }); 1548 } 1549 if (!$('#group_all', self.listViewLeft).is(':checked')) { 1550 options.ages = []; 1551 filter.ages = []; 1552 $('[id^=group_]', self.ageList).each(function () { 1553 if ($(this).is(':checked')) { 1554 options.ages.push(encodeURIComponent($(this).attr('value'))); 1555 filter.ages.push($.trim($(this).parent().text())); 1556 } 1557 }); 1558 } 1559 if (!$('#type_all', self.listViewLeft).is(':checked')) { 1560 options.types = []; 1561 filter.types = []; 1562 $('[id^=type_]', self.typeList).each(function () { 1563 if ($(this).is(':checked')) { 1564 options.types.push(encodeURIComponent($(this).attr('value'))); 1565 filter.types.push($.trim($(this).parent().text())); 1566 } 1567 }); 1568 } 1569 if ((term && term.length > 2) || filter.locations.length > 0 || filter.ages.length > 0 || filter.types.length > 0) { 1570 var filterString = 'Showing '; 1571 if (term && term.length > 2) { 1572 filterString += 'search results for <b>' + term + '</b> for '; 1573 } 1574 if (filter.types.length > 0) { 1575 filterString += filter.types.join(', ') + ' events'; 1576 } else { 1577 filterString += 'all ' + self.settings.customEventLabel + ' types'; 1578 } 1579 filterString += ' at '; 1580 if (filter.locations.length > 0) { 1581 filterString += filter.locations.join(', '); 1582 } else { 1583 filterString += 'all locations'; 1584 } 1585 filterString += ' for '; 1586 if (filter.ages.length > 0) { 1587 if (filter.ages.length > 1) { 1588 filterString += 'the age groups ' + filter.ages.join(', '); 1589 } else { 1590 filterString += 'the age group ' + filter.ages[0]; 1591 } 1592 } else { 1593 filterString += 'all ages'; 1594 } 1595 $('.events-filter-message', self.views).html(filterString); 1596 $('.events-filter-details', self.views).fadeIn(); 1597 } else { 1598 $('.events-filter-details', self.views).hide(); 1599 } 1600 $('.events-date-range-string', self.listViewRight).text(''); 1601 1602 var $list = $('.events-body', self.listViewRight).empty().text('Loading events...'); 1603 1604 var $grid = $('.events-grid-body', self.gridView).empty().text('Loading events...'); 1605 1606 // Fix for bad dates. 1607 options.days++; 1608 1609 // Request for brochure on front-end, need to save off the filters - which are all the options used to get event data 1610 var filterOptions = { 1611 ages: filter.ages, 1612 locations: filter.locations, 1613 types: filter.types, 1614 days: options.days, 1615 date: options.date, 1616 private: options.private, 1617 term: options.search 1618 }; 1619 1620 self.settings.locations = options.locations; 1621 self.settings.filters = filterOptions; 1622 if (typeof (filterString) !== "undefined") { 1623 self.settings.filters.display = filterString.substr(7); 1624 } else { 1625 self.settings.filters.display = "All events for date range, no filters."; 1626 } 1627 1628 if (typeof (options.display) !== "undefined") { 1629 delete options.display; 1630 } 1631 1632 self.settings.filterOptions = options; 1633 self._setURLPieces();
1634 self._updateQuickRangeLinks(); 1635 1636 var website = (window.websiteUrl || ""); 1637 $.getJSON(website + '/eeventcaldata?event_type=' + self.settings.type + '&req=' + encodeURIComponent(JSON.stringify(options)), function (data) { 1638 if (self.settings.view == 'list') { 1639 $('.events-date-string', self.listViewRight).text(start.format('MMMM D YYYY')); 1640 $('.events-date-range-string', self.listViewRight).text(start.format('MMMM D YYYY') + ' - ' + end.format('MMMM D YYYY')); 1641 $list.empty(); 1642 $.each(data, function (index, val) { 1643 1644 var cancelled = parseInt(val.changed); 1645 if ((cancelled !== 1 || isNaN(cancelled)) || self.settings.eventsCalendarShowCancelledEvents) { 1646 $('<div class="eelistevent"></div>').append(self._getEventBlock(val, false)).appendTo($list); 1647 } 1648 }); 1649 if ($list.children().length === 0) $list.html('<div class="eelisttitle" style="margin-left:20px">Sorry there are no events that match your selection.</div>'); 1650 } else if (self.settings.view == 'grid') { 1651 var sortedData = {}; 1652 $.each(data, function (index, val) { 1653 var d = moment(val.raw_start_time).format('YYYY-M-D'); 1654 if (!sortedData[d]) sortedData[d] = []; 1655 1656 var cancelled = parseInt(val.changed); 1657 if ((cancelled !== 1 || isNaN(cancelled)) || self.settings.eventsCalendarShowCancelledEvents) { 1658 sortedData[d].push(val); 1659 } 1660 }); 1661 $grid.empty(); 1662 var month = self.gridView.data('date').format('M'); 1663 $('.events-date-string', self.gridView).text(self.gridView.data('date').format('MMMM YYYY')); 1664 1665 var a = moment(options.date); 1666 var b = a.clone().add(42, 'days'); 1667 var row = false; 1668 for (var m = a; m.isBefore(b); m.add(1, 'days')) { 1669 if (m.format('e') == 0) { 1670 row = $('<div class="events-grid-row"></div>').appendTo($grid); 1671 } 1672 var cell = $('<div class="events-grid-cell noselect"></div>').appendTo(row); 1673 1674 $('<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); 1675 var cellContent = $('<div class="events-grid-cell-content"></div>').appendTo(cell); 1676 var cellTypes = $('<div class="events-grid-cell-types"></div>').appendTo(cell); 1677 1678 if (m.format('M') !== month) cell.addClass('events-grid-cell-fade'); 1679 if (m.isSame(moment().startOf('day'))) cell.addClass('events-grid-cell-today'); 1680 cell.data('events', sortedData[m.format('YYYY-M-D')] || []); 1681 1682 if (cell.data('events').length > 0) { 1683 var dayData = cell.data('events'); 1684 var evts = $('<div class="events-grid-cell-event-holder"></div>').appendTo(cell); 1685 if (dayData.length <= self.settings.inCellEvents) { 1686 $.each(dayData, function (index, val) { 1687 if (self.settings.eventsGroupCalenderBAge) { 1688 var age = val.agesArray[0]; 1689 if (parseInt(val.changed, 10) === 2) { 1690 var start = (val.changed_start_time == '12:00am' && val.changed_end_time == '11:59pm') ? 'All day' : val.changed_start_time; 1691 } else { 1692 var start = (val.start_time == '12:00am' && val.end_time == '11:59pm') ? 'All day' : val.start_time; 1693 } 1694 var dotColour = typeof self.ages[age] !== 'undefined' ? self.ages[age] : self._genColour(age); 1695 } else { 1696 var tag = val.tagsArray[0]; 1697 if (parseInt(val.changed, 10) === 2) { 1698 var start = (val.changed_start_time == '12:00am' && val.changed_end_time == '11:59pm') ? 'All day' : val.changed_start_time; 1699 } else { 1700 var start = (val.start_time == '12:00am' && val.end_time == '11:59pm') ? 'All day' : val.start_time; 1701 } 1702 var dotColour = typeof self.tags[tag] !== 'undefined' ? self.tags[tag] : self._genColour(tag); 1703 } 1704 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); 1705 evcell.qtip({ 1706 content: { 1707 text: function (event, api) { 1708 return self._getEventBlock(val, true); 1709 } 1710 }, 1711 style: { 1712 classes: 'qtip-bootstrap events-popup', 1713 def: false, 1714 width: 500 1715 }, 1716 hide: { 1717 fixed: true, 1718 delay: 300 1719 }, 1720 position: { 1721 viewport: $(window) 1722 } 1723 }); 1724 1725 }); 1726 } else { 1727 var locs = []; 1728 var tags = {}; 1729 $.each(dayData, function (index, val) { 1730 if (parseInt(val.changed, 10) == 1) return;
1730 // Do not show cancelled events in total 1731 locs.push(val.location); 1732 if (self.settings.eventsGroupCalenderBAge) { 1733 if (val.ages) { 1734 $.each(val.agesArray, function (index, val) { 1735 if (!tags[val]) { 1736 tags[val] = 1; 1737 } else { 1738 tags[val]++; 1739 } 1740 }); 1741 } 1742 } else { 1743 if (val.tags) { 1744 $.each(val.tagsArray, function (index, val) { 1745 if (!tags[val]) { 1746 tags[val] = 1; 1747 } else { 1748 tags[val]++; 1749 } 1750 }); 1751 } 1752 } 1753 }); 1754 locs = locs.filter(function (item, i, ar) { 1755 return ar.indexOf(item) === i; 1756 }); 1757 1758 var i = 0; 1759 $.each(tags, function (type, total) { 1760 i++; 1761 if (i <= 14) { 1762 if (self.settings.eventsGroupCalenderBAge) { 1763 var textColour = self._getContrastYIQ(self.ages[type] || self._genColour(type)); 1764 $('<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); 1765 } else { 1766 var textColour = self._getContrastYIQ(self.tags[type] || self._genColour(type)); 1767 $('<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); 1768 } 1769 } 1770 }); 1771 if (i > 14) { 1772 $('<div class="events-grid-cell-more">+ ' + (i - 14) + ' more ' + escapeHtml(self.settings.customEventLabel) + ' types</div>').appendTo(cellTypes); 1773 } 1774 var summary = dayData.length + ' ' + escapeHtml(self.settings.customEventsLabel) + ' at<br>'; 1775 summary += locs.length > 1 ? locs.length + ' locations' : ' 1 location'; 1776 cellContent.prepend(summary); 1777 } 1778 } 1779 1780 } 1781 1782 } 1783 self._scheduleHeightPost(); 1784 }); 1785 }, 1786 _eraseCookie: function (name) { 1787 createCookie(name, "", -1); 1788 }, 1789 _createCookie: function (name, value, days) { 1790 var expires = ""; 1791 if (days) { 1792 var date = new Date(); 1793 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 1794 expires = "; expires=" + date.toGMTString(); 1795 } 1796 document.cookie = name + "=" + value + expires + "; path=/"; 1797 }, 1798 _readCookie: function (name) { 1799 var nameEQ = name + "="; 1800 var ca = document.cookie.split(';'); 1801 for (var i = 0; i < ca.length; i++) { 1802 var c = ca[i]; 1803 while (c.charAt(0) == ' ') c = c.substring(1, c.length); 1804 if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); 1805 } 1806 return null; 1807 }, 1808 setView: function (view) { 1809 var self = this; 1810 view = (view === 'list' || view === 'grid') ? view : 'list'; 1811 self._createCookie('eventsView', view, 365); 1812 $('.linkcolour', self.viewPicker).removeClass('linkcolour'); 1813 $('[data-view="' + view + '"]', self.viewPicker).addClass('linkcolour'); 1814 $('[data-view]', self.views).hide(); 1815 $('[data-view="' + view + '"]', self.views).show(); 1816 1817 if (self.settings.view == view) return; 1818 self.settings.view = view; 1819 self._update(); 1820 }, 1821 reload: function () { 1822 this._update(); 1823 }, 1824 _getContrastYIQ: function (hexcolor) { 1825 var r = parseInt(hexcolor.substr(1, 2), 16); 1826 var g = parseInt(hexcolor.substr(3, 2), 16); 1827 var b = parseInt(hexcolor.substr(5, 2), 16); 1828 var yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000; 1829 return (yiq >= 128) ? 'black' : 'white'; 1830 }, 1831 _genColour: function (str) { 1832 for (var i = 0, hash = 0; i < str.length; hash = str.charCodeAt(i++) + ((hash << 5) - hash)); 1833 for (var i = 0, colour = "#"; i < 3; colour += ("00" + ((hash >> i++ * 8) & 0xFF).toString(16)).slice(-2)); 1834 return colour; 1835 }, 1836 _genColumn: function (item, idx, targetEle, last) { 1837 var self = this; 1838 if (self.settings.filterCurrentColumn === null) { 1839 self.settings.filterCurrentColumn = $('<div style="float:left;width:250px;" />'); 1840 } 1841 1842 var limit = (typeof this.settings.filterMaxItems !== "undefined") ? this.settings.filterMaxItems : 15; 1843 if (idx % limit === 0) { 1844 self.settings.filterCurrentColumn.appendTo(targetEle); 1845 if (idx > 0) { 1846 self.settings.filterCurrentColumn = $('<div style="float:left;width:250px;" />'); 1847 self.settings.filterCurrentColumnCount++; 1848 } 1849 } 1850 1851 item.appendTo(self.settings.filterCurrentColumn); 1852 1853 if (last) { 1854 var colsMax = 250; 1855 self.settings.filterCurrentColumn.appendTo(targetEle); 1856 colsMax = (self.settings.filterCurrentColumnCount + 1) * 250; 1857 targetEle.css('max-width', colsMax.toString() + "px !important"); 1858 self.settings.filterCurrentColumn = null; 1859 self.settings.filterCurrentColumnCount = 0; 1860 } 1861 }, 1862 _loadFilters: function () { 1863 var self = this; 1864 $.getJSON(this.settings.apiServer + '/v1/' + self.settings.client + '/locations', function (json, textStatus) { 1865 self.locations = json; 1866 1867 $.each(json, function (index, val) { 1868 var lcName = val.name.toLowerCase().replace(/,/g, ''); 1869 var checked = self.settings.locations.indexOf(lcName) >= 0 ? 'checked="checked"' : ''; 1870 if (self.settings.excludedLocations.length > 0) { 1871 checked = self.settings.excludedLocations.indexOf(lcName) >= 0 ? '' : 'checked="checked"'; 1872 } 1873 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>'); 1874 self._genColumn(item, index, self.locationList, index === (json.length - 1)); 1875 }); 1876 1877 self.locationsLoaded = true; 1878 if (self.agesLoaded && self.locationsLoaded && self.tagsLoaded) self._update(); 1879 }).error(function (jqXHR, textStatus, errorThrown) { 1880 console.log(errorThrown); 1881 }); 1882 1883 $.getJSON(this.settings.apiServer + '/v1/' + self.settings.client + '/eventstags', function (json, textStatus) { 1884 if (self.settings.eventsGroupCalenderBAge) { 1885 self.tags = json; 1886 1887 $.each(json, function (index, val) { 1888 var lcName = val.name.toLowerCase(); 1889 var checked = self.settings.types.indexOf(lcName) >= 0 ? 'checked="checked"' : ''; 1890 if (self.settings.excludedTypes.length > 0) { 1891 checked = self.settings.excludedTypes.indexOf(lcName) >= 0 ? '' : 'checked="checked"'; 1892 } 1893 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>'); 1894 self._genColumn(item, index, self.typeList, index === (json.length - 1)); 1895 }); 1896 } else { 1897 self.tags = {}; 1898 1899 $.each(json, function (index, val) { 1900 if (!val.colour) { 1901 val.colour = self._genColour(val.name); 1902 } 1903 1904 self.tags[val.name] = val.colour; 1905 var lcName = val.name.toLowerCase(); 1906 var checked = ''; 1907 if (self.settings.types.length > 0) { 1908 checked = self.settings.types.indexOf(lcName) >= 0 ? 'checked="checked"' : ''; 1909 } else if (self.settings.excludedTypes.length > 0) { 1910 checked = self.settings.excludedTypes.indexOf(lcName) >= 0 ? '' : 'checked="checked"'; 1911 } else { 1912 //checked = 'checked="checked"'; 1913 } 1914 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>'); 1915 self._genColumn(item, index, self.typeList, index === (json.length - 1)); 1916 }); 1917 } 1918 1919 self.tagsLoaded = true; 1920 if (self.agesLoaded && self.locationsLoaded && self.tagsLoaded) self._update(); 1921 }); 1922 $.getJSON(this.settings.apiServer + '/v1/' + self.settings.client + '/eventsages', function (json, textStatus) { 1923 if (self.settings.eventsGroupCalenderBAge) { 1924 self.ages = {}; 1925 1926 $.each(json, function (index, val) { 1927 if (!val.colour) { 1928 val.colour = self._genColour(val.name); 1929 } 1930 1931 self.ages[val.name] = val.colour; 1932 var lcName = val.name.toLowerCase(); 1933 var checked = self.settings.ages.indexOf(lcName) >= 0 ? 'checked="checked"' : ''; 1934 if (self.settings.excludedAges.length > 0) { 1935 checked = self.settings.excludedAges.indexOf(lcName) >= 0 ? '' : 'checked="checked"'; 1936 } 1937 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>'); 1938 self._genColumn(item, index, self.ageList, index === (json.length - 1)); 1939 }); 1940 } else { 1941 self.ages = json; 1942 1943 $.each(json, function (index, val) { 1944 var lcName = val.name.toLowerCase(); 1945 var checked = self.settings.ages.indexOf(lcName) >= 0 ? 'checked="checked"' : ''; 1946 if (self.settings.excludedAges.length > 0) { 1947 checked = self.settings.excludedAges.indexOf(lcName) >= 0 ? '' : 'checked="checked"'; 1948 } 1949 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>'); 1950 self._genColumn(item, index, self.ageList, index === (json.length - 1)); 1951 }); 1952 } 1953 self.agesLoaded = true; 1954 if (self.agesLoaded && self.locationsLoaded && self.tagsLoaded) self._update(); 1955 }); 1956 } 1957 }); 1958 1959 $.fn[pluginName] = function (options) { 1960 return this.each(function () { 1961 if (!$.data(this, "plugin_" + pluginName)) { 1962 $.data(this, "plugin_" + pluginName, new Plugin(this, options)); 1963 } 1964 }); 1965 }; 1966})(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.