[Does NOT work in Firefox] Safari 11 XHR bug workaround

iOS 11.3 Safari / macOS Safari 11.1 empty <input type="file"> XHR bug workaround

by ypresto

HTML

<div id="main">
  <form>
    <div>
      Select File (leave this empty) <input type="file" name="file">  
    </div>
    <div>
      Text <input type="text" name="html" value="foobar">
    </div>
    <button id="submit-as-is-button" type="button">Submit as-is</button>
    <button id="submit-filtered-button" type="button">Submit w/ input filtered</button>
  </form>
  <div id="result">The result will be shown here.</div>
  <div id="echo">Request body will be shown here.</div>
</div>

CSS

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#main {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  text-align: center;
  transition: all 0.2s;
  margin: 0 auto;
  width: 400px;
}

#main div {
  margin: 4px;
  padding: 4px;
  border: 1px solid #ccc;
}

#main #result {
  margin-top: 24px;
}

button {
  background: #0084ff;
  border: none;
  border-radius: 5px;
  padding: 8px 14px;
  font-size: 15px;
  color: #fff;
}

JavaScript

// iOS 11.3 Safari / macOS Safari 11.1 empty <input type="file"> XHR bug workaround.

var formDataFilter = function(formData) {
  if (!(window.FormData && formData instanceof window.FormData)) return formData
  if (!formData.keys) return formData // unsupported browser
  var newFormData = new window.FormData()
  Array.from(formData.entries()).forEach(function(entry) {
    var value = entry[1]
    if (value instanceof window.File && value.name === '' && value.size === 0) {
      newFormData.append(entry[0], new window.Blob([]), '')
    } else {
      newFormData.append(entry[0], value)
    }
  })
  return newFormData
}

var submit = function(filter) {
  var $result = $('#result')
  var $echo = $('#echo')
  var formData = new FormData($('form')[0])
  if (filter) {
    formData = formDataFilter(formData)
  }
  $result.text('In Progress')
	$.ajax({
    type: 'POST',
    enctype: 'multipart/form-data',
    url: '/echo/html/',
    data: formData,
    contentType: false,
    processData: false,
    cache: false,
    complete: function(xhr) {
      $result.text(xhr.status + ' ' + xhr.statusText)
      $echo.text("" + xhr.responseText)
    }
	})
}

$("#submit-as-is-button").on("click", function() { submit() })
$("#submit-filtered-button").on("click", function() { submit(true) })