diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/flipdown.iml b/.idea/flipdown.iml new file mode 100644 index 0000000..a8a0eec --- /dev/null +++ b/.idea/flipdown.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml new file mode 100644 index 0000000..02b915b --- /dev/null +++ b/.idea/git_toolbox_prj.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000..d3d2e18 --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..857998a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index b81ce1d..0a8954e 100644 --- a/README.md +++ b/README.md @@ -31,17 +31,33 @@ For basic usage, FlipDown takes a unix timestamp (in seconds) as an argument. new FlipDown(1538137672).start(); ``` -Include the [CSS and JS](https://github.com/PButcher/flipdown/tree/master/dist) in `` and include the following line in your HTML. +Include the [CSS and JS](https://github.com/PButcher/flipdown/tree/master/dist) in `` and include the following +line in your HTML. ```html +
``` See a full example [here](https://github.com/PButcher/flipdown/tree/master/example). +## Extended Timer Usage + +To display an extended timer, simply provide the extendedText option during instantiation: + +```javascript +new FlipDown(1631000000, { + extraTime: 5, // Set the extra time in seconds +}).start(); +``` +When extraTime is set, the timer will start extra countdown after the original one ends. + +e.g: Bonus Time + ## Multiple Instances -To use multiple instances of FlipDown on the same page, specify a DOM element ID as the second argument in FlipDown's constructor: +To use multiple instances of FlipDown on the same page, specify a DOM element ID as the second argument in FlipDown's +constructor: ```javascript new FlipDown(1588017373, "registerBy").start(); @@ -49,6 +65,7 @@ new FlipDown(1593561600, "eventStart").start(); ``` ```html +
``` @@ -60,11 +77,12 @@ FlipDown comes with 2 themes as standard: - dark [default] - light -To change the theme, you can supply the `theme` property in the `opt` object in the constructor with the theme name as a string: +To change the theme, you can supply the `theme` property in the `opt` object in the constructor with the theme name as a +string: ```javascript { - theme: "light"; + theme: "light"; } ``` @@ -72,30 +90,35 @@ For example, to instantiate FlipDown using the light theme instead: ```javascript new FlipDown(1538137672, { - theme: "light", + theme: "light", }).start(); ``` ### Custom Themes -Custom themes can be added by adding a new stylesheet using the FlipDown [theme template](https://github.com/PButcher/flipdown/blob/master/src/flipdown.css#L3-L34). +Custom themes can be added by adding a new stylesheet using the +FlipDown [theme template](https://github.com/PButcher/flipdown/blob/master/src/flipdown.css#L3-L34). -FlipDown themes must have the class name prefix of: `.flipdown__theme-` followed by the name of your theme. For example, the standard theme class names are: +FlipDown themes must have the class name prefix of: `.flipdown__theme-` followed by the name of your theme. For example, +the standard theme class names are: - `.flipdown__theme-dark` - `.flipdown__theme-light` -You can then load your theme by specifying the `theme` property in the `opt` object of the constructor (see [Themes](#Themes)). +You can then load your theme by specifying the `theme` property in the `opt` object of the constructor ( +see [Themes](#Themes)). ## Headings -You can add your own rotor group headings by passing an array as part of the `opt` object. Bear in mind this won't change the functionality of the rotors (eg: the 'days' rotor won't magically start counting months because you passed it 'Months' as a heading). +You can add your own rotor group headings by passing an array as part of the `opt` object. Bear in mind this won't +change the functionality of the rotors (eg: the 'days' rotor won't magically start counting months because you passed +it 'Months' as a heading). Suggested use is for i18n. Usage as follows: ```javascript new FlipDown(1538137672, { - headings: ["Nap", "Óra", "Perc", "Másodperc"], + headings: ["Nap", "Óra", "Perc", "Másodperc"], }).start(); ``` @@ -153,13 +176,13 @@ Function to execute once the countdown has ended. ```javascript var flipdown = new FlipDown(1538137672) - // Start the countdown - .start() + // Start the countdown + .start() - // Do something when the countdown ends - .ifEnded(() => { - console.log("The countdown has ended!"); - }); + // Do something when the countdown ends + .ifEnded(() => { + console.log("The countdown has ended!"); + }); ``` ## Acknowledgements @@ -169,3 +192,5 @@ Thanks to the following people for their suggestions/fixes: - [@chuckbergeron](https://github.com/chuckbergeron) for his help with making FlipDown responsive. - [@vasiliki-b](https://github.com/vasiliki-b) for spotting and fixing the Safari backface-visibility issue. - [@joeinnes](https://github.com/joeinnes) for adding i18n to rotor group headings. +- [@2btech-llc](https://github.com/2btech-llc) for contributing extended timer functionality. +- [@kha333n](https://github.com/kha333n) for contributing extended timer implementation. diff --git a/dist/flipdown.js b/dist/flipdown.js index f53e9e1..edc6505 100644 --- a/dist/flipdown.js +++ b/dist/flipdown.js @@ -1,29 +1,26 @@ "use strict"; -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } - +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } +function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } var FlipDown = function () { function FlipDown(uts) { var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "flipdown"; var opt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - _classCallCheck(this, FlipDown); - + this.extendedCountdown = false; + this.extraTime = 0; + this.extendedCallback = null; if (typeof uts !== "number") { throw new Error("FlipDown: Constructor expected unix timestamp, got ".concat(_typeof(uts), " instead.")); } - if (_typeof(el) === "object") { opt = el; el = "flipdown"; } - this.version = "0.3.2"; this.initialised = false; this.now = this._getTime(); @@ -43,15 +40,23 @@ var FlipDown = function () { this.clockValuesAsString = []; this.prevClockValuesAsString = []; this.opts = this._parseOptions(opt); - this._setOptions(); - console.log("FlipDown ".concat(this.version, " (Theme: ").concat(this.opts.theme, ")")); } - _createClass(FlipDown, [{ key: "start", value: function start() { + if (this.extraTime > 0 && this._getTime() >= this.epoch) { + console.log("FlipDown: Extra time is set, extending countdown..."); + this.epoch += this.extraTime; + this.extendedCountdown = true; + this._hasCountdownEnded(); + this._setOptions(); + if (!this.initialised) this._init(); + this._tick(); + this.countdown = setInterval(this._tick.bind(this), 1000); + return this; + } if (!this.initialised) this._init(); this.countdown = setInterval(this._tick.bind(this), 1000); return this; @@ -59,13 +64,25 @@ var FlipDown = function () { }, { key: "ifEnded", value: function ifEnded(cb) { + var _this = this; this.hasEndedCallback = function () { cb(); - this.hasEndedCallback = null; + _this.hasEndedCallback = null; + if (_this.extraTime > 0) { + _this.start(); + } }; - return this; } + }, { + key: "ifExtendedEnded", + value: function ifExtendedEnded(cb) { + var _this2 = this; + this.extendedCallback = function () { + cb(); + _this2.extendedCallback = null; + }; + } }, { key: "_getTime", value: function _getTime() { @@ -75,13 +92,18 @@ var FlipDown = function () { key: "_hasCountdownEnded", value: function _hasCountdownEnded() { if (this.epoch - this.now < 0) { + if (this.extendedCountdown) { + this.extendedCountdown = false; + if (this.extendedCallback) { + this.extendedCallback(); + } + return true; + } this.countdownEnded = true; - if (this.hasEndedCallback != null) { this.hasEndedCallback(); this.hasEndedCallback = null; } - return true; } else { this.countdownEnded = false; @@ -92,13 +114,15 @@ var FlipDown = function () { key: "_parseOptions", value: function _parseOptions(opt) { var headings = ["Days", "Hours", "Minutes", "Seconds"]; - if (opt.headings && opt.headings.length === 4) { headings = opt.headings; } - + this.extraTime = opt.hasOwnProperty("extraTime") ? opt.extraTime : 0; + this.extendedText = opt.hasOwnProperty("extendedText") ? opt.extendedText : "Extended Time"; return { theme: opt.hasOwnProperty("theme") ? opt.theme : "dark", + extraTime: opt.hasOwnProperty("extraTime") ? opt.extraTime : 0, + extendedText: opt.hasOwnProperty("extendedText") ? opt.extendedText : "Extended", headings: headings }; } @@ -111,48 +135,41 @@ var FlipDown = function () { key: "_init", value: function _init() { this.initialised = true; - if (this._hasCountdownEnded()) { this.daysremaining = 0; } else { this.daysremaining = Math.floor((this.epoch - this.now) / 86400).toString().length; } - var dayRotorCount = this.daysremaining <= 2 ? 2 : this.daysremaining; - for (var i = 0; i < dayRotorCount + 6; i++) { this.rotors.push(this._createRotor(0)); } - var dayRotors = []; - for (var i = 0; i < dayRotorCount; i++) { dayRotors.push(this.rotors[i]); } - this.element.appendChild(this._createRotorGroup(dayRotors, 0)); var count = dayRotorCount; - for (var i = 0; i < 3; i++) { var otherRotors = []; - for (var j = 0; j < 2; j++) { otherRotors.push(this.rotors[count]); count++; } - this.element.appendChild(this._createRotorGroup(otherRotors, i + 1)); } - this.rotorLeafFront = Array.prototype.slice.call(this.element.getElementsByClassName("rotor-leaf-front")); this.rotorLeafRear = Array.prototype.slice.call(this.element.getElementsByClassName("rotor-leaf-rear")); this.rotorTop = Array.prototype.slice.call(this.element.getElementsByClassName("rotor-top")); this.rotorBottom = Array.prototype.slice.call(this.element.getElementsByClassName("rotor-bottom")); - + if (this.extendedCountdown) { + this.extendedTextElement = document.createElement("h4"); + this.extendedTextElement.textContent = this.opts.extendedText; + this.extendedTextElement.classList.add("extended-text"); + this.element.appendChild(this.extendedTextElement); + } this._tick(); - this._updateClockValues(true); - return this; } }, { @@ -202,16 +219,13 @@ var FlipDown = function () { this.clockValues.m = Math.floor(diff / 60); diff -= this.clockValues.m * 60; this.clockValues.s = Math.floor(diff); - this._updateClockValues(); - this._hasCountdownEnded(); } }, { key: "_updateClockValues", value: function _updateClockValues() { - var _this = this; - + var _this3 = this; var init = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; this.clockStrings.d = pad(this.clockValues.d, 2); this.clockStrings.h = pad(this.clockValues.h, 2); @@ -219,37 +233,32 @@ var FlipDown = function () { this.clockStrings.s = pad(this.clockValues.s, 2); this.clockValuesAsString = (this.clockStrings.d + this.clockStrings.h + this.clockStrings.m + this.clockStrings.s).split(""); this.rotorLeafFront.forEach(function (el, i) { - el.textContent = _this.prevClockValuesAsString[i]; + el.textContent = _this3.prevClockValuesAsString[i]; }); this.rotorBottom.forEach(function (el, i) { - el.textContent = _this.prevClockValuesAsString[i]; + el.textContent = _this3.prevClockValuesAsString[i]; }); - function rotorTopFlip() { - var _this2 = this; - + var _this4 = this; this.rotorTop.forEach(function (el, i) { - if (el.textContent != _this2.clockValuesAsString[i]) { - el.textContent = _this2.clockValuesAsString[i]; + if (el.textContent != _this4.clockValuesAsString[i]) { + el.textContent = _this4.clockValuesAsString[i]; } }); } - function rotorLeafRearFlip() { - var _this3 = this; - + var _this5 = this; this.rotorLeafRear.forEach(function (el, i) { - if (el.textContent != _this3.clockValuesAsString[i]) { - el.textContent = _this3.clockValuesAsString[i]; + if (el.textContent != _this5.clockValuesAsString[i]) { + el.textContent = _this5.clockValuesAsString[i]; el.parentElement.classList.add("flipped"); var flip = setInterval(function () { el.parentElement.classList.remove("flipped"); clearInterval(flip); - }.bind(_this3), 500); + }.bind(_this5), 500); } }); } - if (!init) { setTimeout(rotorTopFlip.bind(this), 500); setTimeout(rotorLeafRearFlip.bind(this), 500); @@ -257,19 +266,15 @@ var FlipDown = function () { rotorTopFlip.call(this); rotorLeafRearFlip.call(this); } - this.prevClockValuesAsString = this.clockValuesAsString; } }]); - return FlipDown; }(); - function pad(n, len) { n = n.toString(); return n.length < len ? pad("0" + n, len) : n; } - function appendChildren(parent, children) { children.forEach(function (el) { parent.appendChild(el); diff --git a/dist/flipdown.min.js b/dist/flipdown.min.js index 51d6c7d..e4e1588 100644 --- a/dist/flipdown.min.js +++ b/dist/flipdown.min.js @@ -1 +1 @@ -"use strict";function _typeof(a){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a},_typeof(a)}function _classCallCheck(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}function _defineProperties(a,b){for(var c,d=0;dthis.epoch-this.now?(this.countdownEnded=!0,null!=this.hasEndedCallback&&(this.hasEndedCallback(),this.hasEndedCallback=null),!0):(this.countdownEnded=!1,!1)}},{key:"_parseOptions",value:function c(a){var b=["Days","Hours","Minutes","Seconds"];return a.headings&&4===a.headings.length&&(b=a.headings),{theme:a.hasOwnProperty("theme")?a.theme:"dark",headings:b}}},{key:"_setOptions",value:function a(){this.element.classList.add("flipdown__theme-".concat(this.opts.theme))}},{key:"_init",value:function h(){this.initialised=!0,this.daysremaining=this._hasCountdownEnded()?0:b((this.epoch-this.now)/86400).toString().length;for(var a=2>=this.daysremaining?2:this.daysremaining,c=0;cc;c++){e=[];for(var g=0;2>g;g++)e.push(this.rotors[f]),f++;this.element.appendChild(this._createRotorGroup(e,c+1))}return this.rotorLeafFront=Array.prototype.slice.call(this.element.getElementsByClassName("rotor-leaf-front")),this.rotorLeafRear=Array.prototype.slice.call(this.element.getElementsByClassName("rotor-leaf-rear")),this.rotorTop=Array.prototype.slice.call(this.element.getElementsByClassName("rotor-top")),this.rotorBottom=Array.prototype.slice.call(this.element.getElementsByClassName("rotor-bottom")),this._tick(),this._updateClockValues(!0),this}},{key:"_createRotorGroup",value:function e(a,b){var c=document.createElement("div");c.className="rotor-group";var d=document.createElement("div");return d.className="rotor-group-heading",d.setAttribute("data-before",this.opts.headings[b]),c.appendChild(d),appendChildren(c,a),c}},{key:"_createRotor",value:function h(){var a=0=this.epoch-this.now?0:this.epoch-this.now;this.clockValues.d=b(a/86400),a-=86400*this.clockValues.d,this.clockValues.h=b(a/3600),a-=3600*this.clockValues.h,this.clockValues.m=b(a/60),a-=60*this.clockValues.m,this.clockValues.s=b(a),this._updateClockValues(),this._hasCountdownEnded()}},{key:"_updateClockValues",value:function e(){function a(){var a=this;this.rotorTop.forEach(function(b,c){b.textContent!=a.clockValuesAsString[c]&&(b.textContent=a.clockValuesAsString[c])})}function b(){var a=this;this.rotorLeafRear.forEach(function(b,c){if(b.textContent!=a.clockValuesAsString[c]){b.textContent=a.clockValuesAsString[c],b.parentElement.classList.add("flipped");var d=setInterval(function(){b.parentElement.classList.remove("flipped"),clearInterval(d)}.bind(a),500)}})}var c=this,d=!!(0=this.epoch?(console.log("FlipDown: Extra time is set, extending countdown..."),this.epoch+=this.extraTime,this.extendedCountdown=!0,this._hasCountdownEnded(),this._setOptions(),this.initialised||this._init(),this._tick(),this.countdown=setInterval(this._tick.bind(this),1e3),this):(this.initialised||this._init(),this.countdown=setInterval(this._tick.bind(this),1e3),this)}},{key:"ifEnded",value:function ifEnded(a){var b=this;return this.hasEndedCallback=function(){a(),b.hasEndedCallback=null,0this.epoch-this.now?this.extendedCountdown?(this.extendedCountdown=!1,this.extendedCallback&&this.extendedCallback(),!0):(this.countdownEnded=!0,null!=this.hasEndedCallback&&(this.hasEndedCallback(),this.hasEndedCallback=null),!0):(this.countdownEnded=!1,!1)}},{key:"_parseOptions",value:function _parseOptions(a){var b=["Days","Hours","Minutes","Seconds"];return a.headings&&4===a.headings.length&&(b=a.headings),this.extraTime=a.hasOwnProperty("extraTime")?a.extraTime:0,this.extendedText=a.hasOwnProperty("extendedText")?a.extendedText:"Extended Time",{theme:a.hasOwnProperty("theme")?a.theme:"dark",extraTime:a.hasOwnProperty("extraTime")?a.extraTime:0,extendedText:a.hasOwnProperty("extendedText")?a.extendedText:"Extended",headings:b}}},{key:"_setOptions",value:function _setOptions(){this.element.classList.add("flipdown__theme-".concat(this.opts.theme))}},{key:"_init",value:function _init(){this.initialised=!0,this.daysremaining=this._hasCountdownEnded()?0:a((this.epoch-this.now)/86400).toString().length;for(var b=2>=this.daysremaining?2:this.daysremaining,c=0;cc;c++){e=[];for(var g=0;2>g;g++)e.push(this.rotors[f]),f++;this.element.appendChild(this._createRotorGroup(e,c+1))}return this.rotorLeafFront=Array.prototype.slice.call(this.element.getElementsByClassName("rotor-leaf-front")),this.rotorLeafRear=Array.prototype.slice.call(this.element.getElementsByClassName("rotor-leaf-rear")),this.rotorTop=Array.prototype.slice.call(this.element.getElementsByClassName("rotor-top")),this.rotorBottom=Array.prototype.slice.call(this.element.getElementsByClassName("rotor-bottom")),this.extendedCountdown&&(this.extendedTextElement=document.createElement("h4"),this.extendedTextElement.textContent=this.opts.extendedText,this.extendedTextElement.classList.add("extended-text"),this.element.appendChild(this.extendedTextElement)),this._tick(),this._updateClockValues(!0),this}},{key:"_createRotorGroup",value:function _createRotorGroup(a,b){var c=document.createElement("div");c.className="rotor-group";var d=document.createElement("div");return d.className="rotor-group-heading",d.setAttribute("data-before",this.opts.headings[b]),c.appendChild(d),appendChildren(c,a),c}},{key:"_createRotor",value:function _createRotor(){var a=0=this.epoch-this.now?0:this.epoch-this.now;this.clockValues.d=a(b/86400),b-=86400*this.clockValues.d,this.clockValues.h=a(b/3600),b-=3600*this.clockValues.h,this.clockValues.m=a(b/60),b-=60*this.clockValues.m,this.clockValues.s=a(b),this._updateClockValues(),this._hasCountdownEnded()}},{key:"_updateClockValues",value:function _updateClockValues(){function a(){var a=this;this.rotorTop.forEach(function(b,c){b.textContent!=a.clockValuesAsString[c]&&(b.textContent=a.clockValuesAsString[c])})}function b(){var a=this;this.rotorLeafRear.forEach(function(b,c){if(b.textContent!=a.clockValuesAsString[c]){b.textContent=a.clockValuesAsString[c],b.parentElement.classList.add("flipped");var d=setInterval(function(){b.parentElement.classList.remove("flipped"),clearInterval(d)}.bind(a),500)}})}var c=this,d=!!(0FlipDown.js

⏰ A lightweight and performant flip styled countdown clock

+

Version: (<11KB minified)

Get started diff --git a/example/js/flipdown/flipdown.js b/example/js/flipdown/flipdown.js index f53e9e1..edc6505 100644 --- a/example/js/flipdown/flipdown.js +++ b/example/js/flipdown/flipdown.js @@ -1,29 +1,26 @@ "use strict"; -function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } - +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } +function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } var FlipDown = function () { function FlipDown(uts) { var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "flipdown"; var opt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - _classCallCheck(this, FlipDown); - + this.extendedCountdown = false; + this.extraTime = 0; + this.extendedCallback = null; if (typeof uts !== "number") { throw new Error("FlipDown: Constructor expected unix timestamp, got ".concat(_typeof(uts), " instead.")); } - if (_typeof(el) === "object") { opt = el; el = "flipdown"; } - this.version = "0.3.2"; this.initialised = false; this.now = this._getTime(); @@ -43,15 +40,23 @@ var FlipDown = function () { this.clockValuesAsString = []; this.prevClockValuesAsString = []; this.opts = this._parseOptions(opt); - this._setOptions(); - console.log("FlipDown ".concat(this.version, " (Theme: ").concat(this.opts.theme, ")")); } - _createClass(FlipDown, [{ key: "start", value: function start() { + if (this.extraTime > 0 && this._getTime() >= this.epoch) { + console.log("FlipDown: Extra time is set, extending countdown..."); + this.epoch += this.extraTime; + this.extendedCountdown = true; + this._hasCountdownEnded(); + this._setOptions(); + if (!this.initialised) this._init(); + this._tick(); + this.countdown = setInterval(this._tick.bind(this), 1000); + return this; + } if (!this.initialised) this._init(); this.countdown = setInterval(this._tick.bind(this), 1000); return this; @@ -59,13 +64,25 @@ var FlipDown = function () { }, { key: "ifEnded", value: function ifEnded(cb) { + var _this = this; this.hasEndedCallback = function () { cb(); - this.hasEndedCallback = null; + _this.hasEndedCallback = null; + if (_this.extraTime > 0) { + _this.start(); + } }; - return this; } + }, { + key: "ifExtendedEnded", + value: function ifExtendedEnded(cb) { + var _this2 = this; + this.extendedCallback = function () { + cb(); + _this2.extendedCallback = null; + }; + } }, { key: "_getTime", value: function _getTime() { @@ -75,13 +92,18 @@ var FlipDown = function () { key: "_hasCountdownEnded", value: function _hasCountdownEnded() { if (this.epoch - this.now < 0) { + if (this.extendedCountdown) { + this.extendedCountdown = false; + if (this.extendedCallback) { + this.extendedCallback(); + } + return true; + } this.countdownEnded = true; - if (this.hasEndedCallback != null) { this.hasEndedCallback(); this.hasEndedCallback = null; } - return true; } else { this.countdownEnded = false; @@ -92,13 +114,15 @@ var FlipDown = function () { key: "_parseOptions", value: function _parseOptions(opt) { var headings = ["Days", "Hours", "Minutes", "Seconds"]; - if (opt.headings && opt.headings.length === 4) { headings = opt.headings; } - + this.extraTime = opt.hasOwnProperty("extraTime") ? opt.extraTime : 0; + this.extendedText = opt.hasOwnProperty("extendedText") ? opt.extendedText : "Extended Time"; return { theme: opt.hasOwnProperty("theme") ? opt.theme : "dark", + extraTime: opt.hasOwnProperty("extraTime") ? opt.extraTime : 0, + extendedText: opt.hasOwnProperty("extendedText") ? opt.extendedText : "Extended", headings: headings }; } @@ -111,48 +135,41 @@ var FlipDown = function () { key: "_init", value: function _init() { this.initialised = true; - if (this._hasCountdownEnded()) { this.daysremaining = 0; } else { this.daysremaining = Math.floor((this.epoch - this.now) / 86400).toString().length; } - var dayRotorCount = this.daysremaining <= 2 ? 2 : this.daysremaining; - for (var i = 0; i < dayRotorCount + 6; i++) { this.rotors.push(this._createRotor(0)); } - var dayRotors = []; - for (var i = 0; i < dayRotorCount; i++) { dayRotors.push(this.rotors[i]); } - this.element.appendChild(this._createRotorGroup(dayRotors, 0)); var count = dayRotorCount; - for (var i = 0; i < 3; i++) { var otherRotors = []; - for (var j = 0; j < 2; j++) { otherRotors.push(this.rotors[count]); count++; } - this.element.appendChild(this._createRotorGroup(otherRotors, i + 1)); } - this.rotorLeafFront = Array.prototype.slice.call(this.element.getElementsByClassName("rotor-leaf-front")); this.rotorLeafRear = Array.prototype.slice.call(this.element.getElementsByClassName("rotor-leaf-rear")); this.rotorTop = Array.prototype.slice.call(this.element.getElementsByClassName("rotor-top")); this.rotorBottom = Array.prototype.slice.call(this.element.getElementsByClassName("rotor-bottom")); - + if (this.extendedCountdown) { + this.extendedTextElement = document.createElement("h4"); + this.extendedTextElement.textContent = this.opts.extendedText; + this.extendedTextElement.classList.add("extended-text"); + this.element.appendChild(this.extendedTextElement); + } this._tick(); - this._updateClockValues(true); - return this; } }, { @@ -202,16 +219,13 @@ var FlipDown = function () { this.clockValues.m = Math.floor(diff / 60); diff -= this.clockValues.m * 60; this.clockValues.s = Math.floor(diff); - this._updateClockValues(); - this._hasCountdownEnded(); } }, { key: "_updateClockValues", value: function _updateClockValues() { - var _this = this; - + var _this3 = this; var init = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; this.clockStrings.d = pad(this.clockValues.d, 2); this.clockStrings.h = pad(this.clockValues.h, 2); @@ -219,37 +233,32 @@ var FlipDown = function () { this.clockStrings.s = pad(this.clockValues.s, 2); this.clockValuesAsString = (this.clockStrings.d + this.clockStrings.h + this.clockStrings.m + this.clockStrings.s).split(""); this.rotorLeafFront.forEach(function (el, i) { - el.textContent = _this.prevClockValuesAsString[i]; + el.textContent = _this3.prevClockValuesAsString[i]; }); this.rotorBottom.forEach(function (el, i) { - el.textContent = _this.prevClockValuesAsString[i]; + el.textContent = _this3.prevClockValuesAsString[i]; }); - function rotorTopFlip() { - var _this2 = this; - + var _this4 = this; this.rotorTop.forEach(function (el, i) { - if (el.textContent != _this2.clockValuesAsString[i]) { - el.textContent = _this2.clockValuesAsString[i]; + if (el.textContent != _this4.clockValuesAsString[i]) { + el.textContent = _this4.clockValuesAsString[i]; } }); } - function rotorLeafRearFlip() { - var _this3 = this; - + var _this5 = this; this.rotorLeafRear.forEach(function (el, i) { - if (el.textContent != _this3.clockValuesAsString[i]) { - el.textContent = _this3.clockValuesAsString[i]; + if (el.textContent != _this5.clockValuesAsString[i]) { + el.textContent = _this5.clockValuesAsString[i]; el.parentElement.classList.add("flipped"); var flip = setInterval(function () { el.parentElement.classList.remove("flipped"); clearInterval(flip); - }.bind(_this3), 500); + }.bind(_this5), 500); } }); } - if (!init) { setTimeout(rotorTopFlip.bind(this), 500); setTimeout(rotorLeafRearFlip.bind(this), 500); @@ -257,19 +266,15 @@ var FlipDown = function () { rotorTopFlip.call(this); rotorLeafRearFlip.call(this); } - this.prevClockValuesAsString = this.clockValuesAsString; } }]); - return FlipDown; }(); - function pad(n, len) { n = n.toString(); return n.length < len ? pad("0" + n, len) : n; } - function appendChildren(parent, children) { children.forEach(function (el) { parent.appendChild(el); diff --git a/example/js/main.js b/example/js/main.js index 8fd8102..b76a75a 100644 --- a/example/js/main.js +++ b/example/js/main.js @@ -1,28 +1,37 @@ document.addEventListener('DOMContentLoaded', () => { - // Unix timestamp (in seconds) to count down to - var twoDaysFromNow = (new Date().getTime() / 1000) + (86400 * 2) + 1; + // Unix timestamp (in seconds) to count down to + const fifteenSeconds = Math.floor(new Date().getTime() / 1000) + 2; + const fiveDays3Hours2Minutes = 5 * 24 * 60 * 60 + 3 * 60 * 60 + 2 * 60; - // Set up FlipDown - var flipdown = new FlipDown(twoDaysFromNow) + // Set up FlipDown with extra time and extended text + const flipdown = new FlipDown(fifteenSeconds, 'flipdown', { + extraTime: fiveDays3Hours2Minutes, // Set the extra time in seconds + }); // Start the countdown - .start() + flipdown.start(); + + // Do something when the initial countdown ends + flipdown.ifEnded(() => { + console.log('The initial countdown has ended!'); + document.body.querySelector('#extended').style.display = 'block'; + }); - // Do something when the countdown ends - .ifEnded(() => { - console.log('The countdown has ended!'); + // Do something when the extended countdown ends + flipdown.ifExtendedEnded(() => { + console.log('The extended countdown has ended!'); }); - // Toggle theme - var interval = setInterval(() => { - let body = document.body; - body.classList.toggle('light-theme'); - body.querySelector('#flipdown').classList.toggle('flipdown__theme-dark'); - body.querySelector('#flipdown').classList.toggle('flipdown__theme-light'); - }, 5000); + // Toggle theme + var interval = setInterval(() => { + let body = document.body; + body.classList.toggle('light-theme'); + body.querySelector('#flipdown').classList.toggle('flipdown__theme-dark'); + body.querySelector('#flipdown').classList.toggle('flipdown__theme-light'); + }, 5000); - // Show version number - var ver = document.getElementById('ver'); - ver.innerHTML = flipdown.version; + // Show version number + var ver = document.getElementById('ver'); + ver.innerHTML = flipdown.version; }); diff --git a/src/flipdown.js b/src/flipdown.js index 35829cd..579f05c 100644 --- a/src/flipdown.js +++ b/src/flipdown.js @@ -8,10 +8,15 @@ **/ class FlipDown { constructor(uts, el = "flipdown", opt = {}) { + // Initialize extended countdown properties + this.extendedCountdown = false; + this.extraTime = 0; + this.extendedCallback = null; + // If uts is not specified if (typeof uts !== "number") { throw new Error( - `FlipDown: Constructor expected unix timestamp, got ${typeof uts} instead.` + `FlipDown: Constructor expected unix timestamp, got ${typeof uts} instead.` ); } @@ -81,6 +86,18 @@ class FlipDown { * @author PButcher **/ start() { + if (this.extraTime > 0 && this._getTime() >= this.epoch) { + console.log("FlipDown: Extra time is set, extending countdown...") + this.epoch += this.extraTime; + this.extendedCountdown = true; + this._hasCountdownEnded(); // Check if the extended countdown has ended + this._setOptions(); + if (!this.initialised) this._init(); + this._tick(); + this.countdown = setInterval(this._tick.bind(this), 1000); + return this; + } + // Initialise the clock if (!this.initialised) this._init(); @@ -98,15 +115,29 @@ class FlipDown { * @param {function} cb - Callback **/ ifEnded(cb) { - this.hasEndedCallback = function () { + this.hasEndedCallback = () => { cb(); this.hasEndedCallback = null; + + if (this.extraTime > 0) { + this.start(); + } }; // Chainable return this; } + + + ifExtendedEnded(cb) { + this.extendedCallback = () => { + cb(); + this.extendedCallback = null; + }; + } + + /** * @name _getTime * @description Get the time in seconds (unix timestamp) @@ -124,6 +155,15 @@ class FlipDown { _hasCountdownEnded() { // Countdown has ended if (this.epoch - this.now < 0) { + + if (this.extendedCountdown) { + this.extendedCountdown = false; + if (this.extendedCallback) { + this.extendedCallback(); + } + return true; + } + this.countdownEnded = true; // Fire the ifEnded callback once if it was set @@ -155,9 +195,13 @@ class FlipDown { if (opt.headings && opt.headings.length === 4) { headings = opt.headings; } + this.extraTime = opt.hasOwnProperty("extraTime") ? opt.extraTime : 0; + this.extendedText = opt.hasOwnProperty("extendedText") ? opt.extendedText : "Extended Time"; return { // Theme theme: opt.hasOwnProperty("theme") ? opt.theme : "dark", + extraTime: opt.hasOwnProperty("extraTime") ? opt.extraTime : 0, + extendedText: opt.hasOwnProperty("extendedText") ? opt.extendedText : "Extended", headings, }; } @@ -185,7 +229,7 @@ class FlipDown { this.daysremaining = 0; } else { this.daysremaining = Math.floor( - (this.epoch - this.now) / 86400 + (this.epoch - this.now) / 86400 ).toString().length; } var dayRotorCount = this.daysremaining <= 2 ? 2 : this.daysremaining; @@ -215,18 +259,26 @@ class FlipDown { // Store and convert rotor nodelists to arrays this.rotorLeafFront = Array.prototype.slice.call( - this.element.getElementsByClassName("rotor-leaf-front") + this.element.getElementsByClassName("rotor-leaf-front") ); this.rotorLeafRear = Array.prototype.slice.call( - this.element.getElementsByClassName("rotor-leaf-rear") + this.element.getElementsByClassName("rotor-leaf-rear") ); this.rotorTop = Array.prototype.slice.call( - this.element.getElementsByClassName("rotor-top") + this.element.getElementsByClassName("rotor-top") ); this.rotorBottom = Array.prototype.slice.call( - this.element.getElementsByClassName("rotor-bottom") + this.element.getElementsByClassName("rotor-bottom") ); + // Add extended time text if extended countdown is active + if (this.extendedCountdown) { + this.extendedTextElement = document.createElement("h4"); + this.extendedTextElement.textContent = this.opts.extendedText; + this.extendedTextElement.classList.add("extended-text"); + this.element.appendChild(this.extendedTextElement); + } + // Set initial values; this._tick(); this._updateClockValues(true); @@ -246,8 +298,8 @@ class FlipDown { var dayRotorGroupHeading = document.createElement("div"); dayRotorGroupHeading.className = "rotor-group-heading"; dayRotorGroupHeading.setAttribute( - "data-before", - this.opts.headings[rotorIndex] + "data-before", + this.opts.headings[rotorIndex] ); rotorGroup.appendChild(dayRotorGroupHeading); appendChildren(rotorGroup, rotors); @@ -330,10 +382,10 @@ class FlipDown { // Concat clock value strings this.clockValuesAsString = ( - this.clockStrings.d + - this.clockStrings.h + - this.clockStrings.m + - this.clockStrings.s + this.clockStrings.d + + this.clockStrings.h + + this.clockStrings.m + + this.clockStrings.s ).split(""); // Update rotor values @@ -365,11 +417,11 @@ class FlipDown { el.textContent = this.clockValuesAsString[i]; el.parentElement.classList.add("flipped"); var flip = setInterval( - function () { - el.parentElement.classList.remove("flipped"); - clearInterval(flip); - }.bind(this), - 500 + function () { + el.parentElement.classList.remove("flipped"); + clearInterval(flip); + }.bind(this), + 500 ); } });