|
| 1 | +/* |
| 2 | + * Allows to inject and remove a FormData polyfill which supports get() and |
| 3 | + * getAll() methods. |
| 4 | + * |
| 5 | + * Except for Chrome (>= 50) and Firefox (>= 39) major browser engines implement |
| 6 | + * only a very basic subset of FormData specification. Especially current Safari, |
| 7 | + * IE, Edge and PhantomJS does not support any methods to retrieve data of a |
| 8 | + * FormData object. |
| 9 | + * This is a hard limitation in testing. E.g. in an ember-cli-mirage route handler |
| 10 | + * you are not able to retrieve values of the request. |
| 11 | + * |
| 12 | + * Implementation follows FormData specification: |
| 13 | + * https://xhr.spec.whatwg.org/#interface-formdata |
| 14 | + */ |
| 15 | + |
| 16 | +import Ember from 'ember'; |
| 17 | + |
| 18 | +const { isArray, warn } = Ember; |
| 19 | + |
| 20 | +function TestableFormData() { |
| 21 | + this._data = {}; |
| 22 | +} |
| 23 | + |
| 24 | +/* |
| 25 | + * Injects FormData polyfill by overriding window.FormData if current browser |
| 26 | + * engine does not implement FormData.get method. |
| 27 | + * Overriding window.FormData could be forced by passing `true` as first argument. |
| 28 | + */ |
| 29 | +TestableFormData.inject = function(force) { |
| 30 | + if ( |
| 31 | + window && |
| 32 | + (force || typeof window.FormData.get === 'undefined') |
| 33 | + ) { |
| 34 | + this.OldFormData = window.FormData; |
| 35 | + window.FormData = TestableFormData; |
| 36 | + } |
| 37 | +}; |
| 38 | + |
| 39 | +TestableFormData.remove = function() { |
| 40 | + if (window && this.OldFormData) { |
| 41 | + window.FormData = this.OldFormData; |
| 42 | + delete this.OldFormData; |
| 43 | + } |
| 44 | +}; |
| 45 | + |
| 46 | +/* |
| 47 | + * FormData.append() |
| 48 | + * The append(name, value) and append(name, blobValue, filename) methods, when |
| 49 | + * invoked, must run these steps: |
| 50 | + * 1. Let value be value if given, and blobValue otherwise. |
| 51 | + * 2. Let entry be the result of creating an entry with name, value, and |
| 52 | + * filename if given. |
| 53 | + * 3. Append entry to context object’s list of entries. |
| 54 | + * Note: The reason there is an argument named value as well as blobValue is |
| 55 | + * due to a limitation of the editing software used to write the XMLHttpRequest |
| 56 | + * Standard. |
| 57 | + * https://xhr.spec.whatwg.org/#dom-formdata-append |
| 58 | + */ |
| 59 | +TestableFormData.prototype.append = function(name, value, filename) { |
| 60 | + if (!isArray(this._data[name])) { |
| 61 | + this._data[name] = []; |
| 62 | + } |
| 63 | + /* |
| 64 | + * To create an entry for name, value, and optionally a filename, run these steps: |
| 65 | + * 3. If value is a Blob object and not a File object, then set value to a |
| 66 | + * new File object, representing the same bytes, whose name attribute |
| 67 | + * value is "blob". |
| 68 | + * 4. If value is (now) a File object and filename is given, then set value |
| 69 | + * to a new File object, representing the same bytes, whose name attribute |
| 70 | + * value is filename. |
| 71 | + * https://xhr.spec.whatwg.org/#create-an-entry |
| 72 | + */ |
| 73 | + if ( |
| 74 | + // it's a Blob |
| 75 | + value instanceof Blob && |
| 76 | + // but it's not a File yet |
| 77 | + !(value instanceof File) && |
| 78 | + // File is supported by current engine |
| 79 | + typeof File === 'function' |
| 80 | + ) { |
| 81 | + value = new File([value], filename || 'blob'); |
| 82 | + } |
| 83 | + this._data[name].push(value); |
| 84 | +}; |
| 85 | + |
| 86 | +/* |
| 87 | + * FormData.get() |
| 88 | + * The get(name) method, when invoked, must return the value of the first entry |
| 89 | + * whose name is name, and null otherwise. |
| 90 | + * https://xhr.spec.whatwg.org/#dom-formdata-get |
| 91 | + */ |
| 92 | +TestableFormData.prototype.get = function(name) { |
| 93 | + let values = this._data[name]; |
| 94 | + return ( isArray(values) && values.length > 0 ) ? values[0] : null; |
| 95 | +}; |
| 96 | + |
| 97 | +/* |
| 98 | + * FormData.getAll() |
| 99 | + * The getAll(name) method, when invoked, must return the values of all entries |
| 100 | + * whose name is name, in list order, and the empty sequence otherwise. |
| 101 | + * https://xhr.spec.whatwg.org/#dom-formdata-getall |
| 102 | + */ |
| 103 | +TestableFormData.prototype.getAll = function(name) { |
| 104 | + let value = this._data[name]; |
| 105 | + return isArray(value) ? value : []; |
| 106 | +}; |
| 107 | + |
| 108 | +export default TestableFormData; |
0 commit comments