vendor: 1,173 bytes, lines 1-48
1(function($) { 2 3 var useWindow = window; 4 5 /* From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys */ 6 if (!Object.keys) { 7 Object.keys = (function() { 8 'use strict'; 9 var hasOwnProperty = Object.prototype.hasOwnProperty, 10 hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), 11 dontEnums = [ 12 'toString', 13 'toLocaleString', 14 'valueOf', 15 'hasOwnProperty', 16 'isPrototypeOf', 17 'propertyIsEnumerable', 18 'constructor' 19 ], 20 dontEnumsLength = dontEnums.length; 21 22 return function(obj) { 23 if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { 24 throw new TypeError('Object.keys called on non-object'); 25 } 26 27 var result = [], prop, i; 28 29 for (prop in obj) { 30 if (hasOwnProperty.call(obj, prop)) { 31 result.push(prop); 32 } 33 } 34 35 if (hasDontEnumBug) { 36 for (i = 0; i < dontEnumsLength; i++) { 37 if (hasOwnProperty.call(obj, dontEnums[i])) { 38 result.push(dontEnums[i]); 39 } 40 } 41 } 42 return result; 43 }; 44 }()); 45 } 46 47 /* Used to disable some features on IE8 */ 48 var limited_mode = false;
49 var tick_duration = 200; // in ms 50 51 var debug = (location.hash === "#debug"); 52 function debug_log(msg) { 53 if (debug) { 54 console.log(msg); 55 } 56 } 57 58 var allUnits = ["Days", "Hours", "Minutes", "Seconds"]; 59 var nextUnits = { 60 Seconds: "Minutes", 61 Minutes: "Hours", 62 Hours: "Days", 63 Days: "Years" 64 }; 65 var secondsIn = { 66 Seconds: 1, 67 Minutes: 60, 68 Hours: 3600, 69 Days: 86400, 70 Months: 2678400, 71 Years: 31536000 72 }; 73 74 /** 75 * Converts hex color code into object containing integer values for the r,g,b use 76 * This function (hexToRgb) originates from: 77 * http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb 78 * @param {string} hex color code 79 */ 80 function hexToRgb(hex) { 81 // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") 82 var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; 83 hex = hex.replace(shorthandRegex, function(m, r, g, b) { 84 return r + r + g + g + b + b; 85 }); 86 87 var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 88 return result ? { 89 r: parseInt(result[1], 16), 90 g: parseInt(result[2], 16), 91 b: parseInt(result[3], 16) 92 } : null; 93 } 94 95 function isCanvasSupported() { 96 var elem = document.createElement('canvas'); 97 return !!(elem.getContext && elem.getContext('2d')); 98 } 99 100 /** 101 * Function s4() and guid() originate from: 102 * http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript 103 */ 104 function s4() { 105 return Math.floor((1 + Math.random()) * 0x10000) 106 .toString(16) 107 .substring(1); 108 } 109 110 /** 111 * Creates a unique id 112 * @returns {String} 113 */ 114 function guid() { 115 return s4() + s4() + '-' + s4() + '-' + s4() + '-' + 116 s4() + '-' + s4() + s4() + s4(); 117 } 118 119 /** 120 * Array.prototype.indexOf fallback for IE8 121 * @param {Mixed} mixed 122 * @returns {Number} 123 */ 124 if (!Array.prototype.indexOf) { 125 Array.prototype.indexOf = function(elt /*, from*/) 126 { 127 var len = this.length >>> 0; 128 129 var from = Number(arguments[1]) || 0; 130 from = (from < 0) 131 ? Math.ceil(from) 132 : Math.floor(from); 133 if (from < 0) 134 from += len; 135 136 for (; from < len; from++) 137 { 138 if (from in this && 139 this[from] === elt) 140 return from; 141 } 142 return -1; 143 }; 144 } 145 146 function parse_date(str) { 147 var match = str.match(/^[0-9]{4}-[0-9]{2}-[0-9]{2}\s[0-9]{1,2}:[0-9]{2}:[0-9]{2}$/); 148 if (match !== null && match.length > 0) { 149 var parts = str.split(" "); 150 var date = parts[0].split("-"); 151 var time = parts[1].split(":"); 152 return new Date(date[0], date[1] - 1, date[2], time[0], time[1], time[2]); 153 } 154 /* Fallback for different date formats */ 155 var d = Date.parse(str); 156 if (!isNaN(d)) 157 return d; 158 d = Date.parse(str.replace(/-/g, '/').replace('T', ' ')); 159 if (!isNaN(d)) 160 return d; 161 /* Cant find anything */ 162 return new Date(); 163 } 164 165 function parse_times(diff, old_diff, total_duration, units, floor) { 166 var raw_time = {}; 167 var raw_old_time = {}; 168 var time = {}; 169 var pct = {}; 170 var old_pct = {}; 171 var old_time = {}; 172 173 var greater_unit = null; 174 for(var i = 0; i < units.length; i++) { 175 var unit = units[i]; 176 var maxUnits; 177 178 if (greater_unit === null) { 179 maxUnits = total_duration / secondsIn[unit]; 180 } 181 else { 182 maxUnits = secondsIn[greater_unit] / secondsIn[unit]; 183 } 184 185 var curUnits = (diff / secondsIn[unit]); 186 var oldUnits = (old_diff / secondsIn[unit]); 187 188 if(floor) { 189 if(curUnits > 0) curUnits = Math.floor(curUnits); 190 else curUnits = Math.ceil(curUnits); 191 if(oldUnits > 0) oldUnits = Math.floor(oldUnits); 192 else oldUnits = Math.ceil(oldUnits); 193 } 194 195 if (unit !== "Days") { 196 curUnits = curUnits % maxUnits; 197 oldUnits = oldUnits % maxUnits; 198 } 199 200 raw_time[unit] = curUnits; 201 time[unit] = Math.abs(curUnits); 202 raw_old_time[unit] = oldUnits; 203 old_time[unit] = Math.abs(oldUnits); 204 pct[unit] = Math.abs(curUnits) / maxUnits; 205 old_pct[unit] = Math.abs(oldUnits) / maxUnits; 206 207 greater_unit = unit; 208 } 209 210 return { 211 raw_time: raw_time, 212 raw_old_time: raw_old_time, 213 time: time, 214 old_time: old_time, 215 pct: pct, 216 old_pct: old_pct 217 }; 218 } 219 220 var TC_Instance_List = {}; 221 function updateUsedWindow() { 222 if(typeof useWindow.TC_Instance_List !== "undefined") {
223 TC_Instance_List = useWindow.TC_Instance_List; 224 } 225 else { 226 useWindow.TC_Instance_List = TC_Instance_List; 227 } 228 initializeAnimationFrameHandler(useWindow); 229 }; 230 231 function initializeAnimationFrameHandler(w) { 232 var vendors = ['webkit', 'moz']; 233 for (var x = 0; x < vendors.length && !w.requestAnimationFrame; ++x) { 234 w.requestAnimationFrame = w[vendors[x] + 'RequestAnimationFrame']; 235 w.cancelAnimationFrame = w[vendors[x] + 'CancelAnimationFrame']; 236 } 237 238 if (!w.requestAnimationFrame || !w.cancelAnimationFrame) { 239 w.requestAnimationFrame = function(callback, element, instance) { 240 if (typeof instance === "undefined") 241 instance = {data: {last_frame: 0}}; 242 var currTime = new Date().getTime(); 243 var timeToCall = Math.max(0, 16 - (currTime - instance.data.last_frame)); 244 var id = w.setTimeout(function() { 245 callback(currTime + timeToCall); 246 }, timeToCall); 247 instance.data.last_frame = currTime + timeToCall; 248 return id; 249 }; 250 w.cancelAnimationFrame = function(id) { 251 clearTimeout(id); 252 }; 253 } 254 }; 255 256 var TC_Instance = function(element, options) { 257 this.element = element; 258 this.container; 259 this.listeners = null; 260 this.data = { 261 paused: false, 262 last_frame: 0, 263 animation_frame: null, 264 interval_fallback: null, 265 timer: false, 266 total_duration: null, 267 prev_time: null, 268 drawn_units: [], 269 text_elements: { 270 Days: null, 271 Hours: null, 272 Minutes: null, 273 Seconds: null 274 }, 275 attributes: { 276 canvas: null, 277 context: null, 278 item_size: null, 279 line_width: null, 280 radius: null, 281 outer_radius: null 282 }, 283 state: { 284 fading: { 285 Days: false, 286 Hours: false, 287 Minutes: false, 288 Seconds: false 289 } 290 } 291 }; 292 293 this.config = null; 294 this.setOptions(options); 295 this.initialize(); 296 }; 297 298 TC_Instance.prototype.clearListeners = function() { 299 this.listeners = { all: [], visible: [] }; 300 }; 301 302 TC_Instance.prototype.addTime = function(seconds_to_add) { 303 if(this.data.attributes.ref_date instanceof Date) { 304 var d = this.data.attributes.ref_date; 305 d.setSeconds(d.getSeconds() + seconds_to_add); 306 } 307 else if(!isNaN(this.data.attributes.ref_date)) { 308 this.data.attributes.ref_date += (seconds_to_add * 1000); 309 } 310 }; 311 312 TC_Instance.prototype.initialize = function(clear_listeners) { 313 /* Initialize drawn units */ 314 this.data.drawn_units = []; 315 for(var i = 0; i < Object.keys(this.config.time).length; i++) { 316 var unit = Object.keys(this.config.time)[i]; 317 if (this.config.time[unit].show) { 318 this.data.drawn_units.push(unit); 319 } 320 } 321 322 /* Avoid stacking */ 323 $(this.element).children('div.time_circles').remove(); 324 325 if (typeof clear_listeners === "undefined") 326 clear_listeners = true; 327 if (clear_listeners || this.listeners === null) { 328 this.clearListeners(); 329 } 330 this.container = $("<div>"); 331 this.container.addClass('time_circles'); 332 this.container.appendTo(this.element); 333 334 /* Determine the needed width and height of TimeCircles */ 335 var height = this.element.offsetHeight; 336 var width = this.element.offsetWidth; 337 if (height === 0) 338 height = $(this.element).height(); 339 if (width === 0) 340 width = $(this.element).width(); 341 342 if (height === 0 && width > 0) 343 height = width / this.data.drawn_units.length; 344 else if (width === 0 && height > 0) 345 width = height * this.data.drawn_units.length; 346 347 /* Create our canvas and set it to the appropriate size */ 348 var canvasElement = document.createElement('canvas'); 349 canvasElement.width = width; 350 canvasElement.height = height; 351 352 /* Add canvas elements */ 353 this.data.attributes.canvas = $(canvasElement); 354 this.data.attributes.canvas.appendTo(this.container); 355 356 /* Check if the browser has browser support */ 357 var canvasSupported = isCanvasSupported(); 358 /* If the browser doesn't have browser support, check if explorer canvas is loaded */ 359 /* (A javascript library that adds canvas support to browsers that don't have it) */ 360 if(!canvasSupported && typeof G_vmlCanvasManager !== "undefined") { 361 G_vmlCanvasManager.initElement(canvasElement); 362 limited_mode = true; 363 canvasSupported = true; 364 } 365 if(canvasSupported) { 366 this.data.attributes.context = canvasElement.getContext('2d'); 367 } 368 369 this.data.attributes.item_size = Math.min(width / this.data.drawn_units.length, height); 370 this.data.attributes.line_width = this.data.attributes.item_size * this.config.fg_width; 371 this.data.attributes.radius = ((this.data.attributes.item_size * 0.8) - this.data.attributes.line_width) / 2; 372 this.data.attributes.outer_radius = this.data.attributes.radius + 0.5 * Math.max(this.data.attributes.line_width, this.data.attributes.line_width * this.config.bg_width); 373 374 /* Prepare Time Elements */ 375 var i = 0; 376 for (var key in this.data.text_elements) { 377 if (!this.config.time[key].show) 378 continue; 379 380 var textElement = $("<div>"); 381 textElement.addClass('textDiv_' + key); 382 textElement.css("top", Math.round(0.35 * this.data.attributes.item_size)); 383 textElement.css("left", Math.round(i++ * this.data.attributes.item_size)); 384 textElement.css("width", this.data.attributes.item_size); 385 textElement.appendTo(this.container); 386 387 var headerElement = $("<h4>"); 388 headerElement.text(this.config.time[key].text); /* Options */ 389 headerElement.css("font-size", Math.round(this.config.text_size * this.data.attributes.item_size)); 390 headerElement.css("line-height", Math.round(this.config.text_size * this.data.attributes.item_size) + "px"); 391 headerElement.appendTo(textElement); 392 393 var numberElement = $("<span>"); 394 numberElement.css("font-size", Math.round(3 * this.config.text_size * this.data.attributes.item_size)); 395 numberElement.css("line-height", Math.round(this.config.text_size * this.data.attributes.item_size) + "px"); 396 numberElement.appendTo(textElement); 397 398 this.data.text_elements[key] = numberElement; 399 } 400 401 this.start(); 402 if (!this.config.start) { 403 this.data.paused = true; 404 } 405
406 /* Set up interval fallback */ 407 var _this = this; 408 this.data.interval_fallback = useWindow.setInterval(function(){ 409 _this.update.call(_this, true); 410 }, 100); 411 }; 412 413 TC_Instance.prototype.update = function(nodraw) { 414 if(typeof nodraw === "undefined") { 415 nodraw = false; 416 } 417 else if(nodraw && this.data.paused) { 418 return; 419 } 420 421 if(limited_mode) { 422 /* Per unit clearing doesn't work in IE8 using explorer canvas, so do it in one time. The downside is that radial fade cant be used */ 423 this.data.attributes.context.clearRect(0, 0, this.data.attributes.canvas[0].width, this.data.attributes.canvas[0].hright); 424 } 425 var diff, old_diff; 426 427 var prevDate = this.data.prev_time; 428 var curDate = new Date(); 429 this.data.prev_time = curDate; 430 431 if (prevDate === null) 432 prevDate = curDate; 433 434 /* If not counting past zero, and time < 0, then simply draw the zero point once, and call stop */ 435 if (!this.config.count_past_zero) { 436 if (curDate > this.data.attributes.ref_date) { 437 for(var i = 0; i < this.data.drawn_units.length; i++) { 438 var key = this.data.drawn_units[i]; 439 440 /* Set the text value */ 441 this.data.text_elements[key].text("0"); 442 var x = (i * this.data.attributes.item_size) + (this.data.attributes.item_size / 2); 443 var y = this.data.attributes.item_size / 2; 444 var color = this.config.time[key].color; 445 this.drawArc(x, y, color, 0); 446 } 447 this.stop(); 448 return; 449 } 450 } 451 452 /* Compare current time with reference */ 453 diff = (this.data.attributes.ref_date - curDate) / 1000; 454 old_diff = (this.data.attributes.ref_date - prevDate) / 1000; 455 456 var floor = this.config.animation !== "smooth"; 457 458 var visible_times = parse_times(diff, old_diff, this.data.total_duration, this.data.drawn_units, floor); 459 var all_times = parse_times(diff, old_diff, secondsIn["Years"], allUnits, floor); 460 461 var i = 0; 462 var j = 0; 463 var lastKey = null; 464 465 var cur_shown = this.data.drawn_units.slice(); 466 for (var i in allUnits) { 467 var key = allUnits[i]; 468 469 /* Notify (all) listeners */ 470 if (Math.floor(all_times.raw_time[key]) !== Math.floor(all_times.raw_old_time[key])) { 471 this.notifyListeners(key, Math.floor(all_times.time[key]), Math.floor(diff), "all"); 472 } 473 474 if (cur_shown.indexOf(key) < 0) 475 continue; 476 477 /* Notify (visible) listeners */ 478 if (Math.floor(visible_times.raw_time[key]) !== Math.floor(visible_times.raw_old_time[key])) { 479 this.notifyListeners(key, Math.floor(visible_times.time[key]), Math.floor(diff), "visible"); 480 } 481 482 if(!nodraw) { 483 /* Set the text value */ 484 this.data.text_elements[key].text(Math.floor(Math.abs(visible_times.time[key]))); 485 486 var x = (j * this.data.attributes.item_size) + (this.data.attributes.item_size / 2); 487 var y = this.data.attributes.item_size / 2; 488 var color = this.config.time[key].color; 489 490 if (this.config.animation === "smooth") { 491 if (lastKey !== null && !limited_mode) { 492 if (Math.floor(visible_times.time[lastKey]) > Math.floor(visible_times.old_time[lastKey])) { 493 this.radialFade(x, y, color, 1, key); 494 this.data.state.fading[key] = true; 495 } 496 else if (Math.floor(visible_times.time[lastKey]) < Math.floor(visible_times.old_time[lastKey])) { 497 this.radialFade(x, y, color, 0, key); 498 this.data.state.fading[key] = true; 499 } 500 } 501 if (!this.data.state.fading[key]) { 502 this.drawArc(x, y, color, visible_times.pct[key]); 503 } 504 } 505 else { 506 this.animateArc(x, y, color, visible_times.pct[key], visible_times.old_pct[key], (new Date()).getTime() + tick_duration); 507 } 508 } 509 lastKey = key; 510 j++; 511 } 512 513 /* Dont request another update if we should be paused */ 514 if(this.data.paused || nodraw) { 515 return; 516 } 517 518 /* We need this for our next frame either way */ 519 var _this = this; 520 var update = function() { 521 _this.update.call(_this); 522 }; 523 524 /* Either call next update immediately, or in a second */ 525 if (this.config.animation === "smooth") { 526 /* Smooth animation, Queue up the next frame */ 527 this.data.animation_frame = useWindow.requestAnimationFrame(update, _this.element, _this); 528 } 529 else { 530 /* Tick animation, Don't queue until very slightly after the next second happens */
531 var delay = (diff % 1) * 1000; 532 if (delay < 0) 533 delay = 1000 + delay; 534 delay += 50; 535 536 _this.data.animation_frame = useWindow.setTimeout(function() { 537 _this.data.animation_frame = useWindow.requestAnimationFrame(update, _this.element, _this); 538 }, delay); 539 } 540 }; 541 542 TC_Instance.prototype.animateArc = function(x, y, color, target_pct, cur_pct, animation_end) { 543 if (this.data.attributes.context === null) 544 return; 545 546 var diff = cur_pct - target_pct; 547 if (Math.abs(diff) > 0.5) { 548 if (target_pct === 0) { 549 this.radialFade(x, y, color, 1); 550 } 551 else { 552 this.radialFade(x, y, color, 0); 553 } 554 } 555 else { 556 var progress = (tick_duration - (animation_end - (new Date()).getTime())) / tick_duration; 557 if (progress > 1) 558 progress = 1; 559 560 var pct = (cur_pct * (1 - progress)) + (target_pct * progress); 561 this.drawArc(x, y, color, pct); 562 563 /*var show_pct = */ 564 if (progress >= 1) 565 return; 566 var _this = this; 567 useWindow.requestAnimationFrame(function() { 568 _this.animateArc(x, y, color, target_pct, cur_pct, animation_end); 569 }, this.element); 570 } 571 }; 572 573 TC_Instance.prototype.drawArc = function(x, y, color, pct) { 574 if (this.data.attributes.context === null) 575 return; 576 577 var clear_radius = Math.max(this.data.attributes.outer_radius, this.data.attributes.item_size / 2); 578 if(!limited_mode) { 579 this.data.attributes.context.clearRect( 580 x - clear_radius, 581 y - clear_radius, 582 clear_radius * 2, 583 clear_radius * 2 584 ); 585 } 586 587 if (this.config.use_background) { 588 this.data.attributes.context.beginPath(); 589 this.data.attributes.context.arc(x, y, this.data.attributes.radius, 0, 2 * Math.PI, false); 590 this.data.attributes.context.lineWidth = this.data.attributes.line_width * this.config.bg_width; 591 592 /* line color */ 593 this.data.attributes.context.strokeStyle = this.config.circle_bg_color; 594 this.data.attributes.context.stroke(); 595 } 596 597 /* Direction */ 598 var startAngle, endAngle, counterClockwise; 599 var defaultOffset = (-0.5 * Math.PI); 600 var fullCircle = 2 * Math.PI; 601 startAngle = defaultOffset + (this.config.start_angle / 360 * fullCircle); 602 var offset = (2 * pct * Math.PI); 603 604 if (this.config.direction === "Both") { 605 counterClockwise = false; 606 startAngle -= (offset / 2); 607 endAngle = startAngle + offset; 608 } 609 else { 610 if (this.config.direction === "Clockwise") { 611 counterClockwise = false; 612 endAngle = startAngle + offset; 613 } 614 else { 615 counterClockwise = true; 616 endAngle = startAngle - offset; 617 } 618 } 619 620 this.data.attributes.context.beginPath(); 621 this.data.attributes.context.arc(x, y, this.data.attributes.radius, startAngle, endAngle, counterClockwise); 622 this.data.attributes.context.lineWidth = this.data.attributes.line_width; 623 624 /* line color */ 625 this.data.attributes.context.strokeStyle = color; 626 this.data.attributes.context.stroke(); 627 }; 628 629 TC_Instance.prototype.radialFade = function(x, y, color, from, key) { 630 /* TODO: Make fade_time option */ 631 var rgb = hexToRgb(color); 632 var _this = this; /* We have a few inner scopes here that will need access to our instance */ 633 634 var step = 0.2 * ((from === 1) ? -1 : 1); 635 var i; 636 for (i = 0; from <= 1 && from >= 0; i++) { 637 /* Create inner scope so our variables are not changed by the time the Timeout triggers */ 638 (function() { 639 var delay = 50 * i; 640 var rgba = "rgba(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ", " + (Math.round(from * 10) / 10) + ")"; 641 useWindow.setTimeout(function() { 642 _this.drawArc(x, y, rgba, 1); 643 }, delay); 644 }()); 645 from += step; 646 } 647 if (typeof key !== undefined) { 648 useWindow.setTimeout(function() { 649 _this.data.state.fading[key] = false; 650 }, 50 * i); 651 } 652 }; 653 654 TC_Instance.prototype.timeLeft = function() { 655 if (this.data.paused && typeof this.data.timer === "number") { 656 return this.data.timer; 657 } 658 var now = new Date(); 659 return ((this.data.attributes.ref_date - now) / 1000); 660 }; 661 662 TC_Instance.prototype.start = function() { 663 useWindow.cancelAnimationFrame(this.data.animation_frame); 664 useWindow.clearTimeout(this.data.animation_frame) 665 666 /* Check if a date was passed in html attribute or jquery data */ 667 var attr_data_date = $(this.element).data('date'); 668 if (typeof attr_data_date === "undefined") { 669 attr_data_date = $(this.element).attr('data-date'); 670 } 671 if (typeof attr_data_date === "string") { 672 this.data.attributes.ref_date = parse_date(attr_data_date); 673 } 674 /* Check if this is an unpause of a timer */ 675 else if (typeof this.data.timer === "number") { 676 if (this.data.paused) { 677 this.data.attributes.ref_date = (new Date()).getTime() + (this.data.timer * 1000); 678 } 679 } 680 else { 681 /* Try to get data-timer */ 682 var attr_data_timer = $(this.element).data('timer'); 683 if (typeof attr_data_timer === "undefined") { 684 attr_data_timer = $(this.element).attr('data-timer'); 685 } 686 if (typeof attr_data_timer === "string") { 687 attr_data_timer = parseFloat(attr_data_timer); 688 } 689 if (typeof attr_data_timer === "number") { 690 this.data.timer = attr_data_timer; 691 this.data.attributes.ref_date = (new Date()).getTime() + (attr_data_timer * 1000); 692 } 693 else { 694 /* data-timer and data-date were both not set 695 use config date */ 696 this.data.attributes.ref_date = this.config.ref_date; 697 } 698 } 699
700 /* Start running */ 701 this.data.paused = false; 702 this.update.call(this); 703 }; 704 705 TC_Instance.prototype.restart = function() { 706 this.data.timer = false; 707 this.start(); 708 }; 709 710 TC_Instance.prototype.stop = function() { 711 if (typeof this.data.timer === "number") { 712 this.data.timer = this.timeLeft(this); 713 } 714 /* Stop running */ 715 this.data.paused = true; 716 useWindow.cancelAnimationFrame(this.data.animation_frame); 717 }; 718 719 TC_Instance.prototype.destroy = function() { 720 this.clearListeners(); 721 this.stop(); 722 useWindow.clearInterval(this.data.interval_fallback); 723 this.data.interval_fallback = null; 724 725 this.container.remove(); 726 $(this.element).removeAttr('data-tc-id'); 727 $(this.element).removeData('tc-id'); 728 }; 729 730 TC_Instance.prototype.setOptions = function(options) { 731 if (this.config === null) { 732 this.default_options.ref_date = new Date(); 733 this.config = $.extend(true, {}, this.default_options); 734 } 735 $.extend(true, this.config, options); 736 737 /* Use window.top if use_top_frame is true */ 738 if(this.config.use_top_frame) { 739 useWindow = window.top; 740 } 741 else { 742 useWindow = window; 743 } 744 updateUsedWindow(); 745 746 this.data.total_duration = this.config.total_duration; 747 if (typeof this.data.total_duration === "string") { 748 if (typeof secondsIn[this.data.total_duration] !== "undefined") { 749 /* If set to Years, Months, Days, Hours or Minutes, fetch the secondsIn value for that */ 750 this.data.total_duration = secondsIn[this.data.total_duration]; 751 } 752 else if (this.data.total_duration === "Auto") { 753 /* If set to auto, total_duration is the size of 1 unit, of the unit type bigger than the largest shown */ 754 for(var i = 0; i < Object.keys(this.config.time).length; i++) { 755 var unit = Object.keys(this.config.time)[i]; 756 if (this.config.time[unit].show) { 757 this.data.total_duration = secondsIn[nextUnits[unit]]; 758 break; 759 } 760 } 761 } 762 else { 763 /* If it's a string, but neither of the above, user screwed up. */ 764 this.data.total_duration = secondsIn["Years"]; 765 console.error("Valid values for TimeCircles config.total_duration are either numeric, or (string) Years, Months, Days, Hours, Minutes, Auto"); 766 } 767 } 768 }; 769 770 TC_Instance.prototype.addListener = function(f, context, type) { 771 if (typeof f !== "function") 772 return; 773 if (typeof type === "undefined") 774 type = "visible"; 775 this.listeners[type].push({func: f, scope: context}); 776 }; 777 778 TC_Instance.prototype.notifyListeners = function(unit, value, total, type) { 779 for (var i = 0; i < this.listeners[type].length; i++) { 780 var listener = this.listeners[type][i]; 781 listener.func.apply(listener.scope, [unit, value, total]); 782 } 783 }; 784 785 TC_Instance.prototype.default_options = { 786 ref_date: new Date(), 787 start: true, 788 animation: "smooth", 789 count_past_zero: true, 790 circle_bg_color: "#313332", 791 use_background: true, 792 fg_width: 0.1, 793 bg_width: 1.2, 794 text_size: 0.07, 795 total_duration: "Auto", 796 direction: "Clockwise", 797 use_top_frame: false, 798 start_angle: 0, 799 time: { 800 Days: { 801 show: true, 802 text: "Days", 803 color: "#e3be32" 804 }, 805 Hours: { 806 show: true, 807 text: "Hours", 808 color: "#36b0e3" 809 }, 810 Minutes: { 811 show: true, 812 text: "Minutes", 813 color: "#75bf44" 814 }, 815 Seconds: { 816 show: true, 817 text: "Seconds", 818 color: "#66c5af" 819 } 820 } 821 }; 822 823 /* Time circle class */ 824 var TC_Class = function(elements, options) { 825 this.elements = elements; 826 this.options = options; 827 this.foreach(); 828 }; 829 830 TC_Class.prototype.getInstance = function(element) { 831 var instance; 832 833 var cur_id = $(element).data("tc-id"); 834 if (typeof cur_id === "undefined") { 835 cur_id = guid(); 836 $(element).attr("data-tc-id", cur_id); 837 } 838 if (typeof TC_Instance_List[cur_id] === "undefined") { 839 var options = this.options; 840 var element_options = $(element).data('options'); 841 if (typeof element_options === "string") { 842 element_options = JSON.parse(element_options); 843 } 844 if (typeof element_options === "object") { 845 options = $.extend(true, {}, this.options, element_options); 846 } 847 instance = new TC_Instance(element, options); 848 TC_Instance_List[cur_id] = instance; 849 } 850 else { 851 instance = TC_Instance_List[cur_id]; 852 if (typeof this.options !== "undefined") { 853 instance.setOptions(this.options); 854 } 855 } 856 return instance; 857 }; 858 859 TC_Class.prototype.addTime = function(seconds_to_add) { 860 this.foreach(function(instance) { 861 instance.addTime(seconds_to_add); 862 }); 863 }; 864 865 TC_Class.prototype.foreach = function(callback) { 866 var _this = this; 867 this.elements.each(function() { 868 var instance = _this.getInstance(this); 869 if (typeof callback === "function") { 870 callback(instance); 871 } 872 }); 873 return this; 874 }; 875 876 TC_Class.prototype.start = function() { 877 this.foreach(function(instance) { 878 instance.start(); 879 }); 880 return this; 881 }; 882 883 TC_Class.prototype.stop = function() { 884 this.foreach(function(instance) { 885 instance.stop(); 886 }); 887 return this; 888 }; 889 890 TC_Class.prototype.restart = function() { 891 this.foreach(function(instance) { 892 instance.restart(); 893 }); 894 return this; 895 }; 896 897 TC_Class.prototype.rebuild = function() { 898 this.foreach(function(instance) { 899 instance.initialize(false); 900 }); 901 return this; 902 }; 903 904 TC_Class.prototype.getTime = function() { 905 return this.getInstance(this.elements[0]).timeLeft(); 906 }; 907 908 TC_Class.prototype.addListener = function(f, type) { 909 if (typeof type === "undefined") 910 type = "visible"; 911 var _this = this; 912 this.foreach(function(instance) { 913 instance.addListener(f, _this.elements, type); 914 }); 915 return this; 916 }; 917 918 TC_Class.prototype.destroy = function() { 919 this.foreach(function(instance) { 920 instance.destroy(); 921 }); 922 return this; 923 }; 924 925 TC_Class.prototype.end = function() { 926 return this.elements; 927 }; 928 929 $.fn.TimeCircles = function(options) { 930 return new TC_Class(this, options); 931 }; 932}(jQuery));
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.