123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- /*!
- FileReader.js - v0.99
- A lightweight wrapper for common FileReader usage.
- Copyright 2014 Brian Grinstead - MIT License.
- See http://github.com/bgrins/filereader.js for documentation.
- */
- (function(window, document) {
- var FileReader = window.FileReader;
- var FileReaderSyncSupport = false;
- var workerScript = "self.addEventListener('message', function(e) { var data=e.data; try { var reader = new FileReaderSync; postMessage({ result: reader[data.readAs](data.file), extra: data.extra, file: data.file})} catch(e){ postMessage({ result:'error', extra:data.extra, file:data.file}); } }, false);";
- var syncDetectionScript = "onmessage = function(e) { postMessage(!!FileReaderSync); };";
- var fileReaderEvents = ['loadstart', 'progress', 'load', 'abort', 'error', 'loadend'];
- var sync = false;
- var FileReaderJS = window.FileReaderJS = {
- enabled: false,
- setupInput: setupInput,
- setupBlob: setupBlob,
- setupDrop: setupDrop,
- setupClipboard: setupClipboard,
- setSync: function (value) {
- sync = value;
- if (sync && !FileReaderSyncSupport) {
- checkFileReaderSyncSupport();
- }
- },
- getSync: function() {
- return sync && FileReaderSyncSupport;
- },
- output: [],
- opts: {
- dragClass: "drag",
- accept: false,
- readAsDefault: 'DataURL',
- readAsMap: {
- },
- on: {
- loadstart: noop,
- progress: noop,
- load: noop,
- abort: noop,
- error: noop,
- loadend: noop,
- skip: noop,
- groupstart: noop,
- groupend: noop,
- beforestart: noop
- }
- }
- };
- // Setup jQuery plugin (if available)
- if (typeof(jQuery) !== "undefined") {
- jQuery.fn.fileReaderJS = function(opts) {
- return this.each(function() {
- if (jQuery(this).is("input")) {
- setupInput(this, opts);
- }
- else {
- setupDrop(this, opts);
- }
- });
- };
- jQuery.fn.fileClipboard = function(opts) {
- return this.each(function() {
- setupClipboard(this, opts);
- });
- };
- }
- // Not all browsers support the FileReader interface. Return with the enabled bit = false.
- if (!FileReader) {
- return;
- }
- // makeWorker is a little wrapper for generating web workers from strings
- function makeWorker(script) {
- var URL = window.URL || window.webkitURL;
- var Blob = window.Blob;
- var Worker = window.Worker;
- if (!URL || !Blob || !Worker || !script) {
- return null;
- }
- var blob = new Blob([script]);
- var worker = new Worker(URL.createObjectURL(blob));
- return worker;
- }
- // setupClipboard: bind to clipboard events (intended for document.body)
- function setupClipboard(element, opts) {
- if (!FileReaderJS.enabled) {
- return;
- }
- var instanceOptions = extend(extend({}, FileReaderJS.opts), opts);
- element.addEventListener("paste", onpaste, false);
- function onpaste(e) {
- var files = [];
- var clipboardData = e.clipboardData || {};
- var items = clipboardData.items || [];
- for (var i = 0; i < items.length; i++) {
- var file = items[i].getAsFile();
- if (file) {
- // Create a fake file name for images from clipboard, since this data doesn't get sent
- var matches = new RegExp("/\(.*\)").exec(file.type);
- if (!file.name && matches) {
- var extension = matches[1];
- file.name = "clipboard" + i + "." + extension;
- }
- files.push(file);
- }
- }
- if (files.length) {
- processFileList(e, files, instanceOptions);
- e.preventDefault();
- e.stopPropagation();
- }
- }
- }
- // setupInput: bind the 'change' event to an input[type=file]
- function setupInput(input, opts) {
- if (!FileReaderJS.enabled) {
- return;
- }
- var instanceOptions = extend(extend({}, FileReaderJS.opts), opts);
- input.addEventListener("change", inputChange, false);
- input.addEventListener("drop", inputDrop, false);
- function inputChange(e) {
- processFileList(e, input.files, instanceOptions);
- }
- function inputDrop(e) {
- e.stopPropagation();
- e.preventDefault();
- processFileList(e, e.dataTransfer.files, instanceOptions);
- }
- }
- // setupFile: bind the 'change' event to an input[type=file]
- function setupBlob(blob, opts) {
-
- if (!FileReaderJS.enabled) {
- return;
- }
- if(blob.constructor !== Array && blob.constructor !== Function){
- if(blob.name === undefined){
- blob.name = "blob";
- }
- blob = [blob];
- }else{
- if(blob[0].name === undefined){
- blob[0].name = "blob";
- }
- }
-
- var instanceOptions = extend(extend({}, FileReaderJS.opts), opts);
- processFileList(null, blob, instanceOptions);
- }
- // setupDrop: bind the 'drop' event for a DOM element
- function setupDrop(dropbox, opts) {
- if (!FileReaderJS.enabled) {
- return;
- }
- var instanceOptions = extend(extend({}, FileReaderJS.opts), opts);
- var dragClass = instanceOptions.dragClass;
- var initializedOnBody = false;
- // Bind drag events to the dropbox to add the class while dragging, and accept the drop data transfer.
- dropbox.addEventListener("dragenter", onlyWithFiles(dragenter), false);
- dropbox.addEventListener("dragleave", onlyWithFiles(dragleave), false);
- dropbox.addEventListener("dragover", onlyWithFiles(dragover), false);
- dropbox.addEventListener("drop", onlyWithFiles(drop), false);
- // Bind to body to prevent the dropbox events from firing when it was initialized on the page.
- document.body.addEventListener("dragstart", bodydragstart, true);
- document.body.addEventListener("dragend", bodydragend, true);
- document.body.addEventListener("drop", bodydrop, false);
- function bodydragend(e) {
- initializedOnBody = false;
- }
- function bodydragstart(e) {
- initializedOnBody = true;
- }
- function bodydrop(e) {
- if (e.dataTransfer.files && e.dataTransfer.files.length ){
- e.stopPropagation();
- e.preventDefault();
- }
- }
- function onlyWithFiles(fn) {
- return function() {
- if (!initializedOnBody) {
- fn.apply(this, arguments);
- }
- };
- }
- function drop(e) {
- e.stopPropagation();
- e.preventDefault();
- if (dragClass) {
- removeClass(dropbox, dragClass);
- }
- processFileList(e, e.dataTransfer.files, instanceOptions);
- }
- function dragenter(e) {
- e.stopPropagation();
- e.preventDefault();
- if (dragClass) {
- addClass(dropbox, dragClass);
- }
- }
- function dragleave(e) {
- if (dragClass) {
- removeClass(dropbox, dragClass);
- }
- }
- function dragover(e) {
- e.stopPropagation();
- e.preventDefault();
- if (dragClass) {
- addClass(dropbox, dragClass);
- }
- }
- }
- // setupCustomFileProperties: modify the file object with extra properties
- function setupCustomFileProperties(files, groupID) {
- for (var i = 0; i < files.length; i++) {
- var file = files[i];
- file.extra = {
- nameNoExtension: file.name.substring(0, file.name.lastIndexOf('.')),
- extension: file.name.substring(file.name.lastIndexOf('.') + 1),
- fileID: i,
- uniqueID: getUniqueID(),
- groupID: groupID,
- prettySize: prettySize(file.size)
- };
- }
- }
- // getReadAsMethod: return method name for 'readAs*' - http://www.w3.org/TR/FileAPI/#reading-a-file
- function getReadAsMethod(type, readAsMap, readAsDefault) {
- for (var r in readAsMap) {
- if (type.match(new RegExp(r))) {
- return 'readAs' + readAsMap[r];
- }
- }
- return 'readAs' + readAsDefault;
- }
- // processFileList: read the files with FileReader, send off custom events.
- function processFileList(e, files, opts) {
- var filesLeft = files.length;
- var group = {
- groupID: getGroupID(),
- files: files,
- started: new Date()
- };
- function groupEnd() {
- group.ended = new Date();
- opts.on.groupend(group);
- }
- function groupFileDone() {
- if (--filesLeft === 0) {
- groupEnd();
- }
- }
- FileReaderJS.output.push(group);
- setupCustomFileProperties(files, group.groupID);
- opts.on.groupstart(group);
- // No files in group - end immediately
- if (!files.length) {
- groupEnd();
- return;
- }
- var supportsSync = sync && FileReaderSyncSupport;
- var syncWorker;
- // Only initialize the synchronous worker if the option is enabled - to prevent the overhead
- if (supportsSync) {
- syncWorker = makeWorker(workerScript);
- syncWorker.onmessage = function(e) {
- var file = e.data.file;
- var result = e.data.result;
- // Workers seem to lose the custom property on the file object.
- if (!file.extra) {
- file.extra = e.data.extra;
- }
- file.extra.ended = new Date();
- // Call error or load event depending on success of the read from the worker.
- opts.on[result === "error" ? "error" : "load"]({ target: { result: result } }, file);
- groupFileDone();
- };
- }
- Array.prototype.forEach.call(files, function(file) {
- file.extra.started = new Date();
- if (opts.accept && !file.type.match(new RegExp(opts.accept))) {
- opts.on.skip(file);
- groupFileDone();
- return;
- }
- if (opts.on.beforestart(file) === false) {
- opts.on.skip(file);
- groupFileDone();
- return;
- }
- var readAs = getReadAsMethod(file.type, opts.readAsMap, opts.readAsDefault);
- if (syncWorker) {
- syncWorker.postMessage({
- file: file,
- extra: file.extra,
- readAs: readAs
- });
- }
- else {
- var reader = new FileReader();
- reader.originalEvent = e;
- fileReaderEvents.forEach(function(eventName) {
- reader['on' + eventName] = function(e) {
- if (eventName == 'load' || eventName == 'error') {
- file.extra.ended = new Date();
- }
- opts.on[eventName](e, file);
- if (eventName == 'loadend') {
- groupFileDone();
- }
- };
- });
- reader[readAs](file);
- }
- });
- }
- // checkFileReaderSyncSupport: Create a temporary worker and see if FileReaderSync exists
- function checkFileReaderSyncSupport() {
- var worker = makeWorker(syncDetectionScript);
- if (worker) {
- worker.onmessage =function(e) {
- FileReaderSyncSupport = e.data;
- };
- worker.postMessage({});
- }
- }
- // noop: do nothing
- function noop() {
- }
- // extend: used to make deep copies of options object
- function extend(destination, source) {
- for (var property in source) {
- if (source[property] && source[property].constructor &&
- source[property].constructor === Object) {
- destination[property] = destination[property] || {};
- arguments.callee(destination[property], source[property]);
- }
- else {
- destination[property] = source[property];
- }
- }
- return destination;
- }
- // hasClass: does an element have the css class?
- function hasClass(el, name) {
- return new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)").test(el.className);
- }
- // addClass: add the css class for the element.
- function addClass(el, name) {
- if (!hasClass(el, name)) {
- el.className = el.className ? [el.className, name].join(' ') : name;
- }
- }
- // removeClass: remove the css class from the element.
- function removeClass(el, name) {
- if (hasClass(el, name)) {
- var c = el.className;
- el.className = c.replace(new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)", "g"), " ").replace(/^\s\s*/, '').replace(/\s\s*$/, '');
- }
- }
- // prettySize: convert bytes to a more readable string.
- function prettySize(bytes) {
- var s = ['bytes', 'kb', 'MB', 'GB', 'TB', 'PB'];
- var e = Math.floor(Math.log(bytes)/Math.log(1024));
- return (bytes/Math.pow(1024, Math.floor(e))).toFixed(2)+" "+s[e];
- }
- // getGroupID: generate a unique int ID for groups.
- var getGroupID = (function(id) {
- return function() {
- return id++;
- };
- })(0);
- // getUniqueID: generate a unique int ID for files
- var getUniqueID = (function(id) {
- return function() {
- return id++;
- };
- })(0);
- // The interface is supported, bind the FileReaderJS callbacks
- FileReaderJS.enabled = true;
- })(this, document);
|