c9-core/plugins/c9.ide.upload/batch.js

264 wiersze
7.5 KiB
JavaScript

define(function(require, module, exports) {
"use strict";
var SUPPORT_FOLDER_UPLOAD = (function() {
var input = document.createElement("input");
return "webkitdirectory" in input || "directory" in input;
})();
function Batch(files, entries) {
this.files = files;
this.entries = entries;
}
Batch.prototype.hasDirectories = function() {
return this.files.some(function(file) {
return !!file.isDirectory;
});
};
/**
* remove all files within the given root folder of with the given root file name
*/
Batch.prototype.removeRoot = function(root) {
this.files = this.files.filter(function(file) {
return file.fullPath.split("/")[1] !== root;
});
};
Batch.prototype.subTree = function(root) {
return this.files.filter(function(file) {
return file.fullPath.split("/")[1] === root;
});
};
Batch.prototype.ignoreFiles = function(ignoredFilesMap) {
this.files = this.files.filter(function(file) {
return !ignoredFilesMap[file.name];
});
};
Batch.prototype.getSizes = function() {
var max = 0;
var sum = this.files.reduce(function(sum, file) {
if (file.size > max)
max = file.size;
return sum + file.size;
}, 0);
return {
max: max,
sum: sum,
count: this.files.length
};
};
Batch.prototype.getRoots = function() {
return Object.keys(this.files.reduce(function(roots, file) {
var root = file.fullPath.split("/")[1];
if (root)
roots[root] = 1;
return roots;
}, {}));
};
Batch.prototype._detectDirectories = function(callback) {
forEach(this.files, function(file, next) {
if (typeof file.size !== "number") {
file.isDirectory = true;
return next();
}
if (file.size > 17000) {
file.isFile = true;
return next();
}
try {
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onloadend = function(e) {
var error = reader.error;
var hadError = error && (
error.name == "SecurityError" || // Firefox
error.name == "NotReadableError" || // Firefox
error.code == 4 || // Safari
error.code == 1); // Chrome
console.log(e, hadError, reader.error, file.size);
if (hadError)
file.isDirectory = true;
else
file.isFile = true;
next();
};
} catch (e) {
file.isDirectory = true;
return next();
}
}, callback);
};
Batch.fromInput = function(inputEl, callback) {
if (!inputEl.files)
return new Batch([]);
var files = [].slice.call(inputEl.files, 0);
files.forEach(function(file) {
var relativePath = file.relativePath || file.webkitRelativePath;
file.fullPath = "/" + (relativePath ? relativePath : file.name);
});
var fromFolderUpload =
SUPPORT_FOLDER_UPLOAD &&
inputEl.getAttribute &&
(typeof inputEl.getAttribute("directory") === "string" || typeof inputEl.getAttribute("webkitdirectory") === "string");
// folder uploads handle directories differently
if (fromFolderUpload) {
files = files.filter(function(file) {
file.isFile = true;
return file.name !== ".";
});
return callback(null, new Batch(files));
}
var batch = new Batch(files);
batch._detectDirectories(function(err) {
callback(err, batch);
});
};
Batch.fromFileApi = function(entries, callback) {
var files = [];
var skipped = {};
forEach(entries, function(entry, next) {
walkFiles(entry, function(entry, next) {
// ignore directories
if (entry.isDirectory)
return next();
entry.file(function(file) {
file.fullPath = entry.fullPath;
file.isFile = true;
files.push(file);
next();
}, function(err) {
skipped[entry.fullPath] = err;
next();
});
}, function(err) {
next();
});
}, function(err) {
if (err) return callback(err);
callback(null, new Batch(files, entries), skipped);
});
};
Batch.fromDrop = function(dropEvent, callback) {
var dataTransfer = dropEvent.dataTransfer;
if (!dataTransfer)
return callback(null, new Batch([]));
if (dataTransfer.getFilesAndDirectories)
return Batch.fromMozFileApi(dataTransfer, callback);
if (!dataTransfer.items)
return Batch.fromInput(dataTransfer, callback);
if (!dataTransfer.items || dataTransfer.items.length === 0)
return callback(null, new Batch([]));
var first = dataTransfer.items[0];
var getAsEntry = first.getAsEntry || first.webkitGetAsEntry;
var entries = [].map.call(dataTransfer.items, function(item) {
return getAsEntry.call(item);
});
Batch.fromFileApi(entries, callback);
};
Batch.fromMozFileApi = function(dataTransfer, callback) {
var files = [];
var pending = 0;
// requires dom.input.dirpicker true in about:config
var walkdDirs = function(entries, parentPath) {
entries.forEach(function(entry) {
var name = entry.name;
if (parentPath == "/" && (name[0] == "\\" || name[0] == "//"))
name = name.slice(1);
var path = parentPath ? parentPath + name : "";
if (typeof entry.getFilesAndDirectories === 'function') {
pending++;
entry.getFilesAndDirectories().then(function(entries) {
walkdDirs(entries, path + "/");
pending--;
done();
});
} else {
entry.fullPath = path;
entry.isFile = true;
files.push(entry);
}
});
done();
};
function done() {
if (!pending)
callback(null, new Batch(files));
}
walkdDirs([dataTransfer]);
};
function walkFiles(entry, onEntry, callback) {
if (!entry) {
return callback();
}
if (entry.isFile) {
onEntry(entry, callback);
}
else if (entry.isDirectory) {
onEntry(entry, function(err) {
if (err) return callback(err);
var reader = entry.createReader();
function handleEntries(entries) {
if (!entries.length)
return callback();
forEach(entries, function(entry, next) {
walkFiles(entry, onEntry, next);
}, readMore);
}
function readMore() {
// Keep calling readEntries() until no more results are returned.
reader.readEntries(handleEntries, callback);
}
readMore();
});
}
}
function forEach(list, onEntry, callback) {
(function loop(i) {
if (i >= list.length)
return callback();
onEntry(list[i], function(err) {
if (err) return callback(err);
loop(i + 1);
});
})(0);
}
return {
SUPPORT_FOLDER_UPLOAD: SUPPORT_FOLDER_UPLOAD,
fromFileApi: Batch.fromFileApi,
fromDrop: Batch.fromDrop,
fromInput: Batch.fromInput
};
});