From 28fc4c1c68bff17130be7af0a2065a30909ba9ac Mon Sep 17 00:00:00 2001 From: Usman Khan <2btech.dev2@gmail.com> Date: Mon, 7 Aug 2023 15:26:40 +0500 Subject: [PATCH 1/4] Extended Time Functionality Added --- .idea/.gitignore | 5 + .idea/flipdown.iml | 13 + .idea/jsLibraryMappings.xml | 6 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + README.md | 57 ++- dist/flipdown.css | 283 --------------- dist/flipdown.js | 277 -------------- dist/flipdown.min.css | 1 - dist/flipdown.min.js | 1 - example/css/flipdown/flipdown.css | 283 --------------- example/index.html | 1 + example/js/flipdown/flipdown.js | 580 +++++++++++++++++++----------- example/js/main.js | 45 ++- src/flipdown.js | 29 ++ 15 files changed, 516 insertions(+), 1079 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/flipdown.iml create mode 100644 .idea/jsLibraryMappings.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml delete mode 100644 dist/flipdown.css delete mode 100644 dist/flipdown.js delete mode 100644 dist/flipdown.min.css delete mode 100644 dist/flipdown.min.js delete mode 100644 example/css/flipdown/flipdown.css 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/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.css b/dist/flipdown.css deleted file mode 100644 index 9531476..0000000 --- a/dist/flipdown.css +++ /dev/null @@ -1,283 +0,0 @@ -/* THEMES */ - -/********** Theme: dark **********/ -/* Font styles */ -.flipdown.flipdown__theme-dark { - font-family: sans-serif; - font-weight: bold; -} -/* Rotor group headings */ -.flipdown.flipdown__theme-dark .rotor-group-heading:before { - color: #000000; -} -/* Delimeters */ -.flipdown.flipdown__theme-dark .rotor-group:nth-child(n+2):nth-child(-n+3):before, -.flipdown.flipdown__theme-dark .rotor-group:nth-child(n+2):nth-child(-n+3):after { - background-color: #151515; -} -/* Rotor tops */ -.flipdown.flipdown__theme-dark .rotor, -.flipdown.flipdown__theme-dark .rotor-top, -.flipdown.flipdown__theme-dark .rotor-leaf-front { - color: #FFFFFF; - background-color: #151515; -} -/* Rotor bottoms */ -.flipdown.flipdown__theme-dark .rotor-bottom, -.flipdown.flipdown__theme-dark .rotor-leaf-rear { - color: #EFEFEF; - background-color: #202020; -} -/* Hinge */ -.flipdown.flipdown__theme-dark .rotor:after { - border-top: solid 1px #151515; -} - -/********** Theme: light **********/ -/* Font styles */ -.flipdown.flipdown__theme-light { - font-family: sans-serif; - font-weight: bold; -} -/* Rotor group headings */ -.flipdown.flipdown__theme-light .rotor-group-heading:before { - color: #EEEEEE; -} -/* Delimeters */ -.flipdown.flipdown__theme-light .rotor-group:nth-child(n+2):nth-child(-n+3):before, -.flipdown.flipdown__theme-light .rotor-group:nth-child(n+2):nth-child(-n+3):after { - background-color: #DDDDDD; -} -/* Rotor tops */ -.flipdown.flipdown__theme-light .rotor, -.flipdown.flipdown__theme-light .rotor-top, -.flipdown.flipdown__theme-light .rotor-leaf-front { - color: #222222; - background-color: #DDDDDD; -} -/* Rotor bottoms */ -.flipdown.flipdown__theme-light .rotor-bottom, -.flipdown.flipdown__theme-light .rotor-leaf-rear { - color: #333333; - background-color: #EEEEEE; -} -/* Hinge */ -.flipdown.flipdown__theme-light .rotor:after { - border-top: solid 1px #222222; -} - -/* END OF THEMES */ - -.flipdown { - overflow: visible; - width: 510px; - height: 110px; -} - -.flipdown .rotor-group { - position: relative; - float: left; - padding-right: 30px; -} - -.flipdown .rotor-group:last-child { - padding-right: 0; -} - -.flipdown .rotor-group-heading:before { - display: block; - height: 30px; - line-height: 30px; - text-align: center; -} - -.flipdown .rotor-group:nth-child(1) .rotor-group-heading:before { - content: attr(data-before); -} - -.flipdown .rotor-group:nth-child(2) .rotor-group-heading:before { - content: attr(data-before); -} - -.flipdown .rotor-group:nth-child(3) .rotor-group-heading:before { - content: attr(data-before); -} - -.flipdown .rotor-group:nth-child(4) .rotor-group-heading:before { - content: attr(data-before); -} - -.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before { - content: ''; - position: absolute; - bottom: 20px; - left: 115px; - width: 10px; - height: 10px; - border-radius: 50%; -} - -.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after { - content: ''; - position: absolute; - bottom: 50px; - left: 115px; - width: 10px; - height: 10px; - border-radius: 50%; -} - -.flipdown .rotor { - position: relative; - float: left; - width: 50px; - height: 80px; - margin: 0px 5px 0px 0px; - border-radius: 4px; - font-size: 4rem; - text-align: center; - perspective: 200px; -} - -.flipdown .rotor:last-child { - margin-right: 0; -} - -.flipdown .rotor-top, -.flipdown .rotor-bottom { - overflow: hidden; - position: absolute; - width: 50px; - height: 40px; -} - -.flipdown .rotor-leaf { - z-index: 1; - position: absolute; - width: 50px; - height: 80px; - transform-style: preserve-3d; - transition: transform 0s; -} - -.flipdown .rotor-leaf.flipped { - transform: rotateX(-180deg); - transition: all 0.5s ease-in-out; -} - -.flipdown .rotor-leaf-front, -.flipdown .rotor-leaf-rear { - overflow: hidden; - position: absolute; - width: 50px; - height: 40px; - margin: 0; - transform: rotateX(0deg); - backface-visibility: hidden; - -webkit-backface-visibility: hidden; -} - -.flipdown .rotor-leaf-front { - line-height: 80px; - border-radius: 4px 4px 0px 0px; -} - -.flipdown .rotor-leaf-rear { - line-height: 0px; - border-radius: 0px 0px 4px 4px; - transform: rotateX(-180deg); -} - -.flipdown .rotor-top { - line-height: 80px; - border-radius: 4px 4px 0px 0px; -} - -.flipdown .rotor-bottom { - bottom: 0; - line-height: 0px; - border-radius: 0px 0px 4px 4px; -} - -.flipdown .rotor:after { - content: ''; - z-index: 2; - position: absolute; - bottom: 0px; - left: 0px; - width: 50px; - height: 40px; - border-radius: 0px 0px 4px 4px; -} - -@media (max-width: 550px) { - - .flipdown { - width: 312px; - height: 70px; - } - - .flipdown .rotor { - font-size: 2.2rem; - margin-right: 3px; - } - - .flipdown .rotor, - .flipdown .rotor-leaf, - .flipdown .rotor-leaf-front, - .flipdown .rotor-leaf-rear, - .flipdown .rotor-top, - .flipdown .rotor-bottom, - .flipdown .rotor:after { - width: 30px; - } - - .flipdown .rotor-group { - padding-right: 20px; - } - - .flipdown .rotor-group:last-child { - padding-right: 0px; - } - - .flipdown .rotor-group-heading:before { - font-size: 0.8rem; - height: 20px; - line-height: 20px; - } - - .flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before, - .flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after { - left: 69px; - } - - .flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before { - bottom: 13px; - height: 8px; - width: 8px; - } - - .flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after { - bottom: 29px; - height: 8px; - width: 8px; - } - - .flipdown .rotor-leaf-front, - .flipdown .rotor-top { - line-height: 50px; - } - - .flipdown .rotor-leaf, - .flipdown .rotor { - height: 50px; - } - - .flipdown .rotor-leaf-front, - .flipdown .rotor-leaf-rear, - .flipdown .rotor-top, - .flipdown .rotor-bottom, - .flipdown .rotor:after { - height: 25px; - } -} diff --git a/dist/flipdown.js b/dist/flipdown.js deleted file mode 100644 index f53e9e1..0000000 --- a/dist/flipdown.js +++ /dev/null @@ -1,277 +0,0 @@ -"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 _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; } - -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); - - 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(); - this.epoch = uts; - this.countdownEnded = false; - this.hasEndedCallback = null; - this.element = document.getElementById(el); - this.rotors = []; - this.rotorLeafFront = []; - this.rotorLeafRear = []; - this.rotorTops = []; - this.rotorBottoms = []; - this.countdown = null; - this.daysRemaining = 0; - this.clockValues = {}; - this.clockStrings = {}; - 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.initialised) this._init(); - this.countdown = setInterval(this._tick.bind(this), 1000); - return this; - } - }, { - key: "ifEnded", - value: function ifEnded(cb) { - this.hasEndedCallback = function () { - cb(); - this.hasEndedCallback = null; - }; - - return this; - } - }, { - key: "_getTime", - value: function _getTime() { - return new Date().getTime() / 1000; - } - }, { - key: "_hasCountdownEnded", - value: function _hasCountdownEnded() { - if (this.epoch - this.now < 0) { - this.countdownEnded = true; - - if (this.hasEndedCallback != null) { - this.hasEndedCallback(); - this.hasEndedCallback = null; - } - - return true; - } else { - this.countdownEnded = false; - return false; - } - } - }, { - key: "_parseOptions", - value: function _parseOptions(opt) { - var headings = ["Days", "Hours", "Minutes", "Seconds"]; - - if (opt.headings && opt.headings.length === 4) { - headings = opt.headings; - } - - return { - theme: opt.hasOwnProperty("theme") ? opt.theme : "dark", - headings: headings - }; - } - }, { - key: "_setOptions", - value: function _setOptions() { - this.element.classList.add("flipdown__theme-".concat(this.opts.theme)); - } - }, { - 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")); - - this._tick(); - - this._updateClockValues(true); - - return this; - } - }, { - key: "_createRotorGroup", - value: function _createRotorGroup(rotors, rotorIndex) { - var rotorGroup = document.createElement("div"); - rotorGroup.className = "rotor-group"; - var dayRotorGroupHeading = document.createElement("div"); - dayRotorGroupHeading.className = "rotor-group-heading"; - dayRotorGroupHeading.setAttribute("data-before", this.opts.headings[rotorIndex]); - rotorGroup.appendChild(dayRotorGroupHeading); - appendChildren(rotorGroup, rotors); - return rotorGroup; - } - }, { - key: "_createRotor", - value: function _createRotor() { - var v = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; - var rotor = document.createElement("div"); - var rotorLeaf = document.createElement("div"); - var rotorLeafRear = document.createElement("figure"); - var rotorLeafFront = document.createElement("figure"); - var rotorTop = document.createElement("div"); - var rotorBottom = document.createElement("div"); - rotor.className = "rotor"; - rotorLeaf.className = "rotor-leaf"; - rotorLeafRear.className = "rotor-leaf-rear"; - rotorLeafFront.className = "rotor-leaf-front"; - rotorTop.className = "rotor-top"; - rotorBottom.className = "rotor-bottom"; - rotorLeafRear.textContent = v; - rotorTop.textContent = v; - rotorBottom.textContent = v; - appendChildren(rotor, [rotorLeaf, rotorTop, rotorBottom]); - appendChildren(rotorLeaf, [rotorLeafRear, rotorLeafFront]); - return rotor; - } - }, { - key: "_tick", - value: function _tick() { - this.now = this._getTime(); - var diff = this.epoch - this.now <= 0 ? 0 : this.epoch - this.now; - this.clockValues.d = Math.floor(diff / 86400); - diff -= this.clockValues.d * 86400; - this.clockValues.h = Math.floor(diff / 3600); - diff -= this.clockValues.h * 3600; - 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 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); - this.clockStrings.m = pad(this.clockValues.m, 2); - 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]; - }); - this.rotorBottom.forEach(function (el, i) { - el.textContent = _this.prevClockValuesAsString[i]; - }); - - function rotorTopFlip() { - var _this2 = this; - - this.rotorTop.forEach(function (el, i) { - if (el.textContent != _this2.clockValuesAsString[i]) { - el.textContent = _this2.clockValuesAsString[i]; - } - }); - } - - function rotorLeafRearFlip() { - var _this3 = this; - - this.rotorLeafRear.forEach(function (el, i) { - if (el.textContent != _this3.clockValuesAsString[i]) { - el.textContent = _this3.clockValuesAsString[i]; - el.parentElement.classList.add("flipped"); - var flip = setInterval(function () { - el.parentElement.classList.remove("flipped"); - clearInterval(flip); - }.bind(_this3), 500); - } - }); - } - - if (!init) { - setTimeout(rotorTopFlip.bind(this), 500); - setTimeout(rotorLeafRearFlip.bind(this), 500); - } else { - 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.css b/dist/flipdown.min.css deleted file mode 100644 index b4bed07..0000000 --- a/dist/flipdown.min.css +++ /dev/null @@ -1 +0,0 @@ -.flipdown.flipdown__theme-dark{font-family:sans-serif;font-weight:bold}.flipdown.flipdown__theme-dark .rotor-group-heading:before{color:#000}.flipdown.flipdown__theme-dark .rotor-group:nth-child(n+2):nth-child(-n+3):before,.flipdown.flipdown__theme-dark .rotor-group:nth-child(n+2):nth-child(-n+3):after{background-color:#151515}.flipdown.flipdown__theme-dark .rotor,.flipdown.flipdown__theme-dark .rotor-top,.flipdown.flipdown__theme-dark .rotor-leaf-front{color:#fff;background-color:#151515}.flipdown.flipdown__theme-dark .rotor-bottom,.flipdown.flipdown__theme-dark .rotor-leaf-rear{color:#efefef;background-color:#202020}.flipdown.flipdown__theme-dark .rotor:after{border-top:solid 1px #151515}.flipdown.flipdown__theme-light{font-family:sans-serif;font-weight:bold}.flipdown.flipdown__theme-light .rotor-group-heading:before{color:#eee}.flipdown.flipdown__theme-light .rotor-group:nth-child(n+2):nth-child(-n+3):before,.flipdown.flipdown__theme-light .rotor-group:nth-child(n+2):nth-child(-n+3):after{background-color:#ddd}.flipdown.flipdown__theme-light .rotor,.flipdown.flipdown__theme-light .rotor-top,.flipdown.flipdown__theme-light .rotor-leaf-front{color:#222;background-color:#ddd}.flipdown.flipdown__theme-light .rotor-bottom,.flipdown.flipdown__theme-light .rotor-leaf-rear{color:#333;background-color:#eee}.flipdown.flipdown__theme-light .rotor:after{border-top:solid 1px #222}.flipdown{overflow:visible;width:510px;height:110px}.flipdown .rotor-group{position:relative;float:left;padding-right:30px}.flipdown .rotor-group:last-child{padding-right:0}.flipdown .rotor-group-heading:before{display:block;height:30px;line-height:30px;text-align:center}.flipdown .rotor-group:nth-child(1) .rotor-group-heading:before{content:attr(data-before)}.flipdown .rotor-group:nth-child(2) .rotor-group-heading:before{content:attr(data-before)}.flipdown .rotor-group:nth-child(3) .rotor-group-heading:before{content:attr(data-before)}.flipdown .rotor-group:nth-child(4) .rotor-group-heading:before{content:attr(data-before)}.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before{content:'';position:absolute;bottom:20px;left:115px;width:10px;height:10px;border-radius:50%}.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after{content:'';position:absolute;bottom:50px;left:115px;width:10px;height:10px;border-radius:50%}.flipdown .rotor{position:relative;float:left;width:50px;height:80px;margin:0 5px 0 0;border-radius:4px;font-size:4rem;text-align:center;perspective:200px}.flipdown .rotor:last-child{margin-right:0}.flipdown .rotor-top,.flipdown .rotor-bottom{overflow:hidden;position:absolute;width:50px;height:40px}.flipdown .rotor-leaf{z-index:1;position:absolute;width:50px;height:80px;transform-style:preserve-3d;transition:transform 0s}.flipdown .rotor-leaf.flipped{transform:rotateX(-180deg);transition:all .5s ease-in-out}.flipdown .rotor-leaf-front,.flipdown .rotor-leaf-rear{overflow:hidden;position:absolute;width:50px;height:40px;margin:0;transform:rotateX(0);backface-visibility:hidden;-webkit-backface-visibility:hidden}.flipdown .rotor-leaf-front{line-height:80px;border-radius:4px 4px 0 0}.flipdown .rotor-leaf-rear{line-height:0;border-radius:0 0 4px 4px;transform:rotateX(-180deg)}.flipdown .rotor-top{line-height:80px;border-radius:4px 4px 0 0}.flipdown .rotor-bottom{bottom:0;line-height:0;border-radius:0 0 4px 4px}.flipdown .rotor:after{content:'';z-index:2;position:absolute;bottom:0;left:0;width:50px;height:40px;border-radius:0 0 4px 4px}@media(max-width:550px){.flipdown{width:312px;height:70px}.flipdown .rotor{font-size:2.2rem;margin-right:3px}.flipdown .rotor,.flipdown .rotor-leaf,.flipdown .rotor-leaf-front,.flipdown .rotor-leaf-rear,.flipdown .rotor-top,.flipdown .rotor-bottom,.flipdown .rotor:after{width:30px}.flipdown .rotor-group{padding-right:20px}.flipdown .rotor-group:last-child{padding-right:0}.flipdown .rotor-group-heading:before{font-size:.8rem;height:20px;line-height:20px}.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before,.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after{left:69px}.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before{bottom:13px;height:8px;width:8px}.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after{bottom:29px;height:8px;width:8px}.flipdown .rotor-leaf-front,.flipdown .rotor-top{line-height:50px}.flipdown .rotor-leaf,.flipdown .rotor{height:50px}.flipdown .rotor-leaf-front,.flipdown .rotor-leaf-rear,.flipdown .rotor-top,.flipdown .rotor-bottom,.flipdown .rotor:after{height:25px}} diff --git a/dist/flipdown.min.js b/dist/flipdown.min.js deleted file mode 100644 index 51d6c7d..0000000 --- a/dist/flipdown.min.js +++ /dev/null @@ -1 +0,0 @@ -"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=!!(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..27bd255 100644 --- a/example/js/flipdown/flipdown.js +++ b/example/js/flipdown/flipdown.js @@ -1,277 +1,457 @@ -"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 _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; } - -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); - +/** + * @name FlipDown + * @description Flip styled countdown clock + * @author Peter Butcher (PButcher) + * @param {number} uts - Time to count down to as unix timestamp + * @param {string} el - DOM element to attach FlipDown to + * @param {object} opt - Optional configuration settings + **/ +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 ".concat(_typeof(uts), " instead.")); + throw new Error( + `FlipDown: Constructor expected unix timestamp, got ${typeof uts} instead.` + ); } - if (_typeof(el) === "object") { + // If opt is specified, but not el + if (typeof el === "object") { opt = el; el = "flipdown"; } + // FlipDown version this.version = "0.3.2"; + + // Initialised? this.initialised = false; + + // Time at instantiation in seconds this.now = this._getTime(); + + // UTS to count down to this.epoch = uts; + + // UTS passed to FlipDown is in the past this.countdownEnded = false; + + // User defined callback for countdown end this.hasEndedCallback = null; + + // FlipDown DOM element this.element = document.getElementById(el); + + // Rotor DOM elements this.rotors = []; this.rotorLeafFront = []; this.rotorLeafRear = []; this.rotorTops = []; this.rotorBottoms = []; + + // Interval this.countdown = null; + + // Number of days remaining this.daysRemaining = 0; + + // Clock values as numbers this.clockValues = {}; + + // Clock values as strings this.clockStrings = {}; + + // Clock values as array this.clockValuesAsString = []; this.prevClockValuesAsString = []; + + // Parse options this.opts = this._parseOptions(opt); + // Set options this._setOptions(); - console.log("FlipDown ".concat(this.version, " (Theme: ").concat(this.opts.theme, ")")); + // Print Version + console.log(`FlipDown ${this.version} (Theme: ${this.opts.theme})`); } - _createClass(FlipDown, [{ - key: "start", - value: function start() { + /** + * @name start + * @description Start the countdown + * @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; } - }, { - key: "ifEnded", - value: function ifEnded(cb) { - this.hasEndedCallback = function () { - cb(); - this.hasEndedCallback = null; - }; - return this; - } - }, { - key: "_getTime", - value: function _getTime() { - return new Date().getTime() / 1000; - } - }, { - key: "_hasCountdownEnded", - value: function _hasCountdownEnded() { - if (this.epoch - this.now < 0) { - this.countdownEnded = true; - - if (this.hasEndedCallback != null) { - this.hasEndedCallback(); - this.hasEndedCallback = null; - } + // Initialise the clock + if (!this.initialised) this._init(); - return true; - } else { - this.countdownEnded = false; - return false; - } - } - }, { - key: "_parseOptions", - value: function _parseOptions(opt) { - var headings = ["Days", "Hours", "Minutes", "Seconds"]; + // Set up the countdown interval + this.countdown = setInterval(this._tick.bind(this), 1000); - if (opt.headings && opt.headings.length === 4) { - headings = opt.headings; - } + // Chainable + return this; + } - return { - theme: opt.hasOwnProperty("theme") ? opt.theme : "dark", - headings: headings - }; - } - }, { - key: "_setOptions", - value: function _setOptions() { - this.element.classList.add("flipdown__theme-".concat(this.opts.theme)); - } - }, { - 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; + /** + * @name ifEnded + * @description Call a function once the countdown ends + * @author PButcher + * @param {function} cb - Callback + **/ + ifEnded(cb) { + this.hasEndedCallback = () => { + cb(); + this.hasEndedCallback = null; + + if (this.extraTime > 0) { + this.start(); } + }; - var dayRotorCount = this.daysremaining <= 2 ? 2 : this.daysremaining; + // Chainable + return this; + } - 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]); - } + ifExtendedEnded(cb) { + this.extendedCallback = () => { + cb(); + this.extendedCallback = null; + }; + } - this.element.appendChild(this._createRotorGroup(dayRotors, 0)); - var count = dayRotorCount; - for (var i = 0; i < 3; i++) { - var otherRotors = []; + /** + * @name _getTime + * @description Get the time in seconds (unix timestamp) + * @author PButcher + **/ + _getTime() { + return new Date().getTime() / 1000; + } - for (var j = 0; j < 2; j++) { - otherRotors.push(this.rotors[count]); - count++; + /** + * @name _hasCountdownEnded + * @description Has the countdown ended? + * @author PButcher + **/ + _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; - this.element.appendChild(this._createRotorGroup(otherRotors, i + 1)); + // Fire the ifEnded callback once if it was set + if (this.hasEndedCallback != null) { + // Call ifEnded callback + this.hasEndedCallback(); + + // Remove the callback + this.hasEndedCallback = null; } - 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")); + return true; - this._tick(); + // Countdown has not ended + } else { + this.countdownEnded = false; + return false; + } + } - this._updateClockValues(true); + /** + * @name _parseOptions + * @description Parse any passed options + * @param {object} opt - Optional configuration settings + * @author PButcher + **/ + _parseOptions(opt) { + let headings = ["Days", "Hours", "Minutes", "Seconds"]; + if (opt.headings && opt.headings.length === 4) { + headings = opt.headings; + } + this.extraTime = opt.hasOwnProperty("extraTime") ? opt.extraTime : 0; + return { + // Theme + theme: opt.hasOwnProperty("theme") ? opt.theme : "dark", + extraTime: opt.hasOwnProperty("extraTime") ? opt.extraTime : 0, + extendedText: opt.hasOwnProperty("extendedText") ? opt.extendedText : "Extended", + headings, + }; + } - return this; + /** + * @name _setOptions + * @description Set optional configuration settings + * @author PButcher + **/ + _setOptions() { + // Apply theme + this.element.classList.add(`flipdown__theme-${this.opts.theme}`); + } + + /** + * @name _init + * @description Initialise the countdown + * @author PButcher + **/ + _init() { + this.initialised = true; + + // Check whether countdown has ended and calculate how many digits the day counter needs + if (this._hasCountdownEnded()) { + this.daysremaining = 0; + } else { + this.daysremaining = Math.floor( + (this.epoch - this.now) / 86400 + ).toString().length; } - }, { - key: "_createRotorGroup", - value: function _createRotorGroup(rotors, rotorIndex) { - var rotorGroup = document.createElement("div"); - rotorGroup.className = "rotor-group"; - var dayRotorGroupHeading = document.createElement("div"); - dayRotorGroupHeading.className = "rotor-group-heading"; - dayRotorGroupHeading.setAttribute("data-before", this.opts.headings[rotorIndex]); - rotorGroup.appendChild(dayRotorGroupHeading); - appendChildren(rotorGroup, rotors); - return rotorGroup; + var dayRotorCount = this.daysremaining <= 2 ? 2 : this.daysremaining; + + // Create and store rotors + for (var i = 0; i < dayRotorCount + 6; i++) { + this.rotors.push(this._createRotor(0)); } - }, { - key: "_createRotor", - value: function _createRotor() { - var v = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; - var rotor = document.createElement("div"); - var rotorLeaf = document.createElement("div"); - var rotorLeafRear = document.createElement("figure"); - var rotorLeafFront = document.createElement("figure"); - var rotorTop = document.createElement("div"); - var rotorBottom = document.createElement("div"); - rotor.className = "rotor"; - rotorLeaf.className = "rotor-leaf"; - rotorLeafRear.className = "rotor-leaf-rear"; - rotorLeafFront.className = "rotor-leaf-front"; - rotorTop.className = "rotor-top"; - rotorBottom.className = "rotor-bottom"; - rotorLeafRear.textContent = v; - rotorTop.textContent = v; - rotorBottom.textContent = v; - appendChildren(rotor, [rotorLeaf, rotorTop, rotorBottom]); - appendChildren(rotorLeaf, [rotorLeafRear, rotorLeafFront]); - return rotor; + + // Create day rotor group + var dayRotors = []; + for (var i = 0; i < dayRotorCount; i++) { + dayRotors.push(this.rotors[i]); } - }, { - key: "_tick", - value: function _tick() { - this.now = this._getTime(); - var diff = this.epoch - this.now <= 0 ? 0 : this.epoch - this.now; - this.clockValues.d = Math.floor(diff / 86400); - diff -= this.clockValues.d * 86400; - this.clockValues.h = Math.floor(diff / 3600); - diff -= this.clockValues.h * 3600; - this.clockValues.m = Math.floor(diff / 60); - diff -= this.clockValues.m * 60; - this.clockValues.s = Math.floor(diff); - - this._updateClockValues(); - - this._hasCountdownEnded(); + this.element.appendChild(this._createRotorGroup(dayRotors, 0)); + + // Create other rotor groups + 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)); } - }, { - key: "_updateClockValues", - value: function _updateClockValues() { - var _this = 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); - this.clockStrings.m = pad(this.clockValues.m, 2); - 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]; - }); - this.rotorBottom.forEach(function (el, i) { - el.textContent = _this.prevClockValuesAsString[i]; - }); - function rotorTopFlip() { - var _this2 = this; + // Store and convert rotor nodelists to arrays + 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") + ); + + // Set initial values; + this._tick(); + this._updateClockValues(true); + + return this; + } + + /** + * @name _createRotorGroup + * @description Add rotors to the DOM + * @author PButcher + * @param {array} rotors - A set of rotors + **/ + _createRotorGroup(rotors, rotorIndex) { + var rotorGroup = document.createElement("div"); + rotorGroup.className = "rotor-group"; + var dayRotorGroupHeading = document.createElement("div"); + dayRotorGroupHeading.className = "rotor-group-heading"; + dayRotorGroupHeading.setAttribute( + "data-before", + this.opts.headings[rotorIndex] + ); + rotorGroup.appendChild(dayRotorGroupHeading); + appendChildren(rotorGroup, rotors); + return rotorGroup; + } - this.rotorTop.forEach(function (el, i) { - if (el.textContent != _this2.clockValuesAsString[i]) { - el.textContent = _this2.clockValuesAsString[i]; - } - }); - } + /** + * @name _createRotor + * @description Create a rotor DOM element + * @author PButcher + * @param {number} v - Initial rotor value + **/ + _createRotor(v = 0) { + var rotor = document.createElement("div"); + var rotorLeaf = document.createElement("div"); + var rotorLeafRear = document.createElement("figure"); + var rotorLeafFront = document.createElement("figure"); + var rotorTop = document.createElement("div"); + var rotorBottom = document.createElement("div"); + rotor.className = "rotor"; + rotorLeaf.className = "rotor-leaf"; + rotorLeafRear.className = "rotor-leaf-rear"; + rotorLeafFront.className = "rotor-leaf-front"; + rotorTop.className = "rotor-top"; + rotorBottom.className = "rotor-bottom"; + rotorLeafRear.textContent = v; + rotorTop.textContent = v; + rotorBottom.textContent = v; + appendChildren(rotor, [rotorLeaf, rotorTop, rotorBottom]); + appendChildren(rotorLeaf, [rotorLeafRear, rotorLeafFront]); + return rotor; + } - function rotorLeafRearFlip() { - var _this3 = this; + /** + * @name _tick + * @description Calculate current tick + * @author PButcher + **/ + _tick() { + // Get time now + this.now = this._getTime(); - this.rotorLeafRear.forEach(function (el, i) { - if (el.textContent != _this3.clockValuesAsString[i]) { - el.textContent = _this3.clockValuesAsString[i]; - el.parentElement.classList.add("flipped"); - var flip = setInterval(function () { + // Between now and epoch + var diff = this.epoch - this.now <= 0 ? 0 : this.epoch - this.now; + + // Days remaining + this.clockValues.d = Math.floor(diff / 86400); + diff -= this.clockValues.d * 86400; + + // Hours remaining + this.clockValues.h = Math.floor(diff / 3600); + diff -= this.clockValues.h * 3600; + + // Minutes remaining + this.clockValues.m = Math.floor(diff / 60); + diff -= this.clockValues.m * 60; + + // Seconds remaining + this.clockValues.s = Math.floor(diff); + + // Update clock values + this._updateClockValues(); + + // Has the countdown ended? + this._hasCountdownEnded(); + } + + /** + * @name _updateClockValues + * @description Update the clock face values + * @author PButcher + * @param {boolean} init - True if calling for initialisation + **/ + _updateClockValues(init = false) { + // Build clock value strings + this.clockStrings.d = pad(this.clockValues.d, 2); + this.clockStrings.h = pad(this.clockValues.h, 2); + this.clockStrings.m = pad(this.clockValues.m, 2); + this.clockStrings.s = pad(this.clockValues.s, 2); + + // Concat clock value strings + this.clockValuesAsString = ( + this.clockStrings.d + + this.clockStrings.h + + this.clockStrings.m + + this.clockStrings.s + ).split(""); + + // Update rotor values + // Note that the faces which are initially visible are: + // - rotorLeafFront (top half of current rotor) + // - rotorBottom (bottom half of current rotor) + // Note that the faces which are initially hidden are: + // - rotorTop (top half of next rotor) + // - rotorLeafRear (bottom half of next rotor) + this.rotorLeafFront.forEach((el, i) => { + el.textContent = this.prevClockValuesAsString[i]; + }); + + this.rotorBottom.forEach((el, i) => { + el.textContent = this.prevClockValuesAsString[i]; + }); + + function rotorTopFlip() { + this.rotorTop.forEach((el, i) => { + if (el.textContent != this.clockValuesAsString[i]) { + el.textContent = this.clockValuesAsString[i]; + } + }); + } + + function rotorLeafRearFlip() { + this.rotorLeafRear.forEach((el, i) => { + if (el.textContent != this.clockValuesAsString[i]) { + el.textContent = this.clockValuesAsString[i]; + el.parentElement.classList.add("flipped"); + var flip = setInterval( + function () { el.parentElement.classList.remove("flipped"); clearInterval(flip); - }.bind(_this3), 500); - } - }); - } - - if (!init) { - setTimeout(rotorTopFlip.bind(this), 500); - setTimeout(rotorLeafRearFlip.bind(this), 500); - } else { - rotorTopFlip.call(this); - rotorLeafRearFlip.call(this); - } + }.bind(this), + 500 + ); + } + }); + } - this.prevClockValuesAsString = this.clockValuesAsString; + // Init + if (!init) { + setTimeout(rotorTopFlip.bind(this), 500); + setTimeout(rotorLeafRearFlip.bind(this), 500); + } else { + rotorTopFlip.call(this); + rotorLeafRearFlip.call(this); } - }]); - return FlipDown; -}(); + // Save a copy of clock values for next tick + this.prevClockValuesAsString = this.clockValuesAsString; + } +} +/** + * @name pad + * @description Prefix a number with zeroes + * @author PButcher + * @param {string} n - Number to pad + * @param {number} len - Desired length of number + **/ function pad(n, len) { n = n.toString(); return n.length < len ? pad("0" + n, len) : n; } +/** + * @name appendChildren + * @description Add multiple children to an element + * @author PButcher + * @param {object} parent - Parent + **/ function appendChildren(parent, children) { - children.forEach(function (el) { + children.forEach((el) => { parent.appendChild(el); }); } diff --git a/example/js/main.js b/example/js/main.js index 8fd8102..5fb0e68 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) + 15; + 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..01bf626 100644 --- a/src/flipdown.js +++ b/src/flipdown.js @@ -13,6 +13,11 @@ class FlipDown { throw new Error( `FlipDown: Constructor expected unix timestamp, got ${typeof uts} instead.` ); + + // Initialize extended countdown properties + this.extendedCountdown = false; + this.extraTime = 0; + this.extendedCallback = null; } // If opt is specified, but not el @@ -81,6 +86,17 @@ class FlipDown { * @author PButcher **/ start() { + if (this.extraTime > 0 && this._getTime() >= this.epoch) { + this.epoch += this.extraTime; + this.extendedCountdown = true; + this._hasCountdownEnded(); // Check if the extended countdown has ended + this._setOptions(); + this._init(); + this._tick(); + this.countdown = setInterval(this._tick.bind(this), 1000); + return this; + } + // Initialise the clock if (!this.initialised) this._init(); @@ -107,6 +123,10 @@ class FlipDown { return this; } + ifExtendedEnded(cb) { + this.extendedCallback = cb; + } + /** * @name _getTime * @description Get the time in seconds (unix timestamp) @@ -124,6 +144,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 From fcf8121139adedf598eee992671a09cdddcff7ac Mon Sep 17 00:00:00 2001 From: Usman Khan <44539272+kha333n@users.noreply.github.com> Date: Mon, 7 Aug 2023 10:31:54 +0000 Subject: [PATCH 2/4] Build --- dist/flipdown.css | 283 ++++++++++++++ dist/flipdown.js | 263 +++++++++++++ dist/flipdown.min.css | 1 + dist/flipdown.min.js | 1 + example/css/flipdown/flipdown.css | 283 ++++++++++++++ example/js/flipdown/flipdown.js | 616 ++++++++++-------------------- 6 files changed, 1042 insertions(+), 405 deletions(-) create mode 100644 dist/flipdown.css create mode 100644 dist/flipdown.js create mode 100644 dist/flipdown.min.css create mode 100644 dist/flipdown.min.js create mode 100644 example/css/flipdown/flipdown.css diff --git a/dist/flipdown.css b/dist/flipdown.css new file mode 100644 index 0000000..9531476 --- /dev/null +++ b/dist/flipdown.css @@ -0,0 +1,283 @@ +/* THEMES */ + +/********** Theme: dark **********/ +/* Font styles */ +.flipdown.flipdown__theme-dark { + font-family: sans-serif; + font-weight: bold; +} +/* Rotor group headings */ +.flipdown.flipdown__theme-dark .rotor-group-heading:before { + color: #000000; +} +/* Delimeters */ +.flipdown.flipdown__theme-dark .rotor-group:nth-child(n+2):nth-child(-n+3):before, +.flipdown.flipdown__theme-dark .rotor-group:nth-child(n+2):nth-child(-n+3):after { + background-color: #151515; +} +/* Rotor tops */ +.flipdown.flipdown__theme-dark .rotor, +.flipdown.flipdown__theme-dark .rotor-top, +.flipdown.flipdown__theme-dark .rotor-leaf-front { + color: #FFFFFF; + background-color: #151515; +} +/* Rotor bottoms */ +.flipdown.flipdown__theme-dark .rotor-bottom, +.flipdown.flipdown__theme-dark .rotor-leaf-rear { + color: #EFEFEF; + background-color: #202020; +} +/* Hinge */ +.flipdown.flipdown__theme-dark .rotor:after { + border-top: solid 1px #151515; +} + +/********** Theme: light **********/ +/* Font styles */ +.flipdown.flipdown__theme-light { + font-family: sans-serif; + font-weight: bold; +} +/* Rotor group headings */ +.flipdown.flipdown__theme-light .rotor-group-heading:before { + color: #EEEEEE; +} +/* Delimeters */ +.flipdown.flipdown__theme-light .rotor-group:nth-child(n+2):nth-child(-n+3):before, +.flipdown.flipdown__theme-light .rotor-group:nth-child(n+2):nth-child(-n+3):after { + background-color: #DDDDDD; +} +/* Rotor tops */ +.flipdown.flipdown__theme-light .rotor, +.flipdown.flipdown__theme-light .rotor-top, +.flipdown.flipdown__theme-light .rotor-leaf-front { + color: #222222; + background-color: #DDDDDD; +} +/* Rotor bottoms */ +.flipdown.flipdown__theme-light .rotor-bottom, +.flipdown.flipdown__theme-light .rotor-leaf-rear { + color: #333333; + background-color: #EEEEEE; +} +/* Hinge */ +.flipdown.flipdown__theme-light .rotor:after { + border-top: solid 1px #222222; +} + +/* END OF THEMES */ + +.flipdown { + overflow: visible; + width: 510px; + height: 110px; +} + +.flipdown .rotor-group { + position: relative; + float: left; + padding-right: 30px; +} + +.flipdown .rotor-group:last-child { + padding-right: 0; +} + +.flipdown .rotor-group-heading:before { + display: block; + height: 30px; + line-height: 30px; + text-align: center; +} + +.flipdown .rotor-group:nth-child(1) .rotor-group-heading:before { + content: attr(data-before); +} + +.flipdown .rotor-group:nth-child(2) .rotor-group-heading:before { + content: attr(data-before); +} + +.flipdown .rotor-group:nth-child(3) .rotor-group-heading:before { + content: attr(data-before); +} + +.flipdown .rotor-group:nth-child(4) .rotor-group-heading:before { + content: attr(data-before); +} + +.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before { + content: ''; + position: absolute; + bottom: 20px; + left: 115px; + width: 10px; + height: 10px; + border-radius: 50%; +} + +.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after { + content: ''; + position: absolute; + bottom: 50px; + left: 115px; + width: 10px; + height: 10px; + border-radius: 50%; +} + +.flipdown .rotor { + position: relative; + float: left; + width: 50px; + height: 80px; + margin: 0px 5px 0px 0px; + border-radius: 4px; + font-size: 4rem; + text-align: center; + perspective: 200px; +} + +.flipdown .rotor:last-child { + margin-right: 0; +} + +.flipdown .rotor-top, +.flipdown .rotor-bottom { + overflow: hidden; + position: absolute; + width: 50px; + height: 40px; +} + +.flipdown .rotor-leaf { + z-index: 1; + position: absolute; + width: 50px; + height: 80px; + transform-style: preserve-3d; + transition: transform 0s; +} + +.flipdown .rotor-leaf.flipped { + transform: rotateX(-180deg); + transition: all 0.5s ease-in-out; +} + +.flipdown .rotor-leaf-front, +.flipdown .rotor-leaf-rear { + overflow: hidden; + position: absolute; + width: 50px; + height: 40px; + margin: 0; + transform: rotateX(0deg); + backface-visibility: hidden; + -webkit-backface-visibility: hidden; +} + +.flipdown .rotor-leaf-front { + line-height: 80px; + border-radius: 4px 4px 0px 0px; +} + +.flipdown .rotor-leaf-rear { + line-height: 0px; + border-radius: 0px 0px 4px 4px; + transform: rotateX(-180deg); +} + +.flipdown .rotor-top { + line-height: 80px; + border-radius: 4px 4px 0px 0px; +} + +.flipdown .rotor-bottom { + bottom: 0; + line-height: 0px; + border-radius: 0px 0px 4px 4px; +} + +.flipdown .rotor:after { + content: ''; + z-index: 2; + position: absolute; + bottom: 0px; + left: 0px; + width: 50px; + height: 40px; + border-radius: 0px 0px 4px 4px; +} + +@media (max-width: 550px) { + + .flipdown { + width: 312px; + height: 70px; + } + + .flipdown .rotor { + font-size: 2.2rem; + margin-right: 3px; + } + + .flipdown .rotor, + .flipdown .rotor-leaf, + .flipdown .rotor-leaf-front, + .flipdown .rotor-leaf-rear, + .flipdown .rotor-top, + .flipdown .rotor-bottom, + .flipdown .rotor:after { + width: 30px; + } + + .flipdown .rotor-group { + padding-right: 20px; + } + + .flipdown .rotor-group:last-child { + padding-right: 0px; + } + + .flipdown .rotor-group-heading:before { + font-size: 0.8rem; + height: 20px; + line-height: 20px; + } + + .flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before, + .flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after { + left: 69px; + } + + .flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before { + bottom: 13px; + height: 8px; + width: 8px; + } + + .flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after { + bottom: 29px; + height: 8px; + width: 8px; + } + + .flipdown .rotor-leaf-front, + .flipdown .rotor-top { + line-height: 50px; + } + + .flipdown .rotor-leaf, + .flipdown .rotor { + height: 50px; + } + + .flipdown .rotor-leaf-front, + .flipdown .rotor-leaf-rear, + .flipdown .rotor-top, + .flipdown .rotor-bottom, + .flipdown .rotor:after { + height: 25px; + } +} diff --git a/dist/flipdown.js b/dist/flipdown.js new file mode 100644 index 0000000..0c4d8cb --- /dev/null +++ b/dist/flipdown.js @@ -0,0 +1,263 @@ +"use strict"; + +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, _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); + if (typeof uts !== "number") { + throw new Error("FlipDown: Constructor expected unix timestamp, got ".concat(_typeof(uts), " instead.")); + this.extendedCountdown = false; + this.extraTime = 0; + this.extendedCallback = null; + } + if (_typeof(el) === "object") { + opt = el; + el = "flipdown"; + } + this.version = "0.3.2"; + this.initialised = false; + this.now = this._getTime(); + this.epoch = uts; + this.countdownEnded = false; + this.hasEndedCallback = null; + this.element = document.getElementById(el); + this.rotors = []; + this.rotorLeafFront = []; + this.rotorLeafRear = []; + this.rotorTops = []; + this.rotorBottoms = []; + this.countdown = null; + this.daysRemaining = 0; + this.clockValues = {}; + this.clockStrings = {}; + 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) { + this.epoch += this.extraTime; + this.extendedCountdown = true; + this._hasCountdownEnded(); + this._setOptions(); + 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; + } + }, { + key: "ifEnded", + value: function ifEnded(cb) { + this.hasEndedCallback = function () { + cb(); + this.hasEndedCallback = null; + }; + return this; + } + }, { + key: "ifExtendedEnded", + value: function ifExtendedEnded(cb) { + this.extendedCallback = cb; + } + }, { + key: "_getTime", + value: function _getTime() { + return new Date().getTime() / 1000; + } + }, { + 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; + return false; + } + } + }, { + key: "_parseOptions", + value: function _parseOptions(opt) { + var headings = ["Days", "Hours", "Minutes", "Seconds"]; + if (opt.headings && opt.headings.length === 4) { + headings = opt.headings; + } + return { + theme: opt.hasOwnProperty("theme") ? opt.theme : "dark", + headings: headings + }; + } + }, { + key: "_setOptions", + value: function _setOptions() { + this.element.classList.add("flipdown__theme-".concat(this.opts.theme)); + } + }, { + 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")); + this._tick(); + this._updateClockValues(true); + return this; + } + }, { + key: "_createRotorGroup", + value: function _createRotorGroup(rotors, rotorIndex) { + var rotorGroup = document.createElement("div"); + rotorGroup.className = "rotor-group"; + var dayRotorGroupHeading = document.createElement("div"); + dayRotorGroupHeading.className = "rotor-group-heading"; + dayRotorGroupHeading.setAttribute("data-before", this.opts.headings[rotorIndex]); + rotorGroup.appendChild(dayRotorGroupHeading); + appendChildren(rotorGroup, rotors); + return rotorGroup; + } + }, { + key: "_createRotor", + value: function _createRotor() { + var v = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var rotor = document.createElement("div"); + var rotorLeaf = document.createElement("div"); + var rotorLeafRear = document.createElement("figure"); + var rotorLeafFront = document.createElement("figure"); + var rotorTop = document.createElement("div"); + var rotorBottom = document.createElement("div"); + rotor.className = "rotor"; + rotorLeaf.className = "rotor-leaf"; + rotorLeafRear.className = "rotor-leaf-rear"; + rotorLeafFront.className = "rotor-leaf-front"; + rotorTop.className = "rotor-top"; + rotorBottom.className = "rotor-bottom"; + rotorLeafRear.textContent = v; + rotorTop.textContent = v; + rotorBottom.textContent = v; + appendChildren(rotor, [rotorLeaf, rotorTop, rotorBottom]); + appendChildren(rotorLeaf, [rotorLeafRear, rotorLeafFront]); + return rotor; + } + }, { + key: "_tick", + value: function _tick() { + this.now = this._getTime(); + var diff = this.epoch - this.now <= 0 ? 0 : this.epoch - this.now; + this.clockValues.d = Math.floor(diff / 86400); + diff -= this.clockValues.d * 86400; + this.clockValues.h = Math.floor(diff / 3600); + diff -= this.clockValues.h * 3600; + 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 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); + this.clockStrings.m = pad(this.clockValues.m, 2); + 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]; + }); + this.rotorBottom.forEach(function (el, i) { + el.textContent = _this.prevClockValuesAsString[i]; + }); + function rotorTopFlip() { + var _this2 = this; + this.rotorTop.forEach(function (el, i) { + if (el.textContent != _this2.clockValuesAsString[i]) { + el.textContent = _this2.clockValuesAsString[i]; + } + }); + } + function rotorLeafRearFlip() { + var _this3 = this; + this.rotorLeafRear.forEach(function (el, i) { + if (el.textContent != _this3.clockValuesAsString[i]) { + el.textContent = _this3.clockValuesAsString[i]; + el.parentElement.classList.add("flipped"); + var flip = setInterval(function () { + el.parentElement.classList.remove("flipped"); + clearInterval(flip); + }.bind(_this3), 500); + } + }); + } + if (!init) { + setTimeout(rotorTopFlip.bind(this), 500); + setTimeout(rotorLeafRearFlip.bind(this), 500); + } else { + 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.css b/dist/flipdown.min.css new file mode 100644 index 0000000..b4bed07 --- /dev/null +++ b/dist/flipdown.min.css @@ -0,0 +1 @@ +.flipdown.flipdown__theme-dark{font-family:sans-serif;font-weight:bold}.flipdown.flipdown__theme-dark .rotor-group-heading:before{color:#000}.flipdown.flipdown__theme-dark .rotor-group:nth-child(n+2):nth-child(-n+3):before,.flipdown.flipdown__theme-dark .rotor-group:nth-child(n+2):nth-child(-n+3):after{background-color:#151515}.flipdown.flipdown__theme-dark .rotor,.flipdown.flipdown__theme-dark .rotor-top,.flipdown.flipdown__theme-dark .rotor-leaf-front{color:#fff;background-color:#151515}.flipdown.flipdown__theme-dark .rotor-bottom,.flipdown.flipdown__theme-dark .rotor-leaf-rear{color:#efefef;background-color:#202020}.flipdown.flipdown__theme-dark .rotor:after{border-top:solid 1px #151515}.flipdown.flipdown__theme-light{font-family:sans-serif;font-weight:bold}.flipdown.flipdown__theme-light .rotor-group-heading:before{color:#eee}.flipdown.flipdown__theme-light .rotor-group:nth-child(n+2):nth-child(-n+3):before,.flipdown.flipdown__theme-light .rotor-group:nth-child(n+2):nth-child(-n+3):after{background-color:#ddd}.flipdown.flipdown__theme-light .rotor,.flipdown.flipdown__theme-light .rotor-top,.flipdown.flipdown__theme-light .rotor-leaf-front{color:#222;background-color:#ddd}.flipdown.flipdown__theme-light .rotor-bottom,.flipdown.flipdown__theme-light .rotor-leaf-rear{color:#333;background-color:#eee}.flipdown.flipdown__theme-light .rotor:after{border-top:solid 1px #222}.flipdown{overflow:visible;width:510px;height:110px}.flipdown .rotor-group{position:relative;float:left;padding-right:30px}.flipdown .rotor-group:last-child{padding-right:0}.flipdown .rotor-group-heading:before{display:block;height:30px;line-height:30px;text-align:center}.flipdown .rotor-group:nth-child(1) .rotor-group-heading:before{content:attr(data-before)}.flipdown .rotor-group:nth-child(2) .rotor-group-heading:before{content:attr(data-before)}.flipdown .rotor-group:nth-child(3) .rotor-group-heading:before{content:attr(data-before)}.flipdown .rotor-group:nth-child(4) .rotor-group-heading:before{content:attr(data-before)}.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before{content:'';position:absolute;bottom:20px;left:115px;width:10px;height:10px;border-radius:50%}.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after{content:'';position:absolute;bottom:50px;left:115px;width:10px;height:10px;border-radius:50%}.flipdown .rotor{position:relative;float:left;width:50px;height:80px;margin:0 5px 0 0;border-radius:4px;font-size:4rem;text-align:center;perspective:200px}.flipdown .rotor:last-child{margin-right:0}.flipdown .rotor-top,.flipdown .rotor-bottom{overflow:hidden;position:absolute;width:50px;height:40px}.flipdown .rotor-leaf{z-index:1;position:absolute;width:50px;height:80px;transform-style:preserve-3d;transition:transform 0s}.flipdown .rotor-leaf.flipped{transform:rotateX(-180deg);transition:all .5s ease-in-out}.flipdown .rotor-leaf-front,.flipdown .rotor-leaf-rear{overflow:hidden;position:absolute;width:50px;height:40px;margin:0;transform:rotateX(0);backface-visibility:hidden;-webkit-backface-visibility:hidden}.flipdown .rotor-leaf-front{line-height:80px;border-radius:4px 4px 0 0}.flipdown .rotor-leaf-rear{line-height:0;border-radius:0 0 4px 4px;transform:rotateX(-180deg)}.flipdown .rotor-top{line-height:80px;border-radius:4px 4px 0 0}.flipdown .rotor-bottom{bottom:0;line-height:0;border-radius:0 0 4px 4px}.flipdown .rotor:after{content:'';z-index:2;position:absolute;bottom:0;left:0;width:50px;height:40px;border-radius:0 0 4px 4px}@media(max-width:550px){.flipdown{width:312px;height:70px}.flipdown .rotor{font-size:2.2rem;margin-right:3px}.flipdown .rotor,.flipdown .rotor-leaf,.flipdown .rotor-leaf-front,.flipdown .rotor-leaf-rear,.flipdown .rotor-top,.flipdown .rotor-bottom,.flipdown .rotor:after{width:30px}.flipdown .rotor-group{padding-right:20px}.flipdown .rotor-group:last-child{padding-right:0}.flipdown .rotor-group-heading:before{font-size:.8rem;height:20px;line-height:20px}.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before,.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after{left:69px}.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):before{bottom:13px;height:8px;width:8px}.flipdown .rotor-group:nth-child(n+2):nth-child(-n+3):after{bottom:29px;height:8px;width:8px}.flipdown .rotor-leaf-front,.flipdown .rotor-top{line-height:50px}.flipdown .rotor-leaf,.flipdown .rotor{height:50px}.flipdown .rotor-leaf-front,.flipdown .rotor-leaf-rear,.flipdown .rotor-top,.flipdown .rotor-bottom,.flipdown .rotor:after{height:25px}} diff --git a/dist/flipdown.min.js b/dist/flipdown.min.js new file mode 100644 index 0000000..423690f --- /dev/null +++ b/dist/flipdown.min.js @@ -0,0 +1 @@ +"use strict";function _typeof(a){"@babel/helpers - typeof";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;d=this.epoch?(this.epoch+=this.extraTime,this.extendedCountdown=!0,this._hasCountdownEnded(),this._setOptions(),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){return this.hasEndedCallback=function(){a(),this.hasEndedCallback=null},this}},{key:"ifExtendedEnded",value:function ifExtendedEnded(a){this.extendedCallback=a}},{key:"_getTime",value:function _getTime(){return new Date().getTime()/1e3}},{key:"_hasCountdownEnded",value:function _hasCountdownEnded(){return 0>this.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),{theme:a.hasOwnProperty("theme")?a.theme:"dark",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._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=!!(0 - * @param {number} uts - Time to count down to as unix timestamp - * @param {string} el - DOM element to attach FlipDown to - * @param {object} opt - Optional configuration settings - **/ -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 +"use strict"; + +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, _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); if (typeof uts !== "number") { - throw new Error( - `FlipDown: Constructor expected unix timestamp, got ${typeof uts} instead.` - ); + throw new Error("FlipDown: Constructor expected unix timestamp, got ".concat(_typeof(uts), " instead.")); + this.extendedCountdown = false; + this.extraTime = 0; + this.extendedCallback = null; } - - // If opt is specified, but not el - if (typeof el === "object") { + if (_typeof(el) === "object") { opt = el; el = "flipdown"; } - - // FlipDown version this.version = "0.3.2"; - - // Initialised? this.initialised = false; - - // Time at instantiation in seconds this.now = this._getTime(); - - // UTS to count down to this.epoch = uts; - - // UTS passed to FlipDown is in the past this.countdownEnded = false; - - // User defined callback for countdown end this.hasEndedCallback = null; - - // FlipDown DOM element this.element = document.getElementById(el); - - // Rotor DOM elements this.rotors = []; this.rotorLeafFront = []; this.rotorLeafRear = []; this.rotorTops = []; this.rotorBottoms = []; - - // Interval this.countdown = null; - - // Number of days remaining this.daysRemaining = 0; - - // Clock values as numbers this.clockValues = {}; - - // Clock values as strings this.clockStrings = {}; - - // Clock values as array this.clockValuesAsString = []; this.prevClockValuesAsString = []; - - // Parse options this.opts = this._parseOptions(opt); - - // Set options this._setOptions(); - - // Print Version - console.log(`FlipDown ${this.version} (Theme: ${this.opts.theme})`); + console.log("FlipDown ".concat(this.version, " (Theme: ").concat(this.opts.theme, ")")); } - - /** - * @name start - * @description Start the countdown - * @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(); + _createClass(FlipDown, [{ + key: "start", + value: function start() { + if (this.extraTime > 0 && this._getTime() >= this.epoch) { + this.epoch += this.extraTime; + this.extendedCountdown = true; + this._hasCountdownEnded(); + this._setOptions(); + this._init(); + this._tick(); + this.countdown = setInterval(this._tick.bind(this), 1000); + return this; + } 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(); - - // Set up the countdown interval - this.countdown = setInterval(this._tick.bind(this), 1000); - - // Chainable - return this; - } - - /** - * @name ifEnded - * @description Call a function once the countdown ends - * @author PButcher - * @param {function} cb - Callback - **/ - ifEnded(cb) { - 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) - * @author PButcher - **/ - _getTime() { - return new Date().getTime() / 1000; - } - - /** - * @name _hasCountdownEnded - * @description Has the countdown ended? - * @author PButcher - **/ - _hasCountdownEnded() { - // Countdown has ended - if (this.epoch - this.now < 0) { - - if (this.extendedCountdown) { - this.extendedCountdown = false; - if (this.extendedCallback) { - this.extendedCallback(); + }, { + key: "ifEnded", + value: function ifEnded(cb) { + this.hasEndedCallback = function () { + cb(); + this.hasEndedCallback = null; + }; + return this; + } + }, { + key: "ifExtendedEnded", + value: function ifExtendedEnded(cb) { + this.extendedCallback = cb; + } + }, { + key: "_getTime", + value: function _getTime() { + return new Date().getTime() / 1000; + } + }, { + 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; + return false; } - - this.countdownEnded = true; - - // Fire the ifEnded callback once if it was set - if (this.hasEndedCallback != null) { - // Call ifEnded callback - this.hasEndedCallback(); - - // Remove the callback - this.hasEndedCallback = null; + } + }, { + key: "_parseOptions", + value: function _parseOptions(opt) { + var headings = ["Days", "Hours", "Minutes", "Seconds"]; + if (opt.headings && opt.headings.length === 4) { + headings = opt.headings; } - - return true; - - // Countdown has not ended - } else { - this.countdownEnded = false; - return false; + return { + theme: opt.hasOwnProperty("theme") ? opt.theme : "dark", + headings: headings + }; } - } - - /** - * @name _parseOptions - * @description Parse any passed options - * @param {object} opt - Optional configuration settings - * @author PButcher - **/ - _parseOptions(opt) { - let headings = ["Days", "Hours", "Minutes", "Seconds"]; - if (opt.headings && opt.headings.length === 4) { - headings = opt.headings; + }, { + key: "_setOptions", + value: function _setOptions() { + this.element.classList.add("flipdown__theme-".concat(this.opts.theme)); } - this.extraTime = opt.hasOwnProperty("extraTime") ? opt.extraTime : 0; - return { - // Theme - theme: opt.hasOwnProperty("theme") ? opt.theme : "dark", - extraTime: opt.hasOwnProperty("extraTime") ? opt.extraTime : 0, - extendedText: opt.hasOwnProperty("extendedText") ? opt.extendedText : "Extended", - headings, - }; - } - - /** - * @name _setOptions - * @description Set optional configuration settings - * @author PButcher - **/ - _setOptions() { - // Apply theme - this.element.classList.add(`flipdown__theme-${this.opts.theme}`); - } - - /** - * @name _init - * @description Initialise the countdown - * @author PButcher - **/ - _init() { - this.initialised = true; - - // Check whether countdown has ended and calculate how many digits the day counter needs - if (this._hasCountdownEnded()) { - this.daysremaining = 0; - } else { - this.daysremaining = Math.floor( - (this.epoch - this.now) / 86400 - ).toString().length; + }, { + 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")); + this._tick(); + this._updateClockValues(true); + return this; } - var dayRotorCount = this.daysremaining <= 2 ? 2 : this.daysremaining; - - // Create and store rotors - for (var i = 0; i < dayRotorCount + 6; i++) { - this.rotors.push(this._createRotor(0)); + }, { + key: "_createRotorGroup", + value: function _createRotorGroup(rotors, rotorIndex) { + var rotorGroup = document.createElement("div"); + rotorGroup.className = "rotor-group"; + var dayRotorGroupHeading = document.createElement("div"); + dayRotorGroupHeading.className = "rotor-group-heading"; + dayRotorGroupHeading.setAttribute("data-before", this.opts.headings[rotorIndex]); + rotorGroup.appendChild(dayRotorGroupHeading); + appendChildren(rotorGroup, rotors); + return rotorGroup; } - - // Create day rotor group - var dayRotors = []; - for (var i = 0; i < dayRotorCount; i++) { - dayRotors.push(this.rotors[i]); + }, { + key: "_createRotor", + value: function _createRotor() { + var v = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var rotor = document.createElement("div"); + var rotorLeaf = document.createElement("div"); + var rotorLeafRear = document.createElement("figure"); + var rotorLeafFront = document.createElement("figure"); + var rotorTop = document.createElement("div"); + var rotorBottom = document.createElement("div"); + rotor.className = "rotor"; + rotorLeaf.className = "rotor-leaf"; + rotorLeafRear.className = "rotor-leaf-rear"; + rotorLeafFront.className = "rotor-leaf-front"; + rotorTop.className = "rotor-top"; + rotorBottom.className = "rotor-bottom"; + rotorLeafRear.textContent = v; + rotorTop.textContent = v; + rotorBottom.textContent = v; + appendChildren(rotor, [rotorLeaf, rotorTop, rotorBottom]); + appendChildren(rotorLeaf, [rotorLeafRear, rotorLeafFront]); + return rotor; } - this.element.appendChild(this._createRotorGroup(dayRotors, 0)); - - // Create other rotor groups - 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)); + }, { + key: "_tick", + value: function _tick() { + this.now = this._getTime(); + var diff = this.epoch - this.now <= 0 ? 0 : this.epoch - this.now; + this.clockValues.d = Math.floor(diff / 86400); + diff -= this.clockValues.d * 86400; + this.clockValues.h = Math.floor(diff / 3600); + diff -= this.clockValues.h * 3600; + this.clockValues.m = Math.floor(diff / 60); + diff -= this.clockValues.m * 60; + this.clockValues.s = Math.floor(diff); + this._updateClockValues(); + this._hasCountdownEnded(); } - - // Store and convert rotor nodelists to arrays - 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") - ); - - // Set initial values; - this._tick(); - this._updateClockValues(true); - - return this; - } - - /** - * @name _createRotorGroup - * @description Add rotors to the DOM - * @author PButcher - * @param {array} rotors - A set of rotors - **/ - _createRotorGroup(rotors, rotorIndex) { - var rotorGroup = document.createElement("div"); - rotorGroup.className = "rotor-group"; - var dayRotorGroupHeading = document.createElement("div"); - dayRotorGroupHeading.className = "rotor-group-heading"; - dayRotorGroupHeading.setAttribute( - "data-before", - this.opts.headings[rotorIndex] - ); - rotorGroup.appendChild(dayRotorGroupHeading); - appendChildren(rotorGroup, rotors); - return rotorGroup; - } - - /** - * @name _createRotor - * @description Create a rotor DOM element - * @author PButcher - * @param {number} v - Initial rotor value - **/ - _createRotor(v = 0) { - var rotor = document.createElement("div"); - var rotorLeaf = document.createElement("div"); - var rotorLeafRear = document.createElement("figure"); - var rotorLeafFront = document.createElement("figure"); - var rotorTop = document.createElement("div"); - var rotorBottom = document.createElement("div"); - rotor.className = "rotor"; - rotorLeaf.className = "rotor-leaf"; - rotorLeafRear.className = "rotor-leaf-rear"; - rotorLeafFront.className = "rotor-leaf-front"; - rotorTop.className = "rotor-top"; - rotorBottom.className = "rotor-bottom"; - rotorLeafRear.textContent = v; - rotorTop.textContent = v; - rotorBottom.textContent = v; - appendChildren(rotor, [rotorLeaf, rotorTop, rotorBottom]); - appendChildren(rotorLeaf, [rotorLeafRear, rotorLeafFront]); - return rotor; - } - - /** - * @name _tick - * @description Calculate current tick - * @author PButcher - **/ - _tick() { - // Get time now - this.now = this._getTime(); - - // Between now and epoch - var diff = this.epoch - this.now <= 0 ? 0 : this.epoch - this.now; - - // Days remaining - this.clockValues.d = Math.floor(diff / 86400); - diff -= this.clockValues.d * 86400; - - // Hours remaining - this.clockValues.h = Math.floor(diff / 3600); - diff -= this.clockValues.h * 3600; - - // Minutes remaining - this.clockValues.m = Math.floor(diff / 60); - diff -= this.clockValues.m * 60; - - // Seconds remaining - this.clockValues.s = Math.floor(diff); - - // Update clock values - this._updateClockValues(); - - // Has the countdown ended? - this._hasCountdownEnded(); - } - - /** - * @name _updateClockValues - * @description Update the clock face values - * @author PButcher - * @param {boolean} init - True if calling for initialisation - **/ - _updateClockValues(init = false) { - // Build clock value strings - this.clockStrings.d = pad(this.clockValues.d, 2); - this.clockStrings.h = pad(this.clockValues.h, 2); - this.clockStrings.m = pad(this.clockValues.m, 2); - this.clockStrings.s = pad(this.clockValues.s, 2); - - // Concat clock value strings - this.clockValuesAsString = ( - this.clockStrings.d + - this.clockStrings.h + - this.clockStrings.m + - this.clockStrings.s - ).split(""); - - // Update rotor values - // Note that the faces which are initially visible are: - // - rotorLeafFront (top half of current rotor) - // - rotorBottom (bottom half of current rotor) - // Note that the faces which are initially hidden are: - // - rotorTop (top half of next rotor) - // - rotorLeafRear (bottom half of next rotor) - this.rotorLeafFront.forEach((el, i) => { - el.textContent = this.prevClockValuesAsString[i]; - }); - - this.rotorBottom.forEach((el, i) => { - el.textContent = this.prevClockValuesAsString[i]; - }); - - function rotorTopFlip() { - this.rotorTop.forEach((el, i) => { - if (el.textContent != this.clockValuesAsString[i]) { - el.textContent = this.clockValuesAsString[i]; - } + }, { + key: "_updateClockValues", + value: function _updateClockValues() { + var _this = 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); + this.clockStrings.m = pad(this.clockValues.m, 2); + 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]; }); - } - - function rotorLeafRearFlip() { - this.rotorLeafRear.forEach((el, i) => { - if (el.textContent != this.clockValuesAsString[i]) { - el.textContent = this.clockValuesAsString[i]; - el.parentElement.classList.add("flipped"); - var flip = setInterval( - function () { + this.rotorBottom.forEach(function (el, i) { + el.textContent = _this.prevClockValuesAsString[i]; + }); + function rotorTopFlip() { + var _this2 = this; + this.rotorTop.forEach(function (el, i) { + if (el.textContent != _this2.clockValuesAsString[i]) { + el.textContent = _this2.clockValuesAsString[i]; + } + }); + } + function rotorLeafRearFlip() { + var _this3 = this; + this.rotorLeafRear.forEach(function (el, i) { + if (el.textContent != _this3.clockValuesAsString[i]) { + el.textContent = _this3.clockValuesAsString[i]; + el.parentElement.classList.add("flipped"); + var flip = setInterval(function () { el.parentElement.classList.remove("flipped"); clearInterval(flip); - }.bind(this), - 500 - ); - } - }); - } - - // Init - if (!init) { - setTimeout(rotorTopFlip.bind(this), 500); - setTimeout(rotorLeafRearFlip.bind(this), 500); - } else { - rotorTopFlip.call(this); - rotorLeafRearFlip.call(this); + }.bind(_this3), 500); + } + }); + } + if (!init) { + setTimeout(rotorTopFlip.bind(this), 500); + setTimeout(rotorLeafRearFlip.bind(this), 500); + } else { + rotorTopFlip.call(this); + rotorLeafRearFlip.call(this); + } + this.prevClockValuesAsString = this.clockValuesAsString; } - - // Save a copy of clock values for next tick - this.prevClockValuesAsString = this.clockValuesAsString; - } -} - -/** - * @name pad - * @description Prefix a number with zeroes - * @author PButcher - * @param {string} n - Number to pad - * @param {number} len - Desired length of number - **/ + }]); + return FlipDown; +}(); function pad(n, len) { n = n.toString(); return n.length < len ? pad("0" + n, len) : n; } - -/** - * @name appendChildren - * @description Add multiple children to an element - * @author PButcher - * @param {object} parent - Parent - **/ function appendChildren(parent, children) { - children.forEach((el) => { + children.forEach(function (el) { parent.appendChild(el); }); } From 65049f8c17538b076413f10d807a24663570979a Mon Sep 17 00:00:00 2001 From: Usman Khan <2btech.dev2@gmail.com> Date: Mon, 7 Aug 2023 17:24:57 +0500 Subject: [PATCH 3/4] Extended Time Functionality Added --- .idea/git_toolbox_prj.xml | 15 + example/js/flipdown/flipdown.js | 625 +++++++++++++++++++++----------- example/js/main.js | 2 +- src/flipdown.js | 73 ++-- 4 files changed, 478 insertions(+), 237 deletions(-) create mode 100644 .idea/git_toolbox_prj.xml 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/example/js/flipdown/flipdown.js b/example/js/flipdown/flipdown.js index 0c4d8cb..6d9879d 100644 --- a/example/js/flipdown/flipdown.js +++ b/example/js/flipdown/flipdown.js @@ -1,263 +1,466 @@ -"use strict"; - -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, _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); +/** + * @name FlipDown + * @description Flip styled countdown clock + * @author Peter Butcher (PButcher) + * @param {number} uts - Time to count down to as unix timestamp + * @param {string} el - DOM element to attach FlipDown to + * @param {object} opt - Optional configuration settings + **/ +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 ".concat(_typeof(uts), " instead.")); - this.extendedCountdown = false; - this.extraTime = 0; - this.extendedCallback = null; + throw new Error( + `FlipDown: Constructor expected unix timestamp, got ${typeof uts} instead.` + ); } - if (_typeof(el) === "object") { + + // If opt is specified, but not el + if (typeof el === "object") { opt = el; el = "flipdown"; } + + // FlipDown version this.version = "0.3.2"; + + // Initialised? this.initialised = false; + + // Time at instantiation in seconds this.now = this._getTime(); + + // UTS to count down to this.epoch = uts; + + // UTS passed to FlipDown is in the past this.countdownEnded = false; + + // User defined callback for countdown end this.hasEndedCallback = null; + + // FlipDown DOM element this.element = document.getElementById(el); + + // Rotor DOM elements this.rotors = []; this.rotorLeafFront = []; this.rotorLeafRear = []; this.rotorTops = []; this.rotorBottoms = []; + + // Interval this.countdown = null; + + // Number of days remaining this.daysRemaining = 0; + + // Clock values as numbers this.clockValues = {}; + + // Clock values as strings this.clockStrings = {}; + + // Clock values as array this.clockValuesAsString = []; this.prevClockValuesAsString = []; + + // Parse options this.opts = this._parseOptions(opt); + + // Set options this._setOptions(); - console.log("FlipDown ".concat(this.version, " (Theme: ").concat(this.opts.theme, ")")); + + // Print Version + console.log(`FlipDown ${this.version} (Theme: ${this.opts.theme})`); } - _createClass(FlipDown, [{ - key: "start", - value: function start() { - if (this.extraTime > 0 && this._getTime() >= this.epoch) { - this.epoch += this.extraTime; - this.extendedCountdown = true; - this._hasCountdownEnded(); - this._setOptions(); - this._init(); - this._tick(); - this.countdown = setInterval(this._tick.bind(this), 1000); - return this; - } + + /** + * @name start + * @description Start the countdown + * @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; } - }, { - key: "ifEnded", - value: function ifEnded(cb) { - this.hasEndedCallback = function () { - cb(); - this.hasEndedCallback = null; - }; - return this; - } - }, { - key: "ifExtendedEnded", - value: function ifExtendedEnded(cb) { - this.extendedCallback = cb; - } - }, { - key: "_getTime", - value: function _getTime() { - return new Date().getTime() / 1000; - } - }, { - 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; + + // Initialise the clock + if (!this.initialised) this._init(); + + // Set up the countdown interval + this.countdown = setInterval(this._tick.bind(this), 1000); + + // Chainable + return this; + } + + /** + * @name ifEnded + * @description Call a function once the countdown ends + * @author PButcher + * @param {function} cb - Callback + **/ + ifEnded(cb) { + 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) + * @author PButcher + **/ + _getTime() { + return new Date().getTime() / 1000; + } + + /** + * @name _hasCountdownEnded + * @description Has the countdown ended? + * @author PButcher + **/ + _hasCountdownEnded() { + // Countdown has ended + if (this.epoch - this.now < 0) { + + if (this.extendedCountdown) { + this.extendedCountdown = false; + if (this.extendedCallback) { + this.extendedCallback(); } return true; - } else { - this.countdownEnded = false; - return false; } - } - }, { - key: "_parseOptions", - value: function _parseOptions(opt) { - var headings = ["Days", "Hours", "Minutes", "Seconds"]; - if (opt.headings && opt.headings.length === 4) { - headings = opt.headings; + + this.countdownEnded = true; + + // Fire the ifEnded callback once if it was set + if (this.hasEndedCallback != null) { + // Call ifEnded callback + this.hasEndedCallback(); + + // Remove the callback + this.hasEndedCallback = null; } - return { - theme: opt.hasOwnProperty("theme") ? opt.theme : "dark", - headings: headings - }; + + return true; + + // Countdown has not ended + } else { + this.countdownEnded = false; + return false; } - }, { - key: "_setOptions", - value: function _setOptions() { - this.element.classList.add("flipdown__theme-".concat(this.opts.theme)); + } + + /** + * @name _parseOptions + * @description Parse any passed options + * @param {object} opt - Optional configuration settings + * @author PButcher + **/ + _parseOptions(opt) { + let headings = ["Days", "Hours", "Minutes", "Seconds"]; + if (opt.headings && opt.headings.length === 4) { + headings = opt.headings; } - }, { - 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")); - this._tick(); - this._updateClockValues(true); - return this; + 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, + }; + } + + /** + * @name _setOptions + * @description Set optional configuration settings + * @author PButcher + **/ + _setOptions() { + // Apply theme + this.element.classList.add(`flipdown__theme-${this.opts.theme}`); + } + + /** + * @name _init + * @description Initialise the countdown + * @author PButcher + **/ + _init() { + this.initialised = true; + + // Check whether countdown has ended and calculate how many digits the day counter needs + if (this._hasCountdownEnded()) { + this.daysremaining = 0; + } else { + this.daysremaining = Math.floor( + (this.epoch - this.now) / 86400 + ).toString().length; } - }, { - key: "_createRotorGroup", - value: function _createRotorGroup(rotors, rotorIndex) { - var rotorGroup = document.createElement("div"); - rotorGroup.className = "rotor-group"; - var dayRotorGroupHeading = document.createElement("div"); - dayRotorGroupHeading.className = "rotor-group-heading"; - dayRotorGroupHeading.setAttribute("data-before", this.opts.headings[rotorIndex]); - rotorGroup.appendChild(dayRotorGroupHeading); - appendChildren(rotorGroup, rotors); - return rotorGroup; + var dayRotorCount = this.daysremaining <= 2 ? 2 : this.daysremaining; + + // Create and store rotors + for (var i = 0; i < dayRotorCount + 6; i++) { + this.rotors.push(this._createRotor(0)); + } + + // Create day rotor group + var dayRotors = []; + for (var i = 0; i < dayRotorCount; i++) { + dayRotors.push(this.rotors[i]); } - }, { - key: "_createRotor", - value: function _createRotor() { - var v = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; - var rotor = document.createElement("div"); - var rotorLeaf = document.createElement("div"); - var rotorLeafRear = document.createElement("figure"); - var rotorLeafFront = document.createElement("figure"); - var rotorTop = document.createElement("div"); - var rotorBottom = document.createElement("div"); - rotor.className = "rotor"; - rotorLeaf.className = "rotor-leaf"; - rotorLeafRear.className = "rotor-leaf-rear"; - rotorLeafFront.className = "rotor-leaf-front"; - rotorTop.className = "rotor-top"; - rotorBottom.className = "rotor-bottom"; - rotorLeafRear.textContent = v; - rotorTop.textContent = v; - rotorBottom.textContent = v; - appendChildren(rotor, [rotorLeaf, rotorTop, rotorBottom]); - appendChildren(rotorLeaf, [rotorLeafRear, rotorLeafFront]); - return rotor; + this.element.appendChild(this._createRotorGroup(dayRotors, 0)); + + // Create other rotor groups + 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)); } - }, { - key: "_tick", - value: function _tick() { - this.now = this._getTime(); - var diff = this.epoch - this.now <= 0 ? 0 : this.epoch - this.now; - this.clockValues.d = Math.floor(diff / 86400); - diff -= this.clockValues.d * 86400; - this.clockValues.h = Math.floor(diff / 3600); - diff -= this.clockValues.h * 3600; - this.clockValues.m = Math.floor(diff / 60); - diff -= this.clockValues.m * 60; - this.clockValues.s = Math.floor(diff); - this._updateClockValues(); - this._hasCountdownEnded(); + + // Store and convert rotor nodelists to arrays + 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") + ); + + // 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); } - }, { - key: "_updateClockValues", - value: function _updateClockValues() { - var _this = 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); - this.clockStrings.m = pad(this.clockValues.m, 2); - 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]; - }); - this.rotorBottom.forEach(function (el, i) { - el.textContent = _this.prevClockValuesAsString[i]; + + // Set initial values; + this._tick(); + this._updateClockValues(true); + + return this; + } + + /** + * @name _createRotorGroup + * @description Add rotors to the DOM + * @author PButcher + * @param {array} rotors - A set of rotors + **/ + _createRotorGroup(rotors, rotorIndex) { + var rotorGroup = document.createElement("div"); + rotorGroup.className = "rotor-group"; + var dayRotorGroupHeading = document.createElement("div"); + dayRotorGroupHeading.className = "rotor-group-heading"; + dayRotorGroupHeading.setAttribute( + "data-before", + this.opts.headings[rotorIndex] + ); + rotorGroup.appendChild(dayRotorGroupHeading); + appendChildren(rotorGroup, rotors); + return rotorGroup; + } + + /** + * @name _createRotor + * @description Create a rotor DOM element + * @author PButcher + * @param {number} v - Initial rotor value + **/ + _createRotor(v = 0) { + var rotor = document.createElement("div"); + var rotorLeaf = document.createElement("div"); + var rotorLeafRear = document.createElement("figure"); + var rotorLeafFront = document.createElement("figure"); + var rotorTop = document.createElement("div"); + var rotorBottom = document.createElement("div"); + rotor.className = "rotor"; + rotorLeaf.className = "rotor-leaf"; + rotorLeafRear.className = "rotor-leaf-rear"; + rotorLeafFront.className = "rotor-leaf-front"; + rotorTop.className = "rotor-top"; + rotorBottom.className = "rotor-bottom"; + rotorLeafRear.textContent = v; + rotorTop.textContent = v; + rotorBottom.textContent = v; + appendChildren(rotor, [rotorLeaf, rotorTop, rotorBottom]); + appendChildren(rotorLeaf, [rotorLeafRear, rotorLeafFront]); + return rotor; + } + + /** + * @name _tick + * @description Calculate current tick + * @author PButcher + **/ + _tick() { + // Get time now + this.now = this._getTime(); + + // Between now and epoch + var diff = this.epoch - this.now <= 0 ? 0 : this.epoch - this.now; + + // Days remaining + this.clockValues.d = Math.floor(diff / 86400); + diff -= this.clockValues.d * 86400; + + // Hours remaining + this.clockValues.h = Math.floor(diff / 3600); + diff -= this.clockValues.h * 3600; + + // Minutes remaining + this.clockValues.m = Math.floor(diff / 60); + diff -= this.clockValues.m * 60; + + // Seconds remaining + this.clockValues.s = Math.floor(diff); + + // Update clock values + this._updateClockValues(); + + // Has the countdown ended? + this._hasCountdownEnded(); + } + + /** + * @name _updateClockValues + * @description Update the clock face values + * @author PButcher + * @param {boolean} init - True if calling for initialisation + **/ + _updateClockValues(init = false) { + // Build clock value strings + this.clockStrings.d = pad(this.clockValues.d, 2); + this.clockStrings.h = pad(this.clockValues.h, 2); + this.clockStrings.m = pad(this.clockValues.m, 2); + this.clockStrings.s = pad(this.clockValues.s, 2); + + // Concat clock value strings + this.clockValuesAsString = ( + this.clockStrings.d + + this.clockStrings.h + + this.clockStrings.m + + this.clockStrings.s + ).split(""); + + // Update rotor values + // Note that the faces which are initially visible are: + // - rotorLeafFront (top half of current rotor) + // - rotorBottom (bottom half of current rotor) + // Note that the faces which are initially hidden are: + // - rotorTop (top half of next rotor) + // - rotorLeafRear (bottom half of next rotor) + this.rotorLeafFront.forEach((el, i) => { + el.textContent = this.prevClockValuesAsString[i]; + }); + + this.rotorBottom.forEach((el, i) => { + el.textContent = this.prevClockValuesAsString[i]; + }); + + function rotorTopFlip() { + this.rotorTop.forEach((el, i) => { + if (el.textContent != this.clockValuesAsString[i]) { + el.textContent = this.clockValuesAsString[i]; + } }); - function rotorTopFlip() { - var _this2 = this; - this.rotorTop.forEach(function (el, i) { - if (el.textContent != _this2.clockValuesAsString[i]) { - el.textContent = _this2.clockValuesAsString[i]; - } - }); - } - function rotorLeafRearFlip() { - var _this3 = this; - this.rotorLeafRear.forEach(function (el, i) { - if (el.textContent != _this3.clockValuesAsString[i]) { - el.textContent = _this3.clockValuesAsString[i]; - el.parentElement.classList.add("flipped"); - var flip = setInterval(function () { + } + + function rotorLeafRearFlip() { + this.rotorLeafRear.forEach((el, i) => { + if (el.textContent != this.clockValuesAsString[i]) { + el.textContent = this.clockValuesAsString[i]; + el.parentElement.classList.add("flipped"); + var flip = setInterval( + function () { el.parentElement.classList.remove("flipped"); clearInterval(flip); - }.bind(_this3), 500); - } - }); - } - if (!init) { - setTimeout(rotorTopFlip.bind(this), 500); - setTimeout(rotorLeafRearFlip.bind(this), 500); - } else { - rotorTopFlip.call(this); - rotorLeafRearFlip.call(this); - } - this.prevClockValuesAsString = this.clockValuesAsString; + }.bind(this), + 500 + ); + } + }); } - }]); - return FlipDown; -}(); + + // Init + if (!init) { + setTimeout(rotorTopFlip.bind(this), 500); + setTimeout(rotorLeafRearFlip.bind(this), 500); + } else { + rotorTopFlip.call(this); + rotorLeafRearFlip.call(this); + } + + // Save a copy of clock values for next tick + this.prevClockValuesAsString = this.clockValuesAsString; + } +} + +/** + * @name pad + * @description Prefix a number with zeroes + * @author PButcher + * @param {string} n - Number to pad + * @param {number} len - Desired length of number + **/ function pad(n, len) { n = n.toString(); return n.length < len ? pad("0" + n, len) : n; } + +/** + * @name appendChildren + * @description Add multiple children to an element + * @author PButcher + * @param {object} parent - Parent + **/ function appendChildren(parent, children) { - children.forEach(function (el) { + children.forEach((el) => { parent.appendChild(el); }); } diff --git a/example/js/main.js b/example/js/main.js index 5fb0e68..b76a75a 100644 --- a/example/js/main.js +++ b/example/js/main.js @@ -1,7 +1,7 @@ document.addEventListener('DOMContentLoaded', () => { // Unix timestamp (in seconds) to count down to - const fifteenSeconds = Math.floor(new Date().getTime() / 1000) + 15; + const fifteenSeconds = Math.floor(new Date().getTime() / 1000) + 2; const fiveDays3Hours2Minutes = 5 * 24 * 60 * 60 + 3 * 60 * 60 + 2 * 60; // Set up FlipDown with extra time and extended text diff --git a/src/flipdown.js b/src/flipdown.js index 01bf626..579f05c 100644 --- a/src/flipdown.js +++ b/src/flipdown.js @@ -8,16 +8,16 @@ **/ 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.` ); - - // Initialize extended countdown properties - this.extendedCountdown = false; - this.extraTime = 0; - this.extendedCallback = null; } // If opt is specified, but not el @@ -87,11 +87,12 @@ class FlipDown { **/ 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(); - this._init(); + if (!this.initialised) this._init(); this._tick(); this.countdown = setInterval(this._tick.bind(this), 1000); return this; @@ -114,19 +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 = () => { + cb(); + this.extendedCallback = null; + }; } + /** * @name _getTime * @description Get the time in seconds (unix timestamp) @@ -184,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, }; } @@ -214,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; @@ -244,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); @@ -275,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); @@ -359,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 @@ -394,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 ); } }); From bf23ae10c9cb3fdbb39880496dab3fb5acd9e435 Mon Sep 17 00:00:00 2001 From: Usman Khan <44539272+kha333n@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:27:26 +0000 Subject: [PATCH 4/4] Updated Build --- dist/flipdown.js | 51 ++- dist/flipdown.min.js | 2 +- example/js/flipdown/flipdown.js | 638 ++++++++++++-------------------- 3 files changed, 263 insertions(+), 428 deletions(-) diff --git a/dist/flipdown.js b/dist/flipdown.js index 0c4d8cb..edc6505 100644 --- a/dist/flipdown.js +++ b/dist/flipdown.js @@ -11,11 +11,11 @@ var FlipDown = function () { 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.")); - this.extendedCountdown = false; - this.extraTime = 0; - this.extendedCallback = null; } if (_typeof(el) === "object") { opt = el; @@ -47,11 +47,12 @@ var FlipDown = function () { 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(); - this._init(); + if (!this.initialised) this._init(); this._tick(); this.countdown = setInterval(this._tick.bind(this), 1000); return this; @@ -63,16 +64,24 @@ 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) { - this.extendedCallback = cb; + var _this2 = this; + this.extendedCallback = function () { + cb(); + _this2.extendedCallback = null; + }; } }, { key: "_getTime", @@ -108,8 +117,12 @@ var FlipDown = function () { 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 }; } @@ -149,6 +162,12 @@ var FlipDown = function () { 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; @@ -206,7 +225,7 @@ var FlipDown = function () { }, { 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); @@ -214,29 +233,29 @@ 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); } }); } diff --git a/dist/flipdown.min.js b/dist/flipdown.min.js index 423690f..e4e1588 100644 --- a/dist/flipdown.min.js +++ b/dist/flipdown.min.js @@ -1 +1 @@ -"use strict";function _typeof(a){"@babel/helpers - typeof";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;d=this.epoch?(this.epoch+=this.extraTime,this.extendedCountdown=!0,this._hasCountdownEnded(),this._setOptions(),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){return this.hasEndedCallback=function(){a(),this.hasEndedCallback=null},this}},{key:"ifExtendedEnded",value:function ifExtendedEnded(a){this.extendedCallback=a}},{key:"_getTime",value:function _getTime(){return new Date().getTime()/1e3}},{key:"_hasCountdownEnded",value:function _hasCountdownEnded(){return 0>this.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),{theme:a.hasOwnProperty("theme")?a.theme:"dark",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._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=!!(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=!!(0 - * @param {number} uts - Time to count down to as unix timestamp - * @param {string} el - DOM element to attach FlipDown to - * @param {object} opt - Optional configuration settings - **/ -class FlipDown { - constructor(uts, el = "flipdown", opt = {}) { - // Initialize extended countdown properties +"use strict"; + +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, _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 uts is not specified if (typeof uts !== "number") { - throw new Error( - `FlipDown: Constructor expected unix timestamp, got ${typeof uts} instead.` - ); + throw new Error("FlipDown: Constructor expected unix timestamp, got ".concat(_typeof(uts), " instead.")); } - - // If opt is specified, but not el - if (typeof el === "object") { + if (_typeof(el) === "object") { opt = el; el = "flipdown"; } - - // FlipDown version this.version = "0.3.2"; - - // Initialised? this.initialised = false; - - // Time at instantiation in seconds this.now = this._getTime(); - - // UTS to count down to this.epoch = uts; - - // UTS passed to FlipDown is in the past this.countdownEnded = false; - - // User defined callback for countdown end this.hasEndedCallback = null; - - // FlipDown DOM element this.element = document.getElementById(el); - - // Rotor DOM elements this.rotors = []; this.rotorLeafFront = []; this.rotorLeafRear = []; this.rotorTops = []; this.rotorBottoms = []; - - // Interval this.countdown = null; - - // Number of days remaining this.daysRemaining = 0; - - // Clock values as numbers this.clockValues = {}; - - // Clock values as strings this.clockStrings = {}; - - // Clock values as array this.clockValuesAsString = []; this.prevClockValuesAsString = []; - - // Parse options this.opts = this._parseOptions(opt); - - // Set options this._setOptions(); - - // Print Version - console.log(`FlipDown ${this.version} (Theme: ${this.opts.theme})`); + console.log("FlipDown ".concat(this.version, " (Theme: ").concat(this.opts.theme, ")")); } - - /** - * @name start - * @description Start the countdown - * @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(); + _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._tick(); this.countdown = setInterval(this._tick.bind(this), 1000); return this; } - - // Initialise the clock - if (!this.initialised) this._init(); - - // Set up the countdown interval - this.countdown = setInterval(this._tick.bind(this), 1000); - - // Chainable - return this; - } - - /** - * @name ifEnded - * @description Call a function once the countdown ends - * @author PButcher - * @param {function} cb - Callback - **/ - ifEnded(cb) { - 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) - * @author PButcher - **/ - _getTime() { - return new Date().getTime() / 1000; - } - - /** - * @name _hasCountdownEnded - * @description Has the countdown ended? - * @author PButcher - **/ - _hasCountdownEnded() { - // Countdown has ended - if (this.epoch - this.now < 0) { - - if (this.extendedCountdown) { - this.extendedCountdown = false; - if (this.extendedCallback) { - this.extendedCallback(); + }, { + key: "ifEnded", + value: function ifEnded(cb) { + var _this = this; + this.hasEndedCallback = function () { + cb(); + _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() { + return new Date().getTime() / 1000; + } + }, { + 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; + return false; } - - this.countdownEnded = true; - - // Fire the ifEnded callback once if it was set - if (this.hasEndedCallback != null) { - // Call ifEnded callback - this.hasEndedCallback(); - - // Remove the callback - this.hasEndedCallback = null; + } + }, { + key: "_parseOptions", + value: function _parseOptions(opt) { + var headings = ["Days", "Hours", "Minutes", "Seconds"]; + if (opt.headings && opt.headings.length === 4) { + headings = opt.headings; } - - return true; - - // Countdown has not ended - } else { - this.countdownEnded = false; - return false; + 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 + }; } - } - - /** - * @name _parseOptions - * @description Parse any passed options - * @param {object} opt - Optional configuration settings - * @author PButcher - **/ - _parseOptions(opt) { - let headings = ["Days", "Hours", "Minutes", "Seconds"]; - if (opt.headings && opt.headings.length === 4) { - headings = opt.headings; + }, { + key: "_setOptions", + value: function _setOptions() { + this.element.classList.add("flipdown__theme-".concat(this.opts.theme)); } - 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, - }; - } - - /** - * @name _setOptions - * @description Set optional configuration settings - * @author PButcher - **/ - _setOptions() { - // Apply theme - this.element.classList.add(`flipdown__theme-${this.opts.theme}`); - } - - /** - * @name _init - * @description Initialise the countdown - * @author PButcher - **/ - _init() { - this.initialised = true; - - // Check whether countdown has ended and calculate how many digits the day counter needs - 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; - - // Create and store rotors - for (var i = 0; i < dayRotorCount + 6; i++) { - this.rotors.push(this._createRotor(0)); + }, { + 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; } - - // Create day rotor group - var dayRotors = []; - for (var i = 0; i < dayRotorCount; i++) { - dayRotors.push(this.rotors[i]); + }, { + key: "_createRotorGroup", + value: function _createRotorGroup(rotors, rotorIndex) { + var rotorGroup = document.createElement("div"); + rotorGroup.className = "rotor-group"; + var dayRotorGroupHeading = document.createElement("div"); + dayRotorGroupHeading.className = "rotor-group-heading"; + dayRotorGroupHeading.setAttribute("data-before", this.opts.headings[rotorIndex]); + rotorGroup.appendChild(dayRotorGroupHeading); + appendChildren(rotorGroup, rotors); + return rotorGroup; } - this.element.appendChild(this._createRotorGroup(dayRotors, 0)); - - // Create other rotor groups - 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)); + }, { + key: "_createRotor", + value: function _createRotor() { + var v = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var rotor = document.createElement("div"); + var rotorLeaf = document.createElement("div"); + var rotorLeafRear = document.createElement("figure"); + var rotorLeafFront = document.createElement("figure"); + var rotorTop = document.createElement("div"); + var rotorBottom = document.createElement("div"); + rotor.className = "rotor"; + rotorLeaf.className = "rotor-leaf"; + rotorLeafRear.className = "rotor-leaf-rear"; + rotorLeafFront.className = "rotor-leaf-front"; + rotorTop.className = "rotor-top"; + rotorBottom.className = "rotor-bottom"; + rotorLeafRear.textContent = v; + rotorTop.textContent = v; + rotorBottom.textContent = v; + appendChildren(rotor, [rotorLeaf, rotorTop, rotorBottom]); + appendChildren(rotorLeaf, [rotorLeafRear, rotorLeafFront]); + return rotor; } - - // Store and convert rotor nodelists to arrays - 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") - ); - - // 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); + }, { + key: "_tick", + value: function _tick() { + this.now = this._getTime(); + var diff = this.epoch - this.now <= 0 ? 0 : this.epoch - this.now; + this.clockValues.d = Math.floor(diff / 86400); + diff -= this.clockValues.d * 86400; + this.clockValues.h = Math.floor(diff / 3600); + diff -= this.clockValues.h * 3600; + this.clockValues.m = Math.floor(diff / 60); + diff -= this.clockValues.m * 60; + this.clockValues.s = Math.floor(diff); + this._updateClockValues(); + this._hasCountdownEnded(); } - - // Set initial values; - this._tick(); - this._updateClockValues(true); - - return this; - } - - /** - * @name _createRotorGroup - * @description Add rotors to the DOM - * @author PButcher - * @param {array} rotors - A set of rotors - **/ - _createRotorGroup(rotors, rotorIndex) { - var rotorGroup = document.createElement("div"); - rotorGroup.className = "rotor-group"; - var dayRotorGroupHeading = document.createElement("div"); - dayRotorGroupHeading.className = "rotor-group-heading"; - dayRotorGroupHeading.setAttribute( - "data-before", - this.opts.headings[rotorIndex] - ); - rotorGroup.appendChild(dayRotorGroupHeading); - appendChildren(rotorGroup, rotors); - return rotorGroup; - } - - /** - * @name _createRotor - * @description Create a rotor DOM element - * @author PButcher - * @param {number} v - Initial rotor value - **/ - _createRotor(v = 0) { - var rotor = document.createElement("div"); - var rotorLeaf = document.createElement("div"); - var rotorLeafRear = document.createElement("figure"); - var rotorLeafFront = document.createElement("figure"); - var rotorTop = document.createElement("div"); - var rotorBottom = document.createElement("div"); - rotor.className = "rotor"; - rotorLeaf.className = "rotor-leaf"; - rotorLeafRear.className = "rotor-leaf-rear"; - rotorLeafFront.className = "rotor-leaf-front"; - rotorTop.className = "rotor-top"; - rotorBottom.className = "rotor-bottom"; - rotorLeafRear.textContent = v; - rotorTop.textContent = v; - rotorBottom.textContent = v; - appendChildren(rotor, [rotorLeaf, rotorTop, rotorBottom]); - appendChildren(rotorLeaf, [rotorLeafRear, rotorLeafFront]); - return rotor; - } - - /** - * @name _tick - * @description Calculate current tick - * @author PButcher - **/ - _tick() { - // Get time now - this.now = this._getTime(); - - // Between now and epoch - var diff = this.epoch - this.now <= 0 ? 0 : this.epoch - this.now; - - // Days remaining - this.clockValues.d = Math.floor(diff / 86400); - diff -= this.clockValues.d * 86400; - - // Hours remaining - this.clockValues.h = Math.floor(diff / 3600); - diff -= this.clockValues.h * 3600; - - // Minutes remaining - this.clockValues.m = Math.floor(diff / 60); - diff -= this.clockValues.m * 60; - - // Seconds remaining - this.clockValues.s = Math.floor(diff); - - // Update clock values - this._updateClockValues(); - - // Has the countdown ended? - this._hasCountdownEnded(); - } - - /** - * @name _updateClockValues - * @description Update the clock face values - * @author PButcher - * @param {boolean} init - True if calling for initialisation - **/ - _updateClockValues(init = false) { - // Build clock value strings - this.clockStrings.d = pad(this.clockValues.d, 2); - this.clockStrings.h = pad(this.clockValues.h, 2); - this.clockStrings.m = pad(this.clockValues.m, 2); - this.clockStrings.s = pad(this.clockValues.s, 2); - - // Concat clock value strings - this.clockValuesAsString = ( - this.clockStrings.d + - this.clockStrings.h + - this.clockStrings.m + - this.clockStrings.s - ).split(""); - - // Update rotor values - // Note that the faces which are initially visible are: - // - rotorLeafFront (top half of current rotor) - // - rotorBottom (bottom half of current rotor) - // Note that the faces which are initially hidden are: - // - rotorTop (top half of next rotor) - // - rotorLeafRear (bottom half of next rotor) - this.rotorLeafFront.forEach((el, i) => { - el.textContent = this.prevClockValuesAsString[i]; - }); - - this.rotorBottom.forEach((el, i) => { - el.textContent = this.prevClockValuesAsString[i]; - }); - - function rotorTopFlip() { - this.rotorTop.forEach((el, i) => { - if (el.textContent != this.clockValuesAsString[i]) { - el.textContent = this.clockValuesAsString[i]; - } + }, { + key: "_updateClockValues", + value: function _updateClockValues() { + 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); + this.clockStrings.m = pad(this.clockValues.m, 2); + 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 = _this3.prevClockValuesAsString[i]; }); - } - - function rotorLeafRearFlip() { - this.rotorLeafRear.forEach((el, i) => { - if (el.textContent != this.clockValuesAsString[i]) { - el.textContent = this.clockValuesAsString[i]; - el.parentElement.classList.add("flipped"); - var flip = setInterval( - function () { + this.rotorBottom.forEach(function (el, i) { + el.textContent = _this3.prevClockValuesAsString[i]; + }); + function rotorTopFlip() { + var _this4 = this; + this.rotorTop.forEach(function (el, i) { + if (el.textContent != _this4.clockValuesAsString[i]) { + el.textContent = _this4.clockValuesAsString[i]; + } + }); + } + function rotorLeafRearFlip() { + var _this5 = this; + this.rotorLeafRear.forEach(function (el, 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(this), - 500 - ); - } - }); - } - - // Init - if (!init) { - setTimeout(rotorTopFlip.bind(this), 500); - setTimeout(rotorLeafRearFlip.bind(this), 500); - } else { - rotorTopFlip.call(this); - rotorLeafRearFlip.call(this); + }.bind(_this5), 500); + } + }); + } + if (!init) { + setTimeout(rotorTopFlip.bind(this), 500); + setTimeout(rotorLeafRearFlip.bind(this), 500); + } else { + rotorTopFlip.call(this); + rotorLeafRearFlip.call(this); + } + this.prevClockValuesAsString = this.clockValuesAsString; } - - // Save a copy of clock values for next tick - this.prevClockValuesAsString = this.clockValuesAsString; - } -} - -/** - * @name pad - * @description Prefix a number with zeroes - * @author PButcher - * @param {string} n - Number to pad - * @param {number} len - Desired length of number - **/ + }]); + return FlipDown; +}(); function pad(n, len) { n = n.toString(); return n.length < len ? pad("0" + n, len) : n; } - -/** - * @name appendChildren - * @description Add multiple children to an element - * @author PButcher - * @param {object} parent - Parent - **/ function appendChildren(parent, children) { - children.forEach((el) => { + children.forEach(function (el) { parent.appendChild(el); }); }