media_duplicate_check-1.0.0/js/duplicate-check.js

js/duplicate-check.js
/**
 * @file
 * JavaScript for media duplicate checking functionality.
 */

(function ($, Drupal, drupalSettings) {
  'use strict';

  /**
   * Get translated string from drupalSettings or fallback to English.
   */
  function getTranslation(key, fallback) {
    if (drupalSettings.media_duplicate_check && 
        drupalSettings.media_duplicate_check.translations && 
        drupalSettings.media_duplicate_check.translations[key]) {
      return drupalSettings.media_duplicate_check.translations[key];
    }
    return fallback || key;
  }

  /**
   * Store warning state globally to persist through AJAX updates
   */
  window.duplicateWarningState = {
    hasWarning: false,
    warningHtml: '',
    filename: '',
    fileInput: null
  };

  /**
   * Media duplicate check behaviors.
   */
  Drupal.behaviors.mediaDuplicateCheck = {
    attach: function (context, settings) {
      // Initialize the duplicate check handler.
      if (!window.mediaDuplicateCheck) {
        window.mediaDuplicateCheck = new MediaDuplicateCheck();
      }
      
      // Restore warning state if it exists
      if (window.duplicateWarningState.hasWarning && window.duplicateWarningState.warningHtml) {
        var $container = $('#duplicate-check-wrapper');
        if ($container.length > 0 && $container.html().trim() === '') {
          $container.html(window.duplicateWarningState.warningHtml).addClass('has-duplicate-warning');
          // Re-attach event handlers
          window.mediaDuplicateCheck.attachWarningHandlers($container);
        }
      }
      
      // Re-check file inputs that may have been added via AJAX
      var $fileInputs = $('input[type="file"]', context);
      $fileInputs.each(function() {
        if (this.files && this.files.length > 0 && !$(this).data('duplicate-checked')) {
          var filename = this.files[0].name;
          window.mediaDuplicateCheck.checkOriginalFilename(filename, this);
          $(this).data('duplicate-checked', true);
        }
      });
    }
  };

  /**
   * MediaDuplicateCheck class.
   */
  function MediaDuplicateCheck() {
    this.fileInput = null;
    this.confirmed = false;
  }

  /**
   * Confirm the upload and close modal.
   */
  MediaDuplicateCheck.prototype.confirmUpload = function() {
    // Set the confirmation flag.
    $('#duplicate-confirmed').val('1');
    this.confirmed = true;
    
    // Send AJAX request to set session confirmation
    var filename = $('.duplicate-media-preview').data('filename') || '';
    if (filename) {
      $.post('/admin/config/media/duplicate-check/confirm', {
        filename: filename,
        confirmed: '1'
      });
    }
    
    // Close the modal.
    $('.ui-dialog-content').dialog('close');
    
    // Clear the warning message.
    $('#duplicate-check-wrapper').html('');
    
    // Show a confirmation message using proper Drupal markup.
    var confirmMessage = '<div class="messages messages--status">' +
      '<h2 class="visually-hidden">' + getTranslation('status_message', 'Status message') + '</h2>' +
      '<p>' + getTranslation('upload_confirmed_save', 'Upload confirmed. You may now save the media item.') + '</p>' +
      '</div>';
    $('#duplicate-check-wrapper').html(confirmMessage);
    
    // Enable form submission buttons.
    $('form').find('input[type="submit"], button[type="submit"]').prop('disabled', false);
  };

  /**
   * Cancel the upload and reset the file input.
   */
  MediaDuplicateCheck.prototype.cancelUpload = function() {
    // Reset the confirmation flag.
    $('#duplicate-confirmed').val('0');
    this.confirmed = false;
    
    // Close the modal.
    $('.ui-dialog-content').dialog('close');
    
    // Find and click the remove button to properly clear the uploaded file
    var $removeBtn = $('input[name*="remove_button"], button[name*="remove_button"]').filter(':visible').first();
    
    if ($removeBtn.length > 0) {
      // Click the remove button to trigger proper AJAX removal
      $removeBtn.trigger('click');
      
      // Clear the warning message.
      $('#duplicate-check-wrapper').html('');
    } else {
      // Fallback: manually clear file inputs if no remove button found
      var fileInputs = $('input[type="file"]');
      fileInputs.each(function() {
        $(this).val('');
        // Trigger change event to clear any file preview.
        $(this).trigger('change');
      });
      
      // Clear the warning message.
      $('#duplicate-check-wrapper').html('');
      
      // Show a cancellation message.
      var cancelMessage = '<div class="messages messages--info">' +
        '<h2 class="visually-hidden">' + getTranslation('information_message', 'Information message') + '</h2>' +
        getTranslation('upload_cancelled', 'Upload cancelled. Please select a different file.') +
        '</div>';
      $('#duplicate-check-wrapper').html(cancelMessage);
      
      // Fade out the message after 3 seconds.
      setTimeout(function() {
        $('#duplicate-check-wrapper').fadeOut('slow', function() {
          $(this).html('').show();
        });
      }, 3000);
    }
  };

  /**
   * Attach event handlers to warning buttons
   */
  MediaDuplicateCheck.prototype.attachWarningHandlers = function($container) {
    var self = this;
    
    $('.duplicate-proceed-btn', $container).off('click').on('click', function() {
      var confirmedFilename = $(this).data('filename');
      $('#duplicate-confirmed').val('1');
      self.confirmed = true;
      
      // Clear warning state
      window.duplicateWarningState.hasWarning = false;
      window.duplicateWarningState.warningHtml = '';
      
      // Set session confirmation
      $.post('/admin/config/media/duplicate-check/confirm', {
        filename: confirmedFilename,
        confirmed: '1'
      });
      
      // Clear warning
      $container.html('').removeClass('has-duplicate-warning');
      
      // Show confirmation message using proper Drupal markup
      var confirmMessage = '<div class="messages messages--status">' +
        '<h2 class="visually-hidden">' + getTranslation('status_message', 'Status message') + '</h2>' +
        '<p>' + getTranslation('upload_confirmed_auto_name', 'Upload confirmed. The file will be uploaded with an automatically generated name to avoid conflicts.') + '</p>' +
        '</div>';
      $container.html(confirmMessage);
    });
    
    $('.duplicate-cancel-btn', $container).off('click').on('click', function() {
      // Clear warning state
      window.duplicateWarningState.hasWarning = false;
      window.duplicateWarningState.warningHtml = '';
      
      // Clear warning first
      $container.html('').removeClass('has-duplicate-warning');
      
      // Look for remove button with more specific selectors
      var $removeBtn = $('input[value="Remove"], button[value="Remove"], input[id*="remove-button"], button[id*="remove-button"]').filter(':visible');
      
      if ($removeBtn.length > 0) {
        // Get the form and trigger submit with the remove button
        var $form = $removeBtn.closest('form');
        var $removeButton = $removeBtn.first();
        
        // Create a temporary submit button click event
        var formData = new FormData($form[0]);
        formData.append($removeButton.attr('name'), $removeButton.val());
        
        // Try to trigger the AJAX request manually
        if (Drupal.ajax && Drupal.ajax.instances) {
          // Find the AJAX instance for this button
          var ajaxInstance = null;
          for (var i in Drupal.ajax.instances) {
            if (Drupal.ajax.instances[i] && Drupal.ajax.instances[i].element === $removeButton[0]) {
              ajaxInstance = Drupal.ajax.instances[i];
              break;
            }
          }
          
          if (ajaxInstance) {
            try {
              ajaxInstance.eventResponse(ajaxInstance, null);
            } catch (e) {
              // Fallback to click events
              $removeButton.trigger('mousedown').trigger('mouseup').trigger('click');
              if ($removeButton[0].click) {
                $removeButton[0].click();
              }
            }
          } else {
            // Fallback to click events
            $removeButton.trigger('mousedown').trigger('mouseup').trigger('click');
            if ($removeButton[0].click) {
              $removeButton[0].click();
            }
          }
        } else {
          // Fallback to click events
          $removeButton.trigger('mousedown').trigger('mouseup').trigger('click');
          if ($removeButton[0].click) {
            $removeButton[0].click();
          }
        }
      } else {
        // More aggressive fallback: look for any upload button or file input and try to reset
        var $form = $container.closest('form');
        var $fileInputs = $form.find('input[type="file"]');
        
        // Clear file inputs
        $fileInputs.each(function() {
          $(this).val('');
          $(this).trigger('change');
        });
        
        // Try to find and trigger any "Remove" or upload-related buttons
        var $anyRemoveBtn = $form.find('input[type="submit"], button[type="submit"]').filter(function() {
          var value = $(this).val() || $(this).text();
          return value && (value.toLowerCase().includes('remove') || value.toLowerCase().includes('fjern'));
        });
        
        if ($anyRemoveBtn.length > 0) {
          $anyRemoveBtn.first().click();
        } else {
          // Show cancellation message using proper Drupal markup
          var cancelMessage = '<div class="messages messages--info">' +
            '<h2 class="visually-hidden">' + getTranslation('information_message', 'Information message') + '</h2>' +
            '<p>' + getTranslation('upload_cancelled', 'Upload cancelled. Please select a different file.') + '</p>' +
            '</div>';
          $container.html(cancelMessage);
          
          // Fade out the message after 3 seconds
          setTimeout(function() {
            $container.fadeOut('slow', function() {
              $(this).html('').show();
            });
          }, 3000);
        }
      }
    });
  };

  /**
   * Reset the duplicate check state.
   */
  MediaDuplicateCheck.prototype.reset = function() {
    $('#duplicate-confirmed').val('0');
    this.confirmed = false;
    
    // Clear global warning state
    window.duplicateWarningState = {
      hasWarning: false,
      warningHtml: '',
      filename: '',
      fileInput: null
    };
    
    // Clear all possible warning containers
    $('#duplicate-check-wrapper').html('').removeClass('has-duplicate-warning');
    $('.media-library-add-form #duplicate-check-wrapper').html('').removeClass('has-duplicate-warning');
    $('[data-drupal-selector*="media-library"] #duplicate-check-wrapper').html('').removeClass('has-duplicate-warning');
  };

  /**
   * Check for duplicates using the original filename (before upload).
   */
  MediaDuplicateCheck.prototype.checkOriginalFilename = function(filename, fileInput) {
    var self = this;
    
    // Skip check if already confirmed for this file
    if (self.confirmed) {
      return;
    }
    
    // Send AJAX request to check for duplicates
    $.ajax({
      url: '/admin/config/media/duplicate-check/check-original',
      method: 'POST',
      data: {
        filename: filename
      },
      success: function(response) {
        if (response.duplicates && response.duplicates.length > 0) {
          // Show warning and modal
          self.showPreUploadWarning(response.duplicates, filename, fileInput);
        } else {
          // Clear any previous warnings
          $('#duplicate-check-wrapper').html('');
          // Allow normal upload to proceed
          self.confirmed = true;
        }
      },
      error: function(xhr, status, error) {
        // Allow upload to proceed on error
        self.confirmed = true;
      }
    });
  };

  /**
   * Show warning before upload when duplicates are detected.
   */
  MediaDuplicateCheck.prototype.showPreUploadWarning = function(duplicates, filename, fileInput) {
    var self = this;
    var count = duplicates.length;
    var message = Drupal.formatPlural(count,
      '@count media item with the filename "@filename" already exists. Are you sure you want to upload this file with a new filename?',
      '@count media items with the filename "@filename" already exist. Are you sure you want to upload this file with a new filename?',
      {'@count': count, '@filename': filename}
    );
    
    // Build list of existing media links using proper Drupal markup
    var existingMediaLinks = '';
    if (duplicates.length > 0) {
      existingMediaLinks = '<div class="duplicate-warning__existing-media">' +
        '<p class="existing-media-links__header">' + getTranslation('existing_media', 'Existing media:') + '</p>' +
        '<ul class="existing-media-links__list">';
      duplicates.forEach(function(media) {
        existingMediaLinks += '<li class="existing-media-links__item">' +
          '<a href="' + media.url + '" target="_blank" class="existing-media-link">' + 
          media.name + '</a> (' + media.type + ', ' + media.created_formatted + ')' +
          '</li>';
      });
      existingMediaLinks += '</ul></div>';
    }
    
    // Show warning message using details/summary structure matching Claro pattern
    var warningHtml = '<details class="duplicate-warning claro-details" open data-once="details">' +
      '<summary class="claro-details__summary" role="button" aria-expanded="true">' +
      getTranslation('duplicate_file_detected', 'Duplicate file detected: @filename').replace('@filename', filename) +
      '</summary>' +
      '<div class="claro-details__wrapper details-wrapper">' +
      '<p class="duplicate-warning__message">' + message + '</p>' +
      existingMediaLinks +
      '<div class="duplicate-warning-actions form-actions">' +
      '<button type="button" class="button button--danger duplicate-proceed-btn" data-filename="' + filename + '">' +
      getTranslation('yes_upload_anyway', 'Yes, Upload Anyway') + '</button>' +
      '<button type="button" class="button button--primary duplicate-cancel-btn">' +
      getTranslation('cancel', 'Cancel') + '</button>' +
      '</div>' +
      '</div>' +
      '</details>';
    
    // Store warning state globally
    window.duplicateWarningState = {
      hasWarning: true,
      warningHtml: warningHtml,
      filename: filename,
      fileInput: fileInput
    };
    
    // Find the appropriate container for the warning
    var $warningContainer = $('#duplicate-check-wrapper');
    
    // If not found, try to find it in media library context
    if ($warningContainer.length === 0) {
      var $mediaLibraryForm = $(fileInput).closest('.media-library-add-form, [data-drupal-selector*="media-library"]');
      if ($mediaLibraryForm.length > 0) {
        // Create a warning container if it doesn't exist
        if ($mediaLibraryForm.find('#duplicate-check-wrapper').length === 0) {
          $mediaLibraryForm.prepend('<div id="duplicate-check-wrapper"></div>');
        }
        $warningContainer = $mediaLibraryForm.find('#duplicate-check-wrapper');
      }
    }
    
    // Fallback: create container at the top of the form
    if ($warningContainer.length === 0) {
      var $form = $(fileInput).closest('form');
      if ($form.find('#duplicate-check-wrapper').length === 0) {
        $form.prepend('<div id="duplicate-check-wrapper"></div>');
      }
      $warningContainer = $form.find('#duplicate-check-wrapper');
    }
    
    // Store the warning HTML as data to persist through AJAX updates
    $warningContainer.html(warningHtml).data('duplicate-warning', warningHtml);
    
    // Add a class to the container for CSS styling
    $warningContainer.addClass('has-duplicate-warning');
    
    // Don't disable the file input - just show the warning
    // Users can still proceed with normal upload process
    
    // Attach event handlers
    this.attachWarningHandlers($warningContainer);
  };

  // Make the MediaDuplicateCheck instance globally available.
  window.mediaDuplicateCheck = new MediaDuplicateCheck();

  // Listen for file input changes to check for duplicates BEFORE upload.
  $(document).on('change', 'input[type="file"]', function(e) {
    // Skip if this is triggered by our duplicate check process
    if (e.namespace === 'duplicateCheck') {
      return;
    }
    
    var fileInput = this;
    var files = fileInput.files;
    
    // Check if this is in a media library context
    var isMediaLibrary = $(fileInput).closest('.media-library-add-form').length > 0 || 
                        $(fileInput).closest('[data-drupal-selector*="media-library"]').length > 0;
    
    if (files && files.length > 0) {
      var file = files[0];
      var filename = file.name;
      
      // Check if this file was already confirmed
      if (window.mediaDuplicateCheck && window.mediaDuplicateCheck.confirmed) {
        // Reset confirmation for new file
        window.mediaDuplicateCheck.confirmed = false;
        $('#duplicate-confirmed').val('0');
        return;
      }
      
      // Check for duplicates using the original filename
      if (window.mediaDuplicateCheck) {
        window.mediaDuplicateCheck.checkOriginalFilename(filename, fileInput);
      }
    }
    
    if (window.mediaDuplicateCheck && !window.mediaDuplicateCheck.confirmed) {
      window.mediaDuplicateCheck.reset();
    }
  });

  // Listen for AJAX events to restore warnings if needed
  $(document).ajaxComplete(function(event, xhr, settings) {
    // Check if this was a media library related AJAX call
    if (settings.url && (settings.url.indexOf('media-library') !== -1 || settings.url.indexOf('ajax_form') !== -1)) {
      // Restore warnings for any file inputs with data
      setTimeout(function() {
        if (window.duplicateWarningState.hasWarning && window.duplicateWarningState.warningHtml) {
          var $container = $('#duplicate-check-wrapper');
          
          // If container doesn't exist, create it
          if ($container.length === 0) {
            var $form = $('.media-library-add-form, form[data-drupal-selector*="media-library"]').first();
            if ($form.length > 0) {
              $form.prepend('<div id="duplicate-check-wrapper"></div>');
              $container = $('#duplicate-check-wrapper');
            }
          }
          
          if ($container.length > 0 && ($container.html().trim() === '' || !$container.hasClass('has-duplicate-warning'))) {
            $container.html(window.duplicateWarningState.warningHtml).addClass('has-duplicate-warning');
            
            // Re-attach event handlers
            if (window.mediaDuplicateCheck) {
              window.mediaDuplicateCheck.attachWarningHandlers($container);
            }
          }
        }
      }, 100);
    }
  });

  // Monitor DOM mutations to catch dynamic form updates
  if (window.MutationObserver) {
    var observer = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        if (mutation.type === 'childList' && window.duplicateWarningState.hasWarning) {
          // Check if the duplicate-check-wrapper was removed or emptied
          var $container = $('#duplicate-check-wrapper');
          if ($container.length === 0 || ($container.html().trim() === '' && window.duplicateWarningState.warningHtml)) {
            // Find or create container
            if ($container.length === 0) {
              var $form = $('.media-library-add-form, form[data-drupal-selector*="media-library"]').first();
              if ($form.length > 0) {
                $form.prepend('<div id="duplicate-check-wrapper"></div>');
                $container = $('#duplicate-check-wrapper');
              }
            }
            
            if ($container.length > 0) {
              $container.html(window.duplicateWarningState.warningHtml).addClass('has-duplicate-warning');
              
              // Re-attach event handlers
              if (window.mediaDuplicateCheck) {
                window.mediaDuplicateCheck.attachWarningHandlers($container);
              }
            }
          }
        }
      });
    });
    
    // Start observing
    observer.observe(document.body, {
      childList: true,
      subtree: true
    });
  }

  // Add visual feedback when hovering over existing media items.
  $(document).on('mouseenter', '.existing-media-item', function() {
    $(this).addClass('hover');
  }).on('mouseleave', '.existing-media-item', function() {
    $(this).removeClass('hover');
  });

})(jQuery, Drupal, drupalSettings);

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

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