UNPKG

metro4

Version:

The front-end framework for Build responsive, mobile-first projects on the web with the first front-end component library in Metro Style

588 lines (482 loc) 18.6 kB
/* global Metro, datetime, Datetime, METRO_LOCALE */ (function(Metro, $) { 'use strict'; var Utils = Metro.utils; var CountdownDefaultConfig = { countdownDeferred: 0, stopOnBlur: true, animate: "none", ease: "linear", duration: 600, inputFormat: null, locale: METRO_LOCALE, days: 0, hours: 0, minutes: 0, seconds: 0, date: null, start: true, clsCountdown: "", clsPart: "", clsZero: "", clsAlarm: "", clsDays: "", clsHours: "", clsMinutes: "", clsSeconds: "", onAlarm: Metro.noop, onTick: Metro.noop, onZero: Metro.noop, onBlink: Metro.noop, onCountdownCreate: Metro.noop }; Metro.countdownSetup = function (options) { CountdownDefaultConfig = $.extend({}, CountdownDefaultConfig, options); }; if (typeof window["metroCountdownSetup"] !== undefined) { Metro.countdownSetup(window["metroCountdownSetup"]); } Metro.Component('countdown', { init: function( options, elem ) { this._super(elem, options, CountdownDefaultConfig, { locale: Metro.locales["en-US"], breakpoint: (new Date()).getTime(), blinkInterval: null, tickInterval: null, zeroDaysFired: false, zeroHoursFired: false, zeroMinutesFired: false, zeroSecondsFired: false, fontSize: parseInt(Utils.getStyleOne(elem, "font-size")), current: { d: 0, h: 0, m: 0, s: 0 }, inactiveTab: false, id: Utils.elementId("countdown"), duration: 600 }); return this; }, _create: function(){ var o = this.options; this.locale = Metro.locales[o.locale] !== undefined ? Metro.locales[o.locale] : Metro.locales["en-US"]; this.duration = (+o.duration <= 0 || +o.duration >= 1000) ? 600 : +o.duration; this._build(); this._createEvents(); }, _setBreakpoint: function(){ var o = this.options; var dm = 86400000, hm = 3600000, mm = 60000, sm = 1000; this.breakpoint = datetime().time(); if (o.date) { this.breakpoint = (o.inputFormat ? Datetime.from(o.date, o.inputFormat) : datetime(o.date)).time(); } if (parseInt(o.days) > 0) { this.breakpoint += parseInt(o.days) * dm; } if (parseInt(o.hours) > 0) { this.breakpoint += parseInt(o.hours) * hm; } if (parseInt(o.minutes) > 0) { this.breakpoint += parseInt(o.minutes) * mm; } if (parseInt(o.seconds) > 0) { this.breakpoint += parseInt(o.seconds) * sm; } }, _build: function(){ var that = this, element = this.element, o = this.options; var parts = ["days", "hours", "minutes", "seconds"]; var dm = 24*60*60*1000; var delta_days; var now = datetime().time(); var digit; if (!element.attr("id")) { element.attr("id", Utils.elementId("countdown")); } if (!Utils.isValue(element.attr("id"))) { element.attr("id", Utils.elementId("countdown")); } element.addClass("countdown").addClass(o.clsCountdown); this._setBreakpoint(); delta_days = Math.round((that.breakpoint - now) / dm); $.each(parts, function(){ var part = $("<div>").addClass("part " + this).addClass(o.clsPart).attr("data-label", that.locale["calendar"]["time"][this]).appendTo(element); if (this === "days") {part.addClass(o.clsDays);} if (this === "hours") {part.addClass(o.clsHours);} if (this === "minutes") {part.addClass(o.clsMinutes);} if (this === "seconds") {part.addClass(o.clsSeconds);} $("<div>").addClass("digit").appendTo(part); $("<div>").addClass("digit").appendTo(part); if (this === "days" && delta_days >= 100) { for(var i = 0; i < String(Math.round(delta_days/100)).length; i++) { $("<div>").addClass("digit").appendTo(part); } } }); digit = element.find(".digit"); digit.append($("<span class='digit-placeholder'>").html("0")); digit.append($("<span class='digit-value'>").html("0")); this._fireEvent("countdown-create", { element: element }) if (o.start === true) { this.start(); } else { this.tick(); } }, _createEvents: function(){ var that = this; $(document).on("visibilitychange", function() { if (document.hidden) { that.pause(); } else { that.resume(); } }, {ns: this.id}); }, blink: function(){ var element = this.element; element.toggleClass("blink"); this._fireEvent("blink", { time: this.current }); }, tick: function(){ var element = this.element, o = this.options; var dm = 24*60*60, hm = 60*60, mm = 60, sm = 1; var left, now = datetime().time(); var d, h, m, s; var days = element.find(".days"), hours = element.find(".hours"), minutes = element.find(".minutes"), seconds = element.find(".seconds"); left = Math.floor((this.breakpoint - now)/1000); if (left <= -1) { this.stop(); element.addClass(o.clsAlarm); this._fireEvent("alarm", { time: now }); return ; } d = Math.floor(left / dm); left -= d * dm; if (this.current.d !== d) { this.current.d = d; this.draw("days", d); } if (d === 0) { if (this.zeroDaysFired === false) { this.zeroDaysFired = true; days.addClass(o.clsZero); this._fireEvent("zero", { part: "days", value: days }); } } h = Math.floor(left / hm); left -= h*hm; if (this.current.h !== h) { this.current.h = h; this.draw("hours", h); } if (d === 0 && h === 0) { if (this.zeroHoursFired === false) { this.zeroHoursFired = true; hours.addClass(o.clsZero); this._fireEvent("zero", { part: "hours", value: hours }); } } m = Math.floor(left / mm); left -= m*mm; if (this.current.m !== m) { this.current.m = m; this.draw("minutes", m); } if (d === 0 && h === 0 && m === 0) { if (this.zeroMinutesFired === false) { this.zeroMinutesFired = true; minutes.addClass(o.clsZero); this._fireEvent("zero", { part: "minutes", value: minutes }); } } s = Math.floor(left / sm); if (this.current.s !== s) { this.current.s = s; this.draw("seconds", s); } if (d === 0 && h === 0 && m === 0 && s === 0) { if (this.zeroSecondsFired === false) { this.zeroSecondsFired = true; seconds.addClass(o.clsZero); this._fireEvent("zero", { part: "seconds", value: seconds }); } } this._fireEvent("tick", { days: d, hours: h, minutes: m, seconds: s }); }, draw: function(part, value){ var element = this.element, o = this.options; var digits, digits_length, digit_value, digit_current, digit; var len, i, duration = this.duration; var fontSize = this.fontSize; var slideDigit = function(digit, value){ var digit_copy, height = digit.height(); digit.siblings(".-old-digit").remove(); digit_copy = digit.clone().appendTo(digit.parent()); digit_copy.css({ top: -1 * height + 'px' }); digit .addClass("-old-digit") .animate({ draw: { top: height, opacity: 0 }, dur: duration, ease: o.ease, onDone: function(){ $(this).remove(); } }); digit_copy .html(value) .animate({ draw: { top: 0, opacity: 1 }, dur: duration, ease: o.ease }); }; var fadeDigit = function(digit, value){ var digit_copy; digit.siblings(".-old-digit").remove(); digit_copy = digit.clone().appendTo(digit.parent()); digit_copy.css({ opacity: 0 }); digit .addClass("-old-digit") .animate({ draw: { opacity: 0 }, dur: duration / 2, ease: o.ease, onDone: function(){ $(this).remove(); } }); digit_copy .html(value) .animate({ draw: { opacity: 1 }, dur: duration / 2, ease: o.ease }); }; var zoomDigit = function(digit, value) { var digit_copy, height = digit.height(), fs = fontSize// parseInt(digit.style("font-size")); digit.siblings(".-old-digit").remove(); digit_copy = digit.clone().appendTo(digit.parent()); digit_copy.css({ top: 0, left: 0, opacity: 1 }); digit .addClass("-old-digit") .animate({ draw: { top: height, opacity: 0, fontSize: 0 }, dur: duration, ease: o.ease, onDone: function(){ $(this).remove(); } }); digit_copy .html(value) .animate({ draw: { top: 0, opacity: 1, fontSize: [0, fs] }, dur: duration, ease: o.ease }); }; value = ""+value; if (value.length === 1) { value = '0'+value; } len = value.length; digits = element.find("."+part+" .digit:not(.-old-digit)"); digits_length = digits.length; element.find(".-old-digit").remove() for(i = 0; i < len; i++){ digit = digits.eq(digits_length - 1).find(".digit-value"); digit_value = Math.floor( parseInt(value) / Math.pow(10, i) ) % 10; digit_current = parseInt(digit.text()); digits_length--; if (digit_current === digit_value) { continue; } switch ((""+o.animate).toLowerCase()) { case "slide": slideDigit(digit, digit_value); break; case "fade": fadeDigit(digit, digit_value); break; case "zoom": zoomDigit(digit, digit_value); break; default: digit.html(digit_value); } } }, start: function(){ var that = this, element = this.element; if (element.data("paused") === false) { return; } clearInterval(this.blinkInterval); clearInterval(this.tickInterval); element.data("paused", false); this._setBreakpoint(); this.tick(); this.blinkInterval = setInterval(function(){that.blink();}, 500); this.tickInterval = setInterval(function(){that.tick();}, 1000); }, stop: function(){ var element = this.element; clearInterval(this.blinkInterval); clearInterval(this.tickInterval); element.data("paused", true); element.find(".digit").html("0"); this.current = { d: 0, h:0, m: 0, s:0 }; }, pause: function(){ clearInterval(this.blinkInterval); clearInterval(this.tickInterval); this.element.data("paused", true); }, resume: function(){ var that = this; this.element.data("paused", false); this.blinkInterval = setInterval(function(){that.blink();}, 500); this.tickInterval = setInterval(function(){that.tick();}, 1000); }, reset: function(){ var that = this, element = this.element, o = this.options; clearInterval(this.blinkInterval); clearInterval(this.tickInterval); element.find(".part").removeClass(o.clsZero); var digit = element.find(".digit").clear(); digit.append($("<span class='digit-placeholder'>").html("0")); digit.append($("<span class='digit-value'>").html("0")); this._setBreakpoint(); element.data("paused", false); this.tick(); this.blinkInterval = setInterval(function(){that.blink();}, 500); this.tickInterval = setInterval(function(){that.tick();}, 1000); }, resetWith: function(val){ var that = this, element = this.element, o = this.options; if (typeof val === "string") { element.attr("data-date", val) o.date = val } else if (typeof val === 'object') { var keys = ["days", "hours", "minutes", "seconds"] $.each(keys, function(i, v){ if (Metro.utils.isValue(val[v])) { element.attr("data-"+v, val[v]) o[v] = val[v] } }) } this.reset() }, togglePlay: function(){ if (this.element.attr("data-pause") === true) { this.pause(); } else { this.start(); } }, isPaused: function(){ return this.element.data("paused"); }, getBreakpoint: function(asDate){ return asDate === true ? new Date(this.breakpoint) : this.breakpoint; }, getLeft: function(){ var dm = 24*60*60*1000, hm = 60*60*1000, mm = 60*1000, sm = 1000; var now = (new Date()).getTime(); var left_seconds = Math.floor(this.breakpoint - now); return { days: Math.round(left_seconds / dm), hours: Math.round(left_seconds / hm), minutes: Math.round(left_seconds / mm), seconds: Math.round(left_seconds / sm) }; }, i18n: function(val){ var that = this, element = this.element, o = this.options; var parts = ["days", "hours", "minutes", "seconds"]; if (val === undefined) { return o.locale; } if (Metro.locales[val] === undefined) { return false; } o.locale = val; this.locale = Metro.locales[o.locale]; $.each(parts, function(){ var cls = ".part." + this; var part = element.find(cls); part.attr("data-label", that.locale["calendar"]["time"][this]); }); }, changeAttrLocale: function(){ var element = this.element; var locale = element.attr('data-locale'); this.i18n(locale); }, changeAttribute: function(attr, newVal){ switch (attr) { case "data-pause": this.togglePlay(); break; case "data-locale": this.i18n(newVal); break; case "data-duration": this.duration = +newVal <= 0 || +newVal >= 1000 ? 600 : +newVal; break; } }, destroy: function(){ clearInterval(this.blinkInterval); clearInterval(this.tickInterval); $(document).off("visibilitychange", {ns: this.id}); return this.element; } }); }(Metro, m4q));