PageRenderTime 27ms CodeModel.GetById 7ms RepoModel.GetById 1ms app.codeStats 0ms

/mig/images/widget-deps/epiclock-2.2.3/jquery.epiclock.js

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