mirror of
https://github.com/WordPress/WordPress.git
synced 2024-11-18 08:36:04 +01:00
8614d14887
We decided to split the media webpack config into it's own file. The main webpack config then combines this file with the packages config. Include vendor scripts by copying them. We copy the minified files if they are available. If they aren't available we minify the original files ourselves. Props omarreiss, herregroen, gziolo, youknowriad, netweb, adamsilverstein. Merges [43719] to trunk. See #45065. Built from https://develop.svn.wordpress.org/trunk@44112 git-svn-id: http://core.svn.wordpress.org/trunk@43942 1a063a9b-81f0-0310-95a4-ce76da25c4cd
391 lines
9.2 KiB
JavaScript
391 lines
9.2 KiB
JavaScript
if (typeof FormData === 'undefined' || !FormData.prototype.keys) {
|
|
const global = typeof window === 'object'
|
|
? window : typeof self === 'object'
|
|
? self : this
|
|
|
|
// keep a reference to native implementation
|
|
const _FormData = global.FormData
|
|
|
|
// To be monkey patched
|
|
const _send = global.XMLHttpRequest && global.XMLHttpRequest.prototype.send
|
|
const _fetch = global.Request && global.fetch
|
|
|
|
// Unable to patch Request constructor correctly
|
|
// const _Request = global.Request
|
|
// 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) {
|
|
if (!Blob.prototype[stringTag]) {
|
|
Blob.prototype[stringTag] = 'Blob'
|
|
}
|
|
|
|
if ('File' in global && !File.prototype[stringTag]) {
|
|
File.prototype[stringTag] = 'File'
|
|
}
|
|
}
|
|
|
|
// Fix so you can construct your own File
|
|
try {
|
|
new File([], '')
|
|
} catch (a) {
|
|
global.File = function(b, d, c) {
|
|
const blob = new Blob(b, c)
|
|
const t = c && void 0 !== c.lastModified ? new Date(c.lastModified) : new Date
|
|
|
|
Object.defineProperties(blob, {
|
|
name: {
|
|
value: d
|
|
},
|
|
lastModifiedDate: {
|
|
value: t
|
|
},
|
|
lastModified: {
|
|
value: +t
|
|
},
|
|
toString: {
|
|
value() {
|
|
return '[object File]'
|
|
}
|
|
}
|
|
})
|
|
|
|
if (stringTag) {
|
|
Object.defineProperty(blob, stringTag, {
|
|
value: 'File'
|
|
})
|
|
}
|
|
|
|
return blob
|
|
}
|
|
}
|
|
|
|
function normalizeValue([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
|
|
}
|
|
|
|
function stringify(name) {
|
|
if (!arguments.length)
|
|
throw new TypeError('1 argument required, but only 0 present.')
|
|
|
|
return [name + '']
|
|
}
|
|
|
|
function normalizeArgs(name, value, filename) {
|
|
if (arguments.length < 2)
|
|
throw new TypeError(
|
|
`2 arguments required, but only ${arguments.length} present.`
|
|
)
|
|
|
|
return value instanceof Blob
|
|
// normalize name and filename if adding an attachment
|
|
? [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 + '']
|
|
}
|
|
|
|
/**
|
|
* @implements {Iterable}
|
|
*/
|
|
class FormDataPolyfill {
|
|
|
|
/**
|
|
* FormData class
|
|
*
|
|
* @param {HTMLElement=} form
|
|
*/
|
|
constructor(form) {
|
|
map.set(this, Object.create(null))
|
|
|
|
if (!form)
|
|
return this
|
|
|
|
for (let elm of arrayFrom(form.elements)) {
|
|
if (!elm.name || elm.disabled) continue
|
|
|
|
if (elm.type === 'file')
|
|
for (let file of arrayFrom(elm.files || []))
|
|
this.append(elm.name, file)
|
|
else if (elm.type === 'select-multiple' || elm.type === 'select-one')
|
|
for (let opt of arrayFrom(elm.options))
|
|
!opt.disabled && opt.selected && this.append(elm.name, opt.value)
|
|
else if (elm.type === 'checkbox' || elm.type === 'radio') {
|
|
if (elm.checked) this.append(elm.name, elm.value)
|
|
} else
|
|
this.append(elm.name, elm.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}
|
|
*/
|
|
append(name, value, filename) {
|
|
const map = wm(this)
|
|
|
|
if (!map[name])
|
|
map[name] = []
|
|
|
|
map[name].push([value, filename])
|
|
}
|
|
|
|
|
|
/**
|
|
* Delete all fields values given name
|
|
*
|
|
* @param {String} name Field name
|
|
* @return {Undefined}
|
|
*/
|
|
delete(name) {
|
|
delete wm(this)[name]
|
|
}
|
|
|
|
|
|
/**
|
|
* 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)]
|
|
}
|
|
|
|
/**
|
|
* Iterate over all fields
|
|
*
|
|
* @param {Function} callback Executed for each item with parameters (value, name, thisArg)
|
|
* @param {Object=} thisArg `this` context for callback function
|
|
* @return {Undefined}
|
|
*/
|
|
forEach(callback, thisArg) {
|
|
for (let [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
|
|
*/
|
|
get(name) {
|
|
const map = wm(this)
|
|
return map[name] ? normalizeValue(map[name][0]) : null
|
|
}
|
|
|
|
|
|
/**
|
|
* Return all fields values given name
|
|
*
|
|
* @param {String} name Fields name
|
|
* @return {Array} [{String|File}]
|
|
*/
|
|
getAll(name) {
|
|
return (wm(this)[name] || []).map(normalizeValue)
|
|
}
|
|
|
|
|
|
/**
|
|
* Check for field name existence
|
|
*
|
|
* @param {String} name Field name
|
|
* @return {boolean}
|
|
*/
|
|
has(name) {
|
|
return name in wm(this)
|
|
}
|
|
|
|
|
|
/**
|
|
* Iterate over all fields name
|
|
*
|
|
* @return {Iterator}
|
|
*/
|
|
*keys() {
|
|
for (let [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}
|
|
*/
|
|
set(name, value, filename) {
|
|
wm(this)[name] = [[value, filename]]
|
|
}
|
|
|
|
|
|
/**
|
|
* Iterate over all fields
|
|
*
|
|
* @return {Iterator}
|
|
*/
|
|
*values() {
|
|
for (let [name, 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
|
|
|
|
for (let [name, value] of this)
|
|
fd.append(name, value)
|
|
|
|
return fd
|
|
}
|
|
|
|
|
|
/**
|
|
* [_blob description]
|
|
*
|
|
* @return {Blob} [description]
|
|
*/
|
|
['_blob']() {
|
|
const boundary = '----formdata-polyfill-' + Math.random()
|
|
const chunks = []
|
|
|
|
for (let [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-Type: ${value.type || 'application/octet-stream'}\r\n\r\n`,
|
|
value,
|
|
'\r\n'
|
|
)
|
|
} else {
|
|
chunks.push(
|
|
`Content-Disposition: form-data; name="${name}"\r\n\r\n${value}\r\n`
|
|
)
|
|
}
|
|
}
|
|
|
|
chunks.push(`--${boundary}--`)
|
|
|
|
return new Blob(chunks, {type: 'multipart/form-data; boundary=' + boundary})
|
|
}
|
|
|
|
|
|
/**
|
|
* The class itself is iterable
|
|
* alias for formdata.entries()
|
|
*
|
|
* @return {Iterator}
|
|
*/
|
|
[Symbol.iterator]() {
|
|
return this.entries()
|
|
}
|
|
|
|
|
|
/**
|
|
* Create the default string description.
|
|
*
|
|
* @return {String} [object FormData]
|
|
*/
|
|
toString() {
|
|
return '[object FormData]'
|
|
}
|
|
}
|
|
|
|
|
|
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
|
|
if (data instanceof FormDataPolyfill) {
|
|
const blob = data['_blob']()
|
|
this.setRequestHeader('Content-Type', blob.type)
|
|
_send.call(this, blob)
|
|
} else {
|
|
_send.call(this, data)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Patch fetch's function to call _blob transparently
|
|
if (_fetch) {
|
|
const _fetch = global.fetch
|
|
|
|
global.fetch = function(input, init) {
|
|
if (init && init.body && init.body instanceof FormDataPolyfill) {
|
|
init.body = init.body['_blob']()
|
|
}
|
|
|
|
return _fetch(input, init)
|
|
}
|
|
}
|
|
|
|
global['FormData'] = FormDataPolyfill
|
|
}
|