multi-countdown.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. 'use strict';
  2. $(function () {
  3. // Countdown
  4. /* Usage example
  5. There are two ways to use this script. On is better for simple needs such a topbar.
  6. And the other one is good if you need to display more elements and have more control
  7. over the CSS
  8. **** SIMPLE MODE ****: Just set a main Class and the content within the data attributes.
  9. (days), (hours), etc.. will be replaced and you can use
  10. p_hours, p_minutes, etc.. for pluralization
  11. <div class="countdown simple-bar" data-Date='2021/9/5 17:12:0' data-endText="Offer ended">
  12. (days) p_days, (hours) p_hours, and (minutes) p_minutes left!
  13. </div>
  14. **** EXTENDED MODE: ****
  15. <div class="countdown show" data-Date='2020/12/10 17:37:53'>
  16. <h2>Live with Madonna</h2>
  17. <div class="running">
  18. <timer>
  19. <span class = "days"></span>:<span class = "hours"></span>:<span class = "minutes"></span>:<span class = "seconds"></span>
  20. </timer>
  21. <div class = "break"></div>
  22. <div class = "labels"><span>Days</span><span>Hours</span><span>Minutes</span><span>Seconds</span></div>
  23. <div class = "break"></div>
  24. <div class="text">until Concert begins</div>
  25. <div class = "break"></div>
  26. <button>Buy Ticket Now!</button>
  27. </div>
  28. <div class="ended">
  29. <div class="text">Show is ended</div>
  30. <div class = "break"></div>
  31. <button>Suscribe for next event!</button>
  32. </div>
  33. </div>
  34. On this way, you have to setup a main Class, and the end Date in the data attributes.
  35. Then, you need to use the classes "running" and "ended" (you can change the names) and the element <timer>
  36. On this way, the "ended" class will be visible when the countdown is ready and you have a lot of
  37. control over the content and the layout.
  38. *** TIMER Mode ***
  39. On the timer mode, you have to enter the data in JSON format such in this example
  40. <div class="countdown simple-bar fix" data-fixTime = '{"Days": "3", "Hours": "2", "Minutes": "10"}' data-endText="Offer ended">
  41. (days) p_days, (hours) p_hours, (minutes) p_minutes and (seconds) p_seconds left!
  42. </div>
  43. *** ZERO-PAD ***
  44. By default, Zero-PAdding is enabled. You can set it to false in a data attribute on this way:
  45. <div ...... data-zeroPad='{"Days": "false"}'>
  46. Each variable (Days, Hours, Minutes and Seconds) can be set to false
  47. TODO:
  48. - cookie (or localStorage)
  49. - pluralization: it works now but only in simple mode, and only in English
  50. - weeks support
  51. - prevent errors with false configs
  52. CONFIG:
  53. - mainClass
  54. - Offset Location
  55. - runningClass (optional)
  56. - endedClass (optional)
  57. offset value base on which location time zone you would like to set
  58. For India offset value +5.5,
  59. New York offset value -4,
  60. London offset value +1
  61. All locations offset: https://en.wikipedia.org/wiki/List_of_UTC_time_offsets
  62. */
  63. // CONFIG
  64. let mainClass = '.countdown';
  65. let OffsetLocation = -4;
  66. let runningClass = '.running'; //optinonal
  67. let endedClass = ".ended"; //optional
  68. // END CONFIG
  69. //init
  70. let date, fixTime, index = 0, extraClass, initText, zeroPad;
  71. $(mainClass).each(function () { //for each countdown instance
  72. index++;
  73. date = $(this).attr('data-Date');
  74. fixTime = $(this).attr('data-fixTime');
  75. zeroPad = $(this).attr('data-zeroPad');
  76. extraClass = 'd_' + index;
  77. $(this).addClass(extraClass); //add a class to recognize each counter
  78. $(this).css('display','block'); //allow to start hidding the class to avoid a bad effect until js is loading
  79. if (fixTime != undefined) date = getFixDate(fixTime);
  80. //get init text with or whitout an extra Class
  81. if ($('.' + extraClass + ' ' + runningClass + ' timer').length) {
  82. initText = $('.' + extraClass + ' ' + runningClass + ' timer').text();
  83. } else {
  84. initText = $(this).text();
  85. }
  86. //show and hide classes
  87. $('.' + extraClass + ' ' + runningClass).css('display', 'flex');
  88. $('.' + extraClass + ' ' + endedClass).css('display', 'none');
  89. //call main function
  90. dateReplace(extraClass, date, fixTime, initText, zeroPad); //prevent delay for the first time
  91. setInterval(dateReplace, 1000, extraClass, date, fixTime, initText, zeroPad);
  92. });
  93. function dateReplace(extraClass, date, fixTime, initText, zeroPad) {
  94. let dif = timeDistance(date, fixTime);
  95. let text = initText;
  96. let zeroPadArr = [];
  97. if (dif[0] < 0 || dif[1] < 0 || dif[2] < 0 || dif[3] < 0) {
  98. //countdown ended
  99. let endText = $('.' + extraClass).attr('data-endText');
  100. if (endText != undefined) { //case data-endText attr
  101. $('.' + extraClass).text(endText);
  102. } else { //case with two blocks
  103. $('.' + extraClass + ' ' + runningClass).css('display', 'none');
  104. $('.' + extraClass + ' ' + endedClass).css('display', 'flex');
  105. }
  106. } else {
  107. //Zero-pad
  108. if(zeroPad != undefined) zeroPadArr = JSON.parse(zeroPad);
  109. if (zeroPadArr['Days'] != "false") dif[0] = String(dif[0]).padStart(2, '0');
  110. if (zeroPadArr['Hours'] != "false") dif[1] = String(dif[1]).padStart(2, '0');
  111. if (zeroPadArr['Minutes'] != "false") dif[2] = String(dif[2]).padStart(2, '0');
  112. if (zeroPadArr['Seconds'] != "false") dif[3] = String(dif[3]).padStart(2, '0');
  113. //replace text with or without extra class
  114. //whith extras Class
  115. if ($('.' + extraClass + ' ' + runningClass + ' timer').length) {
  116. $('.' + extraClass + ' ' + runningClass + ' timer .days').text(dif[0]);
  117. $('.' + extraClass + ' ' + runningClass + ' timer .hours').text(dif[1]);
  118. $('.' + extraClass + ' ' + runningClass + ' timer .minutes').text(dif[2]);
  119. $('.' + extraClass + ' ' + runningClass + ' timer .seconds').text(dif[3]);
  120. } else {
  121. //replace parts without extra Class
  122. text = text.replace('(days)', dif[0]);
  123. text = text.replace('(hours)', dif[1]);
  124. text = text.replace('(minutes)', dif[2]);
  125. text = text.replace('(seconds)', dif[3]);
  126. $('.' + extraClass).text(text);
  127. }
  128. pluralization(extraClass, dif);
  129. }
  130. }
  131. function timeDistance(date, fixTime) {
  132. var date1 = new Date(date);
  133. let date2, d, utc;
  134. d = new Date();
  135. utc = d.getTime() + (d.getTimezoneOffset() * 60000);
  136. if (fixTime != undefined) date2 = new Date;
  137. else date2 = new Date(utc + (3600000 * OffsetLocation));
  138. var diff = date1.getTime() - date2;
  139. var msec = diff;
  140. var hh = Math.floor(msec / 1000 / 60 / 60);
  141. msec -= hh * 1000 * 60 * 60;
  142. var mm = Math.floor(msec / 1000 / 60);
  143. msec -= mm * 1000 * 60;
  144. var ss = Math.floor(msec / 1000);
  145. msec -= ss * 1000;
  146. var dd = Math.floor(hh / 24);
  147. if (dd > 0) {
  148. hh = hh - (dd * 24);
  149. }
  150. return [dd, hh, mm, ss];
  151. }
  152. function getFixDate(fixTime) {
  153. let getFixTimeDate = 0;
  154. var fixTimeDate = JSON.parse($('.' + extraClass).attr('data-fixTime'));
  155. if (fixTimeDate['Days'] != undefined) { getFixTimeDate += +fixTimeDate['Days'] * 60 * 24; }
  156. if (fixTimeDate['Hours'] != undefined) { getFixTimeDate += +fixTimeDate['Hours'] * 60; }
  157. if (fixTimeDate['Minutes'] != undefined) getFixTimeDate += +fixTimeDate['Minutes'];
  158. var now = new Date();
  159. now.setMinutes(now.getMinutes() + getFixTimeDate); // timestamp
  160. date = new Date(now); // Date object
  161. return date;
  162. }
  163. // Note this *is* JQuery, see below for JS solution instead
  164. function replaceText(selector, text, newText, flags) {
  165. var matcher = new RegExp(text, flags);
  166. $(selector).each(function () {
  167. var $this = $(this);
  168. if (!$this.children().length)
  169. $this.text($this.text().replace(matcher, newText));
  170. });
  171. }
  172. function pluralization(extraClass, dif) {
  173. //pluralization
  174. if (dif[0] == 1) replaceText('.' + extraClass, 'p_days', 'Day', 'g');
  175. else replaceText('.' + extraClass, 'p_days', 'Days', 'g');
  176. if (dif[1] == 1) replaceText('.' + extraClass, 'p_hours', 'Hour', 'g');
  177. else replaceText('.' + extraClass, 'p_hours', 'Hours', 'g');
  178. if (dif[2] == 1) replaceText('.' + extraClass, 'p_minutes', 'Minute', 'g');
  179. else replaceText('.' + extraClass, 'p_minutes', 'Minutes', 'g');
  180. if (dif[3] == 1) replaceText('.' + extraClass, 'p_seconds', 'Second', 'g');
  181. else replaceText('.' + extraClass, 'p_seconds', 'Seconds', 'g');
  182. }
  183. })