1/* 2* FileSaver.js 3* A saveAs() FileSaver implementation. 4* 5* By Eli Grey, http://eligrey.com 6* 7* License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT) 8* source : http://purl.eligrey.com/github/FileSaver.js 9*/ 10 11// The one and only way of getting global scope in all environments 12// https://stackoverflow.com/q/3277182/1008999 13var _global = typeof window === 'object' && window.window === window 14 ? window : typeof self === 'object' && self.self === self 15 ? self : typeof global === 'object' && global.global === global 16 ? global 17 : this 18 19function bom (blob, opts) { 20 if (typeof opts === 'undefined') opts = { autoBom: false } 21 else if (typeof opts !== 'object') { 22 console.warn('Deprecated: Expected third argument to be a object') 23 opts = { autoBom: !opts } 24 } 25 26 // prepend BOM for UTF-8 XML and text/* types (including HTML) 27 // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF 28 if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { 29 return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type }) 30 } 31 return blob 32} 33 34function download (url, name, opts) { 35 var xhr = new XMLHttpRequest() 36 xhr.open('GET', url) 37 xhr.responseType = 'blob' 38 xhr.onload = function () { 39 saveAs(xhr.response, name, opts) 40 } 41 xhr.onerror = function () { 42 console.error('could not download file') 43 } 44 xhr.send() 45} 46 47function corsEnabled (url) { 48 var xhr = new XMLHttpRequest() 49 // use sync to avoid popup blocker 50 xhr.open('HEAD', url, false) 51 try { 52 xhr.send() 53 } catch (e) {} 54 return xhr.status >= 200 && xhr.status <= 299 55} 56 57// `a.click()` doesn't work for all browsers (#465) 58function click (node) { 59 try { 60 node.dispatchEvent(new MouseEvent('click')) 61 } catch (e) { 62 var evt = document.createEvent('MouseEvents') 63 evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 64 20, false, false, false, false, 0, null) 65 node.dispatchEvent(evt) 66 } 67} 68 69// Detect WebView inside a native macOS app by ruling out all browsers 70// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too 71// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos 72var isMacOSWebView = _global.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent) 73 74var saveAs = _global.saveAs || ( 75 // probably in some web worker 76 (typeof window !== 'object' || window !== _global) 77 ? function saveAs () { /* noop */ } 78 79 // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView 80 : ('download' in HTMLAnchorElement.prototype && !isMacOSWebView) 81 ? function saveAs (blob, name, opts) { 82 var URL = _global.URL || _global.webkitURL 83 // Namespace is used to prevent conflict w/ Chrome Poper Blocker extension (Issue #561) 84 var a = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') 85 name = name || blob.name || 'download' 86
87 a.download = name 88 a.rel = 'noopener' // tabnabbing 89 90 // TODO: detect chrome extensions & packaged apps 91 // a.target = '_blank' 92 93 if (typeof blob === 'string') { 94 // Support regular links 95 a.href = blob 96 if (a.origin !== location.origin) { 97 corsEnabled(a.href) 98 ? download(blob, name, opts) 99 : click(a, a.target = '_blank') 100 } else { 101 click(a) 102 } 103 } else { 104 // Support blobs 105 a.href = URL.createObjectURL(blob) 106 setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s 107 setTimeout(function () { click(a) }, 0) 108 } 109 } 110 111 // Use msSaveOrOpenBlob as a second approach 112 : 'msSaveOrOpenBlob' in navigator 113 ? function saveAs (blob, name, opts) { 114 name = name || blob.name || 'download' 115 116 if (typeof blob === 'string') { 117 if (corsEnabled(blob)) { 118 download(blob, name, opts) 119 } else { 120 var a = document.createElement('a') 121 a.href = blob 122 a.target = '_blank' 123 setTimeout(function () { click(a) }) 124 } 125 } else { 126 navigator.msSaveOrOpenBlob(bom(blob, opts), name) 127 } 128 } 129 130 // Fallback to using FileReader and a popup 131 : function saveAs (blob, name, opts, popup) { 132 // Open a popup immediately do go around popup blocker 133 // Mostly only available on user interaction and the fileReader is async so... 134 popup = popup || open('', '_blank') 135 if (popup) { 136 popup.document.title = 137 popup.document.body.innerText = 'downloading...' 138 } 139 140 if (typeof blob === 'string') return download(blob, name, opts) 141 142 var force = blob.type === 'application/octet-stream' 143 var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari 144 var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent) 145 146 if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== 'undefined') { 147 // Safari doesn't allow downloading of blob URLs 148 var reader = new FileReader() 149 reader.onloadend = function () { 150 var url = reader.result 151 url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;') 152 if (popup) popup.location.href = url 153 else location = url 154 popup = null // reverse-tabnabbing #460 155 } 156 reader.readAsDataURL(blob) 157 } else { 158 var URL = _global.URL || _global.webkitURL 159 var url = URL.createObjectURL(blob) 160 if (popup) popup.location = url 161 else location.href = url 162 popup = null // reverse-tabnabbing #460 163 setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s 164 } 165 } 166) 167 168_global.saveAs = saveAs.saveAs = saveAs 169 170if (typeof module !== 'undefined') { 171 module.exports = saveAs; 172}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.