PageSourceSearch

https://truckstopconcertseries.com/wp-content/themes/evenio/assets/js/time-circle.js?ver=20151215

js truckstopconcertseries.com collected 2026-10-04 21:06:46 UTC 34,990 bytes, 959 lines download raw bytes

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