* @class elFinder command "restore"
* Restore items from the trash
(elFinder.prototype.commands.restore = function() {
getFilesRecursively = function(files) {
dfd._xhrReject = function() {
$.each(reqs, function() {
this && this.reject && this.reject();
getFile && getFile._xhrReject();
$.each(files, function(i, f) {
f.mime === 'directory'? dirs.push(f) : results.push(f);
$.each(dirs, function(i, d) {
data : {cmd : 'open', target : d.hash},
$.when.apply($, reqs).fail(function() {
$.each(arguments, function(i, r) {
items = items.concat(r.files);
hash: 'fakefile_' + (fakeCnt++),
getFile = getFilesRecursively(items).done(function(res) {
results = results.concat(res);
restore = function(dfrd, files, targets, ops) {
fm.lockfiles({files : targets});
dirs = $.map(files, function(f) {
return f.mime === 'directory'? f.hash : null;
dirs && fm.exec('rm', dirs, {forceRm : true, quiet : true});
fm.unlockfiles({files : targets});
tm = setTimeout(function() {
fm.notify({type : 'search', id : id, cnt : 1, hideCnt : true, cancel : function() {
getFile && getFile._xhrReject();
getFile = getFilesRecursively(files).always(function() {
fm.notify({type : 'search', id: id, cnt : -1, hideCnt : true});
dfrd.reject('errRestore', 'errFileNotFound');
var errFolderNotfound = ['errRestore', 'errFolderNotFound'],
$.each(res, function(i, f) {
if (srcRoot = fm.trashes[phash]) {
if (! rHashes[srcRoot]) {
// Keep items of other trash
return null; // continue $.each
tPath = fm.path(f.hash).substr(fm.path(phash).length).replace(/\\/g, '/');
tPath = tPath.replace(/\/[^\/]+?$/, '');
if (!rHashes[srcRoot][tPath]) {
rHashes[srcRoot][tPath] = [];
if (f.mime === 'fakefile') {
fm.updateCache({removed:[f.hash]});
rHashes[srcRoot][tPath].push(f.hash);
if (!dirTop || dirTop.length > tPath.length) {
// Go up one level for next check
// Detection method for search results
$.each(fm.trashes, function(ph) {
if ((!file.volumeid || f.hash.indexOf(file.volumeid) === 0) && fm.path(f.hash).indexOf(filePath) === 0) {
$.each(rHashes, function(src, dsts) {
var dirs = Object.keys(dsts),
data : {cmd : 'mkdir', target : src, dirs : dirs},
notify : {type : 'chkdir', cnt : cnt},
}).fail(function(error) {
fm.unlockfiles({files : targets});
if (hashes = data.hashes) {
cmdPaste = fm.getCommand('paste');
// wait until file cache made
fm.one('mkdirdone', function() {
$.each(dsts, function(dir, files) {
if (fm.file(hashes[dir])) {
fm.clipboard(files, true);
fm.exec('paste', [ hashes[dir] ], {_cmd : 'restore', noToast : (opts.noToast || dir !== dirTop)})
if (data && (data.error || data.warning)) {
dfrd[hasErr? 'reject' : 'resolve']();
// Restore items of other trash
fm.exec('restore', others);
dfrd.reject(errFolderNotfound);
// Restore items of other trash
fm.exec('restore', others);
dfrd.reject(['errRestore', 'errCmdNoSupport', '(paste)']);
dfrd.reject(errFolderNotfound);
dfrd.reject(errFolderNotfound);
dfrd.reject('errFileNotFound');
dirs && fm.exec('rm', dirs, {forceRm : true, quiet : true});
// for to be able to overwrite
this.linkedCmds = ['copy', 'paste', 'mkdir', 'rm'];
this.updateOnSelect = false;
// re-assign for extended command
this.getstate = function(sel, e) {
sel = sel || fm.selected();
return sel.length && $.grep(sel, function(h) {var f = fm.file(h); return f && ! f.locked && ! fm.isRoot(f)? true : false; }).length == sel.length
this.exec = function(hashes, opts) {
error && fm.error(error);
files = self.files(hashes);
$.each(files, function(i, file) {
return !dfrd.reject(['errRestore', file.name]);
return !dfrd.reject(['errLocked', file.name]);
if (dfrd.state() === 'pending') {
this.restore(dfrd, files, hashes, opts);
}).prototype = { forceLoad : true }; // this is required command