jQuery(function($) { // https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/repeat if (!String.prototype.repeat) { String.prototype.repeat = function(count) { 'use strict'; if (this == null) { throw new TypeError('can\'t convert ' + this + ' to object'); } var str = '' + this; count = +count; if (count != count) { count = 0; } if (count < 0) { throw new RangeError('repeat count must be non-negative'); } if (count == Infinity) { throw new RangeError('repeat count must be less than infinity'); } count = Math.floor(count); if (str.length == 0 || count == 0) { return ''; } // Обеспечение того, что count является 31-битным целым числом, позволяет нам значительно // соптимизировать главную часть функции. Впрочем, большинство современных (на август // 2014 года) браузеров не обрабатывают строки, длиннее 1 << 28 символов, так что: if (str.length * count >= 1 << 28) { throw new RangeError( 'repeat count must not overflow maximum string size'); } var rpt = ''; for (var i = 0; i < count; i++) { rpt += str; } return rpt; }; } // https://github.com/uxitten/polyfill/blob/master/string.polyfill.js // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart if (!String.prototype.padStart) { String.prototype.padStart = function padStart(targetLength, padString) { targetLength = targetLength >> 0; //truncate if number or convert non-number to 0; padString = String((typeof padString !== 'undefined' ? padString : ' ')); if (this.length > targetLength) { return String(this); } else { targetLength = targetLength - this.length; if (targetLength > padString.length) { padString += padString.repeat(targetLength / padString.length); //append to original to ensure we are longer than needed } return padString.slice(0, targetLength) + String(this); } }; } $.fn.flipper = function(action, options) { var $flipper = $(this); var action = action || 'init'; var settings = $.extend({ // defaults. reverse: $flipper.data('reverse') || false, datetime: $flipper.data('datetime') || 'now', template: $flipper.data('template') || 'HH:ii:ss', labels: $flipper.data('labels') || 'Hours|Minutes|Seconds', preload: true, }, options); if (action === 'init') { if ($flipper.hasClass('flipper-initialized')) { return; } $flipper.addClass('flipper-initialized'); var templateParts = settings.template.split('|'); var labelsArray = settings.labels.split('|'); var n; templateParts.forEach(function(part, index) { if (index > 0) { $flipper.append( '
:
'); } $flipper.append( '
'); var $part = $flipper.find('.flipper-group.flipper-' + part); if (typeof labelsArray[index] !== 'undefined') { $part.append(''); } if (part === 'd' || part === 'H' || part === 'i' || part === 's') { var rev = settings.reverse ? 'reverse' : ''; $part.append('
'); } if (part === 'dd' || part === 'ddd' || part === 'HH' || part === 'ii' || part === 'ss') { var rev = settings.reverse ? 'reverse' : ''; $part.append('
'); $part.append('
'); $part.append('
'); if (part === 'ddd') { $part.append('
'); $part.append('
'); } } if (part === 'd') { for (n = 0; n <= 31; n++) { $part.find('.flipper-digit:eq(0)'). append('
' + n + '
'); $part.find('.flipper-digit:eq(1)'). append('
' + n + '
'); } } if (part === 'H') { for (n = 0; n <= 23; n++) { $part.find('.flipper-digit:eq(0)'). append('
' + n + '
'); $part.find('.flipper-digit:eq(1)'). append('
' + n + '
'); } } if (part === 'i' || part === 's') { for (n = 0; n <= 59; n++) { $part.find('.flipper-digit:eq(0)'). append('
' + n + '
'); $part.find('.flipper-digit:eq(1)'). append('
' + n + '
'); } } if (part === 'dd' || part === 'ddd') { for (n = 0; n <= 9; n++) { $part.find('.flipper-digit:eq(0)'). append('
' + n + '
'); $part.find('.flipper-digit:eq(1)'). append('
' + n + '
'); if (part === 'ddd') { $part.find('.flipper-digit:eq(2)'). append('
' + n + '
'); } } } if (part === 'HH') { for (n = 0; n <= 2; n++) { $part.find('.flipper-digit:eq(0)'). append('
' + n + '
'); } for (n = 0; n <= 9; n++) { $part.find('.flipper-digit:eq(1)'). append('
' + n + '
'); } } if (part === 'ii' || part === 'ss') { for (n = 0; n <= 5; n++) { $part.find('.flipper-digit:eq(0)'). append('
' + n + '
'); } for (n = 0; n <= 9; n++) { $part.find('.flipper-digit:eq(1)'). append('
' + n + '
'); } } }); if (settings.preload) { setFlipperDate($flipper, settings.datetime, false); } setInterval(function() { setFlipperDate($flipper, settings.datetime, true); }, 1000); upsizeToParent($flipper); $(window).on('resize', function() { upsizeToParent($flipper); }); } var flipTime = 400; var $body = $('body'); function flipDigit($digit) { if (!$digit.closest('.flipper').is('.flipper-initialized')) { return; } if ($digit.hasClass('r')) { setTimeout(function() { flipDigit($digit); }, flipTime + 1); return; } $digit.addClass('r'); var $currentTop = $digit.find('.digit-top'); var $currentTop2 = $digit.find('.digit-top2'); var $currentBottom = $digit.find('.digit-bottom'); var $activeDigit = $digit.find('.digit-face.active'); var $firstDigit = $digit.find('.digit-face:first'); var $prevDigit = $activeDigit.prev('.digit-face'); var $nextDigit = $activeDigit.next('.digit-face'); var $lastDigit = $digit.find('.digit-face:last'); if ($digit.hasClass('reverse')) { var $next = $prevDigit.length ? $prevDigit : $lastDigit; } else { var $next = $nextDigit.length ? $nextDigit : $firstDigit; } var current = parseInt($currentTop.html()); var next = $next.html(); $digit.find('.digit-next').html(next); $digit.find('.digit-face').removeClass('active'); $next.addClass('active'); $currentTop.addClass('r'); $currentTop2.addClass('r'); $currentBottom.addClass('r'); if (next.toString() === $digit.attr('data-value')) { $digit.removeAttr('data-value'); } setTimeout(function() { $currentTop.html(next).hide(); $currentTop2.html(next); setTimeout(function() { $currentBottom.html(next).removeClass('r'); $currentTop.removeClass('r').show(); $currentTop2.html(next).removeClass('r'); $digit.removeClass('r'); }, flipTime / 2); }, flipTime / 2); } function upsizeToParent($flipper) { var parentWidth; var flipperWidth; var maxFontSize = 1000; var fontSize = maxFontSize; var i = 0; var minFontSize = 0; $flipper.css('font-size', fontSize + 'px'); while (i < 20) { i++; parentWidth = $flipper.innerWidth(); $flipper.css('width', '9999px'); flipperWidth = 0; $flipper.find('.flipper-group').each(function() { var w = parseFloat($(this).outerWidth()); flipperWidth += w; }); if ((parentWidth - flipperWidth) < 10 && (parentWidth - flipperWidth) > 0) { $flipper.css('width', ''); return; } if (flipperWidth > parentWidth) { maxFontSize = fontSize < maxFontSize ? fontSize : maxFontSize; } else { minFontSize = fontSize > minFontSize ? fontSize : minFontSize; } fontSize = (maxFontSize + minFontSize) / 2; $flipper.css('width', ''); $flipper.css('font-size', fontSize + 'px'); } } function setDigitValue(digitIndex, value) { var $flipper = $('.flipper'); var $digit = $flipper.find('.flipper-digit:eq(' + digitIndex + ')'); var currentValue = getDigitValue($digit); if (currentValue.toString() === value.toString()) { return; // has same value, do nothing } $digit.attr('data-value', value); } setInterval(function() { var $flipper = $('.flipper'); $flipper.find('.flipper-digit[data-value]').each(function() { var $digit = $(this); if ($digit.find('.active').html() === $digit.attr('data-value')) { return; // } if (!$digit.is('.r')) { flipDigit($digit); } }); }, flipTime / 4); function formatFlipperDate(dateStr) { var a = dateStr.split(' '); var d = a[0].split('-'); var t = a[1].split(':'); var date = new Date(d[0], (d[1] - 1), d[2], t[0], t[1], t[2]); return date; } function addAppearance($flipper) { $flipper.find('.flipper-digit').each(function() { var $digit = $(this); var value = $digit.find('.digit-face.active').html(); $digit.find('.digit-top').remove(); $digit.find('.digit-top2').remove(); $digit.find('.digit-bottom').remove(); $digit.find('.digit-next').remove(); $digit.prepend('
' + value + '
'); $digit.prepend('
' + value + '
'); $digit.prepend('
' + value + '
'); $digit.prepend('
'); }); } function setFlipperDate($flipper, dateString, animate) { var animate = animate || false; if (!$flipper.is(':visible')) { $flipper.addClass('flipper-invisible'); return; } if ($flipper.hasClass('flipper-invisible')) { $flipper.removeClass('flipper-invisible'); upsizeToParent($flipper); setFlipperDate($flipper, settings.datetime, false); } var now = Date.now(); if (dateString === 'now') { var now = new Date(); var seconds = now.getSeconds(); var minutes = now.getMinutes(); var hours = now.getHours(); var days = now.getDate(); } else { var timestamp = Date.parse(formatFlipperDate(dateString)); var remainder = (timestamp - now) / 1000; var days = Math.floor(remainder / 60 / 60 / 24); remainder -= days * 60 * 60 * 24; var hours = Math.floor(remainder / 60 / 60); remainder -= hours * 60 * 60; var minutes = Math.floor(remainder / 60); remainder -= minutes * 60; var seconds = Math.floor(remainder); } var days_str = days.toString().padStart(3, '0'); var hours_str = hours.toString().padStart(2, '0'); var minutes_str = minutes.toString().padStart(2, '0'); var seconds_str = seconds.toString().padStart(2, '0'); if (animate) { // one section $flipper.find('.flipper-d'). find('.flipper-digit:eq(0)'). attr('data-value', days); $flipper.find('.flipper-H'). find('.flipper-digit:eq(0)'). attr('data-value', hours); $flipper.find('.flipper-i'). find('.flipper-digit:eq(0)'). attr('data-value', minutes); $flipper.find('.flipper-s'). find('.flipper-digit:eq(0)'). attr('data-value', seconds); // two sections $flipper.find('.flipper-dd'). find('.flipper-digit:eq(0)'). attr('data-value', days_str[1]); $flipper.find('.flipper-dd'). find('.flipper-digit:eq(1)'). attr('data-value', days_str[2]); $flipper.find('.flipper-HH'). find('.flipper-digit:eq(0)'). attr('data-value', hours_str[0]); $flipper.find('.flipper-HH'). find('.flipper-digit:eq(1)'). attr('data-value', hours_str[1]); $flipper.find('.flipper-ii'). find('.flipper-digit:eq(0)'). attr('data-value', minutes_str[0]); $flipper.find('.flipper-ii'). find('.flipper-digit:eq(1)'). attr('data-value', minutes_str[1]); $flipper.find('.flipper-ss'). find('.flipper-digit:eq(0)'). attr('data-value', seconds_str[0]); $flipper.find('.flipper-ss'). find('.flipper-digit:eq(1)'). attr('data-value', seconds_str[1]); // three sections $flipper.find('.flipper-ddd'). find('.flipper-digit:eq(0)'). attr('data-value', days_str[0]); $flipper.find('.flipper-ddd'). find('.flipper-digit:eq(1)'). attr('data-value', days_str[1]); $flipper.find('.flipper-ddd'). find('.flipper-digit:eq(2)'). attr('data-value', days_str[2]); } else { $flipper.find('.flipper-group .flipper-digit').removeAttr('data-value'); $flipper.find('.digit-face.active').removeClass('active'); // one section $flipper.find( '.flipper-d .flipper-digit:eq(0) .digit-face:contains(' + days + ')').addClass('active'); $flipper.find( '.flipper-H .flipper-digit:eq(0) .digit-face:contains(' + hours + ')').addClass('active'); $flipper.find( '.flipper-i .flipper-digit:eq(0) .digit-face:contains(' + minutes + ')').addClass('active'); $flipper.find( '.flipper-s .flipper-digit:eq(0) .digit-face:contains(' + seconds + ')').addClass('active'); // two sections $flipper.find('.flipper-dd .flipper-digit:eq(0) .digit-face:contains(' + days_str[1] + ')').addClass('active'); $flipper.find('.flipper-dd .flipper-digit:eq(1) .digit-face:contains(' + days_str[2] + ')').addClass('active'); $flipper.find('.flipper-HH .flipper-digit:eq(0) .digit-face:contains(' + hours_str[0] + ')').addClass('active'); $flipper.find('.flipper-HH .flipper-digit:eq(1) .digit-face:contains(' + hours_str[1] + ')').addClass('active'); $flipper.find('.flipper-ii .flipper-digit:eq(0) .digit-face:contains(' + minutes_str[0] + ')').addClass('active'); $flipper.find('.flipper-ii .flipper-digit:eq(1) .digit-face:contains(' + minutes_str[1] + ')').addClass('active'); $flipper.find('.flipper-ss .flipper-digit:eq(0) .digit-face:contains(' + seconds_str[0] + ')').addClass('active'); $flipper.find('.flipper-ss .flipper-digit:eq(1) .digit-face:contains(' + seconds_str[1] + ')').addClass('active'); // three sections $flipper.find( '.flipper-ddd .flipper-digit:eq(0) .digit-face:contains(' + days_str[0] + ')').addClass('active'); $flipper.find( '.flipper-ddd .flipper-digit:eq(1) .digit-face:contains(' + days_str[1] + ')').addClass('active'); $flipper.find( '.flipper-ddd .flipper-digit:eq(2) .digit-face:contains(' + days_str[2] + ')').addClass('active'); addAppearance($flipper); } } }; });