--- a/wp/wp-includes/js/dist/vendor/wp-polyfill-formdata.js Tue Dec 15 15:52:01 2020 +0100
+++ b/wp/wp-includes/js/dist/vendor/wp-polyfill-formdata.js Wed Sep 21 18:19:35 2022 +0200
@@ -1,7 +1,12 @@
-if (typeof FormData === 'undefined' || !FormData.prototype.keys) {
- const global = typeof window === 'object'
- ? window : typeof self === 'object'
- ? self : this
+/* global FormData self Blob File */
+/* eslint-disable no-inner-declarations */
+
+if (typeof Blob !== 'undefined' && (typeof FormData === 'undefined' || !FormData.prototype.keys)) {
+ const global = typeof globalThis === 'object'
+ ? globalThis
+ : typeof window === 'object'
+ ? window
+ : typeof self === 'object' ? self : this
// keep a reference to native implementation
const _FormData = global.FormData
@@ -9,16 +14,15 @@
// To be monkey patched
const _send = global.XMLHttpRequest && global.XMLHttpRequest.prototype.send
const _fetch = global.Request && global.fetch
+ const _sendBeacon = global.navigator && global.navigator.sendBeacon
+ // Might be a worker thread...
+ const _match = global.Element && global.Element.prototype
- // Unable to patch Request constructor correctly
- // const _Request = global.Request
+ // Unable to patch Request/Response constructor correctly #109
// only way is to use ES6 class extend
// https://github.com/babel/babel/issues/1966
const stringTag = global.Symbol && Symbol.toStringTag
- const map = new WeakMap
- const wm = o => map.get(o)
- const arrayFrom = Array.from || (obj => [].slice.call(obj))
// Add missing stringTags to blob and files
if (stringTag) {
@@ -33,11 +37,11 @@
// Fix so you can construct your own File
try {
- new File([], '')
+ new File([], '') // eslint-disable-line
} catch (a) {
- global.File = function(b, d, c) {
+ global.File = function File (b, d, c) {
const blob = new Blob(b, c)
- const t = c && void 0 !== c.lastModified ? new Date(c.lastModified) : new Date
+ const t = c && void 0 !== c.lastModified ? new Date(c.lastModified) : new Date()
Object.defineProperties(blob, {
name: {
@@ -50,7 +54,7 @@
value: +t
},
toString: {
- value() {
+ value () {
return '[object File]'
}
}
@@ -66,41 +70,42 @@
}
}
- function normalizeValue([value, filename]) {
- if (value instanceof Blob)
+ function normalizeValue ([name, value, filename]) {
+ if (value instanceof Blob) {
// Should always returns a new File instance
// console.assert(fd.get(x) !== fd.get(x))
value = new File([value], filename, {
type: value.type,
lastModified: value.lastModified
})
+ }
- return value
+ return [name, value]
}
- function stringify(name) {
- if (!arguments.length)
- throw new TypeError('1 argument required, but only 0 present.')
-
- return [name + '']
+ function ensureArgs (args, expected) {
+ if (args.length < expected) {
+ throw new TypeError(`${expected} argument required, but only ${args.length} present.`)
+ }
}
- function normalizeArgs(name, value, filename) {
- if (arguments.length < 2)
- throw new TypeError(
- `2 arguments required, but only ${arguments.length} present.`
- )
-
+ function normalizeArgs (name, value, filename) {
return value instanceof Blob
// normalize name and filename if adding an attachment
- ? [name + '', value, filename !== undefined
+ ? [String(name), value, filename !== undefined
? filename + '' // Cast filename to string if 3th arg isn't undefined
: typeof value.name === 'string' // if name prop exist
? value.name // Use File.name
: 'blob'] // otherwise fallback to Blob
// If no attachment, just cast the args to strings
- : [name + '', value + '']
+ : [String(name), String(value)]
+ }
+
+ // normalize linefeeds for textareas
+ // https://html.spec.whatwg.org/multipage/form-elements.html#textarea-line-break-normalisation-transformation
+ function normalizeLinefeeds (value) {
+ return value.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n')
}
function each (arr, cb) {
@@ -113,25 +118,31 @@
* @implements {Iterable}
*/
class FormDataPolyfill {
-
/**
* FormData class
*
* @param {HTMLElement=} form
*/
- constructor(form) {
- map.set(this, Object.create(null))
-
- if (!form)
- return this
+ constructor (form) {
+ this._data = []
const self = this
- each(form.elements, elm => {
- if (!elm.name || elm.disabled || elm.type === 'submit' || elm.type === 'button') return
+ form && each(form.elements, elm => {
+ if (
+ !elm.name ||
+ elm.disabled ||
+ elm.type === 'submit' ||
+ elm.type === 'button' ||
+ elm.matches('form fieldset[disabled] *')
+ ) return
if (elm.type === 'file') {
- each(elm.files || [], file => {
+ const files = elm.files && elm.files.length
+ ? elm.files
+ : [new File([], '', { type: 'application/octet-stream' })] // #78
+
+ each(files, file => {
self.append(elm.name, file)
})
} else if (elm.type === 'select-multiple' || elm.type === 'select-one') {
@@ -141,52 +152,52 @@
} else if (elm.type === 'checkbox' || elm.type === 'radio') {
if (elm.checked) self.append(elm.name, elm.value)
} else {
- self.append(elm.name, elm.value)
+ const value = elm.type === 'textarea' ? normalizeLinefeeds(elm.value) : elm.value
+ self.append(elm.name, value)
}
})
}
-
/**
* Append a field
*
- * @param {String} name field name
- * @param {String|Blob|File} value string / blob / file
- * @param {String=} filename filename to use with blob
- * @return {Undefined}
+ * @param {string} name field name
+ * @param {string|Blob|File} value string / blob / file
+ * @param {string=} filename filename to use with blob
+ * @return {undefined}
*/
- append(name, value, filename) {
- const map = wm(this)
-
- if (!map[name])
- map[name] = []
-
- map[name].push([value, filename])
+ append (name, value, filename) {
+ ensureArgs(arguments, 2)
+ this._data.push(normalizeArgs(name, value, filename))
}
-
/**
* Delete all fields values given name
*
- * @param {String} name Field name
- * @return {Undefined}
+ * @param {string} name Field name
+ * @return {undefined}
*/
- delete(name) {
- delete wm(this)[name]
+ delete (name) {
+ ensureArgs(arguments, 1)
+ const result = []
+ name = String(name)
+
+ each(this._data, entry => {
+ entry[0] !== name && result.push(entry)
+ })
+
+ this._data = result
}
-
/**
* Iterate over all fields as [name, value]
*
* @return {Iterator}
*/
- *entries() {
- const map = wm(this)
-
- for (let name in map)
- for (let value of map[name])
- yield [name, normalizeValue(value)]
+ * entries () {
+ for (var i = 0; i < this._data.length; i++) {
+ yield normalizeValue(this._data[i])
+ }
}
/**
@@ -194,115 +205,150 @@
*
* @param {Function} callback Executed for each item with parameters (value, name, thisArg)
* @param {Object=} thisArg `this` context for callback function
- * @return {Undefined}
+ * @return {undefined}
*/
- forEach(callback, thisArg) {
- for (let [name, value] of this)
+ forEach (callback, thisArg) {
+ ensureArgs(arguments, 1)
+ for (const [name, value] of this) {
callback.call(thisArg, value, name, this)
+ }
}
-
/**
* Return first field value given name
* or null if non existen
*
- * @param {String} name Field name
- * @return {String|File|null} value Fields value
+ * @param {string} name Field name
+ * @return {string|File|null} value Fields value
*/
- get(name) {
- const map = wm(this)
- return map[name] ? normalizeValue(map[name][0]) : null
+ get (name) {
+ ensureArgs(arguments, 1)
+ const entries = this._data
+ name = String(name)
+ for (let i = 0; i < entries.length; i++) {
+ if (entries[i][0] === name) {
+ return normalizeValue(entries[i])[1]
+ }
+ }
+ return null
}
-
/**
* Return all fields values given name
*
- * @param {String} name Fields name
+ * @param {string} name Fields name
* @return {Array} [{String|File}]
*/
- getAll(name) {
- return (wm(this)[name] || []).map(normalizeValue)
+ getAll (name) {
+ ensureArgs(arguments, 1)
+ const result = []
+ name = String(name)
+ each(this._data, data => {
+ data[0] === name && result.push(normalizeValue(data)[1])
+ })
+
+ return result
}
-
/**
* Check for field name existence
*
- * @param {String} name Field name
+ * @param {string} name Field name
* @return {boolean}
*/
- has(name) {
- return name in wm(this)
+ has (name) {
+ ensureArgs(arguments, 1)
+ name = String(name)
+ for (let i = 0; i < this._data.length; i++) {
+ if (this._data[i][0] === name) {
+ return true
+ }
+ }
+ return false
}
-
/**
* Iterate over all fields name
*
* @return {Iterator}
*/
- *keys() {
- for (let [name] of this)
+ * keys () {
+ for (const [name] of this) {
yield name
+ }
}
-
/**
* Overwrite all values given name
*
- * @param {String} name Filed name
- * @param {String} value Field value
- * @param {String=} filename Filename (optional)
- * @return {Undefined}
+ * @param {string} name Filed name
+ * @param {string} value Field value
+ * @param {string=} filename Filename (optional)
+ * @return {undefined}
*/
- set(name, value, filename) {
- wm(this)[name] = [[value, filename]]
+ set (name, value, filename) {
+ ensureArgs(arguments, 2)
+ name = String(name)
+ const result = []
+ const args = normalizeArgs(name, value, filename)
+ let replace = true
+
+ // - replace the first occurrence with same name
+ // - discards the remaning with same name
+ // - while keeping the same order items where added
+ each(this._data, data => {
+ data[0] === name
+ ? replace && (replace = !result.push(args))
+ : result.push(data)
+ })
+
+ replace && result.push(args)
+
+ this._data = result
}
-
/**
* Iterate over all fields
*
* @return {Iterator}
*/
- *values() {
- for (let [name, value] of this)
+ * values () {
+ for (const [, value] of this) {
yield value
+ }
}
-
/**
* Return a native (perhaps degraded) FormData with only a `append` method
* Can throw if it's not supported
*
* @return {FormData}
*/
- ['_asNative']() {
- const fd = new _FormData
+ ['_asNative'] () {
+ const fd = new _FormData()
- for (let [name, value] of this)
+ for (const [name, value] of this) {
fd.append(name, value)
+ }
return fd
}
-
/**
* [_blob description]
*
* @return {Blob} [description]
*/
- ['_blob']() {
+ ['_blob'] () {
const boundary = '----formdata-polyfill-' + Math.random()
const chunks = []
- for (let [name, value] of this) {
+ for (const [name, value] of this) {
chunks.push(`--${boundary}\r\n`)
if (value instanceof Blob) {
chunks.push(
- `Content-Disposition: form-data; name="${name}"; filename="${value.name}"\r\n`,
+ `Content-Disposition: form-data; name="${name}"; filename="${value.name}"\r\n` +
`Content-Type: ${value.type || 'application/octet-stream'}\r\n\r\n`,
value,
'\r\n'
@@ -316,67 +362,68 @@
chunks.push(`--${boundary}--`)
- return new Blob(chunks, {type: 'multipart/form-data; boundary=' + boundary})
+ return new Blob(chunks, {
+ type: 'multipart/form-data; boundary=' + boundary
+ })
}
-
/**
* The class itself is iterable
* alias for formdata.entries()
*
* @return {Iterator}
*/
- [Symbol.iterator]() {
+ [Symbol.iterator] () {
return this.entries()
}
-
/**
* Create the default string description.
*
- * @return {String} [object FormData]
+ * @return {string} [object FormData]
*/
- toString() {
+ toString () {
return '[object FormData]'
}
}
+ if (_match && !_match.matches) {
+ _match.matches =
+ _match.matchesSelector ||
+ _match.mozMatchesSelector ||
+ _match.msMatchesSelector ||
+ _match.oMatchesSelector ||
+ _match.webkitMatchesSelector ||
+ function (s) {
+ var matches = (this.document || this.ownerDocument).querySelectorAll(s)
+ var i = matches.length
+ while (--i >= 0 && matches.item(i) !== this) {}
+ return i > -1
+ }
+ }
if (stringTag) {
/**
* Create the default string description.
* It is accessed internally by the Object.prototype.toString().
- *
- * @return {String} FormData
*/
FormDataPolyfill.prototype[stringTag] = 'FormData'
}
- const decorations = [
- ['append', normalizeArgs],
- ['delete', stringify],
- ['get', stringify],
- ['getAll', stringify],
- ['has', stringify],
- ['set', normalizeArgs]
- ]
-
- decorations.forEach(arr => {
- const orig = FormDataPolyfill.prototype[arr[0]]
- FormDataPolyfill.prototype[arr[0]] = function() {
- return orig.apply(this, arr[1].apply(this, arrayFrom(arguments)))
- }
- })
-
// Patch xhr's send method to call _blob transparently
if (_send) {
- XMLHttpRequest.prototype.send = function(data) {
- // I would check if Content-Type isn't already set
- // But xhr lacks getRequestHeaders functionallity
- // https://github.com/jimmywarting/FormData/issues/44
+ const setRequestHeader = global.XMLHttpRequest.prototype.setRequestHeader
+
+ global.XMLHttpRequest.prototype.setRequestHeader = function (name, value) {
+ setRequestHeader.call(this, name, value)
+ if (name.toLowerCase() === 'content-type') this._hasContentType = true
+ }
+
+ global.XMLHttpRequest.prototype.send = function (data) {
+ // need to patch send b/c old IE don't send blob's type (#44)
if (data instanceof FormDataPolyfill) {
const blob = data['_blob']()
- this.setRequestHeader('Content-Type', blob.type)
+ if (!this._hasContentType) this.setRequestHeader('Content-Type', blob.type)
_send.call(this, blob)
} else {
_send.call(this, data)
@@ -386,14 +433,22 @@
// Patch fetch's function to call _blob transparently
if (_fetch) {
- const _fetch = global.fetch
-
- global.fetch = function(input, init) {
+ global.fetch = function (input, init) {
if (init && init.body && init.body instanceof FormDataPolyfill) {
init.body = init.body['_blob']()
}
- return _fetch(input, init)
+ return _fetch.call(this, input, init)
+ }
+ }
+
+ // Patch navigator.sendBeacon to use native FormData
+ if (_sendBeacon) {
+ global.navigator.sendBeacon = function (url, data) {
+ if (data instanceof FormDataPolyfill) {
+ data = data['_asNative']()
+ }
+ return _sendBeacon.call(this, url, data)
}
}