[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/js/dist/vendor/ -> wp-polyfill-formdata.js (source)

   1  if (typeof FormData === 'undefined' || !FormData.prototype.keys) {
   2    const global = typeof window === 'object'
   3      ? window : typeof self === 'object'
   4      ? self : this
   5  
   6    // keep a reference to native implementation
   7    const _FormData = global.FormData
   8  
   9    // To be monkey patched
  10    const _send = global.XMLHttpRequest && global.XMLHttpRequest.prototype.send
  11    const _fetch = global.Request && global.fetch
  12  
  13    // Unable to patch Request constructor correctly
  14    // const _Request = global.Request
  15    // only way is to use ES6 class extend
  16    // https://github.com/babel/babel/issues/1966
  17  
  18    const stringTag = global.Symbol && Symbol.toStringTag
  19    const map = new WeakMap
  20    const wm = o => map.get(o)
  21    const arrayFrom = Array.from || (obj => [].slice.call(obj))
  22  
  23    // Add missing stringTags to blob and files
  24    if (stringTag) {
  25      if (!Blob.prototype[stringTag]) {
  26        Blob.prototype[stringTag] = 'Blob'
  27      }
  28  
  29      if ('File' in global && !File.prototype[stringTag]) {
  30        File.prototype[stringTag] = 'File'
  31      }
  32    }
  33  
  34    // Fix so you can construct your own File
  35    try {
  36      new File([], '')
  37    } catch (a) {
  38      global.File = function(b, d, c) {
  39        const blob = new Blob(b, c)
  40        const t = c && void 0 !== c.lastModified ? new Date(c.lastModified) : new Date
  41  
  42        Object.defineProperties(blob, {
  43          name: {
  44            value: d
  45          },
  46          lastModifiedDate: {
  47            value: t
  48          },
  49          lastModified: {
  50            value: +t
  51          },
  52          toString: {
  53            value() {
  54              return '[object File]'
  55            }
  56          }
  57        })
  58  
  59        if (stringTag) {
  60          Object.defineProperty(blob, stringTag, {
  61            value: 'File'
  62          })
  63        }
  64  
  65        return blob
  66      }
  67    }
  68  
  69    function normalizeValue([value, filename]) {
  70      if (value instanceof Blob)
  71        // Should always returns a new File instance
  72        // console.assert(fd.get(x) !== fd.get(x))
  73        value = new File([value], filename, {
  74          type: value.type,
  75          lastModified: value.lastModified
  76        })
  77  
  78      return value
  79    }
  80  
  81    function stringify(name) {
  82      if (!arguments.length)
  83        throw new TypeError('1 argument required, but only 0 present.')
  84  
  85      return [name + '']
  86    }
  87  
  88    function normalizeArgs(name, value, filename) {
  89      if (arguments.length < 2)
  90        throw new TypeError(
  91          `2 arguments required, but only $arguments.length} present.`
  92        )
  93  
  94      return value instanceof Blob
  95        // normalize name and filename if adding an attachment
  96        ? [name + '', value, filename !== undefined
  97          ? filename + '' // Cast filename to string if 3th arg isn't undefined
  98          : typeof value.name === 'string' // if name prop exist
  99            ? value.name // Use File.name
 100            : 'blob'] // otherwise fallback to Blob
 101  
 102        // If no attachment, just cast the args to strings
 103        : [name + '', value + '']
 104    }
 105  
 106    /**
 107     * @implements {Iterable}
 108     */
 109    class FormDataPolyfill {
 110  
 111      /**
 112       * FormData class
 113       *
 114       * @param {HTMLElement=} form
 115       */
 116      constructor(form) {
 117        map.set(this, Object.create(null))
 118  
 119        if (!form)
 120          return this
 121  
 122        for (let elm of arrayFrom(form.elements)) {
 123          if (!elm.name || elm.disabled) continue
 124  
 125          if (elm.type === 'file')
 126            for (let file of arrayFrom(elm.files || []))
 127              this.append(elm.name, file)
 128          else if (elm.type === 'select-multiple' || elm.type === 'select-one')
 129            for (let opt of arrayFrom(elm.options))
 130              !opt.disabled && opt.selected && this.append(elm.name, opt.value)
 131          else if (elm.type === 'checkbox' || elm.type === 'radio') {
 132            if (elm.checked) this.append(elm.name, elm.value)
 133          } else
 134            this.append(elm.name, elm.value)
 135        }
 136      }
 137  
 138  
 139      /**
 140       * Append a field
 141       *
 142       * @param   {String}           name      field name
 143       * @param   {String|Blob|File} value     string / blob / file
 144       * @param   {String=}          filename  filename to use with blob
 145       * @return  {Undefined}
 146       */
 147      append(name, value, filename) {
 148        const map = wm(this)
 149  
 150        if (!map[name])
 151          map[name] = []
 152  
 153        map[name].push([value, filename])
 154      }
 155  
 156  
 157      /**
 158       * Delete all fields values given name
 159       *
 160       * @param   {String}  name  Field name
 161       * @return  {Undefined}
 162       */
 163      delete(name) {
 164        delete wm(this)[name]
 165      }
 166  
 167  
 168      /**
 169       * Iterate over all fields as [name, value]
 170       *
 171       * @return {Iterator}
 172       */
 173      *entries() {
 174        const map = wm(this)
 175  
 176        for (let name in map)
 177          for (let value of map[name])
 178            yield [name, normalizeValue(value)]
 179      }
 180  
 181      /**
 182       * Iterate over all fields
 183       *
 184       * @param   {Function}  callback  Executed for each item with parameters (value, name, thisArg)
 185       * @param   {Object=}   thisArg   `this` context for callback function
 186       * @return  {Undefined}
 187       */
 188      forEach(callback, thisArg) {
 189        for (let [name, value] of this)
 190          callback.call(thisArg, value, name, this)
 191      }
 192  
 193  
 194      /**
 195       * Return first field value given name
 196       * or null if non existen
 197       *
 198       * @param   {String}  name      Field name
 199       * @return  {String|File|null}  value Fields value
 200       */
 201      get(name) {
 202        const map = wm(this)
 203        return map[name] ? normalizeValue(map[name][0]) : null
 204      }
 205  
 206  
 207      /**
 208       * Return all fields values given name
 209       *
 210       * @param   {String}  name  Fields name
 211       * @return  {Array}         [{String|File}]
 212       */
 213      getAll(name) {
 214        return (wm(this)[name] || []).map(normalizeValue)
 215      }
 216  
 217  
 218      /**
 219       * Check for field name existence
 220       *
 221       * @param   {String}   name  Field name
 222       * @return  {boolean}
 223       */
 224      has(name) {
 225        return name in wm(this)
 226      }
 227  
 228  
 229      /**
 230       * Iterate over all fields name
 231       *
 232       * @return {Iterator}
 233       */
 234      *keys() {
 235        for (let [name] of this)
 236          yield name
 237      }
 238  
 239  
 240      /**
 241       * Overwrite all values given name
 242       *
 243       * @param   {String}    name      Filed name
 244       * @param   {String}    value     Field value
 245       * @param   {String=}   filename  Filename (optional)
 246       * @return  {Undefined}
 247       */
 248      set(name, value, filename) {
 249        wm(this)[name] = [[value, filename]]
 250      }
 251  
 252  
 253      /**
 254       * Iterate over all fields
 255       *
 256       * @return {Iterator}
 257       */
 258      *values() {
 259        for (let [name, value] of this)
 260          yield value
 261      }
 262  
 263  
 264      /**
 265       * Return a native (perhaps degraded) FormData with only a `append` method
 266       * Can throw if it's not supported
 267       *
 268       * @return {FormData}
 269       */
 270      ['_asNative']() {
 271        const fd = new _FormData
 272  
 273        for (let [name, value] of this)
 274          fd.append(name, value)
 275  
 276        return fd
 277      }
 278  
 279  
 280      /**
 281       * [_blob description]
 282       *
 283       * @return {Blob} [description]
 284       */
 285      ['_blob']() {
 286        const boundary = '----formdata-polyfill-' + Math.random()
 287        const chunks = []
 288  
 289        for (let [name, value] of this) {
 290          chunks.push(`--$boundary}\r\n`)
 291  
 292          if (value instanceof Blob) {
 293            chunks.push(
 294              `Content-Disposition: form-data; name="$name}"; filename="$value.name}"\r\n`,
 295              `Content-Type: $value.type || 'application/octet-stream'}\r\n\r\n`,
 296              value,
 297              '\r\n'
 298            )
 299          } else {
 300            chunks.push(
 301              `Content-Disposition: form-data; name="$name}"\r\n\r\n$value}\r\n`
 302            )
 303          }
 304        }
 305  
 306        chunks.push(`--$boundary}--`)
 307  
 308        return new Blob(chunks, {type: 'multipart/form-data; boundary=' + boundary})
 309      }
 310  
 311  
 312      /**
 313       * The class itself is iterable
 314       * alias for formdata.entries()
 315       *
 316       * @return  {Iterator}
 317       */
 318      [Symbol.iterator]() {
 319        return this.entries()
 320      }
 321  
 322  
 323      /**
 324       * Create the default string description.
 325       *
 326       * @return  {String} [object FormData]
 327       */
 328      toString() {
 329        return '[object FormData]'
 330      }
 331    }
 332  
 333  
 334    if (stringTag) {
 335      /**
 336       * Create the default string description.
 337       * It is accessed internally by the Object.prototype.toString().
 338       *
 339       * @return {String} FormData
 340       */
 341      FormDataPolyfill.prototype[stringTag] = 'FormData'
 342    }
 343  
 344    const decorations = [
 345      ['append', normalizeArgs],
 346      ['delete', stringify],
 347      ['get',    stringify],
 348      ['getAll', stringify],
 349      ['has',    stringify],
 350      ['set',    normalizeArgs]
 351    ]
 352  
 353    decorations.forEach(arr => {
 354      const orig = FormDataPolyfill.prototype[arr[0]]
 355      FormDataPolyfill.prototype[arr[0]] = function() {
 356        return orig.apply(this, arr[1].apply(this, arrayFrom(arguments)))
 357      }
 358    })
 359  
 360    // Patch xhr's send method to call _blob transparently
 361    if (_send) {
 362        XMLHttpRequest.prototype.send = function(data) {
 363        // I would check if Content-Type isn't already set
 364        // But xhr lacks getRequestHeaders functionallity
 365        // https://github.com/jimmywarting/FormData/issues/44
 366        if (data instanceof FormDataPolyfill) {
 367          const blob = data['_blob']()
 368          this.setRequestHeader('Content-Type', blob.type)
 369          _send.call(this, blob)
 370        } else {
 371          _send.call(this, data)
 372        }
 373      }
 374    }
 375  
 376    // Patch fetch's function to call _blob transparently
 377    if (_fetch) {
 378      const _fetch = global.fetch
 379  
 380      global.fetch = function(input, init) {
 381        if (init && init.body && init.body instanceof FormDataPolyfill) {
 382          init.body = init.body['_blob']()
 383        }
 384  
 385        return _fetch(input, init)
 386      }
 387    }
 388  
 389    global['FormData'] = FormDataPolyfill
 390  }


Generated: Mon Jan 7 01:00:05 2019 Cross-referenced by PHPXref 0.7.1