|
|
@ -1,16 +1,20 @@ |
|
|
|
import {bytesToArrayBuffer, blobSafeMimeType, blobConstruct, bytesToBase64} from './bin_utils'; |
|
|
|
import {bytesToArrayBuffer, blobSafeMimeType, blobConstruct, bytesToBase64} from './bin_utils'; |
|
|
|
|
|
|
|
|
|
|
|
class FileManager { |
|
|
|
import 'web-streams-polyfill/ponyfill'; |
|
|
|
/* $window.URL = $window.URL || $window.webkitURL |
|
|
|
// @ts-ignore
|
|
|
|
$window.BlobBuilder = $window.BlobBuilder || $window.WebKitBlobBuilder || $window.MozBlobBuilder */ |
|
|
|
import streamSaver from 'streamsaver'; |
|
|
|
|
|
|
|
if(window.location.href.indexOf('localhost') === -1) { |
|
|
|
|
|
|
|
streamSaver.mitm = 'mitm.html'; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FileManager { |
|
|
|
public isSafari = 'safari' in window; |
|
|
|
public isSafari = 'safari' in window; |
|
|
|
public safariVersion = parseFloat(this.isSafari && (navigator.userAgent.match(/Version\/(\d+\.\d+).* Safari/) || [])[1]); |
|
|
|
public safariVersion = parseFloat(this.isSafari && (navigator.userAgent.match(/Version\/(\d+\.\d+).* Safari/) || [])[1]); |
|
|
|
public safariWithDownload = this.isSafari && this.safariVersion >= 11.0; |
|
|
|
public safariWithDownload = this.isSafari && this.safariVersion >= 11.0; |
|
|
|
public buggyUnknownBlob = this.isSafari && !this.safariWithDownload; |
|
|
|
public buggyUnknownBlob = this.isSafari && !this.safariWithDownload; |
|
|
|
|
|
|
|
|
|
|
|
public blobSupported = true; |
|
|
|
public blobSupported = true; |
|
|
|
|
|
|
|
|
|
|
|
constructor() { |
|
|
|
constructor() { |
|
|
|
try { |
|
|
|
try { |
|
|
|
blobConstruct([], ''); |
|
|
|
blobConstruct([], ''); |
|
|
@ -18,12 +22,12 @@ class FileManager { |
|
|
|
this.blobSupported = false; |
|
|
|
this.blobSupported = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public isAvailable() { |
|
|
|
public isAvailable() { |
|
|
|
return this.blobSupported; |
|
|
|
return this.blobSupported; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public copy(fromFileEntry: any, toFileEntry: any) { |
|
|
|
/* public copy(fromFileEntry: any, toFileEntry: any) { |
|
|
|
return this.getFileWriter(toFileEntry).then((fileWriter) => { |
|
|
|
return this.getFileWriter(toFileEntry).then((fileWriter) => { |
|
|
|
return this.write(fileWriter, fromFileEntry).then(() => { |
|
|
|
return this.write(fileWriter, fromFileEntry).then(() => { |
|
|
|
return fileWriter; |
|
|
|
return fileWriter; |
|
|
@ -32,13 +36,28 @@ class FileManager { |
|
|
|
// @ts-ignore
|
|
|
|
// @ts-ignore
|
|
|
|
fileWriter.truncate(0); |
|
|
|
fileWriter.truncate(0); |
|
|
|
} catch (e) {} |
|
|
|
} catch (e) {} |
|
|
|
|
|
|
|
|
|
|
|
return Promise.reject(error); |
|
|
|
return Promise.reject(error); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
} */ |
|
|
|
|
|
|
|
public copy(fromFileEntry: any, toFileEntry: any) { |
|
|
|
|
|
|
|
return this.write(toFileEntry, fromFileEntry).then(() => { |
|
|
|
|
|
|
|
console.log('copy success'); |
|
|
|
|
|
|
|
return toFileEntry; |
|
|
|
|
|
|
|
}, (error: any) => { |
|
|
|
|
|
|
|
console.error('copy error 1:', error); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
toFileEntry.truncate(0); |
|
|
|
|
|
|
|
} catch(e) { |
|
|
|
|
|
|
|
console.error('copy error', e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return Promise.reject(error); |
|
|
|
|
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public write(fileWriter: any, bytes: any) { |
|
|
|
/* public write(fileWriter: any, bytes: any) { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
fileWriter.onwriteend = function(e: any) { |
|
|
|
fileWriter.onwriteend = function(e: any) { |
|
|
|
resolve(); |
|
|
|
resolve(); |
|
|
@ -46,7 +65,7 @@ class FileManager { |
|
|
|
fileWriter.onerror = function(e: any) { |
|
|
|
fileWriter.onerror = function(e: any) { |
|
|
|
reject(e); |
|
|
|
reject(e); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
if(bytes.file) { |
|
|
|
if(bytes.file) { |
|
|
|
bytes.file((file: any) => { |
|
|
|
bytes.file((file: any) => { |
|
|
|
fileWriter.write(file); |
|
|
|
fileWriter.write(file); |
|
|
@ -62,54 +81,52 @@ class FileManager { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public write(fileWriter: any, bytes: any): Promise<void> { |
|
|
|
|
|
|
|
if(bytes.file) { |
|
|
|
|
|
|
|
return bytes.file((file: any) => { |
|
|
|
|
|
|
|
return fileWriter.write(file); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} else if(bytes instanceof Blob) { // is file bytes
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
|
|
|
|
let fileReader = new FileReader(); |
|
|
|
|
|
|
|
fileReader.onload = function(event) { |
|
|
|
|
|
|
|
let arrayBuffer = event.target.result as ArrayBuffer; |
|
|
|
|
|
|
|
|
|
|
|
public chooseSaveFile(fileName: string, ext: string, mimeType: string) { |
|
|
|
let arr = new Uint8Array(arrayBuffer); |
|
|
|
return Promise.reject(); |
|
|
|
|
|
|
|
/* if(!window.chrome || !chrome.fileSystem || !chrome.fileSystem.chooseEntry) { |
|
|
|
|
|
|
|
//return qSync.reject()
|
|
|
|
|
|
|
|
return Promise.reject(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
var deferred = $q.defer() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
chrome.fileSystem.chooseEntry({ |
|
|
|
fileWriter.write(arr).then(resolve, reject); |
|
|
|
type: 'saveFile', |
|
|
|
}; |
|
|
|
suggestedName: fileName, |
|
|
|
|
|
|
|
accepts: [{ |
|
|
|
|
|
|
|
mimeTypes: [mimeType], |
|
|
|
|
|
|
|
extensions: [ext] |
|
|
|
|
|
|
|
}] |
|
|
|
|
|
|
|
}, function (writableFileEntry) { |
|
|
|
|
|
|
|
deferred.resolve(writableFileEntry) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return deferred.promise */ |
|
|
|
fileReader.readAsArrayBuffer(bytes); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
//var blob = blobConstruct([bytesToArrayBuffer(bytes)]);
|
|
|
|
|
|
|
|
//return fileWriter.write(blob);
|
|
|
|
|
|
|
|
return fileWriter.write(bytes); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public getFileWriter(fileEntry: any) { |
|
|
|
public chooseSaveFile(fileName: string, ext: string, mimeType: string, size?: number): any { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
let fileStream = streamSaver.createWriteStream(fileName, { |
|
|
|
fileEntry.createWriter(resolve, reject); |
|
|
|
size: size, |
|
|
|
|
|
|
|
writableStrategy: undefined, |
|
|
|
|
|
|
|
readableStrategy: undefined |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
let writer = fileStream.getWriter(); |
|
|
|
|
|
|
|
return writer; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public getFakeFileWriter(mimeType: string, saveFileCallback: any) { |
|
|
|
public getFakeFileWriter(mimeType: string, saveFileCallback: any) { |
|
|
|
var blobParts: Array<Blob> = []; |
|
|
|
var blobParts: Array<Blob> = []; |
|
|
|
var fakeFileWriter: any = { |
|
|
|
var fakeFileWriter = { |
|
|
|
write: (blob: Blob) => { |
|
|
|
write: async(blob: Blob) => { |
|
|
|
if(!this.blobSupported) { |
|
|
|
if(!this.blobSupported) { |
|
|
|
if(fakeFileWriter.onerror) { |
|
|
|
throw false; |
|
|
|
fakeFileWriter.onerror(new Error('Blob not supported by browser')); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
blobParts.push(blob); |
|
|
|
blobParts.push(blob); |
|
|
|
setTimeout(() => { |
|
|
|
|
|
|
|
if(fakeFileWriter.onwriteend) { |
|
|
|
|
|
|
|
fakeFileWriter.onwriteend(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, 0); |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
truncate: () => { |
|
|
|
truncate: () => { |
|
|
|
blobParts = []; |
|
|
|
blobParts = []; |
|
|
@ -119,14 +136,14 @@ class FileManager { |
|
|
|
if(saveFileCallback) { |
|
|
|
if(saveFileCallback) { |
|
|
|
saveFileCallback(blob); |
|
|
|
saveFileCallback(blob); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return blob; |
|
|
|
return blob; |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
return fakeFileWriter; |
|
|
|
return fakeFileWriter; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public getUrl(fileData: any, mimeType: string) { |
|
|
|
public getUrl(fileData: any, mimeType: string) { |
|
|
|
var safeMimeType = blobSafeMimeType(mimeType); |
|
|
|
var safeMimeType = blobSafeMimeType(mimeType); |
|
|
|
// console.log(dT(), 'get url', fileData, mimeType, fileData.toURL !== undefined, fileData instanceof Blob)
|
|
|
|
// console.log(dT(), 'get url', fileData, mimeType, fileData.toURL !== undefined, fileData instanceof Blob)
|
|
|
@ -138,7 +155,7 @@ class FileManager { |
|
|
|
} |
|
|
|
} |
|
|
|
return 'data:' + safeMimeType + ';base64,' + bytesToBase64(fileData); |
|
|
|
return 'data:' + safeMimeType + ';base64,' + bytesToBase64(fileData); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public getByteArray(fileData: any) { |
|
|
|
public getByteArray(fileData: any) { |
|
|
|
if(fileData instanceof Blob) { |
|
|
|
if(fileData instanceof Blob) { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
@ -146,7 +163,7 @@ class FileManager { |
|
|
|
var reader = new FileReader(); |
|
|
|
var reader = new FileReader(); |
|
|
|
reader.onloadend = (e) => { |
|
|
|
reader.onloadend = (e) => { |
|
|
|
// @ts-ignore
|
|
|
|
// @ts-ignore
|
|
|
|
resolve(new Uint8Array(e.target.result)); |
|
|
|
resolve(new Uint8Array(e.target.result)); |
|
|
|
}; |
|
|
|
}; |
|
|
|
reader.onerror = (e) => { |
|
|
|
reader.onerror = (e) => { |
|
|
|
reject(e); |
|
|
|
reject(e); |
|
|
@ -163,11 +180,11 @@ class FileManager { |
|
|
|
}, reject); |
|
|
|
}, reject); |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return Promise.resolve(fileData); |
|
|
|
return Promise.resolve(fileData); |
|
|
|
//return $q.when(fileData);
|
|
|
|
//return $q.when(fileData);
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public getDataUrl(blob: any) { |
|
|
|
public getDataUrl(blob: any) { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
try { |
|
|
|
try { |
|
|
@ -181,7 +198,7 @@ class FileManager { |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public getFileCorrectUrl(blob: any, mimeType: string) { |
|
|
|
public getFileCorrectUrl(blob: any, mimeType: string) { |
|
|
|
if(this.buggyUnknownBlob && blob instanceof Blob) { |
|
|
|
if(this.buggyUnknownBlob && blob instanceof Blob) { |
|
|
|
// @ts-ignore
|
|
|
|
// @ts-ignore
|
|
|
@ -190,48 +207,48 @@ class FileManager { |
|
|
|
return this.getDataUrl(blob); |
|
|
|
return this.getDataUrl(blob); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return Promise.resolve(this.getUrl(blob, mimeType)); |
|
|
|
return Promise.resolve(this.getUrl(blob, mimeType)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// downloadFile
|
|
|
|
// downloadFile
|
|
|
|
public download(blob: any, mimeType: string, fileName: string) { |
|
|
|
public download(blob: any, mimeType: string, fileName: string) { |
|
|
|
if(window.navigator && navigator.msSaveBlob !== undefined) { |
|
|
|
if(window.navigator && navigator.msSaveBlob !== undefined) { |
|
|
|
window.navigator.msSaveBlob(blob, fileName); |
|
|
|
window.navigator.msSaveBlob(blob, fileName); |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(window.navigator && 'getDeviceStorage' in navigator) { |
|
|
|
if(window.navigator && 'getDeviceStorage' in navigator) { |
|
|
|
var storageName = 'sdcard'; |
|
|
|
var storageName = 'sdcard'; |
|
|
|
var subdir = 'telegram/'; |
|
|
|
var subdir = 'telegram/'; |
|
|
|
switch(mimeType.split('/')[0]) { |
|
|
|
switch(mimeType.split('/')[0]) { |
|
|
|
case 'video': |
|
|
|
case 'video': |
|
|
|
storageName = 'videos'; |
|
|
|
storageName = 'videos'; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case 'audio': |
|
|
|
case 'audio': |
|
|
|
storageName = 'music'; |
|
|
|
storageName = 'music'; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case 'image': |
|
|
|
case 'image': |
|
|
|
storageName = 'pictures'; |
|
|
|
storageName = 'pictures'; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
// @ts-ignore
|
|
|
|
var deviceStorage = navigator.getDeviceStorage(storageName); |
|
|
|
var deviceStorage = navigator.getDeviceStorage(storageName); |
|
|
|
var request = deviceStorage.addNamed(blob, subdir + fileName); |
|
|
|
var request = deviceStorage.addNamed(blob, subdir + fileName); |
|
|
|
|
|
|
|
|
|
|
|
request.onsuccess = function () { |
|
|
|
request.onsuccess = function () { |
|
|
|
console.log('Device storage save result', this.result); |
|
|
|
console.log('Device storage save result', this.result); |
|
|
|
}; |
|
|
|
}; |
|
|
|
request.onerror = () => {}; |
|
|
|
request.onerror = () => {}; |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var popup: Window; |
|
|
|
var popup: Window; |
|
|
|
if(this.isSafari && !this.safariWithDownload) { |
|
|
|
if(this.isSafari && !this.safariWithDownload) { |
|
|
|
popup = window.open(); |
|
|
|
popup = window.open(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.getFileCorrectUrl(blob, mimeType).then((url) => { |
|
|
|
this.getFileCorrectUrl(blob, mimeType).then((url) => { |
|
|
|
if(popup) { |
|
|
|
if(popup) { |
|
|
|
try { |
|
|
|
try { |
|
|
@ -240,7 +257,7 @@ class FileManager { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} catch (e) {} |
|
|
|
} catch (e) {} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var anchor = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') as HTMLAnchorElement; |
|
|
|
var anchor = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') as HTMLAnchorElement; |
|
|
|
anchor.href = url as string; |
|
|
|
anchor.href = url as string; |
|
|
|
if(!this.safariWithDownload) { |
|
|
|
if(!this.safariWithDownload) { |
|
|
@ -254,29 +271,30 @@ class FileManager { |
|
|
|
anchor.style.position = 'absolute'; |
|
|
|
anchor.style.position = 'absolute'; |
|
|
|
anchor.style.top = '1px'; |
|
|
|
anchor.style.top = '1px'; |
|
|
|
anchor.style.left = '1px'; |
|
|
|
anchor.style.left = '1px'; |
|
|
|
|
|
|
|
|
|
|
|
document.body.append(anchor); |
|
|
|
document.body.append(anchor); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
var clickEvent = document.createEvent('MouseEvents'); |
|
|
|
var clickEvent = document.createEvent('MouseEvents'); |
|
|
|
clickEvent.initMouseEvent( |
|
|
|
clickEvent.initMouseEvent( |
|
|
|
'click', true, false, window, 0, 0, 0, 0, 0 |
|
|
|
'click', true, false, window, 0, 0, 0, 0, 0 |
|
|
|
, false, false, false, false, 0, null |
|
|
|
, false, false, false, false, 0, null |
|
|
|
) |
|
|
|
) |
|
|
|
anchor.dispatchEvent(clickEvent); |
|
|
|
anchor.dispatchEvent(clickEvent); |
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
console.error('Download click error', e); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
anchor.click(); |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
window.open(url as string, '_blank'); |
|
|
|
console.error('Download click error', e); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
anchor.click(); |
|
|
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
|
|
window.open(url as string, '_blank'); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
setTimeout(() => { |
|
|
|
setTimeout(() => { |
|
|
|
anchor.remove(); |
|
|
|
anchor.remove(); |
|
|
|
}, 100); |
|
|
|
}, 100); |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export default new FileManager(); |
|
|
|
export default new FileManager(); |
|
|
|
|