countdown-8.x-1.8/js/integrations/countdown.flipclock.integration.js

js/integrations/countdown.flipclock.integration.js
/**
 * @file
 * Integration for the FlipClock.js library (supports v0.7.x and v0.10.x).
 *
 * This file handles initialization of FlipClock instances for both the legacy
 * jQuery-based version (0.7.x) and the modern ES6 version (0.10.x).
 */

(function (Drupal) {
  'use strict';

  /**
   * Initialize a FlipClock timer.
   *
   * @param {Element} element
   *   The DOM element to initialize as a timer.
   * @param {Object} settings
   *   The settings object from drupalSettings.
   */
  function initializeFlipClock(element, settings) {
    // Resolve settings using shared utility.
    const config = Drupal.countdown.utils.resolveCountdownSettings(element, settings, 'flipclock');

    // Determine library version from settings or detection.
    const isModernVersion = config.isModernVersion || detectFlipClockVersion();
    const libraryVersion = config.libraryVersion || (isModernVersion ? '0.10.8' : '0.7.8');

    // Get target date from various possible sources.
    const targetDate = config.target_date || element.dataset.countdownTarget;

    if (!targetDate) {
      Drupal.countdown.utils.handleError(element, 'No target date specified', 'flipclock');
      return;
    }

    // Initialize based on detected version.
    if (isModernVersion) {
      initializeModernFlipClock(element, config, targetDate);
    } else {
      initializeLegacyFlipClock(element, config, targetDate);
    }
  }

  /**
   * Detect FlipClock version based on available APIs.
   *
   * @return {boolean}
   *   True if modern version (0.10.x), false if legacy (0.7.x).
   */
  function detectFlipClockVersion() {
    // Modern version has FlipClock.Face, legacy doesn't.
    return typeof FlipClock !== 'undefined' && typeof FlipClock.Face !== 'undefined';
  }

  /**
   * Initialize modern FlipClock (v0.10.x).
   *
   * @param {Element} element
   *   The DOM element.
   * @param {Object} settings
   *   The merged settings.
   * @param {string} targetDate
   *   The target date string.
   */
  function initializeModernFlipClock(element, settings, targetDate) {
    // Validate library availability.
    if (typeof FlipClock === 'undefined') {
      Drupal.countdown.utils.handleError(element, 'Modern FlipClock library not loaded', 'flipclock');
      return;
    }

    // Parse target date and calculate time difference.
    const now = new Date();
    const target = new Date(targetDate);

    // Validate target date.
    if (isNaN(target.getTime())) {
      Drupal.countdown.utils.handleError(element, 'Invalid target date: ' + targetDate, 'flipclock');
      return;
    }

    const diffMs = settings.countdown !== false ? target - now : now - target;

    // Check if countdown has already expired.
    if (settings.countdown !== false && diffMs <= 0) {
      Drupal.countdown.utils.showExpiredMessage(element, settings, 'flipclock');
      return;
    }

    // Get face name from settings (v0.10.x uses 'face' key).
    const faceName = settings.face || settings.clockFace || 'DayCounter';

    // Build configuration for modern FlipClock.
    const config = {
      face: faceName,
      countdown: settings.countdown !== false,
      autoPlay: settings.autoPlay !== false,
      autoStart: settings.autoStart !== false
    };

    // Add language/labels if specified.
    if (settings.language) {
      config.language = settings.language;
    }
    if (settings.labels) {
      config.labels = settings.labels;
    }

    // Add minimum digits if specified.
    if (settings.minimumDigits !== undefined) {
      config.minimumDigits = settings.minimumDigits;
    }

    try {
      // Create FlipClock instance with value directly.
      const clock = new FlipClock(element, target, config);

      // Store instance for cleanup.
      Drupal.countdown.storeInstance(element, {
        instance: clock,
        stop: function () {
          if (clock && clock.stop) {
            clock.stop();
          }
        }
      });

      // Mark as initialized.
      element.classList.add('countdown-initialized');
      element.classList.add('flipclock');

      // Dispatch initialization event.
      Drupal.countdown.utils.dispatchEvent(element, 'initialized', {
        library: 'flipclock',
        element: element,
        settings: settings,
        instance: clock
      });

      // Monitor for completion.
      monitorFlipClockCompletion(element, clock, settings);
    }
    catch (error) {
      console.error('Countdown: Failed to create modern FlipClock', error);
      Drupal.countdown.utils.handleError(element, 'Failed to create FlipClock: ' + error.message, 'flipclock');
    }
  }

  /**
   * Initialize legacy FlipClock (v0.7.x).
   *
   * @param {Element} element
   *   The DOM element.
   * @param {Object} settings
   *   The merged settings.
   * @param {string} targetDate
   *   The target date string.
   */
  function initializeLegacyFlipClock(element, settings, targetDate) {
    // Validate library and jQuery availability.
    if (typeof FlipClock === 'undefined' || typeof jQuery === 'undefined') {
      console.error('Countdown: Legacy FlipClock or jQuery not loaded.');
      element.dispatchEvent(new CustomEvent('countdown:error', {
        detail: { message: 'Legacy FlipClock library or jQuery not loaded' }
      }));
      return;
    }

    const $ = jQuery;

    // Parse dates and calculate difference.
    const now = new Date();
    const target = new Date(targetDate);

    // Validate target date.
    if (isNaN(target.getTime())) {
      console.error('Countdown: Invalid target date for FlipClock:', targetDate);
      element.dispatchEvent(new CustomEvent('countdown:error', {
        detail: { message: 'Invalid target date: ' + targetDate }
      }));
      return;
    }

    const diffMs = settings.countdown ? target - now : now - target;
    const diffSeconds = Math.floor(Math.abs(diffMs) / 1000);

    // Check if countdown has already expired.
    if (settings.countdown && diffMs <= 0) {
      const finishMessage = settings.finish_message ||
        settings.finishMessage || "Time's up!";
      $(element).html('<div class="flipclock-expired">' +
        finishMessage + '</div>');
      element.dispatchEvent(new CustomEvent('countdown:complete', {
        detail: { element: element, library: 'flipclock' }
      }));
      return;
    }

    // Build configuration for legacy FlipClock.
    const config = {
      clockFace: settings.clockFace || settings.face || 'DayCounter',
      countdown: settings.countdown !== false,
      autoStart: settings.autoStart !== false,
      callbacks: {
        stop: function () {
          const finishMessage = settings.finish_message ||
            settings.finishMessage || "Time's up!";
          $(element).find('.flip-clock-wrapper').append(
            '<div class="flipclock-finish-message">' + finishMessage + '</div>'
          );
          element.dispatchEvent(new CustomEvent('countdown:complete', {
            detail: { element: element, library: 'flipclock' }
          }));
        }
      }
    };

    // Add language if specified.
    if (settings.language) {
      config.language = settings.language;
    }

    // Add minimum digits if specified.
    if (settings.minimumDigits !== undefined) {
      config.minimumDigits = settings.minimumDigits;
    }

    try {
      // Create legacy FlipClock instance.
      const clock = $(element).FlipClock(diffSeconds, config);

      // Store instance for cleanup.
      Drupal.countdown.storeInstance(element, {
        instance: clock,
        stop: function () {
          if (clock && clock.stop) {
            clock.stop();
          }
        }
      });

      // Mark as initialized.
      element.classList.add('countdown-initialized');
      element.classList.add('flipclock-legacy');

      // Dispatch initialization event.
      element.dispatchEvent(new CustomEvent('countdown:initialized', {
        detail: {
          library: 'flipclock',
          element: element,
          settings: settings,
          instance: clock
        }
      }));
    }
    catch (error) {
      console.error('Countdown: Failed to create legacy FlipClock', error);
      element.dispatchEvent(new CustomEvent('countdown:error', {
        detail: { message: 'Failed to create FlipClock: ' + error.message }
      }));
    }
  }

  /**
   * Monitor FlipClock for completion.
   *
   * @param {Element} element
   *   The countdown element.
   * @param {Object} clock
   *   The FlipClock instance.
   * @param {Object} settings
   *   The settings object.
   */
  function monitorFlipClockCompletion(element, clock, settings) {
    // Set up an interval to check for completion.
    const checkInterval = setInterval(function () {
      let isComplete = false;

      try {
        // Check different ways based on clock configuration.
        if (clock.value !== undefined) {
          const value = clock.value;
          if (value instanceof Date) {
            const now = new Date();
            isComplete = settings.countdown !== false ? value <= now : value >= now;
          } else if (typeof value === 'number') {
            isComplete = settings.countdown !== false ? value <= 0 : value >= 0;
          }
        }

        // Additional check for modern FlipClock versions
        if (clock.face && clock.face.value) {
          const faceValue = clock.face.value.value;
          if (faceValue instanceof Date) {
            const now = new Date();
            isComplete = settings.countdown !== false ? faceValue <= now : faceValue >= now;
          } else if (typeof faceValue === 'number') {
            isComplete = settings.countdown !== false ? faceValue <= 0 : faceValue >= 0;
          }
        }
      } catch (e) {
        // Silently handle access errors.
      }

      if (isComplete) {
        clearInterval(checkInterval);

        // Stop the clock if possible.
        if (clock.stop && typeof clock.stop === 'function') {
          clock.stop();
        }

        // Show completion message.
        Drupal.countdown.utils.showExpiredMessage(element, settings, 'flipclock');
      }
    }, 1000);

    // Store interval ID for cleanup.
    element.dataset.flipclockInterval = checkInterval;
  }

  // Register loader with countdown system.
  Drupal.countdown.registerLoader('flipclock', initializeFlipClock);

})(Drupal);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc