1/** 2 * TimeTo jQuery plug-in 3 * Show countdown timer or realtime clock 4 * 5 * @author Alexey Teterin <[email protected]> 6 * @version 1.0.15 7 * @license MIT http://opensource.org/licenses/MIT 8 * @date 2014-01-17 9 */ 10(function ($) { 11 12 var defaults = { 13 callback: null, // callback function for exec when timer out 14 captionSize: 0, // font-size by pixels for captions, if 0 then calculate automaticaly 15 countdown: true, // is countdown or real clock 16 countdownAlertLimit: 10, // limit in seconds when display red background 17 displayCaptions: false, // display captions under digit groups 18 displayDays: 0, // display day timer, count of days digits 19 displayHours: true, // display hours 20 fontFamily: 'Verdana, sans-serif', 21 fontSize: 28, // font-size of a digit by pixels 22 lang: {days:'days',hours:'hours',min:'minutes',sec:'secondes',}, // language of caption 23 seconds: 0, // timer's countdown value in seconds 24 start: true, // true to start timer immediately 25 theme: 'white', // 'white' or 'black' theme fo timer's view 26 27 vals: [0, 0, 0, 0, 0, 0, 0, 0, 0], // private, current value of each digit 28 limits: [9, 9, 9, 2, 9, 5, 9, 5, 9],// private, max value of each digit 29 iSec: 8, // private, index of second digit 30 iHour: 4, // private, index of hour digit 31 tickTimeout: 1000, // timeout betweet each timer tick in miliseconds 32 intervalId: null // private 33 }; 34 35 var methods = { 36 start: function(sec) { 37 if(sec) init.call(this, sec); 38 var me = this, 39 intervalId = setTimeout(function(){ tick.call(me); }, 1000); 40 41 // save start time 42 this.data('ttStartTime', (new Date()).getTime()); 43 this.data('intervalId', intervalId); 44 }, 45 46 stop: function() { 47 var data = this.data(); 48 49 if(data.intervalId){ 50 clearTimeout(data.intervalId); 51 this.data('intervalId', null); 52 } 53 return data; 54 }, 55 56 reset: function(sec){ 57 var data = methods.stop.call(this); 58 59 this.find('div').css({ backgroundPosition: 'left center' }); 60 this.find('ul').parent().removeClass('timeTo-alert'); 61 62 if(typeof sec === "undefined") { sec = data.value; } 63 init.call(this, sec, true); 64 } 65 }; 66 if(typeof $.support.transition === 'undefined') { 67 $.support.transition = (function(){ 68 var thisBody = document.body || document.documentElement, 69 thisStyle = thisBody.style, 70 support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined; 71 72 return support; 73 })(); 74 } 75 76 77 $.fn.timeTo = function(){ 78 var method, options = {}; 79 80 for(var i = 0, arg; arg = arguments[i]; ++i) { 81 if(i == 0 && typeof arg === 'string') { 82 method = arg; 83 } 84 else { 85 if(typeof arg === 'object') { 86 if(typeof arg.getTime === 'function') { 87 options.timeTo = arg; 88 } 89 else { 90 options = $.extend(options, arg); 91 } 92 } 93 else { 94 if(typeof arg === 'function') { 95 options.callback = arg; 96 } 97 else { 98 var v = parseInt(arg, 10); 99 if(!isNaN(v)) { 100 options.seconds = v; 101 } 102 } 103 } 104 } 105 } 106 107 // set time for countdown to 108 if(options.timeTo) { 109 var time, 110 now = (new Date()).getTime(); 111 112 if(options.timeTo.getTime) { // set time as date object 113 time = options.timeTo.getTime(); 114 } 115 else if(typeof options.timeTo === 'number') { // set time as integer in millisec 116 time = options.timeTo; 117 } 118 if(options.timeTo > now) { 119 options.seconds = Math.floor((time - now) / 1000); 120 } 121 }else if(options.time || !options.seconds) { 122 var time = options.time; 123 124 if(!time) time = new Date(); 125 126 if(typeof time === 'object' && time.getTime) { 127 options.seconds = time.getHours()*3600 + time.getMinutes()*60 + time.getSeconds(); 128 options.countdown = false; 129 } 130 else if(typeof time === 'string') { 131 var tt = time.split(':'), 132 sec = 0, m = 1, t; 133 134 while(t = tt.pop()) { 135 sec += t*m; 136 m *= 60; 137 } 138 options.seconds = sec; 139 options.countdown = false; 140 } 141 } 142 143 if(options.countdown !== false && options.seconds > 86400 && typeof options.displayDays === 'undefined') { 144 var days = Math.floor(options.seconds / 86400); 145 options.displayDays = days < 10 && 1 || days < 100 && 2 || 3; 146 } 147 else if(options.displayDays === true) { 148 options.displayDays = 3; 149 } 150 else if(options.displayDays) { 151 options.displayDays = options.displayDays > 0 ? Math.floor(options.displayDays) : 3; 152 } 153 154 return this.each(function() { 155 var $this = $(this), 156 data = $this.data(), 157 i; 158 159 160 if(data.intervalId) { 161 clearInterval(data.intervalId); 162 data.intervalId = null; 163 } 164 165 if(!data.vals || method === 'reset') { // new clock 166 if(data.options) { 167 options = data.options; 168 } 169 data = $.extend(defaults, options); 170 data.options = options; 171 172 data.height = Math.round(data.fontSize * 100 / 93); 173 data.width = Math.round(data.fontSize * .8 + data.height * .13); 174 data.displayHours = !!(data.displayDays || data.displayHours); 175 176 $this 177 .addClass('timeTo') 178 .addClass('timeTo-'+ data.theme) 179 .css({ 180 fontFamily: data.fontFamily, 181 fontSize: data.fontSize +'px' 182 }); 183 184 var left = Math.round(data.height / 10), 185 ulhtml = '<ul style="left:'+ left +'px; top:-'+ data.height +'px"><li>0</li><li>0</li></ul></div>', 186 style = ' style="width:'+ data.width +'px; height:'+ data.height +'px;"', 187 dhtml1 = '<div class="first"'+ style +'>'+ ulhtml, 188 dhtml2 = '<div'+ style +'>'+ ulhtml, 189 dot2 = '<span> </span>', 190 maxWidth = Math.round(data.width * 2 + 3), 191 captionSize = data.captionSize || Math.round(data.fontSize * 0.43), 192 193 thtml = (data.displayCaptions ? 194 (data.displayHours 195 ? '<figure style="max-width:'+ maxWidth +'px">$1<figcaption style="font-size:'+ captionSize +'px">'+ data.lang.hours +'</figcaption></figure>'+ dot2 196 : '') + 197 '<figure style="max-width:'+ maxWidth +'px">$1<figcaption style="font-size:'+ captionSize +'px">'+ data.lang.min +'</figcaption></figure>'+ dot2 + 198 '<figure style="max-width:'+ maxWidth +'px">$1<figcaption style="font-size:'+ captionSize +'px">'+ data.lang.sec +'</figcaption></figure>'+ '<span style="width: 8px; display: inline-block;"> </span>' 199 : (data.displayHours ? '$1'+ dot2 : '') +'$1'+ dot2 +'$1' 200 ).replace(/\$1/g, dhtml1 + dhtml2); 201 202 if(data.displayDays > 0) { 203 var marginRight = data.fontSize * 0.4, 204 dhtml = dhtml1; 205 for(i = data.displayDays - 1; i > 0; i--) { 206 dhtml += i === 1 ? dhtml2.replace('">', ' margin-right:'+ Math.round(marginRight) +'px">') : dhtml2; 207 } 208 thtml = (data.displayCaptions ? 209 '<figure style="width:'+ Math.round(data.width*data.displayDays + marginRight + 4) +'px">$1<figcaption style="font-size:'+ captionSize +'px; padding-right:'+ Math.round(marginRight) +'px">'+ data.lang.days +'</figcaption></figure>' 210 : '$1').replace( 211 /\$1/, dhtml 212 ) + thtml; 213 } 214 $this.html(thtml); 215 } 216 else { // exists clock 217 $.extend(data, options); 218 } 219 220 var $digits = $this.find('div'); 221 222 if($digits.length < data.vals.length) { 223 var dif = data.vals.length - $digits.length, 224 vals = data.vals, limits = data.limits; 225 226 data.vals = []; 227 data.limits = []; 228 for(i = 0; i < $digits.length; i++){ 229 data.vals[i] = vals[dif + i]; 230 data.limits[i] = limits[dif + i]; 231 } 232 data.iSec = data.vals.length - 1; 233 data.iHour = data.vals.length - 5; 234 } 235 data.sec = data.seconds; 236 $this.data(data); 237 238 if(method && methods[method]) { 239 methods[ method ].call($this, data.seconds); 240 } 241 else if(data.start) { 242 methods.start.call($this, data.seconds); 243 } 244 else { 245 init.call($this, data.seconds); 246 } 247 }); 248 }; 249 250 251 function init(sec, force) { 252 var data = this.data(), 253 $digits = this.find('ul'), 254 isInterval = false; 255 256 if (!data.vals || $digits.length === 0) { 257 return; 258 } 259 260 if(!sec) { 261 sec = data.seconds; 262 } 263 264 if (data.intervalId) { 265 isInterval = true; 266 clearTimeout(data.intervalId); 267 } 268 269 var days = Math.floor(sec / 86400), 270 rest = days * 86400, 271 h = Math.floor((sec - rest) / 3600); 272 273 rest += h * 3600; 274 275 var m = Math.floor((sec - rest) / 60); 276 277 rest += m * 60; 278 279 var s = sec - rest, 280 str = (days < 100 ? '0' + (days < 10 ? '0' : '') : '') + days + (h < 10 ? '0' : '') + h + (m < 10 ? '0' : '') + m + (s < 10 ? '0' : '') + s; 281 282 for(var i = data.vals.length - 1, j = str.length - 1, v; i >= 0; i--, j--) { 283 v = parseInt(str.substr(j, 1)); 284 data.vals[i] = v; 285 $digits.eq(i).children().html(v); 286 } 287 if(isInterval || force) { 288 var me = this; 289 data.ttStartTime = Date.now(); 290 data.intervalId = setTimeout(function(){ tick.call(me); }, 1000); 291 this.data('intervalId', data.intervalId); 292 } 293 } 294 295 /** 296 * Switch specified digit by digit index 297 * @param {number} - digit index 298 */ 299 function tick(digit) { 300 var $digits = this.find('ul'), 301 data = this.data(); 302 303 if(!data.vals || $digits.length == 0) { 304 if(data.intervalId) { 305 clearTimeout(data.intervalId); 306 this.data('intervalId', null); 307 } 308 if(data.callback) { 309 data.callback(); 310 } 311 312 return; 313 } 314 if(digit == undefined) { 315 digit = data.iSec; 316 } 317 318 var n = data.vals[digit], 319 $ul = $digits.eq(digit), 320 $li = $ul.children(), 321 step = data.countdown ? -1 : 1; 322 323 $li.eq(1).html(n); 324 n += step; 325 326 if(digit == data.iSec) { 327 var tickTimeout = data.tickTimeout, 328 timeDiff = (new Date()).getTime() - data.ttStartTime; 329 330 data.sec += step; 331 332 tickTimeout += Math.abs(data.seconds - data.sec) * tickTimeout - timeDiff; 333 334 data.intervalId = setTimeout(function(){ tick.call(me); }, tickTimeout); 335 } 336 337 if(n < 0 || n > data.limits[digit]) { 338 if(n < 0) { 339 n = data.limits[digit]; 340 if(digit == data.iHour && data.displayDays > 0 && digit > 0 && data.vals[digit-1] == 0) // fix for hours when day changing 341 n = 3; 342 } 343 else { 344 n = 0; 345 } 346 347 if(digit > 0) { 348 tick.call(this, digit-1); 349 } 350 } 351 //$ul.removeClass('transition'); 352 //$ul.css({top:"-" + data.height + "px"}); 353 $li.eq(0).html(n); 354 355 var me = this; 356
357 if($.support.transition) { 358 $ul.addClass('transition'); 359 $ul.css({top:0}); 360 361 setTimeout(function() { 362 $ul.removeClass('transition'); 363 $li.eq(1).html(n); 364 $ul.css({top:"-"+ data.height +"px"}); 365 366 if(step > 0 || digit != data.iSec) { 367 return; 368 } 369 370 if(data.sec == data.countdownAlertLimit) { 371 $digits.parent().addClass('timeTo-alert'); 372 } 373 374 if(data.sec === 0) { 375 $digits.parent().removeClass('timeTo-alert'); 376 377 if(data.intervalId) { 378 clearTimeout(data.intervalId); 379 me.data('intervalId', null); 380 } 381 382 if(typeof data.callback === 'function') { 383 data.callback(); 384 } 385 } 386 }, 410); 387 } 388 else { 389 $ul.stop().animate({top:0}, 400, digit != data.iSec ? null : function() { 390 $li.eq(1).html(n); 391 $ul.css({top:"-"+ data.height +"px"}); 392 if(step > 0 || digit != data.iSec) { 393 return; 394 } 395 396 if(data.sec == data.countdownAlertLimit) { 397 $digits.parent().addClass('timeTo-alert'); 398 } 399 else if(data.sec == 0) { 400 $digits.parent().removeClass('timeTo-alert'); 401 402 if(data.intervalId) { 403 clearTimeout(data.intervalId); 404 me.data('intervalId', null); 405 } 406 407 if(typeof data.callback === 'function') { 408 data.callback(); 409 } 410 } 411 }); 412 } 413 data.vals[digit] = n; 414 //this.data('vals', data.vals); 415 } 416 417 return jQuery; 418 419})(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.