1(function( $, globals ) { 2 'use strict'; 3 4 function TeamstuffCalendar(widget) { 5 this.widget = widget; 6 this.template = widget.children('.ts-calendar-row.hidden').clone().removeClass('hidden'); // create a visible copy of the row template for use later 7 this.eventRows = widget.children('#ts-calendar-event-rows'); 8 this.locale = widget.children('#ts-calendar-locale').val(); 9 this.url = widget.children('#ts-calendar-rest-url').val(); 10 this.teamName = widget.find("#ts-calendar-team-name").text(); 11 this.cache = {}; 12 this.cacheRefreshMs = 1000*60; // data is valid for 1 minute 13 } 14 15 TeamstuffCalendar.getEventState = function(startTime, nowTime, durationMs) { 16 var state = "future"; 17 18 var startTimeMs = startTime.valueOf(); 19 var nowTimeMs = nowTime.valueOf(); 20 var endTimeMs = startTimeMs + durationMs; 21 if(nowTimeMs >= startTimeMs) { 22 if(nowTimeMs > endTimeMs) { 23 state = "past"; 24 } else { 25 state = "current"; 26 } 27 } 28 return state; 29 }; 30 31 TeamstuffCalendar.createRow = function(template, rowData, locale, now) { 32 var row = template.clone(); 33 34 if(rowData.bye) { 35 // Add styling for a bye 36 row.addClass('ts-calendar-row-bye'); 37 38 // Remove relevant contents 39 row.find("#ts-calendar-time").parent().html('BYE'); 40 row.find("#ts-calendar-team-us").parent().html(rowData.team.name); 41 row.find("#ts-calendar-location").parent().html(''); 42 row.find("#ts-calendar-score-win").parent().html(''); 43 } 44 else { 45 46 // get times into UTC 47 var time = moment(rowData.whistle_time).utc(); 48 var now = moment(now).utc(); 49 50 var eventState = TeamstuffCalendar.getEventState(time, now, rowData.duration_in_seconds * 1000); 51 var showTime = true; 52 switch(eventState) { 53 case "future": 54 row.addClass('ts-calendar-row-future'); 55 break; 56 case "current": 57 row.addClass('ts-calendar-row-current'); 58 row.find("#ts-calendar-time-now").removeClass('hidden'); 59 // remove the elements related to time 60 row.find("#ts-calendar-time").remove(); 61 row.find("#ts-calendar-time-suffix").remove(); 62 row.find("#ts-calendar-time-user").remove(); 63 row.find("#ts-calendar-time-suffix-user").remove(); 64 break; 65 case "past": 66 row.addClass('ts-calendar-row-past'); 67 break; 68 } 69 70 // game time in the timezone it's being played in (so display as UTC) 71 var timeStringSplit = time.format('LT').split(' '); 72 row.find("#ts-calendar-time").text(timeStringSplit[0]); 73 if(timeStringSplit.length > 1) { 74 row.find('#ts-calendar-time-suffix').text(timeStringSplit[1]); 75 } 76 row.find("#ts-calendar-date").text(time.format('D MMM YYYY')); 77 78 // game time in the viewer's timezone -- if it's different 79 var userOffset = moment().utcOffset(); 80 var gameOffset = rowData.timezone_offset / 60; 81 if(gameOffset != userOffset && eventState == "future") { 82 row.find('.ts-calendar-time-user-container').removeClass('hidden'); 83 84 var effectiveOffset = userOffset - gameOffset; 85 var userTime = time.clone().utcOffset(effectiveOffset); 86 87 timeStringSplit = userTime.format('LT').split(' '); 88 row.find("#ts-calendar-time-user").text(timeStringSplit[0]); 89 if(timeStringSplit.length > 1) { 90 row.find('#ts-calendar-time-suffix-user').text(timeStringSplit[1]); 91 } 92 93 // display the date as well if it is different 94 if(userTime.day() != time.day()) { 95 row.find("#ts-calendar-date-user").text(userTime.format('D MMM YYYY')); 96 } 97 } 98 99 // apply teams 100 row.find("#ts-calendar-team-us").text(rowData.team.name); 101 row.find("#ts-calendar-team-them").text(rowData.opposition); 102 103 // apply location and home/away 104 var locationText = rowData.location_name; 105 if(locationText == null || locationText.length < 1) locationText = rowData.address; 106 107 row.find("#ts-calendar-location").text(locationText); 108 if(rowData.away_game) { 109 row.find('#ts-calendar-homeaway').addClass('ts-calendar-away').text('A'); 110 } else { 111 row.find('#ts-calendar-homeaway').addClass('ts-calendar-home').text('H'); 112 } 113 114 // apply map link 115 var mapLink = encodeURIComponent(rowData.address) + "/@" + encodeURIComponent(rowData.location_data); 116 row.find('#ts-calendar-maplink').click(function(e) { 117 window.open("https://www.google.com.au/maps/place/" + mapLink); 118 e.preventDefault(); 119 }); 120 121 // apply scores 122 if(row.find('#ts-calendar-score-us').length > 0) { // if displaying scores is enabled in the plugin
123 if(rowData.our_score === null || rowData.their_score === null) { 124 row.find("#ts-calendar-score-us").parent().html(""); // clear the score column (to remove the colon) 125 } else { 126 row.find("#ts-calendar-score-us").text(rowData.our_score); 127 row.find("#ts-calendar-score-them").text(rowData.their_score); 128 } 129 } 130 131 // apply win indicator if relevant 132 if(rowData.result == 'win') { 133 row.find('#ts-calendar-score-win').removeClass('hidden'); 134 } 135 } 136 137 return row; 138 }; 139 140 TeamstuffCalendar.getCacheKey = function(date, direction) { 141 return moment(date).utc().format('DD/MM/YY') + direction; 142 }; 143 144 TeamstuffCalendar.prototype.getTeamGames = function(startDate, endDate, teamName) { 145 // perform request to load the data 146 var params = { startDate: '0000-01-01' }; // workaround because endpoint without either parameters only gives future games 147 if(startDate) { 148 startDate = moment(startDate); 149 params['startDate'] = startDate.format('YYYY-MM-DD'); 150 } 151 if(endDate) { 152 endDate = moment(endDate); 153 params['endDate'] = endDate.format('YYYY-MM-DD'); 154 } 155 var req = $.getJSON(this.url + '/events-range', params) 156 .done(function(data) { 157 // filter the games by the team 158 data.games = data.games.filter(function(game) { 159 return game.team.name == teamName; 160 }); 161 162 // sort the games 163 data.games.sort(function(a, b) { 164 if(a.whistle_time == "") { return 1; } 165 if(b.whistle_time == "") { return -1; } 166 return Date.parse(a.whistle_time) - Date.parse(b.whistle_time); 167 }); 168 }); 169 170 return req; 171 }; 172 173 TeamstuffCalendar.prototype.getDateGames = function(date, direction) { 174 // check the cache 175 var cacheKey = TeamstuffCalendar.getCacheKey(date, direction); 176 var cacheEntry = this.cache[cacheKey]; 177 var promise; 178 if(cacheEntry && cacheEntry.retrieved + this.cacheRefreshMs > Date.now()) { 179 // wrap cache data in a promise 180 var deferred = $.Deferred() 181 deferred.resolve(cacheEntry.data); 182 promise = deferred.promise(); 183 } else { 184 var self = this; 185 // trigger request to retrieve data from API 186 var params = { date: moment(date).format('YYYY-MM-DD') }; 187 if(direction) { 188 params.direction = direction; 189 } 190 promise = jQuery.getJSON(this.url + '/events', params) 191 .done(function(data) { 192 // sort the games 193 data.games.sort(function(a, b) { 194 if(a.whistle_time == "") { return 1; } 195 if(b.whistle_time == "") { return -1; } 196 return Date.parse(a.whistle_time) - Date.parse(b.whistle_time); 197 }); 198 199 // update the cache 200 self.cache[cacheKey] = { retrieved: Date.now(), data: data }; 201 }); 202 } 203 204 return promise; 205 }; 206 207 TeamstuffCalendar.prototype.loadTeam = function(startDate, endDate) { 208 // based on startDate and endDate, make one of the date range labels visible 209 var dateRange; 210 if(startDate && endDate) { 211 dateRange = this.widget.find("#ts-calendar-date-range"); 212 } else if(startDate) { 213 dateRange = this.widget.find("#ts-calendar-date-range-from"); 214 } else if(endDate) { 215 dateRange = this.widget.find("#ts-calendar-date-range-to"); 216 } else { 217 dateRange = this.widget.find("#ts-calendar-date-range-all"); 218 } 219 dateRange.removeClass('hidden'); 220 221 // set the date range indicators 222 if(startDate) { 223 startDate = moment(startDate).utc().locale(this.locale); 224 dateRange.find("#ts-calendar-date-from").text(startDate.format('D MMM YYYY')); 225 } 226 if(endDate) { 227 endDate = moment(endDate).utc().locale(this.locale); 228 dateRange.find("#ts-calendar-date-to").text(endDate.format('D MMM YYYY')); 229 } 230 231 // perform request to load the data 232 var self = this; 233 var req = this.getTeamGames(startDate, endDate, this.teamName) 234 .done(function(data) { 235 // hide the loading row 236 self.widget.children('#ts-calendar-loading-row').addClass('hidden'); 237 238 // clear the old rows 239 self.eventRows.empty(); 240 self.eventRows.removeClass('hidden'); 241 242 // update views with event data or display empty row 243 if(data.games.length == 0) { 244 self.widget.children('#ts-calendar-empty-row').removeClass('hidden'); 245 } else { 246 self.populateRows(data); 247 } 248 }) 249 .fail(function(err) { 250 self.widget.children('#ts-calendar-error-row').removeClass('hidden'); 251 }) 252 .always(function() { 253 self.widget.children('#ts-calendar-loading-row').addClass('hidden'); 254 }); 255 } 256 257 TeamstuffCalendar.prototype.preloadDate = function(date) { 258 // create container for preload requests if need be 259 this.requestPreload = this.requestPreload || {}; 260 261 var directions = [ 'next', 'previous']; 262 var self = this; 263 $.each(directions, function(i, direction) { 264 // if we have a current preloading request for this direction, abort it 265 if(self.requestPreload[direction] && self.requestPreload[direction].abort) 266 self.requestPreload[direction].abort(); 267 268 self.requestPreload[direction] = self.getDateGames(date, direction) 269 .always(function() { 270 self.requestPreload[direction] = null; 271 }) 272 .done(function(data) { 273 // if we preload but get no games (no more events in that direction) 274 if(data.games.length == 0) { 275 // disable the appropriate arrow 276 if(direction == 'previous') 277 self.widget.find('#ts-calendar-date-prev').addClass('hidden'); 278 else if(direction == 'next') 279 self.widget.find('#ts-calendar-date-next').addClass('hidden'); 280 } 281 }); 282 }); 283 }; 284 285 TeamstuffCalendar.prototype.changeDate = function(currDate, direction) { 286 // if a request exists (that is actually a request -- has .abort), abort it 287 if(this.request && this.request.abort) 288 this.request.abort(); 289 290 // hide the old events 291 this.eventRows.addClass('hidden'); 292 293 // hide the error row 294 this.widget.children('#ts-calendar-error-row').addClass('hidden'); 295 // hide the empty row 296 this.widget.children('#ts-calendar-empty-row').addClass('hidden'); 297 298 // display the loading row and the direction buttons 299 this.widget.children('#ts-calendar-loading-row').removeClass('hidden'); 300 this.widget.find('#ts-calendar-date-prev').removeClass('hidden'); 301 this.widget.find('#ts-calendar-date-next').removeClass('hidden'); 302 303 var self = this; 304 this.request = this.getDateGames(currDate, direction) 305 .fail(function(err) { 306 // display the error row 307 self.widget.children('#ts-calendar-error-row').removeClass('hidden'); 308 }) 309 .always(function() { 310 self.widget.children('#ts-calendar-loading-row').addClass('hidden'); 311 self.request = null; 312 }) 313 .done(function(data) { 314 315 if(!data || !data.games) { 316 // display the error row 317 self.widget.children('#ts-calendar-error-row').removeClass('hidden'); 318 } else { 319 320 // make sure the navigation arrows are visible 321 self.widget.find('#ts-calendar-date-prev').removeClass('hidden'); 322 self.widget.find('#ts-calendar-date-next').removeClass('hidden'); 323 324 // extract the date from the data (data used by the calendar is UTC) 325 var newDate = moment(data.current_date).utc().locale(self.locale); 326 self.date = newDate; 327 328 // trigger fetching of previous/next from this new date 329 self.preloadDate(newDate); 330 331 // update the header date and year 332 self.widget.find('#ts-calendar-date').text(newDate.format('dddd D MMMM')); 333 self.widget.find('#ts-calendar-year').text(newDate.format('YYYY')); 334 335 // if we tried to change date but got no more games (no more events) 336 if(direction != null && data.games.length == 0) { 337 // disable the appropriate arrow 338 if(direction == 'previous') 339 self.widget.find('#ts-calendar-date-prev').addClass('hidden'); 340 else if(direction == 'next') 341 self.widget.find('#ts-calendar-date-next').addClass('hidden'); 342 343 // re-display the existing events for this date 344 self.eventRows.removeClass('hidden'); 345 } else { 346 // clear the old rows 347 self.eventRows.empty(); 348 self.eventRows.removeClass('hidden'); 349 350 // update views with event data or display empty row 351 if(data.games.length == 0) { 352 self.widget.children('#ts-calendar-empty-row').removeClass('hidden'); 353 } else { 354 self.populateRows(data); 355 } 356 } 357 } 358 }); 359 }; 360 361 TeamstuffCalendar.prevDate = function(e) { 362 this.changeDate(this.date, 'previous'); 363 e.preventDefault(); 364 }; 365 366 TeamstuffCalendar.nextDate = function(e) { 367 this.changeDate(this.date, 'next'); 368 e.preventDefault(); 369 }; 370 371 TeamstuffCalendar.prototype.populateRows = function(events) { 372 var self = this; 373 var now = Date.now() 374 $.each(events.games, function() { 375 var newRow = TeamstuffCalendar.createRow(self.template, this, self.locale, now); 376 self.eventRows.append(newRow); 377 }); 378 }; 379 380 TeamstuffCalendar.initialise = function(widget) { 381 var ts = new TeamstuffCalendar(widget); 382 383 if(ts.teamName != "") { 384 var fromDate = moment(widget.find("#ts-calendar-param-date-from").val()); 385 var toDate = moment(widget.find("#ts-calendar-param-date-to").val()); 386 ts.loadTeam( 387 fromDate.isValid() ? fromDate : null, 388 toDate.isValid() ? toDate : null 389 ); 390 } else { 391 // attach click handlers to prev/next 392 widget.find('#ts-calendar-date-prev').click(TeamstuffCalendar.prevDate.bind(ts)); 393 widget.find('#ts-calendar-date-next').click(TeamstuffCalendar.nextDate.bind(ts)); 394 395 // initialise calendar with the current date 396 var now = new Date(); 397 ts.changeDate(now); 398 } 399 }; 400 401 globals.TeamstuffCalendar = TeamstuffCalendar; 402})( jQuery, function() {return this;}.call() );
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.