|
Shopify.IEFormUpload = -> |
|
originalRequest = Batman.RestStorage::request |
|
Batman.RestStorage::request = (env, next) -> |
|
if env.action in ['create', 'update'] && env.subject._batman.saveWithForm |
|
return @iframeUpload(env, next) |
|
|
|
originalRequest.call(this, env, next) |
|
|
|
Batman.RestStorage::iframeUpload = (env, next) -> |
|
form = env.subject._batman.saveWithForm.get('node') |
|
|
|
iframe = document.getElementById('admin2_iframe_bridge') |
|
|
|
_bridgeIframeCallback = -> |
|
Batman.DOM.removeEventListener(iframe, 'load', _bridgeIframeCallback) |
|
|
|
data = Batman.DOM.textContent(iframe.contentWindow.document.body) |
|
[status, parsedData] = JSON.parse(data) |
|
|
|
if status >= 400 |
|
responseText = JSON.stringify(parsedData) |
|
env.error = |
|
request: |
|
status: status |
|
responseText: responseText |
|
env.response = responseText |
|
else |
|
env.data = parsedData |
|
|
|
next() |
|
|
|
Batman.DOM.addEventListener(iframe, 'load', _bridgeIframeCallback) |
|
|
|
@_setupFormAttributes(form, env.options.url) |
|
@_setupFormFields(form, env) |
|
form.submit() |
|
|
|
Batman.RestStorage::_setupFormAttributes = (form, action) -> |
|
form.setAttribute('method', 'POST') |
|
form.setAttribute('enctype', 'multipart/form-data') |
|
form.setAttribute('action', action) |
|
form.setAttribute('target', 'admin2_iframe_bridge') |
|
|
|
Batman.RestStorage::_setupFormFields = (form, env) -> |
|
# Cleanup any previous field containers |
|
for node in Batman.DOM.querySelectorAll(form, '.iframe_upload_fields') |
|
Batman.DOM.destroyNode(node) |
|
|
|
# Create a container for the fields |
|
fieldsContainer = document.createElement('div') |
|
fieldsContainer.setAttribute('class', 'iframe_upload_fields') |
|
fieldsContainer.style.display = 'none' |
|
form.appendChild(fieldsContainer) |
|
|
|
# Add hidden fields for inputs |
|
@createInputs(fieldsContainer, env.options.data) |
|
|
|
# Add authenticity token |
|
csrfParam = Batman.DOM.querySelector(null, 'meta[name="csrf-param"]') |
|
csrfToken = Batman.DOM.querySelector(null, 'meta[name="csrf-token"]') |
|
@createInput(fieldsContainer, csrfParam.getAttribute('content'), csrfToken.getAttribute('content')) |
|
|
|
# Add input so back-end does not send back Content-Type: text/json |
|
@createInput(fieldsContainer, '_withIframe', '1') |
|
|
|
# Create a hidden inputs for API headers since we can't pass them |
|
@createInput(fieldsContainer, "_apiFeatures", apiFeatures) if apiFeatures = env.options.headers['X-Shopify-Api-Features'] |
|
|
|
# If this isn't a POST action we will need to create a hidden input |
|
# with _method = METHOD |
|
if env.options.method != 'POST' |
|
@createInput(fieldsContainer, '_method', env.options.method) |
|
|
|
Batman.RestStorage::createInputs = (form, data, namespace = '') -> |
|
for key of data |
|
value = data[key] |
|
|
|
namespaceKey = if Batman.typeOf(data) == 'Array' |
|
'' |
|
else |
|
key |
|
|
|
nextNamespace = if namespace == '' |
|
namespaceKey |
|
else |
|
namespace + "[#{namespaceKey}]" |
|
|
|
typeOfValue = Batman.typeOf(value) |
|
|
|
if typeOfValue == 'Array' |
|
@createInputs(form, value, nextNamespace) |
|
else if typeOfValue == 'Object' |
|
# IE 9 |
|
# We polyfill File so the binding will have a value, |
|
# but we don't want to create hidden inputs for it |
|
# as it will overwrite our <input type="file"> that is |
|
# in the HTML. |
|
continue if value instanceof File |
|
|
|
@createInputs(form, value, nextNamespace) |
|
else if typeOfValue == 'File' |
|
# Safari 5.1 has partial file reader support. |
|
# You can obtain the filename, but you cannot |
|
# read the content of the files. This is why we have |
|
# to skip it here. |
|
else |
|
@createInput(form, nextNamespace, value) |
|
null |
|
|
|
Batman.RestStorage::createInput = (form, name, value) -> |
|
return if window.File && value instanceof File |
|
input = document.createElement('input') |
|
|
|
value = '' if value is null |
|
|
|
input.setAttribute('type', 'text') |
|
input.setAttribute('name', name) |
|
input.setAttribute('value', value) |
|
form.appendChild(input) |
|
|
|
originalInitialized = Batman.DOM.FormBinding::initialized |
|
Batman.DOM.FormBinding::initialized = -> |
|
originalInitialized?.call(this) |
|
if $(this.node).find('input:file').length > 0 |
|
@setupUploadPolyfill() |
|
|
|
Batman.DOM.FormBinding::setupUploadPolyfill = -> |
|
keyPath = @get('keyPath') |
|
model = @view.lookupKeypath(keyPath) |
|
|
|
return unless model |
|
return if model._batman.saveWithForm |
|
|
|
model._batman.saveWithForm = this |
|
|
|
Batman.DOM.FormBinding::destroyUploadPolyfill = (model) -> |
|
model._batman.saveWithForm = null |
|
|
|
originalDie = Batman.DOM.FormBinding::die |
|
Batman.DOM.FormBinding::die = -> |
|
keyPath = @get('keyPath') |
|
model = @view.lookupKeypath(keyPath) |
|
|
|
@destroyUploadPolyfill(model) if model?._batman.saveWithForm |
|
originalDie?.call(this) |
|
|
|
class File |
|
constructor: (node) -> |
|
this.name = node.value.split('\\').pop() |
|
|
|
originalNodeChange = Batman.DOM.FileBinding::nodeChange |
|
Batman.DOM.FileBinding::nodeChange = (node, subContext) -> |
|
node.files = [new File(node)] |
|
originalNodeChange.call(this, node, subContext) |
Thanks for posting this!