Saturday 7 August 2021

Image Uploader Not Working In Safari - Possible Work Arounds (JavaScript)

I've been building an image uploader that is now theoretically complete, but it is not working in Safari.

I initially thought the problem was because DataTransfer, or more specifically dataTransfer.files was not supported, but this is now supported in Desktop Safari (Version 14.1 +). Although there is no support at all in iOS I will be having the file-picker only (no drag and drop) on iOS so this isn't an issue.

The Problem / Scenario on Desktop Safari

  1. When a user clicks the 'select files' link and submits the images, it all works OK.

  2. When a user drags and drops images the file preview images are duplicated (e.g. 2 images shows 4 previews). When submitted, only the 2 images are uploaded though (which is correct obviously).

  3. When a user clicks the 'select files' link instead of using the drag and drop functionality and then deletes an image from the image previews, the image previews are then duplicated (similar to the way the are in point 2. above).

Logically this would make me think the problem is with the change event listener, but I can't seem to fix it.

Any help would be hugely appreciated.

const dropZone = document.getElementById("drop-zone"),
  showSelectedImages = document.getElementById("show-selected-images"),
  fileUploader = document.getElementById("standard-upload-files");

dropZone.addEventListener("click", (evt) => {
  // assigns the dropzone to the hidden input element so when you click 'select files' it brings up a file picker window
  fileUploader.click();
});

// Prevent browser default when draging over
dropZone.addEventListener("dragover", (evt) => {
  evt.preventDefault();
});

fileUploader.addEventListener("change", (evt) => {
  // this function is further down but declared here and shows a thumbnail of the image
  [...fileUploader.files].forEach(updateThumbnail);
});

function getFileListItems(files) {
  var transferObject = new ClipboardEvent("").clipboardData || new DataTransfer()
  for (var i = 0; i < files.length; i++) transferObject.items.add(files[i])
  return transferObject.files;
}

dropZone.addEventListener("drop", (evt) => {
  evt.preventDefault();
  // assign dropped files to the hidden input element
  if (evt.dataTransfer.files.length) {
    fileUploader.files = getFileListItems([...fileUploader.files, ...evt.dataTransfer.files]);
  }
  // function is declared here but written further down
  [...evt.dataTransfer.files].forEach(updateThumbnail);
});

// updateThumbnail function that needs to be able to handle multiple files
function updateThumbnail(file) {
  if (file.type.startsWith("image/")) {
    let uploadImageWrapper = document.createElement("article"),
      removeImage = document.createElement("div"),
      thumbnailElement = new Image();

    // 'x' that deletes the image
    removeImage.classList.add("remove-image");
    removeImage.innerHTML =
      '<svg id="remove-x" viewBox="0 0 150 150"><path fill="#000" d="M147.23,133.89a9.43,9.43,0,1,1-13.33,13.34L75,88.34,16.1,147.23A9.43,9.43,0,1,1,2.76,133.89L61.66,75,2.76,16.09A9.43,9.43,0,0,1,16.1,2.77L75,61.66,133.9,2.77a9.42,9.42,0,1,1,13.33,13.32L88.33,75Z"/></svg>';

    // image thumbnail
    thumbnailElement.classList.add("drop-zone__thumb");
    thumbnailElement.src = URL.createObjectURL(file);

    // appending elements
    showSelectedImages.append(uploadImageWrapper); // <article> element
    uploadImageWrapper.append(removeImage); // 'x' to delete
    uploadImageWrapper.append(thumbnailElement); // image thumbnail

    // Delete images
    removeImage.addEventListener("click", (evt) => {
      if (evt.target) {
        var deleteImage = removeImage.parentElement;
        deleteImage.remove();
        fileUploader.files = getFileListItems([...fileUploader.files].filter(f => file !== f));
      }
    });
  }
} // end of 'updateThumbnail' function
body {
  margin: 0;
  display: flex;
  justify-content: center;
  width: 100%;
}

form {
  width: 30%;
}

#drop-zone {
  border: 1px dashed;
  width: 100%;
  padding: 1rem;
  margin-bottom: 1rem;
}

.select-files {
  text-decoration: underline;
  cursor: pointer;
}

/* images that are previewed prior to form submission*/

.drop-zone__thumb {
  width: 200px;
  height: auto;
  display: block;
}

#remove-x {
  width: 1rem;
  height: 1rem;
}

#submit-images {
  margin: 1rem 0;
}

#show-selected-images {
  display: flex;
}
<form id="upload-images-form" enctype="multipart/form-data" method="post">
  <h1>Upload Your Images</h1>
  <div id="drop-zone" class="drop-zone flex">
    <p class="td text-center">DRAG AND DROP IMAGES HERE</p>
    <p class="td text-center" style="margin: 0">Or</p>
    <p class="tl text-center select-files text-bold pointer">Select Files</p>
  </div>
  <input id="standard-upload-files" style="display:none" style="min-width: 100%" type="file" name="standard-upload-files[]" multiple>
  <input type="submit" name="submit-images" id="submit-images" value="SUBMIT IMAGES">
  <div id="show-selected-images"></div>
</form>


from Image Uploader Not Working In Safari - Possible Work Arounds (JavaScript)

No comments:

Post a Comment