This commit is contained in:
2026-07-02 15:54:39 -06:00
commit 9883323161
17470 changed files with 4470592 additions and 0 deletions
@@ -0,0 +1,100 @@
/**
* @class elFinder command "archive"
* Archive selected files
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.archive = function() {
"use strict";
var self = this,
fm = self.fm,
mimes = [],
dfrd;
this.variants = [];
this.disableOnSearch = false;
this.nextAction = {};
/**
* Update mimes on open/reload
*
* @return void
**/
fm.bind('open reload', function() {
self.variants = [];
$.each((mimes = fm.option('archivers')['create'] || []), function(i, mime) {
self.variants.push([mime, fm.mime2kind(mime)]);
});
self.change();
});
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length,
chk = (cnt && ! fm.isRoot(sel[0]) && (fm.file(sel[0].phash) || {}).write),
filter = function(files) {
var fres = true;
return $.grep(files, function(f) {
fres = fres && f.read && f.hash.indexOf(cwdId) === 0 ? true : false;
return fres;
});
},
cwdId;
if (chk && fm.searchStatus.state > 1) {
if (chk = (cnt === filter(sel).length)) {
cwdId = fm.cwd().volumeid;
}
}
return chk && !this._disabled && mimes.length && (cnt || (dfrd && dfrd.state() == 'pending')) ? 0 : -1;
};
this.exec = function(hashes, type) {
var files = this.files(hashes),
cnt = files.length,
mime = type || mimes[0],
cwd = fm.file(files[0].phash) || null,
error = ['errArchive', 'errPerm', 'errCreatingTempDir', 'errFtpDownloadFile', 'errFtpUploadFile', 'errFtpMkdir', 'errArchiveExec', 'errExtractExec', 'errRm'],
i, open;
dfrd = $.Deferred().fail(function(error) {
error && fm.error(error);
});
if (! (cnt && mimes.length && $.inArray(mime, mimes) !== -1)) {
return dfrd.reject();
}
if (!cwd.write) {
return dfrd.reject(error);
}
for (i = 0; i < cnt; i++) {
if (!files[i].read) {
return dfrd.reject(error);
}
}
self.mime = mime;
self.prefix = ((cnt > 1)? 'Archive' : files[0].name) + (fm.option('archivers')['createext']? '.' + fm.option('archivers')['createext'][mime] : '');
self.data = {targets : self.hashes(hashes), type : mime};
if (fm.cwd().hash !== cwd.hash) {
open = fm.exec('open', cwd.hash).done(function() {
fm.one('cwdrender', function() {
fm.selectfiles({files : hashes});
dfrd = $.proxy(fm.res('mixin', 'make'), self)();
});
});
} else {
fm.selectfiles({files : hashes});
dfrd = $.proxy(fm.res('mixin', 'make'), self)();
}
return dfrd;
};
};
@@ -0,0 +1,23 @@
/**
* @class elFinder command "back"
* Open last visited folder
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.back = function() {
"use strict";
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.shortcuts = [{
pattern : 'ctrl+left backspace'
}];
this.getstate = function() {
return this.fm.history.canBack() ? 0 : -1;
};
this.exec = function() {
return this.fm.history.back();
};
}).prototype = { forceLoad : true }; // this is required command
@@ -0,0 +1,323 @@
/**
* @class elFinder command "chmod".
* Chmod files.
*
* @type elFinder.command
* @author Naoki Sawada
*/
elFinder.prototype.commands.chmod = function() {
"use strict";
this.updateOnSelect = false;
var fm = this.fm,
level = {
0 : 'owner',
1 : 'group',
2 : 'other'
},
msg = {
read : fm.i18n('read'),
write : fm.i18n('write'),
execute : fm.i18n('execute'),
perm : fm.i18n('perm'),
kind : fm.i18n('kind'),
files : fm.i18n('files')
},
isPerm = function(perm){
return (!isNaN(parseInt(perm, 8)) && parseInt(perm, 8) <= 511) || perm.match(/^([r-][w-][x-]){3}$/i);
};
this.tpl = {
main : '<div class="ui-helper-clearfix elfinder-info-title"><span class="elfinder-cwd-icon {class} ui-corner-all"></span>{title}</div>'
+'{dataTable}',
itemTitle : '<strong>{name}</strong><span id="elfinder-info-kind">{kind}</span>',
groupTitle : '<strong>{items}: {num}</strong>',
dataTable : '<table id="{id}-table-perm"><tr><td>{0}</td><td>{1}</td><td>{2}</td></tr></table>'
+'<div class="">'+msg.perm+': <input class="elfinder-tabstop elfinder-focus" id="{id}-perm" type="text" size="4" maxlength="3" value="{value}"></div>',
fieldset : '<fieldset id="{id}-fieldset-{level}"><legend>{f_title}{name}</legend>'
+'<input type="checkbox" value="4" class="elfinder-tabstop" id="{id}-read-{level}-perm"{checked-r}> <label for="{id}-read-{level}-perm">'+msg.read+'</label><br>'
+'<input type="checkbox" value="6" class="elfinder-tabstop" id="{id}-write-{level}-perm"{checked-w}> <label for="{id}-write-{level}-perm">'+msg.write+'</label><br>'
+'<input type="checkbox" value="5" class="elfinder-tabstop" id="{id}-execute-{level}-perm"{checked-x}> <label for="{id}-execute-{level}-perm">'+msg.execute+'</label><br>'
};
this.shortcuts = [{
//pattern : 'ctrl+p'
}];
this.getstate = function(sel) {
var fm = this.fm;
sel = sel || fm.selected();
if (sel.length == 0) {
sel = [ fm.cwd().hash ];
}
return this.checkstate(this.files(sel)) ? 0 : -1;
};
this.checkstate = function(sel) {
var cnt = sel.length,
filter = function(files) {
var fres = true;
return $.grep(sel, function(f) {
fres = fres && f.isowner && f.perm && isPerm(f.perm) && (cnt == 1 || f.mime != 'directory') ? true : false;
return fres;
});
};
return (cnt && cnt === filter(sel).length)? true : false;
};
this.exec = function(select) {
var hashes = this.hashes(select),
files = this.files(hashes);
if (! files.length) {
hashes = [ this.fm.cwd().hash ];
files = this.files(hashes);
}
var fm = this.fm,
dfrd = $.Deferred().always(function() {
fm.enable();
}),
tpl = this.tpl,
cnt = files.length,
file = files[0],
id = fm.namespace + '-perm-' + file.hash,
view = tpl.main,
checked = ' checked="checked"',
buttons = function() {
var buttons = {};
buttons[fm.i18n('btnApply')] = save;
buttons[fm.i18n('btnCancel')] = function() { dialog.elfinderdialog('close'); };
return buttons;
},
save = function() {
var perm = $.trim($('#'+id+'-perm').val()),
reqData;
if (!isPerm(perm)) return false;
dialog.elfinderdialog('close');
reqData = {
cmd : 'chmod',
targets : hashes,
mode : perm
};
fm.request({
data : reqData,
notify : {type : 'chmod', cnt : cnt}
})
.fail(function(error) {
dfrd.reject(error);
})
.done(function(data) {
if (data.changed && data.changed.length) {
data.undo = {
cmd : 'chmod',
callback : function() {
var reqs = [];
$.each(prevVals, function(perm, hashes) {
reqs.push(fm.request({
data : {cmd : 'chmod', targets : hashes, mode : perm},
notify : {type : 'undo', cnt : hashes.length}
}));
});
return $.when.apply(null, reqs);
}
};
data.redo = {
cmd : 'chmod',
callback : function() {
return fm.request({
data : reqData,
notify : {type : 'redo', cnt : hashes.length}
});
}
};
}
dfrd.resolve(data);
});
},
setperm = function() {
var perm = '';
var _perm;
for (var i = 0; i < 3; i++){
_perm = 0;
if ($("#"+id+"-read-"+level[i]+'-perm').is(':checked')) {
_perm = (_perm | 4);
}
if ($("#"+id+"-write-"+level[i]+'-perm').is(':checked')) {
_perm = (_perm | 2);
}
if ($("#"+id+"-execute-"+level[i]+'-perm').is(':checked')) {
_perm = (_perm | 1);
}
perm += _perm.toString(8);
}
$('#'+id+'-perm').val(perm);
},
setcheck = function(perm) {
var _perm;
for (var i = 0; i < 3; i++){
_perm = parseInt(perm.slice(i, i+1), 8);
$("#"+id+"-read-"+level[i]+'-perm').prop("checked", false);
$("#"+id+"-write-"+level[i]+'-perm').prop("checked", false);
$("#"+id+"-execute-"+level[i]+'-perm').prop("checked", false);
if ((_perm & 4) == 4) {
$("#"+id+"-read-"+level[i]+'-perm').prop("checked", true);
}
if ((_perm & 2) == 2) {
$("#"+id+"-write-"+level[i]+'-perm').prop("checked", true);
}
if ((_perm & 1) == 1) {
$("#"+id+"-execute-"+level[i]+'-perm').prop("checked", true);
}
}
setperm();
},
makeperm = function(files) {
var perm = '777', ret = '', chk, _chk, _perm;
var len = files.length;
for (var i2 = 0; i2 < len; i2++) {
chk = getPerm(files[i2].perm);
if (! prevVals[chk]) {
prevVals[chk] = [];
}
prevVals[chk].push(files[i2].hash);
ret = '';
for (var i = 0; i < 3; i++){
_chk = parseInt(chk.slice(i, i+1), 8);
_perm = parseInt(perm.slice(i, i+1), 8);
if ((_chk & 4) != 4 && (_perm & 4) == 4) {
_perm -= 4;
}
if ((_chk & 2) != 2 && (_perm & 2) == 2) {
_perm -= 2;
}
if ((_chk & 1) != 1 && (_perm & 1) == 1) {
_perm -= 1;
}
ret += _perm.toString(8);
}
perm = ret;
}
return perm;
},
makeName = function(name) {
return name? ':'+name : '';
},
makeDataTable = function(perm, f) {
var _perm, fieldset;
var value = '';
var dataTable = tpl.dataTable;
for (var i = 0; i < 3; i++){
_perm = parseInt(perm.slice(i, i+1), 8);
value += _perm.toString(8);
fieldset = tpl.fieldset.replace('{f_title}', fm.i18n(level[i])).replace('{name}', makeName(f[level[i]])).replace(/\{level\}/g, level[i]);
dataTable = dataTable.replace('{'+i+'}', fieldset)
.replace('{checked-r}', ((_perm & 4) == 4)? checked : '')
.replace('{checked-w}', ((_perm & 2) == 2)? checked : '')
.replace('{checked-x}', ((_perm & 1) == 1)? checked : '');
}
dataTable = dataTable.replace('{value}', value).replace('{valueCaption}', msg['perm']);
return dataTable;
},
getPerm = function(perm){
if (isNaN(parseInt(perm, 8))) {
var mode_array = perm.split('');
var a = [];
for (var i = 0, l = mode_array.length; i < l; i++) {
if (i === 0 || i === 3 || i === 6) {
if (mode_array[i].match(/[r]/i)) {
a.push(1);
} else if (mode_array[i].match(/[-]/)) {
a.push(0);
}
} else if ( i === 1 || i === 4 || i === 7) {
if (mode_array[i].match(/[w]/i)) {
a.push(1);
} else if (mode_array[i].match(/[-]/)) {
a.push(0);
}
} else {
if (mode_array[i].match(/[x]/i)) {
a.push(1);
} else if (mode_array[i].match(/[-]/)) {
a.push(0);
}
}
}
a.splice(3, 0, ",");
a.splice(7, 0, ",");
var b = a.join("");
var b_array = b.split(",");
var c = [];
for (var j = 0, m = b_array.length; j < m; j++) {
var p = parseInt(b_array[j], 2).toString(8);
c.push(p);
}
perm = c.join('');
} else {
perm = parseInt(perm, 8).toString(8);
}
return perm;
},
opts = {
title : this.title,
width : 'auto',
buttons : buttons(),
close : function() { $(this).elfinderdialog('destroy'); }
},
dialog = fm.getUI().find('#'+id),
prevVals = {},
tmb = '', title, dataTable;
if (dialog.length) {
dialog.elfinderdialog('toTop');
return $.Deferred().resolve();
}
view = view.replace('{class}', cnt > 1 ? 'elfinder-cwd-icon-group' : fm.mime2class(file.mime));
if (cnt > 1) {
title = tpl.groupTitle.replace('{items}', fm.i18n('items')).replace('{num}', cnt);
} else {
title = tpl.itemTitle.replace('{name}', file.name).replace('{kind}', fm.mime2kind(file));
tmb = fm.tmb(file);
}
dataTable = makeDataTable(makeperm(files), files.length == 1? files[0] : {});
view = view.replace('{title}', title).replace('{dataTable}', dataTable).replace(/{id}/g, id);
dialog = this.fmDialog(view, opts);
dialog.attr('id', id);
// load thumbnail
if (tmb) {
$('<img/>')
.on('load', function() { dialog.find('.elfinder-cwd-icon').addClass(tmb.className).css('background-image', "url('"+tmb.url+"')"); })
.attr('src', tmb.url);
}
$('#' + id + '-table-perm :checkbox').on('click', function(){setperm('perm');});
$('#' + id + '-perm').on('keydown', function(e) {
var c = e.keyCode;
if (c == $.ui.keyCode.ENTER) {
e.stopPropagation();
save();
return;
}
}).on('focus', function(e){
$(this).trigger('select');
}).on('keyup', function(e) {
if ($(this).val().length == 3) {
$(this).trigger('select');
setcheck($(this).val());
}
});
return dfrd;
};
};
@@ -0,0 +1,21 @@
/**
* @class elFinder command "colwidth"
* CWD list table columns width to auto
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.colwidth = function() {
"use strict";
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.getstate = function() {
return this.fm.getUI('cwd').find('table').css('table-layout') === 'fixed' ? 0 : -1;
};
this.exec = function() {
this.fm.getUI('cwd').trigger('colwidth');
return $.Deferred().resolve();
};
};
@@ -0,0 +1,44 @@
/**
* @class elFinder command "copy".
* Put files in filemanager clipboard.
*
* @type elFinder.command
* @author Dmitry (dio) Levashov
*/
elFinder.prototype.commands.copy = function() {
"use strict";
this.shortcuts = [{
pattern : 'ctrl+c ctrl+insert'
}];
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length,
filter = function(files) {
var fres = true;
return $.grep(files, function(f) {
fres = fres && f.read ? true : false;
return fres;
});
};
return cnt && filter(sel).length == cnt ? 0 : -1;
};
this.exec = function(hashes) {
var fm = this.fm,
dfrd = $.Deferred()
.fail(function(error) {
fm.error(error);
});
$.each(this.files(hashes), function(i, file) {
if (! file.read) {
return !dfrd.reject(['errCopy', file.name, 'errPerm']);
}
});
return dfrd.state() == 'rejected' ? dfrd : dfrd.resolve(fm.clipboard(this.hashes(hashes)));
};
};
@@ -0,0 +1,48 @@
/**
* @class elFinder command "copy".
* Put files in filemanager clipboard.
*
* @type elFinder.command
* @author Dmitry (dio) Levashov
*/
elFinder.prototype.commands.cut = function() {
"use strict";
var fm = this.fm;
this.shortcuts = [{
pattern : 'ctrl+x shift+insert'
}];
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length,
filter = function(files) {
var fres = true;
return $.grep(files, function(f) {
fres = fres && f.read && ! f.locked && ! fm.isRoot(f) ? true : false;
return fres;
});
};
return cnt && filter(sel).length == cnt ? 0 : -1;
};
this.exec = function(hashes) {
var dfrd = $.Deferred()
.fail(function(error) {
fm.error(error);
});
$.each(this.files(hashes), function(i, file) {
if (!(file.read && ! file.locked && ! fm.isRoot(file)) ) {
return !dfrd.reject(['errCopy', file.name, 'errPerm']);
}
if (file.locked) {
return !dfrd.reject(['errLocked', file.name]);
}
});
return dfrd.state() == 'rejected' ? dfrd : dfrd.resolve(fm.clipboard(this.hashes(hashes), true));
};
};
@@ -0,0 +1,466 @@
/**
* @class elFinder command "download".
* Download selected files.
* Only for new api
*
* @author Dmitry (dio) Levashov, dio@std42.ru
**/
elFinder.prototype.commands.zipdl = function() {};
elFinder.prototype.commands.download = function() {
"use strict";
var self = this,
fm = this.fm,
czipdl = null,
zipOn = false,
mixed = false,
dlntf = false,
cpath = window.location.pathname || '/',
filter = function(hashes, inExec) {
var volumeid, mixedCmd;
if (czipdl !== null) {
if (fm.searchStatus.state > 1) {
mixed = fm.searchStatus.mixed;
} else if (fm.leafRoots[fm.cwd().hash]) {
volumeid = fm.cwd().volumeid;
$.each(hashes, function(i, h) {
if (h.indexOf(volumeid) !== 0) {
mixed = true;
return false;
}
});
}
zipOn = (fm.isCommandEnabled('zipdl', hashes[0]));
}
if (mixed) {
mixedCmd = czipdl? 'zipdl' : 'download';
hashes = $.grep(hashes, function(h) {
var f = fm.file(h),
res = (! f || (! czipdl && f.mime === 'directory') || ! fm.isCommandEnabled(mixedCmd, h))? false : true;
if (f && inExec && ! res) {
fm.cwdHash2Elm(f.hash).trigger('unselect');
}
return res;
});
if (! hashes.length) {
return [];
}
} else {
if (!fm.isCommandEnabled('download', hashes[0])) {
return [];
}
}
return $.grep(self.files(hashes), function(f) {
var res = (! f.read || (! zipOn && f.mime == 'directory')) ? false : true;
if (inExec && ! res) {
fm.cwdHash2Elm(f.hash).trigger('unselect');
}
return res;
});
};
this.linkedCmds = ['zipdl'];
this.shortcuts = [{
pattern : 'shift+enter'
}];
this.getstate = function(select) {
var sel = this.hashes(select),
cnt = sel.length,
maxReq = this.options.maxRequests || 10,
mixed = false,
croot = '';
if (cnt < 1) {
return -1;
}
cnt = filter(sel).length;
return (cnt && (zipOn || (cnt <= maxReq && ((!fm.UA.IE && !fm.UA.Mobile) || cnt == 1))) ? 0 : -1);
};
fm.bind('contextmenu', function(e){
var fm = self.fm,
helper = null,
targets, file, link,
getExtra = function(file) {
var link = file.url || fm.url(file.hash);
return {
icon: 'link',
node: $('<a></a>')
.attr({href: link, target: '_blank', title: fm.i18n('link')})
.text(file.name)
.on('mousedown click touchstart touchmove touchend contextmenu', function(e){
e.stopPropagation();
})
.on('dragstart', function(e) {
var dt = e.dataTransfer || e.originalEvent.dataTransfer || null;
helper = null;
if (dt) {
var icon = function(f) {
var mime = f.mime, i, tmb = fm.tmb(f);
i = '<div class="elfinder-cwd-icon '+fm.mime2class(mime)+' ui-corner-all"></div>';
if (tmb) {
i = $(i).addClass(tmb.className).css('background-image', "url('"+tmb.url+"')").get(0).outerHTML;
}
return i;
};
dt.effectAllowed = 'copyLink';
if (dt.setDragImage) {
helper = $('<div class="elfinder-drag-helper html5-native">').append(icon(file)).appendTo($(document.body));
dt.setDragImage(helper.get(0), 50, 47);
}
if (!fm.UA.IE) {
dt.setData('elfinderfrom', window.location.href + file.phash);
dt.setData('elfinderfrom:' + dt.getData('elfinderfrom'), '');
}
}
})
.on('dragend', function(e) {
helper && helper.remove();
})
};
};
self.extra = null;
if (e.data) {
targets = e.data.targets || [];
if (targets.length === 1 && (file = fm.file(targets[0])) && file.mime !== 'directory') {
if (file.url != '1') {
self.extra = getExtra(file);
} else {
// Get URL ondemand
var node;
self.extra = {
icon: 'link',
node: $('<a></a>')
.attr({href: '#', title: fm.i18n('getLink'), draggable: 'false'})
.text(file.name)
.on('click touchstart', function(e){
if (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
return;
}
var parent = node.parent();
e.stopPropagation();
e.preventDefault();
parent.removeClass('ui-state-disabled').addClass('elfinder-button-icon-spinner');
fm.request({
data : {cmd : 'url', target : file.hash},
preventDefault : true
})
.always(function(data) {
parent.removeClass('elfinder-button-icon-spinner');
if (data.url) {
var rfile = fm.file(file.hash);
rfile.url = data.url;
node.replaceWith(getExtra(file).node);
} else {
parent.addClass('ui-state-disabled');
}
});
})
};
node = self.extra.node;
node.ready(function(){
requestAnimationFrame(function(){
node.parent().addClass('ui-state-disabled').css('pointer-events', 'auto');
});
});
}
}
}
}).one('open', function() {
if (fm.api >= 2.1012) {
czipdl = fm.getCommand('zipdl');
}
dlntf = fm.cookieEnabled && fm.api > 2.1038 && !fm.isCORS;
});
this.exec = function(select) {
var hashes = this.hashes(select),
fm = this.fm,
base = fm.options.url,
files = filter(hashes, true),
dfrd = $.Deferred(),
iframes = '',
cdata = '',
targets = {},
i, url,
linkdl = false,
getTask = function(hashes) {
return function() {
var dfd = $.Deferred(),
root = fm.file(fm.root(hashes[0])),
single = (hashes.length === 1),
volName = root? (root.i18 || root.name) : null,
dir, dlName, phash;
if (single) {
if (dir = fm.file(hashes[0])) {
dlName = (dir.i18 || dir.name);
}
} else {
$.each(hashes, function() {
var d = fm.file(this);
if (d && (!phash || phash === d.phash)) {
phash = d.phash;
} else {
phash = null;
return false;
}
});
if (phash && (dir = fm.file(phash))) {
dlName = (dir.i18 || dir.name) + '-' + hashes.length;
}
}
if (dlName) {
volName = dlName;
}
volName && (volName = ' (' + volName + ')');
fm.request({
data : {cmd : 'zipdl', targets : hashes},
notify : {type : 'zipdl', cnt : 1, hideCnt : true, msg : fm.i18n('ntfzipdl') + volName},
cancel : true,
eachCancel : true,
preventDefault : true
}).done(function(e) {
var zipdl, dialog, btn = {}, dllink, form, iframe, m,
uniq = 'dlw' + (+new Date()),
zipdlFn = function(url) {
dllink = $('<a></a>')
.attr('href', url)
.attr('download', fm.escape(dlName))
.on('click', function() {
dfd.resolve();
dialog && dialog.elfinderdialog('destroy');
});
if (linkdl) {
dllink.attr('target', '_blank')
.append('<span class="elfinder-button-icon elfinder-button-icon-download"></span>'+fm.escape(dlName));
btn[fm.i18n('btnCancel')] = function() {
dialog.elfinderdialog('destroy');
};
dialog = self.fmDialog(dllink, {
title: fm.i18n('link'),
buttons: btn,
width: '200px',
destroyOnClose: true,
close: function() {
(dfd.state() !== 'resolved') && dfd.resolve();
}
});
} else {
click(dllink.hide().appendTo('body').get(0));
dllink.remove();
}
};
if (e.error) {
fm.error(e.error);
dfd.resolve();
} else if (e.zipdl) {
zipdl = e.zipdl;
if (dlName) {
m = fm.splitFileExtention(zipdl.name || '');
dlName += m[1]? ('.' + m[1]) : '.zip';
} else {
dlName = zipdl.name;
}
if (html5dl || linkdl) {
url = fm.options.url + (fm.options.url.indexOf('?') === -1 ? '?' : '&')
+ 'cmd=zipdl&download=1';
$.each([hashes[0], zipdl.file, dlName, zipdl.mime], function(key, val) {
url += '&targets%5B%5D='+encodeURIComponent(val);
});
$.each(fm.customData, function(key, val) {
url += '&'+encodeURIComponent(key)+'='+encodeURIComponent(val);
});
url += '&'+encodeURIComponent(dlName);
if (fm.hasParrotHeaders()) {
fm.getBinaryByUrl({url: url}, function(blob) {
if (blob instanceof Blob) {
url = (window.URL || window.webkitURL).createObjectURL(blob);
zipdlFn(url);
} else {
fm.error(['errUploadTransfer', fm.i18n('kindZIP')]);
}
});
} else {
zipdlFn(url);
}
} else {
form = $('<form action="'+fm.options.url+'" method="post" target="'+uniq+'" style="display:none"></form>')
.append('<input type="hidden" name="cmd" value="zipdl"/>')
.append('<input type="hidden" name="download" value="1"/>');
$.each([hashes[0], zipdl.file, dlName, zipdl.mime], function(key, val) {
form.append('<input type="hidden" name="targets[]" value="'+fm.escape(val)+'"/>');
});
$.each(fm.customData, function(key, val) {
form.append('<input type="hidden" name="'+key+'" value="'+fm.escape(val)+'"/>');
});
form.attr('target', uniq).appendTo('body');
iframe = $('<iframe style="display:none" name="'+uniq+'">')
.appendTo('body')
.ready(function() {
form.submit().remove();
dfd.resolve();
setTimeout(function() {
iframe.remove();
}, 20000); // give 20 sec file to be saved
});
}
}
}).fail(function(error) {
error && fm.error(error);
dfd.resolve();
});
return dfd.promise();
};
},
// use MouseEvent to click element for Safari etc
click = function(a) {
var clickEv;
if (typeof MouseEvent === 'function') {
clickEv = new MouseEvent('click');
} else {
clickEv = document.createEvent('MouseEvents');
clickEv.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
}
fm.pauseUnloadCheck(true);
a.dispatchEvent(clickEv);
},
checkCookie = function(id) {
var name = 'elfdl' + id,
parts;
parts = document.cookie.split(name + "=");
if (parts.length === 2) {
ntftm && clearTimeout(ntftm);
document.cookie = name + '=; path=' + cpath + '; max-age=0';
closeNotify();
} else {
setTimeout(function() { checkCookie(id); }, 200);
}
},
closeNotify = function() {
if (fm.ui.notify.children('.elfinder-notify-download').length) {
fm.notify({
type : 'download',
cnt : -1
});
}
},
reqids = [],
link, html5dl, fileCnt, clickEv, cid, ntftm, reqid, getUrlDfrd, urls;
if (!files.length) {
return dfrd.reject();
}
fileCnt = $.grep(files, function(f) { return f.mime === 'directory'? false : true; }).length;
link = $('<a>').hide().appendTo('body');
html5dl = (typeof link.get(0).download === 'string');
if (zipOn && (fileCnt !== files.length || fileCnt >= (this.options.minFilesZipdl || 1))) {
link.remove();
linkdl = (!html5dl && fm.UA.Mobile);
if (mixed) {
targets = {};
$.each(files, function(i, f) {
var p = f.hash.split('_', 2);
if (! targets[p[0]]) {
targets[p[0]] = [ f.hash ];
} else {
targets[p[0]].push(f.hash);
}
});
if (!linkdl && fm.UA.Mobile && Object.keys(targets).length > 1) {
linkdl = true;
}
} else {
targets = [ $.map(files, function(f) { return f.hash; }) ];
}
dfrd = fm.sequence($.map(targets, function(t) { return getTask(t); })).always(
function() {
fm.trigger('download', {files : files});
}
);
return dfrd;
} else {
reqids = [];
getUrlDfrd = $.Deferred().done(function(urls) {
for (i = 0; i < urls.length; i++) {
url = urls[i];
if (dlntf && url.substr(0, fm.options.url.length) === fm.options.url) {
reqid = fm.getRequestId();
reqids.push(reqid);
url += '&cpath=' + cpath + '&reqid=' + reqid;
ntftm = setTimeout(function() {
fm.notify({
type : 'download',
cnt : 1,
cancel : (fm.UA.IE || fm.UA.Edge)? void(0) : function() {
if (reqids.length) {
$.each(reqids, function() {
fm.request({
data: {
cmd: 'abort',
id: this
},
preventDefault: true
});
});
}
reqids = [];
}
});
}, fm.notifyDelay);
checkCookie(reqid);
}
if (html5dl) {
click(link.attr('href', url)
.attr('download', fm.escape(files[i].name))
.get(0)
);
} else {
if (fm.UA.Mobile) {
setTimeout(function(){
if (! window.open(url)) {
fm.error('errPopup');
ntftm && cleaerTimeout(ntftm);
closeNotify();
}
}, 100);
} else {
iframes += '<iframe class="downloader" id="downloader-' + files[i].hash+'" style="display:none" src="'+url+'"></iframe>';
}
}
}
link.remove();
$(iframes)
.appendTo('body')
.ready(function() {
setTimeout(function() {
$(iframes).each(function() {
$('#' + $(this).attr('id')).remove();
});
}, 20000 + (10000 * i)); // give 20 sec + 10 sec for each file to be saved
});
fm.trigger('download', {files : files});
dfrd.resolve();
});
fileCnt = files.length;
urls = [];
for (i = 0; i < files.length; i++) {
fm.openUrl(files[i].hash, true, function(v) {
v && urls.push(v);
if (--fileCnt < 1) {
getUrlDfrd.resolve(urls);
}
});
}
return dfrd;
}
};
};
@@ -0,0 +1,62 @@
/**
* @class elFinder command "duplicate"
* Create file/folder copy with suffix "copy Number"
*
* @type elFinder.command
* @author Dmitry (dio) Levashov
*/
elFinder.prototype.commands.duplicate = function() {
"use strict";
var fm = this.fm;
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length,
filter = function(files) {
var fres = true;
return $.grep(files, function(f) {
fres = fres && f.read && f.phash === fm.cwd().hash && ! fm.isRoot(f)? true : false;
return fres;
});
};
return cnt && fm.cwd().write && filter(sel).length == cnt ? 0 : -1;
};
this.exec = function(hashes) {
var fm = this.fm,
files = this.files(hashes),
cnt = files.length,
dfrd = $.Deferred()
.fail(function(error) {
error && fm.error(error);
}),
args = [];
if (! cnt) {
return dfrd.reject();
}
$.each(files, function(i, file) {
if (!file.read || !fm.file(file.phash).write) {
return !dfrd.reject(['errCopy', file.name, 'errPerm']);
}
});
if (dfrd.state() == 'rejected') {
return dfrd;
}
return fm.request({
data : {cmd : 'duplicate', targets : this.hashes(hashes)},
notify : {type : 'copy', cnt : cnt},
navigate : {
toast : {
inbuffer : {msg: fm.i18n(['complete', fm.i18n('cmdduplicate')])}
}
}
});
};
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,126 @@
/**
* @class elFinder command "empty".
* Empty the folder
*
* @type elFinder.command
* @author Naoki Sawada
*/
elFinder.prototype.commands.empty = function() {
"use strict";
var self, fm,
selFiles = function(select) {
var sel = self.files(select);
if (!sel.length) {
sel = [ fm.cwd() ];
}
return sel;
};
this.linkedCmds = ['rm'];
this.init = function() {
// lazy assign to make possible to become superclass
self = this;
fm = this.fm;
};
this.getstate = function(select) {
var sel = selFiles(select),
cnt,
filter = function(files) {
var fres = true;
return $.grep(files, function(f) {
fres = fres && f.read && f.write && f.mime === 'directory' ? true : false;
return fres;
});
};
cnt = sel.length;
return filter(sel).length == cnt ? 0 : -1;
};
this.exec = function(hashes) {
var dirs = selFiles(hashes),
cnt = dirs.length,
dfrd = $.Deferred()
.done(function() {
var data = {changed: {}};
fm.toast({msg: fm.i18n(['"'+success.join('", ')+'"', 'complete', fm.i18n('cmdempty')])});
$.each(dirs, function(i, dir) {
data.changed[dir.hash] = dir;
});
fm.change(data);
})
.always(function() {
var cwd = fm.cwd().hash;
fm.trigger('selectfiles', {files: $.map(dirs, function(d) { return cwd === d.phash? d.hash : null; })});
}),
success = [],
done = function(res) {
if (typeof res === 'number') {
success.push(dirs[res].name);
delete dirs[res].dirs;
} else {
res && fm.error(res);
}
(--cnt < 1) && dfrd[success.length? 'resolve' : 'reject']();
};
$.each(dirs, function(i, dir) {
var tm;
if (!(dir.write && dir.mime === 'directory')) {
done(['errEmpty', dir.name, 'errPerm']);
return null;
}
if (!fm.isCommandEnabled('rm', dir.hash)) {
done(['errCmdNoSupport', '"rm"']);
return null;
}
tm = setTimeout(function() {
fm.notify({type : 'search', cnt : 1, hideCnt : cnt > 1? false : true});
}, fm.notifyDelay);
fm.request({
data : {cmd : 'open', target : dir.hash},
preventDefault : true,
asNotOpen : true
}).done(function(data) {
var targets = [];
tm && clearTimeout(tm);
if (fm.ui.notify.children('.elfinder-notify-search').length) {
fm.notify({type : 'search', cnt : -1, hideCnt : cnt > 1? false : true});
}
if (data && data.files && data.files.length) {
if (data.files.length > fm.maxTargets) {
done(['errEmpty', dir.name, 'errMaxTargets', fm.maxTargets]);
} else {
fm.updateCache(data);
$.each(data.files, function(i, f) {
if (!f.write || f.locked) {
done(['errEmpty', dir.name, 'errRm', f.name, 'errPerm']);
targets = [];
return false;
}
targets.push(f.hash);
});
if (targets.length) {
fm.exec('rm', targets, { _userAction : true, addTexts : [ fm.i18n('folderToEmpty', dir.name) ] })
.fail(function(error) {
fm.trigger('unselectfiles', {files: fm.selected()});
done(fm.parseError(error) || '');
})
.done(function() { done(i); });
}
}
} else {
fm.toast({ mode: 'warning', msg: fm.i18n('filderIsEmpty', dir.name)});
done('');
}
}).fail(function(error) {
done(fm.parseError(error) || '');
});
});
return dfrd;
};
};
@@ -0,0 +1,225 @@
/**
* @class elFinder command "extract"
* Extract files from archive
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.extract = function() {
"use strict";
var self = this,
fm = self.fm,
mimes = [],
filter = function(files) {
var fres = true;
return $.grep(files, function(file) {
fres = fres && file.read && $.inArray(file.mime, mimes) !== -1 ? true : false;
return fres;
});
};
this.variants = [];
this.disableOnSearch = true;
// Update mimes list on open/reload
fm.bind('open reload', function() {
mimes = fm.option('archivers')['extract'] || [];
if (fm.api > 2) {
self.variants = [[{makedir: true}, fm.i18n('cmdmkdir')], [{}, fm.i18n('btnCwd')]];
} else {
self.variants = [[{}, fm.i18n('btnCwd')]];
}
self.change();
});
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length,
cwdHash, cwdChk;
if (!cnt || filter(sel).length != cnt) {
return -1;
} else if (fm.searchStatus.state > 0) {
cwdHash = this.fm.cwd().hash;
$.each(sel, function(i, file) {
cwdChk = (file.phash === cwdHash);
return cwdChk;
});
return cwdChk? 0 : -1;
} else {
return this.fm.cwd().write? 0 : -1;
}
};
this.exec = function(hashes, opts) {
var files = this.files(hashes),
dfrd = $.Deferred(),
cnt = files.length,
makedir = opts && opts.makedir ? 1 : 0,
i, error,
decision,
overwriteAll = false,
omitAll = false,
mkdirAll = 0,
siblings = fm.files(files[0].phash),
names = [],
map = {};
$.each(siblings, function(id, file) {
map[file.name] = file;
names.push(file.name);
});
var decide = function(decision) {
switch (decision) {
case 'overwrite_all' :
overwriteAll = true;
break;
case 'omit_all':
omitAll = true;
break;
}
};
var unpack = function(file) {
if (!(file.read && fm.file(file.phash).write)) {
error = ['errExtract', file.name, 'errPerm'];
fm.error(error);
dfrd.reject(error);
} else if ($.inArray(file.mime, mimes) === -1) {
error = ['errExtract', file.name, 'errNoArchive'];
fm.error(error);
dfrd.reject(error);
} else {
fm.request({
data:{cmd:'extract', target:file.hash, makedir:makedir},
notify:{type:'extract', cnt:1},
syncOnFail:true,
navigate:{
toast : makedir? {
incwd : {msg: fm.i18n(['complete', fm.i18n('cmdextract')]), action: {cmd: 'open', msg: 'cmdopen'}},
inbuffer : {msg: fm.i18n(['complete', fm.i18n('cmdextract')]), action: {cmd: 'open', msg: 'cmdopen'}}
} : {
inbuffer : {msg: fm.i18n(['complete', fm.i18n('cmdextract')])}
}
}
})
.fail(function (error) {
if (dfrd.state() != 'rejected') {
dfrd.reject(error);
}
})
.done(function () {
});
}
};
var confirm = function(files, index) {
var file = files[index],
name = fm.splitFileExtention(file.name)[0],
existed = ($.inArray(name, names) >= 0),
next = function(){
if((index+1) < cnt) {
confirm(files, index+1);
} else {
dfrd.resolve();
}
};
if (!makedir && existed && map[name].mime != 'directory') {
fm.confirm(
{
title : fm.i18n('ntfextract'),
text : ['errExists', name, 'confirmRepl'],
accept:{
label : 'btnYes',
callback:function (all) {
decision = all ? 'overwrite_all' : 'overwrite';
decide(decision);
if(!overwriteAll && !omitAll) {
if('overwrite' == decision) {
unpack(file);
}
if((index+1) < cnt) {
confirm(files, index+1);
} else {
dfrd.resolve();
}
} else if(overwriteAll) {
for (i = index; i < cnt; i++) {
unpack(files[i]);
}
dfrd.resolve();
}
}
},
reject : {
label : 'btnNo',
callback:function (all) {
decision = all ? 'omit_all' : 'omit';
decide(decision);
if(!overwriteAll && !omitAll && (index+1) < cnt) {
confirm(files, index+1);
} else if (omitAll) {
dfrd.resolve();
}
}
},
cancel : {
label : 'btnCancel',
callback:function () {
dfrd.resolve();
}
},
all : ((index+1) < cnt)
}
);
} else if (!makedir) {
if (mkdirAll == 0) {
fm.confirm({
title : fm.i18n('cmdextract'),
text : [fm.i18n('cmdextract')+' "'+file.name+'"', 'confirmRepl'],
accept:{
label : 'btnYes',
callback:function (all) {
all && (mkdirAll = 1);
unpack(file);
next();
}
},
reject : {
label : 'btnNo',
callback:function (all) {
all && (mkdirAll = -1);
next();
}
},
cancel : {
label : 'btnCancel',
callback:function () {
dfrd.resolve();
}
},
all : ((index+1) < cnt)
});
} else {
(mkdirAll > 0) && unpack(file);
next();
}
} else {
unpack(file);
next();
}
};
if (!(this.enabled() && cnt && mimes.length)) {
return dfrd.reject();
}
if(cnt > 0) {
confirm(files, 0);
}
return dfrd;
};
};
@@ -0,0 +1,23 @@
/**
* @class elFinder command "forward"
* Open next visited folder
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.forward = function() {
"use strict";
this.alwaysEnabled = true;
this.updateOnSelect = true;
this.shortcuts = [{
pattern : 'ctrl+right'
}];
this.getstate = function() {
return this.fm.history.canForward() ? 0 : -1;
};
this.exec = function() {
return this.fm.history.forward();
};
}).prototype = { forceLoad : true }; // this is required command
@@ -0,0 +1,47 @@
/**
* @class elFinder command "fullscreen"
* elFinder node to full scrren mode
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.fullscreen = function() {
"use strict";
var self = this,
fm = this.fm,
update = function(e, data) {
var full;
e.preventDefault();
e.stopPropagation();
if (data && data.fullscreen) {
full = (data.fullscreen === 'on');
self.update(void(0), full);
self.title = fm.i18n(full ? 'reinstate' : 'cmdfullscreen');
}
};
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.syncTitleOnChange = true;
this.value = false;
this.options = {
ui : 'fullscreenbutton'
};
this.getstate = function() {
return 0;
};
this.exec = function() {
var node = fm.getUI().get(0),
full = (node === fm.toggleFullscreen(node));
self.title = fm.i18n(full ? 'reinstate' : 'cmdfullscreen');
self.update(void(0), full);
return $.Deferred().resolve();
};
fm.bind('init', function() {
fm.getUI().off('resize.' + fm.namespace, update).on('resize.' + fm.namespace, update);
});
};
@@ -0,0 +1,164 @@
/**
* @class elFinder command "getfile".
* Return selected files info into outer callback.
* For use elFinder with wysiwyg editors etc.
*
* @author Dmitry (dio) Levashov, dio@std42.ru
**/
(elFinder.prototype.commands.getfile = function() {
"use strict";
var self = this,
fm = this.fm,
filter = function(files) {
var o = self.options,
fres = true;
files = $.grep(files, function(file) {
fres = fres && (file.mime != 'directory' || o.folders) && file.read ? true : false;
return fres;
});
return o.multiple || files.length == 1 ? files : [];
};
this.alwaysEnabled = true;
this.callback = fm.options.getFileCallback;
this._disabled = typeof(this.callback) == 'function';
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length;
return this.callback && cnt && filter(sel).length == cnt ? 0 : -1;
};
this.exec = function(hashes) {
var fm = this.fm,
opts = this.options,
files = this.files(hashes),
cnt = files.length,
url = fm.option('url'),
tmb = fm.option('tmbUrl'),
dfrd = $.Deferred()
.done(function(data) {
var res,
done = function() {
if (opts.oncomplete == 'close') {
fm.hide();
} else if (opts.oncomplete == 'destroy') {
fm.destroy();
}
},
fail = function(error) {
if (opts.onerror == 'close') {
fm.hide();
} else if (opts.onerror == 'destroy') {
fm.destroy();
} else {
error && fm.error(error);
}
};
fm.trigger('getfile', {files : data});
try {
res = self.callback(data, fm);
} catch(e) {
fail(['Error in `getFileCallback`.', e.message]);
return;
}
if (typeof res === 'object' && typeof res.done === 'function') {
res.done(done).fail(fail);
} else {
done();
}
}),
result = function(file) {
return opts.onlyURL
? opts.multiple ? $.map(files, function(f) { return f.url; }) : files[0].url
: opts.multiple ? files : files[0];
},
req = [],
i, file, dim;
for (i = 0; i < cnt; i++) {
file = files[i];
if (file.mime == 'directory' && !opts.folders) {
return dfrd.reject();
}
file.baseUrl = url;
if (file.url == '1') {
req.push(fm.request({
data : {cmd : 'url', target : file.hash},
notify : {type : 'url', cnt : 1, hideCnt : true},
preventDefault : true
})
.done(function(data) {
if (data.url) {
var rfile = fm.file(this.hash);
rfile.url = this.url = data.url;
}
}.bind(file)));
} else {
file.url = fm.url(file.hash);
}
if (! opts.onlyURL) {
if (opts.getPath) {
file.path = fm.path(file.hash);
if (file.path === '' && file.phash) {
// get parents
(function() {
var dfd = $.Deferred();
req.push(dfd);
fm.path(file.hash, false, {})
.done(function(path) {
file.path = path;
})
.fail(function() {
file.path = '';
})
.always(function() {
dfd.resolve();
});
})();
}
}
if (file.tmb && file.tmb != 1) {
file.tmb = tmb + file.tmb;
}
if (!file.width && !file.height) {
if (file.dim) {
dim = file.dim.split('x');
file.width = dim[0];
file.height = dim[1];
} else if (opts.getImgSize && file.mime.indexOf('image') !== -1) {
req.push(fm.request({
data : {cmd : 'dim', target : file.hash},
notify : {type : 'dim', cnt : 1, hideCnt : true},
preventDefault : true
})
.done(function(data) {
if (data.dim) {
var dim = data.dim.split('x');
var rfile = fm.file(this.hash);
rfile.width = this.width = dim[0];
rfile.height = this.height = dim[1];
}
}.bind(file)));
}
}
}
}
if (req.length) {
$.when.apply(null, req).always(function() {
dfrd.resolve(result(files));
});
return dfrd;
}
return dfrd.resolve(result(files));
};
}).prototype = { forceLoad : true }; // this is required command
@@ -0,0 +1,414 @@
/**
* @class elFinder command "help"
* "About" dialog
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.help = function() {
"use strict";
var fm = this.fm,
self = this,
linktpl = '<div class="elfinder-help-link"> <a href="{url}">{link}</a></div>',
linktpltgt = '<div class="elfinder-help-link"> <a href="{url}" target="_blank">{link}</a></div>',
atpl = '<div class="elfinder-help-team"><div>{author}</div>{work}</div>',
url = /\{url\}/,
link = /\{link\}/,
author = /\{author\}/,
work = /\{work\}/,
r = 'replace',
prim = 'ui-priority-primary',
sec = 'ui-priority-secondary',
lic = 'elfinder-help-license',
tab = '<li class="' + fm.res('class', 'tabstab') + ' elfinder-help-tab-{id}"><a href="#'+fm.namespace+'-help-{id}" class="ui-tabs-anchor">{title}</a></li>',
html = ['<div class="ui-tabs ui-widget ui-widget-content ui-corner-all elfinder-help">',
'<ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-top">'],
stpl = '<div class="elfinder-help-shortcut"><div class="elfinder-help-shortcut-pattern">{pattern}</div> {descrip}</div>',
sep = '<div class="elfinder-help-separator"></div>',
selfUrl = $('base').length? fm.escape(document.location.href.replace(/#.*$/, '')) : '',
clTabActive = fm.res('class', 'tabsactive'),
getTheme = function() {
var src;
if (fm.theme && fm.theme.author) {
src = atpl[r]('elfinder-help-team', 'elfinder-help-team elfinder-help-term-theme')[r](author, fm.i18n(fm.theme.author) + (fm.theme.email? ' &lt;'+fm.theme.email+'&gt;' : ''))[r](work, fm.i18n('theme') + ' ('+fm.i18n(fm.theme.name)+')');
} else {
src = '<div class="elfinder-help-team elfinder-help-term-theme" style="display:none"></div>';
}
return src;
},
about = function() {
html.push('<div id="'+fm.namespace+'-help-about" class="ui-tabs-panel ui-widget-content ui-corner-bottom"><div class="elfinder-help-logo"></div>');
html.push('<h3>elFinder</h3>');
html.push('<div class="'+prim+'">'+fm.i18n('webfm')+'</div>');
html.push('<div class="'+sec+'">'+fm.i18n('ver')+': '+fm.version+'</div>');
html.push('<div class="'+sec+'">'+fm.i18n('protocolver')+': <span class="apiver"></span></div>');
html.push('<div class="'+sec+'">jQuery/jQuery UI: '+$().jquery+'/'+$.ui.version+'</div>');
html.push(sep);
html.push(linktpltgt[r](url, 'https://studio-42.github.io/elFinder/')[r](link, fm.i18n('homepage')));
html.push(linktpltgt[r](url, 'https://github.com/Studio-42/elFinder/wiki')[r](link, fm.i18n('docs')));
html.push(linktpltgt[r](url, 'https://github.com/Studio-42/elFinder')[r](link, fm.i18n('github')));
//html.push(linktpltgt[r](url, 'http://twitter.com/elrte_elfinder')[r](link, fm.i18n('twitter')));
html.push(sep);
html.push('<div class="'+prim+'">'+fm.i18n('team')+'</div>');
html.push(atpl[r](author, 'Dmitry "dio" Levashov &lt;dio@std42.ru&gt;')[r](work, fm.i18n('chiefdev')));
html.push(atpl[r](author, 'Naoki Sawada (nao-pon)&lt;hypweb+elfinder@gmail.com&gt;')[r](work, fm.i18n('developer')));
html.push(atpl[r](author, 'Troex Nevelin &lt;troex@fury.scancode.ru&gt;')[r](work, fm.i18n('maintainer')));
html.push(atpl[r](author, 'Alexey Sukhotin &lt;strogg@yandex.ru&gt;')[r](work, fm.i18n('contributor')));
if (fm.i18[fm.lang].translator) {
$.each(fm.i18[fm.lang].translator.split(', '), function() {
html.push(atpl[r](author, $.trim(this))[r](work, fm.i18n('translator')+' ('+fm.i18[fm.lang].language+')'));
});
}
html.push(getTheme());
html.push(sep);
html.push('<div class="'+lic+'">'+fm.i18n('icons')+': Pixelmixer, <a href="http://p.yusukekamiyamane.com" target="_blank">Fugue</a>, <a href="https://icons8.com" target="_blank">Icons8</a></div>');
html.push(sep);
html.push('<div class="'+lic+'">Licence: 3-clauses BSD Licence</div>');
html.push('<div class="'+lic+'">Copyright © 2009-2022, Studio 42 / nao-pon</div>');
html.push('<div class="'+lic+'">„ …'+fm.i18n('dontforget')+' ”</div>');
html.push('</div>');
},
shortcuts = function() {
var sh = fm.shortcuts();
// shortcuts tab
html.push('<div id="'+fm.namespace+'-help-shortcuts" class="ui-tabs-panel ui-widget-content ui-corner-bottom">');
if (sh.length) {
html.push('<div class="ui-widget-content elfinder-help-shortcuts">');
$.each(sh, function(i, s) {
html.push(stpl.replace(/\{pattern\}/, s[0]).replace(/\{descrip\}/, s[1]));
});
html.push('</div>');
} else {
html.push('<div class="elfinder-help-disabled">'+fm.i18n('shortcutsof')+'</div>');
}
html.push('</div>');
},
help = function() {
// help tab
html.push('<div id="'+fm.namespace+'-help-help" class="ui-tabs-panel ui-widget-content ui-corner-bottom">');
html.push('<a href="https://github.com/Studio-42/elFinder/wiki" target="_blank" class="elfinder-dont-panic"><span>DON\'T PANIC</span></a>');
html.push('</div>');
// end help
},
useInteg = false,
integrations = function() {
useInteg = true;
html.push('<div id="'+fm.namespace+'-help-integrations" class="ui-tabs-panel ui-widget-content ui-corner-bottom"></div>');
},
useDebug = false,
debug = function() {
useDebug = true;
// debug tab
html.push('<div id="'+fm.namespace+'-help-debug" class="ui-tabs-panel ui-widget-content ui-corner-bottom">');
html.push('<div class="ui-widget-content elfinder-help-debug"><ul></ul></div>');
html.push('</div>');
// end debug
},
debugRender = function() {
var render = function(elm, obj) {
$.each(obj, function(k, v) {
elm.append($('<dt></dt>').text(k));
if (typeof v === 'undefined') {
elm.append($('<dd></dd>').append($('<span></span>').text('undfined')));
} else if (typeof v === 'object' && !v) {
elm.append($('<dd></dd>').append($('<span></span>').text('null')));
} else if (typeof v === 'object' && ($.isPlainObject(v) || v.length)) {
elm.append( $('<dd></dd>').append(render($('<dl></dl>'), v)));
} else {
elm.append($('<dd></dd>').append($('<span></span>').text((v && typeof v === 'object')? '[]' : (v? v : '""'))));
}
});
return elm;
},
cnt = debugUL.children('li').length,
targetL, target, tabId,
info, lastUL, lastDIV;
if (self.debug.options || self.debug.debug) {
if (cnt >= 5) {
lastUL = debugUL.children('li:last');
lastDIV = debugDIV.children('div:last');
if (lastDIV.is(':hidden')) {
lastUL.remove();
lastDIV.remove();
} else {
lastUL.prev().remove();
lastDIV.prev().remove();
}
}
tabId = fm.namespace + '-help-debug-' + (+new Date());
targetL = $('<li></li>').html('<a href="'+selfUrl+'#'+tabId+'">'+self.debug.debug.cmd+'</a>').prependTo(debugUL);
target = $('<div id="'+tabId+'"></div>').data('debug', self.debug);
targetL.on('click.debugrender', function() {
var debug = target.data('debug');
target.removeData('debug');
if (debug) {
target.hide();
if (debug.debug) {
info = $('<fieldset>').append($('<legend></legend>').text('debug'), render($('<dl></dl>'), debug.debug));
target.append(info);
}
if (debug.options) {
info = $('<fieldset>').append($('<legend></legend>').text('options'), render($('<dl></dl>'), debug.options));
target.append(info);
}
target.show();
}
targetL.off('click.debugrender');
});
debugUL.after(target);
opened && debugDIV.tabs('refresh');
}
},
content = '',
opened, tabInteg, integDIV, tabDebug, debugDIV, debugUL;
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.state = -1;
this.shortcuts = [{
pattern : 'f1',
description : this.title
}];
fm.bind('load', function() {
var parts = self.options.view || ['about', 'shortcuts', 'help', 'integrations', 'debug'],
i, helpSource, tabBase, tabNav, tabs, delta;
// remove 'preference' tab, it moved to command 'preference'
if ((i = $.inArray('preference', parts)) !== -1) {
parts.splice(i, 1);
}
// debug tab require jQueryUI Tabs Widget
if (! $.fn.tabs) {
if ((i = $.inArray(parts, 'debug')) !== -1) {
parts.splice(i, 1);
}
}
$.each(parts, function(i, title) {
html.push(tab[r](/\{id\}/g, title)[r](/\{title\}/, fm.i18n(title)));
});
html.push('</ul>');
$.inArray('about', parts) !== -1 && about();
$.inArray('shortcuts', parts) !== -1 && shortcuts();
if ($.inArray('help', parts) !== -1) {
helpSource = fm.i18nBaseUrl + 'help/%s.html.js';
help();
}
$.inArray('integrations', parts) !== -1 && integrations();
$.inArray('debug', parts) !== -1 && debug();
html.push('</div>');
content = $(html.join(''));
content.find('.ui-tabs-nav li')
.on('mouseenter mouseleave', function(e) {
$(this).toggleClass('ui-state-hover', e.type === 'mouseenter');
})
.on('focus blur', 'a', function(e) {
$(e.delegateTarget).toggleClass('ui-state-focus', e.type === 'focusin');
})
.children()
.on('click', function(e) {
var link = $(this);
e.preventDefault();
e.stopPropagation();
link.parent().addClass(clTabActive).siblings().removeClass(clTabActive);
content.children('.ui-tabs-panel').hide().filter(link.attr('href')).show();
})
.filter(':first').trigger('click');
if (useInteg) {
tabInteg = content.find('.elfinder-help-tab-integrations').hide();
integDIV = content.find('#'+fm.namespace+'-help-integrations').hide().append($('<div class="elfinder-help-integrations-desc"></div>').html(fm.i18n('integrationWith')));
fm.bind('helpIntegration', function(e) {
var ul = integDIV.children('ul:first'),
data, elm, cmdUL, cmdCls;
if (e.data) {
if ($.isPlainObject(e.data)) {
data = Object.assign({
link: '',
title: '',
banner: ''
}, e.data);
if (data.title || data.link) {
if (!data.title) {
data.title = data.link;
}
if (data.link) {
elm = $('<a></a>').attr('href', data.link).attr('target', '_blank').text(data.title);
} else {
elm = $('<span></span>').text(data.title);
}
if (data.banner) {
elm = $('<span></span>').append($('<img/>').attr(data.banner), elm);
}
}
} else {
elm = $(e.data);
elm.filter('a').each(function() {
var tgt = $(this);
if (!tgt.attr('target')) {
tgt.attr('target', '_blank');;
}
});
}
if (elm) {
tabInteg.show();
if (!ul.length) {
ul = $('<ul class="elfinder-help-integrations"></ul>').appendTo(integDIV);
}
if (data && data.cmd) {
cmdCls = 'elfinder-help-integration-' + data.cmd;
cmdUL = ul.find('ul.' + cmdCls);
if (!cmdUL.length) {
cmdUL = $('<ul class="'+cmdCls+'"></ul>');
ul.append($('<li></li>').append($('<span></span>').html(fm.i18n('cmd'+data.cmd))).append(cmdUL));
}
elm = cmdUL.append($('<li></li>').append(elm));
} else {
ul.append($('<li></li>').append(elm));
}
}
}
}).bind('themechange', function() {
content.find('div.elfinder-help-term-theme').replaceWith(getTheme());
});
}
// debug
if (useDebug) {
tabDebug = content.find('.elfinder-help-tab-debug').hide();
debugDIV = content.find('#'+fm.namespace+'-help-debug').children('div:first');
debugUL = debugDIV.children('ul:first').on('click', function(e) {
e.preventDefault();
e.stopPropagation();
});
self.debug = {};
fm.bind('backenddebug', function(e) {
// CAUTION: DO NOT TOUCH `e.data`
if (useDebug && e.data && e.data.debug) {
self.debug = { options : e.data.options, debug : Object.assign({ cmd : fm.currentReqCmd }, e.data.debug) };
if (self.dialog) {
debugRender();
}
}
});
}
content.find('#'+fm.namespace+'-help-about').find('.apiver').text(fm.api);
self.dialog = self.fmDialog(content, {
title : self.title,
width : 530,
maxWidth: 'window',
maxHeight: 'window',
autoOpen : false,
destroyOnClose : false,
close : function() {
if (useDebug) {
tabDebug.hide();
debugDIV.tabs('destroy');
}
opened = false;
}
})
.on('click', function(e) {
e.stopPropagation();
})
.css({
overflow: 'hidden'
});
tabBase = self.dialog.children('.ui-tabs');
tabNav = tabBase.children('.ui-tabs-nav:first');
tabs = tabBase.children('.ui-tabs-panel');
delta = self.dialog.outerHeight(true) - self.dialog.height();
self.dialog.closest('.ui-dialog').on('resize', function() {
tabs.height(self.dialog.height() - delta - tabNav.outerHeight(true) - 20);
});
if (helpSource) {
self.dialog.one('initContents', function() {
$.ajax({
url: self.options.helpSource? self.options.helpSource : helpSource.replace('%s', fm.lang),
dataType: 'html'
}).done(function(source) {
$('#'+fm.namespace+'-help-help').html(source);
}).fail(function() {
$.ajax({
url: helpSource.replace('%s', 'en'),
dataType: 'html'
}).done(function(source) {
$('#'+fm.namespace+'-help-help').html(source);
});
});
});
}
self.state = 0;
fm.trigger('helpBuilded', self.dialog);
}).one('open', function() {
var debug = false;
fm.one('backenddebug', function() {
debug =true;
}).one('opendone', function() {
requestAnimationFrame(function() {
if (! debug && useDebug) {
useDebug = false;
tabDebug.hide();
debugDIV.hide();
debugUL.hide();
}
});
});
});
this.getstate = function() {
return 0;
};
this.exec = function(sel, opts) {
var tab = opts? opts.tab : void(0),
debugShow = function() {
if (useDebug) {
debugDIV.tabs();
debugUL.find('a:first').trigger('click');
tabDebug.show();
opened = true;
}
};
debugShow();
this.dialog.trigger('initContents').elfinderdialog('open').find((tab? '.elfinder-help-tab-'+tab : '.ui-tabs-nav li') + ' a:first').trigger('click');
return $.Deferred().resolve();
};
}).prototype = { forceLoad : true }; // this is required command
@@ -0,0 +1,14 @@
/**
* @class elFinder command "hidden"
* Always hidden command for uiCmdMap
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.hidden = function() {
"use strict";
this.hidden = true;
this.updateOnSelect = false;
this.getstate = function() {
return -1;
};
};
@@ -0,0 +1,167 @@
/**
* @class elFinder command "hide".
* folders/files to hide as personal setting.
*
* @type elFinder.command
* @author Naoki Sawada
*/
elFinder.prototype.commands.hide = function() {
"use strict";
var self = this,
nameCache = {},
hideData, hideCnt, cMenuType, sOrigin;
this.syncTitleOnChange = true;
this.shortcuts = [{
pattern : 'ctrl+shift+dot',
description : this.fm.i18n('toggleHidden')
}];
this.init = function() {
var fm = this.fm;
hideData = fm.storage('hide') || {items: {}};
hideCnt = Object.keys(hideData.items).length;
this.title = fm.i18n(hideData.show? 'hideHidden' : 'showHidden');
self.update(void(0), self.title);
};
this.fm.bind('select contextmenucreate closecontextmenu', function(e, fm) {
var sel = (e.data? (e.data.selected || e.data.targets) : null) || fm.selected();
if (e.type === 'select' && e.data) {
sOrigin = e.data.origin;
} else if (e.type === 'contextmenucreate') {
cMenuType = e.data.type;
}
if (!sel.length || (((e.type !== 'contextmenucreate' && sOrigin !== 'navbar') || cMenuType === 'cwd') && sel[0] === fm.cwd().hash)) {
self.title = fm.i18n(hideData.show? 'hideHidden' : 'showHidden');
} else {
self.title = fm.i18n('cmdhide');
}
if (e.type !== 'closecontextmenu') {
self.update(cMenuType === 'cwd'? (hideCnt? 0 : -1) : void(0), self.title);
} else {
cMenuType = '';
requestAnimationFrame(function() {
self.update(void(0), self.title);
});
}
});
this.getstate = function(sel) {
return (this.fm.cookieEnabled && cMenuType !== 'cwd' && (sel || this.fm.selected()).length) || hideCnt? 0 : -1;
};
this.exec = function(hashes, opts) {
var fm = this.fm,
dfrd = $.Deferred()
.done(function() {
fm.trigger('hide', {items: items, opts: opts});
})
.fail(function(error) {
fm.error(error);
}),
o = opts || {},
items = o.targets? o.targets : (hashes || fm.selected()),
added = [],
removed = [],
notifyto, files, res;
hideData = fm.storage('hide') || {};
if (!$.isPlainObject(hideData)) {
hideData = {};
}
if (!$.isPlainObject(hideData.items)) {
hideData.items = {};
}
if (opts._currentType === 'shortcut' || !items.length || (opts._currentType !== 'navbar' && sOrigin !=='navbar' && items[0] === fm.cwd().hash)) {
if (hideData.show) {
o.hide = true;
} else if (Object.keys(hideData.items).length) {
o.show = true;
}
}
if (o.reset) {
o.show = true;
hideCnt = 0;
}
if (o.show || o.hide) {
if (o.show) {
hideData.show = true;
} else {
delete hideData.show;
}
if (o.show) {
fm.storage('hide', o.reset? null : hideData);
self.title = fm.i18n('hideHidden');
self.update(o.reset? -1 : void(0), self.title);
$.each(hideData.items, function(h) {
var f = fm.file(h, true);
if (f && (fm.searchStatus.state || !f.phash || fm.file(f.phash))) {
added.push(f);
}
});
if (added.length) {
fm.updateCache({added: added});
fm.add({added: added});
}
if (o.reset) {
hideData = {items: {}};
}
return dfrd.resolve();
}
items = Object.keys(hideData.items);
}
if (items.length) {
$.each(items, function(i, h) {
var f;
if (!hideData.items[h]) {
f = fm.file(h);
if (f) {
nameCache[h] = f.i18 || f.name;
}
hideData.items[h] = nameCache[h]? nameCache[h] : h;
}
});
hideCnt = Object.keys(hideData.items).length;
files = this.files(items);
fm.storage('hide', hideData);
fm.remove({removed: items});
if (hideData.show) {
this.exec(void(0), {hide: true});
}
if (!o.hide) {
res = {};
res.undo = {
cmd : 'hide',
callback : function() {
var nData = fm.storage('hide');
if (nData) {
$.each(items, function(i, h) {
delete nData.items[h];
});
hideCnt = Object.keys(nData.items).length;
fm.storage('hide', nData);
fm.trigger('hide', {items: items, opts: {}});
self.update(hideCnt? 0 : -1);
}
fm.updateCache({added: files});
fm.add({added: files});
}
};
res.redo = {
cmd : 'hide',
callback : function() {
return fm.exec('hide', void(0), {targets: items});
}
};
}
}
return dfrd.state() == 'rejected' ? dfrd : dfrd.resolve(res);
};
};
@@ -0,0 +1,23 @@
(elFinder.prototype.commands.home = function() {
"use strict";
this.title = 'Home';
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.shortcuts = [{
pattern : 'ctrl+home ctrl+shift+up',
description : 'Home'
}];
this.getstate = function() {
var root = this.fm.root(),
cwd = this.fm.cwd().hash;
return root && cwd && root != cwd ? 0: -1;
};
this.exec = function() {
return this.fm.exec('open', this.fm.root());
};
}).prototype = { forceLoad : true }; // this is required command
@@ -0,0 +1,345 @@
/**
* @class elFinder command "info".
* Display dialog with file properties.
*
* @author Dmitry (dio) Levashov, dio@std42.ru
**/
(elFinder.prototype.commands.info = function() {
"use strict";
var m = 'msg',
fm = this.fm,
spclass = 'elfinder-spinner',
btnclass = 'elfinder-info-button',
msg = {
calc : fm.i18n('calc'),
size : fm.i18n('size'),
unknown : fm.i18n('unknown'),
path : fm.i18n('path'),
aliasfor : fm.i18n('aliasfor'),
modify : fm.i18n('modify'),
perms : fm.i18n('perms'),
locked : fm.i18n('locked'),
dim : fm.i18n('dim'),
kind : fm.i18n('kind'),
files : fm.i18n('files'),
folders : fm.i18n('folders'),
roots : fm.i18n('volumeRoots'),
items : fm.i18n('items'),
yes : fm.i18n('yes'),
no : fm.i18n('no'),
link : fm.i18n('link'),
owner : fm.i18n('owner'),
group : fm.i18n('group'),
perm : fm.i18n('perm'),
getlink : fm.i18n('getLink')
},
applyZWSP = function(str, remove) {
if (remove) {
return str.replace(/\u200B/g, '');
} else {
return str.replace(/(\/|\\)/g, "$1\u200B");
}
};
this.items = ['size', 'aliasfor', 'path', 'link', 'dim', 'modify', 'perms', 'locked', 'owner', 'group', 'perm'];
if (this.options.custom && Object.keys(this.options.custom).length) {
$.each(this.options.custom, function(name, details) {
details.label && this.items.push(details.label);
});
}
this.tpl = {
main : '<div class="ui-helper-clearfix elfinder-info-title {dirclass}"><span class="elfinder-cwd-icon {class} ui-corner-all"{style}></span>{title}</div><table class="elfinder-info-tb">{content}</table>',
itemTitle : '<strong>{name}</strong><span class="elfinder-info-kind">{kind}</span>',
groupTitle : '<strong>{items}: {num}</strong>',
row : '<tr><td class="elfinder-info-label">{label} : </td><td class="{class}">{value}</td></tr>',
spinner : '<span>{text}</span> <span class="'+spclass+' '+spclass+'-{name}"></span>'
};
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.shortcuts = [{
pattern : 'ctrl+i'
}];
this.init = function() {
$.each(msg, function(k, v) {
msg[k] = fm.i18n(v);
});
};
this.getstate = function() {
return 0;
};
this.exec = function(hashes) {
var files = this.files(hashes);
if (! files.length) {
files = this.files([ this.fm.cwd().hash ]);
}
var self = this,
fm = this.fm,
o = this.options,
tpl = this.tpl,
row = tpl.row,
cnt = files.length,
content = [],
view = tpl.main,
l = '{label}',
v = '{value}',
reqs = [],
reqDfrd = null,
opts = {
title : fm.i18n('selectionInfo'),
width : 'auto',
close : function() {
$(this).elfinderdialog('destroy');
if (reqDfrd && reqDfrd.state() === 'pending') {
reqDfrd.reject();
}
$.grep(reqs, function(r) {
r && r.state() === 'pending' && r.reject();
});
}
},
count = [],
replSpinner = function(msg, name, className) {
dialog.find('.'+spclass+'-'+name).parent().html(msg).addClass(className || '');
},
id = fm.namespace+'-info-'+$.map(files, function(f) { return f.hash; }).join('-'),
dialog = fm.getUI().find('#'+id),
customActions = [],
style = '',
hashClass = 'elfinder-font-mono elfinder-info-hash',
getHashAlgorisms = [],
ndialog = fm.ui.notify,
size, tmb, file, title, dcnt, rdcnt, path, hideItems, hashProg;
if (ndialog.is(':hidden') && ndialog.children('.elfinder-notify').length) {
ndialog.elfinderdialog('open').height('auto');
}
if (!cnt) {
return $.Deferred().reject();
}
if (dialog.length) {
dialog.elfinderdialog('toTop');
return $.Deferred().resolve();
}
hideItems = fm.storage('infohides') || fm.arrayFlip(o.hideItems, true);
if (cnt === 1) {
file = files[0];
if (file.icon) {
style = ' '+fm.getIconStyle(file);
}
view = view.replace('{dirclass}', file.csscls? fm.escape(file.csscls) : '').replace('{class}', fm.mime2class(file.mime)).replace('{style}', style);
title = tpl.itemTitle.replace('{name}', fm.escape(file.i18 || file.name)).replace('{kind}', '<span title="'+fm.escape(file.mime)+'">'+fm.mime2kind(file)+'</span>');
tmb = fm.tmb(file);
if (!file.read) {
size = msg.unknown;
} else if (file.mime != 'directory' || file.alias) {
size = fm.formatSize(file.size);
} else {
size = tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'size');
count.push(file.hash);
}
!hideItems.size && content.push(row.replace(l, msg.size).replace(v, size));
!hideItems.aleasfor && file.alias && content.push(row.replace(l, msg.aliasfor).replace(v, file.alias));
if (!hideItems.path) {
if (path = fm.path(file.hash, true)) {
content.push(row.replace(l, msg.path).replace(v, applyZWSP(fm.escape(path))).replace('{class}', 'elfinder-info-path'));
} else {
content.push(row.replace(l, msg.path).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'path')).replace('{class}', 'elfinder-info-path'));
reqs.push(fm.path(file.hash, true, {notify: null})
.fail(function() {
replSpinner(msg.unknown, 'path');
})
.done(function(path) {
replSpinner(applyZWSP(path), 'path');
}));
}
}
if (!hideItems.link && file.read) {
var href,
name_esc = fm.escape(file.name);
if (file.url == '1') {
content.push(row.replace(l, msg.link).replace(v, '<button class="'+btnclass+' '+spclass+'-url">'+msg.getlink+'</button>'));
} else {
if (file.url) {
href = file.url;
} else if (file.mime === 'directory') {
if (o.nullUrlDirLinkSelf && file.url === null) {
var loc = window.location;
href = loc.pathname + loc.search + '#elf_' + file.hash;
} else if (file.url !== '' && fm.option('url', (!fm.isRoot(file) && file.phash) || file.hash)) {
href = fm.url(file.hash);
}
} else {
href = fm.url(file.hash);
}
href && content.push(row.replace(l, msg.link).replace(v, '<a href="'+href+'" target="_blank">'+name_esc+'</a>'));
}
}
if (!hideItems.dim) {
if (file.dim) { // old api
content.push(row.replace(l, msg.dim).replace(v, file.dim));
} else if (file.mime.indexOf('image') !== -1) {
if (file.width && file.height) {
content.push(row.replace(l, msg.dim).replace(v, file.width+'x'+file.height));
} else if (file.size && file.size !== '0') {
content.push(row.replace(l, msg.dim).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'dim')));
reqs.push(fm.request({
data : {cmd : 'dim', target : file.hash},
preventDefault : true
})
.fail(function() {
replSpinner(msg.unknown, 'dim');
})
.done(function(data) {
replSpinner(data.dim || msg.unknown, 'dim');
if (data.dim) {
var dim = data.dim.split('x');
var rfile = fm.file(file.hash);
rfile.width = dim[0];
rfile.height = dim[1];
}
}));
}
}
}
!hideItems.modify && content.push(row.replace(l, msg.modify).replace(v, fm.formatDate(file)));
!hideItems.perms && content.push(row.replace(l, msg.perms).replace(v, fm.formatPermissions(file)));
!hideItems.locked && content.push(row.replace(l, msg.locked).replace(v, file.locked ? msg.yes : msg.no));
!hideItems.owner && file.owner && content.push(row.replace(l, msg.owner).replace(v, file.owner));
!hideItems.group && file.group && content.push(row.replace(l, msg.group).replace(v, file.group));
!hideItems.perm && file.perm && content.push(row.replace(l, msg.perm).replace(v, fm.formatFileMode(file.perm)));
// Add custom info fields
if (o.custom) {
$.each(o.custom, function(name, details) {
if (
!hideItems[details.label]
&&
(!details.mimes || $.grep(details.mimes, function(m){return (file.mime === m || file.mime.indexOf(m+'/') === 0)? true : false;}).length)
&&
(!details.hashRegex || file.hash.match(details.hashRegex))
) {
// Add to the content
content.push(row.replace(l, fm.i18n(details.label)).replace(v , details.tpl.replace('{id}', id)));
// Register the action
if (details.action && (typeof details.action == 'function')) {
customActions.push(details.action);
}
}
});
}
} else {
view = view.replace('{class}', 'elfinder-cwd-icon-group');
title = tpl.groupTitle.replace('{items}', msg.items).replace('{num}', cnt);
dcnt = $.grep(files, function(f) { return f.mime == 'directory' ? true : false ; }).length;
if (!dcnt) {
size = 0;
$.each(files, function(h, f) {
var s = parseInt(f.size);
if (s >= 0 && size >= 0) {
size += s;
} else {
size = 'unknown';
}
});
content.push(row.replace(l, msg.kind).replace(v, msg.files));
!hideItems.size && content.push(row.replace(l, msg.size).replace(v, fm.formatSize(size)));
} else {
rdcnt = $.grep(files, function(f) { return f.mime === 'directory' && (! f.phash || f.isroot)? true : false ; }).length;
dcnt -= rdcnt;
content.push(row.replace(l, msg.kind).replace(v, (rdcnt === cnt || dcnt === cnt)? msg[rdcnt? 'roots' : 'folders'] : $.map({roots: rdcnt, folders: dcnt, files: cnt - rdcnt - dcnt}, function(c, t) { return c? msg[t]+' '+c : null; }).join(', ')));
!hideItems.size && content.push(row.replace(l, msg.size).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'size')));
count = $.map(files, function(f) { return f.hash; });
}
}
view = view.replace('{title}', title).replace('{content}', content.join('').replace(/{class}/g, ''));
dialog = self.fmDialog(view, opts);
dialog.attr('id', id).one('mousedown', '.elfinder-info-path', function() {
$(this).html(applyZWSP($(this).html(), true));
});
if (getHashAlgorisms.length) {
hashProg.appendTo(dialog.find('.'+spclass+'-'+getHashAlgorisms[0]).parent());
}
if (fm.UA.Mobile && $.fn.tooltip) {
dialog.children('.ui-dialog-content .elfinder-info-title').tooltip({
classes: {
'ui-tooltip': 'elfinder-ui-tooltip ui-widget-shadow'
},
tooltipClass: 'elfinder-ui-tooltip ui-widget-shadow',
track: true
});
}
if (file && file.url == '1') {
dialog.on('click', '.'+spclass+'-url', function(){
$(this).parent().html(tpl.spinner.replace('{text}', fm.i18n('ntfurl')).replace('{name}', 'url'));
fm.request({
data : {cmd : 'url', target : file.hash},
preventDefault : true
})
.fail(function() {
replSpinner(name_esc, 'url');
})
.done(function(data) {
if (data.url) {
replSpinner('<a href="'+data.url+'" target="_blank">'+name_esc+'</a>' || name_esc, 'url');
var rfile = fm.file(file.hash);
rfile.url = data.url;
} else {
replSpinner(name_esc, 'url');
}
});
});
}
// load thumbnail
if (tmb) {
$('<img/>')
.on('load', function() { dialog.find('.elfinder-cwd-icon').addClass(tmb.className).css('background-image', "url('"+tmb.url+"')"); })
.attr('src', tmb.url);
}
// send request to count total size
if (count.length) {
reqDfrd = fm.getSize(count).done(function(data) {
replSpinner(data.formated, 'size');
}).fail(function() {
replSpinner(msg.unknown, 'size');
});
}
// call custom actions
if (customActions.length) {
$.each(customActions, function(i, action) {
try {
action(file, fm, dialog);
} catch(e) {
fm.debug('error', e);
}
});
}
return $.Deferred().resolve();
};
}).prototype = { forceLoad : true }; // this is required command
@@ -0,0 +1,92 @@
/**
* @class elFinder command "mkdir"
* Create new folder
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.mkdir = function() {
"use strict";
var fm = this.fm,
self = this,
curOrg;
this.value = '';
this.disableOnSearch = true;
this.updateOnSelect = false;
this.syncTitleOnChange = true;
this.mime = 'directory';
this.prefix = 'untitled folder';
this.exec = function(select, cOpts) {
var onCwd;
if (select && select.length && cOpts && cOpts._currentType && cOpts._currentType === 'navbar') {
this.origin = cOpts._currentType;
this.data = {
target: select[0]
};
} else {
onCwd = fm.cwd().hash === select[0];
this.origin = curOrg && !onCwd? curOrg : 'cwd';
delete this.data;
}
if (! select && ! this.options.intoNewFolderToolbtn) {
fm.getUI('cwd').trigger('unselectall');
}
//this.move = (!onCwd && curOrg !== 'navbar' && fm.selected().length)? true : false;
this.move = this.value === fm.i18n('cmdmkdirin');
return $.proxy(fm.res('mixin', 'make'), self)();
};
this.shortcuts = [{
pattern : 'ctrl+shift+n'
}];
this.init = function() {
if (this.options.intoNewFolderToolbtn) {
this.syncTitleOnChange = true;
}
};
fm.bind('select contextmenucreate closecontextmenu', function(e) {
var sel = (e.data? (e.data.selected || e.data.targets) : null) || fm.selected();
self.className = 'mkdir';
curOrg = e.data && sel.length? (e.data.origin || e.data.type || '') : '';
if (!self.options.intoNewFolderToolbtn && curOrg === '') {
curOrg = 'cwd';
}
if (sel.length && curOrg !== 'navbar' && curOrg !== 'cwd' && fm.cwd().hash !== sel[0]) {
self.title = fm.i18n('cmdmkdirin');
self.className += ' elfinder-button-icon-mkdirin';
} else {
self.title = fm.i18n('cmdmkdir');
}
if (e.type !== 'closecontextmenu') {
self.update(void(0), self.title);
} else {
requestAnimationFrame(function() {
self.update(void(0), self.title);
});
}
});
this.getstate = function(select) {
var cwd = fm.cwd(),
sel = (curOrg === 'navbar' || (select && select[0] !== cwd.hash))? this.files(select || fm.selected()) : [],
cnt = sel.length,
filter = function(files) {
var fres = true;
return $.grep(files, function(f) {
fres = fres && f.read && ! f.locked? true : false;
return fres;
});
};
if (curOrg === 'navbar') {
return cnt && sel[0].write && sel[0].read? 0 : -1;
} else {
return cwd.write && (!cnt || filter(sel).length == cnt)? 0 : -1;
}
};
};
@@ -0,0 +1,57 @@
/**
* @class elFinder command "mkfile"
* Create new empty file
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.mkfile = function() {
"use strict";
var self = this;
this.disableOnSearch = true;
this.updateOnSelect = false;
this.mime = 'text/plain';
this.prefix = 'untitled file.txt';
this.variants = [];
this.getTypeName = function(mime, type) {
var fm = self.fm,
name;
if (name = fm.messages['kind' + fm.kinds[mime]]) {
name = fm.i18n(['extentiontype', type.toUpperCase(), name]);
} else {
name = fm.i18n(['extentionfile', type.toUpperCase()]);
}
return name;
};
this.fm.bind('open reload canMakeEmptyFile', function() {
var fm = self.fm,
hides = fm.getCommand('edit').getMkfileHides();
self.variants = [];
if (fm.mimesCanMakeEmpty) {
$.each(fm.mimesCanMakeEmpty, function(mime, type) {
type && !hides[mime] && fm.uploadMimeCheck(mime) && self.variants.push([mime, self.getTypeName(mime, type)]);
});
}
self.change();
});
this.getstate = function() {
return this.fm.cwd().write ? 0 : -1;
};
this.exec = function(_dum, mime) {
var fm = self.fm,
type, err;
if (type = fm.mimesCanMakeEmpty[mime]) {
if (fm.uploadMimeCheck(mime)) {
this.mime = mime;
this.prefix = fm.i18n(['untitled file', type]);
return $.proxy(fm.res('mixin', 'make'), self)();
}
err = ['errMkfile', self.getTypeName(mime, type)];
}
return $.Deferred().reject(err);
};
};
@@ -0,0 +1,381 @@
/**
* @class elFinder command "netmount"
* Mount network volume with user credentials.
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.netmount = function() {
"use strict";
var self = this,
hasMenus = false,
content;
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.drivers = [];
this.handlers = {
load : function() {
var fm = self.fm;
if (fm.cookieEnabled) {
fm.one('open', function() {
self.drivers = fm.netDrivers;
if (self.drivers.length) {
$.each(self.drivers, function() {
var d = self.options[this];
if (d) {
hasMenus = true;
if (d.integrateInfo) {
fm.trigger('helpIntegration', Object.assign({cmd: 'netmount'}, d.integrateInfo));
}
}
});
}
});
}
}
};
this.getstate = function() {
return hasMenus ? 0 : -1;
};
this.exec = function() {
var fm = self.fm,
dfrd = $.Deferred(),
o = self.options,
create = function() {
var winFocus = function() {
inputs.protocol.trigger('change', 'winfocus');
},
inputs = {
protocol : $('<select></select>')
.on('change', function(e, data){
var protocol = this.value;
content.find('.elfinder-netmount-tr').hide();
content.find('.elfinder-netmount-tr-'+protocol).show();
dialogNode && dialogNode.children('.ui-dialog-buttonpane:first').find('button').show();
if (typeof o[protocol].select == 'function') {
o[protocol].select(fm, e, data);
}
})
.addClass('ui-corner-all')
},
opts = {
title : fm.i18n('netMountDialogTitle'),
resizable : true,
modal : true,
destroyOnClose : false,
open : function() {
$(window).on('focus.'+fm.namespace, winFocus);
inputs.protocol.trigger('change');
},
close : function() {
dfrd.state() == 'pending' && dfrd.reject();
$(window).off('focus.'+fm.namespace, winFocus);
},
buttons : {}
},
doMount = function() {
var protocol = inputs.protocol.val(),
data = {cmd : 'netmount', protocol: protocol},
cur = o[protocol],
mnt2res;
$.each(content.find('input.elfinder-netmount-inputs-'+protocol), function(name, input) {
var val, elm;
elm = $(input);
if (elm.is(':radio,:checkbox')) {
if (elm.is(':checked')) {
val = $.trim(elm.val());
}
} else {
val = $.trim(elm.val());
}
if (val) {
data[input.name] = val;
}
});
if (!data.host) {
return fm.trigger('error', {error : 'errNetMountHostReq', opts : {modal: true}});
}
if (data.mnt2res) {
mnt2res = true;
}
fm.request({data : data, notify : {type : 'netmount', cnt : 1, hideCnt : true}})
.done(function(data) {
var pdir;
if (data.added && data.added.length) {
mnt2res && inputs.protocol.trigger('change', 'reset');
if (data.added[0].phash) {
if (pdir = fm.file(data.added[0].phash)) {
if (! pdir.dirs) {
pdir.dirs = 1;
fm.change({ changed: [ pdir ] });
}
}
}
fm.one('netmountdone', function() {
fm.exec('open', data.added[0].hash);
});
}
dfrd.resolve();
})
.fail(function(error) {
if (cur.fail && typeof cur.fail == 'function') {
cur.fail(fm, fm.parseError(error));
}
dfrd.reject(error);
});
self.dialog.elfinderdialog('close');
},
form = $('<form autocomplete="off"></form>').on('keydown', 'input', function(e) {
var comp = true,
next;
if (e.keyCode === $.ui.keyCode.ENTER) {
$.each(form.find('input:visible:not(.elfinder-input-optional)'), function() {
if ($(this).val() === '') {
comp = false;
next = $(this);
return false;
}
});
if (comp) {
doMount();
} else {
next.trigger('focus');
}
}
}),
hidden = $('<div></div>'),
dialog;
content = $('<table class="elfinder-info-tb elfinder-netmount-tb"></table>')
.append($('<tr></tr>').append($('<td>'+fm.i18n('protocol')+'</td>')).append($('<td></td>').append(inputs.protocol)));
$.each(self.drivers, function(i, protocol) {
if (o[protocol]) {
inputs.protocol.append('<option value="'+protocol+'">'+fm.i18n(o[protocol].name || protocol)+'</option>');
$.each(o[protocol].inputs, function(name, input) {
input.attr('name', name);
if (input.attr('type') != 'hidden') {
input.addClass('ui-corner-all elfinder-netmount-inputs-'+protocol);
content.append($('<tr></tr>').addClass('elfinder-netmount-tr elfinder-netmount-tr-'+protocol).append($('<td>'+fm.i18n(name)+'</td>')).append($('<td></td>').append(input)));
} else {
input.addClass('elfinder-netmount-inputs-'+protocol);
hidden.append(input);
}
});
o[protocol].protocol = inputs.protocol;
}
});
content.append(hidden);
content.find('.elfinder-netmount-tr').hide();
content.find('.elfinder-netmount-tr-' + self.drivers[0]).show();
opts.buttons[fm.i18n('btnMount')] = doMount;
opts.buttons[fm.i18n('btnCancel')] = function() {
self.dialog.elfinderdialog('close');
};
content.find('select,input').addClass('elfinder-tabstop');
dialog = self.fmDialog(form.append(content), opts).ready(function() {
inputs.protocol.trigger('change');
dialog.elfinderdialog('posInit');
});
dialogNode = dialog.closest('.ui-dialog');
return dialog;
},
dialogNode;
if (!self.dialog) {
self.dialog = create();
} else {
self.dialog.elfinderdialog('open');
}
return dfrd.promise();
};
self.fm.bind('netmount', function(e) {
var d = e.data || null,
o = self.options,
done = function() {
if (o[d.protocol] && typeof o[d.protocol].done == 'function') {
o[d.protocol].done(self.fm, d);
content.find('select,input').addClass('elfinder-tabstop');
self.dialog.elfinderdialog('tabstopsInit');
}
};
if (d && d.protocol) {
if (d.mode && d.mode === 'redirect') {
// To support of third-party cookie blocking (ITP) on CORS
// On iOS and iPadOS 13.4 and Safari 13.1 on macOS, the session cannot be continued when redirecting OAuth in CORS mode
self.fm.request({
data : {cmd : 'netmount', protocol : d.protocol, host: d.host, user : 'init', pass : 'return', options: d.options},
preventDefault : true
}).done(function(data) {
d = JSON.parse(data.body);
done();
});
} else {
done();
}
}
});
};
elFinder.prototype.commands.netunmount = function() {
var self = this;
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.drivers = [];
this.handlers = {
load : function() {
this.drivers = this.fm.netDrivers;
}
};
this.getstate = function(sel) {
var fm = this.fm,
file;
return !!sel && this.drivers.length && !this._disabled && (file = fm.file(sel[0])) && file.netkey ? 0 : -1;
};
this.exec = function(hashes) {
var self = this,
fm = this.fm,
dfrd = $.Deferred()
.fail(function(error) {
error && fm.error(error);
}),
drive = fm.file(hashes[0]),
childrenRoots = function(hash) {
var roots = [],
work;
if (fm.leafRoots) {
work = [];
$.each(fm.leafRoots, function(phash, hashes) {
var parents = fm.parents(phash),
idx, deep;
if ((idx = $.inArray(hash, parents)) !== -1) {
idx = parents.length - idx;
$.each(hashes, function(i, h) {
work.push({i: idx, hash: h});
});
}
});
if (work.length) {
work.sort(function(a, b) { return a.i < b.i; });
$.each(work, function(i, o) {
roots.push(o.hash);
});
}
}
return roots;
};
if (this._disabled) {
return dfrd.reject();
}
if (dfrd.state() == 'pending') {
fm.confirm({
title : self.title,
text : fm.i18n('confirmUnmount', drive.name),
accept : {
label : 'btnUnmount',
callback : function() {
var target = drive.hash,
roots = childrenRoots(target),
requests = [],
removed = [],
doUmount = function() {
$.when(requests).done(function() {
fm.request({
data : {cmd : 'netmount', protocol : 'netunmount', host: drive.netkey, user : target, pass : 'dum'},
notify : {type : 'netunmount', cnt : 1, hideCnt : true},
preventFail : true
})
.fail(function(error) {
dfrd.reject(error);
})
.done(function(data) {
drive.volumeid && delete fm.volumeExpires[drive.volumeid];
dfrd.resolve();
});
}).fail(function(error) {
if (removed.length) {
fm.remove({ removed: removed });
}
dfrd.reject(error);
});
};
if (roots.length) {
fm.confirm({
title : self.title,
text : (function() {
var msgs = ['unmountChildren'];
$.each(roots, function(i, hash) {
msgs.push([fm.file(hash).name]);
});
return msgs;
})(),
accept : {
label : 'btnUnmount',
callback : function() {
$.each(roots, function(i, hash) {
var d = fm.file(hash);
if (d.netkey) {
requests.push(fm.request({
data : {cmd : 'netmount', protocol : 'netunmount', host: d.netkey, user : d.hash, pass : 'dum'},
notify : {type : 'netunmount', cnt : 1, hideCnt : true},
preventDefault : true
}).done(function(data) {
if (data.removed) {
d.volumeid && delete fm.volumeExpires[d.volumeid];
removed = removed.concat(data.removed);
}
}));
}
});
doUmount();
}
},
cancel : {
label : 'btnCancel',
callback : function() {
dfrd.reject();
}
}
});
} else {
requests = null;
doUmount();
}
}
},
cancel : {
label : 'btnCancel',
callback : function() { dfrd.reject(); }
}
});
}
return dfrd;
};
};
@@ -0,0 +1,249 @@
/**
* @class elFinder command "open"
* Enter folder or open files in new windows
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.open = function() {
"use strict";
var fm = this.fm,
self = this;
this.alwaysEnabled = true;
this.noChangeDirOnRemovedCwd = true;
this._handlers = {
dblclick : function(e) {
var arg = e.data && e.data.file? [ e.data.file ]: void(0);
if (self.getstate(arg) === 0) {
e.preventDefault();
fm.exec('open', arg);
}
},
'select enable disable reload' : function(e) { this.update(e.type == 'disable' ? -1 : void(0)); }
};
this.shortcuts = [{
pattern : 'ctrl+down numpad_enter'+(fm.OS != 'mac' && ' enter')
}];
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length,
filter = function(files) {
var fres = true;
return $.grep(files, function(file) {
fres = fres && file.mime == 'directory' || ! file.read ? false : true;
return fres;
});
};
return cnt == 1
? (sel[0].read ? 0 : -1)
: (cnt && !fm.UA.Mobile) ? ($.grep(sel, function(file) { return file.mime == 'directory' || ! file.read ? false : true;}).length == cnt ? 0 : -1) : -1;
};
this.exec = function(hashes, cOpts) {
var dfrd = $.Deferred().fail(function(error) { error && fm.error(error); }),
files = this.files(hashes),
cnt = files.length,
thash = (typeof cOpts == 'object')? cOpts.thash : false,
opts = this.options,
into = opts.into || 'window',
file, url, s, w, imgW, imgH, winW, winH, reg, link, html5dl, inline,
selAct, cmd;
if (!cnt && !thash) {
{
return dfrd.reject();
}
}
// open folder
if (thash || (cnt == 1 && (file = files[0]) && file.mime == 'directory')) {
if (!thash && file && !file.read) {
return dfrd.reject(['errOpen', file.name, 'errPerm']);
} else {
if (fm.keyState.ctrlKey && (fm.keyState.shiftKey || typeof fm.options.getFileCallback !== 'function')) {
if (fm.getCommand('opennew')) {
return fm.exec('opennew', [thash? thash : file.hash]);
}
}
return fm.request({
data : {cmd : 'open', target : thash || file.hash},
notify : {type : 'open', cnt : 1, hideCnt : true},
syncOnFail : true,
lazy : false
});
}
}
files = $.grep(files, function(file) { return file.mime != 'directory' ? true : false; });
// nothing to open or files and folders selected - do nothing
if (cnt != files.length) {
return dfrd.reject();
}
var doOpen = function() {
var openCB = function(url) {
var link = $('<a rel="noopener">').hide().appendTo($('body'));
if (fm.UA.Mobile || !inline) {
if (html5dl) {
if (!inline) {
link.attr('download', file.name);
} else {
link.attr('target', '_blank');
}
link.attr('href', url).get(0).click();
} else {
wnd = window.open(url);
if (!wnd) {
return dfrd.reject('errPopup');
}
}
} else {
getOnly = (typeof opts.method === 'string' && opts.method.toLowerCase() === 'get');
if (!getOnly
&& url.indexOf(fm.options.url) === 0
&& fm.customData
&& Object.keys(fm.customData).length
// Since playback by POST request can not be done in Chrome, media allows GET request
&& !file.mime.match(/^(?:video|audio)/)
) {
// Send request as 'POST' method to hide custom data at location bar
url = '';
}
if (into === 'window') {
// set window size for image if set
imgW = winW = Math.round(2 * screen.availWidth / 3);
imgH = winH = Math.round(2 * screen.availHeight / 3);
if (parseInt(file.width) && parseInt(file.height)) {
imgW = parseInt(file.width);
imgH = parseInt(file.height);
} else if (file.dim) {
s = file.dim.split('x');
imgW = parseInt(s[0]);
imgH = parseInt(s[1]);
}
if (winW >= imgW && winH >= imgH) {
winW = imgW;
winH = imgH;
} else {
if ((imgW - winW) > (imgH - winH)) {
winH = Math.round(imgH * (winW / imgW));
} else {
winW = Math.round(imgW * (winH / imgH));
}
}
w = 'width='+winW+',height='+winH;
wnd = window.open(url, target, w + ',top=50,left=50,scrollbars=yes,resizable=yes,titlebar=no');
} else {
if (into === 'tabs') {
target = file.hash;
}
wnd = window.open('about:blank', target);
}
if (!wnd) {
return dfrd.reject('errPopup');
}
if (url === '') {
var form = document.createElement("form");
form.action = fm.options.url;
form.method = 'POST';
form.target = target;
form.style.display = 'none';
var params = Object.assign({}, fm.customData, {
cmd: 'file',
target: file.hash,
_t: file.ts || parseInt(+new Date()/1000)
});
$.each(params, function(key, val)
{
var input = document.createElement("input");
input.name = key;
input.value = val;
form.appendChild(input);
});
document.body.appendChild(form);
form.submit();
} else if (into !== 'window') {
wnd.location = url;
}
$(wnd).trigger('focus');
}
link.remove();
},
wnd, target, getOnly;
try {
reg = new RegExp(fm.option('dispInlineRegex'), 'i');
} catch(e) {
reg = false;
}
// open files
html5dl = (typeof $('<a>').get(0).download === 'string');
cnt = files.length;
while (cnt--) {
target = 'elf_open_window';
file = files[cnt];
if (!file.read) {
return dfrd.reject(['errOpen', file.name, 'errPerm']);
}
inline = (reg && file.mime.match(reg));
fm.openUrl(file.hash, !inline, openCB);
}
return dfrd.resolve(hashes);
};
if (cnt > 1) {
fm.confirm({
title: 'openMulti',
text : ['openMultiConfirm', cnt + ''],
accept : {
label : 'cmdopen',
callback : function() { doOpen(); }
},
cancel : {
label : 'btnCancel',
callback : function() {
dfrd.reject();
}
},
buttons : (fm.getCommand('zipdl') && fm.isCommandEnabled('zipdl', fm.cwd().hash))? [
{
label : 'cmddownload',
callback : function() {
fm.exec('download', hashes);
dfrd.reject();
}
}
] : []
});
} else {
selAct = fm.storage('selectAction') || opts.selectAction;
if (selAct) {
$.each(selAct.split('/'), function() {
var cmdName = this.valueOf();
if (cmdName !== 'open' && (cmd = fm.getCommand(cmdName)) && cmd.enabled()) {
return false;
}
cmd = null;
});
if (cmd) {
return fm.exec(cmd.name);
}
}
doOpen();
}
return dfrd;
};
}).prototype = { forceLoad : true }; // this is required command
@@ -0,0 +1,44 @@
/**
* @class elFinder command "opendir"
* Enter parent folder
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.opendir = function() {
"use strict";
this.alwaysEnabled = true;
this.getstate = function() {
var sel = this.fm.selected(),
cnt = sel.length,
wz;
if (cnt !== 1) {
return -1;
}
wz = this.fm.getUI('workzone');
return wz.hasClass('elfinder-search-result')? 0 : -1;
};
this.exec = function(hashes) {
var fm = this.fm,
dfrd = $.Deferred(),
files = this.files(hashes),
cnt = files.length,
hash, pcheck = null;
if (!cnt || !files[0].phash) {
return dfrd.reject();
}
hash = files[0].phash;
fm.trigger('searchend', { noupdate: true });
fm.request({
data : {cmd : 'open', target : hash},
notify : {type : 'open', cnt : 1, hideCnt : true},
syncOnFail : false
});
return dfrd;
};
};
@@ -0,0 +1,56 @@
/**
* @class elFinder command "opennew"
* Open folder in new window
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.opennew = function() {
"use strict";
var fm = this.fm;
this.shortcuts = [{
pattern : (typeof(fm.options.getFileCallback) === 'function'? 'shift+' : '') + 'ctrl+enter'
}];
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length;
return cnt === 1
? (sel[0].mime === 'directory' && sel[0].read? 0 : -1)
: -1;
};
this.exec = function(hashes) {
var dfrd = $.Deferred(),
files = this.files(hashes),
cnt = files.length,
opts = this.options,
file, loc, url, win;
// open folder to new tab (window)
if (cnt === 1 && (file = files[0]) && file.mime === 'directory') {
loc = window.location;
if (opts.url) {
url = opts.url;
} else {
url = loc.pathname;
}
if (opts.useOriginQuery) {
if (!url.match(/\?/)) {
url += loc.search;
} else if (loc.search) {
url += '&' + loc.search.substr(1);
}
}
url += '#elf_' + file.hash;
win = window.open(url, '_blank');
setTimeout(function() {
win.focus();
}, 1000);
return dfrd.resolve();
} else {
return dfrd.reject();
}
};
};
@@ -0,0 +1,412 @@
/**
* @class elFinder command "paste"
* Paste filesfrom clipboard into directory.
* If files pasted in its parent directory - files duplicates will created
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.paste = function() {
"use strict";
this.updateOnSelect = false;
this.handlers = {
changeclipboard : function() { this.update(); }
};
this.shortcuts = [{
pattern : 'ctrl+v shift+insert'
}];
this.getstate = function(dst) {
if (this._disabled) {
return -1;
}
if (dst) {
if (Array.isArray(dst)) {
if (dst.length != 1) {
return -1;
}
dst = this.fm.file(dst[0]);
}
} else {
dst = this.fm.cwd();
}
return this.fm.clipboard().length && dst.mime == 'directory' && dst.write ? 0 : -1;
};
this.exec = function(select, cOpts) {
var self = this,
fm = self.fm,
opts = cOpts || {},
dst = select ? this.files(select)[0] : fm.cwd(),
files = fm.clipboard(),
cnt = files.length,
cut = cnt ? files[0].cut : false,
cmd = opts._cmd? opts._cmd : (cut? 'move' : 'copy'),
error = 'err' + cmd.charAt(0).toUpperCase() + cmd.substr(1),
fpaste = [],
fcopy = [],
dfrd = $.Deferred()
.fail(function(error) {
error && fm.error(error);
})
.always(function() {
fm.unlockfiles({files : $.map(files, function(f) { return f.hash; })});
}),
copy = function(files) {
return files.length && fm._commands.duplicate
? fm.exec('duplicate', files)
: $.Deferred().resolve();
},
paste = function(files) {
var dfrd = $.Deferred(),
existed = [],
hashes = {},
intersect = function(files, names) {
var ret = [],
i = files.length;
while (i--) {
$.inArray(files[i].name, names) !== -1 && ret.unshift(i);
}
return ret;
},
confirm = function(ndx) {
var i = existed[ndx],
file = files[i],
last = ndx == existed.length-1;
if (!file) {
return;
}
fm.confirm({
title : fm.i18n(cmd + 'Files'),
text : ['errExists', file.name, cmd === 'restore'? 'confirmRest' : 'confirmRepl'],
all : !last,
accept : {
label : 'btnYes',
callback : function(all) {
!last && !all
? confirm(++ndx)
: paste(files);
}
},
reject : {
label : 'btnNo',
callback : function(all) {
var i;
if (all) {
i = existed.length;
while (ndx < i--) {
files[existed[i]].remove = true;
}
} else {
files[existed[ndx]].remove = true;
}
!last && !all
? confirm(++ndx)
: paste(files);
}
},
cancel : {
label : 'btnCancel',
callback : function() {
dfrd.resolve();
}
},
buttons : [
{
label : 'btnBackup',
callback : function(all) {
var i;
if (all) {
i = existed.length;
while (ndx < i--) {
files[existed[i]].rename = true;
}
} else {
files[existed[ndx]].rename = true;
}
!last && !all
? confirm(++ndx)
: paste(files);
}
}
]
});
},
valid = function(names) {
var exists = {}, existedArr;
if (names) {
if (Array.isArray(names)) {
if (names.length) {
if (typeof names[0] == 'string') {
// elFinder <= 2.1.6 command `is` results
existed = intersect(files, names);
} else {
$.each(names, function(i, v) {
exists[v.name] = v.hash;
});
existed = intersect(files, $.map(exists, function(h, n) { return n; }));
$.each(files, function(i, file) {
if (exists[file.name]) {
hashes[exists[file.name]] = file.name;
}
});
}
}
} else {
existedArr = [];
existed = $.map(names, function(n) {
if (typeof n === 'string') {
return n;
} else {
// support to >=2.1.11 plugin Normalizer, Sanitizer
existedArr = existedArr.concat(n);
return false;
}
});
if (existedArr.length) {
existed = existed.concat(existedArr);
}
existed = intersect(files, existed);
hashes = names;
}
}
existed.length ? confirm(0) : paste(files);
},
paste = function(selFiles) {
var renames = [],
files = $.grep(selFiles, function(file) {
if (file.rename) {
renames.push(file.name);
}
return !file.remove ? true : false;
}),
cnt = files.length,
groups = {},
args = [],
targets, reqData;
if (!cnt) {
return dfrd.resolve();
}
targets = $.map(files, function(f) { return f.hash; });
reqData = {cmd : 'paste', dst : dst.hash, targets : targets, cut : cut ? 1 : 0, renames : renames, hashes : hashes, suffix : fm.options.backupSuffix};
if (fm.api < 2.1) {
reqData.src = files[0].phash;
}
fm.request({
data : reqData,
notify : {type : cmd, cnt : cnt},
cancel : true,
navigate : {
toast : opts.noToast? {} : {
inbuffer : {msg: fm.i18n(['complete', fm.i18n('cmd' + cmd)]), action: {
cmd: 'open',
msg: 'cmdopendir',
data: [dst.hash],
done: 'select',
cwdNot: dst.hash
}}
}
}
})
.done(function(data) {
var dsts = {},
added = data.added && data.added.length? data.added : null;
if (cut && added) {
// undo/redo
$.each(files, function(i, f) {
var phash = f.phash,
srcHash = function(name) {
var hash;
$.each(added, function(i, f) {
if (f.name === name) {
hash = f.hash;
return false;
}
});
return hash;
},
shash = srcHash(f.name);
if (shash) {
if (dsts[phash]) {
dsts[phash].push(shash);
} else {
dsts[phash] = [ shash ];
}
}
});
if (Object.keys(dsts).length) {
data.undo = {
cmd : 'move',
callback : function() {
var reqs = [];
$.each(dsts, function(dst, targets) {
reqs.push(fm.request({
data : {cmd : 'paste', dst : dst, targets : targets, cut : 1},
notify : {type : 'undo', cnt : targets.length}
}));
});
return $.when.apply(null, reqs);
}
};
data.redo = {
cmd : 'move',
callback : function() {
return fm.request({
data : reqData,
notify : {type : 'redo', cnt : cnt}
});
}
};
}
}
dfrd.resolve(data);
})
.fail(function(flg) {
dfrd.reject();
if (flg === 0) {
// canceling
fm.sync();
}
})
.always(function() {
fm.unlockfiles({files : files});
});
},
internames;
if (!fm.isCommandEnabled(self.name, dst.hash) || !files.length) {
return dfrd.resolve();
}
if (fm.oldAPI) {
paste(files);
} else {
if (!fm.option('copyOverwrite', dst.hash)) {
paste(files);
} else {
internames = $.map(files, function(f) { return f.name; });
dst.hash == fm.cwd().hash
? valid($.map(fm.files(), function(file) { return file.phash == dst.hash ? {hash: file.hash, name: file.name} : null; }))
: fm.request({
data : {cmd : 'ls', target : dst.hash, intersect : internames},
notify : {type : 'prepare', cnt : 1, hideCnt : true},
preventFail : true
})
.always(function(data) {
valid(data.list);
});
}
}
return dfrd;
},
parents, fparents, cutDfrd;
if (!cnt || !dst || dst.mime != 'directory') {
return dfrd.reject();
}
if (!dst.write) {
return dfrd.reject([error, files[0].name, 'errPerm']);
}
parents = fm.parents(dst.hash);
$.each(files, function(i, file) {
if (!file.read) {
return !dfrd.reject([error, file.name, 'errPerm']);
}
if (cut && file.locked) {
return !dfrd.reject(['errLocked', file.name]);
}
if ($.inArray(file.hash, parents) !== -1) {
return !dfrd.reject(['errCopyInItself', file.name]);
}
if (file.mime && file.mime !== 'directory' && ! fm.uploadMimeCheck(file.mime, dst.hash)) {
return !dfrd.reject([error, file.name, 'errUploadMime']);
}
fparents = fm.parents(file.hash);
fparents.pop();
if ($.inArray(dst.hash, fparents) !== -1) {
if ($.grep(fparents, function(h) { var d = fm.file(h); return d.phash == dst.hash && d.name == file.name ? true : false; }).length) {
return !dfrd.reject(['errReplByChild', file.name]);
}
}
if (file.phash == dst.hash) {
fcopy.push(file.hash);
} else {
fpaste.push({
hash : file.hash,
phash : file.phash,
name : file.name
});
}
});
if (dfrd.state() === 'rejected') {
return dfrd;
}
cutDfrd = $.Deferred();
if (cut && self.options.moveConfirm) {
fm.confirm({
title : 'moveFiles',
text : fm.i18n('confirmMove', dst.i18 || dst.name),
accept : {
label : 'btnYes',
callback : function() {
cutDfrd.resolve();
}
},
cancel : {
label : 'btnCancel',
callback : function() {
cutDfrd.reject();
}
}
});
} else {
cutDfrd.resolve();
}
cutDfrd.done(function() {
$.when(
copy(fcopy),
paste(fpaste)
)
.done(function(cr, pr) {
dfrd.resolve(pr && pr.undo? pr : void(0));
})
.fail(function() {
dfrd.reject();
})
.always(function() {
cut && fm.clipboard([]);
});
}).fail(function() {
dfrd.reject();
});
return dfrd;
};
};
@@ -0,0 +1,37 @@
/**
* @class elFinder command "places"
* Regist to Places
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.places = function() {
"use strict";
var self = this,
fm = this.fm,
filter = function(hashes) {
var fres = true;
return $.grep(self.files(hashes), function(f) {
fres = fres && f.mime == 'directory' ? true : false;
return fres;
});
},
places = null;
this.getstate = function(select) {
var sel = this.hashes(select),
cnt = sel.length;
return places && cnt && cnt == filter(sel).length ? 0 : -1;
};
this.exec = function(hashes) {
var files = this.files(hashes);
places.trigger('regist', [ files ]);
return $.Deferred().resolve();
};
fm.one('load', function(){
places = fm.ui.places;
});
};
@@ -0,0 +1,605 @@
/**
* @class elFinder command "preference"
* "Preference" dialog
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.preference = function() {
var self = this,
fm = this.fm,
r = 'replace',
tab = '<li class="' + fm.res('class', 'tabstab') + ' elfinder-preference-tab-{id}"><a href="#'+fm.namespace+'-preference-{id}" id="'+fm.namespace+'-preference-tab-{id}" class="ui-tabs-anchor {class}">{title}</a></li>',
base = $('<div class="ui-tabs ui-widget ui-widget-content ui-corner-all elfinder-preference">'),
ul = $('<ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-top">'),
tabs = $('<div class="elfinder-preference-tabs ui-tabs-panel ui-widget-content ui-corner-bottom"></div>'),
sep = '<div class="elfinder-preference-separator"></div>',
selfUrl = $('base').length? document.location.href.replace(/#.*$/, '') : '',
selectTab = function(tab) {
$('#'+fm.namespace+'-preference-tab-'+tab).trigger('mouseover').trigger('click');
openTab = tab;
},
clTabActive = fm.res('class', 'tabsactive'),
build = function() {
var cats = self.options.categories || {
'language' : ['language'],
'theme' : ['theme'],
'toolbar' : ['toolbarPref'],
'workspace' : ['iconSize','columnPref', 'selectAction', 'makefileTypes', 'useStoredEditor', 'editorMaximized', 'useFullscreen', 'showHidden'],
'dialog' : ['autoFocusDialog'],
'selectionInfo' : ['infoItems', 'hashChecker'],
'reset' : ['clearBrowserData'],
'all' : true
},
forms = self.options.prefs || ['language', 'theme', 'toolbarPref', 'iconSize', 'columnPref', 'selectAction', 'makefileTypes', 'useStoredEditor', 'editorMaximized', 'useFullscreen', 'showHidden', 'infoItems', 'hashChecker', 'autoFocusDialog', 'clearBrowserData'];
if (!fm.cookieEnabled) {
delete cats.language;
}
forms = fm.arrayFlip(forms, true);
if (fm.options.getFileCallback) {
delete forms.selectAction;
}
if (!fm.UA.Fullscreen) {
delete forms.useFullscreen;
}
forms.language && (forms.language = (function() {
var langSel = $('<select></select>').on('change', function() {
var lang = $(this).val();
fm.storage('lang', lang);
$('#'+fm.id).elfinder('reload');
}),
optTags = [],
langs = self.options.langs || {
ar: 'العربية',
bg: 'Български',
ca: 'Català',
cs: 'Čeština',
da: 'Dansk',
de: 'Deutsch',
el: 'Ελληνικά',
en: 'English',
es: 'Español',
fa: 'فارسی',
fo: 'Føroyskt',
fr: 'Français',
fr_CA: 'Français (Canada)',
he: 'עברית',
hr: 'Hrvatski',
hu: 'Magyar',
id: 'Bahasa Indonesia',
it: 'Italiano',
ja: '日本語',
ko: '한국어',
nl: 'Nederlands',
no: 'Norsk',
pl: 'Polski',
pt_BR: 'Português',
ro: 'Română',
ru: 'Pусский',
si: 'සිංහල',
sk: 'Slovenčina',
sl: 'Slovenščina',
sr: 'Srpski',
sv: 'Svenska',
tr: 'Türkçe',
ug_CN: 'ئۇيغۇرچە',
uk: 'Український',
vi: 'Tiếng Việt',
zh_CN: '简体中文',
zh_TW: '正體中文'
};
if (!fm.cookieEnabled) {
return $();
}
$.each(langs, function(lang, name) {
optTags.push('<option value="'+lang+'">'+name+'</option>');
});
return langSel.append(optTags.join('')).val(fm.lang);
})());
forms.theme && (forms.theme = (function() {
var cnt = fm.options.themes? Object.keys(fm.options.themes).length : 0;
if (cnt === 0 || (cnt === 1 && fm.options.themes.default)) {
return null;
}
var themeSel = $('<select></select>').on('change', function() {
var theme = $(this).val();
fm.changeTheme(theme).storage('theme', theme);
}),
optTags = [],
tpl = {
image: '<img class="elfinder-preference-theme elfinder-preference-theme-image" src="$2" />',
link: '<a href="$1" target="_blank" title="$3">$2</a>',
data: '<dt>$1</dt><dd><span class="elfinder-preference-theme elfinder-preference-theme-$0">$2</span></dd>'
},
items = ['image', 'description', 'author', 'email', 'license'],
render = function(key, data) {
},
defBtn = $('<button class="ui-button ui-corner-all ui-widget elfinder-preference-theme-default"></button>').text(fm.i18n('default')).on('click', function(e) {
themeSel.val('default').trigger('change');
}),
list = $('<div class="elfinder-reference-hide-taball"></div>').on('click', 'button', function() {
var val = $(this).data('themeid');
themeSel.val(val).trigger('change');
});
if (!fm.options.themes.default) {
themeSel.append('<option value="default">'+fm.i18n('default')+'</option>');
}
$.each(fm.options.themes, function(id, val) {
var opt = $('<option class="elfinder-theme-option-'+id+'" value="'+id+'">'+fm.i18n(id)+'</option>'),
dsc = $('<fieldset class="ui-widget ui-widget-content ui-corner-all elfinder-theme-list-'+id+'"><legend>'+fm.i18n(id)+'</legend><div><span class="elfinder-spinner"></span></div></fieldset>'),
tm;
themeSel.append(opt);
list.append(dsc);
tm = setTimeout(function() {
dsc.find('span.elfinder-spinner').replaceWith(fm.i18n(['errRead', id]));
}, 10000);
fm.getTheme(id).always(function() {
tm && clearTimeout(tm);
}).done(function(data) {
var link, val = $(), dl = $('<dl></dl>');
link = data.link? tpl.link.replace(/\$1/g, data.link).replace(/\$3/g, fm.i18n('website')) : '$2';
if (data.name) {
opt.html(fm.i18n(data.name));
}
dsc.children('legend').html(link.replace(/\$2/g, fm.i18n(data.name) || id));
$.each(items, function(i, key) {
var t = tpl[key] || tpl.data,
elm;
if (data[key]) {
elm = t.replace(/\$0/g, fm.escape(key)).replace(/\$1/g, fm.i18n(key)).replace(/\$2/g, fm.i18n(data[key]));
if (key === 'image' && data.link) {
elm = $(elm).on('click', function() {
themeSel.val(id).trigger('change');
}).attr('title', fm.i18n('select'));
}
dl.append(elm);
}
});
val = val.add(dl);
val = val.add($('<div class="elfinder-preference-theme-btn"></div>').append($('<button class="ui-button ui-corner-all ui-widget"></button>').data('themeid', id).html(fm.i18n('select'))));
dsc.find('span.elfinder-spinner').replaceWith(val);
}).fail(function() {
dsc.find('span.elfinder-spinner').replaceWith(fm.i18n(['errRead', id]));
});
});
return $('<div></div>').append(themeSel.val(fm.theme && fm.theme.id? fm.theme.id : 'default'), defBtn, list);
})());
forms.toolbarPref && (forms.toolbarPref = (function() {
var pnls = $.map(fm.options.uiOptions.toolbar, function(v) {
return $.isArray(v)? v : null;
}),
tags = [],
hides = fm.storage('toolbarhides') || {};
$.each(pnls, function() {
var cmd = this,
name = fm.i18n('cmd'+cmd);
if (name === 'cmd'+cmd) {
name = fm.i18n(cmd);
}
tags.push('<span class="elfinder-preference-toolbar-item"><label><input type="checkbox" value="'+cmd+'" '+(hides[cmd]? '' : 'checked')+'/>'+name+'</label></span>');
});
return $(tags.join(' ')).on('change', 'input', function() {
var v = $(this).val(),
o = $(this).is(':checked');
if (!o && !hides[v]) {
hides[v] = true;
} else if (o && hides[v]) {
delete hides[v];
}
fm.storage('toolbarhides', hides);
fm.trigger('toolbarpref');
});
})());
forms.iconSize && (forms.iconSize = (function() {
var max = fm.options.uiOptions.cwd.iconsView.sizeMax || 3,
size = fm.storage('iconsize') || fm.options.uiOptions.cwd.iconsView.size || 0,
sld = $('<div class="touch-punch"></div>').slider({
classes: {
'ui-slider-handle': 'elfinder-tabstop',
},
value: size,
max: max,
slide: function(e, ui) {
fm.getUI('cwd').trigger('iconpref', {size: ui.value});
},
change: function(e, ui) {
fm.storage('iconsize', ui.value);
}
});
fm.getUI('cwd').on('iconpref', function(e, data) {
sld.slider('option', 'value', data.size);
});
return sld;
})());
forms.columnPref && (forms.columnPref = (function() {
var cols = fm.options.uiOptions.cwd.listView.columns,
tags = [],
hides = fm.storage('columnhides') || {};
$.each(cols, function() {
var key = this,
name = fm.getColumnName(key);
tags.push('<span class="elfinder-preference-column-item"><label><input type="checkbox" value="'+key+'" '+(hides[key]? '' : 'checked')+'/>'+name+'</label></span>');
});
return $(tags.join(' ')).on('change', 'input', function() {
var v = $(this).val(),
o = $(this).is(':checked');
if (!o && !hides[v]) {
hides[v] = true;
} else if (o && hides[v]) {
delete hides[v];
}
fm.storage('columnhides', hides);
fm.trigger('columnpref', { repaint: true });
});
})());
forms.selectAction && (forms.selectAction = (function() {
var actSel = $('<select></select>').on('change', function() {
var act = $(this).val();
fm.storage('selectAction', act === 'default'? null : act);
}),
optTags = [],
acts = self.options.selectActions,
defAct = fm.getCommand('open').options.selectAction || 'open';
if ($.inArray(defAct, acts) === -1) {
acts.unshift(defAct);
}
$.each(acts, function(i, act) {
var names = $.map(act.split('/'), function(cmd) {
var name = fm.i18n('cmd'+cmd);
if (name === 'cmd'+cmd) {
name = fm.i18n(cmd);
}
return name;
});
optTags.push('<option value="'+act+'">'+names.join('/')+'</option>');
});
return actSel.append(optTags.join('')).val(fm.storage('selectAction') || defAct);
})());
forms.makefileTypes && (forms.makefileTypes = (function() {
var hides = fm.getCommand('edit').getMkfileHides(),
getTag = function() {
var tags = [];
// re-assign hides
hides = fm.getCommand('edit').getMkfileHides();
$.each(fm.mimesCanMakeEmpty, function(mime, type) {
var name = fm.getCommand('mkfile').getTypeName(mime, type);
tags.push('<span class="elfinder-preference-column-item" title="'+fm.escape(name)+'"><label><input type="checkbox" value="'+mime+'" '+(hides[mime]? '' : 'checked')+'/>'+type+'</label></span>');
});
return tags.join(' ');
},
elm = $('<div></div>').on('change', 'input', function() {
var v = $(this).val(),
o = $(this).is(':checked');
if (!o && !hides[v]) {
hides[v] = true;
} else if (o && hides[v]) {
delete hides[v];
}
fm.storage('mkfileHides', hides);
fm.trigger('canMakeEmptyFile');
}).append(getTag()),
add = $('<div></div>').append(
$('<input type="text" placeholder="'+fm.i18n('typeOfTextfile')+'"/>').on('keydown', function(e) {
(e.keyCode === $.ui.keyCode.ENTER) && $(this).next().trigger('click');
}),
$('<button class="ui-button"></button>').html(fm.i18n('add')).on('click', function() {
var input = $(this).prev(),
val = input.val(),
uiToast = fm.getUI('toast'),
err = function() {
uiToast.appendTo(input.closest('.ui-dialog'));
fm.toast({
msg: fm.i18n('errUsupportType'),
mode: 'warning',
onHidden: function() {
uiToast.children().length === 1 && uiToast.appendTo(fm.getUI());
}
});
input.trigger('focus');
return false;
},
tmpMimes;
if (!val.match(/\//)) {
val = fm.arrayFlip(fm.mimeTypes)[val];
if (!val) {
return err();
}
input.val(val);
}
if (!fm.mimeIsText(val) || !fm.mimeTypes[val]) {
return err();
}
fm.trigger('canMakeEmptyFile', {mimes: [val], unshift: true});
tmpMimes = {};
tmpMimes[val] = fm.mimeTypes[val];
fm.storage('mkfileTextMimes', Object.assign(tmpMimes, fm.storage('mkfileTextMimes') || {}));
input.val('');
uiToast.appendTo(input.closest('.ui-dialog'));
fm.toast({
msg: fm.i18n(['complete', val + ' (' + tmpMimes[val] + ')']),
onHidden: function() {
uiToast.children().length === 1 && uiToast.appendTo(fm.getUI());
}
});
}),
$('<button class="ui-button"></button>').html(fm.i18n('reset')).on('click', function() {
fm.one('canMakeEmptyFile', {done: function() {
elm.empty().append(getTag());
}});
fm.trigger('canMakeEmptyFile', {resetTexts: true});
})
),
tm;
fm.bind('canMakeEmptyFile', {done: function(e) {
if (e.data && e.data.mimes && e.data.mimes.length) {
elm.empty().append(getTag());
}
}});
return $('<div></div>').append(elm, add);
})());
forms.useStoredEditor && (forms.useStoredEditor = $('<input type="checkbox"/>').prop('checked', (function() {
var s = fm.storage('useStoredEditor');
return s? (s > 0) : fm.options.commandsOptions.edit.useStoredEditor;
})()).on('change', function(e) {
fm.storage('useStoredEditor', $(this).is(':checked')? 1 : -1);
}));
forms.editorMaximized && (forms.editorMaximized = $('<input type="checkbox"/>').prop('checked', (function() {
var s = fm.storage('editorMaximized');
return s? (s > 0) : fm.options.commandsOptions.edit.editorMaximized;
})()).on('change', function(e) {
fm.storage('editorMaximized', $(this).is(':checked')? 1 : -1);
}));
forms.useFullscreen && (forms.useFullscreen = $('<input type="checkbox"/>').prop('checked', (function() {
var s = fm.storage('useFullscreen');
return s? (s > 0) : fm.options.commandsOptions.fullscreen.mode === 'screen';
})()).on('change', function(e) {
fm.storage('useFullscreen', $(this).is(':checked')? 1 : -1);
}));
if (forms.showHidden) {
(function() {
var setTitle = function() {
var s = fm.storage('hide'),
t = [],
v;
if (s && s.items) {
$.each(s.items, function(h, n) {
t.push(fm.escape(n));
});
}
elms.prop('disabled', !t.length)[t.length? 'removeClass' : 'addClass']('ui-state-disabled');
v = t.length? t.join('\n') : '';
forms.showHidden.attr('title',v);
useTooltip && forms.showHidden.tooltip('option', 'content', v.replace(/\n/g, '<br>')).tooltip('close');
},
chk = $('<input type="checkbox"/>').prop('checked', (function() {
var s = fm.storage('hide');
return s && s.show;
})()).on('change', function(e) {
var o = {};
o[$(this).is(':checked')? 'show' : 'hide'] = true;
fm.exec('hide', void(0), o);
}),
btn = $('<button class="ui-button ui-corner-all ui-widget"></button>').append(fm.i18n('reset')).on('click', function() {
fm.exec('hide', void(0), {reset: true});
$(this).parent().find('input:first').prop('checked', false);
setTitle();
}),
elms = $().add(chk).add(btn),
useTooltip;
forms.showHidden = $('<div></div>').append(chk, btn);
fm.bind('hide', function(e) {
var d = e.data;
if (!d.opts || (!d.opts.show && !d.opts.hide)) {
setTitle();
}
});
if (fm.UA.Mobile && $.fn.tooltip) {
useTooltip = true;
forms.showHidden.tooltip({
classes: {
'ui-tooltip': 'elfinder-ui-tooltip ui-widget-shadow'
},
tooltipClass: 'elfinder-ui-tooltip ui-widget-shadow',
track: true
}).css('user-select', 'none');
btn.css('user-select', 'none');
}
setTitle();
})();
}
forms.infoItems && (forms.infoItems = (function() {
var items = fm.getCommand('info').items,
tags = [],
hides = fm.storage('infohides') || fm.arrayFlip(fm.options.commandsOptions.info.hideItems, true);
$.each(items, function() {
var key = this,
name = fm.i18n(key);
tags.push('<span class="elfinder-preference-info-item"><label><input type="checkbox" value="'+key+'" '+(hides[key]? '' : 'checked')+'/>'+name+'</label></span>');
});
return $(tags.join(' ')).on('change', 'input', function() {
var v = $(this).val(),
o = $(this).is(':checked');
if (!o && !hides[v]) {
hides[v] = true;
} else if (o && hides[v]) {
delete hides[v];
}
fm.storage('infohides', hides);
fm.trigger('infopref', { repaint: true });
});
})());
forms.hashChecker && fm.hashCheckers.length && (forms.hashChecker = (function() {
var tags = [],
enabled = fm.arrayFlip(fm.storage('hashchekcer') || fm.options.commandsOptions.info.showHashAlgorisms, true);
$.each(fm.hashCheckers, function() {
var cmd = this,
name = fm.i18n(cmd);
tags.push('<span class="elfinder-preference-hashchecker-item"><label><input type="checkbox" value="'+cmd+'" '+(enabled[cmd]? 'checked' : '')+'/>'+name+'</label></span>');
});
return $(tags.join(' ')).on('change', 'input', function() {
var v = $(this).val(),
o = $(this).is(':checked');
if (o) {
enabled[v] = true;
} else if (enabled[v]) {
delete enabled[v];
}
fm.storage('hashchekcer', $.grep(fm.hashCheckers, function(v) {
return enabled[v];
}));
});
})());
forms.autoFocusDialog && (forms.autoFocusDialog = $('<input type="checkbox"/>').prop('checked', (function() {
var s = fm.storage('autoFocusDialog');
return s? (s > 0) : fm.options.uiOptions.dialog.focusOnMouseOver;
})()).on('change', function(e) {
fm.storage('autoFocusDialog', $(this).is(':checked')? 1 : -1);
}));
forms.clearBrowserData && (forms.clearBrowserData = $('<button></button>').text(fm.i18n('reset')).button().on('click', function(e) {
e.preventDefault();
fm.storage();
$('#'+fm.id).elfinder('reload');
}));
$.each(cats, function(id, prefs) {
var dls, found;
if (prefs === true) {
found = 1;
} else if (prefs) {
dls = $();
$.each(prefs, function(i, n) {
var f, title, chks = '', cbox;
if (f = forms[n]) {
found = 2;
title = fm.i18n(n);
cbox = $(f).filter('input[type="checkbox"]');
if (!cbox.length) {
cbox = $(f).find('input[type="checkbox"]');
}
if (cbox.length === 1) {
if (!cbox.attr('id')) {
cbox.attr('id', 'elfinder-preference-'+n+'-checkbox');
}
title = '<label for="'+cbox.attr('id')+'">'+title+'</label>';
} else if (cbox.length > 1) {
chks = ' elfinder-preference-checkboxes';
}
dls = dls.add($('<dt class="elfinder-preference-'+n+chks+'">'+title+'</dt>')).add($('<dd class="elfinder-preference-'+n+chks+'"></dd>').append(f));
}
});
}
if (found) {
ul.append(tab[r](/\{id\}/g, id)[r](/\{title\}/, fm.i18n(id))[r](/\{class\}/, openTab === id? 'elfinder-focus' : ''));
if (found === 2) {
tabs.append(
$('<div id="'+fm.namespace+'-preference-'+id+'" class="elfinder-preference-content"></div>')
.hide()
.append($('<dl></dl>').append(dls))
);
}
}
});
ul.on('click', 'a', function(e) {
var t = $(e.target),
h = t.attr('href');
e.preventDefault();
e.stopPropagation();
ul.children().removeClass(clTabActive);
t.removeClass('ui-state-hover').parent().addClass(clTabActive);
if (h.match(/all$/)) {
tabs.addClass('elfinder-preference-taball').children().show();
} else {
tabs.removeClass('elfinder-preference-taball').children().hide();
$(h).show();
}
}).on('focus blur', 'a', function(e) {
$(this).parent().toggleClass('ui-state-focus', e.type === 'focusin');
}).on('mouseenter mouseleave', 'li', function(e) {
$(this).toggleClass('ui-state-hover', e.type === 'mouseenter');
});
tabs.find('a,input,select,button').addClass('elfinder-tabstop');
base.append(ul, tabs);
dialog = self.fmDialog(base, {
title : self.title,
width : self.options.width || 600,
height: self.options.height || 400,
maxWidth: 'window',
maxHeight: 'window',
autoOpen : false,
destroyOnClose : false,
allowMinimize : false,
open : function() {
openTab && selectTab(openTab);
openTab = null;
},
resize : function() {
tabs.height(dialog.height() - ul.outerHeight(true) - (tabs.outerHeight(true) - tabs.height()) - 5);
}
})
.on('click', function(e) {
e.stopPropagation();
})
.css({
overflow: 'hidden'
});
dialog.closest('.ui-dialog')
.css({
overflow: 'hidden'
})
.addClass('elfinder-bg-translucent');
openTab = 'all';
},
dialog, openTab;
this.shortcuts = [{
pattern : 'ctrl+comma',
description : this.title
}];
this.alwaysEnabled = true;
this.getstate = function() {
return 0;
};
this.exec = function(sel, cOpts) {
!dialog && build();
if (cOpts) {
if (cOpts.tab) {
selectTab(cOpts.tab);
} else if (cOpts._currentType === 'cwd') {
selectTab('workspace');
}
}
dialog.elfinderdialog('open');
return $.Deferred().resolve();
};
};
@@ -0,0 +1,885 @@
/**
* @class elFinder command "quicklook"
* Fast preview for some files types
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.quicklook = function() {
"use strict";
var self = this,
fm = self.fm,
/**
* window closed state
*
* @type Number
**/
closed = 0,
/**
* window animated state
*
* @type Number
**/
animated = 1,
/**
* window opened state
*
* @type Number
**/
opened = 2,
/**
* window docked state
*
* @type Number
**/
docked = 3,
/**
* window docked and hidden state
*
* @type Number
**/
dockedhidden = 4,
/**
* window state
*
* @type Number
**/
state = closed,
/**
* Event name of update
* for fix conflicts with Prototype.JS
*
* `@see https://github.com/Studio-42/elFinder/pull/2346
* @type String
**/
evUpdate = Element.update? 'quicklookupdate' : 'update',
/**
* navbar icon class
*
* @type String
**/
navicon = 'elfinder-quicklook-navbar-icon',
/**
* navbar "fullscreen" icon class
*
* @type String
**/
fullscreen = 'elfinder-quicklook-fullscreen',
/**
* info wrapper class
*
* @type String
*/
infocls = 'elfinder-quicklook-info-wrapper',
/**
* Triger keydown/keypress event with left/right arrow key code
*
* @param Number left/right arrow key code
* @return void
**/
navtrigger = function(code) {
$(document).trigger($.Event('keydown', { keyCode: code, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false }));
},
/**
* Return css for closed window
*
* @param jQuery file node in cwd
* @return void
**/
closedCss = function(node) {
var elf = fm.getUI().offset(),
base = (function() {
var target = node.find('.elfinder-cwd-file-wrapper');
return target.length? target : node;
})(),
baseOffset = base.offset() || { top: 0, left: 0 };
return {
opacity : 0,
width : base.width(),
height : base.height() - 30,
top : baseOffset.top - elf.top,
left : baseOffset.left - elf.left
};
},
/**
* Return css for opened window
*
* @return void
**/
openedCss = function() {
var contain = self.options.contain || fm.options.dialogContained,
win = contain? fm.getUI() : $(window),
elf = fm.getUI().offset(),
w = Math.min(width, win.width()-10),
h = Math.min(height, win.height()-80);
return {
opacity : 1,
width : w,
height : h,
top : parseInt((win.height() - h - 60) / 2 + (contain? 0 : win.scrollTop() - elf.top)),
left : parseInt((win.width() - w) / 2 + (contain? 0 : win.scrollLeft() - elf.left))
};
},
mediaNode = {},
support = function(codec, name) {
var node = name || codec.substr(0, codec.indexOf('/')),
media = mediaNode[node]? mediaNode[node] : (mediaNode[node] = document.createElement(node)),
value = false;
try {
value = media.canPlayType && media.canPlayType(codec);
} catch(e) {}
return (value && value !== '' && value != 'no')? true : false;
},
platformWin = (window.navigator.platform.indexOf('Win') != -1),
/**
* Opened window width (from config)
*
* @type Number
**/
width,
/**
* Opened window height (from config)
*
* @type Number
**/
height,
/**
* Previous style before docked
*
* @type String
**/
prevStyle,
/**
* elFinder node
*
* @type jQuery
**/
parent,
/**
* elFinder current directory node
*
* @type jQuery
**/
cwd,
/**
* Current directory hash
*
* @type String
**/
cwdHash,
dockEnabled = false,
navdrag = false,
navmove = false,
navtm = null,
leftKey = $.ui.keyCode.LEFT,
rightKey = $.ui.keyCode.RIGHT,
coverEv = 'mousemove touchstart ' + ('onwheel' in document? 'wheel' : 'onmousewheel' in document? 'mousewheel' : 'DOMMouseScroll'),
title = $('<span class="elfinder-dialog-title elfinder-quicklook-title"></span>'),
icon = $('<div></div>'),
info = $('<div class="elfinder-quicklook-info"></div>'),//.hide(),
cover = $('<div class="ui-front elfinder-quicklook-cover"></div>'),
fsicon = $('<div class="'+navicon+' '+navicon+'-fullscreen"></div>')
.on('click touchstart', function(e) {
if (navmove) {
return;
}
var win = self.window,
full = win.hasClass(fullscreen),
$window = $(window),
resize = function() { self.preview.trigger('changesize'); };
e.stopPropagation();
e.preventDefault();
if (full) {
navStyle = '';
navShow();
win.toggleClass(fullscreen)
.css(win.data('position'));
$window.trigger(self.resize).off(self.resize, resize);
navbar.off('mouseenter mouseleave');
cover.off(coverEv);
} else {
win.toggleClass(fullscreen)
.data('position', {
left : win.css('left'),
top : win.css('top'),
width : win.width(),
height : win.height(),
display: 'block'
})
.removeAttr('style');
$(window).on(self.resize, resize)
.trigger(self.resize);
cover.on(coverEv, function(e) {
if (! navdrag) {
if (e.type === 'mousemove' || e.type === 'touchstart') {
navShow();
navtm = setTimeout(function() {
if (fm.UA.Mobile || navbar.parent().find('.elfinder-quicklook-navbar:hover').length < 1) {
navbar.fadeOut('slow', function() {
cover.show();
});
}
}, 3000);
}
if (cover.is(':visible')) {
coverHide();
cover.data('tm', setTimeout(function() {
cover.show();
}, 3000));
}
}
}).show().trigger('mousemove');
navbar.on('mouseenter mouseleave', function(e) {
if (! navdrag) {
if (e.type === 'mouseenter') {
navShow();
} else {
cover.trigger('mousemove');
}
}
});
}
if (fm.zIndex) {
win.css('z-index', fm.zIndex + 1);
}
if (fm.UA.Mobile) {
navbar.attr('style', navStyle);
} else {
navbar.attr('style', navStyle).draggable(full ? 'destroy' : {
start: function() {
navdrag = true;
navmove = true;
cover.show();
navShow();
},
stop: function() {
navdrag = false;
navStyle = self.navbar.attr('style');
requestAnimationFrame(function() {
navmove = false;
});
}
});
}
$(this).toggleClass(navicon+'-fullscreen-off');
var collection = win;
if (parent.is('.ui-resizable')) {
collection = collection.add(parent);
}
collection.resizable(full ? 'enable' : 'disable').removeClass('ui-state-disabled');
win.trigger('viewchange');
}
),
updateOnSel = function() {
self.update(void(0), (function() {
var fm = self.fm,
files = fm.selectedFiles(),
cnt = files.length,
inDock = self.docked(),
getInfo = function() {
var ts = 0;
$.each(files, function(i, f) {
var t = parseInt(f.ts);
if (ts >= 0) {
if (t > ts) {
ts = t;
}
} else {
ts = 'unknown';
}
});
return {
hash : files[0].hash + '/' + (+new Date()),
name : fm.i18n('items') + ': ' + cnt,
mime : 'group',
size : spinner,
ts : ts,
files : $.map(files, function(f) { return f.hash; }),
getSize : true
};
};
if (! cnt) {
cnt = 1;
files = [fm.cwd()];
}
return (cnt === 1)? files[0] : getInfo();
})());
},
navShow = function() {
if (self.window.hasClass(fullscreen)) {
navtm && clearTimeout(navtm);
navtm = null;
// if use `show()` it make infinite loop with old jQuery (jQuery/jQuery UI: 1.8.0/1.9.0)
// see #1478 https://github.com/Studio-42/elFinder/issues/1478
navbar.stop(true, true).css('display', 'block');
coverHide();
}
},
coverHide = function() {
cover.data('tm') && clearTimeout(cover.data('tm'));
cover.removeData('tm');
cover.hide();
},
prev = $('<div class="'+navicon+' '+navicon+'-prev"></div>').on('click touchstart', function(e) { ! navmove && navtrigger(leftKey); return false; }),
next = $('<div class="'+navicon+' '+navicon+'-next"></div>').on('click touchstart', function(e) { ! navmove && navtrigger(rightKey); return false; }),
navbar = $('<div class="elfinder-quicklook-navbar"></div>')
.append(prev)
.append(fsicon)
.append(next)
.append('<div class="elfinder-quicklook-navbar-separator"></div>')
.append($('<div class="'+navicon+' '+navicon+'-close"></div>').on('click touchstart', function(e) { ! navmove && self.window.trigger('close'); return false; }))
,
titleClose = $('<span class="ui-front ui-icon elfinder-icon-close ui-icon-closethick"></span>').on('mousedown', function(e) {
e.stopPropagation();
self.window.trigger('close');
}),
titleDock = $('<span class="ui-front ui-icon elfinder-icon-minimize ui-icon-minusthick"></span>').on('mousedown', function(e) {
e.stopPropagation();
if (! self.docked()) {
self.window.trigger('navdockin');
} else {
self.window.trigger('navdockout');
}
}),
spinner = '<span class="elfinder-spinner-text">' + fm.i18n('calc') + '</span>' + '<span class="elfinder-spinner"></span>',
navStyle = '',
init = true,
dockHeight, getSize, tm4cwd, dockedNode, selectTm;
/**
* Any flags for each plugin
*/
this.flags = {};
this.cover = cover;
this.evUpdate = evUpdate;
(this.navbar = navbar)._show = navShow;
this.resize = 'resize.'+fm.namespace;
this.info = $('<div></div>').addClass(infocls)
.append(icon)
.append(info);
this.autoPlay = function() {
if (self.opened()) {
return !! self.options[self.docked()? 'dockAutoplay' : 'autoplay'];
}
return false;
};
this.preview = $('<div class="elfinder-quicklook-preview ui-helper-clearfix"></div>')
// clean info/icon
.on('change', function() {
navShow();
navbar.attr('style', navStyle);
self.docked() && navbar.hide();
self.preview.attr('style', '').removeClass('elfinder-overflow-auto');
self.info.attr('style', '').hide();
self.cover.removeClass('elfinder-quicklook-coverbg');
icon.removeAttr('class').attr('style', '');
info.html('');
})
// update info/icon
.on(evUpdate, function(e) {
var preview = self.preview,
file = e.file,
tpl = '<div class="elfinder-quicklook-info-data">{value}</div>',
update = function() {
var win = self.window.css('overflow', 'hidden');
name = fm.escape(file.i18 || file.name);
!file.read && e.stopImmediatePropagation();
self.window.data('hash', file.hash);
self.preview.off('changesize').trigger('change').children().remove();
title.html(name);
prev.css('visibility', '');
next.css('visibility', '');
if (file.hash === fm.cwdId2Hash(cwd.find('[id]:not(.elfinder-cwd-parent):first').attr('id'))) {
prev.css('visibility', 'hidden');
}
if (file.hash === fm.cwdId2Hash(cwd.find('[id]:last').attr('id'))) {
next.css('visibility', 'hidden');
}
if (file.mime === 'directory') {
getSizeHashes = [ file.hash ];
} else if (file.mime === 'group' && file.getSize) {
getSizeHashes = file.files;
}
info.html(
tpl.replace(/\{value\}/, name)
+ tpl.replace(/\{value\}/, fm.mime2kind(file))
+ tpl.replace(/\{value\}/, getSizeHashes.length ? spinner : fm.formatSize(file.size))
+ tpl.replace(/\{value\}/, fm.i18n('modify')+': '+ fm.formatDate(file))
);
if (getSizeHashes.length) {
getSize = fm.getSize(getSizeHashes).done(function(data) {
info.find('span.elfinder-spinner').parent().html(data.formated);
}).fail(function() {
info.find('span.elfinder-spinner').parent().html(fm.i18n('unknown'));
}).always(function() {
getSize = null;
});
getSize._hash = file.hash;
}
icon.addClass('elfinder-cwd-icon ui-corner-all '+fm.mime2class(file.mime));
if (file.icon) {
icon.css(fm.getIconStyle(file, true));
}
self.info.attr('class', infocls);
if (file.csscls) {
self.info.addClass(file.csscls);
}
if (file.read && (tmb = fm.tmb(file))) {
$('<img/>')
.hide()
.appendTo(self.preview)
.on('load', function() {
icon.addClass(tmb.className).css('background-image', "url('"+tmb.url+"')");
$(this).remove();
})
.attr('src', tmb.url);
}
self.info.delay(100).fadeIn(10);
if (self.window.hasClass(fullscreen)) {
cover.trigger('mousemove');
}
win.css('overflow', '');
},
tmb, name, getSizeHashes = [];
if (file && ! Object.keys(file).length) {
file = fm.cwd();
}
if (file && getSize && getSize.state() === 'pending' && getSize._hash !== file.hash) {
getSize.reject();
}
if (file && (e.forceUpdate || self.window.data('hash') !== file.hash)) {
update();
} else {
e.stopImmediatePropagation();
}
});
this.window = $('<div class="ui-front ui-helper-reset ui-widget elfinder-quicklook touch-punch" style="position:absolute"></div>')
.hide()
.addClass(fm.UA.Touch? 'elfinder-touch' : '')
.on('click', function(e) {
var win = this;
e.stopPropagation();
if (state === opened) {
requestAnimationFrame(function() {
state === opened && fm.toFront(win);
});
}
})
.append(
$('<div class="ui-dialog-titlebar ui-widget-header ui-corner-top ui-helper-clearfix elfinder-quicklook-titlebar"></div>')
.append(
$('<span class="ui-widget-header ui-dialog-titlebar-close ui-corner-all elfinder-titlebar-button elfinder-quicklook-titlebar-icon'+(platformWin? ' elfinder-titlebar-button-right' : '')+'"></span>').append(
titleClose, titleDock
),
title
),
this.preview,
self.info.hide(),
cover.hide(),
navbar
)
.draggable({handle : 'div.elfinder-quicklook-titlebar'})
.on('open', function(e, clcss) {
var win = self.window,
file = self.value,
node = fm.getUI('cwd'),
open = function(status) {
state = status;
self.update(1, self.value);
self.change();
win.trigger('resize.' + fm.namespace);
};
if (!init && state === closed) {
if (file && file.hash !== cwdHash) {
node = fm.cwdHash2Elm(file.hash.split('/', 2)[0]);
}
navStyle = '';
navbar.attr('style', '');
state = animated;
node.trigger('scrolltoview');
coverHide();
win.css(clcss || closedCss(node))
.show()
.animate(openedCss(), 550, function() {
open(opened);
navShow();
});
fm.toFront(win);
} else if (state === dockedhidden) {
fm.getUI('navdock').data('addNode')(dockedNode);
open(docked);
self.preview.trigger('changesize');
fm.storage('previewDocked', '1');
if (fm.getUI('navdock').width() === 0) {
win.trigger('navdockout');
}
}
})
.on('close', function(e, dfd) {
var win = self.window,
preview = self.preview.trigger('change'),
file = self.value,
hash = (win.data('hash') || '').split('/', 2)[0],
close = function(status, winhide) {
state = status;
winhide && fm.toHide(win);
preview.children().remove();
self.update(0, self.value);
win.data('hash', '');
dfd && dfd.resolve();
},
node;
if (self.opened()) {
getSize && getSize.state() === 'pending' && getSize.reject();
if (! self.docked()) {
state = animated;
win.hasClass(fullscreen) && fsicon.click();
(hash && (node = cwd.find('#'+hash)).length)
? win.animate(closedCss(node), 500, function() {
preview.off('changesize');
close(closed, true);
})
: close(closed, true);
} else {
dockedNode = fm.getUI('navdock').data('removeNode')(self.window.attr('id'), 'detach');
close(dockedhidden);
fm.storage('previewDocked', '2');
}
}
})
.on('navdockin', function(e, data) {
var w = self.window,
box = fm.getUI('navdock'),
height = dockHeight || box.width(),
opts = data || {};
if (init) {
opts.init = true;
}
state = docked;
prevStyle = w.attr('style');
w.toggleClass('ui-front').removeClass('ui-widget').draggable('disable').resizable('disable').removeAttr('style').css({
width: '100%',
height: height,
boxSizing: 'border-box',
paddingBottom: 0,
zIndex: 'unset'
});
navbar.hide();
titleDock.toggleClass('ui-icon-plusthick ui-icon-minusthick elfinder-icon-full elfinder-icon-minimize');
fm.toHide(w, true);
box.data('addNode')(w, opts);
self.preview.trigger('changesize');
fm.storage('previewDocked', '1');
})
.on('navdockout', function(e) {
var w = self.window,
box = fm.getUI('navdock'),
dfd = $.Deferred(),
clcss = closedCss(self.preview);
dockHeight = w.outerHeight();
box.data('removeNode')(w.attr('id'), fm.getUI());
w.toggleClass('ui-front').addClass('ui-widget').draggable('enable').resizable('enable').attr('style', prevStyle);
titleDock.toggleClass('ui-icon-plusthick ui-icon-minusthick elfinder-icon-full elfinder-icon-minimize');
state = closed;
w.trigger('open', clcss);
fm.storage('previewDocked', '0');
})
.on('resize.' + fm.namespace, function() {
self.preview.trigger('changesize');
});
/**
* This command cannot be disable by backend
*
* @type Boolean
**/
this.alwaysEnabled = true;
/**
* Selected file
*
* @type Object
**/
this.value = null;
this.handlers = {
// save selected file
select : function(e, d) {
selectTm && cancelAnimationFrame(selectTm);
if (! e.data || ! e.data.selected || ! e.data.selected.length) {
selectTm = requestAnimationFrame(function() {
self.opened() && updateOnSel();
});
} else {
self.opened() && updateOnSel();
}
},
error : function() { self.window.is(':visible') && self.window.trigger('close'); },
'searchshow searchhide' : function() { this.opened() && this.window.trigger('close'); },
navbarshow : function() {
requestAnimationFrame(function() {
self.docked() && self.preview.trigger('changesize');
});
},
destroy : function() { self.window.remove(); }
};
this.shortcuts = [{
pattern : 'space'
}];
this.support = {
audio : {
ogg : support('audio/ogg;'),
webm: support('audio/webm;'),
mp3 : support('audio/mpeg;'),
wav : support('audio/wav;'),
m4a : support('audio/mp4;') || support('audio/x-m4a;') || support('audio/aac;'),
flac: support('audio/flac;'),
amr : support('audio/amr;')
},
video : {
ogg : support('video/ogg;'),
webm : support('video/webm;'),
mp4 : support('video/mp4;'),
mkv : support('video/x-matroska;') || support('video/webm;'),
'3gp': support('video/3gpp;') || support('video/mp4;'), // try as mp4
m3u8 : support('application/x-mpegURL', 'video') || support('application/vnd.apple.mpegURL', 'video'),
mpd : support('application/dash+xml', 'video')
}
};
// for GC
mediaNode = {};
/**
* Return true if quickLoock window is hiddenReturn true if quickLoock window is visible and not animated
*
* @return Boolean
**/
this.closed = function() {
return (state == closed || state == dockedhidden);
};
/**
* Return true if quickLoock window is visible and not animated
*
* @return Boolean
**/
this.opened = function() {
return state == opened || state == docked;
};
/**
* Return true if quickLoock window is in NavDock
*
* @return Boolean
**/
this.docked = function() {
return state == docked;
};
/**
* Adds an integration into help dialog.
*
* @param Object opts options
*/
this.addIntegration = function(opts) {
requestAnimationFrame(function() {
fm.trigger('helpIntegration', Object.assign({cmd: 'quicklook'}, opts));
});
};
/**
* Init command.
* Add default plugins and init other plugins
*
* @return Object
**/
this.init = function() {
var o = this.options,
win = this.window,
preview = this.preview,
i, p, cwdDispInlineRegex;
width = o.width > 0 ? parseInt(o.width) : 450;
height = o.height > 0 ? parseInt(o.height) : 300;
if (o.dockHeight !== 'auto') {
dockHeight = parseInt(o.dockHeight);
if (! dockHeight) {
dockHeight = void(0);
}
}
fm.one('load', function() {
dockEnabled = fm.getUI('navdock').data('dockEnabled');
! dockEnabled && titleDock.hide();
parent = fm.getUI();
cwd = fm.getUI('cwd');
if (fm.zIndex) {
win.css('z-index', fm.zIndex + 1);
}
win.appendTo(parent);
// close window on escape
$(document).on('keydown.'+fm.namespace, function(e) {
e.keyCode == $.ui.keyCode.ESCAPE && self.opened() && ! self.docked() && win.hasClass('elfinder-frontmost') && win.trigger('close');
});
win.resizable({
handles : 'se',
minWidth : 350,
minHeight : 120,
resize : function() {
// use another event to avoid recursion in fullscreen mode
// may be there is clever solution, but i cant find it :(
preview.trigger('changesize');
}
});
self.change(function() {
if (self.opened()) {
if (self.value) {
if (self.value.tmb && self.value.tmb == 1) {
// try re-get file object
self.value = Object.assign({}, fm.file(self.value.hash));
}
preview.trigger($.Event(evUpdate, {file : self.value}));
}
}
});
preview.on(evUpdate, function(e) {
var file, hash, serach;
if (file = e.file) {
hash = file.hash;
serach = (fm.searchStatus.mixed && fm.searchStatus.state > 1);
if (file.mime !== 'directory') {
if (parseInt(file.size) || file.mime.match(o.mimeRegexNotEmptyCheck)) {
// set current dispInlineRegex
self.dispInlineRegex = cwdDispInlineRegex;
if (serach || fm.optionsByHashes[hash]) {
try {
self.dispInlineRegex = new RegExp(fm.option('dispInlineRegex', hash), 'i');
} catch(e) {
try {
self.dispInlineRegex = new RegExp(!fm.isRoot(file)? fm.option('dispInlineRegex', file.phash) : fm.options.dispInlineRegex, 'i');
} catch(e) {
self.dispInlineRegex = /^$/;
}
}
}
} else {
// do not preview of file that size = 0
e.stopImmediatePropagation();
}
} else {
self.dispInlineRegex = /^$/;
}
self.info.show();
} else {
e.stopImmediatePropagation();
}
});
$.each(fm.commands.quicklook.plugins || [], function(i, plugin) {
if (typeof(plugin) == 'function') {
new plugin(self);
}
});
}).one('open', function() {
var dock = Number(fm.storage('previewDocked') || o.docked),
win;
if (dockEnabled && dock >= 1) {
win = self.window;
self.exec();
win.trigger('navdockin', { init : true });
if (dock === 2) {
win.trigger('close');
} else {
self.update(void(0), fm.cwd());
self.change();
}
}
init = false;
}).bind('open', function() {
cwdHash = fm.cwd().hash;
self.value = fm.cwd();
// set current volume dispInlineRegex
try {
cwdDispInlineRegex = new RegExp(fm.option('dispInlineRegex'), 'i');
} catch(e) {
cwdDispInlineRegex = /^$/;
}
}).bind('change', function(e) {
if (e.data && e.data.changed && self.opened()) {
$.each(e.data.changed, function() {
if (self.window.data('hash') === this.hash) {
self.window.data('hash', null);
self.preview.trigger(evUpdate);
return false;
}
});
}
}).bind('navdockresizestart navdockresizestop', function(e) {
cover[e.type === 'navdockresizestart'? 'show' : 'hide']();
});
};
this.getstate = function() {
return self.opened()? 1 : 0;
};
this.exec = function() {
self.closed() && updateOnSel();
self.enabled() && self.window.trigger(self.opened() ? 'close' : 'open');
return $.Deferred().resolve();
};
this.hideinfo = function() {
this.info.stop(true, true).hide();
};
}).prototype = { forceLoad : true }; // this is required command
@@ -0,0 +1,72 @@
/**
* @class elFinder command "reload"
* Sync files and folders
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.reload = function() {
"use strict";
var self = this,
search = false;
this.alwaysEnabled = true;
this.updateOnSelect = true;
this.shortcuts = [{
pattern : 'ctrl+shift+r f5'
}];
this.getstate = function() {
return 0;
};
this.init = function() {
this.fm.bind('search searchend', function() {
search = this.type == 'search';
});
};
this.fm.bind('contextmenu', function(){
var fm = self.fm;
if (fm.options.sync >= 1000) {
self.extra = {
icon: 'accept',
node: $('<span></span>')
.attr({title: fm.i18n('autoSync')})
.on('click touchstart', function(e){
if (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
return;
}
e.stopPropagation();
e.preventDefault();
$(this).parent()
.toggleClass('ui-state-disabled', fm.options.syncStart)
.parent().removeClass('ui-state-hover');
fm.options.syncStart = !fm.options.syncStart;
fm.autoSync(fm.options.syncStart? null : 'stop');
}).on('ready', function(){
$(this).parent().toggleClass('ui-state-disabled', !fm.options.syncStart).css('pointer-events', 'auto');
})
};
}
});
this.exec = function() {
var fm = this.fm;
if (!search) {
var dfrd = fm.sync(),
timeout = setTimeout(function() {
fm.notify({type : 'reload', cnt : 1, hideCnt : true});
dfrd.always(function() { fm.notify({type : 'reload', cnt : -1}); });
}, fm.notifyDelay);
return dfrd.always(function() {
clearTimeout(timeout);
fm.trigger('reload');
});
} else {
$('div.elfinder-toolbar > div.'+fm.res('class', 'searchbtn') + ' > span.ui-icon-search').click();
}
};
}).prototype = { forceLoad : true }; // this is required command
@@ -0,0 +1,583 @@
/**
* @class elFinder command "rename".
* Rename selected file.
*
* @author Dmitry (dio) Levashov, dio@std42.ru
* @author Naoki Sawada
**/
elFinder.prototype.commands.rename = function() {
"use strict";
// set alwaysEnabled to allow root rename on client size
this.alwaysEnabled = true;
this.syncTitleOnChange = true;
var self = this,
fm = self.fm,
request = function(dfrd, targtes, file, name) {
var sel = targtes? [file.hash].concat(targtes) : [file.hash],
cnt = sel.length,
data = {}, rootNames;
fm.lockfiles({files : sel});
if (fm.isRoot(file) && !file.netkey) {
if (!(rootNames = fm.storage('rootNames'))) {
rootNames = {};
}
if (name === '') {
if (rootNames[file.hash]) {
file.name = file._name;
file.i18 = file._i18;
delete rootNames[file.hash];
delete file._name;
delete file._i18;
} else {
dfrd && dfrd.reject();
fm.unlockfiles({files : sel}).trigger('selectfiles', {files : sel});
return;
}
} else {
if (typeof file._name === 'undefined') {
file._name = file.name;
file._i18 = file.i18;
}
file.name = rootNames[file.hash] = name;
delete file.i18;
}
fm.storage('rootNames', rootNames);
data = { changed: [file] };
fm.updateCache(data);
fm.change(data);
dfrd && dfrd.resolve(data);
fm.unlockfiles({files : sel}).trigger('selectfiles', {files : sel});
return;
}
data = {
cmd : 'rename',
name : name,
target : file.hash
};
if (cnt > 1) {
data['targets'] = targtes;
if (name.match(/\*/)) {
data['q'] = name;
}
}
fm.request({
data : data,
notify : {type : 'rename', cnt : cnt},
navigate : {}
})
.fail(function(error) {
var err = fm.parseError(error);
dfrd && dfrd.reject();
if (! err || ! Array.isArray(err) || err[0] !== 'errRename') {
fm.sync();
}
})
.done(function(data) {
var cwdHash;
if (data.added && data.added.length && cnt === 1) {
data.undo = {
cmd : 'rename',
callback : function() {
return fm.request({
data : {cmd : 'rename', target : data.added[0].hash, name : file.name},
notify : {type : 'undo', cnt : 1}
});
}
};
data.redo = {
cmd : 'rename',
callback : function() {
return fm.request({
data : {cmd : 'rename', target : file.hash, name : name},
notify : {type : 'rename', cnt : 1}
});
}
};
}
dfrd && dfrd.resolve(data);
if (!(cwdHash = fm.cwd().hash) || cwdHash === file.hash) {
fm.exec('open', $.map(data.added, function(f) {
return (f.mime === 'directory')? f.hash : null;
})[0]);
}
})
.always(function() {
fm.unlockfiles({files : sel}).trigger('selectfiles', {files : sel});
}
);
},
getHint = function(name, target) {
var sel = target || fm.selected(),
splits = fm.splitFileExtention(name),
f1 = fm.file(sel[0]),
f2 = fm.file(sel[1]),
ext, hint, add;
ext = splits[1]? ('.' + splits[1]) : '';
if (splits[1] && splits[0] === '*') {
// change extention
hint = '"' + fm.splitFileExtention(f1.name)[0] + ext + '", ';
hint += '"' + fm.splitFileExtention(f2.name)[0] + ext + '"';
} else if (splits[0].length > 1) {
if (splits[0].substr(-1) === '*') {
// add prefix
add = splits[0].substr(0, splits[0].length - 1);
hint = '"' + add + f1.name+'", ';
hint += '"' + add + f2.name+'"';
} else if (splits[0].substr(0, 1) === '*') {
// add suffix
add = splits[0].substr(1);
hint = '"'+fm.splitFileExtention(f1.name)[0] + add + ext + '", ';
hint += '"'+fm.splitFileExtention(f2.name)[0] + add + ext + '"';
}
}
if (!hint) {
hint = '"'+splits[0] + '1' + ext + '", "' + splits[0] + '2' + ext + '"';
}
if (sel.length > 2) {
hint += ' ...';
}
return hint;
},
batchRename = function() {
var sel = fm.selected(),
tplr = '<input name="type" type="radio" class="elfinder-tabstop">',
mkChk = function(node, label) {
return $('<label class="elfinder-rename-batch-checks">' + fm.i18n(label) + '</label>').prepend(node);
},
name = $('<input type="text" class="ui-corner-all elfinder-tabstop">'),
num = $(tplr),
prefix = $(tplr),
suffix = $(tplr),
extention = $(tplr),
checks = $('<div></div>').append(
mkChk(num, 'plusNumber'),
mkChk(prefix, 'asPrefix'),
mkChk(suffix, 'asSuffix'),
mkChk(extention, 'changeExtention')
),
preview = $('<div class="elfinder-rename-batch-preview"></div>'),
node = $('<div class="elfinder-rename-batch"></div>').append(
$('<div class="elfinder-rename-batch-name"></div>').append(name),
$('<div class="elfinder-rename-batch-type"></div>').append(checks),
preview
),
opts = {
title : fm.i18n('batchRename'),
modal : true,
destroyOnClose : true,
width: Math.min(380, fm.getUI().width() - 20),
buttons : {},
open : function() {
name.on('input', mkPrev).trigger('focus');
}
},
getName = function() {
var vName = name.val(),
ext = fm.splitFileExtention(fm.file(sel[0]).name)[1];
if (vName !== '' || num.is(':checked')) {
if (prefix.is(':checked')) {
vName += '*';
} else if (suffix.is(':checked')) {
vName = '*' + vName + '.' + ext;
} else if (extention.is(':checked')) {
vName = '*.' + vName;
} else if (ext) {
vName += '.' + ext;
}
}
return vName;
},
mkPrev = function() {
var vName = getName();
if (vName !== '') {
preview.html(fm.i18n(['renameMultiple', sel.length, getHint(vName)]));
} else {
preview.empty();
}
},
radios = checks.find('input:radio').on('change', mkPrev),
dialog;
opts.buttons[fm.i18n('btnApply')] = function() {
var vName = getName(),
file, targets;
if (vName !== '') {
dialog.elfinderdialog('close');
targets = sel;
file = fm.file(targets.shift());
request(void(0), targets, file, vName);
}
};
opts.buttons[fm.i18n('btnCancel')] = function() {
dialog.elfinderdialog('close');
};
if ($.fn.checkboxradio) {
radios.checkboxradio({
create: function(e, ui) {
if (this === num.get(0)) {
num.prop('checked', true).change();
}
}
});
} else {
checks.buttonset({
create: function(e, ui) {
num.prop('checked', true).change();
}
});
}
dialog = self.fmDialog(node, opts);
};
this.noChangeDirOnRemovedCwd = true;
this.shortcuts = [{
pattern : 'f2' + (fm.OS == 'mac' ? ' enter' : '')
}, {
pattern : 'shift+f2',
description : 'batchRename',
callback : function() {
fm.selected().length > 1 && batchRename();
}
}];
this.getstate = function(select) {
var sel = this.files(select),
cnt = sel.length,
phash, ext, mime, brk, state, isRoot;
if (!cnt) {
return -1;
}
if (cnt > 1 && sel[0].phash) {
phash = sel[0].phash;
ext = fm.splitFileExtention(sel[0].name)[1].toLowerCase();
mime = sel[0].mime;
}
if (cnt === 1) {
isRoot = fm.isRoot(sel[0]);
}
state = (cnt === 1 && ((fm.cookieEnabled && isRoot) || !sel[0].locked) || (fm.api > 2.1030 && cnt === $.grep(sel, function(f) {
if (!brk && !f.locked && f.phash === phash && !fm.isRoot(f) && (mime === f.mime || ext === fm.splitFileExtention(f.name)[1].toLowerCase())) {
return true;
} else {
brk && (brk = true);
return false;
}
}).length)) ? 0 : -1;
// because alwaysEnabled = true, it need check disabled on connector
if (!isRoot && state === 0 && fm.option('disabledFlip', sel[0].hash)['rename']) {
state = -1;
}
if (state !== -1 && cnt > 1) {
self.extra = {
icon: 'preference',
node: $('<span></span>')
.attr({title: fm.i18n('batchRename')})
.on('click touchstart', function(e){
if (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
return;
}
e.stopPropagation();
e.preventDefault();
fm.getUI().trigger('click'); // to close the context menu immediately
batchRename();
})
};
} else {
delete self.extra;
}
return state;
};
this.exec = function(hashes, cOpts) {
var cwd = fm.getUI('cwd'),
sel = hashes || (fm.selected().length? fm.selected() : false) || [fm.cwd().hash],
cnt = sel.length,
file = fm.file(sel.shift()),
filename = '.elfinder-cwd-filename',
opts = cOpts || {},
incwd = (fm.cwd().hash == file.hash),
type = (opts._currentType === 'navbar' || opts._currentType === 'files')? opts._currentType : (incwd? 'navbar' : 'files'),
navbar = (type !== 'files'),
target = fm[navbar? 'navHash2Elm' : 'cwdHash2Elm'](file.hash),
tarea = (!navbar && fm.storage('view') != 'list'),
split = function(name) {
var ext = fm.splitFileExtention(name)[1];
return [name.substr(0, name.length - ext.length - 1), ext];
},
unselect = function() {
requestAnimationFrame(function() {
input && input.trigger('blur');
});
},
rest = function(){
if (!overlay.is(':hidden')) {
overlay.elfinderoverlay('hide').off('click close', cancel);
}
pnode.removeClass('ui-front')
.css('position', '')
.off('unselect.'+fm.namespace, unselect);
if (tarea) {
node && node.css('max-height', '');
} else if (!navbar) {
pnode.css('width', '')
.parent('td').css('overflow', '');
}
}, colwidth,
dfrd = $.Deferred()
.fail(function(error) {
var parent = input.parent(),
name = fm.escape(file.i18 || file.name);
input.off();
if (tarea) {
name = name.replace(/([_.])/g, '&#8203;$1');
}
requestAnimationFrame(function() {
if (navbar) {
input.replaceWith(name);
} else {
if (parent.length) {
input.remove();
parent.html(name);
} else {
target.find(filename).html(name);
}
}
});
error && fm.error(error);
})
.always(function() {
rest();
fm.unbind('resize', resize);
fm.enable();
}),
blur = function(e) {
var name = $.trim(input.val()),
splits = fm.splitFileExtention(name),
valid = true,
req = function() {
input.off();
rest();
if (navbar) {
input.replaceWith(fm.escape(name));
} else {
node.html(fm.escape(name));
}
request(dfrd, sel, file, name);
};
if (!overlay.is(':hidden')) {
pnode.css('z-index', '');
}
if (name === '') {
if (!fm.isRoot(file)) {
return cancel();
}
if (navbar) {
input.replaceWith(fm.escape(file.name));
} else {
node.html(fm.escape(file.name));
}
}
if (!inError && pnode.length) {
input.off('blur');
if (cnt === 1 && name === file.name) {
return dfrd.reject();
}
if (fm.options.validName && fm.options.validName.test) {
try {
valid = fm.options.validName.test(name);
} catch(e) {
valid = false;
}
}
if (name === '.' || name === '..' || !valid) {
inError = true;
fm.error(file.mime === 'directory'? 'errInvDirname' : 'errInvName', {modal: true, close: function(){setTimeout(select, 120);}});
return false;
}
if (cnt === 1 && fm.fileByName(name, file.phash)) {
inError = true;
fm.error(['errExists', name], {modal: true, close: function(){setTimeout(select, 120);}});
return false;
}
if (cnt === 1) {
req();
} else {
fm.confirm({
title : 'cmdrename',
text : ['renameMultiple', cnt, getHint(name, [file.hash].concat(sel))],
accept : {
label : 'btnYes',
callback : req
},
cancel : {
label : 'btnCancel',
callback : function() {
setTimeout(function() {
inError = true;
select();
}, 120);
}
}
});
setTimeout(function() {
fm.trigger('unselectfiles', {files: fm.selected()})
.trigger('selectfiles', {files : [file.hash].concat(sel)});
}, 120);
}
}
},
input = $(tarea? '<textarea></textarea>' : '<input type="text"/>')
.on('keyup text', function(){
if (tarea) {
this.style.height = '1px';
this.style.height = this.scrollHeight + 'px';
} else if (colwidth) {
this.style.width = colwidth + 'px';
if (this.scrollWidth > colwidth) {
this.style.width = this.scrollWidth + 10 + 'px';
}
}
})
.on('keydown', function(e) {
e.stopImmediatePropagation();
if (e.keyCode == $.ui.keyCode.ESCAPE) {
dfrd.reject();
} else if (e.keyCode == $.ui.keyCode.ENTER) {
e.preventDefault();
input.trigger('blur');
}
})
.on('mousedown click dblclick', function(e) {
e.stopPropagation();
if (e.type === 'dblclick') {
e.preventDefault();
}
})
.on('blur', blur)
.on('dragenter dragleave dragover drop', function(e) {
// stop bubbling to prevent upload with native drop event
e.stopPropagation();
}),
select = function() {
var name = fm.splitFileExtention(input.val())[0];
if (!inError && fm.UA.Mobile && !fm.UA.iOS) { // since iOS has a bug? (z-index not effect) so disable it
overlay.on('click close', cancel).elfinderoverlay('show');
pnode.css('z-index', overlay.css('z-index') + 1);
}
! fm.enabled() && fm.enable();
if (inError) {
inError = false;
input.on('blur', blur);
}
input.trigger('focus').trigger('select');
input[0].setSelectionRange && input[0].setSelectionRange(0, name.length);
},
node = navbar? target.contents().filter(function(){ return this.nodeType==3 && $(this).parent().attr('id') === fm.navHash2Id(file.hash); })
: target.find(filename),
pnode = node.parent(),
overlay = fm.getUI('overlay'),
cancel = function(e) {
if (!overlay.is(':hidden')) {
pnode.css('z-index', '');
}
if (! inError) {
dfrd.reject();
if (e) {
e.stopPropagation();
e.preventDefault();
}
}
},
resize = function() {
target.trigger('scrolltoview', {blink : false});
},
inError = false;
pnode.addClass('ui-front')
.css('position', 'relative')
.on('unselect.'+fm.namespace, unselect);
fm.bind('resize', resize);
if (navbar) {
node.replaceWith(input.val(file.name));
} else {
if (tarea) {
node.css('max-height', 'none');
} else if (!navbar) {
colwidth = pnode.width();
pnode.width(colwidth - 15)
.parent('td').css('overflow', 'visible');
}
node.empty().append(input.val(file.name));
}
if (cnt > 1 && fm.api <= 2.1030) {
return dfrd.reject();
}
if (!file || !node.length) {
return dfrd.reject('errCmdParams', this.title);
}
if (file.locked && !fm.isRoot(file)) {
return dfrd.reject(['errLocked', file.name]);
}
fm.one('select', function() {
input.parent().length && file && $.inArray(file.hash, fm.selected()) === -1 && input.trigger('blur');
});
input.trigger('keyup');
select();
return dfrd;
};
fm.bind('select contextmenucreate closecontextmenu', function(e) {
var sel = (e.data? (e.data.selected || e.data.targets) : null) || fm.selected(),
file;
if (sel && sel.length === 1 && (file = fm.file(sel[0])) && fm.isRoot(file)) {
self.title = fm.i18n('kindAlias') + ' (' + fm.i18n('preference') + ')';
} else {
self.title = fm.i18n('cmdrename');
}
if (e.type !== 'closecontextmenu') {
self.update(void(0), self.title);
} else {
requestAnimationFrame(function() {
self.update(void(0), self.title);
});
}
}).remove(function(e) {
var rootNames;
if (e.data && e.data.removed && (rootNames = fm.storage('rootNames'))) {
$.each(e.data.removed, function(i, h) {
if (rootNames[h]) {
delete rootNames[h];
}
});
fm.storage('rootNames', rootNames);
}
});
};
@@ -0,0 +1,286 @@
/**
* @class elFinder command "restore"
* Restore items from the trash
*
* @author Naoki Sawada
**/
(elFinder.prototype.commands.restore = function() {
"use strict";
var self = this,
fm = this.fm,
fakeCnt = 0,
getFilesRecursively = function(files) {
var dfd = $.Deferred(),
dirs = [],
results = [],
reqs = [],
phashes = [],
getFile;
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);
});
if (dirs.length) {
$.each(dirs, function(i, d) {
reqs.push(fm.request({
data : {cmd : 'open', target : d.hash},
preventDefault : true,
asNotOpen : true
}));
phashes[i] = d.hash;
});
$.when.apply($, reqs).fail(function() {
dfd.reject();
}).done(function() {
var items = [];
$.each(arguments, function(i, r) {
var files;
if (r.files) {
if (r.files.length) {
items = items.concat(r.files);
} else {
items.push({
hash: 'fakefile_' + (fakeCnt++),
phash: phashes[i],
mime: 'fakefile',
name: 'fakefile',
ts: 0
});
}
}
});
fm.cache(items);
getFile = getFilesRecursively(items).done(function(res) {
results = results.concat(res);
dfd.resolve(results);
});
});
} else {
dfd.resolve(results);
}
return dfd;
},
restore = function(dfrd, files, targets, ops) {
var rHashes = {},
others = [],
found = false,
dirs = [],
opts = ops || {},
id = +new Date(),
tm, getFile;
fm.lockfiles({files : targets});
dirs = $.map(files, function(f) {
return f.mime === 'directory'? f.hash : null;
});
dfrd.done(function() {
dirs && fm.exec('rm', dirs, {forceRm : true, quiet : true});
}).always(function() {
fm.unlockfiles({files : targets});
});
tm = setTimeout(function() {
fm.notify({type : 'search', id : id, cnt : 1, hideCnt : true, cancel : function() {
getFile && getFile._xhrReject();
dfrd.reject();
}});
}, fm.notifyDelay);
fakeCnt = 0;
getFile = getFilesRecursively(files).always(function() {
tm && clearTimeout(tm);
fm.notify({type : 'search', id: id, cnt : -1, hideCnt : true});
}).fail(function() {
dfrd.reject('errRestore', 'errFileNotFound');
}).done(function(res) {
var errFolderNotfound = ['errRestore', 'errFolderNotFound'],
dirTop = '';
if (res.length) {
$.each(res, function(i, f) {
var phash = f.phash,
pfile,
srcRoot, tPath;
while(phash) {
if (srcRoot = fm.trashes[phash]) {
if (! rHashes[srcRoot]) {
if (found) {
// Keep items of other trash
others.push(f.hash);
return null; // continue $.each
}
rHashes[srcRoot] = {};
found = true;
}
tPath = fm.path(f.hash).substr(fm.path(phash).length).replace(/\\/g, '/');
tPath = tPath.replace(/\/[^\/]+?$/, '');
if (tPath === '') {
tPath = '/';
}
if (!rHashes[srcRoot][tPath]) {
rHashes[srcRoot][tPath] = [];
}
if (f.mime === 'fakefile') {
fm.updateCache({removed:[f.hash]});
} else {
rHashes[srcRoot][tPath].push(f.hash);
}
if (!dirTop || dirTop.length > tPath.length) {
dirTop = tPath;
}
break;
}
// Go up one level for next check
pfile = fm.file(phash);
if (!pfile) {
phash = false;
// Detection method for search results
$.each(fm.trashes, function(ph) {
var file = fm.file(ph),
filePath = fm.path(ph);
if ((!file.volumeid || f.hash.indexOf(file.volumeid) === 0) && fm.path(f.hash).indexOf(filePath) === 0) {
phash = ph;
return false;
}
});
} else {
phash = pfile.phash;
}
}
});
if (found) {
$.each(rHashes, function(src, dsts) {
var dirs = Object.keys(dsts),
cnt = dirs.length;
fm.request({
data : {cmd : 'mkdir', target : src, dirs : dirs},
notify : {type : 'chkdir', cnt : cnt},
preventFail : true
}).fail(function(error) {
dfrd.reject(error);
fm.unlockfiles({files : targets});
}).done(function(data) {
var cmdPaste, hashes;
if (hashes = data.hashes) {
cmdPaste = fm.getCommand('paste');
if (cmdPaste) {
// wait until file cache made
fm.one('mkdirdone', function() {
var hasErr = false;
$.each(dsts, function(dir, files) {
if (hashes[dir]) {
if (files.length) {
if (fm.file(hashes[dir])) {
fm.clipboard(files, true);
fm.exec('paste', [ hashes[dir] ], {_cmd : 'restore', noToast : (opts.noToast || dir !== dirTop)})
.done(function(data) {
if (data && (data.error || data.warning)) {
hasErr = true;
}
})
.fail(function() {
hasErr = true;
})
.always(function() {
if (--cnt < 1) {
dfrd[hasErr? 'reject' : 'resolve']();
if (others.length) {
// Restore items of other trash
fm.exec('restore', others);
}
}
});
} else {
dfrd.reject(errFolderNotfound);
}
} else {
if (--cnt < 1) {
dfrd.resolve();
if (others.length) {
// Restore items of other trash
fm.exec('restore', others);
}
}
}
}
});
});
} else {
dfrd.reject(['errRestore', 'errCmdNoSupport', '(paste)']);
}
} else {
dfrd.reject(errFolderNotfound);
}
});
});
} else {
dfrd.reject(errFolderNotfound);
}
} else {
dfrd.reject('errFileNotFound');
dirs && fm.exec('rm', dirs, {forceRm : true, quiet : true});
}
});
};
// for to be able to overwrite
this.restore = restore;
this.linkedCmds = ['copy', 'paste', 'mkdir', 'rm'];
this.updateOnSelect = false;
this.init = function() {
// re-assign for extended command
self = this;
fm = this.fm;
};
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
? 0 : -1;
};
this.exec = function(hashes, opts) {
var dfrd = $.Deferred()
.fail(function(error) {
error && fm.error(error);
}),
files = self.files(hashes);
if (! files.length) {
return dfrd.reject();
}
$.each(files, function(i, file) {
if (fm.isRoot(file)) {
return !dfrd.reject(['errRestore', file.name]);
}
if (file.locked) {
return !dfrd.reject(['errLocked', file.name]);
}
});
if (dfrd.state() === 'pending') {
this.restore(dfrd, files, hashes, opts);
}
return dfrd;
};
}).prototype = { forceLoad : true }; // this is required command
@@ -0,0 +1,501 @@
/**
* @class elFinder command "rm"
* Delete files
*
* @author Dmitry (dio) Levashov
* @author Naoki Sawada
**/
elFinder.prototype.commands.rm = function() {
"use strict";
var self = this,
fm = this.fm,
tpl = '<div class="ui-helper-clearfix elfinder-rm-title"><span class="elfinder-cwd-icon {class} ui-corner-all"></span>{title}<div class="elfinder-rm-desc">{desc}</div></div>',
confirm = function(dfrd, targets, files, tHash, addTexts) {
var cnt = targets.length,
cwd = fm.cwd().hash,
descs = [],
spinner = fm.i18n('calc') + '<span class="elfinder-spinner"></span>',
dialog, text, tmb, size, f, fname;
if (cnt > 1) {
size = 0;
$.each(files, function(h, f) {
if (f.size && f.size != 'unknown' && f.mime !== 'directory') {
var s = parseInt(f.size);
if (s >= 0 && size >= 0) {
size += s;
}
} else {
size = 'unknown';
return false;
}
});
getSize = (size === 'unknown');
descs.push(fm.i18n('size')+': '+(getSize? spinner : fm.formatSize(size)));
text = [$(tpl.replace('{class}', 'elfinder-cwd-icon-group').replace('{title}', '<strong>' + fm.i18n('items')+ ': ' + cnt + '</strong>').replace('{desc}', descs.join('<br>')))];
} else {
f = files[0];
tmb = fm.tmb(f);
getSize = (f.mime === 'directory');
descs.push(fm.i18n('size')+': '+(getSize? spinner : fm.formatSize(f.size)));
descs.push(fm.i18n('modify')+': '+fm.formatDate(f));
fname = fm.escape(f.i18 || f.name).replace(/([_.])/g, '&#8203;$1');
text = [$(tpl.replace('{class}', fm.mime2class(f.mime)).replace('{title}', '<strong>' + fname + '</strong>').replace('{desc}', descs.join('<br>')))];
}
if (addTexts) {
text = text.concat(addTexts);
}
text.push(tHash? 'confirmTrash' : 'confirmRm');
dialog = fm.confirm({
title : self.title,
text : text,
accept : {
label : 'btnRm',
callback : function() {
if (tHash) {
self.toTrash(dfrd, targets, tHash);
} else {
remove(dfrd, targets);
}
}
},
cancel : {
label : 'btnCancel',
callback : function() {
fm.unlockfiles({files : targets});
if (targets.length === 1 && fm.file(targets[0]).phash !== cwd) {
fm.select({selected : targets});
} else {
fm.selectfiles({files : targets});
}
dfrd.reject();
}
}
});
// load thumbnail
if (tmb) {
$('<img/>')
.on('load', function() { dialog.find('.elfinder-cwd-icon').addClass(tmb.className).css('background-image', "url('"+tmb.url+"')"); })
.attr('src', tmb.url);
}
if (getSize) {
getSize = fm.getSize($.map(files, function(f) { return f.mime === 'directory'? f.hash : null; })).done(function(data) {
dialog.find('span.elfinder-spinner').parent().html(fm.i18n('size')+': '+data.formated);
}).fail(function() {
dialog.find('span.elfinder-spinner').parent().html(fm.i18n('size')+': '+fm.i18n('unknown'));
}).always(function() {
getSize = false;
});
}
},
toTrash = function(dfrd, targets, tHash) {
var dsts = {},
itemCnt = targets.length,
maxCnt = self.options.toTrashMaxItems,
checkDirs = [],
reqDfd = $.Deferred(),
req, dirs, cnt;
if (itemCnt > maxCnt) {
self.confirm(dfrd, targets, self.files(targets), null, [fm.i18n('tooManyToTrash')]);
return;
}
// Directory preparation preparation and directory enumeration
$.each(targets, function(i, h) {
var file = fm.file(h),
path = fm.path(h).replace(/\\/g, '/'),
m = path.match(/^[^\/]+?(\/(?:[^\/]+?\/)*)[^\/]+?$/);
if (file) {
if (m) {
m[1] = m[1].replace(/(^\/.*?)\/?$/, '$1');
if (! dsts[m[1]]) {
dsts[m[1]] = [];
}
dsts[m[1]].push(h);
}
if (file.mime === 'directory') {
checkDirs.push(h);
}
}
});
// Check directory information
if (checkDirs.length) {
req = fm.request({
data : {cmd : 'size', targets : checkDirs},
notify : {type: 'readdir', cnt: 1, hideCnt: true},
preventDefault : true
}).done(function(data) {
var cnt = 0;
data.fileCnt && (cnt += parseInt(data.fileCnt));
data.dirCnt && (cnt += parseInt(data.dirCnt));
reqDfd[cnt > maxCnt ? 'reject' : 'resolve']();
}).fail(function() {
reqDfd.reject();
});
setTimeout(function() {
var xhr = (req && req.xhr)? req.xhr : null;
if (xhr && xhr.state() == 'pending') {
req.syncOnFail(false);
req.reject();
reqDfd.reject();
}
}, self.options.infoCheckWait * 1000);
} else {
reqDfd.resolve();
}
// Directory creation and paste command execution
reqDfd.done(function() {
dirs = Object.keys(dsts);
cnt = dirs.length;
if (cnt) {
fm.request({
data : {cmd : 'mkdir', target : tHash, dirs : dirs},
notify : {type : 'chkdir', cnt : cnt},
preventFail : true
})
.fail(function(error) {
dfrd.reject(error);
fm.unlockfiles({files : targets});
})
.done(function(data) {
var margeRes = function(data, phash, reqData) {
var undo, prevUndo, redo, prevRedo;
$.each(data, function(k, v) {
if (Array.isArray(v)) {
if (res[k]) {
res[k] = res[k].concat(v);
} else {
res[k] = v;
}
}
});
if (data.sync) {
res.sync = 1;
}
if (data.added && data.added.length) {
undo = function() {
var targets = [],
dirs = $.map(data.added, function(f) { return f.mime === 'directory'? f.hash : null; });
$.each(data.added, function(i, f) {
if ($.inArray(f.phash, dirs) === -1) {
targets.push(f.hash);
}
});
return fm.exec('restore', targets, {noToast: true});
};
redo = function() {
return fm.request({
data : reqData,
notify : {type : 'redo', cnt : targets.length}
});
};
if (res.undo) {
prevUndo = res.undo;
res.undo = function() {
undo();
prevUndo();
};
} else {
res.undo = undo;
}
if (res.redo) {
prevRedo = res.redo;
res.redo = function() {
redo();
prevRedo();
};
} else {
res.redo = redo;
}
}
},
err = ['errTrash'],
res = {},
hasNtf = function() {
return fm.ui.notify.children('.elfinder-notify-trash').length;
},
hashes, tm, prg, prgSt;
if (hashes = data.hashes) {
prg = 1 / cnt * 100;
prgSt = cnt === 1? 100 : 5;
tm = setTimeout(function() {
fm.notify({type : 'trash', cnt : 1, hideCnt : true, progress : prgSt});
}, fm.notifyDelay);
$.each(dsts, function(dir, files) {
var phash = fm.file(files[0]).phash,
reqData;
if (hashes[dir]) {
reqData = {cmd : 'paste', dst : hashes[dir], targets : files, cut : 1};
fm.request({
data : reqData,
preventDefault : true
})
.fail(function(error) {
if (error) {
err = err.concat(error);
}
})
.done(function(data) {
data = fm.normalize(data);
fm.updateCache(data);
margeRes(data, phash, reqData);
if (data.warning) {
err = err.concat(data.warning);
delete data.warning;
}
// fire some event to update cache/ui
data.removed && data.removed.length && fm.remove(data);
data.added && data.added.length && fm.add(data);
data.changed && data.changed.length && fm.change(data);
// fire event with command name
fm.trigger('paste', data);
// fire event with command name + 'done'
fm.trigger('pastedone');
// force update content
data.sync && fm.sync();
})
.always(function() {
var hashes = [], addTexts, end = 2;
if (hasNtf()) {
fm.notify({type : 'trash', cnt : 0, hideCnt : true, progress : prg});
} else {
prgSt+= prg;
}
if (--cnt < 1) {
tm && clearTimeout(tm);
hasNtf() && fm.notify({type : 'trash', cnt : -1});
fm.unlockfiles({files : targets});
if (Object.keys(res).length) {
if (err.length > 1) {
if (res.removed || res.removed.length) {
hashes = $.grep(targets, function(h) {
return $.inArray(h, res.removed) === -1? true : false;
});
}
if (hashes.length) {
if (err.length > end) {
end = (fm.messages[err[end-1]] || '').indexOf('$') === -1? end : end + 1;
}
dfrd.reject();
fm.exec('rm', hashes, { addTexts: err.slice(0, end), forceRm: true });
} else {
fm.error(err);
}
}
res._noSound = true;
if (res.undo && res.redo) {
res.undo = {
cmd : 'trash',
callback : res.undo,
};
res.redo = {
cmd : 'trash',
callback : res.redo
};
}
dfrd.resolve(res);
} else {
dfrd.reject(err);
}
}
});
}
});
} else {
dfrd.reject('errFolderNotFound');
fm.unlockfiles({files : targets});
}
});
} else {
dfrd.reject(['error', 'The folder hierarchy to be deleting can not be determined.']);
fm.unlockfiles({files : targets});
}
}).fail(function() {
self.confirm(dfrd, targets, self.files(targets), null, [fm.i18n('tooManyToTrash')]);
});
},
remove = function(dfrd, targets, quiet) {
var notify = quiet? {} : {type : 'rm', cnt : targets.length};
fm.request({
data : {cmd : 'rm', targets : targets},
notify : notify,
preventFail : true
})
.fail(function(error) {
dfrd.reject(error);
})
.done(function(data) {
if (data.error || data.warning) {
data.sync = true;
}
dfrd.resolve(data);
})
.always(function() {
fm.unlockfiles({files : targets});
});
},
getTHash = function(targets) {
var thash = null,
root1st;
if (targets && targets.length) {
if (targets.length > 1 && fm.searchStatus.state === 2) {
root1st = fm.file(fm.root(targets[0])).volumeid;
if (!$.grep(targets, function(h) { return h.indexOf(root1st) !== 0? true : false ; }).length) {
thash = fm.option('trashHash', targets[0]);
}
} else {
thash = fm.option('trashHash', targets[0]);
}
}
return thash;
},
getSize = false;
// for to be able to overwrite
this.confirm = confirm;
this.toTrash = toTrash;
this.remove = remove;
this.syncTitleOnChange = true;
this.updateOnSelect = false;
this.shortcuts = [{
pattern : 'delete ctrl+backspace shift+delete'
}];
this.value = 'rm';
this.init = function() {
var update = function(origin) {
var targets;
delete self.extra;
self.title = fm.i18n('cmd' + self.value);
self.className = self.value;
self.button && self.button.children('span.elfinder-button-icon')[self.value === 'trash'? 'addClass' : 'removeClass']('elfinder-button-icon-trash');
if (origin && origin !== 'cwd' && (self.state > -1 || origin === 'navbar')) {
if (self.value === 'trash') {
self.extra = {
icon: 'rm',
node: $('<span></span>')
.attr({title: fm.i18n('cmdrm')})
.on('ready', function(e, data) {
targets = data.targets;
})
.on('click touchstart', function(e){
if (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
return;
}
e.stopPropagation();
e.preventDefault();
fm.getUI().trigger('click'); // to close the context menu immediately
fm.exec('rm', targets, {_userAction: true, forceRm : true});
})
};
}
}
};
// re-assign for extended command
self = this;
fm = this.fm;
// bind function of change
self.change(function() {
update();
});
fm.bind('contextmenucreate', function(e) {
update(e.data.type);
});
};
this.getstate = function(select) {
var sel = this.hashes(select),
filter = function(files) {
var fres = true;
return $.grep(files, function(h) {
var f;
fres = fres && (f = fm.file(h)) && ! f.locked && ! fm.isRoot(f)? true : false;
return fres;
});
};
return sel.length && filter(sel).length == sel.length ? 0 : -1;
};
this.exec = function(hashes, cOpts) {
var opts = cOpts || {},
dfrd = $.Deferred()
.always(function() {
if (getSize && getSize.state && getSize.state() === 'pending') {
getSize.reject();
}
})
.fail(function(error) {
error && fm.error(error);
}).done(function(data) {
!opts.quiet && !data._noSound && data.removed && data.removed.length && fm.trigger('playsound', {soundFile : 'rm.wav'});
}),
files = self.files(hashes),
cnt = files.length,
tHash = null,
addTexts = opts.addTexts? opts.addTexts : null,
forceRm = opts.forceRm,
quiet = opts.quiet,
targets;
if (! cnt) {
return dfrd.reject();
}
$.each(files, function(i, file) {
if (fm.isRoot(file)) {
return !dfrd.reject(['errRm', file.name, 'errPerm']);
}
if (file.locked) {
return !dfrd.reject(['errLocked', file.name]);
}
});
if (dfrd.state() === 'pending') {
targets = self.hashes(hashes);
cnt = files.length;
if (forceRm || (self.event && self.event.originalEvent && self.event.originalEvent.shiftKey)) {
tHash = '';
self.title = fm.i18n('cmdrm');
}
if (tHash === null) {
tHash = getTHash(targets);
}
fm.lockfiles({files : targets});
if (tHash && self.options.quickTrash) {
self.toTrash(dfrd, targets, tHash);
} else {
if (quiet) {
remove(dfrd, targets, quiet);
} else {
self.confirm(dfrd, targets, files, tHash, addTexts);
}
}
}
return dfrd;
};
fm.bind('select contextmenucreate closecontextmenu', function(e) {
var targets = (e.data? (e.data.selected || e.data.targets) : null) || fm.selected();
if (targets && targets.length) {
self.update(void(0), (targets? getTHash(targets) : fm.option('trashHash'))? 'trash' : 'rm');
}
});
};
@@ -0,0 +1,148 @@
/**
* @class elFinder command "search"
* Find files
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.search = function() {
"use strict";
this.title = 'Find files';
this.options = {ui : 'searchbutton'};
this.alwaysEnabled = true;
this.updateOnSelect = false;
/**
* Return command status.
* Search does not support old api.
*
* @return Number
**/
this.getstate = function() {
return 0;
};
/**
* Send search request to backend.
*
* @param String search string
* @return $.Deferred
**/
this.exec = function(q, target, mime, type) {
var fm = this.fm,
reqDef = [],
sType = type || '',
onlyMimes = fm.options.onlyMimes,
phash, targetVolids = [],
setType = function(data) {
if (sType && sType !== 'SearchName' && sType !== 'SearchMime') {
data.type = sType;
}
return data;
},
rootCnt;
if (typeof q == 'string' && q) {
if (typeof target == 'object') {
mime = target.mime || '';
target = target.target || '';
}
target = target? target : '';
if (mime) {
mime = $.trim(mime).replace(',', ' ').split(' ');
if (onlyMimes.length) {
mime = $.map(mime, function(m){
m = $.trim(m);
return m && ($.inArray(m, onlyMimes) !== -1
|| $.grep(onlyMimes, function(om) { return m.indexOf(om) === 0? true : false; }).length
)? m : null;
});
}
} else {
mime = [].concat(onlyMimes);
}
fm.trigger('searchstart', setType({query : q, target : target, mimes : mime}));
if (! onlyMimes.length || mime.length) {
if (target === '' && fm.api >= 2.1) {
rootCnt = Object.keys(fm.roots).length;
$.each(fm.roots, function(id, hash) {
reqDef.push(fm.request({
data : setType({cmd : 'search', q : q, target : hash, mimes : mime}),
notify : {type : 'search', cnt : 1, hideCnt : (rootCnt > 1? false : true)},
cancel : true,
preventDone : true
}));
});
} else {
reqDef.push(fm.request({
data : setType({cmd : 'search', q : q, target : target, mimes : mime}),
notify : {type : 'search', cnt : 1, hideCnt : true},
cancel : true,
preventDone : true
}));
if (target !== '' && fm.api >= 2.1 && Object.keys(fm.leafRoots).length) {
$.each(fm.leafRoots, function(hash, roots) {
phash = hash;
while(phash) {
if (target === phash) {
$.each(roots, function() {
var f = fm.file(this);
f && f.volumeid && targetVolids.push(f.volumeid);
reqDef.push(fm.request({
data : setType({cmd : 'search', q : q, target : this, mimes : mime}),
notify : {type : 'search', cnt : 1, hideCnt : false},
cancel : true,
preventDone : true
}));
});
}
phash = (fm.file(phash) || {}).phash;
}
});
}
}
} else {
reqDef = [$.Deferred().resolve({files: []})];
}
fm.searchStatus.mixed = (reqDef.length > 1)? targetVolids : false;
return $.when.apply($, reqDef).done(function(data) {
var argLen = arguments.length,
i;
data.warning && fm.error(data.warning);
if (argLen > 1) {
data.files = (data.files || []);
for(i = 1; i < argLen; i++) {
arguments[i].warning && fm.error(arguments[i].warning);
if (arguments[i].files) {
data.files.push.apply(data.files, arguments[i].files);
}
}
}
// because "preventDone : true" so update files cache
data.files && data.files.length && fm.cache(data.files);
fm.lazy(function() {
fm.trigger('search', data);
}).then(function() {
// fire event with command name + 'done'
return fm.lazy(function() {
fm.trigger('searchdone');
});
}).then(function() {
// force update content
data.sync && fm.sync();
});
});
}
fm.getUI('toolbar').find('.'+fm.res('class', 'searchbtn')+' :text').trigger('focus');
return $.Deferred().reject();
};
};
@@ -0,0 +1,27 @@
/**
* @class elFinder command "selectall"
* Select ALL of cwd items
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.selectall = function() {
"use strict";
var self = this,
state = 0;
this.fm.bind('select', function(e) {
state = (e.data && e.data.selectall)? -1 : 0;
});
this.state = 0;
this.updateOnSelect = false;
this.getstate = function() {
return state;
};
this.exec = function() {
$(document).trigger($.Event('keydown', { keyCode: 65, ctrlKey : true, shiftKey : false, altKey : false, metaKey : false }));
return $.Deferred().resolve();
};
};
@@ -0,0 +1,20 @@
/**
* @class elFinder command "selectinvert"
* Invert Selection of cwd items
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.selectinvert = function() {
"use strict";
this.updateOnSelect = false;
this.getstate = function() {
return 0;
};
this.exec = function() {
$(document).trigger($.Event('keydown', { keyCode: 73, ctrlKey : true, shiftKey : true, altKey : false, metaKey : false }));
return $.Deferred().resolve();
};
};
@@ -0,0 +1,28 @@
/**
* @class elFinder command "selectnone"
* Unselect ALL of cwd items
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.selectnone = function() {
"use strict";
var self = this,
fm = this.fm,
state = -1;
fm.bind('select', function(e) {
state = (e.data && e.data.unselectall)? -1 : 0;
});
this.state = -1;
this.updateOnSelect = false;
this.getstate = function() {
return state;
};
this.exec = function() {
fm.getUI('cwd').trigger('unselectall');
return $.Deferred().resolve();
};
};
@@ -0,0 +1,147 @@
/**
* @class elFinder command "sort"
* Change sort files rule
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.sort = function() {
"use strict";
var self = this,
fm = self.fm,
setVar = function() {
self.variants = [];
$.each(fm.sortRules, function(name, value) {
if (fm.sorters[name]) {
var arr = (name === fm.sortType)? (fm.sortOrder === 'asc'? 'n' : 's') : '';
self.variants.push([name, (arr? '<span class="ui-icon ui-icon-arrowthick-1-'+arr+'"></span>' : '') + '&nbsp;' + fm.i18n('sort'+name)]);
}
});
self.variants.push('|');
self.variants.push([
'stick',
(fm.sortStickFolders? '<span class="ui-icon ui-icon-check"></span>' : '') + '&nbsp;' + fm.i18n('sortFoldersFirst')
]);
if (fm.ui.tree && fm.options.sortAlsoTreeview !== null) {
self.variants.push('|');
self.variants.push([
'tree',
(fm.sortAlsoTreeview? '<span class="ui-icon ui-icon-check"></span>' : '') + '&nbsp;' + fm.i18n('sortAlsoTreeview')
]);
}
updateContextmenu();
},
updateContextmenu = function() {
var cm = fm.getUI('contextmenu'),
icon, sub;
if (cm.is(':visible')) {
icon = cm.find('span.elfinder-button-icon-sort');
sub = icon.siblings('div.elfinder-contextmenu-sub');
sub.find('span.ui-icon').remove();
sub.children('div.elfinder-contextsubmenu-item').each(function() {
var tgt = $(this).children('span'),
name = tgt.text().trim(),
arr;
if (name === (i18Name.stick || (i18Name.stick = fm.i18n('sortFoldersFirst')))) {
if (fm.sortStickFolders) {
tgt.prepend('<span class="ui-icon ui-icon-check"></span>');
}
} else if (name === (i18Name.tree || (i18Name.tree = fm.i18n('sortAlsoTreeview')))) {
if (fm.sortAlsoTreeview) {
tgt.prepend('<span class="ui-icon ui-icon-check"></span>');
}
} else if (name === (i18Name[fm.sortType] || (i18Name[fm.sortType] = fm.i18n('sort' + fm.sortType)))) {
arr = fm.sortOrder === 'asc'? 'n' : 's';
tgt.prepend('<span class="ui-icon ui-icon-arrowthick-1-'+arr+'"></span>');
}
});
}
},
i18Name = {};
/**
* Command options
*
* @type Object
*/
this.options = {ui : 'sortbutton'};
this.keepContextmenu = true;
fm.bind('sortchange', setVar)
.bind('sorterupdate', function() {
setVar();
fm.getUI().children('.elfinder-button-sort-menu').children('.elfinder-button-menu-item').each(function() {
var tgt = $(this),
rel = tgt.attr('rel');
tgt.toggle(!!(! rel || fm.sorters[rel]));
});
})
.bind('cwdrender', function() {
var cols = $(fm.cwd).find('div.elfinder-cwd-wrapper-list table');
if (cols.length) {
$.each(fm.sortRules, function(name, value) {
var td = cols.find('thead tr td.elfinder-cwd-view-th-'+name);
if (td.length) {
var current = ( name == fm.sortType),
sort = {
type : name,
order : current ? fm.sortOrder == 'asc' ? 'desc' : 'asc' : fm.sortOrder
},arr;
if (current) {
td.addClass('ui-state-active');
arr = fm.sortOrder == 'asc' ? 'n' : 's';
$('<span class="ui-icon ui-icon-triangle-1-'+arr+'"></span>').appendTo(td);
}
$(td).on('click', function(e){
if (! $(this).data('dragging')) {
e.stopPropagation();
if (! fm.getUI('cwd').data('longtap')) {
fm.exec('sort', [], sort);
}
}
})
.on('mouseenter mouseleave', function(e) {
$(this).toggleClass('ui-state-hover', e.type === 'mouseenter');
});
}
});
}
});
this.getstate = function() {
return 0;
};
this.exec = function(hashes, cOpt) {
var fm = this.fm,
sortopt = $.isPlainObject(cOpt)? cOpt : (function() {
cOpt += '';
var sOpts = {};
if (cOpt === 'stick') {
sOpts.stick = !fm.sortStickFolders;
} else if (cOpt === 'tree') {
sOpts.tree = !fm.sortAlsoTreeview;
} else if (fm.sorters[cOpt]) {
if (fm.sortType === cOpt) {
sOpts.order = fm.sortOrder === 'asc'? 'desc' : 'asc';
} else {
sOpts.type = cOpt;
}
}
return sOpts;
})(),
sort = Object.assign({
type : fm.sortType,
order : fm.sortOrder,
stick : fm.sortStickFolders,
tree : fm.sortAlsoTreeview
}, sortopt);
return fm.lazy(function() {
fm.setSort(sort.type, sort.order, sort.stick, sort.tree);
this.resolve();
});
};
};
@@ -0,0 +1,189 @@
/**
* @class elFinder command "undo"
* Undo previous commands
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.undo = function() {
"use strict";
var self = this,
fm = this.fm,
setTitle = function(undo) {
if (undo) {
self.title = fm.i18n('cmdundo') + ' ' + fm.i18n('cmd'+undo.cmd);
self.state = 0;
} else {
self.title = fm.i18n('cmdundo');
self.state = -1;
}
self.change();
},
cmds = [];
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.shortcuts = [{
pattern : 'ctrl+z'
}];
this.syncTitleOnChange = true;
this.getstate = function() {
return cmds.length? 0 : -1;
};
this.setUndo = function(undo, redo) {
var _undo = {};
if (undo) {
if ($.isPlainObject(undo) && undo.cmd && undo.callback) {
Object.assign(_undo, undo);
if (redo) {
delete redo.undo;
_undo.redo = redo;
} else {
fm.getCommand('redo').setRedo(null);
}
cmds.push(_undo);
setTitle(_undo);
}
}
};
this.exec = function() {
var redo = fm.getCommand('redo'),
dfd = $.Deferred(),
undo, res, _redo = {};
if (cmds.length) {
undo = cmds.pop();
if (undo.redo) {
Object.assign(_redo, undo.redo);
delete undo.redo;
} else {
_redo = null;
}
dfd.done(function() {
if (_redo) {
redo.setRedo(_redo, undo);
}
});
setTitle(cmds.length? cmds[cmds.length-1] : void(0));
res = undo.callback();
if (res && res.done) {
res.done(function() {
dfd.resolve();
}).fail(function() {
dfd.reject();
});
} else {
dfd.resolve();
}
if (cmds.length) {
this.update(0, cmds[cmds.length - 1].name);
} else {
this.update(-1, '');
}
} else {
dfd.reject();
}
return dfd;
};
fm.bind('exec', function(e) {
var data = e.data || {};
if (data.opts && data.opts._userAction) {
if (data.dfrd && data.dfrd.done) {
data.dfrd.done(function(res) {
if (res && res.undo && res.redo) {
res.undo.redo = res.redo;
self.setUndo(res.undo);
}
});
}
}
});
};
/**
* @class elFinder command "redo"
* Redo previous commands
*
* @author Naoki Sawada
**/
elFinder.prototype.commands.redo = function() {
"use strict";
var self = this,
fm = this.fm,
setTitle = function(redo) {
if (redo && redo.callback) {
self.title = fm.i18n('cmdredo') + ' ' + fm.i18n('cmd'+redo.cmd);
self.state = 0;
} else {
self.title = fm.i18n('cmdredo');
self.state = -1;
}
self.change();
},
cmds = [];
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.shortcuts = [{
pattern : 'shift+ctrl+z ctrl+y'
}];
this.syncTitleOnChange = true;
this.getstate = function() {
return cmds.length? 0 : -1;
};
this.setRedo = function(redo, undo) {
if (redo === null) {
cmds = [];
setTitle();
} else {
if (redo && redo.cmd && redo.callback) {
if (undo) {
redo.undo = undo;
}
cmds.push(redo);
setTitle(redo);
}
}
};
this.exec = function() {
var undo = fm.getCommand('undo'),
dfd = $.Deferred(),
redo, res, _undo = {}, _redo = {};
if (cmds.length) {
redo = cmds.pop();
if (redo.undo) {
Object.assign(_undo, redo.undo);
Object.assign(_redo, redo);
delete _redo.undo;
dfd.done(function() {
undo.setUndo(_undo, _redo);
});
}
setTitle(cmds.length? cmds[cmds.length-1] : void(0));
res = redo.callback();
if (res && res.done) {
res.done(function() {
dfd.resolve();
}).fail(function() {
dfd.reject();
});
} else {
dfd.resolve();
}
return dfd;
} else {
return dfd.reject();
}
};
};
@@ -0,0 +1,30 @@
/**
* @class elFinder command "up"
* Go into parent directory
*
* @author Dmitry (dio) Levashov
**/
(elFinder.prototype.commands.up = function() {
"use strict";
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.shortcuts = [{
pattern : 'ctrl+up'
}];
this.getstate = function() {
return this.fm.cwd().phash ? 0 : -1;
};
this.exec = function() {
var fm = this.fm,
cwdhash = fm.cwd().hash;
return this.fm.cwd().phash ? this.fm.exec('open', this.fm.cwd().phash).done(function() {
fm.one('opendone', function() {
fm.selectfiles({files : [cwdhash]});
});
}) : $.Deferred().reject();
};
}).prototype = { forceLoad : true }; // this is required command
@@ -0,0 +1,423 @@
/**
* @class elFinder command "upload"
* Upload files using iframe or XMLHttpRequest & FormData.
* Dialog allow to send files using drag and drop
*
* @type elFinder.command
* @author Dmitry (dio) Levashov
*/
elFinder.prototype.commands.upload = function() {
"use strict";
var hover = this.fm.res('class', 'hover');
this.disableOnSearch = true;
this.updateOnSelect = false;
// Shortcut opens dialog
this.shortcuts = [{
pattern : 'ctrl+u'
}];
/**
* Return command state
*
* @return Number
**/
this.getstate = function(select) {
var fm = this.fm, f,
sel = (select || [fm.cwd().hash]);
if (!this._disabled && sel.length == 1) {
f = fm.file(sel[0]);
}
return (f && f.mime == 'directory' && f.write)? 0 : -1;
};
this.exec = function(data) {
var fm = this.fm,
cwdHash = fm.cwd().hash,
getTargets = function() {
var tgts = data && (data instanceof Array)? data : null,
sel;
if (! data || data instanceof Array) {
if (! tgts && (sel = fm.selected()).length === 1 && fm.file(sel[0]).mime === 'directory') {
tgts = sel;
} else if (!tgts || tgts.length !== 1 || fm.file(tgts[0]).mime !== 'directory') {
tgts = [ cwdHash ];
}
}
return tgts;
},
targets = getTargets(),
check = targets? targets[0] : (data && data.target? data.target : null),
targetDir = check? fm.file(check) : fm.cwd(),
fmUpload = function(data) {
fm.upload(data)
.fail(function(error) {
dfrd.reject(error);
})
.done(function(data) {
var cwd = fm.getUI('cwd'),
node;
dfrd.resolve(data);
if (data && data.added && data.added[0] && ! fm.ui.notify.children('.elfinder-notify-upload').length) {
var newItem = fm.findCwdNodes(data.added);
if (newItem.length) {
newItem.trigger('scrolltoview');
} else {
if (targetDir.hash !== cwdHash) {
node = $('<div></div>').append(
$('<button type="button" class="ui-button ui-widget ui-state-default ui-corner-all elfinder-tabstop"><span class="ui-button-text">'+fm.i18n('cmdopendir')+'</span></button>')
.on('mouseenter mouseleave', function(e) {
$(this).toggleClass('ui-state-hover', e.type == 'mouseenter');
}).on('click', function() {
fm.exec('open', check).done(function() {
fm.one('opendone', function() {
fm.trigger('selectfiles', {files : $.map(data.added, function(f) {return f.hash;})});
});
});
})
);
} else {
fm.trigger('selectfiles', {files : $.map(data.added, function(f) {return f.hash;})});
}
fm.toast({msg: fm.i18n(['complete', fm.i18n('cmdupload')]), extNode: node});
}
}
})
.progress(function() {
dfrd.notifyWith(this, Array.from(arguments));
});
},
upload = function(data) {
dialog.elfinderdialog('close');
if (targets) {
data.target = targets[0];
}
fmUpload(data);
},
getSelector = function() {
var hash = targetDir.hash,
dirs = $.map(fm.files(hash), function(f) {
return (f.mime === 'directory' && f.write)? f : null;
});
if (! dirs.length) {
return $();
}
return $('<div class="elfinder-upload-dirselect elfinder-tabstop" title="' + fm.i18n('folders') + '"></div>')
.on('click', function(e) {
e.stopPropagation();
e.preventDefault();
dirs = fm.sortFiles(dirs);
var $this = $(this),
cwd = fm.cwd(),
base = dialog.closest('div.ui-dialog'),
getRaw = function(f, icon) {
return {
label : fm.escape(f.i18 || f.name),
icon : icon,
remain : false,
callback : function() {
var title = base.children('.ui-dialog-titlebar:first').find('span.elfinder-upload-target');
targets = [ f.hash ];
title.html(' - ' + fm.escape(f.i18 || f.name));
$this.trigger('focus');
},
options : {
className : (targets && targets.length && f.hash === targets[0])? 'ui-state-active' : '',
iconClass : f.csscls || '',
iconImg : f.icon || ''
}
};
},
raw = [ getRaw(targetDir, 'opendir'), '|' ];
$.each(dirs, function(i, f) {
raw.push(getRaw(f, 'dir'));
});
$this.trigger('blur');
fm.trigger('contextmenu', {
raw: raw,
x: e.pageX || $(this).offset().left,
y: e.pageY || $(this).offset().top,
prevNode: base,
fitHeight: true
});
}).append('<span class="elfinder-button-icon elfinder-button-icon-dir" ></span>');
},
inputButton = function(type, caption) {
var button,
input = $('<input type="file" ' + type + '/>')
.on('click', function() {
// for IE's bug
if (fm.UA.IE) {
setTimeout(function() {
form.css('display', 'none').css('position', 'relative');
requestAnimationFrame(function() {
form.css('display', '').css('position', '');
});
}, 100);
}
})
.on('change', function() {
upload({input : input.get(0), type : 'files'});
})
.on('dragover', function(e) {
e.originalEvent.dataTransfer.dropEffect = 'copy';
}),
form = $('<form></form>').append(input).on('click', function(e) {
e.stopPropagation();
});
return $('<div class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only elfinder-tabstop elfinder-focus"><span class="ui-button-text">'+fm.i18n(caption)+'</span></div>')
.append(form)
.on('click', function(e) {
e.stopPropagation();
e.preventDefault();
input.trigger('click');
})
.on('mouseenter mouseleave', function(e) {
$(this).toggleClass(hover, e.type === 'mouseenter');
});
},
dfrd = $.Deferred(),
dialog, dropbox, pastebox, dropUpload, paste, dirs, spinner, uidialog;
dropUpload = function(e) {
e.stopPropagation();
e.preventDefault();
var file = false,
type = '',
elfFrom = null,
mycwd = '',
data = null,
target = e._target || null,
trf = e.dataTransfer || null,
kind = '',
idx, errors;
if (trf) {
if (trf.types && trf.types.length) {
if ((idx = $.inArray('application/x-moz-file', trf.types)) !== -1) {
kind = 'file';
} else if ((idx = $.inArray('Files', trf.types)) !== -1) {
kind = 'file';
}
}
else if (trf.items && trf.items.length && trf.items[0].kind) {
kind = trf.items[0].kind;
}
try {
elfFrom = trf.getData('elfinderfrom');
if (elfFrom) {
mycwd = window.location.href + fm.cwd().hash;
if ((!target && elfFrom === mycwd) || target === mycwd) {
dfrd.reject();
return;
}
}
} catch(e) {}
if (kind === 'file' && (trf.items[idx].getAsEntry || trf.items[idx].webkitGetAsEntry || trf.items[idx].getAsFile)) {
file = trf;
type = 'data';
} else if (kind !== 'string' && trf.files && trf.files.length && $.inArray('Text', trf.types) === -1) {
file = trf.files;
type = 'files';
} else {
try {
if ((data = trf.getData('text/html')) && data.match(/<(?:img|a)/i)) {
file = [ data ];
type = 'html';
}
} catch(e) {}
if (! file) {
if (data = trf.getData('text')) {
file = [ data ];
type = 'text';
} else if (trf && trf.files) {
// maybe folder uploading but this UA dose not support it
kind = 'file';
}
}
}
}
if (file) {
fmUpload({files : file, type : type, target : target, dropEvt : e});
} else {
errors = ['errUploadNoFiles'];
if (kind === 'file') {
errors.push('errFolderUpload');
}
fm.error(errors);
dfrd.reject();
}
};
if (!targets && data) {
if (data.input || data.files) {
data.type = 'files';
fmUpload(data);
} else if (data.dropEvt) {
dropUpload(data.dropEvt);
}
return dfrd;
}
paste = function(ev) {
var e = ev.originalEvent || ev;
var files = [], items = [];
var file;
if (e.clipboardData) {
if (e.clipboardData.items && e.clipboardData.items.length){
items = e.clipboardData.items;
for (var i=0; i < items.length; i++) {
if (e.clipboardData.items[i].kind == 'file') {
file = e.clipboardData.items[i].getAsFile();
files.push(file);
}
}
} else if (e.clipboardData.files && e.clipboardData.files.length) {
files = e.clipboardData.files;
}
if (files.length) {
upload({files : files, type : 'files', clipdata : true});
return;
}
}
var my = e.target || e.srcElement;
requestAnimationFrame(function() {
var type = 'text',
src;
if (my.innerHTML) {
$(my).find('img').each(function(i, v){
if (v.src.match(/^webkit-fake-url:\/\//)) {
// For Safari's bug.
// ref. https://bugs.webkit.org/show_bug.cgi?id=49141
// https://dev.ckeditor.com/ticket/13029
$(v).remove();
}
});
if ($(my).find('a,img').length) {
type = 'html';
}
src = my.innerHTML;
my.innerHTML = '';
upload({files : [ src ], type : type});
}
});
};
dialog = $('<div class="elfinder-upload-dialog-wrapper"></div>')
.append(inputButton('multiple', 'selectForUpload'));
if (! fm.UA.Mobile && (function(input) {
return (typeof input.webkitdirectory !== 'undefined' || typeof input.directory !== 'undefined');})(document.createElement('input'))) {
dialog.append(inputButton('multiple webkitdirectory directory', 'selectFolder'));
}
if (targetDir.dirs) {
if (targetDir.hash === cwdHash || fm.navHash2Elm(targetDir.hash).hasClass('elfinder-subtree-loaded')) {
getSelector().appendTo(dialog);
} else {
spinner = $('<div class="elfinder-upload-dirselect" title="' + fm.i18n('nowLoading') + '"></div>')
.append('<span class="elfinder-button-icon elfinder-button-icon-spinner" ></span>')
.appendTo(dialog);
fm.request({cmd : 'tree', target : targetDir.hash})
.done(function() {
fm.one('treedone', function() {
spinner.replaceWith(getSelector());
uidialog.elfinderdialog('tabstopsInit');
});
})
.fail(function() {
spinner.remove();
});
}
}
if (fm.dragUpload) {
dropbox = $('<div class="ui-corner-all elfinder-upload-dropbox elfinder-tabstop" contenteditable="true" data-ph="'+fm.i18n('dropPasteFiles')+'"></div>')
.on('paste', function(e){
paste(e);
})
.on('mousedown click', function(){
$(this).trigger('focus');
})
.on('focus', function(){
this.innerHTML = '';
})
.on('mouseover', function(){
$(this).addClass(hover);
})
.on('mouseout', function(){
$(this).removeClass(hover);
})
.on('dragenter', function(e) {
e.stopPropagation();
e.preventDefault();
$(this).addClass(hover);
})
.on('dragleave', function(e) {
e.stopPropagation();
e.preventDefault();
$(this).removeClass(hover);
})
.on('dragover', function(e) {
e.stopPropagation();
e.preventDefault();
e.originalEvent.dataTransfer.dropEffect = 'copy';
$(this).addClass(hover);
})
.on('drop', function(e) {
dialog.elfinderdialog('close');
targets && (e.originalEvent._target = targets[0]);
dropUpload(e.originalEvent);
})
.prependTo(dialog)
.after('<div class="elfinder-upload-dialog-or">'+fm.i18n('or')+'</div>')[0];
} else {
pastebox = $('<div class="ui-corner-all elfinder-upload-dropbox" contenteditable="true">'+fm.i18n('dropFilesBrowser')+'</div>')
.on('paste drop', function(e){
paste(e);
})
.on('mousedown click', function(){
$(this).trigger('focus');
})
.on('focus', function(){
this.innerHTML = '';
})
.on('dragenter mouseover', function(){
$(this).addClass(hover);
})
.on('dragleave mouseout', function(){
$(this).removeClass(hover);
})
.prependTo(dialog)
.after('<div class="elfinder-upload-dialog-or">'+fm.i18n('or')+'</div>')[0];
}
uidialog = this.fmDialog(dialog, {
title : this.title + '<span class="elfinder-upload-target">' + (targetDir? ' - ' + fm.escape(targetDir.i18 || targetDir.name) : '') + '</span>',
modal : true,
resizable : false,
destroyOnClose : true,
propagationEvents : ['mousemove', 'mouseup', 'click'],
close : function() {
var cm = fm.getUI('contextmenu');
if (cm.is(':visible')) {
cm.click();
}
}
});
return dfrd;
};
};
@@ -0,0 +1,125 @@
/**
* @class elFinder command "view"
* Change current directory view (icons/list)
*
* @author Dmitry (dio) Levashov
**/
elFinder.prototype.commands.view = function() {
"use strict";
var self = this,
fm = this.fm,
subMenuRaw;
this.value = fm.viewType;
this.alwaysEnabled = true;
this.updateOnSelect = false;
this.options = { ui : 'viewbutton'};
this.getstate = function() {
return 0;
};
this.extra = {
icon: 'menu',
node: $('<span></span>')
.attr({title: fm.i18n('viewtype')})
.on('click touchstart', function(e){
if (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
return;
}
var node = $(this);
e.stopPropagation();
e.preventDefault();
fm.trigger('contextmenu', {
raw: getSubMenuRaw(),
x: node.offset().left,
y: node.offset().top
});
})
};
this.exec = function() {
var self = this,
value = this.value == 'list' ? 'icons' : 'list';
fm.storage('view', value);
return fm.lazy(function() {
fm.viewchange();
self.update(void(0), value);
this.resolve();
});
};
fm.bind('init', function() {
subMenuRaw = (function() {
var cwd = fm.getUI('cwd'),
raws = [],
sizeNames = fm.options.uiOptions.cwd.iconsView.sizeNames,
max = fm.options.uiOptions.cwd.iconsView.sizeMax,
i, size;
for (i = 0; i <= max; i++) {
raws.push(
{
label : fm.i18n(sizeNames[i] || ('Size-' + i + ' icons')),
icon : 'view',
callback : (function(s) {
return function() {
cwd.trigger('iconpref', {size: s});
fm.storage('iconsize', s);
if (self.value === 'list') {
self.exec();
}
};
})(i)
}
);
}
raws.push('|');
raws.push(
{
label : fm.i18n('viewlist'),
icon : 'view-list',
callback : function() {
if (self.value !== 'list') {
self.exec();
}
}
}
);
return raws;
})();
}).bind('contextmenucreate', function() {
self.extra = {
icon: 'menu',
node: $('<span></span>')
.attr({title: fm.i18n('cmdview')})
.on('click touchstart', function(e){
if (e.type === 'touchstart' && e.originalEvent.touches.length > 1) {
return;
}
var node = $(this),
raw = subMenuRaw.concat(),
idx, i;
if (self.value === 'list') {
idx = subMenuRaw.length - 1;
} else {
idx = parseInt(fm.storage('iconsize') || 0);
}
for (i = 0; i < subMenuRaw.length; i++) {
if (subMenuRaw[i] !== '|') {
subMenuRaw[i].options = (i === idx? {'className': 'ui-state-active'} : void(0))
;
}
}
e.stopPropagation();
e.preventDefault();
fm.trigger('contextmenu', {
raw: subMenuRaw,
x: node.offset().left,
y: node.offset().top
});
})
};
});
};