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