Posted By

arantxaortega on 03/12/10


Tagged

javascript clock


Versions (?)

Epiclock in español (js)


 / Published in: JavaScript
 

Documentación en: http://eric.garside.name/docs.html?p=epiclock

  1. /*!
  2.  * epiClock 2.2 - Create Epic Clocks Easily
  3.  *
  4.  * Copyright (c) 2008 Eric Garside (http://eric.garside.name)
  5.  * Dual licensed under:
  6.  * MIT: http://www.opensource.org/licenses/mit-license.php
  7.  * GPLv3: http://www.opensource.org/licenses/gpl-3.0.html
  8.  */
  9.  
  10. // Manager States
  11. var EC_HALT = 'disable', EC_RUN = 'enable', EC_KILL = 'destroy',
  12. // Clock Types
  13. EC_CLOCK = 0, EC_COUNTDOWN = 1, EC_COUNTUP = 2, EC_ROLLOVER = 3,
  14. EC_EXPIRE = 4, EC_LOOP = 5, EC_STOPWATCH = 6, EC_HOLDUP = 7;
  15.  
  16. (function($){
  17.  
  18. /**
  19. * Setup a placeholder for clock styles
  20. */
  21. $.epiclocks = {};
  22.  
  23. var defaults = {
  24. epiClock: {
  25. offset: {
  26. hours: 0,
  27. minutes: 0,
  28. seconds: 0,
  29. days: 0,
  30. years: 0
  31. },
  32. arbitrary: {
  33. days: 0,
  34. years: 0
  35. },
  36. gmt: false,
  37. target: null,
  38. onTimer: null,
  39. onKill: null,
  40. onRender: function(v,val){v.html(val)},
  41. format: null,
  42. frame: {},
  43. dead: false,
  44. displace: 0,
  45. modifier: 0,
  46. variance: 0,
  47. daysadded: 0,
  48. paused: 0,
  49. tolerance: 0,
  50. selfLoc: -1,
  51. mode: EC_CLOCK,
  52. onSetup: null,
  53. stylesheet: null,
  54. containerClass: null,
  55. tpl: '<span></span>'
  56. },
  57. formats: [
  58. 'F j, Y, g:i:s a', // EC_CLOCK
  59. 'V{d} x{h} i{m} s{s}', // EC_COUNTDOWN
  60. 'Q{y} K{d} x{h} i{m} s{s}', // EC_COUNTUP
  61. 'V{d} x{h} i{m} s{s}', // EC_ROLLOVER
  62. 'x{h} i{m} s{s}', // EC_EXPIRE
  63. 'i{m} s{s}', // EC_LOOP
  64. 'x{h} C{m} s{s}', // EC_STOPWATCH
  65. 'Q{y} K{d} x{h} i{m} s{s}' // EC_HOLDUP
  66. ]
  67. },
  68. // The current mode the clock manager is in
  69. current = null,
  70. // The interval timer for the clock
  71. loop = null,
  72. // The clocks we're managing
  73. clocks = [];
  74.  
  75. /**
  76. * jQuery Entry Point - CSS Loader
  77. *
  78. * Provides an interface to include stylesheets dynamically
  79. */
  80. $.cssIncludes = {};
  81. $.cssInclude = function(href, media){
  82. if ($.cssIncludes[href]) return false;
  83.  
  84. $.cssIncludes[href] = true;
  85. media = media || 'screen';
  86.  
  87. $('<link type="text/css" rel="stylesheet" href="' + href + '" media="' + media + '"/>')
  88. .appendTo('head');
  89. }
  90.  
  91. /**
  92. * jQuery Entry Point - Clock Manager
  93. *
  94. * Provides an interface for the user to pause, destroy, or resume/start all clocks.
  95. */
  96. $.epiclock = $.fn.clocks = function(mode, precision, path){
  97. mode = mode || EC_RUN;
  98. precision = precision || 5e2;
  99. if (mode == current) return;
  100.  
  101. switch (mode){
  102. case EC_KILL:
  103. $.each(clocks, function(){
  104. this.epiclock('kill')
  105. })
  106. clocks = [];
  107. case EC_HALT:
  108. if (loop){
  109. clearInterval(loop);
  110. loop = null;
  111. }
  112.  
  113. $.each(clocks, function(){
  114. this.epiclock('disable')
  115. })
  116.  
  117. current = mode;
  118. break;
  119. case EC_RUN:
  120. if (!loop){
  121. cycleClocks(true);
  122. loop = setInterval(cycleClocks, precision);
  123. }
  124. current = mode;
  125. break;
  126. }
  127.  
  128. return this;
  129. }
  130.  
  131. function cycleClocks(enabled){
  132. process = enabled === true;
  133. $.each(clocks, function(i){
  134. if (process)
  135. this.epiclock('enable');
  136.  
  137. this.data('epiClock').render();
  138. })
  139. }
  140.  
  141. /**
  142. * jQuery Entry Point
  143. *
  144. * Creates the clock displays
  145. */
  146. $.fn.epiclock = function(options, predefined){
  147. var action = null;
  148.  
  149. if (typeof options == 'string' && $.epiclocks && $.epiclocks[options])
  150. options = $.epiclocks[options];
  151. else if (predefined && $.epiclocks && $.epiclocks[predefined])
  152. options = $.extend(true, {}, $.epiclocks[predefined], options);
  153.  
  154. switch (options){
  155. case 'destroy':
  156. action = 'kill';
  157. case 'disable':
  158. action = action||'pause';
  159. case 'enable':
  160. action = action||'resume';
  161. return this.each(function(){
  162. var ec = $(this).data('epiClock');
  163. if (ec instanceof epiClock) ec[ action ]();
  164. })
  165. default:
  166. options = $.extend(true, {}, defaults.epiClock, options);
  167. break;
  168. }
  169.  
  170. this.each(function(){
  171. var object = $(this),
  172. format = (options.format || defaults.formats[options.mode]).split(''),
  173. isBuffering = false,
  174. tpl = options.tpl || defaults.tpl,
  175. buffer = '',
  176. clock = new epiClock(options, object);
  177.  
  178. object.data('epiClock', clock);
  179.  
  180. $.each(format, function(){
  181. x = this+'';
  182. switch (x){
  183. case ' ':
  184. if (!isBuffering)
  185. $(tpl).addClass('epiclock epiclock-spacer').appendTo(object);
  186. else buffer += x;
  187. break;
  188. case '{':
  189. isBuffering = true;
  190. break;
  191. case '}':
  192. isBuffering = false;
  193. $(tpl).addClass('epiclock').html(buffer).appendTo(object);
  194. buffer = '';
  195. break;
  196. default:
  197. // If we're buffering, this is label text
  198. if (isBuffering) buffer += x;
  199. // If it's a special character, it will be span updated
  200. else if (Date.prototype[x] || clock[x]) {
  201. clock.frame[x] = $(tpl)
  202. .addClass('epiclock epiclock-digit')
  203. .data('ec-encoding', x)
  204. .appendTo(object);
  205. }
  206. // If it's anything else, it's a single char label seperator
  207. else
  208. $(tpl).addClass('epiclock epiclock-separator').html(x).appendTo(object);
  209. break;
  210. }
  211. });
  212.  
  213. clock.selfLoc = clocks.push(object) - 1;
  214. if ($.isFunction(clock.onSetup)) clock.onSetup.call(clock, []);
  215. if (clock.stylesheet) $.cssInclude(clock.stylesheet);
  216. if (clock.containerClass) object.addClass(clock.containerClass);
  217. })
  218.  
  219. return this;
  220. }
  221.  
  222. /*
  223. * Export the current time.
  224. */
  225. $.fn.epiclockQuery = function(format){
  226. var ec = $(this).data('epiClock');
  227.  
  228. if (!ec)
  229. return "";
  230.  
  231. var format = format.split(''),
  232. buffer = '',
  233. isBuffering = false,
  234. x = '';
  235.  
  236. $.each(format, function(){
  237. x = this+'';
  238. switch (x){
  239. case ' ':
  240. buffer += x;
  241. break;
  242. case '{':
  243. isBuffering = true;
  244. break;
  245. case '}':
  246. isBuffering = false;
  247. break;
  248. default:
  249. // If we're buffering, this is label text
  250. if (isBuffering) buffer += x;
  251. // If it's a special character, it will be span updated
  252. else if (Date.prototype[x] || ec[x]) {
  253. buffer += ($.isFunction(ec.now[x]) ? ec.now[x]() : ec[x]()) + ''
  254. }
  255. // If it's anything else, it's a single char label seperator
  256. else
  257. buffer += x;
  258. break;
  259. }
  260. });
  261.  
  262. return buffer;
  263. }
  264.  
  265. function epiClock(options, element){
  266. if (this instanceof epiClock)
  267. return this.init(options, element);
  268. else return new epiClock(options, element);
  269. }
  270.  
  271. epiClock.prototype = {
  272. Q: function() { return this.arbitrary.years },
  273. E: function() { return this.arbitrary.days },
  274. e: function() { return this.arbitrary.days.pad(0) },
  275. zero: new Date(0),
  276. pause: function(){
  277. if (this.dead) return;
  278. this.paused = new Date().valueOf();
  279. this.dead = true;
  280. },
  281. resume: function(){
  282. if (!this.dead) return;
  283. if (this.mode == EC_STOPWATCH)
  284. this.displace += (this.paused - new Date().valueOf());
  285. this.paused = 0;
  286. this.dead = false;
  287. },
  288. kill: function(){
  289. // Remove and Renumber Clocks Array
  290. clocks.splice(this.selfLoc,1);
  291. $.each(clocks, function(i){this.data('epiClock').selfLoc = i});
  292.  
  293. // Call on kill, set dead
  294. if ($.isFunction(this.onKill)) this.onKill();
  295. this.dead = true;
  296. },
  297. init: function(options, element){
  298. if (options.mode < EC_CLOCK || options.mode > EC_HOLDUP)
  299. throw 'EPICLOCK_INVALID_MODE';
  300.  
  301. var clock = this;
  302. $.each(options, function(k, v){
  303. clock[k] = v;
  304. });
  305.  
  306. switch (this.mode){
  307. case EC_LOOP:
  308. case EC_EXPIRE:
  309. this.target = this.target || new Date();
  310. case EC_COUNTDOWN:
  311. case EC_ROLLOVER:
  312. this.modifier = -1;
  313. this.variance = 1;
  314. break;
  315. case EC_STOPWATCH:
  316. this.displace += this.calculateOffset() + (-1 * new Date().valueOf());
  317. this.dead = true;
  318. this.paused = new Date().valueOf();
  319. return;
  320. case EC_HOLDUP:
  321. this.variance = -1;
  322. this.modifier = 1;
  323. break;
  324. default:
  325. this.modifier = 1;
  326. this.variance = 0;
  327. break;
  328. }
  329.  
  330. if (this.gmt)
  331. this.normalize();
  332.  
  333. switch (true){
  334. case this.target instanceof Date:
  335. this.target = this.target.valueOf();
  336. break;
  337. case typeof this.target == 'string':
  338. this.target = new Date(this.target).valueOf();
  339. break;
  340. }
  341.  
  342. this.displace += this.modifier * this.calculateOffset();
  343. },
  344. calculateOffset: function(offset){
  345. offset = offset || this.offset;
  346.  
  347. return (
  348. offset.years * 3157056e4 +
  349. offset.days * 864e5 +
  350. offset.hours * 36e5 +
  351. offset.minutes * 6e4 +
  352. (this.variance + offset.seconds) * 1e3
  353. );
  354. },
  355. normalize: function(){
  356. this.displace += new Date().getTimezoneOffset()*6e4;
  357. },
  358. render: function(){
  359. if (!this.tick()) return;
  360. var clock = this,
  361. time = (this.mode == EC_HOLDUP) ? this.zero : this.now;
  362.  
  363. $.each(this.frame, function(k,v){
  364. var val = ($.isFunction(time[k]) ? time[k]() : clock[k]()) + '';
  365. if (v.data('last') != val) clock.onRender(v, val);
  366. v.data('last', val)
  367. })
  368. },
  369. tick: function(){
  370. if (this.dead) return false;
  371. var now = new Date().valueOf() + this.displace;
  372.  
  373. switch (this.mode){
  374. case EC_HOLDUP:
  375. if (this.target < now) this.mode = EC_COUNTUP;
  376. case EC_COUNTUP:
  377. now -= this.target;
  378. break;
  379. case EC_ROLLOVER:
  380. if (now > this.target) now = now - this.target;
  381. else now = this.target - now;
  382. break;
  383. case EC_COUNTDOWN:
  384. case EC_EXPIRE:
  385. case EC_LOOP:
  386. now = this.target - now;
  387. if (now < this.tolerance) return this.timerEnd();
  388. break;
  389. }
  390.  
  391. this.now = new Date(now);
  392.  
  393. var days = this.now.V();
  394. if (days <= this.daysadded) return true;
  395.  
  396. this.daysadded = days;
  397. this.arbitrary.days += days;
  398.  
  399. if (this.arbitrary.days < 365) return true;
  400. this.arbitrary.years += Math.floor(this.arbitrary.days/365.4 % 365.4);
  401. this.arbitrary.days = Math.floor(this.arbitrary.days % 365.4);
  402.  
  403. return true;
  404. },
  405. timerEnd: function(){
  406. if ($.isFunction(this.onTimer)) this.onTimer();
  407.  
  408. switch (this.mode){
  409. case EC_COUNTDOWN:
  410. case EC_EXPIRE:
  411. this.kill();
  412. break;
  413. case EC_LOOP:
  414. this.displace += this.modifier * this.calculateOffset();
  415. return this.render();
  416. case EC_ROLLOVER:
  417. this.mode = EC_COUNTUP;
  418. return true;
  419. }
  420.  
  421. this.now = new Date(0);
  422. return true;
  423. }
  424. };
  425.  
  426. $.extend(String.prototype, {
  427. pad: function(s,l){ l=l||2; return this.length < l ? new Array(1+l-this.length).join(s) + this : this },
  428. rpad: function(s,l){ l=l||2; return this.length < l ? this + new Array(1+l-this.length).join(s) : this }
  429. })
  430.  
  431. $.extend(Number.prototype, {
  432. pad: function(s,l){ return (this+'').pad(s,l) },
  433. rpad: function(s,l){ return (this+'').rpad(s,l) }
  434. })
  435.  
  436. /** Prototype the Date function **/
  437. $.extend(Date.prototype, {
  438. // Assistance Definitions
  439. modCalc: function(mod1,mod2){return (Math.floor(Math.floor(this.valueOf()/1e3)/mod1)%mod2)},
  440. months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
  441. days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
  442. suffix: [null, 'st', 'nd', 'rd'],
  443. // Timer Functions
  444. V: function(){return this.modCalc(864e2,1e5)}, // Days
  445. v: function(){return this.V().pad(0)}, // Paded Days
  446. K: function(){return this.V()%365}, // Days Offset for Years
  447. k: function(){return this.K().pad(0)}, // Padded Offset Days
  448. X: function(){return this.modCalc(36e2,24)}, // Hours
  449. x: function(){return this.X().pad(0)}, // Padded Hours
  450. p: function(){return this.modCalc(60,60)}, // Minutes
  451. C: function(){return this.p().pad(0)}, // Padded Minutes
  452. // Day
  453. d: function() { return this.getDate().pad('0') },
  454. D: function() { return this.days[this.getDay()].substring(0,3) },
  455. j: function() { return this.getDate() },
  456. l: function() { return this.days[this.getDay()] },
  457. N: function() { return this.getDay() + 1 },
  458. S: function() { return this.suffix[this.getDate()] || 'th' },
  459. w: function() { return this.getDay() },
  460. z: function() { return Math.round((this-this.f())/864e5) },
  461. // Week
  462. W: function() { return Math.ceil(((((this-this.f())/864e5) + this.f().w())/7)) },
  463. // Month
  464. F: function() { return this.months[this.getMonth()]; },
  465. m: function() { return (this.getMonth()+1).pad(0) },
  466. M: function() { return this.months[this.getMonth()].substring(0,3) },
  467. n: function() { return this.getMonth() + 1 },
  468. // Year
  469. L: function() { var Y = this.Y(); return Y%4 ? false : Y%100 ? true : Y%400 ? false : true },
  470. f: function() { return new Date(this.getFullYear(),0,1) },
  471. Y: function() { return this.getFullYear() },
  472. y: function() { return ('' + this.getFullYear()).substr(2) },
  473. // Time
  474. a: function() { return this.getHours() < 12 ? 'am' : 'pm' },
  475. A: function() { return this.a().toUpperCase() },
  476. B: function() { return Math.floor((((this.getHours()) * 36e5) + (this.getMinutes() * 6e4) + (this.getSeconds() * 1e3))/864e2).pad(0,3) },
  477. g: function() { return this.getHours()%12 || 12 },
  478. G: function() { return this.getHours() },
  479. h: function() { return this.g().pad('0') },
  480. H: function() { return this.getHours().pad('0') },
  481. i: function() { return this.getMinutes().pad(0) },
  482. s: function() { return this.getSeconds().pad('0') },
  483. u: function() { return this.getTime()%1000 },
  484. // Timezone
  485. O: function() { var t = this.getTimezoneOffset() / 60; return (t >= 0 ? '+' : '-') + Math.abs(t).pad(0).rpad(0,4) },
  486. P: function() { var t = this.O(); return t.substr(0,3) + ':' + t.substr(3)},
  487. Z: function() { return this.getTimezoneOffset() * 60;},
  488. // Full Date/Time
  489. c: function() { return this.Y()+'-'+this.m()+'-'+this.d()+'T'+this.H()+':'+this.i()+':'+this.s()+this.P()},
  490. r: function() { return this.toString() },
  491. U: function() { return this.getTime() / 1000 }
  492. });
  493.  
  494. })(jQuery);

Report this snippet  

You need to login to post a comment.